[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] /srv/bzr/gnash/trunk r11649: Add call() to as_object inte
From: |
Benjamin Wolsey |
Subject: |
[Gnash-commit] /srv/bzr/gnash/trunk r11649: Add call() to as_object interface, as this helps AS3 work. |
Date: |
Mon, 23 Nov 2009 19:05:35 +0100 |
User-agent: |
Bazaar (1.16.1) |
------------------------------------------------------------
revno: 11649 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Mon 2009-11-23 19:05:35 +0100
message:
Add call() to as_object interface, as this helps AS3 work.
Improve super handling, CallFunction and CallMethod, as they can also be
implemented more correctly if as_super inherits from as_object.
Allow undefined 'this' in function calls. This is fine for SWF-defined
functions; built-in and native functions should always check before
using the this pointer, but some may not. This would be a bug.
Test and fix super creation in functions.
Change the meaning of fn_call::super (see documentation!) to be an override
only if the normal super is not used. Create super only when necessary,
resulting in major memory saving under suitable circumstances.
added:
testsuite/misc-swfmill.all/super.trace
testsuite/misc-swfmill.all/super.xml
modified:
libcore/ClassHierarchy.cpp
libcore/MovieClip.cpp
libcore/NativeFunction.h
libcore/Property.cpp
libcore/Timers.cpp
libcore/abc/abc_function.cpp
libcore/abc/abc_function.h
libcore/as_function.cpp
libcore/as_function.h
libcore/as_object.cpp
libcore/as_object.h
libcore/as_value.cpp
libcore/asobj/Global_as.h
libcore/asobj/Object.cpp
libcore/builtin_function.h
libcore/swf_function.cpp
libcore/swf_function.h
libcore/vm/ASHandlers.cpp
libcore/vm/fn_call.h
testsuite/actionscript.all/getvariable.as
testsuite/misc-swfmill.all/Makefile.am
testsuite/misc-swfmill.all/PASSING
testsuite/swfdec/PASSING
=== modified file 'libcore/ClassHierarchy.cpp'
--- a/libcore/ClassHierarchy.cpp 2009-11-18 11:51:35 +0000
+++ b/libcore/ClassHierarchy.cpp 2009-11-23 07:42:51 +0000
@@ -75,7 +75,7 @@
{
}
- virtual as_value operator()(const fn_call& fn)
+ virtual as_value call(const fn_call& fn)
{
string_table& st = getStringTable(fn);
log_debug("Loading extension class %s", st.value(mDeclaration.name));
@@ -134,7 +134,7 @@
{
}
- virtual as_value operator()(const fn_call& fn)
+ virtual as_value call(const fn_call& fn)
{
string_table& st = getStringTable(fn);
log_debug("Loading native class %s", st.value(mDeclaration.name));
=== modified file 'libcore/MovieClip.cpp'
--- a/libcore/MovieClip.cpp 2009-11-20 11:36:15 +0000
+++ b/libcore/MovieClip.cpp 2009-11-23 07:42:51 +0000
@@ -1949,7 +1949,7 @@
call.super = super;
// we don't use the constructor return (should we?)
- (*ctor)(call);
+ ctor->call(call);
}
}
=== modified file 'libcore/NativeFunction.h'
--- a/libcore/NativeFunction.h 2009-08-18 08:00:20 +0000
+++ b/libcore/NativeFunction.h 2009-11-23 07:42:51 +0000
@@ -56,7 +56,7 @@
}
/// Invoke this function
- virtual as_value operator()(const fn_call& fn)
+ virtual as_value call(const fn_call& fn)
{
assert(_func);
return _func(fn);
=== modified file 'libcore/Property.cpp'
--- a/libcore/Property.cpp 2009-08-20 06:55:15 +0000
+++ b/libcore/Property.cpp 2009-11-23 07:42:51 +0000
@@ -125,7 +125,7 @@
return underlyingValue;
}
- if ( mGetter ) return (*mGetter)(fn);
+ if (mGetter) return mGetter->call(fn);
else return as_value(); // should we return underlyingValue here ?
}
@@ -139,7 +139,7 @@
return;
}
- (*mSetter)(fn);
+ mSetter->call(fn);
}
as_value
=== modified file 'libcore/Timers.cpp'
--- a/libcore/Timers.cpp 2009-11-16 11:21:48 +0000
+++ b/libcore/Timers.cpp 2009-11-23 14:22:25 +0000
@@ -100,37 +100,13 @@
Timer::execute()
{
- as_value timer_method;
-
// If _function is not 0, _methodName should be 0 anyway, but the
// ternary operator is there for clarity.
as_object* super = _object->get_super(_function ? 0 : _methodName);
VM& vm = getVM(*_object);
- if (_function) {
- timer_method.set_as_function(_function);
- }
- else {
- as_value tmp;
- if (!_object->get_member(_methodName, &tmp)) {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror("object %p has no member named %s (interval method)",
- _object, _methodName);
- );
- return;
- }
-
- as_function* f = tmp.to_function();
-
- if (!f) {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror("member %s of object %p (interval method) is not "
- "a function (%s)", _methodName, (void*)_object, tmp);
- );
- return;
- }
- timer_method.set_as_function(f);
- }
+ as_value timer_method = _function ? _function :
+ _object->getMember(_methodName);
as_environment env(vm);
=== modified file 'libcore/abc/abc_function.cpp'
--- a/libcore/abc/abc_function.cpp 2009-11-16 14:42:56 +0000
+++ b/libcore/abc/abc_function.cpp 2009-11-23 07:42:51 +0000
@@ -34,7 +34,7 @@
// Dispatch.
as_value
-abc_function::operator()(const fn_call& fn)
+abc_function::call(const fn_call& fn)
{
log_abc("Calling an abc_function id=%u.", _methodInfo->methodID());
=== modified file 'libcore/abc/abc_function.h'
--- a/libcore/abc/abc_function.h 2009-11-16 14:42:56 +0000
+++ b/libcore/abc/abc_function.h 2009-11-23 07:42:51 +0000
@@ -43,7 +43,7 @@
public:
abc_function(Method* methodInfo, Machine* machine);
- as_value operator()(const fn_call& fn);
+ as_value call(const fn_call& fn);
CodeStream* getCodeStream() const {
return _methodInfo->getBody();
=== modified file 'libcore/as_function.cpp'
--- a/libcore/as_function.cpp 2009-11-18 12:00:44 +0000
+++ b/libcore/as_function.cpp 2009-11-23 17:14:01 +0000
@@ -79,10 +79,13 @@
}
void
-as_function::extends(as_function& superclass)
+as_function::extends(as_object& superclass)
{
as_object* newproto = new as_object();
- newproto->set_prototype(superclass.getPrototype().get());
+ as_object* p =
+ superclass.getMember(NSV::PROP_PROTOTYPE).to_object(
+ *VM::get().getGlobal());
+ newproto->set_prototype(p);
if (getSWFVersion(superclass) > 5) {
const int flags = PropFlags::dontEnum;
@@ -154,7 +157,9 @@
PropFlags::dontEnum);
}
- fn_call fn(newobj, env, args, newobj->get_super(), true);
+ // Don't set a super so that it will be constructed only if required
+ // by the function.
+ fn_call fn(newobj, env, args, 0, true);
as_value ret;
try {
@@ -271,8 +276,7 @@
function_apply(const fn_call& fn)
{
- // Get function body
- as_function* function_obj = ensure<ThisIs<as_function> >(fn);
+ as_object* function_obj = ensure<ValidThis>(fn);
// Copy new function call from old one, we'll modify
// the copy only if needed
@@ -294,7 +298,13 @@
if (!obj) obj = new as_object;
new_fn_call.this_ptr = obj;
- new_fn_call.super = obj->get_super();
+
+ // Note: do not override fn_call::super by creating a super
+ // object, as it may not be needed. Doing so can have a very
+ // detrimental effect on memory usage!
+ // Normal supers will be created when needed in the function
+ // call.
+ new_fn_call.super = 0;
// Check for second argument ('arguments' array)
if (fn.nargs > 1)
@@ -329,8 +339,7 @@
function_call(const fn_call& fn)
{
- // Get function body
- as_function* function_obj = ensure<ThisIs<as_function> >(fn);
+ as_object* function_obj = ensure<ValidThis>(fn);
// Copy new function call from old one, we'll modify
// the copy only if needed
@@ -364,7 +373,15 @@
new_fn_call.this_ptr = this_ptr;
as_object* proto = this_ptr->get_prototype();
if (proto) {
- new_fn_call.super = this_ptr->get_super();
+ // Note: do not override fn_call::super by creating a super
+ // object, as it may not be needed. Doing so can have a very
+ // detrimental effect on memory usage!
+ // Normal supers will be created when needed in the function
+ // call.
+
+ // TODO: it seems pointless to copy the old fn_call and
+ // then change almost everything...
+ new_fn_call.super = 0;
}
else {
// TODO: check this !
@@ -377,7 +394,7 @@
}
// Call the function
- return (*function_obj)(new_fn_call);
+ return function_obj->call(new_fn_call);
}
=== modified file 'libcore/as_function.h'
--- a/libcore/as_function.h 2009-11-18 09:33:28 +0000
+++ b/libcore/as_function.h 2009-11-23 08:58:01 +0000
@@ -67,11 +67,11 @@
// Avoid RTTI
as_function* to_function() { return this; }
- /// Dispatch.
- virtual as_value operator()(const fn_call& fn) = 0;
-
- /// Alias for operator()
- as_value call(const fn_call& fn) { return operator()(fn); }
+ /// Function dispatch.
+ //
+ /// Override from as_object, although as_objects cannot generally
+ /// be called.
+ virtual as_value call(const fn_call& fn) = 0;
/// Construct an instance of this class
//
@@ -94,7 +94,7 @@
boost::intrusive_ptr<as_object> getPrototype();
/// Make this function a subclass of the given as_function
- void extends(as_function& superclass);
+ void extends(as_object& superclass);
/// Return true if this is a built-in class.
virtual bool isBuiltin() { return false; }
=== modified file 'libcore/as_object.cpp'
--- a/libcore/as_object.cpp 2009-11-20 15:13:16 +0000
+++ b/libcore/as_object.cpp 2009-11-23 18:05:35 +0000
@@ -124,13 +124,13 @@
/// to change this in the future to implement what ECMA-262 refers to
/// as the [[Call]] property of objects.
///
-class as_super : public as_function
+class as_super : public as_object
{
public:
as_super(Global_as& gl, as_object* super)
:
- as_function(gl),
+ as_object(gl),
_super(super)
{
set_prototype(prototype());
@@ -151,7 +151,7 @@
}
/// Dispatch.
- virtual as_value operator()(const fn_call& fn)
+ virtual as_value call(const fn_call& fn)
{
// TODO: this is a hack to make sure objects are constructed, not
@@ -173,7 +173,7 @@
virtual void markReachableResources() const
{
if (_super) _super->setReachable();
- markAsFunctionReachable();
+ markAsObjectReachable();
}
private:
@@ -261,7 +261,6 @@
} // end of anonymous namespace
-
const int as_object::DefaultFlags;
as_object::as_object(Global_as& gl)
@@ -284,6 +283,11 @@
{
}
+as_value
+as_object::call(const fn_call& /*fn*/) {
+ throw ActionTypeError();
+}
+
std::pair<bool,bool>
as_object::delProperty(string_table::key name, string_table::key nsname)
{
=== modified file 'libcore/as_object.h'
--- a/libcore/as_object.h 2009-11-20 15:13:16 +0000
+++ b/libcore/as_object.h 2009-11-23 18:05:35 +0000
@@ -184,6 +184,13 @@
/// Construct an ActionScript object with no prototype associated.
as_object();
+ /// Function dispatch
+ //
+ /// Various objects can be called, including functions and super objects.
+ /// A normal object has no call functionality, so the default
+ /// implementation throws an ActionTypeError.
+ virtual as_value call(const fn_call& fn);
+
/// The most common flags for built-in properties.
//
/// Most API properties, including classes and objects, have these flags.
=== modified file 'libcore/as_value.cpp'
--- a/libcore/as_value.cpp 2009-11-18 11:51:35 +0000
+++ b/libcore/as_value.cpp 2009-11-23 09:04:08 +0000
@@ -1269,8 +1269,7 @@
return "null";
case as_value::AS_FUNCTION:
- if ( getFun()->isSuper() ) return "object";
- else return "function";
+ return "function";
default:
if (is_exception())
=== modified file 'libcore/asobj/Global_as.h'
--- a/libcore/asobj/Global_as.h 2009-11-18 11:51:35 +0000
+++ b/libcore/asobj/Global_as.h 2009-11-23 08:58:01 +0000
@@ -187,7 +187,7 @@
/// Call an as_value on an as_object.
//
-/// The call will fail harmlessly if the as_value is not a function.
+/// The call will fail harmlessly if the as_value is not callable.
inline DSOEXPORT as_value
invoke(const as_value& method, const as_environment& env, as_object* this_ptr,
fn_call::Args& args, as_object* super = 0,
@@ -200,9 +200,9 @@
call.callerDef = callerDef;
try {
- if (as_function* func = method.to_function()) {
+ if (as_object* func = method.to_object(getGlobal(env))) {
// Call function.
- val = (*func)(call);
+ val = func->call(call);
}
else {
IF_VERBOSE_ASCODING_ERRORS(
=== modified file 'libcore/asobj/Object.cpp'
--- a/libcore/asobj/Object.cpp 2009-11-18 11:43:03 +0000
+++ b/libcore/asobj/Object.cpp 2009-11-23 09:04:08 +0000
@@ -188,7 +188,7 @@
{
as_object* obj = fn.this_ptr;
- if (obj && obj->to_function() && !obj->isSuper()) {
+ if (obj && obj->to_function()) {
return as_value("[type Function]");
}
return as_value("[object Object]");
=== modified file 'libcore/builtin_function.h'
--- a/libcore/builtin_function.h 2009-10-15 14:40:38 +0000
+++ b/libcore/builtin_function.h 2009-11-23 07:42:51 +0000
@@ -59,7 +59,7 @@
}
/// Invoke this function or this Class constructor
- virtual as_value operator()(const fn_call& fn)
+ virtual as_value call(const fn_call& fn)
{
// Real native functions don't put self on the CallStack
// (they never end up in an arguments.caller).
=== modified file 'libcore/swf_function.cpp'
--- a/libcore/swf_function.cpp 2009-11-18 11:34:54 +0000
+++ b/libcore/swf_function.cpp 2009-11-23 16:46:42 +0000
@@ -106,7 +106,7 @@
// Dispatch.
as_value
-swf_function::operator()(const fn_call& fn)
+swf_function::call(const fn_call& fn)
{
// Extract caller before pushing ourself on the call stack
as_object* caller = 0;
@@ -122,11 +122,8 @@
// Some features are version-dependant.
const int swfversion = vm.getSWFVersion();
- as_object *super = NULL;
- if (swfversion > 5) {
- super = fn.super;
- }
- else {
+
+ if (swfversion < 6) {
// In SWF5, when 'this' is a DisplayObject it becomes
// the target for this function call.
// See actionscript.all/setProperty.as
@@ -170,12 +167,14 @@
}
// Add 'this'
- assert(fn.this_ptr);
- m_env.set_local("this", fn.this_ptr);
+ m_env.set_local("this", fn.this_ptr ? fn.this_ptr : as_value());
+
+ as_object* super = fn.super ? fn.super :
+ fn.this_ptr ? fn.this_ptr->get_super() : 0;
// Add 'super' (SWF6+ only)
if (super && swfversion > 5) {
- m_env.set_local("super", as_value(super));
+ m_env.set_local("super", super);
}
// Add 'arguments'
@@ -195,13 +194,15 @@
if ((m_function2_flags & PRELOAD_THIS) &&
!(m_function2_flags & SUPPRESS_THIS)) {
// preload 'this' into a register.
- m_env.setRegister(current_reg, as_value(fn.this_ptr));
- current_reg++;
+ // TODO: check whether it should be undefined or null if this_ptr
+ // is null.
+ m_env.setRegister(current_reg, fn.this_ptr);
+ ++current_reg;
}
if (!(m_function2_flags & SUPPRESS_THIS)) {
// Put 'this' in a local var.
- m_env.add_local("this", as_value(fn.this_ptr));
+ m_env.add_local("this", fn.this_ptr ? fn.this_ptr :
as_value());
}
// Init arguments array, if it's going to be needed.
@@ -220,23 +221,24 @@
if (!(m_function2_flags & SUPPRESS_ARGUMENTS)) {
// Put 'arguments' in a local var.
- m_env.add_local("arguments", as_value(arg_array));
+ m_env.add_local("arguments", arg_array);
}
- if ((m_function2_flags & PRELOAD_SUPER) && swfversion > 5) {
- // Put 'super' in a register (SWF6+ only).
- // TOCHECK: should we still set it if not available ?
- if ( super ) {
- m_env.setRegister(current_reg, as_value(super));
+ // If super is not suppressed it is either placed in a register
+ // or set as a local variable, but not both.
+ if (swfversion > 5 && !(m_function2_flags & SUPPRESS_SUPER)) {
+
+ // Put 'super' in a register (SWF6+ only).
+ // TOCHECK: should we still set it if not available ?
+ as_object* super = fn.super ? fn.super :
+ fn.this_ptr ? fn.this_ptr->get_super() : 0;
+
+ if (super && (m_function2_flags & PRELOAD_SUPER)) {
+ m_env.setRegister(current_reg, super);
current_reg++;
}
- }
-
- if (!(m_function2_flags & SUPPRESS_SUPER)) {
- if (super && swfversion > 5) {
- // TOCHECK: should we still set it if unavailable ?
- // Put 'super' in a local var (SWF6+ only)
- m_env.add_local("super", as_value(super));
+ else if (super) {
+ m_env.add_local("super", super);
}
}
@@ -246,7 +248,7 @@
if (tgtch) {
// NOTE: _lockroot will be handled by
getAsRoot()
as_object* r = getObject(tgtch->getAsRoot());
- m_env.setRegister(current_reg, as_value(r));
+ m_env.setRegister(current_reg, r);
++current_reg;
}
}
@@ -263,7 +265,7 @@
if (m_function2_flags & PRELOAD_GLOBAL) {
// Put '_global' in a register.
as_object* global = vm.getGlobal();
- m_env.setRegister(current_reg, as_value(global));
+ m_env.setRegister(current_reg, global);
++current_reg;
}
=== modified file 'libcore/swf_function.h'
--- a/libcore/swf_function.h 2009-11-13 08:19:10 +0000
+++ b/libcore/swf_function.h 2009-11-23 07:42:51 +0000
@@ -139,7 +139,7 @@
void set_length(int len);
/// Dispatch.
- as_value operator()(const fn_call& fn);
+ virtual as_value call(const fn_call& fn);
#ifdef GNASH_USE_GC
/// Mark reachable resources. Override from as_function.
=== modified file 'libcore/vm/ASHandlers.cpp'
--- a/libcore/vm/ASHandlers.cpp 2009-11-20 14:54:19 +0000
+++ b/libcore/vm/ASHandlers.cpp 2009-11-23 18:05:35 +0000
@@ -1326,7 +1326,7 @@
as_object* instance = convertToObject(getGlobal(thread.env), env.top(0));
// Get the "super" function
- as_function* super = env.top(1).to_function();
+ as_object* super = convertToObject(getGlobal(thread.env), env.top(1));
// Invalid args!
if (!super || ! instance)
@@ -2432,47 +2432,38 @@
// In all cases, even undefined, the specified number of arguments
// is dropped from the stack.
const std::string& funcname = env.pop().to_string();
- as_object* this_ptr = thread.getThisPointer();
- as_object* super = NULL;
-
+
+ as_object* super(0);
+
+ as_object* this_ptr;
as_value function = thread.getVariable(funcname, &this_ptr);
if (!function.is_object()) {
+ // In this case the call to invoke() will fail. We won't return
+ // because we still need to handle the stack, and the attempt to
+ // convert the value to an object may have effects in AS (haven't
+ // checked).
IF_VERBOSE_ASCODING_ERRORS (
- log_aserror(_("ActionCallFunction: %s is not an object"), funcname);
+ log_aserror(_("ActionCallFunction: %s is not an object"),
+ funcname);
)
}
else if (!function.is_function()) {
- log_error(_("ActionCallFunction: function name %s evaluated to "
- "non-function value %s"), funcname, function);
- // Calling super ?
- as_object* obj = convertToObject(getGlobal(thread.env), function);
- this_ptr = thread.getThisPointer();
- if (!obj->get_member(NSV::PROP_CONSTRUCTOR, &function) )
- {
- IF_VERBOSE_ASCODING_ERRORS (
- log_aserror(_("Object doesn't have a constructor"));
- )
- }
- }
- else if ( function.to_function()->isSuper() )
- {
- this_ptr = thread.getThisPointer();
-
- // the new 'super' will be computed from the old one
- as_function* oldSuper = function.to_function();
- super = oldSuper->get_super();
+ as_object* obj = function.to_object(getGlobal(thread.env));
+ super = obj->get_super();
+ this_ptr = thread.getThisPointer();
}
// Get number of args, modifying it if not enough values are on the stack.
- unsigned nargs = unsigned(env.pop().to_number());
- unsigned available_args = env.stack_size();
- if ( available_args < nargs )
- {
+ // TODO: this may cause undefined behaviour if the number on the stack
+ // is too large. Fix it.
+ size_t nargs = static_cast<size_t>(env.pop().to_number());
+ const size_t available_args = env.stack_size();
+ if (available_args < nargs) {
IF_VERBOSE_MALFORMED_SWF(
- log_swferror(_("Attempt to call a function with %u arguments "
- "while only %u are available on the stack."),
- nargs, available_args);
+ log_swferror(_("Attempt to call a function with %u arguments "
+ "while only %u are available on the stack."),
+ nargs, available_args);
);
nargs = available_args;
}
@@ -2493,8 +2484,7 @@
env.push(result);
// If the function threw an exception, do so here.
- if (result.is_exception())
- {
+ if (result.is_exception()) {
thread.skipRemainingBuffer();
}
@@ -2553,12 +2543,11 @@
unsigned nargs = unsigned(env.pop().to_number());
as_value constructorval = thread.getVariable(classname);
- boost::intrusive_ptr<as_function> constructor =
constructorval.to_function();
- if ( ! constructor )
- {
+ as_function* constructor = constructorval.to_function();
+ if (!constructor) {
IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("ActionNew: "
- "'%s' is not a constructor"), classname);
+ log_aserror(_("ActionNew: "
+ "'%s' is not a constructor"), classname);
);
env.drop(nargs);
env.push(as_value()); // should we push an object anyway ?
@@ -2570,7 +2559,7 @@
// deleted. BitmapData also fails to construct anything under
// some circumstances.
try {
- as_object* newobj = construct_object(constructor.get(), env, nargs);
+ as_object* newobj = construct_object(constructor, env, nargs);
#ifdef USE_DEBUGGER
debugger.addSymbol(newobj, classname);
#endif
@@ -2923,6 +2912,27 @@
env.top(0).set_double(env.top(0).to_number() - 1);
}
+
+/// Call a method of an object
+//
+/// Stack: method, object, argc, arg0 ... argn
+//
+/// The standard use of this opcode is:
+/// 1. First stack value converted to a string (method name).
+/// 2. Second stack value converted to an object (this pointer).
+/// 3. Arg count and arguments parsed.
+/// 4. The method name must be a property of the object and is called with
+/// the object as its 'this'.
+//
+/// But it can also be used in a different way under some circumstances.
+//
+/// 1. If the method name is defined and not empty, the object value must
+/// be an object and the method name must be a property of the object
+/// (may be inherited). Otherwise the call fails and returns undefined.
+/// 2. If the method name is undefined or empty, the second stack value is
+/// called, and call's 'this' pointer is undefined.
+//
+/// In both usages the arguments are passed.
void
SWFHandlers::ActionCallMethod(ActionExec& thread)
{
@@ -2931,101 +2941,61 @@
// Get name function of the method
as_value method_name = env.pop();
+ std::string method_string = method_name.to_string();
+
// Get an object
as_value obj_value = env.pop();
// Get number of args, modifying it if not enough values are on the stack.
- unsigned nargs = unsigned(env.pop().to_number());
- unsigned available_args = env.stack_size();
- if (available_args < nargs)
- {
+ size_t nargs = static_cast<size_t>(env.pop().to_number());
+ const size_t available_args = env.stack_size();
+ if (available_args < nargs) {
IF_VERBOSE_MALFORMED_SWF(
- log_swferror(_("Attempt to call a method with %u arguments "
- "while only %u are available on the stack."),
- nargs, available_args);
+ log_swferror(_("Attempt to call a method with %u arguments "
+ "while only %u are available on the stack."),
+ nargs, available_args);
);
nargs = available_args;
}
-
IF_VERBOSE_ACTION (
log_action(_(" method name: %s"), method_name);
log_action(_(" method object/func: %s"), obj_value);
log_action(_(" method nargs: %d"), nargs);
);
- std::string method_string = method_name.to_string();
-
- bool hasMethodName = ((!method_name.is_undefined()) &&
- (!method_string.empty()) );
-
as_object* obj = convertToObject(getGlobal(thread.env), obj_value);
if (!obj) {
- // SWF integrity check
+ // If this value is not an object, it can neither have any members
+ // nor be called as a function, so neither opcode usage is possible.
IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("ActionCallMethod invoked with "
- "non-object object/func (%s)"), obj_value);
+ log_aserror(_("ActionCallMethod invoked with "
+ "non-object object/func (%s)"), obj_value);
);
env.drop(nargs);
env.push(as_value());
return;
}
- as_object* this_ptr = obj;
-
- if (obj->isSuper()) {
- if (thread.isFunction()) this_ptr = thread.getThisPointer();
- }
-
+ const bool noMeth = (method_name.is_undefined() || method_string.empty());
+
+ // The method to call
+ as_value method;
+
+ // The object to be the 'this' pointer during the call.
+ as_object* this_ptr(0);
string_table& st = getStringTable(env);
- as_object* super =
- obj->get_super(hasMethodName ? st.find(method_string) : 0);
-
- as_value method_val;
-
- if (!hasMethodName) {
- // We'll be calling the super constructor here
- method_val = obj_value;
-
- if (!method_val.is_function())
- {
-
- log_debug(_("Function object given to ActionCallMethod"
- " is not a function (%s), will try to use"
- " its 'constructor' member (but should instead "
- "invoke its [[Call]] method"), obj_value);
-
- // TODO: all this crap should go into an
- // as_object::getConstructor instead
- as_value ctor;
- if (!obj->get_member(NSV::PROP_CONSTRUCTOR, &ctor) )
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("ActionCallMethod: object has no "
- "constructor"));
- );
- env.drop(nargs);
- env.push(as_value());
- return;
- }
- if (!ctor.is_function())
- {
- IF_VERBOSE_ASCODING_ERRORS(
- log_aserror(_("ActionCallMethod: object constructor "
- "is not a function"));
- );
- env.drop(nargs);
- env.push(as_value());
- return;
- }
- method_val = ctor;
- }
+ as_object* super = obj->get_super(noMeth ? 0 : st.find(method_string));
+
+ // If the method name is undefined or evaluates to an empty string,
+ // the first argument is used as the method name and the 'this' pointer
+ // is undefined. We can signify this by leaving the 'this' pointer as
+ // null.a
+ if (noMeth) {
+ method = obj_value;
}
- else
- {
-
- if ( ! thread.getObjectMember(*obj, method_string, method_val) )
- {
+ else {
+ if (!thread.getObjectMember(*obj, method_string, method)) {
IF_VERBOSE_ASCODING_ERRORS(
log_aserror(_("ActionCallMethod: "
"Can't find method %s of object %s"),
@@ -3033,22 +3003,29 @@
obj_value);
);
env.drop(nargs);
- env.push(as_value()); // should we push an object anyway ?
+ env.push(as_value());
return;
}
+ else {
+ this_ptr = obj;
+ }
+ }
+
+ // If we are calling a method of a super object, the 'this' pointer
+ // for the call is always the this pointer of the function that called
+ // super().
+ if (obj->isSuper()) {
+ if (thread.isFunction()) this_ptr = thread.getThisPointer();
}
#ifdef USE_DEBUGGER
-// log_debug (_("FIXME: method name is: %s"), method_namexxx);
-// // IT IS NOT GUARANTEE WE DO HAVE A METHOD NAME HERE !
- if ( ! method_name.is_undefined() )
- {
+ if (! method_name.is_undefined()) {
debugger.callStackPush(method_name.to_string());
debugger.matchBreakPoint(method_name.to_string(), true);
}
- else
- {
- LOG_ONCE( log_unimpl(_("FIXME: debugger doesn't deal with anonymous
function calls")) );
+ else {
+ LOG_ONCE( log_unimpl(_("FIXME: debugger doesn't deal with "
+ "anonymous function calls")) );
}
#endif
@@ -3057,7 +3034,7 @@
args += env.pop();
}
- as_value result = invoke(method_val, env, this_ptr,
+ as_value result = invoke(method, env, this_ptr,
args, super, &(thread.code.getMovieDefinition()));
env.push(result);
@@ -3122,7 +3099,7 @@
}
}
- boost::intrusive_ptr<as_function> method = method_val.to_function();
+ as_function* method = method_val.to_function();
if (!method) {
IF_VERBOSE_MALFORMED_SWF(
log_swferror(_("ActionNewMethod: method name is undefined "
@@ -3139,7 +3116,7 @@
// deleted. BitmapData also fails to construct anything under
// some circumstances.
try {
- as_object* newobj = construct_object(method.get(), env, nargs);
+ as_object* newobj = construct_object(method, env, nargs);
env.push(newobj);
return;
}
@@ -3334,21 +3311,17 @@
as_environment& env = thread.env;
- as_function* super = env.top(0).to_function();
+ as_object* super = env.top(0).to_object(getGlobal(thread.env));
as_function* sub = env.top(1).to_function();
- if ( ! super || ! sub )
- {
- IF_VERBOSE_ASCODING_ERRORS
- (
- if ( ! super )
- {
- log_aserror(_("ActionExtends: Super is not an as_function
(%s)"),
+ if (!super ||!sub) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ if (!super) {
+ log_aserror(_("ActionExtends: Super is not an object (%s)"),
env.top(0));
}
- if ( ! sub )
- {
- log_aserror(_("ActionExtends: Sub is not an as_function (%s)"),
+ if (!sub) {
+ log_aserror(_("ActionExtends: Sub is not a function (%s)"),
env.top(1));
}
);
=== modified file 'libcore/vm/fn_call.h'
--- a/libcore/vm/fn_call.h 2009-11-16 10:40:56 +0000
+++ b/libcore/vm/fn_call.h 2009-11-23 16:45:19 +0000
@@ -109,13 +109,61 @@
class fn_call
{
public:
+
typedef FunctionArgs<as_value> Args;
+ /// Construct a fn_call
+ //
+ /// @param isNew Pass true if this is a constructing fn_call,
+ /// i.e. if it is called as a result of 'new'.
+ /// @param super Pass an overridden super value to the function
+ /// call. If this is 0, the super reference will be
+ /// calculated from the this pointer (if that is not
+ /// null) whenever a function requires it.
+ fn_call(as_object* this_in, const as_environment& env_in,
+ Args& args, as_object* sup = 0, bool isNew = false)
+ :
+ this_ptr(this_in),
+ super(sup),
+ nargs(args.size()),
+ callerDef(0),
+ _new(isNew),
+ _env(env_in)
+ {
+ args.swap(_args);
+ }
+
+ fn_call(as_object* this_in, const as_environment& env_in)
+ :
+ this_ptr(this_in),
+ super(0),
+ nargs(0),
+ callerDef(0),
+ _new(false),
+ _env(env_in)
+ {
+ }
+
+ /// Copy constructor
+ fn_call(const fn_call& fn)
+ :
+ this_ptr(fn.this_ptr),
+ super(fn.super),
+ nargs(fn.nargs),
+ callerDef(fn.callerDef),
+ _new(false),
+ _env(fn._env),
+ _args(fn._args)
+ {
+ }
+
/// The as_object (or a pointer derived thereof) on which this call
/// is taking place.
as_object* this_ptr;
/// The "super" object in this function call context
+ //
+ /// If this is 0, the super may be constructed from the this pointer.
as_object* super;
/// Number of arguments to this ActionScript function call.
@@ -124,68 +172,6 @@
/// Definition containing caller code. 0 if spontaneous (system event).
const movie_definition* callerDef;
- fn_call(const fn_call& fn)
- :
- this_ptr(fn.this_ptr),
- super(fn.super),
- nargs(fn.nargs),
- callerDef(fn.callerDef),
- _new(false),
- _env(fn._env),
- _args(fn._args)
- {
- }
-
- fn_call(const fn_call& fn, as_object* this_in, as_object* sup = 0)
- :
- this_ptr(this_in),
- super(sup),
- nargs(fn.nargs),
- callerDef(fn.callerDef),
- _new(false),
- _env(fn._env),
- _args(fn._args)
- {
- }
-
- fn_call(as_object* this_in, const as_environment& env_in,
- int nargs_in, size_t first_in, as_object* sup = 0)
- :
- this_ptr(this_in),
- super(sup),
- nargs(nargs_in),
- callerDef(0),
- _new(false),
- _env(env_in)
- {
- assert(first_in + 1 == env_in.stack_size());
- readArgs(env_in, first_in, nargs);
- }
-
- fn_call(as_object* this_in, const as_environment& env_in,
- Args& args, as_object* sup = 0, bool isNew = false)
- :
- this_ptr(this_in),
- super(sup),
- nargs(args.size()),
- callerDef(0),
- _new(isNew),
- _env(env_in)
- {
- args.swap(_args);
- }
-
- fn_call(as_object* this_in, const as_environment& env_in)
- :
- this_ptr(this_in),
- super(0),
- nargs(0),
- callerDef(0),
- _new(false),
- _env(env_in)
- {
- }
-
/// Return the VM this fn_call is running from
VM& getVM() const
{
@@ -195,12 +181,6 @@
/// Return true if this call is an object instantiation
bool isInstantiation() const
{
- // Currently the as_function::constructInstance
- // will set 'this_ptr' to NULL when calling a builtin
- // function, so we use this info to find out.
- // For the future, we might use an explicit flag instead
- // as I belive there are some cases in which 'this' is
- // undefined even in a normal function call.
return _new;
}
@@ -268,14 +248,6 @@
/// The actual arguments
Args::container_type _args;
- void readArgs(const as_environment& env, int first_in, size_t nargs)
- {
- _args.clear();
- for (size_t i = 0; i < nargs; ++i) {
- _args.push_back(env.bottom(first_in - i));
- }
- }
-
};
=== modified file 'testsuite/actionscript.all/getvariable.as'
--- a/testsuite/actionscript.all/getvariable.as 2009-02-25 22:33:03 +0000
+++ b/testsuite/actionscript.all/getvariable.as 2009-11-23 10:33:10 +0000
@@ -687,9 +687,9 @@
//-----------------------------------------------------------------------
#if OUTPUT_VERSION < 6
- xcheck_totals(52); // gnash runs +2 tests ?!
+ check_totals(52); // gnash runs +2 tests ?!
#else
- xcheck_totals(57); // gnash runs +2 tests ?!
+ check_totals(57); // gnash runs +2 tests ?!
#endif
#else // ndef MING_SUPPORT_ASM
=== modified file 'testsuite/misc-swfmill.all/Makefile.am'
--- a/testsuite/misc-swfmill.all/Makefile.am 2009-07-07 07:52:53 +0000
+++ b/testsuite/misc-swfmill.all/Makefile.am 2009-11-23 16:44:15 +0000
@@ -40,6 +40,15 @@
$(NULL)
# XML tests that rely on comparing trace output.
+
+TRACE_AS2_TESTS = \
+ super.xml \
+ $(NULL)
+
+TRACE_AS2_TRACES = \
+ super.trace \
+ $(NULL)
+
TRACE_AS3_TESTS = \
scope1.xml \
stack1.xml \
@@ -52,7 +61,9 @@
EXTRA_DIST = $(SC_AS2_XMLTESTS) \
$(SC_AS3_XMLTESTS) \
- $(TRACE_AS3_TESTS) \
+ $(TRACE_AS2_TESTS) \
+ $(TRACE_AS2_TRACES) \
+ $(TRACE_AS3_TESTS) \
$(TRACE_AS3_TRACES) \
gen-swfmill-trace-runner.sh \
$(NULL)
@@ -70,20 +81,26 @@
-I$(top_srcdir)/testsuite \
$(NULL)
+TRACE_TESTS = $(TRACE_AS2_TESTS)
+TRACES = $(TRACE_AS2_TRACES)
SC_XMLTESTS_OUT = $(SC_AS2_XMLTESTS:.xml=.swf)
-TRACE_XMLTESTS_OUT =
+
if ENABLE_AVM2
if SWFMILL_AS3_SUPPORT
+TRACE_TESTS += $(TRACE_AS3_TESTS)
+TRACES += $(TRACE_AS3_TRACES)
SC_XMLTESTS_OUT += $(SC_AS3_XMLTESTS:.xml=.swf)
-TRACE_XMLTESTS_OUT += $(TRACE_AS3_TESTS:.xml=.swf)
-endif
-endif
+endif
+endif
+
+TRACE_XMLTESTS_OUT = $(TRACE_TESTS:.xml=.swf)
# Dependencies for all self-contained SWF tests
$(SC_XMLTESTS_OUT) :
check_SCRIPTS = \
+ trace-test-runner \
mixed-bytecode-as2-runner \
jump_after_end-runner \
jump_to_prev_block-runner \
@@ -98,7 +115,6 @@
if SWFMILL_AS3_SUPPORT
check_SCRIPTS += \
mixed-bytecode-as3-runner \
- trace-test-runner \
$(NULL)
endif
endif
=== modified file 'testsuite/misc-swfmill.all/PASSING'
--- a/testsuite/misc-swfmill.all/PASSING 2009-06-29 11:43:07 +0000
+++ b/testsuite/misc-swfmill.all/PASSING 2009-11-23 16:44:15 +0000
@@ -1,1 +1,2 @@
stack1
+super
=== added file 'testsuite/misc-swfmill.all/super.trace'
--- a/testsuite/misc-swfmill.all/super.trace 1970-01-01 00:00:00 +0000
+++ b/testsuite/misc-swfmill.all/super.trace 2009-11-23 16:44:15 +0000
@@ -0,0 +1,8 @@
+[object Object]
+undefined
+undefined
+undefined
+[object Object]
+undefined
+undefined
+[object Object]
=== added file 'testsuite/misc-swfmill.all/super.xml'
--- a/testsuite/misc-swfmill.all/super.xml 1970-01-01 00:00:00 +0000
+++ b/testsuite/misc-swfmill.all/super.xml 2009-11-23 16:44:15 +0000
@@ -0,0 +1,362 @@
+<?xml version="1.0"?>
+<swf version="7" compressed="1">
+
+<!-- Tests when and where super is preloaded -->
+<!-- The answer is:
+ If it's suppressed, it's not available at all.
+ If it's preloaded, it is only available in a register, not as
+ a local variable.
+-->
+
+ <Header framerate="12" frames="1">
+ <size>
+ <Rectangle left="0" right="12800" top="0" bottom="9600"/>
+ </size>
+ <tags>
+ <DoAction>
+ <actions>
+ <Dictionary>
+ <strings>
+ <String value="o"/>
+ <String value="ns"/>
+ <String value="super"/>
+ <String value="nr"/>
+ <String value="sss"/>
+ <String value="pss"/>
+ <String value="psr"/>
+ <String value="psss"/>
+ <String value="pssr"/>
+ <String value="__proto__"/>
+ <String value="oo"/>
+ </strings>
+ </Dictionary>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ <StackInteger value="0"/>
+ </items>
+ </PushData>
+ <DeclareObject/>
+ <SetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="1"/>
+ </items>
+ </PushData>
+ <DeclareFunction2 name="" argc="0" regc="2" preloadParent="0"
preloadRoot="0" suppressSuper="0" preloadSuper="0" suppressArguments="0"
preloadArguments="0" suppressThis="0" preloadThis="0" reserved="0"
preloadGlobal="0">
+ <args/>
+ <actions>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="2"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <Return/>
+ </actions>
+ </DeclareFunction2>
+ <SetMember/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="3"/>
+ </items>
+ </PushData>
+
+ <!-- Check what's in register 0 for a normal function (nothing)-->
+ <DeclareFunction2 name="" argc="0" regc="2" preloadParent="0"
preloadRoot="0" suppressSuper="0" preloadSuper="0" suppressArguments="0"
preloadArguments="0" suppressThis="0" preloadThis="0" reserved="0"
preloadGlobal="0">
+ <args/>
+ <actions>
+ <PushData>
+ <items>
+ <StackRegister reg="1"/>
+ </items>
+ </PushData>
+ <Return/>
+ </actions>
+ </DeclareFunction2>
+ <SetMember/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="4"/>
+ </items>
+ </PushData>
+
+ <!-- Check what super is when it's suppressed-->
+ <DeclareFunction2 name="" argc="0" regc="2" preloadParent="0"
preloadRoot="0" suppressSuper="1" preloadSuper="0" suppressArguments="0"
preloadArguments="0" suppressThis="0" preloadThis="0" reserved="0"
preloadGlobal="0">
+ <args/>
+ <actions>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="2"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <Return/>
+ </actions>
+ </DeclareFunction2>
+ <SetMember/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="5"/>
+ </items>
+ </PushData>
+
+ <!-- Check what super is when it's preloaded-->
+ <DeclareFunction2 name="" argc="0" regc="2" preloadParent="0"
preloadRoot="0" suppressSuper="0" preloadSuper="1" suppressArguments="0"
preloadArguments="0" suppressThis="0" preloadThis="0" reserved="0"
preloadGlobal="0">
+ <args/>
+ <actions>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="2"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <Return/>
+ </actions>
+ </DeclareFunction2>
+ <SetMember/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="6"/>
+ </items>
+ </PushData>
+
+ <!-- Check what register 0 is when super is preloaded-->
+ <DeclareFunction2 name="" argc="0" regc="2" preloadParent="0"
preloadRoot="0" suppressSuper="0" preloadSuper="1" suppressArguments="0"
preloadArguments="0" suppressThis="0" preloadThis="0" reserved="0"
preloadGlobal="0">
+ <args/>
+ <actions>
+ <PushData>
+ <items>
+ <StackRegister reg="1"/>
+ </items>
+ </PushData>
+ <Return/>
+ </actions>
+ </DeclareFunction2>
+ <SetMember/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="7"/>
+ </items>
+ </PushData>
+
+ <!-- Check what super is when it's suppressed and preloaded-->
+ <DeclareFunction2 name="" argc="0" regc="2" preloadParent="0"
preloadRoot="0" suppressSuper="1" preloadSuper="1" suppressArguments="0"
preloadArguments="0" suppressThis="0" preloadThis="0" reserved="0"
preloadGlobal="0">
+ <args/>
+ <actions>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="2"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <Return/>
+ </actions>
+ </DeclareFunction2>
+ <SetMember/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="8"/>
+ </items>
+ </PushData>
+
+ <!-- Check what super is when it's suppressed and preloaded-->
+ <DeclareFunction2 name="" argc="0" regc="2" preloadParent="0"
preloadRoot="0" suppressSuper="1" preloadSuper="1" suppressArguments="0"
preloadArguments="0" suppressThis="0" preloadThis="0" reserved="0"
preloadGlobal="0">
+ <args/>
+ <actions>
+ <PushData>
+ <items>
+ <StackRegister reg="1"/>
+ </items>
+ </PushData>
+ <Return/>
+ </actions>
+ </DeclareFunction2>
+ <SetMember/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="9"/>
+ <StackInteger value="0"/>
+ </items>
+ </PushData>
+ <DeclareObject/>
+ <SetMember/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="10"/>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <New/>
+ <SetLocalVariable/>
+
+ <!-- Start function calls -->
+ <PushData>
+ <items>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="1"/>
+ </items>
+ </PushData>
+ <CallMethod/>
+ <Trace/>
+ <PushData>
+ <items>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="3"/>
+ </items>
+ </PushData>
+ <CallMethod/>
+ <Trace/>
+ <PushData>
+ <items>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="4"/>
+ </items>
+ </PushData>
+ <CallMethod/>
+ <Trace/>
+ <PushData>
+ <items>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="5"/>
+ </items>
+ </PushData>
+ <CallMethod/>
+ <Trace/>
+ <PushData>
+ <items>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="6"/>
+ </items>
+ </PushData>
+ <CallMethod/>
+ <Trace/>
+ <PushData>
+ <items>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="7"/>
+ </items>
+ </PushData>
+ <CallMethod/>
+ <Trace/>
+ <PushData>
+ <items>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="8"/>
+ </items>
+ </PushData>
+ <CallMethod/>
+ <Trace/>
+ <PushData>
+ <items>
+ <StackInteger value="0"/>
+ <StackDictionaryLookup index="0"/>
+ </items>
+ </PushData>
+ <GetVariable/>
+ <PushData>
+ <items>
+ <StackDictionaryLookup index="1"/>
+ </items>
+ </PushData>
+ <CallMethod/>
+ <Trace/>
+ <EndAction/>
+ </actions>
+ </DoAction>
+ <ShowFrame/>
+ <End/>
+ </tags>
+ </Header>
+</swf>
=== modified file 'testsuite/swfdec/PASSING'
--- a/testsuite/swfdec/PASSING 2009-11-11 23:18:13 +0000
+++ b/testsuite/swfdec/PASSING 2009-11-23 17:22:36 +0000
@@ -175,6 +175,10 @@
button-properties-8.swf:794f9c47e03aa3b0c75eeff87ba8a140
call-arguments-5.swf:422c391a2abd3e864eb8ed8a1e05ad31
callfunction-stack.swf:21d0c957f4caf0eb0ccd0dcadaf17500
+callmethod-undefined-this-5.swf:affed3be009b851c05f72b8429f13b2d
+callmethod-undefined-this-6.swf:c1695e653464da8c9b58b3e08c0d3325
+callmethod-undefined-this-7.swf:6d2bd3cde681a7283013ebc7d9118cf7
+callmethod-undefined-this-8.swf:467f925f9d959e71b8bcd14bb9222b16
camera-properties-5.swf:495e39b641f89aa49a927cf0a8413028
camera-properties-6.swf:3eb69243268f61cb8e130b661b6eac1a
camera-properties-7.swf:ec270af18a3930560841e04ae4c8d952
- [Gnash-commit] /srv/bzr/gnash/trunk r11649: Add call() to as_object interface, as this helps AS3 work.,
Benjamin Wolsey <=