@swf2es/player-hosts 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/LICENSE.third-party +759 -0
- package/README.md +43 -2
- package/dist/indexeddb.d.ts +27 -0
- package/dist/indexeddb.d.ts.map +1 -0
- package/dist/indexeddb.js +170 -0
- package/dist/indexeddb.js.map +1 -0
- package/dist/node-worker.d.ts +2 -0
- package/dist/node-worker.d.ts.map +1 -0
- package/dist/node-worker.js +12 -0
- package/dist/node-worker.js.map +1 -0
- package/dist/node.d.ts +8 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +43 -0
- package/dist/node.js.map +1 -0
- package/dist/precompiled.d.ts +31 -0
- package/dist/precompiled.d.ts.map +1 -0
- package/dist/precompiled.js +125 -0
- package/dist/precompiled.js.map +1 -0
- package/dist/stage3d.d.ts +13 -0
- package/dist/stage3d.d.ts.map +1 -0
- package/dist/stage3d.js +61 -0
- package/dist/stage3d.js.map +1 -0
- package/dist/thread/codegen/codegen.js +308 -0
- package/dist/thread/codegen/index.js +405 -0
- package/dist/thread/format/abc-names.js +126 -0
- package/dist/thread/format/actions.js +222 -0
- package/dist/thread/format/air-descriptor.js +63 -0
- package/dist/thread/format/api-versions.js +22 -0
- package/dist/thread/format/bitmap.js +199 -0
- package/dist/thread/format/button.js +60 -0
- package/dist/thread/format/compression.js +200 -0
- package/dist/thread/format/display.js +305 -0
- package/dist/thread/format/filters.js +136 -0
- package/dist/thread/format/font.js +168 -0
- package/dist/thread/format/index.js +26 -0
- package/dist/thread/format/pbj.js +484 -0
- package/dist/thread/format/shape.js +411 -0
- package/dist/thread/format/sound.js +91 -0
- package/dist/thread/format/swf.js +163 -0
- package/dist/thread/format/tags.js +58 -0
- package/dist/thread/format/text.js +135 -0
- package/dist/thread/format/zip.js +91 -0
- package/dist/thread/native/audio/binary.js +3 -0
- package/dist/thread/native/audio/index.js +72 -0
- package/dist/thread/native/base64.js +9 -0
- package/dist/thread/native/compress/binary.js +3 -0
- package/dist/thread/native/compress/index.js +145 -0
- package/dist/thread/native/instance.js +49 -0
- package/dist/thread/native/mp3/binary.js +3 -0
- package/dist/thread/native/mp3/index.js +48 -0
- package/dist/thread/native/render/binary.js +3 -0
- package/dist/thread/native/render/bitmap-kernel.js +591 -0
- package/dist/thread/native/render/draw-kernel.js +204 -0
- package/dist/thread/native/render/dxt-encoder.js +94 -0
- package/dist/thread/native/render/index.js +10 -0
- package/dist/thread/native/render/lines.js +122 -0
- package/dist/thread/native/render/module.js +26 -0
- package/dist/thread/native/render/pixel-ops.js +235 -0
- package/dist/thread/native/render/tessellator.js +250 -0
- package/dist/thread/player/avm1/amf.js +507 -0
- package/dist/thread/player/avm1/avm1.js +1304 -0
- package/dist/thread/player/avm1/bindings.js +214 -0
- package/dist/thread/player/avm1/classes.js +75 -0
- package/dist/thread/player/avm1/clips.js +229 -0
- package/dist/thread/player/avm1/compile.js +140 -0
- package/dist/thread/player/avm1/external.js +79 -0
- package/dist/thread/player/avm1/focus.js +278 -0
- package/dist/thread/player/avm1/globals/BitmapData.js +542 -0
- package/dist/thread/player/avm1/globals/Button.js +31 -0
- package/dist/thread/player/avm1/globals/Color.js +115 -0
- package/dist/thread/player/avm1/globals/ExternalInterface.js +310 -0
- package/dist/thread/player/avm1/globals/FileReference.js +217 -0
- package/dist/thread/player/avm1/globals/Key.js +60 -0
- package/dist/thread/player/avm1/globals/LoadVars.js +208 -0
- package/dist/thread/player/avm1/globals/LocalConnection.js +92 -0
- package/dist/thread/player/avm1/globals/MovieClip.js +1070 -0
- package/dist/thread/player/avm1/globals/MovieClipLoader.js +90 -0
- package/dist/thread/player/avm1/globals/NetConnection.js +261 -0
- package/dist/thread/player/avm1/globals/PrintJob.js +37 -0
- package/dist/thread/player/avm1/globals/Selection.js +62 -0
- package/dist/thread/player/avm1/globals/SharedObject.js +245 -0
- package/dist/thread/player/avm1/globals/Sound.js +238 -0
- package/dist/thread/player/avm1/globals/Stage.js +12 -0
- package/dist/thread/player/avm1/globals/StyleSheet.js +205 -0
- package/dist/thread/player/avm1/globals/TextField.js +396 -0
- package/dist/thread/player/avm1/globals/TextFormat.js +194 -0
- package/dist/thread/player/avm1/globals/TextSnapshot.js +88 -0
- package/dist/thread/player/avm1/globals/XML.js +396 -0
- package/dist/thread/player/avm1/globals/XMLNode.js +413 -0
- package/dist/thread/player/avm1/globals/XMLSocket.js +205 -0
- package/dist/thread/player/avm1/globals/drawing.js +202 -0
- package/dist/thread/player/avm1/globals/filters.js +635 -0
- package/dist/thread/player/avm1/globals/geom.js +600 -0
- package/dist/thread/player/avm1/input.js +483 -0
- package/dist/thread/player/avm1/keyboard.js +113 -0
- package/dist/thread/player/avm1/loads.js +352 -0
- package/dist/thread/player/avm1/net.js +219 -0
- package/dist/thread/player/avm1/paths.js +104 -0
- package/dist/thread/player/avm1/pointer.js +512 -0
- package/dist/thread/player/avm1/queue.js +303 -0
- package/dist/thread/player/avm1/sound.js +106 -0
- package/dist/thread/player/avm1/swf.js +141 -0
- package/dist/thread/player/avm1/timers.js +113 -0
- package/dist/thread/player/bitmap/bitmap.js +627 -0
- package/dist/thread/player/bitmap/draw.js +68 -0
- package/dist/thread/player/bitmap/dxt.js +11 -0
- package/dist/thread/player/bitmap/filters.js +656 -0
- package/dist/thread/player/bitmap/images.js +240 -0
- package/dist/thread/player/bitmap/kernel.js +65 -0
- package/dist/thread/player/bitmap/ops.js +1239 -0
- package/dist/thread/player/bitmap/pixel-bender.js +911 -0
- package/dist/thread/player/bitmap/png.js +139 -0
- package/dist/thread/player/bitmap/turbulence.js +89 -0
- package/dist/thread/player/clock.js +182 -0
- package/dist/thread/player/display/bitmapobject.js +25 -0
- package/dist/thread/player/display/bounds.js +520 -0
- package/dist/thread/player/display/buttonobject.js +305 -0
- package/dist/thread/player/display/color.js +40 -0
- package/dist/thread/player/display/container.js +150 -0
- package/dist/thread/player/display/display.js +14 -0
- package/dist/thread/player/display/displayobject.js +664 -0
- package/dist/thread/player/display/drawing.js +613 -0
- package/dist/thread/player/display/filters.js +285 -0
- package/dist/thread/player/display/geometry.js +189 -0
- package/dist/thread/player/display/gradients.js +117 -0
- package/dist/thread/player/display/graphicsdata.js +592 -0
- package/dist/thread/player/display/instantiate.js +71 -0
- package/dist/thread/player/display/matrix3d.js +373 -0
- package/dist/thread/player/display/morph.js +226 -0
- package/dist/thread/player/display/movieclip.js +680 -0
- package/dist/thread/player/display/perspective.js +193 -0
- package/dist/thread/player/display/scale9.js +236 -0
- package/dist/thread/player/display/shapeobject.js +131 -0
- package/dist/thread/player/display/shapes.js +407 -0
- package/dist/thread/player/display/textobjects.js +222 -0
- package/dist/thread/player/display/timeline.js +471 -0
- package/dist/thread/player/display/value-lists.js +40 -0
- package/dist/thread/player/display/videoobject.js +6 -0
- package/dist/thread/player/display/walk.js +127 -0
- package/dist/thread/player/files.js +334 -0
- package/dist/thread/player/hosts.js +207 -0
- package/dist/thread/player/input/avm1.js +82 -0
- package/dist/thread/player/input/context-menu.js +63 -0
- package/dist/thread/player/input/keyboard.js +458 -0
- package/dist/thread/player/input/pointer.js +863 -0
- package/dist/thread/player/input/text-editor.js +319 -0
- package/dist/thread/player/input/touch.js +209 -0
- package/dist/thread/player/localconnection.js +90 -0
- package/dist/thread/player/media/audio.js +376 -0
- package/dist/thread/player/media/dynamic-sound.js +90 -0
- package/dist/thread/player/media/extract.js +135 -0
- package/dist/thread/player/media/mp3.js +152 -0
- package/dist/thread/player/media/sounds.js +507 -0
- package/dist/thread/player/media/streaming-audio.js +133 -0
- package/dist/thread/player/player.js +616 -0
- package/dist/thread/player/playerglobal/air/net/WebSocket.js +250 -0
- package/dist/thread/player/playerglobal/air-library.js +8 -0
- package/dist/thread/player/playerglobal/flash/accessibility/Accessibility.js +21 -0
- package/dist/thread/player/playerglobal/flash/crypto/generateRandomBytes.js +32 -0
- package/dist/thread/player/playerglobal/flash/data/EncryptedLocalStore.js +61 -0
- package/dist/thread/player/playerglobal/flash/desktop/Clipboard.js +173 -0
- package/dist/thread/player/playerglobal/flash/desktop/NativeApplication.js +179 -0
- package/dist/thread/player/playerglobal/flash/display/AVM1Movie.js +19 -0
- package/dist/thread/player/playerglobal/flash/display/Bitmap.js +58 -0
- package/dist/thread/player/playerglobal/flash/display/BitmapData.js +633 -0
- package/dist/thread/player/playerglobal/flash/display/DisplayObject.js +614 -0
- package/dist/thread/player/playerglobal/flash/display/DisplayObjectContainer.js +224 -0
- package/dist/thread/player/playerglobal/flash/display/Graphics.js +345 -0
- package/dist/thread/player/playerglobal/flash/display/InteractiveObject.js +87 -0
- package/dist/thread/player/playerglobal/flash/display/Loader.js +79 -0
- package/dist/thread/player/playerglobal/flash/display/LoaderInfo.js +128 -0
- package/dist/thread/player/playerglobal/flash/display/MovieClip.js +194 -0
- package/dist/thread/player/playerglobal/flash/display/NativeWindow.js +245 -0
- package/dist/thread/player/playerglobal/flash/display/Shader.js +26 -0
- package/dist/thread/player/playerglobal/flash/display/ShaderData.js +85 -0
- package/dist/thread/player/playerglobal/flash/display/ShaderInput.js +64 -0
- package/dist/thread/player/playerglobal/flash/display/ShaderJob.js +181 -0
- package/dist/thread/player/playerglobal/flash/display/ShaderParameter.js +23 -0
- package/dist/thread/player/playerglobal/flash/display/Shape.js +13 -0
- package/dist/thread/player/playerglobal/flash/display/SimpleButton.js +103 -0
- package/dist/thread/player/playerglobal/flash/display/Sprite.js +84 -0
- package/dist/thread/player/playerglobal/flash/display/Stage.js +231 -0
- package/dist/thread/player/playerglobal/flash/display/Stage3D.js +54 -0
- package/dist/thread/player/playerglobal/flash/display/shaders.js +228 -0
- package/dist/thread/player/playerglobal/flash/events/Event.js +58 -0
- package/dist/thread/player/playerglobal/flash/events/EventDispatcher.js +103 -0
- package/dist/thread/player/playerglobal/flash/events/GestureEvent.js +34 -0
- package/dist/thread/player/playerglobal/flash/events/HTTPStatusEvent.js +8 -0
- package/dist/thread/player/playerglobal/flash/events/KeyboardEvent.js +51 -0
- package/dist/thread/player/playerglobal/flash/events/MouseEvent.js +59 -0
- package/dist/thread/player/playerglobal/flash/events/PressAndTapGestureEvent.js +30 -0
- package/dist/thread/player/playerglobal/flash/events/TimerEvent.js +16 -0
- package/dist/thread/player/playerglobal/flash/events/TouchEvent.js +45 -0
- package/dist/thread/player/playerglobal/flash/external/ExternalInterface.js +73 -0
- package/dist/thread/player/playerglobal/flash/filesystem/File.js +340 -0
- package/dist/thread/player/playerglobal/flash/filesystem/FileStream.js +453 -0
- package/dist/thread/player/playerglobal/flash/filesystem/paths.js +156 -0
- package/dist/thread/player/playerglobal/flash/filesystem/writes.js +143 -0
- package/dist/thread/player/playerglobal/flash/filters/BevelFilter.js +4 -0
- package/dist/thread/player/playerglobal/flash/filters/BitmapFilter.js +205 -0
- package/dist/thread/player/playerglobal/flash/filters/BlurFilter.js +4 -0
- package/dist/thread/player/playerglobal/flash/filters/ColorMatrixFilter.js +11 -0
- package/dist/thread/player/playerglobal/flash/filters/ConvolutionFilter.js +26 -0
- package/dist/thread/player/playerglobal/flash/filters/DisplacementMapFilter.js +51 -0
- package/dist/thread/player/playerglobal/flash/filters/DropShadowFilter.js +4 -0
- package/dist/thread/player/playerglobal/flash/filters/GlowFilter.js +4 -0
- package/dist/thread/player/playerglobal/flash/filters/GradientBevelFilter.js +4 -0
- package/dist/thread/player/playerglobal/flash/filters/GradientGlowFilter.js +4 -0
- package/dist/thread/player/playerglobal/flash/filters/ShaderFilter.js +53 -0
- package/dist/thread/player/playerglobal/flash/geom/Matrix3D.js +361 -0
- package/dist/thread/player/playerglobal/flash/geom/PerspectiveProjection.js +122 -0
- package/dist/thread/player/playerglobal/flash/geom/Transform.js +245 -0
- package/dist/thread/player/playerglobal/flash/geom/Utils3D.js +85 -0
- package/dist/thread/player/playerglobal/flash/globalization/Collator.js +149 -0
- package/dist/thread/player/playerglobal/flash/globalization/CurrencyFormatter.js +272 -0
- package/dist/thread/player/playerglobal/flash/globalization/CurrencyParseResult.js +21 -0
- package/dist/thread/player/playerglobal/flash/globalization/DateTimeFormatter.js +463 -0
- package/dist/thread/player/playerglobal/flash/globalization/LocaleID.js +144 -0
- package/dist/thread/player/playerglobal/flash/globalization/NumberFormatter.js +444 -0
- package/dist/thread/player/playerglobal/flash/globalization/NumberParseResult.js +22 -0
- package/dist/thread/player/playerglobal/flash/globalization/StringTools.js +59 -0
- package/dist/thread/player/playerglobal/flash/globalization/locale.js +190 -0
- package/dist/thread/player/playerglobal/flash/media/Camera.js +89 -0
- package/dist/thread/player/playerglobal/flash/media/Microphone.js +126 -0
- package/dist/thread/player/playerglobal/flash/media/Sound.js +543 -0
- package/dist/thread/player/playerglobal/flash/media/SoundMixer.js +74 -0
- package/dist/thread/player/playerglobal/flash/media/SoundTransform.js +40 -0
- package/dist/thread/player/playerglobal/flash/media/Video.js +43 -0
- package/dist/thread/player/playerglobal/flash/net/FileFilter.js +27 -0
- package/dist/thread/player/playerglobal/flash/net/FileReference.js +197 -0
- package/dist/thread/player/playerglobal/flash/net/LocalConnection.js +167 -0
- package/dist/thread/player/playerglobal/flash/net/NetConnection.js +155 -0
- package/dist/thread/player/playerglobal/flash/net/SharedObject.js +299 -0
- package/dist/thread/player/playerglobal/flash/net/Socket.js +282 -0
- package/dist/thread/player/playerglobal/flash/net/URLRequest.js +93 -0
- package/dist/thread/player/playerglobal/flash/net/URLStream.js +146 -0
- package/dist/thread/player/playerglobal/flash/net/XMLSocket.js +14 -0
- package/dist/thread/player/playerglobal/flash/net/local-modern.js +142 -0
- package/dist/thread/player/playerglobal/flash/net/local-values.js +217 -0
- package/dist/thread/player/playerglobal/flash/net/navigateToURL.js +29 -0
- package/dist/thread/player/playerglobal/flash/profiler/Telemetry.js +25 -0
- package/dist/thread/player/playerglobal/flash/sensors/Accelerometer.js +12 -0
- package/dist/thread/player/playerglobal/flash/system/ApplicationDomain.js +69 -0
- package/dist/thread/player/playerglobal/flash/system/Capabilities.js +163 -0
- package/dist/thread/player/playerglobal/flash/system/FSCommandHost.js +17 -0
- package/dist/thread/player/playerglobal/flash/system/Security.js +46 -0
- package/dist/thread/player/playerglobal/flash/system/SecurityDomain.js +21 -0
- package/dist/thread/player/playerglobal/flash/system/System.js +73 -0
- package/dist/thread/player/playerglobal/flash/system/Worker.js +112 -0
- package/dist/thread/player/playerglobal/flash/text/Font.js +95 -0
- package/dist/thread/player/playerglobal/flash/text/StaticText.js +16 -0
- package/dist/thread/player/playerglobal/flash/text/StyleSheet.js +65 -0
- package/dist/thread/player/playerglobal/flash/text/TextField.js +707 -0
- package/dist/thread/player/playerglobal/flash/text/TextRenderer.js +77 -0
- package/dist/thread/player/playerglobal/flash/text/engine/FontDescription.js +141 -0
- package/dist/thread/player/playerglobal/flash/text/engine/TabStop.js +46 -0
- package/dist/thread/player/playerglobal/flash/trace/Trace.js +17 -0
- package/dist/thread/player/playerglobal/flash/ui/ContextMenu.js +17 -0
- package/dist/thread/player/playerglobal/flash/ui/GameInput.js +19 -0
- package/dist/thread/player/playerglobal/flash/ui/Keyboard.js +27 -0
- package/dist/thread/player/playerglobal/flash/ui/Mouse.js +127 -0
- package/dist/thread/player/playerglobal/flash/ui/Multitouch.js +46 -0
- package/dist/thread/player/playerglobal/flash/utils/ByteArray.js +155 -0
- package/dist/thread/player/playerglobal/flash/utils/Timer.js +25 -0
- package/dist/thread/player/playerglobal/flash/xml/XMLDocument.js +74 -0
- package/dist/thread/player/playerglobal/index.js +224 -0
- package/dist/thread/player/playerglobal/libraries.js +10 -0
- package/dist/thread/player/playerglobal/playerglobal-library.js +22 -0
- package/dist/thread/player/playerglobal/toplevel.js +122 -0
- package/dist/thread/player/scripting/clipboard.js +146 -0
- package/dist/thread/player/scripting/code.js +900 -0
- package/dist/thread/player/scripting/evaluate.js +144 -0
- package/dist/thread/player/scripting/events.js +172 -0
- package/dist/thread/player/scripting/handover.js +182 -0
- package/dist/thread/player/scripting/lazy.js +38 -0
- package/dist/thread/player/scripting/lifecycle.js +272 -0
- package/dist/thread/player/scripting/loads.js +860 -0
- package/dist/thread/player/scripting/sha256.js +95 -0
- package/dist/thread/player/scripting/symbols.js +348 -0
- package/dist/thread/player/scripting/timers.js +434 -0
- package/dist/thread/player/scripting/workers.js +923 -0
- package/dist/thread/player/scripting.js +1018 -0
- package/dist/thread/player/stage.js +4 -0
- package/dist/thread/player/text/csm.js +113 -0
- package/dist/thread/player/text/css.js +167 -0
- package/dist/thread/player/text/fonts.js +97 -0
- package/dist/thread/player/text/layout.js +393 -0
- package/dist/thread/player/text/static.js +109 -0
- package/dist/thread/player/text/text.js +431 -0
- package/dist/thread/player/workers/thread.js +159 -0
- package/dist/thread/player/workers/wire.js +198 -0
- package/dist/thread/player-hosts/web-worker.js +19 -0
- package/dist/thread/runtime/avm1/activation.js +89 -0
- package/dist/thread/runtime/avm1/case.js +249 -0
- package/dist/thread/runtime/avm1/clips.js +334 -0
- package/dist/thread/runtime/avm1/control.js +280 -0
- package/dist/thread/runtime/avm1/errors.js +50 -0
- package/dist/thread/runtime/avm1/functions.js +249 -0
- package/dist/thread/runtime/avm1/globals/array.js +549 -0
- package/dist/thread/runtime/avm1/globals/broadcaster.js +131 -0
- package/dist/thread/runtime/avm1/globals/date.js +436 -0
- package/dist/thread/runtime/avm1/globals/global.js +344 -0
- package/dist/thread/runtime/avm1/globals/math.js +139 -0
- package/dist/thread/runtime/avm1/globals/number.js +93 -0
- package/dist/thread/runtime/avm1/globals/string.js +201 -0
- package/dist/thread/runtime/avm1/globals/timers.js +129 -0
- package/dist/thread/runtime/avm1/host.js +5 -0
- package/dist/thread/runtime/avm1/index.js +14 -0
- package/dist/thread/runtime/avm1/inheritance.js +132 -0
- package/dist/thread/runtime/avm1/numbers.js +298 -0
- package/dist/thread/runtime/avm1/objects.js +896 -0
- package/dist/thread/runtime/avm1/operators.js +170 -0
- package/dist/thread/runtime/avm1/realm.js +529 -0
- package/dist/thread/runtime/avm1/runtime.js +882 -0
- package/dist/thread/runtime/avm1/scope.js +385 -0
- package/dist/thread/runtime/avm1/urls.js +180 -0
- package/dist/thread/runtime/avm1/values.js +97 -0
- package/dist/thread/runtime/avm2/amf-classes.js +66 -0
- package/dist/thread/runtime/avm2/amf.js +801 -0
- package/dist/thread/runtime/avm2/array-conversion.js +100 -0
- package/dist/thread/runtime/avm2/builtin-library.js +21 -0
- package/dist/thread/runtime/avm2/cache-fill.js +86 -0
- package/dist/thread/runtime/avm2/classes.js +211 -0
- package/dist/thread/runtime/avm2/definitions.js +69 -0
- package/dist/thread/runtime/avm2/descriptors.js +5 -0
- package/dist/thread/runtime/avm2/dictionary-keys.js +295 -0
- package/dist/thread/runtime/avm2/domain-memory.js +75 -0
- package/dist/thread/runtime/avm2/domain.js +280 -0
- package/dist/thread/runtime/avm2/dynamic-properties.js +182 -0
- package/dist/thread/runtime/avm2/enumeration.js +393 -0
- package/dist/thread/runtime/avm2/errors.js +45 -0
- package/dist/thread/runtime/avm2/float-library.js +66 -0
- package/dist/thread/runtime/avm2/float.js +26 -0
- package/dist/thread/runtime/avm2/hooks.js +19 -0
- package/dist/thread/runtime/avm2/index.js +38 -0
- package/dist/thread/runtime/avm2/messages.js +177 -0
- package/dist/thread/runtime/avm2/method-factories.js +95 -0
- package/dist/thread/runtime/avm2/modules.js +105 -0
- package/dist/thread/runtime/avm2/names.js +248 -0
- package/dist/thread/runtime/avm2/natives/aliases.js +47 -0
- package/dist/thread/runtime/avm2/natives/array.js +390 -0
- package/dist/thread/runtime/avm2/natives/bytearray.js +1227 -0
- package/dist/thread/runtime/avm2/natives/case.js +88 -0
- package/dist/thread/runtime/avm2/natives/concurrent.js +199 -0
- package/dist/thread/runtime/avm2/natives/date.js +581 -0
- package/dist/thread/runtime/avm2/natives/define.js +130 -0
- package/dist/thread/runtime/avm2/natives/describe.js +351 -0
- package/dist/thread/runtime/avm2/natives/dictionary.js +12 -0
- package/dist/thread/runtime/avm2/natives/float-vector.js +81 -0
- package/dist/thread/runtime/avm2/natives/float.js +96 -0
- package/dist/thread/runtime/avm2/natives/index.js +64 -0
- package/dist/thread/runtime/avm2/natives/json.js +514 -0
- package/dist/thread/runtime/avm2/natives/number.js +162 -0
- package/dist/thread/runtime/avm2/natives/object.js +237 -0
- package/dist/thread/runtime/avm2/natives/proxy.js +75 -0
- package/dist/thread/runtime/avm2/natives/regexp.js +485 -0
- package/dist/thread/runtime/avm2/natives/shell-workers.js +404 -0
- package/dist/thread/runtime/avm2/natives/shell.js +557 -0
- package/dist/thread/runtime/avm2/natives/sort.js +377 -0
- package/dist/thread/runtime/avm2/natives/string.js +132 -0
- package/dist/thread/runtime/avm2/natives/sync.js +821 -0
- package/dist/thread/runtime/avm2/natives/toplevel.js +139 -0
- package/dist/thread/runtime/avm2/natives/vector-elements.js +46 -0
- package/dist/thread/runtime/avm2/natives/vector.js +406 -0
- package/dist/thread/runtime/avm2/natives/xml/access.js +633 -0
- package/dist/thread/runtime/avm2/natives/xml/build.js +291 -0
- package/dist/thread/runtime/avm2/natives/xml/chars.js +112 -0
- package/dist/thread/runtime/avm2/natives/xml/escape.js +38 -0
- package/dist/thread/runtime/avm2/natives/xml/names.js +204 -0
- package/dist/thread/runtime/avm2/natives/xml/node.js +272 -0
- package/dist/thread/runtime/avm2/natives/xml/operators.js +69 -0
- package/dist/thread/runtime/avm2/natives/xml/parser.js +356 -0
- package/dist/thread/runtime/avm2/natives/xml/strings.js +191 -0
- package/dist/thread/runtime/avm2/natives/xml/values.js +122 -0
- package/dist/thread/runtime/avm2/natives/xml/xml.js +645 -0
- package/dist/thread/runtime/avm2/number-strings.js +110 -0
- package/dist/thread/runtime/avm2/numbers.js +558 -0
- package/dist/thread/runtime/avm2/options.js +16 -0
- package/dist/thread/runtime/avm2/player-messages.js +550 -0
- package/dist/thread/runtime/avm2/property-cache.js +135 -0
- package/dist/thread/runtime/avm2/runtime.js +2644 -0
- package/dist/thread/runtime/avm2/traits.js +509 -0
- package/dist/thread/runtime/index.js +7 -0
- package/dist/web-worker.d.ts +2 -0
- package/dist/web-worker.d.ts.map +1 -0
- package/dist/web-worker.js +20 -0
- package/dist/web-worker.js.map +1 -0
- package/dist/websocket.d.ts +4 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +27 -0
- package/dist/websocket.js.map +1 -0
- package/dist/workers.d.ts +35 -0
- package/dist/workers.d.ts.map +1 -0
- package/dist/workers.js +171 -0
- package/dist/workers.js.map +1 -0
- package/package.json +62 -3
- package/src/indexeddb.ts +227 -0
- package/src/node-worker.ts +13 -0
- package/src/node.ts +49 -0
- package/src/precompiled.ts +166 -0
- package/src/stage3d.ts +76 -0
- package/src/web-worker.ts +24 -0
- package/src/websocket.ts +32 -0
- package/src/workers.ts +255 -0
|
@@ -0,0 +1,2644 @@
|
|
|
1
|
+
// The AVM2 runtime generated modules call as `rt`: the object model, name
|
|
2
|
+
// lookup, classes and scripts, as avmplus implements them.
|
|
3
|
+
//
|
|
4
|
+
// Objects are JavaScript objects made from their traits' prototype, which
|
|
5
|
+
// holds their methods as $m<dispatch id>, their traits as $traits, and $p,
|
|
6
|
+
// the AS3 prototype object their dynamic lookups continue on. Slots are own
|
|
7
|
+
// fields $<slot id>, and dynamic properties are kept apart from both, in $d.
|
|
8
|
+
// A class object is made the same way from its static traits, and holds its
|
|
9
|
+
// instances' traits in $it.
|
|
10
|
+
//
|
|
11
|
+
// Layouts come from the module, computed by the compiler: the runtime never
|
|
12
|
+
// derives one (docs/architecture/compiler.md, "Modules and the bootstrap").
|
|
13
|
+
import { API_VERSION, checkApiVersion } from "../../format/index.js";
|
|
14
|
+
import { AmfClasses } from "./amf-classes.js";
|
|
15
|
+
import { ArrayConversion } from "./array-conversion.js";
|
|
16
|
+
import { fillCache } from "./cache-fill.js";
|
|
17
|
+
import { newClass, specializeVector, withId } from "./classes.js";
|
|
18
|
+
import { classNamed, classNamedByCode, definingAbc, definitionNamed } from "./definitions.js";
|
|
19
|
+
import { NOT_FOUND, } from "./descriptors.js";
|
|
20
|
+
import { NAMED } from "./dictionary-keys.js";
|
|
21
|
+
import { compileUnit, Domain, definitionNames, findScript } from "./domain.js";
|
|
22
|
+
import { isViewRangeError, SharedMemoryView } from "./domain-memory.js";
|
|
23
|
+
import { continues, dictionaryAt, elementsAt, enumerated, INT_ATOM_LIMIT, nextIndex, ownNames, pairIndex, pairOf, walkless, } from "./enumeration.js";
|
|
24
|
+
import { AsError, describe, errorMessage, stackOf } from "./errors.js";
|
|
25
|
+
import { FloatValue, floatValue } from "./float.js";
|
|
26
|
+
import { hookedBinding } from "./hooks.js";
|
|
27
|
+
import { installMethod, nativeFactory, noBodyFactory, unverifiedFactory, verifyErrorFactory, } from "./method-factories.js";
|
|
28
|
+
import { Modules } from "./modules.js";
|
|
29
|
+
import { arrayIndex, CONSTANT_Multiname, CONSTANT_MultinameA, CONSTANT_MultinameL, CONSTANT_MultinameLA, CONSTANT_Qname, CONSTANT_RTQname, CONSTANT_RTQnameA, CONSTANT_RTQnameL, CONSTANT_RTQnameLA, Multiname, Namespace, NS_Private, NS_Public, namespace, prefixedNamespace, prefixOf, publicNs, publicQname, qname, TypeName, } from "./names.js";
|
|
30
|
+
import { FloatVector, setFloatElement } from "./natives/float-vector.js";
|
|
31
|
+
import { storeDouble, storeInt, storeObject, } from "./natives/vector-elements.js";
|
|
32
|
+
import { escapeAttributeValue, escapeElementValue } from "./natives/xml/escape.js";
|
|
33
|
+
import { numberToString, stringToNumber } from "./number-strings.js";
|
|
34
|
+
import { defaultPrint, memoryFiles, } from "./options.js";
|
|
35
|
+
import { cached, epoch, IC_Call, IC_Const, IC_Dynamic, IC_Get, IC_GetSet, IC_Method, IC_Set, IC_Slot, invalidate, NO_CACHE, REPLACEMENTS, UNFILLED, } from "./property-cache.js";
|
|
36
|
+
import { BIND_Const, BIND_Get, BIND_GetSet, BIND_Method, BIND_Set, BIND_Var, boundKey, ClassRef, methodKey, slotKey, Traits, untypedSetKey, VectorRef, } from "./traits.js";
|
|
37
|
+
export { NOT_FOUND } from "./descriptors.js";
|
|
38
|
+
/**
|
|
39
|
+
* A sealed Array subclass's elements from SWF 13, as avmplus' ArrayObject
|
|
40
|
+
* keeps none for one: never any. Shared and frozen; what writes elements
|
|
41
|
+
* checks for it, and fails as a sealed object does.
|
|
42
|
+
*/
|
|
43
|
+
export const SEALED_ELEMENTS = Object.freeze([]);
|
|
44
|
+
/** The value of `o`'s dynamic property `name`, or NOT_FOUND. */
|
|
45
|
+
function dynamicValue(o, name) {
|
|
46
|
+
const d = o.$d;
|
|
47
|
+
if (!d) {
|
|
48
|
+
return NOT_FOUND;
|
|
49
|
+
}
|
|
50
|
+
const value = d.get(name);
|
|
51
|
+
return value !== undefined || d.has(name) ? value : NOT_FOUND;
|
|
52
|
+
}
|
|
53
|
+
export class Runtime {
|
|
54
|
+
classHooks;
|
|
55
|
+
print;
|
|
56
|
+
debugger;
|
|
57
|
+
compileAbc;
|
|
58
|
+
files;
|
|
59
|
+
/** See RuntimeOptions.workers and worker. */
|
|
60
|
+
workerHost;
|
|
61
|
+
workerInit;
|
|
62
|
+
/** See RuntimeOptions.sync. */
|
|
63
|
+
syncInit;
|
|
64
|
+
/** See RuntimeOptions.swfVersion. */
|
|
65
|
+
swfVersion;
|
|
66
|
+
/** See RuntimeOptions.apiVersion. */
|
|
67
|
+
apiVersion;
|
|
68
|
+
/** The versions of a name user code makes from a string (publicQname): the one list, made once. */
|
|
69
|
+
userVersions;
|
|
70
|
+
/** JSON.stringify's toJSON, at user code's version, made once. */
|
|
71
|
+
toJSONName;
|
|
72
|
+
/**
|
|
73
|
+
* What [[DefaultValue]] calls, in each hint's order: toString and valueOf
|
|
74
|
+
* at user code's version, made once, so that their caches keep the
|
|
75
|
+
* methods of the traits converted most, as a Dictionary's object keys.
|
|
76
|
+
*/
|
|
77
|
+
stringPrimitiveOrder;
|
|
78
|
+
numberPrimitiveOrder;
|
|
79
|
+
natives;
|
|
80
|
+
/** The root application domain, the builtins' and the main SWF's; and the one modules load into now. */
|
|
81
|
+
root = new Domain(null, 0);
|
|
82
|
+
loading = this.root;
|
|
83
|
+
/** The modules loaded, and the domains of their code. */
|
|
84
|
+
modules = new Modules();
|
|
85
|
+
loadingBuiltin = false;
|
|
86
|
+
/** Whether a domain other than the root exists. */
|
|
87
|
+
children = false;
|
|
88
|
+
/** Vector.<T>'s references, by T's. */
|
|
89
|
+
vectorRefs = new Map();
|
|
90
|
+
/**
|
|
91
|
+
* The domain memory the domain memory instructions use: the ByteArray set
|
|
92
|
+
* as it, or, as avmplus' DomainEnv, 1024 bytes of scratch memory.
|
|
93
|
+
*/
|
|
94
|
+
scratchMemory = new DataView(new ArrayBuffer(1024));
|
|
95
|
+
/** The domain memory, and its length kept with it for mops: fields, not an accessor and DataView's getter. */
|
|
96
|
+
memoryView = this.scratchMemory;
|
|
97
|
+
memoryLength = this.scratchMemory.byteLength;
|
|
98
|
+
/**
|
|
99
|
+
* What generated code loads and stores in place through, at an int or
|
|
100
|
+
* uint address: the domain memory itself, whose own range check throws
|
|
101
|
+
* the RangeError memoryError makes avmplus'. Or, where another worker
|
|
102
|
+
* shares the memory, a view that reads its length again before it
|
|
103
|
+
* rejects an address, as mops does.
|
|
104
|
+
*/
|
|
105
|
+
view = this.scratchMemory;
|
|
106
|
+
memoryProvider = null;
|
|
107
|
+
refresh = null;
|
|
108
|
+
/** ByteArray.defaultObjectEncoding: AMF3 until set. */
|
|
109
|
+
defaultObjectEncoding = 3;
|
|
110
|
+
/** ObjectEncoding.dynamicPropertyWriter: what writes a dynamic object's own properties in AMF3, if anything. */
|
|
111
|
+
dynamicPropertyWriter = null;
|
|
112
|
+
/** Class aliases and the classes AMF makes. */
|
|
113
|
+
amfClasses = new AmfClasses(this);
|
|
114
|
+
/** The builtin classes' traits, made before their classes so the bootstrap can refer to them. */
|
|
115
|
+
objectTraits;
|
|
116
|
+
classTraits;
|
|
117
|
+
functionTraits;
|
|
118
|
+
/**
|
|
119
|
+
* Method closures, by receiver and method, so that o.f === o.f; by the
|
|
120
|
+
* method, not its dispatch id, which an override shares with the method
|
|
121
|
+
* super.f names, a closure of its own.
|
|
122
|
+
*/
|
|
123
|
+
closures = new WeakMap();
|
|
124
|
+
builtinTraitsByName = new Map();
|
|
125
|
+
/** The primitives' traits, once a lookup has needed them, for the caches (receiverTraits). */
|
|
126
|
+
stringTraits = undefined;
|
|
127
|
+
numberTraits = undefined;
|
|
128
|
+
booleanTraits = undefined;
|
|
129
|
+
/** The names for-ins go through, per object (see Enumeration). */
|
|
130
|
+
enumerating = new WeakMap();
|
|
131
|
+
/** Where hasNextIn leaves the object and the index a for-in goes on from. */
|
|
132
|
+
enumObject = null;
|
|
133
|
+
enumIndex = 0;
|
|
134
|
+
/** Special traits: an activation's or a catch scope's, by descriptor. */
|
|
135
|
+
scopeTraits = new WeakMap();
|
|
136
|
+
specialized = new Map();
|
|
137
|
+
empty = Object.assign([], { w: 0 });
|
|
138
|
+
/**
|
|
139
|
+
* `natives` are the natives by name, or a provider that makes them for
|
|
140
|
+
* this runtime, so that a natives module can close over its runtime (as a
|
|
141
|
+
* class of natives does, see natives/define.ts). The provider runs once,
|
|
142
|
+
* when the runtime is made; what it returns is read when modules bind.
|
|
143
|
+
*/
|
|
144
|
+
constructor(natives, classHooks, options = {}) {
|
|
145
|
+
this.classHooks = classHooks;
|
|
146
|
+
this.print = options.print ?? defaultPrint;
|
|
147
|
+
this.debugger = options.debugger ?? false;
|
|
148
|
+
this.compileAbc = options.compileAbc ?? null;
|
|
149
|
+
this.files = options.files ?? memoryFiles();
|
|
150
|
+
this.workerHost = options.workers ?? null;
|
|
151
|
+
this.workerInit = options.worker ?? null;
|
|
152
|
+
this.syncInit = options.sync ?? null;
|
|
153
|
+
this.swfVersion = options.swfVersion ?? 31;
|
|
154
|
+
this.apiVersion = checkApiVersion(options.apiVersion ?? API_VERSION);
|
|
155
|
+
this.userVersions = [this.apiVersion];
|
|
156
|
+
this.toJSONName = publicQname("toJSON", this.userVersions);
|
|
157
|
+
const toStringName = publicQname("toString", this.userVersions);
|
|
158
|
+
const valueOfName = publicQname("valueOf", this.userVersions);
|
|
159
|
+
toStringName.cache = UNFILLED;
|
|
160
|
+
valueOfName.cache = UNFILLED;
|
|
161
|
+
this.stringPrimitiveOrder = [toStringName, valueOfName];
|
|
162
|
+
this.numberPrimitiveOrder = [valueOfName, toStringName];
|
|
163
|
+
this.objectTraits = new Traits("Object", null);
|
|
164
|
+
this.objectTraits.dynamic = true;
|
|
165
|
+
this.objectTraits.testsValues = true;
|
|
166
|
+
this.classTraits = new Traits("Class", this.objectTraits);
|
|
167
|
+
this.functionTraits = new Traits("Function", this.objectTraits);
|
|
168
|
+
this.functionTraits.dynamic = true;
|
|
169
|
+
this.natives = typeof natives === "function" ? natives(this) : natives;
|
|
170
|
+
}
|
|
171
|
+
/** Empty the inline caches, so that they keep no traits or code of what is being let go of. */
|
|
172
|
+
forgetCaches() {
|
|
173
|
+
invalidate();
|
|
174
|
+
}
|
|
175
|
+
// Names.
|
|
176
|
+
ns(kind, uri) {
|
|
177
|
+
return namespace(kind, uri);
|
|
178
|
+
}
|
|
179
|
+
privateNs(uri) {
|
|
180
|
+
return new Namespace(5, uri);
|
|
181
|
+
}
|
|
182
|
+
name(N, V, kind, indices, name) {
|
|
183
|
+
const attribute = kind === 0x0d || kind === 0x10 || kind === 0x12 || kind === 0x0e || kind === 0x1c;
|
|
184
|
+
const mn = new Multiname(kind, indices.map((i) => N[i]), indices.map((i) => V[i]), name, attribute);
|
|
185
|
+
mn.domain = this.loading === this.root ? null : this.loading;
|
|
186
|
+
mn.cache = UNFILLED;
|
|
187
|
+
return mn;
|
|
188
|
+
}
|
|
189
|
+
/** A domain whose definitions are looked up after `parent`'s, as `new ApplicationDomain(parent)`. */
|
|
190
|
+
childDomain(parent = this.root) {
|
|
191
|
+
this.children = true;
|
|
192
|
+
return this.modules.newDomain(parent);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* The domain of the innermost code on the stack that a module defines,
|
|
196
|
+
* as avmplus' AvmCore::codeContext; the root without one (see
|
|
197
|
+
* Modules.domainOf). The stack is taken here, so that it has as many of
|
|
198
|
+
* the caller's frames as the engine keeps.
|
|
199
|
+
*/
|
|
200
|
+
codeDomain() {
|
|
201
|
+
if (!this.children) {
|
|
202
|
+
return this.root;
|
|
203
|
+
}
|
|
204
|
+
return this.modules.domainOf(new Error().stack) ?? this.root;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* `f`, which loads modules, with what it loads going into `domain`;
|
|
208
|
+
* `builtin` for a player's own, whose code is not a domain's to
|
|
209
|
+
* codeDomain, as avmplus skips builtin frames for the code context.
|
|
210
|
+
*/
|
|
211
|
+
loadInto(domain, f, builtin = false) {
|
|
212
|
+
const previous = this.loading;
|
|
213
|
+
const wasBuiltin = this.loadingBuiltin;
|
|
214
|
+
this.loading = domain;
|
|
215
|
+
this.loadingBuiltin = builtin;
|
|
216
|
+
try {
|
|
217
|
+
return f();
|
|
218
|
+
}
|
|
219
|
+
finally {
|
|
220
|
+
this.loading = previous;
|
|
221
|
+
this.loadingBuiltin = wasBuiltin;
|
|
222
|
+
if (this.children) {
|
|
223
|
+
this.modules.locate();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
typeName(_N, _V, _S, base, param) {
|
|
228
|
+
return new TypeName(base, [param]);
|
|
229
|
+
}
|
|
230
|
+
/** A multiname with its runtime namespace and name, from the stack. */
|
|
231
|
+
runtimeName(mn, ...parts) {
|
|
232
|
+
let namespaces = mn.namespaces;
|
|
233
|
+
let versions = mn.versions;
|
|
234
|
+
let k = 0;
|
|
235
|
+
if (mn.runtimeNs) {
|
|
236
|
+
const ns = parts[k++];
|
|
237
|
+
namespaces = [this.namespaceOf(ns)];
|
|
238
|
+
versions = [255];
|
|
239
|
+
}
|
|
240
|
+
const kind = mn.kind === CONSTANT_RTQname ||
|
|
241
|
+
mn.kind === CONSTANT_RTQnameA ||
|
|
242
|
+
mn.kind === CONSTANT_RTQnameL ||
|
|
243
|
+
mn.kind === CONSTANT_RTQnameLA
|
|
244
|
+
? CONSTANT_Qname
|
|
245
|
+
: mn.kind;
|
|
246
|
+
let name = mn.name;
|
|
247
|
+
if (mn.runtimeName) {
|
|
248
|
+
const part = parts[k];
|
|
249
|
+
if (part?.$local !== undefined && !(part instanceof Namespace)) {
|
|
250
|
+
// A Proxy's QName of a multiname names its namespaces still.
|
|
251
|
+
if (part.$mn) {
|
|
252
|
+
return part.$mn;
|
|
253
|
+
}
|
|
254
|
+
// A QName names its own namespace, null for any, and local name,
|
|
255
|
+
// null for any, and may be an attribute's.
|
|
256
|
+
// Bindings compare interned namespaces: an XML name's has a prefix.
|
|
257
|
+
const qualified = new Multiname(CONSTANT_Qname, [part.$ns ? part.$ns.interned : null], [255], part.$local, mn.attribute || part.$attr === true);
|
|
258
|
+
qualified.domain = mn.domain;
|
|
259
|
+
return qualified;
|
|
260
|
+
}
|
|
261
|
+
else if (typeof part === "object" && part !== null && !(part instanceof FloatValue)) {
|
|
262
|
+
// Its string only once a lookup needs it: a Dictionary does not.
|
|
263
|
+
const keyed = Multiname.keyed(kind, namespaces, versions, part, mn.attribute, this.keyName);
|
|
264
|
+
keyed.domain = mn.domain;
|
|
265
|
+
return keyed;
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
name = typeof part === "string" ? part : this.toString(part);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const named = new Multiname(kind, namespaces, versions, name, mn.attribute);
|
|
272
|
+
named.domain = mn.domain;
|
|
273
|
+
return named;
|
|
274
|
+
}
|
|
275
|
+
/** An object's string, as the name of an object that is not a Dictionary. */
|
|
276
|
+
keyName = (key) => this.toString(key);
|
|
277
|
+
/** The runtime namespace a Namespace value stands for. */
|
|
278
|
+
namespaceOf(value) {
|
|
279
|
+
if (value instanceof Namespace) {
|
|
280
|
+
return value.interned;
|
|
281
|
+
}
|
|
282
|
+
if (value && value.$ns instanceof Namespace) {
|
|
283
|
+
return value.$ns.interned;
|
|
284
|
+
}
|
|
285
|
+
throw this.error("TypeError", 1034, this.describe(value), "Namespace");
|
|
286
|
+
}
|
|
287
|
+
/** A Namespace constant, as the AS3 Namespace object it is. */
|
|
288
|
+
namespace(ns) {
|
|
289
|
+
return ns;
|
|
290
|
+
}
|
|
291
|
+
cls(ns, name) {
|
|
292
|
+
const domain = this.loading;
|
|
293
|
+
let byName = domain.classRefs.get(ns);
|
|
294
|
+
if (!byName) {
|
|
295
|
+
byName = new Map();
|
|
296
|
+
domain.classRefs.set(ns, byName);
|
|
297
|
+
}
|
|
298
|
+
let ref = byName.get(name);
|
|
299
|
+
if (!ref) {
|
|
300
|
+
ref = new ClassRef(ns, name, domain);
|
|
301
|
+
byName.set(name, ref);
|
|
302
|
+
}
|
|
303
|
+
return ref;
|
|
304
|
+
}
|
|
305
|
+
vector(param) {
|
|
306
|
+
let ref = this.vectorRefs.get(param);
|
|
307
|
+
if (!ref) {
|
|
308
|
+
ref = new VectorRef(param);
|
|
309
|
+
this.vectorRefs.set(param, ref);
|
|
310
|
+
}
|
|
311
|
+
return ref;
|
|
312
|
+
}
|
|
313
|
+
// Modules and scripts.
|
|
314
|
+
/** Load a module: its scripts' names become visible; the entry script of a non-builtin module runs. */
|
|
315
|
+
abc(desc) {
|
|
316
|
+
// The stack taken here has this frame first and the module's factory second.
|
|
317
|
+
return this.modules.load(desc, this.loading, this.loadingBuiltin ? null : new Error());
|
|
318
|
+
}
|
|
319
|
+
/** Run a module's entry point, its last script, as avmshell does. */
|
|
320
|
+
run(abc) {
|
|
321
|
+
const scripts = abc.scriptStates;
|
|
322
|
+
this.initScript(scripts[scripts.length - 1]);
|
|
323
|
+
}
|
|
324
|
+
/** The global object of a script, made the first time it is needed. */
|
|
325
|
+
globalOf(script) {
|
|
326
|
+
if (!script.global) {
|
|
327
|
+
if (script.desc.traits.error) {
|
|
328
|
+
throw this.error("VerifyError", script.desc.traits.error);
|
|
329
|
+
}
|
|
330
|
+
const traits = new Traits("global", this.objectTraits);
|
|
331
|
+
traits.dynamic = true;
|
|
332
|
+
traits.isGlobal = true;
|
|
333
|
+
traits.describe(script.desc.traits);
|
|
334
|
+
const g = traits.instance();
|
|
335
|
+
// As the script's initializer, its methods run in an empty scope chain,
|
|
336
|
+
// as avmplus' script traits' declaring scope is, and as the compiler
|
|
337
|
+
// indexes the scopes their closures capture: the global object is
|
|
338
|
+
// only what they push.
|
|
339
|
+
for (const [d, factory, id, , params] of script.desc.traits.methods) {
|
|
340
|
+
installMethod(this, traits.methodHome(3), d, withId(factory(this.empty, null), id), factory, params);
|
|
341
|
+
}
|
|
342
|
+
// Caches keep the methods.
|
|
343
|
+
invalidate();
|
|
344
|
+
script.global = g;
|
|
345
|
+
}
|
|
346
|
+
return script.global;
|
|
347
|
+
}
|
|
348
|
+
/** Run a script's initializer, once. */
|
|
349
|
+
initScript(script, retry = false) {
|
|
350
|
+
// As avmplus' Toplevel, which is made from the script defining Object
|
|
351
|
+
// before any other runs: builtin scripts refer to each other, as the
|
|
352
|
+
// one defining Object makes XML while XML's needs Object.
|
|
353
|
+
if (!this.toplevelReady) {
|
|
354
|
+
this.toplevelReady = true;
|
|
355
|
+
const toplevel = this.findScript(publicQname("Object", this.userVersions));
|
|
356
|
+
this.toplevel = toplevel;
|
|
357
|
+
if (toplevel && toplevel !== script) {
|
|
358
|
+
this.initScript(toplevel);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const g = this.globalOf(script);
|
|
362
|
+
if (script.state === 0 || (retry && script.state === 3)) {
|
|
363
|
+
script.state = 1;
|
|
364
|
+
try {
|
|
365
|
+
script.desc.init(this.empty, null).call(g);
|
|
366
|
+
}
|
|
367
|
+
catch (e) {
|
|
368
|
+
script.state = 3;
|
|
369
|
+
throw e;
|
|
370
|
+
}
|
|
371
|
+
script.state = 2;
|
|
372
|
+
if (script === this.toplevel) {
|
|
373
|
+
this.arrayConversion.noteConversions();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return g;
|
|
377
|
+
}
|
|
378
|
+
toplevelReady = false;
|
|
379
|
+
toplevel = null;
|
|
380
|
+
/**
|
|
381
|
+
* The script that defines `mn`, kept on the multiname once found: the
|
|
382
|
+
* first definition of a name wins, so later modules cannot change it.
|
|
383
|
+
*/
|
|
384
|
+
definingScript(mn) {
|
|
385
|
+
const known = mn.script;
|
|
386
|
+
if (known) {
|
|
387
|
+
return known;
|
|
388
|
+
}
|
|
389
|
+
const script = this.findScript(mn);
|
|
390
|
+
mn.script = script;
|
|
391
|
+
return script;
|
|
392
|
+
}
|
|
393
|
+
/** The script that defines `mn` in its domain, or null (see findScript in domain.ts). */
|
|
394
|
+
findScript(mn, asType = false) {
|
|
395
|
+
return findScript(mn.domain ?? this.root, mn, asType);
|
|
396
|
+
}
|
|
397
|
+
/** What an ABC loaded into `domain` now compiles in. */
|
|
398
|
+
compileUnit(domain) {
|
|
399
|
+
return compileUnit(domain);
|
|
400
|
+
}
|
|
401
|
+
// Scopes and name lookup.
|
|
402
|
+
/** The scope chain a function or class made here runs in: the chain captured, then the method's own scopes. */
|
|
403
|
+
scope(outer, locals, withs) {
|
|
404
|
+
const chain = outer.concat(locals);
|
|
405
|
+
chain.w = outer.w | (withs << outer.length);
|
|
406
|
+
return chain;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* The global object of the script that defines `mn`, run first if it has
|
|
410
|
+
* not run. A module reads `mn.global` before calling this: once set it
|
|
411
|
+
* stays right, as the defining script never changes and initScript
|
|
412
|
+
* returns its global object without running it again.
|
|
413
|
+
*/
|
|
414
|
+
findDef(mn) {
|
|
415
|
+
const script = this.definingScript(mn);
|
|
416
|
+
if (!script) {
|
|
417
|
+
throw this.error("ReferenceError", 1065, mn.toString());
|
|
418
|
+
}
|
|
419
|
+
const g = this.initScript(script);
|
|
420
|
+
mn.global = g;
|
|
421
|
+
return g;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* As MethodEnv::findproperty: the scope that has `mn`, from the innermost,
|
|
425
|
+
* a with scope by any property and another by its traits; then a script
|
|
426
|
+
* that defines it; then the global object's own properties.
|
|
427
|
+
*/
|
|
428
|
+
findProperty(mn, outer, locals, withs, strict = false) {
|
|
429
|
+
for (let i = locals.length - 1; i >= 0; i--) {
|
|
430
|
+
if (this.scopeHas(locals[i], mn, (withs >> i) & 1)) {
|
|
431
|
+
return locals[i];
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
for (let i = outer.length - 1; i >= 0; i--) {
|
|
435
|
+
if (this.scopeHas(outer[i], mn, (outer.w >> i) & 1)) {
|
|
436
|
+
return outer[i];
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return this.global(mn, outer.length ? outer[0] : locals[0], strict);
|
|
440
|
+
}
|
|
441
|
+
findPropertyStrict(mn, outer, locals, withs) {
|
|
442
|
+
return this.findProperty(mn, outer, locals, withs, true);
|
|
443
|
+
}
|
|
444
|
+
findGlobal(mn, global) {
|
|
445
|
+
return this.global(mn, global, false);
|
|
446
|
+
}
|
|
447
|
+
findGlobalStrict(mn, global) {
|
|
448
|
+
return this.global(mn, global, true);
|
|
449
|
+
}
|
|
450
|
+
global(mn, global, strict) {
|
|
451
|
+
const script = this.definingScript(mn);
|
|
452
|
+
if (script) {
|
|
453
|
+
const g = this.initScript(script);
|
|
454
|
+
mn.global = g;
|
|
455
|
+
return g;
|
|
456
|
+
}
|
|
457
|
+
if (global != null && this.hasProperty(global, mn)) {
|
|
458
|
+
return global;
|
|
459
|
+
}
|
|
460
|
+
if (strict) {
|
|
461
|
+
throw this.error("ReferenceError", 1065, mn.toString());
|
|
462
|
+
}
|
|
463
|
+
return global;
|
|
464
|
+
}
|
|
465
|
+
scopeHas(o, mn, isWith) {
|
|
466
|
+
if (isWith) {
|
|
467
|
+
return this.withHas(o, mn);
|
|
468
|
+
}
|
|
469
|
+
return this.traitsOf(o).find(mn) !== 0;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* As MethodEnv::findWithProperty: a with scope has `mn` if it, or an
|
|
473
|
+
* object on its prototype chain, binds it in its traits or has it itself.
|
|
474
|
+
* An E4X filter asks this of every item, and finds XML's methods on
|
|
475
|
+
* XML.prototype.
|
|
476
|
+
*/
|
|
477
|
+
withHas(o, mn) {
|
|
478
|
+
if (this.delegateHas(o, mn, true)) {
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
// An activation or a catch scope has no prototype.
|
|
482
|
+
for (let p = this.protoOf(o); p; p = p.$p) {
|
|
483
|
+
if (this.delegateHas(p, mn, false)) {
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Whether `d` binds `mn` in its traits, which no attribute is, or has it
|
|
491
|
+
* itself, as hasMultinameProperty: the scope object a key of a
|
|
492
|
+
* Dictionary, what a hooked class says (an XML's children and
|
|
493
|
+
* attributes, a Proxy's hasProperty), an element or a dynamic property;
|
|
494
|
+
* a prototype on its chain an element or a property of its own.
|
|
495
|
+
*/
|
|
496
|
+
delegateHas(d, mn, scope) {
|
|
497
|
+
const traits = this.traitsOf(d);
|
|
498
|
+
if (!mn.attribute && traits.find(mn) !== 0) {
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
if (!scope) {
|
|
502
|
+
const name = mn.dynamicName();
|
|
503
|
+
return name !== null && this.protoOwn(d, name) !== NOT_FOUND;
|
|
504
|
+
}
|
|
505
|
+
if (mn.key !== undefined && d?.$keys !== undefined) {
|
|
506
|
+
if (d.$keys.has(mn.key)) {
|
|
507
|
+
return true;
|
|
508
|
+
}
|
|
509
|
+
const named = this.namespaceKeyName(mn);
|
|
510
|
+
return named !== null && this.delegateHas(d, named, scope);
|
|
511
|
+
}
|
|
512
|
+
if (traits.properties !== null) {
|
|
513
|
+
return traits.properties.has(this, d, mn);
|
|
514
|
+
}
|
|
515
|
+
const name = mn.dynamicName();
|
|
516
|
+
if (name === null) {
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
return this.indexHas(d, name) ?? this.getOwn(d, name) !== NOT_FOUND;
|
|
520
|
+
}
|
|
521
|
+
// Properties.
|
|
522
|
+
/** The traits of any value: a primitive's are its class's. */
|
|
523
|
+
traitsOf(v) {
|
|
524
|
+
switch (typeof v) {
|
|
525
|
+
case "object":
|
|
526
|
+
case "function":
|
|
527
|
+
if (v === null) {
|
|
528
|
+
throw this.error("TypeError", 1009);
|
|
529
|
+
}
|
|
530
|
+
return v instanceof FloatValue
|
|
531
|
+
? this.builtinTraits("float")
|
|
532
|
+
: v instanceof Namespace
|
|
533
|
+
? this.builtinTraits("Namespace")
|
|
534
|
+
: v.$traits;
|
|
535
|
+
// As avmplus' toVTable: every number is a Number at run time, int or
|
|
536
|
+
// not; int's and uint's traits only bind early, from static types.
|
|
537
|
+
case "number":
|
|
538
|
+
return this.builtinTraits("Number");
|
|
539
|
+
case "string":
|
|
540
|
+
return this.builtinTraits("String");
|
|
541
|
+
case "boolean":
|
|
542
|
+
return this.builtinTraits("Boolean");
|
|
543
|
+
default:
|
|
544
|
+
throw this.error("TypeError", 1010);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* The traits a cache knows `v` by, as traitsOf's, without a lookup:
|
|
549
|
+
* undefined for null, undefined, a Namespace (whose traits are not its
|
|
550
|
+
* own) and a primitive before its class's traits are known.
|
|
551
|
+
*/
|
|
552
|
+
receiverTraits(v) {
|
|
553
|
+
switch (typeof v) {
|
|
554
|
+
case "object":
|
|
555
|
+
case "function":
|
|
556
|
+
return v instanceof FloatValue
|
|
557
|
+
? this.builtinTraits("float")
|
|
558
|
+
: v === null
|
|
559
|
+
? undefined
|
|
560
|
+
: v.$traits;
|
|
561
|
+
case "string":
|
|
562
|
+
return this.stringTraits;
|
|
563
|
+
case "number":
|
|
564
|
+
return this.numberTraits;
|
|
565
|
+
case "boolean":
|
|
566
|
+
return this.booleanTraits;
|
|
567
|
+
default:
|
|
568
|
+
return undefined;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/** A builtin class's instance traits, by name, resolved once. */
|
|
572
|
+
builtinTraits(name) {
|
|
573
|
+
let traits = this.builtinTraitsByName.get(name);
|
|
574
|
+
if (!traits) {
|
|
575
|
+
traits = this.builtinClass(name).$it;
|
|
576
|
+
this.builtinTraitsByName.set(name, traits);
|
|
577
|
+
if (name === "String") {
|
|
578
|
+
this.stringTraits = traits;
|
|
579
|
+
}
|
|
580
|
+
else if (name === "Number") {
|
|
581
|
+
this.numberTraits = traits;
|
|
582
|
+
}
|
|
583
|
+
else if (name === "Boolean") {
|
|
584
|
+
this.booleanTraits = traits;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return traits;
|
|
588
|
+
}
|
|
589
|
+
/** A public class of the builtins, by name, kept once resolved. */
|
|
590
|
+
builtinClass(name) {
|
|
591
|
+
let cls = this.builtinClasses.get(name);
|
|
592
|
+
if (!cls) {
|
|
593
|
+
cls = this.resolve(this.cls(publicNs, name));
|
|
594
|
+
this.builtinClasses.set(name, cls);
|
|
595
|
+
}
|
|
596
|
+
return cls;
|
|
597
|
+
}
|
|
598
|
+
builtinClasses = new Map();
|
|
599
|
+
/** What Number(array) runs unless a script replaced it. */
|
|
600
|
+
arrayConversion = new ArrayConversion();
|
|
601
|
+
/** The builtin Array class's instance traits, once its static initializer has run. */
|
|
602
|
+
arrayTraits = null;
|
|
603
|
+
/** Notes the builtin Array class, once its static initializer has run. */
|
|
604
|
+
noteArrayClass(cls) {
|
|
605
|
+
this.arrayTraits = cls.$it;
|
|
606
|
+
this.arrayConversion.noteArrayClass(cls);
|
|
607
|
+
}
|
|
608
|
+
prototypeOf(ref) {
|
|
609
|
+
return this.classOf(ref).$it.proto;
|
|
610
|
+
}
|
|
611
|
+
// Where the runtime calls a function for a SWF's code, a getter, a
|
|
612
|
+
// method or a function value, or calls on to the runtime's own function
|
|
613
|
+
// that does, it never returns the call directly but through a variable
|
|
614
|
+
// assigned apart (`let r; r = f(); return r;`). JavaScriptCore makes a
|
|
615
|
+
// strict `return f()` a proper tail call, which drops the caller's frame,
|
|
616
|
+
// so that the stack a security check reads would lose the runtime's
|
|
617
|
+
// frames between a SWF's code and the function it called through them;
|
|
618
|
+
// minifiers fold `const r = f(); return r;` back into `return f()`,
|
|
619
|
+
// but keep this form (as `return r = f(), r`).
|
|
620
|
+
getProperty(o, mn) {
|
|
621
|
+
let r;
|
|
622
|
+
const e = cached(this.receiverTraits(o), mn);
|
|
623
|
+
if (e !== null) {
|
|
624
|
+
switch (e.kind) {
|
|
625
|
+
case IC_Slot:
|
|
626
|
+
case IC_Const:
|
|
627
|
+
return o[e.key];
|
|
628
|
+
case IC_Get:
|
|
629
|
+
case IC_GetSet:
|
|
630
|
+
r = e.get.call(o);
|
|
631
|
+
return r;
|
|
632
|
+
case IC_Method:
|
|
633
|
+
return this.methodClosure(o, e.traits, e.id);
|
|
634
|
+
case IC_Dynamic: {
|
|
635
|
+
const d = o.$d;
|
|
636
|
+
if (d) {
|
|
637
|
+
const v = d.get(e.key);
|
|
638
|
+
if (v !== undefined || d.has(e.key)) {
|
|
639
|
+
return v;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
// Not its own: its prototypes', as a method on Array.prototype.
|
|
643
|
+
if (mn.key === undefined) {
|
|
644
|
+
const v = this.protoValue(o, e.key);
|
|
645
|
+
if (v !== NOT_FOUND) {
|
|
646
|
+
return v;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
// A Dictionary's object key, before its traits, as DictionaryObject's.
|
|
653
|
+
if (mn.key !== undefined && o?.$keys !== undefined) {
|
|
654
|
+
const v = o.$keys.get(mn.key);
|
|
655
|
+
if (v !== undefined) {
|
|
656
|
+
return v;
|
|
657
|
+
}
|
|
658
|
+
const named = this.namespaceKeyName(mn);
|
|
659
|
+
return named === null ? undefined : this.getProperty(o, named);
|
|
660
|
+
}
|
|
661
|
+
const traits = this.traitsOf(o);
|
|
662
|
+
const b = traits.find(mn);
|
|
663
|
+
this.fill(o, traits, b, mn);
|
|
664
|
+
if (traits.properties !== null && hookedBinding(b, mn, traits.properties)) {
|
|
665
|
+
return traits.properties.get(this, o, mn);
|
|
666
|
+
}
|
|
667
|
+
if (b !== 0) {
|
|
668
|
+
return this.getBound(o, traits, b, mn);
|
|
669
|
+
}
|
|
670
|
+
const name = mn.dynamicName();
|
|
671
|
+
if (name !== null) {
|
|
672
|
+
const own = this.getOwn(o, name);
|
|
673
|
+
if (own !== NOT_FOUND) {
|
|
674
|
+
return own;
|
|
675
|
+
}
|
|
676
|
+
for (let p = this.protoOf(o); p; p = p.$p) {
|
|
677
|
+
const v = this.protoOwn(p, name);
|
|
678
|
+
if (v !== NOT_FOUND) {
|
|
679
|
+
return v;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
// A dynamic object has any dynamic name, but no other: obj.ns::x throws.
|
|
684
|
+
if (traits.dynamic && !traits.refusesNames && name !== null) {
|
|
685
|
+
return undefined;
|
|
686
|
+
}
|
|
687
|
+
// As ScriptObject::getMultinameProperty: an object's namespace set that
|
|
688
|
+
// is no dynamic name has an error of its own; a primitive's has not.
|
|
689
|
+
const object = typeof o === "object" && o !== null && !(o instanceof Namespace);
|
|
690
|
+
const nsset = object &&
|
|
691
|
+
(mn.kind === CONSTANT_Multiname ||
|
|
692
|
+
mn.kind === CONSTANT_MultinameA ||
|
|
693
|
+
mn.kind === CONSTANT_MultinameL ||
|
|
694
|
+
mn.kind === CONSTANT_MultinameLA);
|
|
695
|
+
throw this.error("ReferenceError", name === null && nsset ? 1081 : 1069, mn.name ?? "*", traits.name);
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* obj[i] for a number i, as avmplus' getUintProperty: a Vector's,
|
|
699
|
+
* ByteArray's or Array's element directly; anything else, or a hole, by
|
|
700
|
+
* the name the number makes.
|
|
701
|
+
*/
|
|
702
|
+
getIndexed(o, mn, i) {
|
|
703
|
+
if (typeof o === "object" &&
|
|
704
|
+
o !== null &&
|
|
705
|
+
i >>> 0 === i &&
|
|
706
|
+
i !== 0xffffffff &&
|
|
707
|
+
mn.elementName) {
|
|
708
|
+
const traits = o.$traits;
|
|
709
|
+
if (traits?.getIndex) {
|
|
710
|
+
return traits.getIndex(o, i, this);
|
|
711
|
+
}
|
|
712
|
+
const a = o.$a;
|
|
713
|
+
if (a !== undefined && i in a) {
|
|
714
|
+
return a[i];
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return this.getProperty(o, this.runtimeName(mn, i));
|
|
718
|
+
}
|
|
719
|
+
/** obj[i] = v for a number i, as avmplus' setUintProperty. */
|
|
720
|
+
setIndexed(o, mn, i, v) {
|
|
721
|
+
if (typeof o === "object" && o !== null && i >>> 0 === i && mn.elementName) {
|
|
722
|
+
// The JIT hands a typed index to setUintProperty even at 2^32-1, which is no
|
|
723
|
+
// property name: a ByteArray fails to grow to it, a Vector is out of range.
|
|
724
|
+
const traits = o.$traits;
|
|
725
|
+
if (traits?.setIndex) {
|
|
726
|
+
traits.setIndex(o, i, v, this);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
if (o.$a !== undefined && o.$a !== SEALED_ELEMENTS && i !== 0xffffffff) {
|
|
730
|
+
o.$a[i] = v;
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
this.setProperty(o, this.runtimeName(mn, i), v);
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Element i of Vector o set to x, already converted, as
|
|
738
|
+
* VectorBaseObject::setUintProperty checks it: against the length and
|
|
739
|
+
* fixedness as they are after the conversion, which can run AS3 that
|
|
740
|
+
* changes them, into the elements the Vector has then, through its
|
|
741
|
+
* kind's store (see vector-elements.ts). A number that is no index, as
|
|
742
|
+
* NaN, is out of range too, as _setDoubleProperty finds it.
|
|
743
|
+
*/
|
|
744
|
+
setElement(o, i, x, store) {
|
|
745
|
+
const a = o.$a;
|
|
746
|
+
if (i >>> 0 !== i || i > a.length || (i === a.length && o.$fixed)) {
|
|
747
|
+
throw this.error("RangeError", 1125, i, a.length);
|
|
748
|
+
}
|
|
749
|
+
store(a, i, x);
|
|
750
|
+
}
|
|
751
|
+
// obj[i] for a Vector the code was compiled against, by the kind of its
|
|
752
|
+
// elements: a function for each, so that each sees one kind of array. As
|
|
753
|
+
// TypedVectorObject's _getDoubleProperty and _setDoubleProperty: an index
|
|
754
|
+
// past the end, or a number that is no index, NaN among them, is a
|
|
755
|
+
// RangeError, a set's after it converts the value (setElement); for
|
|
756
|
+
// anything else, such as a null Vector, getIndexed and setIndexed.
|
|
757
|
+
vectorGetInt(o, mn, i) {
|
|
758
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
759
|
+
const a = o.$a;
|
|
760
|
+
if (i >>> 0 === i && i < a.length) {
|
|
761
|
+
return a[i];
|
|
762
|
+
}
|
|
763
|
+
throw this.error("RangeError", 1125, i, a.length);
|
|
764
|
+
}
|
|
765
|
+
return this.getIndexed(o, mn, i);
|
|
766
|
+
}
|
|
767
|
+
vectorSetInt(o, mn, i, v) {
|
|
768
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
769
|
+
this.setElement(o, i, this.toInt(v), storeInt);
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
this.setIndexed(o, mn, i, v);
|
|
773
|
+
}
|
|
774
|
+
vectorGetUint(o, mn, i) {
|
|
775
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
776
|
+
const a = o.$a;
|
|
777
|
+
if (i >>> 0 === i && i < a.length) {
|
|
778
|
+
return a[i];
|
|
779
|
+
}
|
|
780
|
+
throw this.error("RangeError", 1125, i, a.length);
|
|
781
|
+
}
|
|
782
|
+
return this.getIndexed(o, mn, i);
|
|
783
|
+
}
|
|
784
|
+
vectorSetUint(o, mn, i, v) {
|
|
785
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
786
|
+
this.setElement(o, i, this.toUint(v), storeDouble);
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
this.setIndexed(o, mn, i, v);
|
|
790
|
+
}
|
|
791
|
+
vectorGetDouble(o, mn, i) {
|
|
792
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
793
|
+
const a = o.$a;
|
|
794
|
+
if (i >>> 0 === i && i < a.length) {
|
|
795
|
+
return a[i];
|
|
796
|
+
}
|
|
797
|
+
throw this.error("RangeError", 1125, i, a.length);
|
|
798
|
+
}
|
|
799
|
+
return this.getIndexed(o, mn, i);
|
|
800
|
+
}
|
|
801
|
+
vectorSetDouble(o, mn, i, v) {
|
|
802
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
803
|
+
this.setElement(o, i, this.toNumber(v), storeDouble);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
this.setIndexed(o, mn, i, v);
|
|
807
|
+
}
|
|
808
|
+
vectorGetObject(o, mn, i) {
|
|
809
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
810
|
+
const a = o.$a;
|
|
811
|
+
if (i >>> 0 === i && i < a.length) {
|
|
812
|
+
return a instanceof FloatVector ? this.float(a.data[i]) : a[i];
|
|
813
|
+
}
|
|
814
|
+
throw this.error("RangeError", 1125, i, a.length);
|
|
815
|
+
}
|
|
816
|
+
return this.getIndexed(o, mn, i);
|
|
817
|
+
}
|
|
818
|
+
vectorSetObject(o, mn, i, v) {
|
|
819
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
820
|
+
const value = o.$traits.cls.$convert(this, o.$traits.cls, v);
|
|
821
|
+
if (o.$a instanceof FloatVector) {
|
|
822
|
+
setFloatElement(this, o, i, value);
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
this.setElement(o, i, value, storeObject);
|
|
826
|
+
}
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
this.setIndexed(o, mn, i, v);
|
|
830
|
+
}
|
|
831
|
+
/** Unboxed access for code compiled against Vector.<float>; dynamic access uses its hooks. */
|
|
832
|
+
vectorGetFloat(o, mn, i) {
|
|
833
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
834
|
+
const a = o.$a;
|
|
835
|
+
if (i >>> 0 === i && i < a.length) {
|
|
836
|
+
return a.data[i];
|
|
837
|
+
}
|
|
838
|
+
throw this.error("RangeError", 1125, i, a.length);
|
|
839
|
+
}
|
|
840
|
+
return this.toNumber(this.getIndexed(o, mn, i));
|
|
841
|
+
}
|
|
842
|
+
vectorSetFloat(o, mn, i, v) {
|
|
843
|
+
if (o !== null && o !== undefined && mn.elementName) {
|
|
844
|
+
setFloatElement(this, o, i, this.toNumber(v));
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
this.setIndexed(o, mn, i, v);
|
|
848
|
+
}
|
|
849
|
+
/** An object's own dynamic or indexed property, or NOT_FOUND. */
|
|
850
|
+
getOwn(o, name) {
|
|
851
|
+
if (typeof o !== "object" || o === null) {
|
|
852
|
+
return NOT_FOUND;
|
|
853
|
+
}
|
|
854
|
+
// Elements: a class's own indexing (a Vector's, a ByteArray's), else an Array's.
|
|
855
|
+
const traits = o.$traits;
|
|
856
|
+
if (traits?.getIndex || o.$a !== undefined) {
|
|
857
|
+
const i = traits?.index ? traits.index(o, name, this) : arrayIndex(name);
|
|
858
|
+
if (i >= 0) {
|
|
859
|
+
return traits?.getIndex ? traits.getIndex(o, i, this) : i in o.$a ? o.$a[i] : NOT_FOUND;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
const d = o.$d;
|
|
863
|
+
if (d?.has(name)) {
|
|
864
|
+
return d.get(name);
|
|
865
|
+
}
|
|
866
|
+
return NOT_FOUND;
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* A prototype's own dynamic property `name`, or NOT_FOUND: an element
|
|
870
|
+
* too for one with elements, as Array.prototype, an Array, has them.
|
|
871
|
+
*/
|
|
872
|
+
/**
|
|
873
|
+
* Dynamic property `name` of a prototype of `o`, an object of dynamic
|
|
874
|
+
* traits with no binding of it, or NOT_FOUND: as the full lookup goes on
|
|
875
|
+
* from `o` to its prototypes.
|
|
876
|
+
*/
|
|
877
|
+
protoValue(o, name) {
|
|
878
|
+
for (let p = typeof o === "object" ? o.$p : this.protoOf(o); p; p = p.$p) {
|
|
879
|
+
const v = this.protoOwn(p, name);
|
|
880
|
+
if (v !== NOT_FOUND) {
|
|
881
|
+
return v;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
return NOT_FOUND;
|
|
885
|
+
}
|
|
886
|
+
protoOwn(p, name) {
|
|
887
|
+
const a = p.$a;
|
|
888
|
+
if (a !== undefined) {
|
|
889
|
+
const c = name.charCodeAt(0);
|
|
890
|
+
if (c >= 0x30 && c <= 0x39) {
|
|
891
|
+
const i = arrayIndex(name);
|
|
892
|
+
if (i >= 0) {
|
|
893
|
+
return i in a ? a[i] : NOT_FOUND;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
const d = p.$d;
|
|
898
|
+
if (d) {
|
|
899
|
+
const v = d.get(name);
|
|
900
|
+
if (v !== undefined || d.has(name)) {
|
|
901
|
+
return v;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return NOT_FOUND;
|
|
905
|
+
}
|
|
906
|
+
getBound(o, traits, b, mn) {
|
|
907
|
+
let r;
|
|
908
|
+
const id = b >> 3;
|
|
909
|
+
switch (b & 7) {
|
|
910
|
+
case BIND_Var:
|
|
911
|
+
case BIND_Const:
|
|
912
|
+
return o[slotKey(id)];
|
|
913
|
+
case BIND_Get:
|
|
914
|
+
case BIND_GetSet:
|
|
915
|
+
r = traits.proto[methodKey(id)].call(o);
|
|
916
|
+
return r;
|
|
917
|
+
case BIND_Method:
|
|
918
|
+
return this.methodClosure(o, traits, id);
|
|
919
|
+
case BIND_Set: {
|
|
920
|
+
const slot = traits.hooks?.setOnlySlots?.[mn.name ?? ""];
|
|
921
|
+
if (slot !== undefined) {
|
|
922
|
+
return o[slot];
|
|
923
|
+
}
|
|
924
|
+
throw this.error("ReferenceError", 1077, mn.name ?? "*", traits.name);
|
|
925
|
+
}
|
|
926
|
+
default:
|
|
927
|
+
throw this.error("ReferenceError", 1077, mn.name ?? "*", traits.name);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
/** fillCache (cache-fill.ts), for a name that caches on traits a cache knows `o` by. */
|
|
931
|
+
fill(o, traits, b, mn) {
|
|
932
|
+
const head = mn.cache;
|
|
933
|
+
if (head === NO_CACHE ||
|
|
934
|
+
(head.replaced === REPLACEMENTS && head.epoch === epoch()) ||
|
|
935
|
+
this.receiverTraits(o) !== traits) {
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
fillCache(head, o, traits, b, mn);
|
|
939
|
+
}
|
|
940
|
+
/** Method `id` of `o` bound to it, the same function each time. */
|
|
941
|
+
methodClosure(o, traits, id) {
|
|
942
|
+
const method = traits.proto[methodKey(id)];
|
|
943
|
+
const key = typeof o === "object" ? o : traits.proto;
|
|
944
|
+
let byMethod = this.closures.get(key);
|
|
945
|
+
if (!byMethod) {
|
|
946
|
+
byMethod = new Map();
|
|
947
|
+
this.closures.set(key, byMethod);
|
|
948
|
+
}
|
|
949
|
+
let f = typeof o === "object" ? byMethod.get(method) : undefined;
|
|
950
|
+
if (!f) {
|
|
951
|
+
f = this.newFunctionObject(method.$min === undefined
|
|
952
|
+
? (...args) => {
|
|
953
|
+
// biome-ignore lint/style/useConst: a const is folded into a tail call (see Runtime.getProperty)
|
|
954
|
+
let r;
|
|
955
|
+
r = method.apply(o, args);
|
|
956
|
+
return r;
|
|
957
|
+
}
|
|
958
|
+
: (...args) => this.callBound(method, o, args), null);
|
|
959
|
+
// Its length is the method's declared parameters, not the wrapper's: a
|
|
960
|
+
// native's from its ABC, a compiled method's from the parameters it declares.
|
|
961
|
+
f.$length = method.$length ?? method.length;
|
|
962
|
+
f.$id = method.$id ?? 0;
|
|
963
|
+
f.$closure = true;
|
|
964
|
+
if (typeof o === "object") {
|
|
965
|
+
byMethod.set(method, f);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return f;
|
|
969
|
+
}
|
|
970
|
+
setProperty(o, mn, v, init = false) {
|
|
971
|
+
const e = cached(this.receiverTraits(o), mn);
|
|
972
|
+
if (e !== null) {
|
|
973
|
+
switch (e.kind) {
|
|
974
|
+
case IC_Slot:
|
|
975
|
+
o[e.key] = e.type === null ? v : this.coerce(v, e.type);
|
|
976
|
+
return;
|
|
977
|
+
case IC_Set:
|
|
978
|
+
case IC_GetSet:
|
|
979
|
+
e.set.call(o, v);
|
|
980
|
+
return;
|
|
981
|
+
case IC_Dynamic: {
|
|
982
|
+
const d = o.$d;
|
|
983
|
+
if (d) {
|
|
984
|
+
d.set(e.key, v);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (mn.key !== undefined && o?.$keys !== undefined) {
|
|
991
|
+
const keys = o.$keys;
|
|
992
|
+
if (keys.replace(mn.key, v)) {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
const named = this.namespaceKeyName(mn);
|
|
996
|
+
if (named === null) {
|
|
997
|
+
keys.add(mn.key, v);
|
|
998
|
+
}
|
|
999
|
+
else {
|
|
1000
|
+
this.setProperty(o, named, v, init);
|
|
1001
|
+
}
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
const traits = this.traitsOf(o);
|
|
1005
|
+
const b = traits.find(mn);
|
|
1006
|
+
this.fill(o, traits, b, mn);
|
|
1007
|
+
if (traits.properties !== null && hookedBinding(b, mn, traits.properties)) {
|
|
1008
|
+
traits.properties.set(this, o, mn, v);
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
if (b !== 0) {
|
|
1012
|
+
const id = b >> 3;
|
|
1013
|
+
switch (b & 7) {
|
|
1014
|
+
case BIND_Const:
|
|
1015
|
+
if (!init) {
|
|
1016
|
+
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.name);
|
|
1017
|
+
}
|
|
1018
|
+
o[slotKey(id)] = this.coerce(v, traits.slotType(id));
|
|
1019
|
+
return;
|
|
1020
|
+
case BIND_Var:
|
|
1021
|
+
o[slotKey(id)] = this.coerce(v, traits.slotType(id));
|
|
1022
|
+
return;
|
|
1023
|
+
case BIND_Set:
|
|
1024
|
+
case BIND_GetSet:
|
|
1025
|
+
(traits.proto[untypedSetKey(id + 1)] ?? traits.proto[methodKey(id + 1)]).call(o, v);
|
|
1026
|
+
return;
|
|
1027
|
+
case BIND_Method:
|
|
1028
|
+
throw this.error("ReferenceError", 1037, mn.name ?? "*", traits.name);
|
|
1029
|
+
default:
|
|
1030
|
+
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.name);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
const name = mn.dynamicName();
|
|
1034
|
+
if (name !== null && typeof o === "object") {
|
|
1035
|
+
if (traits.setIndex || (o.$a !== undefined && o.$a !== SEALED_ELEMENTS)) {
|
|
1036
|
+
const i = traits.index ? traits.index(o, name, this) : arrayIndex(name);
|
|
1037
|
+
if (i >= 0) {
|
|
1038
|
+
if (traits.setIndex) {
|
|
1039
|
+
traits.setIndex(o, i, v, this);
|
|
1040
|
+
}
|
|
1041
|
+
else {
|
|
1042
|
+
o.$a[i] = v;
|
|
1043
|
+
}
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (o.$d && !traits.refusesNames) {
|
|
1048
|
+
o.$d.set(name, v);
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
throw this.error("ReferenceError", 1056, mn.name ?? "*", traits.name);
|
|
1053
|
+
}
|
|
1054
|
+
initProperty(o, mn, v) {
|
|
1055
|
+
this.setProperty(o, mn, v, true);
|
|
1056
|
+
}
|
|
1057
|
+
deleteProperty(o, mn) {
|
|
1058
|
+
if (mn.key !== undefined && o?.$keys !== undefined) {
|
|
1059
|
+
if (o.$keys.delete(mn.key)) {
|
|
1060
|
+
return true;
|
|
1061
|
+
}
|
|
1062
|
+
const named = this.namespaceKeyName(mn);
|
|
1063
|
+
return named === null || this.deleteProperty(o, named);
|
|
1064
|
+
}
|
|
1065
|
+
// A primitive's property cannot be deleted, as MethodEnv's delproperty has it.
|
|
1066
|
+
if (typeof o !== "object" || o instanceof Namespace) {
|
|
1067
|
+
throw this.error("ReferenceError", 1120, mn.name ?? "*", this.traitsOf(o).name);
|
|
1068
|
+
}
|
|
1069
|
+
// E4X 11.3.1: delete x[list] is a TypeError, as in delete x.a.(b == 1).
|
|
1070
|
+
if (mn.key?.$nodes !== undefined) {
|
|
1071
|
+
throw this.error("TypeError", 1119, "XMLList");
|
|
1072
|
+
}
|
|
1073
|
+
const traits = this.traitsOf(o);
|
|
1074
|
+
const b = traits.find(mn);
|
|
1075
|
+
if (traits.properties !== null && hookedBinding(b, mn, traits.properties)) {
|
|
1076
|
+
return traits.properties.delete(this, o, mn);
|
|
1077
|
+
}
|
|
1078
|
+
if (b !== 0) {
|
|
1079
|
+
return false;
|
|
1080
|
+
}
|
|
1081
|
+
const name = mn.dynamicName();
|
|
1082
|
+
if (name !== null && typeof o === "object") {
|
|
1083
|
+
if (o.$a !== undefined && o.$a !== SEALED_ELEMENTS) {
|
|
1084
|
+
const i = arrayIndex(name);
|
|
1085
|
+
if (i >= 0) {
|
|
1086
|
+
return delete o.$a[i];
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
// A name deleted is enumerable again when set anew, as avmplus has it.
|
|
1090
|
+
o.$dontEnum?.delete(name);
|
|
1091
|
+
return o.$d ? o.$d.delete(name) || true : false;
|
|
1092
|
+
}
|
|
1093
|
+
return false;
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* The name a Dictionary's key stands for when it is a Namespace, else
|
|
1097
|
+
* null. avmplus keys a Dictionary by an object only (isDictionaryLookup),
|
|
1098
|
+
* and a Namespace is none: it names its uri, as AvmCore::intern has it.
|
|
1099
|
+
* Asked only once the key is not there, as a Namespace never is, so that
|
|
1100
|
+
* a key found pays nothing for it.
|
|
1101
|
+
*/
|
|
1102
|
+
namespaceKeyName(mn) {
|
|
1103
|
+
if (!(mn.key instanceof Namespace)) {
|
|
1104
|
+
return null;
|
|
1105
|
+
}
|
|
1106
|
+
const named = new Multiname(mn.kind, mn.namespaces, mn.versions, mn.name, mn.attribute);
|
|
1107
|
+
named.domain = mn.domain;
|
|
1108
|
+
return named;
|
|
1109
|
+
}
|
|
1110
|
+
/** The `in` operator: whether `o` has the public property `name`. */
|
|
1111
|
+
in(name, o) {
|
|
1112
|
+
// As isDictionaryLookup: a Dictionary looks for any object itself, a
|
|
1113
|
+
// QName too. A Namespace is no object to avmplus: on a miss,
|
|
1114
|
+
// dictionaryHas looks for its uri as a name.
|
|
1115
|
+
if (typeof name === "object" &&
|
|
1116
|
+
name !== null &&
|
|
1117
|
+
!(name instanceof FloatValue) &&
|
|
1118
|
+
o?.$keys !== undefined) {
|
|
1119
|
+
return this.dictionaryHas(o, name);
|
|
1120
|
+
}
|
|
1121
|
+
// As in_operator: a uint names an element the object itself has, or
|
|
1122
|
+
// for a primitive its prototype, as hasUintProperty finds it, not one
|
|
1123
|
+
// up the prototype chain.
|
|
1124
|
+
if (typeof name === "number" && name >>> 0 === name && name !== 0xffffffff) {
|
|
1125
|
+
return this.hasOwnIndex(typeof o === "object" && o !== null ? o : this.protoOf(o), name);
|
|
1126
|
+
}
|
|
1127
|
+
return this.hasProperty(o, publicQname(this.nameString(name), this.userVersions));
|
|
1128
|
+
}
|
|
1129
|
+
/** Whether `o` itself has element `i`: its class's indexing, an Array's, or a dynamic property. */
|
|
1130
|
+
hasOwnIndex(o, i) {
|
|
1131
|
+
if (o instanceof Namespace) {
|
|
1132
|
+
return false;
|
|
1133
|
+
}
|
|
1134
|
+
const traits = o.$traits;
|
|
1135
|
+
if (traits?.properties) {
|
|
1136
|
+
return traits.properties.has(this, o, this.publicName(i));
|
|
1137
|
+
}
|
|
1138
|
+
if (traits?.hasIndex) {
|
|
1139
|
+
return traits.hasIndex(o, i);
|
|
1140
|
+
}
|
|
1141
|
+
if (o.$a !== undefined) {
|
|
1142
|
+
return i in o.$a;
|
|
1143
|
+
}
|
|
1144
|
+
return o.$d?.has(String(i)) ?? false;
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Whether Dictionary `o` has object key `key`, as in_operator finds it:
|
|
1148
|
+
* the key itself, then, made a string, on its prototype chain. A
|
|
1149
|
+
* Namespace names its uri, the Dictionary's own or its prototypes'.
|
|
1150
|
+
*/
|
|
1151
|
+
dictionaryHas(o, key) {
|
|
1152
|
+
return o.$keys.has(key) || this.dictionaryHasName(o, key);
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* dictionaryHas once `key` is not there, apart so that the lookup of one
|
|
1156
|
+
* that is stays small enough to inline.
|
|
1157
|
+
*/
|
|
1158
|
+
dictionaryHasName(o, key) {
|
|
1159
|
+
if (key instanceof Namespace) {
|
|
1160
|
+
return this.hasProperty(o, publicQname(this.nameString(key), this.userVersions));
|
|
1161
|
+
}
|
|
1162
|
+
const name = this.toString(key);
|
|
1163
|
+
for (let p = this.protoOf(o); p; p = p.$p) {
|
|
1164
|
+
if (this.protoOwn(p, name) !== NOT_FOUND) {
|
|
1165
|
+
return true;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return false;
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Whether a class that indexes itself (a Vector) has the element `name`,
|
|
1172
|
+
* which is there only within its length: undefined for a name that is
|
|
1173
|
+
* no number, or for another class.
|
|
1174
|
+
*/
|
|
1175
|
+
indexHas(o, name) {
|
|
1176
|
+
const traits = typeof o === "object" && o !== null ? o.$traits : undefined;
|
|
1177
|
+
if (!traits?.hasIndex) {
|
|
1178
|
+
return undefined;
|
|
1179
|
+
}
|
|
1180
|
+
const i = arrayIndex(name);
|
|
1181
|
+
if (i >= 0) {
|
|
1182
|
+
return traits.hasIndex(o, i);
|
|
1183
|
+
}
|
|
1184
|
+
// Another number, negative or fractional, is no index it has, as
|
|
1185
|
+
// VectorBaseObject::hasAtomProperty has it, where a get throws.
|
|
1186
|
+
const c = name.charCodeAt(0);
|
|
1187
|
+
if (((c >= 0x30 && c <= 0x39) || c === 0x2d) && !Number.isNaN(Number(name))) {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
return undefined;
|
|
1191
|
+
}
|
|
1192
|
+
/** Whether `o` has `mn`: bound, dynamic, or on its prototype chain. */
|
|
1193
|
+
hasProperty(o, mn) {
|
|
1194
|
+
if (mn.key !== undefined && o?.$keys !== undefined) {
|
|
1195
|
+
return this.dictionaryHas(o, mn.key);
|
|
1196
|
+
}
|
|
1197
|
+
const own = this.traitsOf(o);
|
|
1198
|
+
const b = own.find(mn);
|
|
1199
|
+
if (own.properties !== null && hookedBinding(b, mn, own.properties)) {
|
|
1200
|
+
return own.properties.has(this, o, mn);
|
|
1201
|
+
}
|
|
1202
|
+
if (b !== 0) {
|
|
1203
|
+
return true;
|
|
1204
|
+
}
|
|
1205
|
+
const name = mn.dynamicName();
|
|
1206
|
+
if (name === null) {
|
|
1207
|
+
return false;
|
|
1208
|
+
}
|
|
1209
|
+
const indexed = this.indexHas(o, name);
|
|
1210
|
+
if (indexed !== undefined) {
|
|
1211
|
+
return indexed;
|
|
1212
|
+
}
|
|
1213
|
+
if (this.getOwn(o, name) !== NOT_FOUND) {
|
|
1214
|
+
return true;
|
|
1215
|
+
}
|
|
1216
|
+
for (let p = this.protoOf(o); p; p = p.$p) {
|
|
1217
|
+
if (this.protoOwn(p, name) !== NOT_FOUND) {
|
|
1218
|
+
return true;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
/** A value's AS3 prototype object: its class's prototype, or its own link for a prototype object. */
|
|
1224
|
+
protoOf(o) {
|
|
1225
|
+
// A namespace is the runtime's own object: its prototype is its class's.
|
|
1226
|
+
if (typeof o === "object" &&
|
|
1227
|
+
o !== null &&
|
|
1228
|
+
!(o instanceof Namespace) &&
|
|
1229
|
+
!(o instanceof FloatValue)) {
|
|
1230
|
+
return o.$p;
|
|
1231
|
+
}
|
|
1232
|
+
return this.traitsOf(o).proto.$p;
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* A public name seen at every version, as the host and the natives reach
|
|
1236
|
+
* members, slots and all; what AS3 itself looks up by a string goes by
|
|
1237
|
+
* publicQname, at user code's version.
|
|
1238
|
+
*/
|
|
1239
|
+
publicName(name) {
|
|
1240
|
+
return qname(publicNs, this.nameString(name));
|
|
1241
|
+
}
|
|
1242
|
+
/** A property name as a string, as ToString makes one. */
|
|
1243
|
+
nameString(name) {
|
|
1244
|
+
return typeof name === "string" ? name : this.toString(name);
|
|
1245
|
+
}
|
|
1246
|
+
// Calls.
|
|
1247
|
+
callProperty(o, mn, ...args) {
|
|
1248
|
+
let r;
|
|
1249
|
+
const e = cached(this.receiverTraits(o), mn);
|
|
1250
|
+
if (e !== null) {
|
|
1251
|
+
switch (e.kind) {
|
|
1252
|
+
case IC_Method:
|
|
1253
|
+
case IC_Call:
|
|
1254
|
+
r = this.callBound(e.get, o, args);
|
|
1255
|
+
return r;
|
|
1256
|
+
case IC_Slot:
|
|
1257
|
+
case IC_Const:
|
|
1258
|
+
r = this.callValue(o[e.key], o, args, mn);
|
|
1259
|
+
return r;
|
|
1260
|
+
case IC_Get:
|
|
1261
|
+
case IC_GetSet:
|
|
1262
|
+
r = this.callValue(e.get.call(o), o, args, mn);
|
|
1263
|
+
return r;
|
|
1264
|
+
case IC_Dynamic: {
|
|
1265
|
+
const d = o.$d;
|
|
1266
|
+
if (d) {
|
|
1267
|
+
const v = d.get(e.key);
|
|
1268
|
+
if (v !== undefined || d.has(e.key)) {
|
|
1269
|
+
r = this.callValue(v, o, args, mn);
|
|
1270
|
+
return r;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
// Not its own: its prototypes', as a method on Array.prototype.
|
|
1274
|
+
if (mn.key === undefined) {
|
|
1275
|
+
const v = this.protoValue(o, e.key);
|
|
1276
|
+
if (v !== NOT_FOUND) {
|
|
1277
|
+
r = this.callValue(v, o, args, mn);
|
|
1278
|
+
return r;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
const traits = this.traitsOf(o);
|
|
1285
|
+
const b = traits.find(mn);
|
|
1286
|
+
this.fill(o, traits, b, mn);
|
|
1287
|
+
if ((b & 7) === BIND_Method) {
|
|
1288
|
+
r = this.callBound(traits.proto[methodKey(b >> 3)], o, args);
|
|
1289
|
+
return r;
|
|
1290
|
+
}
|
|
1291
|
+
r = this.callValue(this.callee(o, traits, b, mn), o, args, mn);
|
|
1292
|
+
return r;
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* What callproperty calls, for a binding other than a method: its value,
|
|
1296
|
+
* else the property. As avmplus' callproperty, on a primitive a name its
|
|
1297
|
+
* class does not have is its prototype's, undefined if none has it, so
|
|
1298
|
+
* that calling it is a TypeError, where getting it is a ReferenceError.
|
|
1299
|
+
*/
|
|
1300
|
+
callee(o, traits, b, mn) {
|
|
1301
|
+
if (b !== 0) {
|
|
1302
|
+
return this.getBound(o, traits, b, mn);
|
|
1303
|
+
}
|
|
1304
|
+
if (traits.properties !== null) {
|
|
1305
|
+
return traits.properties.callee(this, o, mn);
|
|
1306
|
+
}
|
|
1307
|
+
// A name no dynamic property has, such as ns::x, fails as a get does.
|
|
1308
|
+
const name = mn.dynamicName();
|
|
1309
|
+
if (typeof o === "object" || name === null) {
|
|
1310
|
+
return this.getProperty(o, mn);
|
|
1311
|
+
}
|
|
1312
|
+
for (let p = this.protoOf(o); p; p = p.$p) {
|
|
1313
|
+
const v = this.protoOwn(p, name);
|
|
1314
|
+
if (v !== NOT_FOUND) {
|
|
1315
|
+
return v;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
return undefined;
|
|
1319
|
+
}
|
|
1320
|
+
/** callproplex: as callproperty, with no receiver. */
|
|
1321
|
+
callPropLex(o, mn, ...args) {
|
|
1322
|
+
let r;
|
|
1323
|
+
const traits = this.traitsOf(o);
|
|
1324
|
+
const b = traits.find(mn);
|
|
1325
|
+
if ((b & 7) === BIND_Method) {
|
|
1326
|
+
r = this.callBound(traits.proto[methodKey(b >> 3)], o, args);
|
|
1327
|
+
return r;
|
|
1328
|
+
}
|
|
1329
|
+
r = this.callValue(this.callee(o, traits, b, mn), null, args, mn);
|
|
1330
|
+
return r;
|
|
1331
|
+
}
|
|
1332
|
+
call(f, receiver, ...args) {
|
|
1333
|
+
// biome-ignore lint/style/useConst: a const is folded into a tail call (see Runtime.getProperty)
|
|
1334
|
+
let r;
|
|
1335
|
+
r = this.callValue(f, receiver, args, null);
|
|
1336
|
+
return r;
|
|
1337
|
+
}
|
|
1338
|
+
callValue(f, receiver, args, mn) {
|
|
1339
|
+
let r;
|
|
1340
|
+
if (f !== null && typeof f === "object") {
|
|
1341
|
+
if (f.$f) {
|
|
1342
|
+
r = f.$f.apply(receiver ?? f.$global ?? null, args);
|
|
1343
|
+
return r;
|
|
1344
|
+
}
|
|
1345
|
+
if (f.$it) {
|
|
1346
|
+
r = this.callClass(f, args);
|
|
1347
|
+
return r;
|
|
1348
|
+
}
|
|
1349
|
+
// A RegExp called is its exec of the argument's string, as RegExpObject::call has it.
|
|
1350
|
+
if (f.$re !== undefined) {
|
|
1351
|
+
this.execName ??= qname(namespace(NS_Public, "http://adobe.com/AS3/2006/builtin"), "exec");
|
|
1352
|
+
r = this.callProperty(f, this.execName, args.length ? this.toString(args[0]) : "");
|
|
1353
|
+
return r;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
throw this.error("TypeError", 1006, mn ? mn.name : "value");
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* A method that failed its one test on entry: given fewer arguments than
|
|
1360
|
+
* `required` or more than `max` (-1 for any), else called where the
|
|
1361
|
+
* default XML namespace is not its own (callInDxns).
|
|
1362
|
+
*/
|
|
1363
|
+
enter(dxns, f, receiver, args, required, max) {
|
|
1364
|
+
// biome-ignore lint/style/useConst: a const is folded into a tail call (see Runtime.getProperty)
|
|
1365
|
+
let r;
|
|
1366
|
+
if (args.length < required || (max >= 0 && args.length > max)) {
|
|
1367
|
+
throw this.argumentCountError(required, args.length);
|
|
1368
|
+
}
|
|
1369
|
+
r = this.callInDxns(dxns, f, receiver, args);
|
|
1370
|
+
return r;
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* A method called where the default XML namespace is not the one of the
|
|
1374
|
+
* scope it was made in, `dxns`: called again with it, and the caller's
|
|
1375
|
+
* back after.
|
|
1376
|
+
*/
|
|
1377
|
+
callInDxns(dxns, f, receiver, args) {
|
|
1378
|
+
const caller = this.defaultXmlNamespace;
|
|
1379
|
+
this.defaultXmlNamespace = dxns;
|
|
1380
|
+
try {
|
|
1381
|
+
return f.apply(receiver, args);
|
|
1382
|
+
}
|
|
1383
|
+
finally {
|
|
1384
|
+
this.defaultXmlNamespace = caller;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
execName = null;
|
|
1388
|
+
callInterface(iface, disp, o, ...args) {
|
|
1389
|
+
let r;
|
|
1390
|
+
const cls = this.classOf(iface);
|
|
1391
|
+
// The interface's layout names the method; the receiver binds that name.
|
|
1392
|
+
const desc = cls.$desc;
|
|
1393
|
+
for (const [ns, , name, b] of desc.instance.bindings) {
|
|
1394
|
+
if (b >> 3 === disp && (b & 7) === BIND_Method) {
|
|
1395
|
+
r = this.callProperty(o, qname(ns, name), ...args);
|
|
1396
|
+
return r;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
throw this.error("TypeError", 1006, "method");
|
|
1400
|
+
}
|
|
1401
|
+
/**
|
|
1402
|
+
* The key of the method an interface's method, dispatch id `disp` in
|
|
1403
|
+
* the interface's layout, is on `o`, an object of a class that
|
|
1404
|
+
* implements it: its entry for bound calls, as a call through the
|
|
1405
|
+
* interface coerces its arguments to the interface's signature, which
|
|
1406
|
+
* the class's method has too (checkInterfaces), and passes a count the
|
|
1407
|
+
* method takes. Generated code calls `o[key](...)` itself, so that each
|
|
1408
|
+
* site keeps its own feedback in the engine. Found by name once for
|
|
1409
|
+
* each class and interface, and kept on the class's traits. Only for a
|
|
1410
|
+
* member in a private namespace, which has no alias every implementing
|
|
1411
|
+
* class shares (see the codegen's interfaceCall).
|
|
1412
|
+
*/
|
|
1413
|
+
interfaceKey(iface, disp, o) {
|
|
1414
|
+
const traits = o.$traits;
|
|
1415
|
+
const cls = iface.cls ?? this.classOf(iface);
|
|
1416
|
+
if (traits !== undefined && traits.lastInterface === cls.$it) {
|
|
1417
|
+
const key = traits.lastInterfaceKeys[disp];
|
|
1418
|
+
if (key !== undefined) {
|
|
1419
|
+
return key;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
return this.findInterfaceKey(cls, disp, o);
|
|
1423
|
+
}
|
|
1424
|
+
findInterfaceKey(cls, disp, o) {
|
|
1425
|
+
const it = cls.$it;
|
|
1426
|
+
const traits = this.traitsOf(o);
|
|
1427
|
+
traits.interfaceKeys ??= new Map();
|
|
1428
|
+
let keys = traits.interfaceKeys.get(it);
|
|
1429
|
+
if (!keys) {
|
|
1430
|
+
keys = [];
|
|
1431
|
+
traits.interfaceKeys.set(it, keys);
|
|
1432
|
+
}
|
|
1433
|
+
traits.lastInterface = it;
|
|
1434
|
+
traits.lastInterfaceKeys = keys;
|
|
1435
|
+
let key = keys[disp];
|
|
1436
|
+
if (key === undefined) {
|
|
1437
|
+
const desc = cls.$desc;
|
|
1438
|
+
for (const [ns, , name, b] of desc.instance.bindings) {
|
|
1439
|
+
if (b >> 3 === disp && (b & 7) === BIND_Method) {
|
|
1440
|
+
// A class that implements the interface binds its name to a
|
|
1441
|
+
// method (checkInterfaces); anything else is not a function.
|
|
1442
|
+
const own = traits.find(qname(ns, name));
|
|
1443
|
+
if ((own & 7) !== BIND_Method) {
|
|
1444
|
+
throw this.error("TypeError", 1006, name);
|
|
1445
|
+
}
|
|
1446
|
+
key = boundKey(own >> 3);
|
|
1447
|
+
keys[disp] = key;
|
|
1448
|
+
return key;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
throw this.error("TypeError", 1006, "method");
|
|
1452
|
+
}
|
|
1453
|
+
return key;
|
|
1454
|
+
}
|
|
1455
|
+
callStatic(_abc, m, ..._args) {
|
|
1456
|
+
throw this.unsupported(`callstatic ${m}`);
|
|
1457
|
+
}
|
|
1458
|
+
// The super operations, as MethodEnv's: by the base class's traits
|
|
1459
|
+
// alone, a name they do not bind a ReferenceError, not a dynamic property.
|
|
1460
|
+
callSuper(sup, o, mn, ...args) {
|
|
1461
|
+
let r;
|
|
1462
|
+
const traits = sup.$it;
|
|
1463
|
+
const b = traits.find(mn);
|
|
1464
|
+
if ((b & 7) === BIND_Method) {
|
|
1465
|
+
r = this.callBound(traits.proto[methodKey(b >> 3)], o, args);
|
|
1466
|
+
return r;
|
|
1467
|
+
}
|
|
1468
|
+
if (b === 0) {
|
|
1469
|
+
throw this.error("ReferenceError", 1070, mn.name ?? "*", traits.name);
|
|
1470
|
+
}
|
|
1471
|
+
r = this.callValue(this.getBound(o, traits, b, mn), o, args, mn);
|
|
1472
|
+
return r;
|
|
1473
|
+
}
|
|
1474
|
+
getSuper(sup, o, mn) {
|
|
1475
|
+
const traits = sup.$it;
|
|
1476
|
+
const b = traits.find(mn);
|
|
1477
|
+
if (b === 0) {
|
|
1478
|
+
throw this.error("ReferenceError", 1069, mn.name ?? "*", traits.name);
|
|
1479
|
+
}
|
|
1480
|
+
return this.getBound(o, traits, b, mn);
|
|
1481
|
+
}
|
|
1482
|
+
setSuper(sup, o, mn, v) {
|
|
1483
|
+
const traits = sup.$it;
|
|
1484
|
+
const b = traits.find(mn);
|
|
1485
|
+
const id = b >> 3;
|
|
1486
|
+
switch (b & 7) {
|
|
1487
|
+
case BIND_Set:
|
|
1488
|
+
case BIND_GetSet:
|
|
1489
|
+
(traits.proto[untypedSetKey(id + 1)] ?? traits.proto[methodKey(id + 1)]).call(o, v);
|
|
1490
|
+
return;
|
|
1491
|
+
case BIND_Var:
|
|
1492
|
+
o[slotKey(id)] = this.coerce(v, traits.slotType(id));
|
|
1493
|
+
return;
|
|
1494
|
+
case BIND_Method:
|
|
1495
|
+
throw this.error("ReferenceError", 1037, mn.name ?? "*", traits.name);
|
|
1496
|
+
case 0:
|
|
1497
|
+
throw this.error("ReferenceError", 1056, mn.name ?? "*", traits.name);
|
|
1498
|
+
default:
|
|
1499
|
+
throw this.error("ReferenceError", 1074, mn.name ?? "*", traits.name);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
constructSuper(sup, o, ...args) {
|
|
1503
|
+
sup.$it.proto.$init.apply(o, args);
|
|
1504
|
+
}
|
|
1505
|
+
construct(f, ...args) {
|
|
1506
|
+
return this.constructWith(f, args);
|
|
1507
|
+
}
|
|
1508
|
+
/** construct, its arguments as an array: constructProperty passes its own on, unspread. */
|
|
1509
|
+
constructWith(f, args) {
|
|
1510
|
+
if (f !== null && typeof f === "object") {
|
|
1511
|
+
// A method closure is not a constructor, as MethodClosure's construct has it.
|
|
1512
|
+
if (f.$closure) {
|
|
1513
|
+
throw this.error("TypeError", 1064, "function");
|
|
1514
|
+
}
|
|
1515
|
+
if (f.$it) {
|
|
1516
|
+
return this.constructClass(f, args);
|
|
1517
|
+
}
|
|
1518
|
+
if (f.$f) {
|
|
1519
|
+
return this.constructFunction(f, args);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
throw this.error("TypeError", 1007);
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* A function as a constructor: a new Object whose prototype is the
|
|
1526
|
+
* function's. One whose prototype a script cleared gets Object's own
|
|
1527
|
+
* prototype object back at its first new, as avmplus reinitializes it,
|
|
1528
|
+
* so from then on every object is an instance of the function.
|
|
1529
|
+
*/
|
|
1530
|
+
constructFunction(f, args) {
|
|
1531
|
+
const o = this.objectTraits.instance();
|
|
1532
|
+
let p = this.functionPrototype(f);
|
|
1533
|
+
if (p === undefined) {
|
|
1534
|
+
p = this.builtinClass("Object").$prototype;
|
|
1535
|
+
f.$prototype = p;
|
|
1536
|
+
f.$noPrototype = false;
|
|
1537
|
+
}
|
|
1538
|
+
o.$p = p;
|
|
1539
|
+
const result = f.$f.apply(o, args);
|
|
1540
|
+
return result !== null && typeof result === "object" ? result : o;
|
|
1541
|
+
}
|
|
1542
|
+
constructProperty(o, mn, ...args) {
|
|
1543
|
+
// As avmplus' constructprop: a primitive's, a Namespace's among them,
|
|
1544
|
+
// from its prototype, where a missing name is undefined.
|
|
1545
|
+
const primitive = (o !== null && o !== undefined && typeof o !== "object") || o instanceof Namespace;
|
|
1546
|
+
return this.constructWith(this.getProperty(primitive ? this.protoOf(o) : o, mn), args);
|
|
1547
|
+
}
|
|
1548
|
+
constructClass(cls, args) {
|
|
1549
|
+
const hook = this.hookOf(cls, "construct");
|
|
1550
|
+
if (hook) {
|
|
1551
|
+
return hook(this, cls, args);
|
|
1552
|
+
}
|
|
1553
|
+
const o = this.instantiate(cls);
|
|
1554
|
+
cls.$it.proto.$init.apply(o, args);
|
|
1555
|
+
return o;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* The first half of `new`: an instance of `cls` whose constructor has
|
|
1559
|
+
* yet to run, which constructSuper runs; null for a class a hook
|
|
1560
|
+
* constructs whole. A host that has to name an object before its
|
|
1561
|
+
* constructor runs, as Flash does a timeline's button, makes it so.
|
|
1562
|
+
*/
|
|
1563
|
+
allocate(cls) {
|
|
1564
|
+
if (this.hookOf(cls, "construct")) {
|
|
1565
|
+
return null;
|
|
1566
|
+
}
|
|
1567
|
+
return this.instantiate(cls);
|
|
1568
|
+
}
|
|
1569
|
+
/** allocate for a class with no construct hook, which constructClass has looked up already. */
|
|
1570
|
+
instantiate(cls) {
|
|
1571
|
+
// An interface's constructor is a method nothing implements, as avmplus words it.
|
|
1572
|
+
if (cls.$desc?.interface) {
|
|
1573
|
+
throw this.error("VerifyError", 1001, `${cls.$it.name}()`);
|
|
1574
|
+
}
|
|
1575
|
+
if (cls.$it.uninstantiable) {
|
|
1576
|
+
throw this.error("ArgumentError", 2012, cls.$it.name);
|
|
1577
|
+
}
|
|
1578
|
+
return cls.$it.instance();
|
|
1579
|
+
}
|
|
1580
|
+
/** A class called as a function: a conversion for the builtins, else a coercion. */
|
|
1581
|
+
callClass(cls, args) {
|
|
1582
|
+
const hook = this.hookOf(cls, "call");
|
|
1583
|
+
if (hook) {
|
|
1584
|
+
return hook(this, cls, args);
|
|
1585
|
+
}
|
|
1586
|
+
if (args.length !== 1) {
|
|
1587
|
+
throw this.error("ArgumentError", 1112, args.length);
|
|
1588
|
+
}
|
|
1589
|
+
return this.coerce(args[0], this.refOf(cls));
|
|
1590
|
+
}
|
|
1591
|
+
/** A builtin class's hook; hooks are not inherited, but a specialized Vector has its base's. */
|
|
1592
|
+
hookOf(cls, kind) {
|
|
1593
|
+
// Looked up once, then kept on the class.
|
|
1594
|
+
const key = kind === "construct" ? "$constructHook" : "$callHook";
|
|
1595
|
+
let hook = cls[key];
|
|
1596
|
+
if (hook === undefined) {
|
|
1597
|
+
hook = cls.$it.hooks?.[kind] ?? null;
|
|
1598
|
+
cls[key] = hook;
|
|
1599
|
+
}
|
|
1600
|
+
return hook;
|
|
1601
|
+
}
|
|
1602
|
+
/** See specializeVector in classes.ts. */
|
|
1603
|
+
specializeVector(base, param) {
|
|
1604
|
+
return specializeVector(this, base, param);
|
|
1605
|
+
}
|
|
1606
|
+
// Objects, functions and classes.
|
|
1607
|
+
newObject(pairs) {
|
|
1608
|
+
const o = this.objectTraits.instance();
|
|
1609
|
+
for (let i = 0; i < pairs.length; i += 2) {
|
|
1610
|
+
o.$d.set(this.toString(pairs[i]), pairs[i + 1]);
|
|
1611
|
+
}
|
|
1612
|
+
return o;
|
|
1613
|
+
}
|
|
1614
|
+
newArray(values) {
|
|
1615
|
+
return this.array(values);
|
|
1616
|
+
}
|
|
1617
|
+
/** An Array holding `values`. */
|
|
1618
|
+
array(values) {
|
|
1619
|
+
const o = this.builtinTraits("Array").instance();
|
|
1620
|
+
o.$a = values;
|
|
1621
|
+
return o;
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* A method's `arguments`: every argument it was called with, declared or
|
|
1625
|
+
* not, and as `callee`, not enumerable, the method's Function object,
|
|
1626
|
+
* the one a newfunction made for it, so that `arguments.callee === f`,
|
|
1627
|
+
* else one made for it once, as avmplus' MethodClosure is.
|
|
1628
|
+
*/
|
|
1629
|
+
arguments(args, callee) {
|
|
1630
|
+
const o = this.array(Array.prototype.slice.call(args));
|
|
1631
|
+
let f = this.functionObjects.get(callee);
|
|
1632
|
+
if (!f) {
|
|
1633
|
+
f = this.newFunctionObject(callee, null);
|
|
1634
|
+
this.functionObjects.set(callee, f);
|
|
1635
|
+
}
|
|
1636
|
+
o.$d.set("callee", f);
|
|
1637
|
+
o.$dontEnum = new Set(["callee"]);
|
|
1638
|
+
return o;
|
|
1639
|
+
}
|
|
1640
|
+
/** Each method's Function object, by the method, for arguments.callee. */
|
|
1641
|
+
functionObjects = new WeakMap();
|
|
1642
|
+
newFunction(factory, scope, id = 0) {
|
|
1643
|
+
const method = factory(scope, null);
|
|
1644
|
+
const f = this.newFunctionObject(method, scope.length ? scope[0] : null);
|
|
1645
|
+
f.$id = id;
|
|
1646
|
+
this.functionObjects.set(method, f);
|
|
1647
|
+
return f;
|
|
1648
|
+
}
|
|
1649
|
+
/** A Function object calling `f`, with `global` as its receiver when it has none. */
|
|
1650
|
+
newFunctionObject(f, global) {
|
|
1651
|
+
const o = this.functionTraits.instance();
|
|
1652
|
+
o.$f = f;
|
|
1653
|
+
o.$global = global;
|
|
1654
|
+
o.$id = 0;
|
|
1655
|
+
return o;
|
|
1656
|
+
}
|
|
1657
|
+
/** A function's prototype, made when first asked for; undefined once a script has cleared it. */
|
|
1658
|
+
functionPrototype(f) {
|
|
1659
|
+
if (!f.$prototype && !f.$noPrototype) {
|
|
1660
|
+
const p = this.objectTraits.instance();
|
|
1661
|
+
p.$d.set("constructor", f);
|
|
1662
|
+
p.$dontEnum = new Set(["constructor"]);
|
|
1663
|
+
f.$prototype = p;
|
|
1664
|
+
}
|
|
1665
|
+
return f.$prototype;
|
|
1666
|
+
}
|
|
1667
|
+
newActivation(desc) {
|
|
1668
|
+
let traits = this.scopeTraits.get(desc);
|
|
1669
|
+
if (!traits) {
|
|
1670
|
+
traits = new Traits("activation", null);
|
|
1671
|
+
traits.describe(desc);
|
|
1672
|
+
this.scopeTraits.set(desc, traits);
|
|
1673
|
+
}
|
|
1674
|
+
return traits.instance();
|
|
1675
|
+
}
|
|
1676
|
+
newCatch(mn) {
|
|
1677
|
+
const key = mn ?? this;
|
|
1678
|
+
let traits = this.scopeTraits.get(key);
|
|
1679
|
+
if (!traits) {
|
|
1680
|
+
traits = new Traits("catch", null);
|
|
1681
|
+
if (mn?.name) {
|
|
1682
|
+
traits.describe({
|
|
1683
|
+
slots: 1,
|
|
1684
|
+
defaults: [[0, undefined, null]],
|
|
1685
|
+
bindings: [[mn.namespaces[0], 0, mn.name, BIND_Var]],
|
|
1686
|
+
methods: [],
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
this.scopeTraits.set(key, traits);
|
|
1690
|
+
}
|
|
1691
|
+
return traits.instance();
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* As OP_newclass: a class from its module's descriptor, extending `base`,
|
|
1695
|
+
* its methods bound to the scope chain here (see newClass in classes.ts).
|
|
1696
|
+
*/
|
|
1697
|
+
newClass(desc, base, scope) {
|
|
1698
|
+
return newClass(this, desc, base, scope);
|
|
1699
|
+
}
|
|
1700
|
+
/** The classes whose static initializers are running, by qualified name. */
|
|
1701
|
+
defining = new Map();
|
|
1702
|
+
applyType(factory, params) {
|
|
1703
|
+
const hook = factory.$it.hooks?.apply;
|
|
1704
|
+
if (!hook) {
|
|
1705
|
+
throw this.error("TypeError", 1127);
|
|
1706
|
+
}
|
|
1707
|
+
return hook(this, factory, params);
|
|
1708
|
+
}
|
|
1709
|
+
// Types.
|
|
1710
|
+
/** The class a type reference names, resolved and kept the first time. */
|
|
1711
|
+
classOf(ref) {
|
|
1712
|
+
if (typeof ref === "string") {
|
|
1713
|
+
return this.builtinClass(ref);
|
|
1714
|
+
}
|
|
1715
|
+
if (ref === null) {
|
|
1716
|
+
return this.builtinClass("Object");
|
|
1717
|
+
}
|
|
1718
|
+
return this.resolve(ref);
|
|
1719
|
+
}
|
|
1720
|
+
resolve(ref) {
|
|
1721
|
+
if (ref.cls) {
|
|
1722
|
+
return ref.cls;
|
|
1723
|
+
}
|
|
1724
|
+
if (ref instanceof VectorRef) {
|
|
1725
|
+
const vector = this.resolve(this.cls(namespace(NS_Public, "__AS3__.vec"), "Vector"));
|
|
1726
|
+
ref.cls = this.applyType(vector, [ref.param === null ? null : this.classOf(ref.param)]);
|
|
1727
|
+
return ref.cls;
|
|
1728
|
+
}
|
|
1729
|
+
const mn = qname(ref.ns, ref.name);
|
|
1730
|
+
mn.domain = ref.domain === this.root ? null : ref.domain;
|
|
1731
|
+
let cls = this.typeNamed(mn);
|
|
1732
|
+
if (cls === null || cls === undefined || !cls.$it) {
|
|
1733
|
+
cls = this.defining.get(ref.ns.uri ? `${ref.ns.uri}::${ref.name}` : ref.name);
|
|
1734
|
+
if (!cls) {
|
|
1735
|
+
throw this.error("ReferenceError", 1065, ref.name);
|
|
1736
|
+
}
|
|
1737
|
+
// Not kept: the class is not yet where its name will find it.
|
|
1738
|
+
return cls;
|
|
1739
|
+
}
|
|
1740
|
+
ref.cls = cls;
|
|
1741
|
+
return cls;
|
|
1742
|
+
}
|
|
1743
|
+
/** See classNamed in definitions.ts. */
|
|
1744
|
+
classNamed(qualified, domain = null) {
|
|
1745
|
+
return classNamed(this, qualified, domain);
|
|
1746
|
+
}
|
|
1747
|
+
/** See classNamedByCode in definitions.ts. */
|
|
1748
|
+
classNamedByCode(qualified, domain) {
|
|
1749
|
+
return classNamedByCode(this, qualified, domain);
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1752
|
+
* The names `domain`'s own modules define, private ones left out, as
|
|
1753
|
+
* Flash's ApplicationDomain.getQualifiedDefinitionNames lists them:
|
|
1754
|
+
* "pkg::Name", or the name alone in the top-level package.
|
|
1755
|
+
*/
|
|
1756
|
+
definitionNames(domain) {
|
|
1757
|
+
return definitionNames(domain);
|
|
1758
|
+
}
|
|
1759
|
+
/** See definitionNamed in definitions.ts. */
|
|
1760
|
+
definitionNamed(qualified, domain) {
|
|
1761
|
+
return definitionNamed(this, qualified, domain);
|
|
1762
|
+
}
|
|
1763
|
+
/** See definingAbc in definitions.ts. */
|
|
1764
|
+
definingAbc(qualified, domain) {
|
|
1765
|
+
return definingAbc(this, qualified, domain);
|
|
1766
|
+
}
|
|
1767
|
+
/** The class a multiname or TypeName names. */
|
|
1768
|
+
resolveName(mn) {
|
|
1769
|
+
if (mn instanceof TypeName) {
|
|
1770
|
+
const base = this.resolveName(mn.baseName);
|
|
1771
|
+
const param = mn.param(0);
|
|
1772
|
+
return this.applyType(base, [param ? this.resolveName(param) : null]);
|
|
1773
|
+
}
|
|
1774
|
+
const cached = mn.cls;
|
|
1775
|
+
if (cached) {
|
|
1776
|
+
return cached;
|
|
1777
|
+
}
|
|
1778
|
+
const cls = this.getProperty(this.findDef(mn), mn);
|
|
1779
|
+
mn.cls = cls;
|
|
1780
|
+
return cls;
|
|
1781
|
+
}
|
|
1782
|
+
/** The class `mn` names as a type, as avmplus finds traits (see findScript). */
|
|
1783
|
+
typeNamed(mn) {
|
|
1784
|
+
const script = this.findScript(mn, true);
|
|
1785
|
+
if (!script) {
|
|
1786
|
+
throw this.error("ReferenceError", 1065, mn.toString());
|
|
1787
|
+
}
|
|
1788
|
+
return this.getProperty(this.initScript(script), mn);
|
|
1789
|
+
}
|
|
1790
|
+
refOf(cls) {
|
|
1791
|
+
const name = cls.$it.name;
|
|
1792
|
+
// The builtins a coercion converts to go by name, as a module names them.
|
|
1793
|
+
if (BUILTIN_REFS.has(name)) {
|
|
1794
|
+
return name;
|
|
1795
|
+
}
|
|
1796
|
+
// The class's own reference: one by its name could find another class,
|
|
1797
|
+
// as in a domain that defines the name again.
|
|
1798
|
+
if (cls.$ref?.cls !== cls) {
|
|
1799
|
+
const i = name.lastIndexOf("::");
|
|
1800
|
+
const ns = i < 0 ? publicNs : namespace(NS_Public, name.slice(0, i));
|
|
1801
|
+
const abc = cls.$it.abc;
|
|
1802
|
+
cls.$ref = new ClassRef(ns, i < 0 ? name : name.slice(i + 2), abc?.domain ?? this.root);
|
|
1803
|
+
cls.$ref.cls = cls;
|
|
1804
|
+
}
|
|
1805
|
+
return cls.$ref;
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* The instance traits a type reference names. Object's, Class's and
|
|
1809
|
+
* Function's exist before their classes, so a coercion to them works
|
|
1810
|
+
* while the builtins make them, as avmplus' does.
|
|
1811
|
+
*/
|
|
1812
|
+
traitsOfType(type) {
|
|
1813
|
+
if (type instanceof ClassRef && !type.cls && type.ns === publicNs) {
|
|
1814
|
+
switch (type.name) {
|
|
1815
|
+
case "Object":
|
|
1816
|
+
return this.objectTraits;
|
|
1817
|
+
case "Class":
|
|
1818
|
+
return this.classTraits;
|
|
1819
|
+
case "Function":
|
|
1820
|
+
return this.functionTraits;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
return this.classOf(type).$it;
|
|
1824
|
+
}
|
|
1825
|
+
isInstance(v, cls) {
|
|
1826
|
+
return this.isInstanceOf(v, cls.$it);
|
|
1827
|
+
}
|
|
1828
|
+
isInstanceOf(v, traits) {
|
|
1829
|
+
if (!traits.testsValues) {
|
|
1830
|
+
if (v === null || v === undefined) {
|
|
1831
|
+
return false;
|
|
1832
|
+
}
|
|
1833
|
+
// An object's own traits, mostly: traitsOf's instanceof checks walk its prototypes.
|
|
1834
|
+
const own = v.$traits;
|
|
1835
|
+
return own === traits || (own ?? this.traitsOf(v)).isSubtypeOf(traits);
|
|
1836
|
+
}
|
|
1837
|
+
switch (traits.name) {
|
|
1838
|
+
case "float":
|
|
1839
|
+
return v instanceof FloatValue;
|
|
1840
|
+
case "Number":
|
|
1841
|
+
return typeof v === "number" || v instanceof FloatValue;
|
|
1842
|
+
case "int":
|
|
1843
|
+
return typeof v === "number" && (v | 0) === v;
|
|
1844
|
+
case "uint":
|
|
1845
|
+
return typeof v === "number" && v >>> 0 === v;
|
|
1846
|
+
case "String":
|
|
1847
|
+
return typeof v === "string";
|
|
1848
|
+
case "Boolean":
|
|
1849
|
+
return typeof v === "boolean";
|
|
1850
|
+
default:
|
|
1851
|
+
// Object, whose instances are any value but null and undefined.
|
|
1852
|
+
return v !== null && v !== undefined;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
coerce(v, type) {
|
|
1856
|
+
switch (type) {
|
|
1857
|
+
case null:
|
|
1858
|
+
return v;
|
|
1859
|
+
case "int":
|
|
1860
|
+
return this.toInt(v);
|
|
1861
|
+
case "uint":
|
|
1862
|
+
return this.toUint(v);
|
|
1863
|
+
case "float":
|
|
1864
|
+
return this.float(v);
|
|
1865
|
+
case "Number":
|
|
1866
|
+
return this.toNumber(v);
|
|
1867
|
+
case "Boolean":
|
|
1868
|
+
return this.toBoolean(v);
|
|
1869
|
+
case "String":
|
|
1870
|
+
return this.coerceString(v);
|
|
1871
|
+
case "Object":
|
|
1872
|
+
return this.coerceObject(v);
|
|
1873
|
+
case "void":
|
|
1874
|
+
return undefined;
|
|
1875
|
+
default: {
|
|
1876
|
+
if (v === null || v === undefined) {
|
|
1877
|
+
return null;
|
|
1878
|
+
}
|
|
1879
|
+
// An instance of the class itself, most often, then any subtype.
|
|
1880
|
+
const traits = this.traitsOfType(type);
|
|
1881
|
+
if (v.$traits === traits || this.isInstanceOf(v, traits)) {
|
|
1882
|
+
return v;
|
|
1883
|
+
}
|
|
1884
|
+
throw this.error("TypeError", 1034, this.describe(v), traits.name);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
/**
|
|
1889
|
+
* coerce, to a class's instances: what code compiled against the type
|
|
1890
|
+
* calls, with no builtin to look for, and the class's traits kept on the
|
|
1891
|
+
* reference once resolved, as it always resolves to the same class.
|
|
1892
|
+
*/
|
|
1893
|
+
coerceTo(v, type) {
|
|
1894
|
+
if (v === null || v === undefined) {
|
|
1895
|
+
return null;
|
|
1896
|
+
}
|
|
1897
|
+
let traits = type.traits;
|
|
1898
|
+
if (traits === null) {
|
|
1899
|
+
traits = this.traitsOfType(type);
|
|
1900
|
+
type.traits = traits;
|
|
1901
|
+
}
|
|
1902
|
+
if (v.$traits === traits || this.isInstanceOf(v, traits)) {
|
|
1903
|
+
return v;
|
|
1904
|
+
}
|
|
1905
|
+
throw this.error("TypeError", 1034, this.describe(v), traits.name);
|
|
1906
|
+
}
|
|
1907
|
+
coerceString(v) {
|
|
1908
|
+
return v === null || v === undefined ? null : typeof v === "string" ? v : this.toString(v);
|
|
1909
|
+
}
|
|
1910
|
+
coerceObject(v) {
|
|
1911
|
+
return v === undefined ? null : v;
|
|
1912
|
+
}
|
|
1913
|
+
toObject(v) {
|
|
1914
|
+
if (v === null) {
|
|
1915
|
+
throw this.error("TypeError", 1009);
|
|
1916
|
+
}
|
|
1917
|
+
if (v === undefined) {
|
|
1918
|
+
throw this.error("TypeError", 1010);
|
|
1919
|
+
}
|
|
1920
|
+
return v;
|
|
1921
|
+
}
|
|
1922
|
+
isType(v, mn) {
|
|
1923
|
+
return this.isInstance(v, this.resolveName(mn));
|
|
1924
|
+
}
|
|
1925
|
+
asType(v, mn) {
|
|
1926
|
+
return this.isInstance(v, this.resolveName(mn)) ? v : null;
|
|
1927
|
+
}
|
|
1928
|
+
isTypeLate(v, cls) {
|
|
1929
|
+
// A class, which only class objects have instance traits for.
|
|
1930
|
+
if (cls !== null && typeof cls === "object") {
|
|
1931
|
+
const traits = cls.$it;
|
|
1932
|
+
if (traits) {
|
|
1933
|
+
return this.isInstanceOf(v, traits);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
// As Toplevel::toClassITraits: what is not an object, a Namespace
|
|
1937
|
+
// among them, as a null or undefined one is; an object not a class 1041.
|
|
1938
|
+
if (cls === null || typeof cls !== "object" || cls instanceof Namespace) {
|
|
1939
|
+
throw this.error("TypeError", cls === undefined ? 1010 : 1009);
|
|
1940
|
+
}
|
|
1941
|
+
throw this.error("TypeError", 1041);
|
|
1942
|
+
}
|
|
1943
|
+
asTypeLate(v, cls) {
|
|
1944
|
+
return this.isTypeLate(v, cls) ? v : null;
|
|
1945
|
+
}
|
|
1946
|
+
instanceOf(v, f) {
|
|
1947
|
+
if (v instanceof FloatValue) {
|
|
1948
|
+
v = v.value;
|
|
1949
|
+
}
|
|
1950
|
+
if (f === null || typeof f !== "object" || !(f.$it || f.$f)) {
|
|
1951
|
+
throw this.error("TypeError", 1040);
|
|
1952
|
+
}
|
|
1953
|
+
const target = f.$it ? f.$prototype : this.functionPrototype(f);
|
|
1954
|
+
for (let p = v === null || v === undefined ? null : this.protoOf(v); p; p = p.$p) {
|
|
1955
|
+
if (p === target) {
|
|
1956
|
+
return true;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
return false;
|
|
1960
|
+
}
|
|
1961
|
+
typeOf(v) {
|
|
1962
|
+
switch (typeof v) {
|
|
1963
|
+
case "number":
|
|
1964
|
+
case "string":
|
|
1965
|
+
case "boolean":
|
|
1966
|
+
case "undefined":
|
|
1967
|
+
return typeof v;
|
|
1968
|
+
default:
|
|
1969
|
+
if (v === null) {
|
|
1970
|
+
return "object";
|
|
1971
|
+
}
|
|
1972
|
+
if (v instanceof FloatValue) {
|
|
1973
|
+
return "number";
|
|
1974
|
+
}
|
|
1975
|
+
return v.$f
|
|
1976
|
+
? "function"
|
|
1977
|
+
: v.$traits?.name === "XML" || v.$traits?.name === "XMLList"
|
|
1978
|
+
? "xml"
|
|
1979
|
+
: "object";
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
// Conversions.
|
|
1983
|
+
float(v) {
|
|
1984
|
+
return v instanceof FloatValue ? v : floatValue(this.toNumber(v));
|
|
1985
|
+
}
|
|
1986
|
+
toNumeric(v) {
|
|
1987
|
+
if (v !== null && typeof v === "object" && !(v instanceof FloatValue)) {
|
|
1988
|
+
const n = this.arrayConversion.arrayToNumber(v);
|
|
1989
|
+
if (n !== undefined) {
|
|
1990
|
+
return n;
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
const primitive = v !== null && typeof v === "object" && !(v instanceof FloatValue)
|
|
1994
|
+
? this.toPrimitive(v, "number")
|
|
1995
|
+
: v;
|
|
1996
|
+
return primitive instanceof FloatValue ? primitive : this.toNumber(primitive);
|
|
1997
|
+
}
|
|
1998
|
+
toBoolean(v) {
|
|
1999
|
+
return v instanceof FloatValue ? !!v.value : !!v;
|
|
2000
|
+
}
|
|
2001
|
+
subtract(a, b) {
|
|
2002
|
+
const x = this.toNumeric(a);
|
|
2003
|
+
const y = this.toNumeric(b);
|
|
2004
|
+
return x instanceof FloatValue && y instanceof FloatValue
|
|
2005
|
+
? floatValue(x.value - y.value)
|
|
2006
|
+
: +x - +y;
|
|
2007
|
+
}
|
|
2008
|
+
multiply(a, b) {
|
|
2009
|
+
const x = this.toNumeric(a);
|
|
2010
|
+
const y = this.toNumeric(b);
|
|
2011
|
+
return x instanceof FloatValue && y instanceof FloatValue
|
|
2012
|
+
? floatValue(x.value * y.value)
|
|
2013
|
+
: +x * +y;
|
|
2014
|
+
}
|
|
2015
|
+
divide(a, b) {
|
|
2016
|
+
const x = this.toNumeric(a);
|
|
2017
|
+
const y = this.toNumeric(b);
|
|
2018
|
+
return x instanceof FloatValue && y instanceof FloatValue
|
|
2019
|
+
? floatValue(x.value / y.value)
|
|
2020
|
+
: +x / +y;
|
|
2021
|
+
}
|
|
2022
|
+
modulo(a, b) {
|
|
2023
|
+
const x = this.toNumeric(a);
|
|
2024
|
+
const y = this.toNumeric(b);
|
|
2025
|
+
return x instanceof FloatValue && y instanceof FloatValue
|
|
2026
|
+
? floatValue(x.value % y.value)
|
|
2027
|
+
: +x % +y;
|
|
2028
|
+
}
|
|
2029
|
+
negate(v) {
|
|
2030
|
+
const value = this.toNumeric(v);
|
|
2031
|
+
return value instanceof FloatValue ? floatValue(-value.value) : -value;
|
|
2032
|
+
}
|
|
2033
|
+
increment(v) {
|
|
2034
|
+
const value = this.toNumeric(v);
|
|
2035
|
+
return value instanceof FloatValue ? floatValue(value.value + 1) : value + 1;
|
|
2036
|
+
}
|
|
2037
|
+
decrement(v) {
|
|
2038
|
+
const value = this.toNumeric(v);
|
|
2039
|
+
return value instanceof FloatValue ? floatValue(value.value - 1) : value - 1;
|
|
2040
|
+
}
|
|
2041
|
+
toNumber(v) {
|
|
2042
|
+
switch (typeof v) {
|
|
2043
|
+
case "number":
|
|
2044
|
+
return v;
|
|
2045
|
+
case "string":
|
|
2046
|
+
return stringToNumber(v);
|
|
2047
|
+
case "boolean":
|
|
2048
|
+
return v ? 1 : 0;
|
|
2049
|
+
case "undefined":
|
|
2050
|
+
return Number.NaN;
|
|
2051
|
+
default:
|
|
2052
|
+
return v instanceof FloatValue ? v.value : v === null ? 0 : this.objectToNumber(v);
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
objectToNumber(o) {
|
|
2056
|
+
const n = this.arrayConversion.arrayToNumber(o);
|
|
2057
|
+
return n !== undefined ? n : this.toNumber(this.toPrimitive(o, "number"));
|
|
2058
|
+
}
|
|
2059
|
+
toInt(v) {
|
|
2060
|
+
return typeof v === "number" ? v | 0 : this.toNumber(v) | 0;
|
|
2061
|
+
}
|
|
2062
|
+
toUint(v) {
|
|
2063
|
+
return typeof v === "number" ? v >>> 0 : this.toNumber(v) >>> 0;
|
|
2064
|
+
}
|
|
2065
|
+
toString(v) {
|
|
2066
|
+
switch (typeof v) {
|
|
2067
|
+
case "string":
|
|
2068
|
+
return v;
|
|
2069
|
+
case "number":
|
|
2070
|
+
return numberToString(v);
|
|
2071
|
+
case "boolean":
|
|
2072
|
+
case "undefined":
|
|
2073
|
+
return String(v);
|
|
2074
|
+
default:
|
|
2075
|
+
return v instanceof FloatValue
|
|
2076
|
+
? numberToString(v.value)
|
|
2077
|
+
: v === null
|
|
2078
|
+
? "null"
|
|
2079
|
+
: this.toString(this.toPrimitive(v, "string"));
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
/** As [[DefaultValue]]: valueOf and toString, in the hint's order. */
|
|
2083
|
+
toPrimitive(o, hint) {
|
|
2084
|
+
if (o instanceof FloatValue) {
|
|
2085
|
+
return o;
|
|
2086
|
+
}
|
|
2087
|
+
// XML's is its string, as XMLObject::toString gives it.
|
|
2088
|
+
const properties = o.$traits?.properties;
|
|
2089
|
+
if (properties) {
|
|
2090
|
+
return properties.toString(this, o);
|
|
2091
|
+
}
|
|
2092
|
+
// As ScriptObject::defaultValue: each called as a property, so one
|
|
2093
|
+
// that is not a function is TypeError 1006; a Namespace is a primitive.
|
|
2094
|
+
const order = hint === "string" ? this.stringPrimitiveOrder : this.numberPrimitiveOrder;
|
|
2095
|
+
for (let i = 0; i < order.length; i++) {
|
|
2096
|
+
const v = this.callProperty(o, order[i]);
|
|
2097
|
+
if (v === null ||
|
|
2098
|
+
typeof v !== "object" ||
|
|
2099
|
+
v instanceof Namespace ||
|
|
2100
|
+
v instanceof FloatValue) {
|
|
2101
|
+
return v;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
throw this.error("TypeError", 1050, o.$traits.name);
|
|
2105
|
+
}
|
|
2106
|
+
add(a, b) {
|
|
2107
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
2108
|
+
return a + b;
|
|
2109
|
+
}
|
|
2110
|
+
if (a instanceof FloatValue && b instanceof FloatValue) {
|
|
2111
|
+
return floatValue(a.value + b.value);
|
|
2112
|
+
}
|
|
2113
|
+
// As op_add: a String or a Date beside anything concatenates both as
|
|
2114
|
+
// strings, so an object there is converted with the hint String
|
|
2115
|
+
// (toString first), not without a hint as below.
|
|
2116
|
+
if (typeof a === "string" || typeof b === "string" || this.isDate(a) || this.isDate(b)) {
|
|
2117
|
+
return this.toString(a) + this.toString(b);
|
|
2118
|
+
}
|
|
2119
|
+
if (typeof a === "object" && typeof b === "object" && a?.$traits?.properties) {
|
|
2120
|
+
const sum = a.$traits.properties.add(this, a, b);
|
|
2121
|
+
if (sum !== undefined) {
|
|
2122
|
+
return sum;
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
// A Namespace is a primitive atom to avmplus' op_add: it concatenates only beside a
|
|
2126
|
+
// string, and otherwise adds as NaN.
|
|
2127
|
+
const pa = this.addend(a);
|
|
2128
|
+
const pb = this.addend(b);
|
|
2129
|
+
if (typeof pa === "string" || typeof pb === "string") {
|
|
2130
|
+
return this.toString(pa) + this.toString(pb);
|
|
2131
|
+
}
|
|
2132
|
+
return pa instanceof FloatValue && pb instanceof FloatValue
|
|
2133
|
+
? floatValue(pa.value + pb.value)
|
|
2134
|
+
: this.toNumber(pa) + this.toNumber(pb);
|
|
2135
|
+
}
|
|
2136
|
+
addend(v) {
|
|
2137
|
+
if (v === null || typeof v !== "object" || v instanceof Namespace || v instanceof FloatValue) {
|
|
2138
|
+
return v;
|
|
2139
|
+
}
|
|
2140
|
+
// No hint: a Date, whose hint is String, concatenated above.
|
|
2141
|
+
return this.toPrimitive(v, "number");
|
|
2142
|
+
}
|
|
2143
|
+
isDate(v) {
|
|
2144
|
+
return typeof v === "object" && v !== null && v.$traits?.name === "Date";
|
|
2145
|
+
}
|
|
2146
|
+
equals(a, b) {
|
|
2147
|
+
if (a instanceof FloatValue) {
|
|
2148
|
+
a = a.value;
|
|
2149
|
+
}
|
|
2150
|
+
if (b instanceof FloatValue) {
|
|
2151
|
+
b = b.value;
|
|
2152
|
+
}
|
|
2153
|
+
if (typeof a === "object" || typeof b === "object") {
|
|
2154
|
+
const e = this.objectEquals(a, b);
|
|
2155
|
+
if (e !== undefined) {
|
|
2156
|
+
return e;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
if (typeof a === typeof b) {
|
|
2160
|
+
return a === b;
|
|
2161
|
+
}
|
|
2162
|
+
if (a == null && b == null) {
|
|
2163
|
+
return true;
|
|
2164
|
+
}
|
|
2165
|
+
if (a == null || b == null) {
|
|
2166
|
+
return false;
|
|
2167
|
+
}
|
|
2168
|
+
// Without a hint, which is valueOf first, a Date's too: AvmCore::equals
|
|
2169
|
+
// compares a Date with a String by its time, unlike ECMAScript.
|
|
2170
|
+
if (typeof a === "object") {
|
|
2171
|
+
return this.equals(this.toPrimitive(a, "number"), b);
|
|
2172
|
+
}
|
|
2173
|
+
if (typeof b === "object") {
|
|
2174
|
+
return this.equals(a, this.toPrimitive(b, "number"));
|
|
2175
|
+
}
|
|
2176
|
+
return this.toNumber(a) === this.toNumber(b);
|
|
2177
|
+
}
|
|
2178
|
+
/**
|
|
2179
|
+
* == where either side is an object, as E4X has it (11.5.1): XML and
|
|
2180
|
+
* XMLList by their hook, QNames by URI and local name, Namespaces by URI.
|
|
2181
|
+
*/
|
|
2182
|
+
objectEquals(a, b) {
|
|
2183
|
+
if (a === b) {
|
|
2184
|
+
return true;
|
|
2185
|
+
}
|
|
2186
|
+
const properties = a?.$traits?.properties ?? b?.$traits?.properties;
|
|
2187
|
+
if (properties) {
|
|
2188
|
+
return properties.equals(this, a, b);
|
|
2189
|
+
}
|
|
2190
|
+
if (a instanceof Namespace && b instanceof Namespace) {
|
|
2191
|
+
return a.kind !== NS_Private && a.kind === b.kind && a.uri === b.uri;
|
|
2192
|
+
}
|
|
2193
|
+
if (a?.$local !== undefined && b?.$local !== undefined) {
|
|
2194
|
+
return (a.$ns?.uri ?? null) === (b.$ns?.uri ?? null) && a.$local === b.$local;
|
|
2195
|
+
}
|
|
2196
|
+
return undefined;
|
|
2197
|
+
}
|
|
2198
|
+
strictEquals(a, b) {
|
|
2199
|
+
if (a instanceof FloatValue || b instanceof FloatValue) {
|
|
2200
|
+
return a instanceof FloatValue && b instanceof FloatValue && a.value === b.value;
|
|
2201
|
+
}
|
|
2202
|
+
return a === b;
|
|
2203
|
+
}
|
|
2204
|
+
compare(a, b) {
|
|
2205
|
+
const pa = a !== null && typeof a === "object" ? this.toPrimitive(a, "number") : a;
|
|
2206
|
+
const pb = b !== null && typeof b === "object" ? this.toPrimitive(b, "number") : b;
|
|
2207
|
+
if (typeof pa === "string" && typeof pb === "string") {
|
|
2208
|
+
return pa < pb ? -1 : pa > pb ? 1 : 0;
|
|
2209
|
+
}
|
|
2210
|
+
const x = this.toNumber(pa);
|
|
2211
|
+
const y = this.toNumber(pb);
|
|
2212
|
+
if (Number.isNaN(x) || Number.isNaN(y)) {
|
|
2213
|
+
return undefined;
|
|
2214
|
+
}
|
|
2215
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
2216
|
+
}
|
|
2217
|
+
lessThan(a, b) {
|
|
2218
|
+
const c = this.compare(a, b);
|
|
2219
|
+
return c !== undefined && c < 0;
|
|
2220
|
+
}
|
|
2221
|
+
lessEquals(a, b) {
|
|
2222
|
+
const c = this.compare(a, b);
|
|
2223
|
+
return c !== undefined && c <= 0;
|
|
2224
|
+
}
|
|
2225
|
+
greaterThan(a, b) {
|
|
2226
|
+
const c = this.compare(a, b);
|
|
2227
|
+
return c !== undefined && c > 0;
|
|
2228
|
+
}
|
|
2229
|
+
greaterEquals(a, b) {
|
|
2230
|
+
const c = this.compare(a, b);
|
|
2231
|
+
return c !== undefined && c >= 0;
|
|
2232
|
+
}
|
|
2233
|
+
// Iteration: an index counts through an object's own names, then its
|
|
2234
|
+
// prototypes'. As avmplus' hashtable slots, it counts every name, hidden
|
|
2235
|
+
// or not, so hiding one during a for-in (as _dontEnumPrototype does) does
|
|
2236
|
+
// not move the others.
|
|
2237
|
+
/**
|
|
2238
|
+
* hasnext2: whether `o` or an object on its prototype chain has a name
|
|
2239
|
+
* past `index`, the object and the index then in enumObject and
|
|
2240
|
+
* enumIndex, which compiled code reads back rather than taking them apart
|
|
2241
|
+
* from an array at every step.
|
|
2242
|
+
*/
|
|
2243
|
+
hasNextIn(o, index) {
|
|
2244
|
+
let obj = o;
|
|
2245
|
+
let i = index;
|
|
2246
|
+
while (obj !== null && obj !== undefined) {
|
|
2247
|
+
// A step that goes on from the last is over an ordinary object: no hook, no QName.
|
|
2248
|
+
const next = continues(obj, i) ? nextIndex(this.enumerating, obj, i) : this.hasNext(obj, i);
|
|
2249
|
+
if (next) {
|
|
2250
|
+
this.enumObject = obj;
|
|
2251
|
+
this.enumIndex = next;
|
|
2252
|
+
return true;
|
|
2253
|
+
}
|
|
2254
|
+
// Then the prototypes, most of which have nothing to go through.
|
|
2255
|
+
obj = this.protoOf(obj);
|
|
2256
|
+
while (obj !== null && obj !== undefined && walkless(obj)) {
|
|
2257
|
+
obj = obj.$p;
|
|
2258
|
+
}
|
|
2259
|
+
i = 0;
|
|
2260
|
+
}
|
|
2261
|
+
this.enumObject = null;
|
|
2262
|
+
this.enumIndex = 0;
|
|
2263
|
+
return false;
|
|
2264
|
+
}
|
|
2265
|
+
/** hasNextIn's results as one array, as modules compiled before it take them. */
|
|
2266
|
+
hasNext2(o, index) {
|
|
2267
|
+
const has = this.hasNextIn(o, index);
|
|
2268
|
+
return [has, this.enumObject, this.enumIndex];
|
|
2269
|
+
}
|
|
2270
|
+
hasNext(o, index) {
|
|
2271
|
+
if (typeof o !== "object" || o === null) {
|
|
2272
|
+
return 0;
|
|
2273
|
+
}
|
|
2274
|
+
const properties = o.$traits?.properties;
|
|
2275
|
+
if (properties) {
|
|
2276
|
+
return properties.nextIndex(this, o, index);
|
|
2277
|
+
}
|
|
2278
|
+
return pairOf(o) ? pairIndex(index) : nextIndex(this.enumerating, o, index);
|
|
2279
|
+
}
|
|
2280
|
+
/** As avmplus gives a for-in's name: an index as a number while an int atom holds it, a Dictionary's object key as itself. */
|
|
2281
|
+
nextName(o, index) {
|
|
2282
|
+
// The step the last hasNextIn took is over an ordinary object: no hook, no QName.
|
|
2283
|
+
if (!continues(o, index)) {
|
|
2284
|
+
const properties = o?.$traits?.properties;
|
|
2285
|
+
if (properties) {
|
|
2286
|
+
return properties.nextName(this, o, index);
|
|
2287
|
+
}
|
|
2288
|
+
const pair = pairOf(o);
|
|
2289
|
+
if (pair) {
|
|
2290
|
+
return index === 1 ? "uri" : index === 2 ? pair : null;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
// As avmplus' ArrayObject and TypedVectorObject: the elements, then the other names.
|
|
2294
|
+
const length = elementsAt(o, index);
|
|
2295
|
+
if (index > 0 && index <= length) {
|
|
2296
|
+
const element = index - 1;
|
|
2297
|
+
return element < INT_ATOM_LIMIT ? element : String(element);
|
|
2298
|
+
}
|
|
2299
|
+
const keys = dictionaryAt(o, index);
|
|
2300
|
+
const name = keys !== null ? keys.nameAt(index - length) : enumerated(o, index - length, index);
|
|
2301
|
+
if (typeof name !== "string") {
|
|
2302
|
+
return name;
|
|
2303
|
+
}
|
|
2304
|
+
const i = arrayIndex(name);
|
|
2305
|
+
return i >= 0 && i < INT_ATOM_LIMIT ? i : name;
|
|
2306
|
+
}
|
|
2307
|
+
nextValue(o, index) {
|
|
2308
|
+
const traits = o?.$traits;
|
|
2309
|
+
if (!continues(o, index)) {
|
|
2310
|
+
const properties = traits?.properties;
|
|
2311
|
+
if (properties) {
|
|
2312
|
+
return properties.nextValue(this, o, index);
|
|
2313
|
+
}
|
|
2314
|
+
// As avmplus: a QName's values come localName first, though its names come uri first.
|
|
2315
|
+
const pair = pairOf(o);
|
|
2316
|
+
if (pair === "prefix") {
|
|
2317
|
+
return index === 1 ? o.uri : index === 2 ? prefixOf(o) : undefined;
|
|
2318
|
+
}
|
|
2319
|
+
if (pair === "localName") {
|
|
2320
|
+
const uri = o.$ns ? o.$ns.uri : null;
|
|
2321
|
+
const local = o.$local ?? "*";
|
|
2322
|
+
return index === 1 ? local : index === 2 ? uri : null;
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
const length = elementsAt(o, index);
|
|
2326
|
+
if (index > 0 && index <= length) {
|
|
2327
|
+
const element = index - 1;
|
|
2328
|
+
if (traits?.getIndex) {
|
|
2329
|
+
return traits.getIndex(o, element, this);
|
|
2330
|
+
}
|
|
2331
|
+
if (traits === this.arrayTraits) {
|
|
2332
|
+
// A hole reads undefined too: only then is `in` asked.
|
|
2333
|
+
const value = o.$a[element];
|
|
2334
|
+
if (value !== undefined || element in o.$a) {
|
|
2335
|
+
return value;
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
// A Dictionary's key gives its value from its slot, without looking it up.
|
|
2340
|
+
const keys = dictionaryAt(o, index);
|
|
2341
|
+
const value = keys?.valueAt(index - length);
|
|
2342
|
+
if (keys !== null && value !== NAMED) {
|
|
2343
|
+
return value;
|
|
2344
|
+
}
|
|
2345
|
+
// Else a Dictionary's slot holds a dynamic property's name.
|
|
2346
|
+
const name = keys !== null
|
|
2347
|
+
? keys.nameAt(index - length)
|
|
2348
|
+
: index <= length
|
|
2349
|
+
? String(index - 1)
|
|
2350
|
+
: enumerated(o, index - length, index);
|
|
2351
|
+
// A dynamic property's value, as avmplus' nextValue reads its slot's:
|
|
2352
|
+
// no binding has its name, which setting it would have gone to.
|
|
2353
|
+
const dynamic = dynamicValue(o, name);
|
|
2354
|
+
if (dynamic !== NOT_FOUND) {
|
|
2355
|
+
return dynamic;
|
|
2356
|
+
}
|
|
2357
|
+
// These builtins have no bindings over their enumerated own properties.
|
|
2358
|
+
// A missing value still needs the full lookup, including the prototype.
|
|
2359
|
+
if (traits === this.arrayTraits || traits === this.objectTraits) {
|
|
2360
|
+
const own = this.getOwn(o, name);
|
|
2361
|
+
if (own !== NOT_FOUND) {
|
|
2362
|
+
return own;
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
return this.getProperty(o, this.publicName(name));
|
|
2366
|
+
}
|
|
2367
|
+
// Errors.
|
|
2368
|
+
/** A new AS3 error of builtin class `name`, number `id`, with its message's arguments. */
|
|
2369
|
+
error(name, id, ...args) {
|
|
2370
|
+
const message = this.errorMessage(id, args);
|
|
2371
|
+
let cls;
|
|
2372
|
+
try {
|
|
2373
|
+
// A class outside the unnamed package goes by its qualified name.
|
|
2374
|
+
const at = name.lastIndexOf("::");
|
|
2375
|
+
cls =
|
|
2376
|
+
at < 0
|
|
2377
|
+
? this.builtinClass(name)
|
|
2378
|
+
: this.resolve(this.cls(namespace(NS_Public, name.slice(0, at)), name.slice(at + 2)));
|
|
2379
|
+
}
|
|
2380
|
+
catch {
|
|
2381
|
+
return new AsError(`${name}: ${message}`);
|
|
2382
|
+
}
|
|
2383
|
+
return this.constructClass(cls, [message, id]);
|
|
2384
|
+
}
|
|
2385
|
+
/** See stackOf in errors.ts. */
|
|
2386
|
+
stackOf(error) {
|
|
2387
|
+
return stackOf(error);
|
|
2388
|
+
}
|
|
2389
|
+
/** See errorMessage in errors.ts. */
|
|
2390
|
+
errorMessage(id, args = []) {
|
|
2391
|
+
return errorMessage(this.debugger, id, args);
|
|
2392
|
+
}
|
|
2393
|
+
/** As MethodEnv::argcError: ArgumentError 1063, with the count required and the count given. */
|
|
2394
|
+
argumentCountError(required, given) {
|
|
2395
|
+
return this.error("ArgumentError", 1063, "function", required, given);
|
|
2396
|
+
}
|
|
2397
|
+
nullError(v) {
|
|
2398
|
+
return this.error("TypeError", v === undefined ? 1010 : 1009);
|
|
2399
|
+
}
|
|
2400
|
+
/** See describe in errors.ts. */
|
|
2401
|
+
describe(v) {
|
|
2402
|
+
return describe(this, v);
|
|
2403
|
+
}
|
|
2404
|
+
/** An exception as AS3 catches it: a stack overflow is an AS3 Error; the runtime's own errors are not caught. */
|
|
2405
|
+
caught(e) {
|
|
2406
|
+
if (e instanceof RangeError && /call stack/.test(e.message)) {
|
|
2407
|
+
return this.error("Error", 1023);
|
|
2408
|
+
}
|
|
2409
|
+
// Domain memory's, in the handler's own method (see memoryError).
|
|
2410
|
+
if (isViewRangeError(e)) {
|
|
2411
|
+
return this.error("RangeError", 1506);
|
|
2412
|
+
}
|
|
2413
|
+
if (e instanceof Error && !(e instanceof AsError)) {
|
|
2414
|
+
throw e;
|
|
2415
|
+
}
|
|
2416
|
+
return e;
|
|
2417
|
+
}
|
|
2418
|
+
catches(e, type) {
|
|
2419
|
+
return this.isInstanceOf(e, this.traitsOfType(type));
|
|
2420
|
+
}
|
|
2421
|
+
unreachable() {
|
|
2422
|
+
return new Error("swf2es: a dispatcher reached no block");
|
|
2423
|
+
}
|
|
2424
|
+
unsupported(what) {
|
|
2425
|
+
return new Error(`swf2es: ${what} is not supported yet`);
|
|
2426
|
+
}
|
|
2427
|
+
// Class aliases and the classes AMF makes (amf-classes.ts).
|
|
2428
|
+
registerClassAlias(name, cls) {
|
|
2429
|
+
this.amfClasses.registerClassAlias(name, cls);
|
|
2430
|
+
}
|
|
2431
|
+
aliasOf(traits) {
|
|
2432
|
+
return this.amfClasses.aliasOf(traits);
|
|
2433
|
+
}
|
|
2434
|
+
classByAlias(name, orObject = false) {
|
|
2435
|
+
return this.amfClasses.classByAlias(name, orObject);
|
|
2436
|
+
}
|
|
2437
|
+
byteArrayClass() {
|
|
2438
|
+
return this.amfClasses.byteArrayClass();
|
|
2439
|
+
}
|
|
2440
|
+
dictionaryClass() {
|
|
2441
|
+
return this.amfClasses.dictionaryClass();
|
|
2442
|
+
}
|
|
2443
|
+
vectorClass(param) {
|
|
2444
|
+
return this.amfClasses.vectorClass(param);
|
|
2445
|
+
}
|
|
2446
|
+
/** Each Vector class made, by its element class (null for *), kept by Vector's apply. */
|
|
2447
|
+
vectorClasses = new Map();
|
|
2448
|
+
/** An object's own names a for-in visits, in its order: its string names, not a Dictionary's object keys. */
|
|
2449
|
+
enumerableNames(o) {
|
|
2450
|
+
return ownNames(o).filter((n) => typeof n === "string" && !o.$dontEnum?.has(n));
|
|
2451
|
+
}
|
|
2452
|
+
/**
|
|
2453
|
+
* avmshell's avmplus.Domain.currentDomain, as DomainClass::get_currentDomain:
|
|
2454
|
+
* a new instance of Domain, without running its constructor, for the
|
|
2455
|
+
* calling code's domain.
|
|
2456
|
+
*/
|
|
2457
|
+
currentDomain() {
|
|
2458
|
+
const domain = this.resolve(this.cls(namespace(NS_Public, "avmplus"), "Domain")).$it.instance();
|
|
2459
|
+
domain.$domain = this.codeDomain();
|
|
2460
|
+
return domain;
|
|
2461
|
+
}
|
|
2462
|
+
// Domain memory, as avmplus' MOPS: little-endian, an address outside the
|
|
2463
|
+
// memory a RangeError.
|
|
2464
|
+
/** The domain memory: where li8 and the other opcodes read and write, with its length. */
|
|
2465
|
+
get memory() {
|
|
2466
|
+
return this.memoryView;
|
|
2467
|
+
}
|
|
2468
|
+
set memory(view) {
|
|
2469
|
+
this.memoryView = view;
|
|
2470
|
+
this.memoryLength = view.byteLength;
|
|
2471
|
+
if (!this.refresh) {
|
|
2472
|
+
this.view = view;
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* For domain memory another worker shares: its length read again, which
|
|
2477
|
+
* that worker may have changed, before an address past it is rejected.
|
|
2478
|
+
*/
|
|
2479
|
+
get refreshMemory() {
|
|
2480
|
+
return this.refresh;
|
|
2481
|
+
}
|
|
2482
|
+
set refreshMemory(refresh) {
|
|
2483
|
+
this.refresh = refresh;
|
|
2484
|
+
this.view = refresh ? new SharedMemoryView(this) : this.memoryView;
|
|
2485
|
+
}
|
|
2486
|
+
/**
|
|
2487
|
+
* An exception thrown in a method that loads or stores domain memory in
|
|
2488
|
+
* place, as its callers see it: the view's RangeError for an address out
|
|
2489
|
+
* of range made avmplus', anything else as it is.
|
|
2490
|
+
*/
|
|
2491
|
+
memoryError(e) {
|
|
2492
|
+
return isViewRangeError(e) ? this.error("RangeError", 1506) : e;
|
|
2493
|
+
}
|
|
2494
|
+
/** `address` as an int, once checked that the domain memory holds `size` bytes there. */
|
|
2495
|
+
mops(address, size) {
|
|
2496
|
+
const a = this.toInt(address);
|
|
2497
|
+
if (a < 0 || a + size > this.memoryLength) {
|
|
2498
|
+
this.refreshMemory?.();
|
|
2499
|
+
if (a < 0 || a + size > this.memoryLength) {
|
|
2500
|
+
throw this.error("RangeError", 1506);
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
return a;
|
|
2504
|
+
}
|
|
2505
|
+
li8(address) {
|
|
2506
|
+
const at = this.mops(address, 1);
|
|
2507
|
+
return this.memoryView.getUint8(at);
|
|
2508
|
+
}
|
|
2509
|
+
li16(address) {
|
|
2510
|
+
const at = this.mops(address, 2);
|
|
2511
|
+
return this.memoryView.getUint16(at, true);
|
|
2512
|
+
}
|
|
2513
|
+
li32(address) {
|
|
2514
|
+
const at = this.mops(address, 4);
|
|
2515
|
+
return this.memoryView.getInt32(at, true);
|
|
2516
|
+
}
|
|
2517
|
+
lf32(address) {
|
|
2518
|
+
const at = this.mops(address, 4);
|
|
2519
|
+
return this.memoryView.getFloat32(at, true);
|
|
2520
|
+
}
|
|
2521
|
+
lf64(address) {
|
|
2522
|
+
const at = this.mops(address, 8);
|
|
2523
|
+
return this.memoryView.getFloat64(at, true);
|
|
2524
|
+
}
|
|
2525
|
+
si8(value, address) {
|
|
2526
|
+
const at = this.mops(address, 1);
|
|
2527
|
+
this.memoryView.setUint8(at, this.toInt(value));
|
|
2528
|
+
}
|
|
2529
|
+
si16(value, address) {
|
|
2530
|
+
const at = this.mops(address, 2);
|
|
2531
|
+
this.memoryView.setUint16(at, this.toInt(value), true);
|
|
2532
|
+
}
|
|
2533
|
+
si32(value, address) {
|
|
2534
|
+
const at = this.mops(address, 4);
|
|
2535
|
+
this.memoryView.setInt32(at, this.toInt(value), true);
|
|
2536
|
+
}
|
|
2537
|
+
sf32(value, address) {
|
|
2538
|
+
const at = this.mops(address, 4);
|
|
2539
|
+
this.memoryView.setFloat32(at, this.toNumber(value), true);
|
|
2540
|
+
}
|
|
2541
|
+
sf64(value, address) {
|
|
2542
|
+
const at = this.mops(address, 8);
|
|
2543
|
+
this.memoryView.setFloat64(at, this.toNumber(value), true);
|
|
2544
|
+
}
|
|
2545
|
+
// E4X.
|
|
2546
|
+
/** getdescendants: x..name, on XML or XMLList; anything else, as avmplus, TypeError 1016. */
|
|
2547
|
+
getDescendants(o, mn) {
|
|
2548
|
+
const properties = o?.$traits?.properties;
|
|
2549
|
+
if (!properties) {
|
|
2550
|
+
throw this.error("TypeError", 1016, this.describe(o));
|
|
2551
|
+
}
|
|
2552
|
+
return properties.descendants(this, o, mn);
|
|
2553
|
+
}
|
|
2554
|
+
/**
|
|
2555
|
+
* The default XML namespace, as dxns and dxnslate set it. avmplus keeps
|
|
2556
|
+
* it for each frame: one a method set, else the one of the scope the
|
|
2557
|
+
* method was made in. Here the runtime has the current one: each
|
|
2558
|
+
* method's factory captures it, and the method runs with that one
|
|
2559
|
+
* (callInDxns); one that sets it gives its caller's back.
|
|
2560
|
+
*/
|
|
2561
|
+
defaultXmlNamespace = publicNs;
|
|
2562
|
+
/** On entering a method that sets the default XML namespace: the one to give back on leaving it. */
|
|
2563
|
+
enterDxns() {
|
|
2564
|
+
return this.defaultXmlNamespace;
|
|
2565
|
+
}
|
|
2566
|
+
setDefaultXmlNamespace(ns) {
|
|
2567
|
+
if (ns instanceof Namespace) {
|
|
2568
|
+
this.defaultXmlNamespace = ns;
|
|
2569
|
+
}
|
|
2570
|
+
else {
|
|
2571
|
+
const uri = this.toString(ns);
|
|
2572
|
+
this.defaultXmlNamespace = prefixedNamespace(uri === "" ? "" : undefined, uri);
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
/** checkfilter: x.(...) filters XML and XMLList only, else TypeError 1123. */
|
|
2576
|
+
checkFilter(v) {
|
|
2577
|
+
if (!v?.$traits?.properties) {
|
|
2578
|
+
throw this.error("TypeError", 1123, this.describe(v));
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
/** esc_xelem, as AvmCore::ToXMLString: XML's own XML, else a string escaped and trimmed. */
|
|
2582
|
+
escapeElement(v) {
|
|
2583
|
+
if (typeof v === "string") {
|
|
2584
|
+
return escapeElementValue(v, true);
|
|
2585
|
+
}
|
|
2586
|
+
if (typeof v !== "object" || v === null) {
|
|
2587
|
+
return this.toString(v);
|
|
2588
|
+
}
|
|
2589
|
+
const properties = v.$traits?.properties;
|
|
2590
|
+
if (properties) {
|
|
2591
|
+
return properties.toXMLString(this, v);
|
|
2592
|
+
}
|
|
2593
|
+
return escapeElementValue(this.toString(v), true);
|
|
2594
|
+
}
|
|
2595
|
+
escapeAttribute(v) {
|
|
2596
|
+
return escapeAttributeValue(this.toString(v));
|
|
2597
|
+
}
|
|
2598
|
+
// Methods whose bodies are not generated.
|
|
2599
|
+
/** A native method, bound by its name; one the runtime lacks throws when called. */
|
|
2600
|
+
native(name, required = 0, max = -1) {
|
|
2601
|
+
return nativeFactory(this, name, required, max);
|
|
2602
|
+
}
|
|
2603
|
+
/**
|
|
2604
|
+
* A bound method called with arguments the verifier did not see: a
|
|
2605
|
+
* native's count checked, as MethodEnv's argcOk does. A compiled method
|
|
2606
|
+
* checks its own.
|
|
2607
|
+
*/
|
|
2608
|
+
callBound(f, o, args) {
|
|
2609
|
+
// biome-ignore lint/style/useConst: a const is folded into a tail call (see Runtime.getProperty)
|
|
2610
|
+
let r;
|
|
2611
|
+
const min = f.$min;
|
|
2612
|
+
if (min !== undefined) {
|
|
2613
|
+
const max = f.$max;
|
|
2614
|
+
if (args.length < min || (max >= 0 && args.length > max)) {
|
|
2615
|
+
throw this.argumentCountError(min, args.length);
|
|
2616
|
+
}
|
|
2617
|
+
// A native's primitive and Object parameters, coerced as avmplus coerces them on entry.
|
|
2618
|
+
const types = f.$coerce;
|
|
2619
|
+
if (types !== undefined) {
|
|
2620
|
+
for (let i = 0; i < args.length && i < types.length; i++) {
|
|
2621
|
+
const type = types[i];
|
|
2622
|
+
if (type !== null) {
|
|
2623
|
+
args[i] = this.coerce(args[i], type);
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
r = f.apply(o, args);
|
|
2629
|
+
return r;
|
|
2630
|
+
}
|
|
2631
|
+
get noBody() {
|
|
2632
|
+
return noBodyFactory(this);
|
|
2633
|
+
}
|
|
2634
|
+
get unverified() {
|
|
2635
|
+
return unverifiedFactory(this);
|
|
2636
|
+
}
|
|
2637
|
+
verifyError(id) {
|
|
2638
|
+
return verifyErrorFactory(this, id);
|
|
2639
|
+
}
|
|
2640
|
+
isPrimitive(v) {
|
|
2641
|
+
return (v instanceof FloatValue || v === null || (typeof v !== "object" && typeof v !== "function"));
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
const BUILTIN_REFS = new Set(["int", "uint", "Number", "float", "String", "Boolean", "Object"]);
|