Index: server/as_function.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/as_function.cpp,v
retrieving revision 1.49
diff -u -r1.49 as_function.cpp
--- server/as_function.cpp	19 Feb 2008 19:20:52 -0000	1.49
+++ server/as_function.cpp	10 Mar 2008 21:45:05 -0000
@@ -422,9 +422,15 @@
 			}
 		}
 
+		// Super is constructed from this function's prototype
+		as_object* super = NULL;
+		as_object* iface = getPrototype().get(); // this function's prototype
+		if ( iface ) super = iface->get_super();
+
 		// Call the actual constructor function; new_obj is its 'this'.
+
 		// We don't need the function result.
-		call(fn_call(newobj.get(), &env, nargs, first_arg_index));
+		call(fn_call(newobj.get(), &env, nargs, first_arg_index, super));
 	}
 
 	if (!has_proto)
Index: server/as_object.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/as_object.cpp,v
retrieving revision 1.102
diff -u -r1.102 as_object.cpp
--- server/as_object.cpp	10 Mar 2008 08:19:38 -0000	1.102
+++ server/as_object.cpp	10 Mar 2008 21:45:05 -0000
@@ -32,6 +32,7 @@
 #include "Object.h" // for getObjectInterface
 #include "action.h" // for call_method
 #include "array.h" // for setPropFlags
+#include "as_function.h" // for inheritance of as_super
 
 #include <set>
 #include <string>
@@ -46,6 +47,66 @@
 
 using namespace gnash;
 
+/// 'super' is a special kind of object
+//
+/// See http://wiki.gnashdev.org/wiki/index.php/ActionScriptSuper
+///
+/// We make it derive from as_function instead of as_object
+/// to avoid touching too many files (ie: an as_object is not considered
+/// something that can be called by current Gnash code). We may want
+/// 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
+{
+public:
+
+	as_super(as_function* ctor, as_object* proto)
+		:
+		_ctor(ctor),
+		_proto(proto)
+	{
+		//set_prototype(getObjectInterface());
+	}
+
+	virtual bool isSuper() const { return true; }
+
+	// Fetching members from 'super' yelds a lookup on the associated prototype
+	virtual bool get_member(string_table::key name, as_value* val,
+		string_table::key nsname = 0)
+	{
+		//log_debug("as_super::get_member %s called - _proto is %p", getVM().getStringTable().value(name).c_str(), _proto);
+		if ( _proto ) return _proto->get_member(name, val, nsname);
+		log_debug("Super has no associated prototype");
+		return false;
+	}
+
+	// Setting members on 'super' is a no-op
+	virtual void set_member(string_table::key /*key*/, const as_value& /*val*/,
+		string_table::key /*nsname*/ = 0)
+	{
+		// can't assign to super
+		IF_VERBOSE_ASCODING_ERRORS(
+		log_aserror("Can't set members on the 'super' object");
+		);
+	}
+
+	/// Dispatch.
+	virtual as_value operator()(const fn_call& fn)
+	{
+		//log_debug("Super call operator. fn.this_ptr is %p", fn.this_ptr);
+		if ( _ctor ) return _ctor->call(fn);
+		log_debug("Super has no associated constructor");
+		return as_value();
+	}
+
+private:
+
+	as_function* _ctor;
+	as_object* _proto;
+};
+
+
 // A PropertyList visitor copying properties to an object
 class PropsCopier {
 
@@ -144,16 +205,71 @@
 as_object*
 as_object::get_super()
 {
+#if 1
+	// Assuming we're a prototype...
+	as_function* superCtor = get_constructor();      // prototype.__constructor__ is superCtor
+	as_object* superProto = get_prototype().get(); // prototype.__proto__ is superProto
+	as_object* super = new as_super(superCtor, superProto);
+	return super;
+#else
+
 	static bool getting = false;
 	as_object *owner = NULL;
 
 	Property *p = NULL;
 
 	if (getting)
+	{
+		log_debug("Already getting super, return NULL");
 		return NULL;
+	}
 
 	getting = true;
 
+#if 1
+	// Super is prototype.__constructor__
+	p = findProperty(NSV::PROP_PROTOTYPE, 0, &owner);
+	if (!p)
+	{
+		log_debug("This object (%s @ %p) has no 'prototype' get_super returns NULL", typeName(*this), (void*)this);
+		getting = false;
+		return NULL;
+	}
+
+	as_value protoval = p->getValue(*owner);
+	as_object *proto = protoval.to_object().get();
+	if (!proto)
+	{
+		log_debug("This object's (%s @ %p) 'prototype' member is not an object (%s) - get_super returns NULL", typeName(*this), (void*)this, protoval.to_debug_string());
+		getting = false;
+		return NULL;
+	}
+
+	as_function* constructor = proto->get_constructor();
+	if ( ! constructor )
+	{
+		log_debug("This object's (%s @ %p) 'prototype' has no constructor", typeName(*this), (void*)this);
+	}
+
+	// prototype of the constructor is constructor.prototype (I think)
+#if 1
+	as_object* prototype = NULL;
+	if ( constructor && constructor->get_member(NSV::PROP_PROTOTYPE, &protoval) )
+	{
+		prototype = protoval.to_object().get();
+	}
+#else
+	as_object* prototype = get_prototype().get();
+	if ( ! prototype )
+	{
+		log_debug("This object (%s @ %p) has no __proto__", typeName(*this), (void*)this);
+	}
+#endif
+
+	getting = false;
+
+	return new as_super(constructor, prototype);
+#else
 	// Super is this.__proto__.__constructor__.prototype
 	as_object *proto = get_prototype().get();
 	if (!proto)
@@ -197,13 +313,21 @@
 	getting = false;
 
 	return super;
+#endif
+#endif
 }
 
 as_function*
 as_object::get_constructor()
 {
-	// TODO: Implement
-	return NULL;
+	as_value ctorVal;
+	if ( ! get_member(NSV::PROP_uuCONSTRUCTORuu, &ctorVal) )
+	{
+		//log_debug("Object %p has no __constructor__ member");
+		return NULL;
+	}
+	//log_debug("%p.__constructor__ is %s", ctorVal.to_debug_string().c_str());
+	return ctorVal.to_as_function();
 }
 
 int
@@ -855,6 +979,16 @@
 boost::intrusive_ptr<as_object>
 as_object::get_prototype()
 {
+#if 1
+	as_value val;
+	if ( ! get_member(NSV::PROP_uuPROTOuu, &val) )
+	{
+		//log_debug("Object %p has no __proto__ member");
+		return NULL;
+	}
+	//log_debug("%p.__proto__ is %s", val.to_debug_string().c_str());
+	return val.to_object().get();
+#else
 	static string_table::key key = NSV::PROP_uuPROTOuu;
 
 	int swfVersion = _vm.getSWFVersion();
@@ -868,6 +1002,7 @@
 	as_value tmp = prop->getValue(*this);
 
 	return tmp.to_object();
+#endif
 }
 
 bool
Index: server/as_object.h
===================================================================
RCS file: /sources/gnash/gnash/server/as_object.h,v
retrieving revision 1.96
diff -u -r1.96 as_object.h
--- server/as_object.h	10 Mar 2008 08:19:38 -0000	1.96
+++ server/as_object.h	10 Mar 2008 21:45:05 -0000
@@ -718,6 +718,10 @@
 	///
 	virtual bool isDateObject() { return false; }
 
+	/// Return true if this is a 'super' object
+	virtual bool isSuper() const { return false; }
+
+
 	/// Add an interface to the list of interfaces.
 	/// Used by instanceOf
 	void add_interface(as_object* ctor);
Index: server/as_value.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/as_value.cpp,v
retrieving revision 1.118
diff -u -r1.118 as_value.cpp
--- server/as_value.cpp	7 Mar 2008 17:14:05 -0000	1.118
+++ server/as_value.cpp	10 Mar 2008 21:45:06 -0000
@@ -1027,7 +1027,8 @@
 			return "null";
 
 		case as_value::AS_FUNCTION:
-			return "function";
+			if ( getFun()->isSuper() ) return "object";
+			else return "function";
 
 		default:
 			if (is_exception())
Index: server/swf_function.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/swf_function.cpp,v
retrieving revision 1.49
diff -u -r1.49 swf_function.cpp
--- server/swf_function.cpp	7 Mar 2008 21:07:51 -0000	1.49
+++ server/swf_function.cpp	10 Mar 2008 21:45:06 -0000
@@ -101,7 +101,7 @@
 	as_environment*	our_env = m_env;
 	assert(our_env);
 	// if(our_env->get_original_target()->isDestroyed())
-    if (our_env == NULL)
+        if (our_env == NULL)
 	{
 		our_env = &fn.env();
 	}
@@ -118,7 +118,9 @@
 	as_object *super = NULL;
 	if (swfversion > 5)
 	{
-		super = fn.this_ptr->get_super();
+		super = fn.super;
+		//if ( super ) log_debug("Super is %s @ %p", typeName(*super), (void*)super);
+		//else log_debug("Super is not available");
 	}
 
 	if (m_is_function2 == false)
@@ -147,7 +149,7 @@
 		our_env->set_local("this", fn.this_ptr);
 
 		// Add 'super' (SWF6+ only)
-		if ( swfversion > 5 )
+		if ( super && swfversion > 5 )
 		{
 			our_env->set_local("super", as_value(super));
 		}
@@ -244,16 +246,20 @@
 		if ( (m_function2_flags & PRELOAD_SUPER) && swfversion > 5)
 		{
 			// Put 'super' in a register (SWF6+ only).
-			our_env->local_register(current_reg).set_as_object(super);
-			current_reg++;
+			// TOCHECK: should we still set it if not available ?
+			if ( super ) {
+				our_env->local_register(current_reg).set_as_object(super);
+				current_reg++;
+			}
 		}
 
 		if (m_function2_flags & SUPPRESS_SUPER)
 		{
 			// Don't put 'super' in a local var.
 		}
-		else if ( swfversion > 5 )
+		else if ( super && swfversion > 5 )
 		{
+			// TOCHECK: should we still set it if unavailable ?
 			// Put 'super' in a local var (SWF6+ only)
 			our_env->add_local("super", as_value(super));
 		}
Index: server/vm/ASHandlers.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/vm/ASHandlers.cpp,v
retrieving revision 1.207
diff -u -r1.207 ASHandlers.cpp
--- server/vm/ASHandlers.cpp	8 Mar 2008 00:04:20 -0000	1.207
+++ server/vm/ASHandlers.cpp	10 Mar 2008 21:45:06 -0000
@@ -2727,12 +2727,17 @@
 
     thread.ensureStack(2); // func name, nargs
 
+    //log_debug("ActionCallFunction: %s", env.top(0).to_debug_string().c_str());
+
     //cerr << "At ActionCallFunction enter:"<<endl;
     //env.dump_stack();
 
     // Let's consider it a as a string and lookup the function.
     const std::string& funcname = env.top(0).to_string();
     as_object* this_ptr = thread.getThisPointer();
+    as_object* super = NULL;
+
+    //log_debug("ActionCallFunction: thread.getThisPointer returned %s @ %p", typeName(*this_ptr), (void*)this_ptr);
 
     as_value function = thread.getVariable(funcname, &this_ptr);
 
@@ -2744,6 +2749,7 @@
     }
     else if ( ! function.is_function() )
     {
+        log_error("ActionCallFunction: function name %s evaluated to non-function value %s", funcname, function.to_debug_string());
         // Calling super ? 
         boost::intrusive_ptr<as_object> obj = function.to_object();
             this_ptr = thread.getThisPointer();
@@ -2754,6 +2760,15 @@
             )
         }
     }
+    else if ( function.to_as_function()->isSuper() )
+    {
+	this_ptr = thread.getThisPointer();
+
+	// the new 'super' will be computed from the old one
+	// NOTE: this is equivalent to oldSuper->get_super() [ looks like.. ]
+	as_function* oldSuper = function.to_as_function();
+	super = oldSuper->get_super();
+    }
 
     // Get number of args, modifying it if not enough values are on the stack.
     unsigned nargs = unsigned(env.top(1).to_number());
@@ -2775,8 +2790,10 @@
     debugger.callStackPush(function_name);
     debugger.matchBreakPoint(function_name, true);
 #endif
+
+    //log_debug("ActionCallFunction calling call_method with %p as this_ptr", this_ptr);
     as_value result = call_method(function, &env, this_ptr,
-                  nargs, env.get_top_index() - 2);
+                  nargs, env.get_top_index() - 2, super);
 
     //log_debug(_("Function's result: %s"), result.to_string();
 
@@ -3413,16 +3430,42 @@
 	log_action(_(" method nargs: %d"), nargs);
 	);
 
+	// TODO:
+	// 1. if object/func is super keep current 'this' when calling the method (don't pass 'super' as 'this')
+	// 2. if object/func is super pass it over to the function being invoked or it will create a new
+	//    super thus breaking the chain (use fn_call for that ?)
+
 	string method_string = method_name.to_string();
 	as_value method_val;
 	boost::intrusive_ptr<as_object> obj = obj_value.to_object();
-	if ( method_name.is_undefined() || method_string.empty() )
+
+	as_object* this_ptr = obj.get();
+	as_object* super = NULL;
+	if ( obj.get() )
 	{
+		if ( obj->isSuper() ) 
+		{
+			this_ptr = thread.getThisPointer();
+			super = obj->get_super();
+		}
+		else
+		{
+			//log_debug("%p.%s() call", obj.get(), method_string.c_str());
+			as_object* proto = obj->get_prototype().get();
+			if ( proto ) super = proto->get_super();
+			else super = obj->get_super();
+		}
+	}
 
-		// Does this ever happen ?
+	if ( method_name.is_undefined() || method_string.empty() )
+	{
+		// We'll be calling the super constructor here
 		method_val = obj_value;
+
 		if ( ! method_val.is_function() )
 		{
+			// TODO: log_aserror ? or try to invoke a [[Call]] method
+			//       ala ECMA262 ?
 			if ( ! obj )
 			{
 				log_error(_("ActionCallMethod invoked with "
@@ -3433,11 +3476,12 @@
 				return;
 			}
 
-#ifdef GNASH_DEBUG
-			log_error(_("Function object given to ActionCallMethod"
-				       " is not a function, will try to use"
-				       " its 'constructor' member"));
-#endif
+//#ifdef GNASH_DEBUG
+			log_debug(_("Function object given to ActionCallMethod"
+				       " is not a function (%s), will try to use"
+				       " its 'constructor' member (but should instead invoke it's [[Call]] method"),
+					obj_value.to_debug_string().c_str());
+//#endif
 
 			// TODO: all this crap should go into an as_object::getConstructor instead
 			as_value ctor;
@@ -3460,7 +3504,6 @@
 				return;
 			}
 			method_val = ctor;
-			obj = thread.getThisPointer();
 		}
 	}
 	else
@@ -3511,8 +3554,8 @@
 	}
 #endif
 
-	as_value result = call_method(method_val, &env, obj.get(),
-			nargs, env.get_top_index()-3);
+	as_value result = call_method(method_val, &env, this_ptr, 
+			nargs, env.get_top_index()-3, super);
 
 	env.drop(nargs + 2);
 	env.top(0) = result;
Index: server/vm/action.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/vm/action.cpp,v
retrieving revision 1.33
diff -u -r1.33 action.cpp
--- server/vm/action.cpp	19 Feb 2008 19:20:57 -0000	1.33
+++ server/vm/action.cpp	10 Mar 2008 21:45:07 -0000
@@ -138,7 +138,8 @@
     as_environment* env,
     as_object* this_ptr, // this is ourself
     int nargs,
-    int first_arg_bottom_index)
+    int first_arg_bottom_index,
+    as_object* super)
     // first_arg_bottom_index is the stack index, from the bottom,
     // of the first argument.
     // Subsequent arguments are at *lower* indices.
@@ -146,7 +147,7 @@
     // arg2 is at env->bottom(6), etc.
 {
 	as_value val;
-	fn_call call(this_ptr, env, nargs, first_arg_bottom_index);
+	fn_call call(this_ptr, env, nargs, first_arg_bottom_index, super);
 
 	try
 	{
Index: server/vm/action.h
===================================================================
RCS file: /sources/gnash/gnash/server/vm/action.h,v
retrieving revision 1.14
diff -u -r1.14 action.h
--- server/vm/action.h	21 Jan 2008 20:56:04 -0000	1.14
+++ server/vm/action.h	10 Mar 2008 21:45:07 -0000
@@ -83,7 +83,7 @@
 	///
 	DSOEXPORT as_value call_method(const as_value& method, as_environment* env,
 		as_object* this_ptr, // this is ourself
-		int nargs, int first_arg_bottom_index);
+		int nargs, int first_arg_bottom_index, as_object* super=NULL);
 
 	const char*	call_method_parsed(
 		as_environment* env,
Index: server/vm/fn_call.h
===================================================================
RCS file: /sources/gnash/gnash/server/vm/fn_call.h,v
retrieving revision 1.15
diff -u -r1.15 fn_call.h
--- server/vm/fn_call.h	21 Jan 2008 20:56:04 -0000	1.15
+++ server/vm/fn_call.h	10 Mar 2008 21:45:07 -0000
@@ -47,23 +47,28 @@
 	/// is taking place.
 	boost::intrusive_ptr<as_object> this_ptr;
 
+	/// The "super" object in this function call context
+	as_object* super;
+
 	/// Number of arguments to this ActionScript function call.
 	unsigned int nargs;
 
 public:
-	fn_call(const fn_call& fn) : this_ptr(fn.this_ptr), nargs(fn.nargs),
-		_env(fn._env), _stack_offset(fn._stack_offset)
+	fn_call(const fn_call& fn) : this_ptr(fn.this_ptr), super(fn.super),
+		nargs(fn.nargs), _env(fn._env), _stack_offset(fn._stack_offset)
 	{/**/}
 
-	fn_call(const fn_call& fn, as_object* this_in) : this_ptr(this_in),
-		nargs(fn.nargs), _env(fn._env), _stack_offset(fn._stack_offset)
+	fn_call(const fn_call& fn, as_object* this_in, as_object* sup=NULL)
+		: this_ptr(this_in), super(sup), nargs(fn.nargs),
+		_env(fn._env), _stack_offset(fn._stack_offset)
 	{/**/}
 
 	fn_call(as_object* this_in,
 			as_environment* env_in,
-			int nargs_in, int first_in)
+			int nargs_in, int first_in, as_object* sup=NULL)
 		:
 		this_ptr(this_in),
+		super(sup),
 		nargs(nargs_in),
 		_env(env_in),
 		_stack_offset(first_in)
@@ -72,9 +77,11 @@
 
 	fn_call(boost::intrusive_ptr<as_object> this_in,
 			as_environment* env_in,
-			int nargs_in, int first_in)
+			int nargs_in, int first_in,
+			as_object* sup=NULL)
 		:
 		this_ptr(this_in),
+		super(sup),
 		nargs(nargs_in),
 		_env(env_in),
 		_stack_offset(first_in)
@@ -152,6 +159,7 @@
 	/// The offset from the bottom of the env callstack to the first
 	/// argument to our fn_call.
 	unsigned int _stack_offset;
+
 };
 
 /// Signature of a builtin function callable from ActionScript
