avm2: Move some builtin classes to `Toplevel.as`
Ensure that those classes are loaded before the other classes.
This commit is contained in:
parent
506b6a9ad2
commit
4b34efaa54
|
@ -4,7 +4,9 @@ use std::rc::Rc;
|
|||
|
||||
use crate::avm2::class::AllocatorFn;
|
||||
use crate::avm2::error::make_error_1107;
|
||||
use crate::avm2::globals::{SystemClassDefs, SystemClasses};
|
||||
use crate::avm2::globals::{
|
||||
init_builtin_system_classes, init_native_system_classes, SystemClassDefs, SystemClasses,
|
||||
};
|
||||
use crate::avm2::method::{Method, NativeMethodImpl};
|
||||
use crate::avm2::scope::ScopeChain;
|
||||
use crate::avm2::script::{Script, TranslationUnit};
|
||||
|
@ -648,8 +650,7 @@ impl<'gc> Avm2<'gc> {
|
|||
activation.set_outer(ScopeChain::new(domain));
|
||||
|
||||
let num_scripts = abc.scripts.len();
|
||||
let tunit =
|
||||
TranslationUnit::from_abc(abc, domain, name, movie, activation.context.gc_context);
|
||||
let tunit = TranslationUnit::from_abc(abc, domain, name, movie, activation.gc());
|
||||
tunit.load_classes(&mut activation)?;
|
||||
for i in 0..num_scripts {
|
||||
tunit.load_script(i as u32, &mut activation)?;
|
||||
|
@ -661,6 +662,44 @@ impl<'gc> Avm2<'gc> {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
/// Load the playerglobal ABC file.
|
||||
pub fn load_builtin_abc(
|
||||
context: &mut UpdateContext<'gc>,
|
||||
data: &[u8],
|
||||
domain: Domain<'gc>,
|
||||
movie: Arc<SwfMovie>,
|
||||
) {
|
||||
let mut reader = Reader::new(data);
|
||||
let abc = match reader.read() {
|
||||
Ok(abc) => abc,
|
||||
Err(_) => panic!("Builtin ABC should be valid"),
|
||||
};
|
||||
|
||||
let mut activation = Activation::from_domain(context, domain);
|
||||
// Make sure we have the correct domain for code that tries to access it
|
||||
// using `activation.domain()`
|
||||
activation.set_outer(ScopeChain::new(domain));
|
||||
|
||||
let tunit = TranslationUnit::from_abc(abc, domain, None, movie, activation.gc());
|
||||
tunit
|
||||
.load_classes(&mut activation)
|
||||
.expect("Classes should load");
|
||||
|
||||
// The second script (script #1) is Toplevel.as, and includes important
|
||||
// builtin classes such as Namespace, QName, and XML.
|
||||
tunit
|
||||
.load_script(1, &mut activation)
|
||||
.expect("Script should load");
|
||||
init_builtin_system_classes(&mut activation);
|
||||
|
||||
// The first script (script #0) is globals.as, and includes other builtin
|
||||
// classes that are less critical for the AVM to load.
|
||||
tunit
|
||||
.load_script(0, &mut activation)
|
||||
.expect("Script should load");
|
||||
init_native_system_classes(&mut activation);
|
||||
}
|
||||
|
||||
pub fn stage_domain(&self) -> Domain<'gc> {
|
||||
self.stage_domain
|
||||
}
|
||||
|
|
|
@ -777,91 +777,49 @@ mod native {
|
|||
include!(concat!(env!("OUT_DIR"), "/native_table.rs"));
|
||||
}
|
||||
|
||||
/// Loads classes from our custom 'playerglobal' (which are written in ActionScript)
|
||||
/// into the environment. See 'core/src/avm2/globals/README.md' for more information
|
||||
fn load_playerglobal<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
domain: Domain<'gc>,
|
||||
) -> Result<(), Error<'gc>> {
|
||||
activation.avm2().native_method_table = native::NATIVE_METHOD_TABLE;
|
||||
activation.avm2().native_instance_allocator_table = native::NATIVE_INSTANCE_ALLOCATOR_TABLE;
|
||||
activation.avm2().native_super_initializer_table = native::NATIVE_SUPER_INITIALIZER_TABLE;
|
||||
activation.avm2().native_call_handler_table = native::NATIVE_CALL_HANDLER_TABLE;
|
||||
|
||||
let movie = Arc::new(
|
||||
SwfMovie::from_data(PLAYERGLOBAL, "file:///".into(), None)
|
||||
.expect("playerglobal.swf should be valid"),
|
||||
);
|
||||
|
||||
let slice = SwfSlice::from(movie.clone());
|
||||
|
||||
let mut reader = slice.read_from(0);
|
||||
|
||||
let tag_callback = |reader: &mut SwfStream<'_>, tag_code, _tag_len| {
|
||||
if tag_code == TagCode::DoAbc2 {
|
||||
let do_abc = reader
|
||||
.read_do_abc_2()
|
||||
.expect("playerglobal.swf should be valid");
|
||||
Avm2::do_abc(
|
||||
activation.context,
|
||||
do_abc.data,
|
||||
None,
|
||||
do_abc.flags,
|
||||
domain,
|
||||
movie.clone(),
|
||||
)
|
||||
.expect("playerglobal.swf should be valid");
|
||||
} else if tag_code != TagCode::End {
|
||||
panic!("playerglobal should only contain `DoAbc2` tag - found tag {tag_code:?}")
|
||||
}
|
||||
Ok(ControlFlow::Continue)
|
||||
};
|
||||
|
||||
let _ = tag_utils::decode_tags(&mut reader, tag_callback);
|
||||
macro_rules! avm2_system_classes_playerglobal {
|
||||
($activation:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => {
|
||||
let activation = $activation;
|
||||
$(
|
||||
// Lookup with the highest version, so we we see all defined classes here
|
||||
let ns = Namespace::package($package, ApiVersion::VM_INTERNAL, &mut activation.borrow_gc());
|
||||
let name = QName::new(ns, $class_name);
|
||||
let class_object = activation.domain().get_defined_value(activation, name).unwrap_or_else(|e| panic!("Failed to lookup {name:?}: {e:?}"));
|
||||
let class_object = class_object.as_object().unwrap().as_class_object().unwrap();
|
||||
let sc = activation.avm2().system_classes.as_mut().unwrap();
|
||||
sc.$field = class_object;
|
||||
)*
|
||||
}
|
||||
// This acts the same way as 'avm2_system_class', but for classes
|
||||
// declared in 'playerglobal'. Classes are declared as ("package", "class", field_name),
|
||||
// and are stored in 'avm2().system_classes'
|
||||
macro_rules! avm2_system_classes_playerglobal {
|
||||
($activation:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => {
|
||||
let activation = $activation;
|
||||
$(
|
||||
// Lookup with the highest version, so we we see all defined classes here
|
||||
let ns = Namespace::package($package, ApiVersion::VM_INTERNAL, &mut activation.borrow_gc());
|
||||
let name = QName::new(ns, $class_name);
|
||||
let class_object = activation.domain().get_defined_value(activation, name).unwrap_or_else(|e| panic!("Failed to lookup {name:?}: {e:?}"));
|
||||
let class_object = class_object.as_object().unwrap().as_class_object().unwrap();
|
||||
let sc = activation.avm2().system_classes.as_mut().unwrap();
|
||||
sc.$field = class_object;
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! avm2_system_class_defs_playerglobal {
|
||||
($activation:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => {
|
||||
let activation = $activation;
|
||||
$(
|
||||
// Lookup with the highest version, so we we see all defined classes here
|
||||
let ns = Namespace::package($package, ApiVersion::VM_INTERNAL, &mut activation.borrow_gc());
|
||||
let name = QName::new(ns, $class_name);
|
||||
let class_object = activation.domain().get_defined_value(activation, name).unwrap_or_else(|e| panic!("Failed to lookup {name:?}: {e:?}"));
|
||||
let class_def = class_object.as_object().unwrap().as_class_object().unwrap().inner_class_definition();
|
||||
let sc = activation.avm2().system_class_defs.as_mut().unwrap();
|
||||
sc.$field = class_def;
|
||||
)*
|
||||
}
|
||||
macro_rules! avm2_system_class_defs_playerglobal {
|
||||
($activation:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => {
|
||||
let activation = $activation;
|
||||
$(
|
||||
// Lookup with the highest version, so we we see all defined classes here
|
||||
let ns = Namespace::package($package, ApiVersion::VM_INTERNAL, &mut activation.borrow_gc());
|
||||
let name = QName::new(ns, $class_name);
|
||||
let class_object = activation.domain().get_defined_value(activation, name).unwrap_or_else(|e| panic!("Failed to lookup {name:?}: {e:?}"));
|
||||
let class_def = class_object.as_object().unwrap().as_class_object().unwrap().inner_class_definition();
|
||||
let sc = activation.avm2().system_class_defs.as_mut().unwrap();
|
||||
sc.$field = class_def;
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
// This acts the same way as 'avm2_system_class', but for classes
|
||||
// declared in 'playerglobal'. Classes are declared as ("package", "class", field_name),
|
||||
// and are stored in 'avm2().system_classes'
|
||||
pub fn init_builtin_system_classes<'gc>(activation: &mut Activation<'_, 'gc>) {
|
||||
avm2_system_classes_playerglobal!(
|
||||
&mut *activation,
|
||||
[
|
||||
("", "Date", date),
|
||||
("", "Error", error),
|
||||
("", "ArgumentError", argumenterror),
|
||||
("", "QName", qname),
|
||||
("", "EvalError", evalerror),
|
||||
("", "Namespace", namespace),
|
||||
("", "RangeError", rangeerror),
|
||||
("", "RegExp", regexp),
|
||||
("", "ReferenceError", referenceerror),
|
||||
("", "SecurityError", securityerror),
|
||||
("", "SyntaxError", syntaxerror),
|
||||
|
@ -870,6 +828,25 @@ fn load_playerglobal<'gc>(
|
|||
("", "VerifyError", verifyerror),
|
||||
("", "XML", xml),
|
||||
("", "XMLList", xml_list),
|
||||
]
|
||||
);
|
||||
|
||||
avm2_system_class_defs_playerglobal!(
|
||||
&mut *activation,
|
||||
[
|
||||
("", "Namespace", namespace),
|
||||
("", "XML", xml),
|
||||
("", "XMLList", xml_list),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
pub fn init_native_system_classes<'gc>(activation: &mut Activation<'_, 'gc>) {
|
||||
avm2_system_classes_playerglobal!(
|
||||
&mut *activation,
|
||||
[
|
||||
("", "Date", date),
|
||||
("", "RegExp", regexp),
|
||||
("flash.display", "AVM1Movie", avm1movie),
|
||||
("flash.display", "Bitmap", bitmap),
|
||||
("flash.display", "BitmapData", bitmapdata),
|
||||
|
@ -966,9 +943,6 @@ fn load_playerglobal<'gc>(
|
|||
avm2_system_class_defs_playerglobal!(
|
||||
&mut *activation,
|
||||
[
|
||||
("", "Namespace", namespace),
|
||||
("", "XML", xml),
|
||||
("", "XMLList", xml_list),
|
||||
("flash.display", "Bitmap", bitmap),
|
||||
("flash.display", "BitmapData", bitmapdata),
|
||||
("flash.display", "IGraphicsData", igraphicsdata),
|
||||
|
@ -989,6 +963,41 @@ fn load_playerglobal<'gc>(
|
|||
("flash.display", "GraphicsStroke", graphicsstroke),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Loads classes from our custom 'playerglobal' (which are written in ActionScript)
|
||||
/// into the environment. See 'core/src/avm2/globals/README.md' for more information
|
||||
fn load_playerglobal<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
domain: Domain<'gc>,
|
||||
) -> Result<(), Error<'gc>> {
|
||||
activation.avm2().native_method_table = native::NATIVE_METHOD_TABLE;
|
||||
activation.avm2().native_instance_allocator_table = native::NATIVE_INSTANCE_ALLOCATOR_TABLE;
|
||||
activation.avm2().native_super_initializer_table = native::NATIVE_SUPER_INITIALIZER_TABLE;
|
||||
activation.avm2().native_call_handler_table = native::NATIVE_CALL_HANDLER_TABLE;
|
||||
|
||||
let movie = Arc::new(
|
||||
SwfMovie::from_data(PLAYERGLOBAL, "file:///".into(), None)
|
||||
.expect("playerglobal.swf should be valid"),
|
||||
);
|
||||
|
||||
let slice = SwfSlice::from(movie.clone());
|
||||
|
||||
let mut reader = slice.read_from(0);
|
||||
|
||||
let tag_callback = |reader: &mut SwfStream<'_>, tag_code, _tag_len| {
|
||||
if tag_code == TagCode::DoAbc2 {
|
||||
let do_abc = reader
|
||||
.read_do_abc_2()
|
||||
.expect("playerglobal.swf should be valid");
|
||||
Avm2::load_builtin_abc(activation.context, do_abc.data, domain, movie.clone());
|
||||
} else if tag_code != TagCode::End {
|
||||
panic!("playerglobal should only contain `DoAbc2` tag - found tag {tag_code:?}")
|
||||
}
|
||||
Ok(ControlFlow::Continue)
|
||||
};
|
||||
|
||||
let _ = tag_utils::decode_tags(&mut reader, tag_callback);
|
||||
|
||||
// Domain memory must be initialized after playerglobals is loaded because it relies on ByteArray.
|
||||
domain.init_default_domain_memory(activation)?;
|
||||
|
|
|
@ -14,7 +14,7 @@ package {
|
|||
prototype.setPropertyIsEnumerable("toString", false);
|
||||
prototype.setPropertyIsEnumerable("valueOf", false);
|
||||
|
||||
public function Namespace(prefix:* = undefined, uri:* = undefined) {
|
||||
public function Namespace(prefix:* = void 0, uri:* = void 0) {
|
||||
this.init(arguments);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ package {
|
|||
public final class QName {
|
||||
public static const length:* = 2;
|
||||
|
||||
public function QName(uri:* = undefined, localName:* = undefined) {
|
||||
public function QName(uri:* = void 0, localName:* = void 0) {
|
||||
this.init(arguments);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,3 +26,26 @@ package {
|
|||
|
||||
public native function trace(... rest):void;
|
||||
}
|
||||
|
||||
// These classes are required by other core code, so we put them here. Toplevel.as
|
||||
// is loaded before the rest of the global code.
|
||||
|
||||
include "Error.as"
|
||||
|
||||
include "ArgumentError.as"
|
||||
include "DefinitionError.as"
|
||||
include "EvalError.as"
|
||||
include "TypeError.as"
|
||||
include "RangeError.as"
|
||||
include "ReferenceError.as"
|
||||
include "SecurityError.as"
|
||||
include "SyntaxError.as"
|
||||
include "UninitializedError.as"
|
||||
include "URIError.as"
|
||||
include "VerifyError.as"
|
||||
|
||||
include "JSON.as"
|
||||
include "Namespace.as"
|
||||
include "QName.as"
|
||||
include "XML.as"
|
||||
include "XMLList.as"
|
||||
|
|
|
@ -45,7 +45,7 @@ package {
|
|||
};
|
||||
}
|
||||
|
||||
public function XML(value:* = undefined) {
|
||||
public function XML(value:* = void 0) {
|
||||
this.init(value, XML.ignoreComments, XML.ignoreProcessingInstructions, XML.ignoreWhitespace);
|
||||
}
|
||||
|
||||
|
@ -304,7 +304,7 @@ package {
|
|||
return XML.AS3::settings();
|
||||
}
|
||||
|
||||
XML.setSettings = function(v:* = undefined) {
|
||||
XML.setSettings = function(v:* = void 0) {
|
||||
XML.AS3::setSettings(v)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package {
|
|||
[Ruffle(CallHandler)]
|
||||
public final dynamic class XMLList {
|
||||
|
||||
public function XMLList(value:* = undefined) {
|
||||
public function XMLList(value:* = void 0) {
|
||||
this.init(value, XML.ignoreComments, XML.ignoreProcessingInstructions, XML.ignoreWhitespace);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
package flash.filters {
|
||||
namespace AS3 = "http://adobe.com/AS3/2006/builtin";
|
||||
public final class ColorMatrixFilter extends BitmapFilter {
|
||||
private var _matrix: Array;
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
package flash.net {
|
||||
namespace AS3 = "http://adobe.com/AS3/2006/builtin";
|
||||
|
||||
import flash.utils.escapeMultiByte;
|
||||
import flash.utils.unescapeMultiByte;
|
||||
public dynamic class URLVariables {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
package flash.text.engine {
|
||||
namespace AS3 = "http://adobe.com/AS3/2006/builtin";
|
||||
|
||||
import __ruffle__.stub_method;
|
||||
|
||||
import flash.events.EventDispatcher;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package flash.xml
|
||||
{
|
||||
|
||||
namespace AS3 = "http://adobe.com/AS3/2006/builtin";
|
||||
import flash.xml.XMLNode;
|
||||
import flash.xml.XMLNodeType;
|
||||
|
||||
|
|
|
@ -1,34 +1,11 @@
|
|||
// List is ordered alphabetically, except where superclasses/interfaces
|
||||
// need to come before subclasses and implementations.
|
||||
|
||||
package {
|
||||
// This names 'self.AS3::SomeMethod()' calls in 'XML.as' use a 'callproperty'
|
||||
// opcode, instead of a weird dynamic lookup of the 'AS3' namespace
|
||||
namespace AS3 = "http://adobe.com/AS3/2006/builtin";
|
||||
}
|
||||
|
||||
include "__ruffle__/stubs.as"
|
||||
|
||||
include "Error.as"
|
||||
|
||||
include "ArgumentError.as"
|
||||
include "DefinitionError.as"
|
||||
include "JSON.as"
|
||||
include "EvalError.as"
|
||||
include "TypeError.as"
|
||||
include "Math.as"
|
||||
include "Namespace.as"
|
||||
include "QName.as"
|
||||
include "RangeError.as"
|
||||
include "ReferenceError.as"
|
||||
include "RegExp.as"
|
||||
include "SecurityError.as"
|
||||
include "SyntaxError.as"
|
||||
include "UninitializedError.as"
|
||||
include "URIError.as"
|
||||
include "VerifyError.as"
|
||||
|
||||
include "Date.as"
|
||||
include "Math.as"
|
||||
include "RegExp.as"
|
||||
|
||||
include "avmplus.as"
|
||||
|
||||
|
@ -463,6 +440,3 @@ include "flash/utils/Timer.as"
|
|||
include "flash/xml/XMLNodeType.as"
|
||||
include "flash/xml/XMLNode.as" // XMLDocument extends XMLNode, so XMLNode needs to come before it.
|
||||
include "flash/xml/XMLDocument.as"
|
||||
|
||||
include "XML.as"
|
||||
include "XMLList.as"
|
||||
|
|
Loading…
Reference in New Issue