Esempio n. 1
0
	void as_3_function::compile()
	{
#define var_stack jit_getarg( 1 )
#define var_scope jit_getarg( 2 )

#ifdef __GAMESWF_ENABLE_JIT__
		int ip = 0;
		jit_prologue( m_compiled_code );

		if( m_code.size() == 0 ) return;
		do
		{
			Uint8 opcode = m_code[ip++];
			switch (opcode)
			{
				case 0x24:	// pushbyte
				{
					int byte_value;
					ip += read_vu30(byte_value, &m_code[ip]);

					//stack.push_back(byte_value);
					jit_pushargi( m_compiled_code, byte_value );
					jit_load( m_compiled_code, jit_eax, jit_getarg( 1 ) );
					jit_pusharg( m_compiled_code, jit_eax );
					jit_call( m_compiled_code, stack_int_function(stack_push_back_value) );
					jit_popargs( m_compiled_code, 2 );

					//IF_VERBOSE_ACTION(log_msg("EX: pushbyte\t %d\n", byte_value));

					break;
				}

				case 0x2D:	// pushint
				{
					int index;
					ip += read_vu30(index, &m_code[ip]);
					int val = m_abc->get_integer(index);

					//stack.push_back(val);
					jit_pushargi( m_compiled_code, val );
					jit_load( m_compiled_code, jit_eax, jit_getarg( 1 ) );
					jit_pusharg( m_compiled_code, jit_eax );
					jit_call( m_compiled_code, stack_int_function(stack_push_back_value) );
					jit_popargs( m_compiled_code, 2 );

					//IF_VERBOSE_ACTION(log_msg("EX: pushint\t %d\n", val));

					break;
				}

				case 0x2C:	// pushstring
				{
					int index;
					ip += read_vu30(index, &m_code[ip]);
					const char* val = m_abc->get_string(index);

					//stack.push_back(val);
					jit_pushargi( m_compiled_code, val );
					jit_load( m_compiled_code, jit_eax, jit_getarg( 1 ) );
					jit_pusharg( m_compiled_code, jit_eax );
					jit_call( m_compiled_code, stack_charp_function( &stack_push_back_value ) );
					jit_popargs( m_compiled_code, 2 );

					//IF_VERBOSE_ACTION(log_msg("EX: pushstring\t '%s'\n", val));

					break;
				}

				case 0x2F:	// pushdouble
				{
					int index;
					ip += read_vu30(index, &m_code[ip]);
					double val = m_abc->get_double(index);
					
					jit_pushargi( m_compiled_code, val );
					jit_load( m_compiled_code, jit_esi, var_stack );
					jit_pusharg( m_compiled_code, jit_esi );
					jit_call( m_compiled_code, &(stack_push_back_value<double>) );
					jit_popargs( m_compiled_code, 3 ); //double counts for 2;
					//stack.push_back(val);

					//IF_VERBOSE_ACTION(log_msg("EX: pushdouble\t %f\n", val));

					break;
				}

				case 0x30:	// pushscope
				{
					//as_value& val = stack.back();
					typedef as_value& ( array<as_value>::*back_function )();
					jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) );
					jit_this_call( m_compiled_code, (back_function)&array<as_value>::back );

					jit_load( m_compiled_code, jit_this_pointer, var_scope );
					jit_push( m_compiled_code, jit_result );
					jit_call( m_compiled_code, (push_value_function)&array<as_value>::push_back );
					jit_popargs( m_compiled_code, 1 );


					//IF_VERBOSE_ACTION(log_msg("EX: pushscope\t %s\n", val.to_xstring()));
					//TODO: Ecx is caller-saved, copy it to esi or edi before calling to prevent reload from memory
					//stack.resize(stack.size() - 1); 
					compile_stack_resize( 1 );

					break;
				}

				case 0x47:	// returnvoid
				{
					//IF_VERBOSE_ACTION(log_msg("EX: returnvoid\t\n"));

					//result->set_undefined();
					jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 3 ) );
					jit_this_call( m_compiled_code, &as_value::set_undefined );

					break;
				}

				case 0x49:	// constructsuper
				{
					// stack: object, arg1, arg2, ..., argn
					int arg_count;
					ip += read_vu30(arg_count, &m_code[ip]);

					struct constructsuper
					{
					
						static void call( array<as_value> & stack, int arg_count )
						{
							as_object* obj = stack.back().to_object();
							stack.resize(stack.size() - 1);
							for (int i = 0; i < arg_count; i++)
							{
								as_value& val = stack.back();
								stack.resize(stack.size() - 1);
							}

							//TODO: construct super of obj

							IF_VERBOSE_ACTION(log_msg("EX: constructsuper\t 0x%p(args:%d)\n", obj, arg_count));
						}
					};

					jit_pushi( m_compiled_code, arg_count );
					jit_load( m_compiled_code, jit_esi, var_stack );
					jit_push( m_compiled_code, jit_esi );
					jit_call( m_compiled_code, &constructsuper::call );
					jit_popargs( m_compiled_code, 2 );

					break;
				}

				case 0x4F:	// callpropvoid, Call a property, discarding the return value.
				// Stack: …, obj, [ns], [name], arg1,...,argn => …
				{
					int index;
					ip += read_vu30(index, &m_code[ip]);
					const char* name = m_abc->get_multiname(index);

					int arg_count;
					ip += read_vu30(arg_count, &m_code[ip]);

					jit_load( m_compiled_code, jit_esi, var_stack );
					jit_pusharg( m_compiled_code, jit_esi );
					jit_pushargi( m_compiled_code, arg_count );
					jit_pushargi( m_compiled_code, name );
					jit_pushargi( m_compiled_code, this );
					jit_call( m_compiled_code, &callpropvoid::call );
					jit_popargs( m_compiled_code, 4 );

					/*
					struct local
					{
						static void construct_env( as_environment *env, player * player )
						{
							new( env ) as_environment( player );
						}

						static void destruct_env( as_environment *env )
						{
							env->~as_environment();
						}
					};

					//as_environment env(get_player());
					int env_offset = jit_allocate_stack_object_memory( m_compiled_code, sizeof( as_environment ) );
					//Do we query it each it or it won't change? I decided it won't change
					jit_mov( m_compiled_code, jit_edi, jit_stack_pointer );
					jit_pushi( m_compiled_code, (uint32)get_player() );
					jit_push( m_compiled_code, jit_edi );
					jit_call( m_compiled_code, &local::construct_env );
					jit_popargs( m_compiled_code, 2 );

					//as_value* val = stack.back();
					jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) );
					typedef as_value& ( array<as_value>::*back_function )();
					jit_this_call( m_compiled_code, (back_function)&array<as_value>::back );
					jit_mov( m_compiled_code, jit_esi, jit_result );

					for (int i = 0; i < arg_count; i++)
					{
					 //env.push( *val);
					 jit_mov( m_compiled_code, jit_this_pointer, jit_edi );
					 jit_push( m_compiled_code, jit_esi );
					 jit_this_call( m_compiled_code, & as_environment::push<as_value&> );
					 
					 //val--;
					 jit_subi( m_compiled_code, jit_esi, sizeof( as_value ) );
					}

					//stack.resize(stack.size() - arg_count);
					compile_stack_resize( arg_count );

					//as_object* obj = stack.back().to_object();
					jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) );
					typedef as_value& ( array<as_value>::*back_function )();
					jit_this_call( m_compiled_code, (back_function)&array<as_value>::back );
					jit_mov( m_compiled_code, jit_this_pointer, jit_result );
					jit_this_call( m_compiled_code, &as_value::to_object );
					jit_mov( m_compiled_code, jit_esi, jit_result );

					 //stack.resize(stack.size() - 1);
					compile_stack_resize( 1 );


					//as_value func;
					//if (obj && obj->get_member(name, &func))
					//{
					//	call_method(func, &env, obj,	arg_count, env.get_top_index());
					//}

					// Destruct env
					jit_getaddress( m_compiled_code, jit_result, jit_stack_pointer, env_offset );
					jit_push( m_compiled_code ,jit_result );
					jit_call( m_compiled_code, &local::destruct_env );
					jit_popargs( m_compiled_code, 1 );

 
					//IF_VERBOSE_ACTION(log_msg("EX: callpropvoid\t 0x%p.%s(args:%d)\n", obj, name, arg_count));
					*/
					break;
				}

				case 0x5D:	// findpropstrict
				{
					int index;
					ip += read_vu30(index, &m_code[ip]);
					const char* name = m_abc->get_multiname(index);

					// search property in scope
					
					// TODO: inline
					struct findpropstrict
					{
						static as_object * call( char* name, array<as_value> & scope )
						{
							for (int i = scope.size() - 1; i >= 0; i--)
							{
								as_value val;
								if (scope[i].find_property(name, &val))
								{
									return scope[i].to_object();
								}
							}

							return NULL;
						}
					};

					jit_load( m_compiled_code, jit_esi, var_scope );
					jit_push( m_compiled_code, jit_esi );
					jit_pushi( m_compiled_code, name);
					jit_call( m_compiled_code, &findpropstrict::call );
					jit_popargs( m_compiled_code, 2 );

					//IF_VERBOSE_ACTION(log_msg("EX: findpropstrict\t %s, obj=0x%p\n", name, obj));

					//stack.push_back(obj);
					jit_load( m_compiled_code, jit_esi, var_stack );
					jit_push( m_compiled_code, jit_result );
					jit_push( m_compiled_code, jit_esi );
					jit_call( m_compiled_code, &stack_push_back_value<as_object*> );
					jit_popargs( m_compiled_code, 2 );

					break;
				}

				case 0x5E:	// findproperty, Search the scope stack for a property
				{
					int index;
					ip += read_vu30(index, &m_code[ip]);
					const char* name = m_abc->get_multiname(index);

					struct findproperty
					{
						static void call( const char* name, array<as_value> & scope, array<as_value> & stack )
						{
							as_object* obj = NULL;
							for (int i = scope.size() - 1; i >= 0; i--)
							{
								as_value val;
								if (scope[i].find_property(name, &val))
								{
									obj = scope[i].to_object();
									break;
								}
							}

							IF_VERBOSE_ACTION(log_msg("EX: findproperty\t %s, obj=0x%p\n", name, obj));

							stack.push_back(obj);
						}
					};

					jit_load( m_compiled_code, jit_esi, var_stack );
					jit_push( m_compiled_code, jit_esi );
					jit_load( m_compiled_code, jit_esi, var_scope );
					jit_push( m_compiled_code, jit_esi );
					jit_pushi( m_compiled_code, name );
					jit_call( m_compiled_code, &findproperty::call );
					jit_popargs( m_compiled_code, 3 );

					break;

				}

				case 0x60:	// getlex, Find and get a property.
				{
					int index;
					ip += read_vu30(index, &m_code[ip]);
					const char* name = m_abc->get_multiname(index);

					struct getlex
					{
						static void call( const char* name, array<as_value> & scope, array<as_value> &stack )
						{
							// search property in scope
							as_value val;
							for (int i = scope.size() - 1; i >= 0; i--)
							{
								if (scope[i].find_property(name, &val))
								{
									break;
								}
							}

							IF_VERBOSE_ACTION(log_msg("EX: getlex\t %s, value=%s\n", name, val.to_xstring()));

							stack.push_back(val);
						}
					};

					jit_load( m_compiled_code, jit_esi, var_stack );
					jit_push( m_compiled_code, jit_esi );
					jit_load( m_compiled_code, jit_esi, var_scope );
					jit_push( m_compiled_code, jit_esi );
					jit_pushi( m_compiled_code, name );
					jit_call( m_compiled_code, &getlex::call );
					jit_popargs( m_compiled_code, 2 );
					break;
				}

				case 0x66:	// getproperty
				{
					//					 int index;
					//					 ip += read_vu30(index, &m_code[ip]);
					//					 const char* name = m_abc->get_multiname(index);
					// 
					//					 as_object* obj = stack.back().to_object();
					//					 if (obj)
					//					 {
					//						 obj->get_member(name, &stack.back());
					//					 }
					//					 else
					//					 {
					//						 stack.back().set_undefined();
					//					 }
					// 
					//					 IF_VERBOSE_ACTION(log_msg("EX: getproperty\t %s, value=%s\n", name, stack.back().to_xstring()));
					// 
					break;
				}

				case 0x68:	// initproperty, Initialize a property.
				{
					int index;
					ip += read_vu30(index, &m_code[ip]);
					const char* name = m_abc->get_multiname(index);

					struct initproperty
					{
						static void call( const char * name, array<as_value> & stack )
						{
							as_value& val = stack[stack.size() - 1];
							as_object* obj = stack[stack.size() - 2].to_object();
							if (obj)
							{
								obj->set_member(name, val);
							}

							IF_VERBOSE_ACTION(log_msg("EX: initproperty\t 0x%p.%s=%s\n", obj, name, val.to_xstring()));

							stack.resize(stack.size() - 2);
						}
					};

					jit_load( m_compiled_code, jit_esi, var_stack );
					jit_push( m_compiled_code, jit_esi );
					jit_pushi( m_compiled_code, name );
					jit_call( m_compiled_code, &initproperty::call );
					jit_popargs( m_compiled_code, 2 );
					break;
				}

				case 0xD0:	// getlocal_0
				case 0xD1:	// getlocal_1
				case 0xD2:	// getlocal_2
				case 0xD3:	// getlocal_3
				{
					//as_value& val = lregister[opcode & 0x03];
					jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 0 ) );
					jit_pushi( m_compiled_code, opcode & 0x03 );
					jit_this_call( m_compiled_code, (index_function)&array<as_value>::operator[] );
					jit_popargs( m_compiled_code, 1 );

					//stack.push_back(val);
					jit_push( m_compiled_code, jit_result );
					jit_load( m_compiled_code, jit_this_pointer, jit_getarg( 1 ) );
					jit_this_call( m_compiled_code, (push_value_function) &array<as_value>::push_back );
					jit_popargs( m_compiled_code, 1 );

					//IF_VERBOSE_ACTION(log_msg("EX: getlocal_%d\t %s\n", opcode & 0x03, val.to_xstring()));
					break;
				}

				default:
					log_msg("TODO opcode 0x%02X\n", opcode);
					break;
			}

		}
		while (ip < m_code.size());

		jit_return( m_compiled_code );
		m_compiled_code.initialize();
#else
		assert( false );
#endif
	}
Esempio n. 2
0
// interperate action script bytecode
void	as_3_function::execute ( array<as_value>& lregister, as_environment *env, as_value *result )
{
    // m_abc may be destroyed
    assert ( m_abc != NULL );
    vm_stack &stack = *env;
    vm_stack &scope = env->m_scope;

    // some method have no body
    if ( m_code.size() == 0 )
    {
        return;
    }

    int ip = 0;

    do
    {
        Uint8 opcode = m_code[ip++];

        switch ( opcode )
        {
        case 0x11: // iftrue
        {
            bool taken;
            //Follows ECMA-262 11.9.3
            taken = stack.top ( 0 ).to_bool();
            stack.drop ( 1 );

            if ( taken )
            {
                int offset = m_code[ip] | m_code[ip+1]<<8 | m_code[ip+2]<<16;
                ip += offset;
            }

            ip += 3;
            IF_VERBOSE_ACTION ( log_msg ( "EX: iftrue\t %s\n", taken? "taken": "not taken" ) );
        }
        break;

        case 0x12: // iffalse
        {
            bool taken;
            //Follows ECMA-262 11.9.3
            taken = !stack.top ( 0 ).to_bool();
            stack.drop ( 1 );

            if ( taken )
            {
                int offset = m_code[ip] | m_code[ip+1]<<8 | m_code[ip+2]<<16;
                ip += offset;
            }

            ip += 3;
            IF_VERBOSE_ACTION ( log_msg ( "EX: iffalse\t %s\n", taken? "taken": "not taken" ) );
        }
        break;

        case 0x14: // ifne
        {
            bool taken;
            //Follows ECMA-262 11.9.3
            taken = !as_value::abstract_equality_comparison ( scope[ scope.size() - 2 ], scope[ scope.size() - 1 ] );

            if ( taken )
            {
                int offset = m_code[ip] | m_code[ip+1]<<8 | m_code[ip+2]<<16;
                ip += offset;
            }

            ip += 3;
            IF_VERBOSE_ACTION ( log_msg ( "EX: ifne\t %s\n", taken? "taken": "not taken" ) );
        }
        break;

        case 0x1D: // popscope
        {
            scope.pop();
            IF_VERBOSE_ACTION ( log_msg ( "EX: popscope\n" ) );
            break;
        }

        case 0x20:  // pushnull
        {
            as_value value;
            value.set_null();
            stack.push ( value );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushnull\n" ) );
        }
        break;

        case 0x24:	// pushbyte
        {
            int byte_value;
            ip += read_vu30 ( byte_value, &m_code[ip] );
            stack.push ( byte_value );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushbyte\t %d\n", byte_value ) );
            break;
        }

        case 0x25:  // pushshort
        {
            int val;
            ip += read_vu30 ( val, &m_code[ip] );
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushshort\t %d\n", val ) );
            break;
        }

        case 0x26:  // pushtrue
        {
            stack.push ( true );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushtrue\n" ) );
        }
        break;

        case 0x27:  // pushfalse
        {
            stack.push ( false );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushfalse\n" ) );
        }
        break;

        case 0x29:  // pop the value from stack and discard it
        {
            stack.pop();
            IF_VERBOSE_ACTION ( log_msg ( "EX: pop\n" ) );
            break;
        }

        case 0x2A:  // dup
        {
            IF_VERBOSE_ACTION ( log_msg ( "EX: dup %s\n", stack.top ( 0 ).to_xstring() ) );
            stack.push ( stack.top ( 0 ) );
        }
        break;

        case 0x2D:	// pushint
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            int val = m_abc->get_integer ( index );
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushint\t %d\n", val ) );
            break;
        }

        case 0x2C:	// pushstring
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *val = m_abc->get_string ( index );
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushstring\t '%s'\n", val ) );
            break;
        }

        case 0x2F:	// pushdouble
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            double val = m_abc->get_double ( index );
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushdouble\t %f\n", val ) );
            break;
        }

        case 0x30:	// pushscope
        {
            as_value val = stack.pop();
            scope.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: pushscope\t %s\n", val.to_xstring() ) );
            break;
        }

        case 0x46:  // callproperty
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_environment env ( get_player() );

            for ( int i = 0; i < arg_count; i++ )
            {
                env.push ( stack.top ( i ) );
            }

            stack.drop ( arg_count );
            as_value result;

            if ( stack.top ( 0 ).is_object() )
            {
                as_object *obj = stack.top ( 0 ).to_object();
                as_value func, func2;
                result.set_undefined();

                if ( obj &&  obj->get_member ( name, &func ) )
                {
                    if ( func.is_function() )
                    {
                        result = call_method ( func, &env, obj, arg_count, env.get_top_index() );
                    }

                    else if ( func.to_object()->get_member ( "__call__", &func2 ) )
                    {
                        //todo patch scope
                        result = call_method ( func2, &env, obj, arg_count, env.get_top_index() );
                    }
                }
            }

            else
            {
                as_value func;

                if ( stack.top ( 0 ).find_property ( name, &func ) )
                {
                    result = call_method ( func, &env, stack.top ( 0 ), arg_count, env.get_top_index() );
                }
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: callproperty\t 0x%p.%s(args:%d), result %s\n", stack.top ( 0 ).to_xstring(), name, arg_count, result.to_xstring() ) );
            stack.drop ( 1 );
            stack.push ( result );
        }
        break;

        case 0x47:	// returnvoid
        {
            IF_VERBOSE_ACTION ( log_msg ( "EX: returnvoid\t\n" ) );
            result->set_undefined();
            return;
        }

        case 0x48:	// returnvalue
        {
            IF_VERBOSE_ACTION ( log_msg ( "EX: returnvalue \t%s\n", stack.top ( 0 ).to_xstring() ) );
            *result = stack.pop();
            return;
        }

        case 0x49:	// constructsuper
        {
            // stack: object, arg1, arg2, ..., argn
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_environment env ( get_player() );

            for ( int i = 0; i < arg_count; i++ )
            {
                env.push ( stack.pop() );
            }

            gc_ptr<as_object> obj = stack.pop().to_object();
            // Assume we are in a constructor
            tu_string class_name = m_abc->get_class_from_constructor ( m_method );
            tu_string super_class_name = m_abc->get_super_class ( class_name );
            as_object *super = obj.get_ptr();

            while ( super->get_proto() )
            {
                super = super->get_proto();
            }

            as_function *function = m_abc->get_class_constructor ( super_class_name );

            if ( !function )
            {
                as_value value;

                if ( get_player()->get_global()->get_member ( super_class_name, &value ) )
                {
                    function = cast_to<as_function> ( value.to_object() );
                }
            }

            assert ( function );
            as_object *proto = super->create_proto ( function );
            UNUSED ( proto );
            call_method ( function, &env, obj.get_ptr(), arg_count, 0 );
            //stack.top(0) = obj.get_ptr();
            IF_VERBOSE_ACTION ( log_msg ( "EX: constructsuper\t 0x%p(args:%d)\n", obj.get_ptr(), arg_count ) );
            break;
        }

        case 0x4A: //constructprop
            // Stack ..., obj, [ns], [name], arg1,...,argn => ..., value
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            const char *name_space = m_abc->get_multiname_namespace ( index );
            UNUSED ( name_space );
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_environment env ( get_player() );

            for ( int i = 0; i < arg_count; i++ )
            {
                env.push ( stack.top ( i ) );
            }

            stack.drop ( arg_count );
            as_object *obj = stack.pop().to_object();
            as_value func, func2;
            gc_ptr<as_object> new_object;

            if ( obj && obj->get_member ( name, &func ) )
            {
                instance_info *ii = m_abc->get_instance_info ( name );
                new_object = new as_object ( get_player() );
                //:TODO: create prototype .... ( move instanciate class from character -> as_object )
                new_object->set_instance ( ii );
                new_object->create_traits ( m_abc.get_ptr(), ii );
                call_method ( m_abc->get_class_constructor ( name ), &env, new_object.get_ptr(), arg_count, 0 );
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: constructprop\t 0x%p.%s(args:%d)\n", obj, name, arg_count ) );
            stack.push ( new_object.get_ptr() );
        }
        break;

        case 0x4F:	// callpropvoid, Call a property, discarding the return value.
            // Stack: ..., obj, [ns], [name], arg1,...,argn => ...
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_environment env ( get_player() );

            for ( int i = 0; i < arg_count; i++ )
            {
                env.push ( stack.top ( i ) );
            }

            stack.drop ( arg_count );
            as_object *obj = stack.pop().to_object();
            as_value func, func2;

            if ( obj &&  obj->get_member ( name, &func ) )
            {
                if ( func.is_function() )
                {
                    call_method ( func, &env, obj, arg_count, env.get_top_index() );
                }

                else if ( func.to_object()->get_member ( "__call__", &func2 ) )
                {
                    //todo patch scope
                    call_method ( func2, &env, obj, arg_count, env.get_top_index() );
                }
            }

            else
            {
                if ( !obj )
                {
                    log_msg ( "Error #1010: A term is undefined and has no properties (%s call)\n", name );
                }

                else
                {
                    log_msg ( "Error #1006: value is not a function (%s call)\n", name );
                }
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: callpropvoid\t 0x%p.%s(args:%d)\n", obj, name, arg_count ) );
            break;
        }

        case 0x56: //newarray
        {
            int arg_count;
            ip += read_vu30 ( arg_count, &m_code[ip] );
            as_array *array = new as_array ( get_player() );
            int offset = stack.size() - arg_count;

            for ( int arg_index = 0; arg_index < arg_count; ++arg_index )
            {
                array->push ( stack[ offset + arg_index ] );
            }

            stack.resize ( offset + 1 );
            stack.top ( 0 ) = array;
            IF_VERBOSE_ACTION ( log_msg ( "EX: newarray\t arg_count:%i\n", arg_count ) );
        }
        break;

        case 0x58: // newclass
        {
            // stack:	..., basetype => ..., newclass
            int class_index;
            ip += read_vu30 ( class_index, &m_code[ip] );
            IF_VERBOSE_ACTION ( log_msg ( "EX: newclass\t class index:%i\n", class_index ) );
            //					as_object* basetype = stack.top(0).to_object();
            gc_ptr<as_class> new_class = new as_class ( get_player() );
            //new_class->set_proto(basetype);
            new_class->set_class ( m_abc->get_class_info ( class_index ) );
            as_environment env ( get_player() );
            call_method ( m_abc->get_class_function ( class_index ), &env, new_class.get_ptr(), 0, 0 );
            stack.top ( 0 ).set_as_object ( new_class.get_ptr() );
            break;
        }

        case 0x5D:	// findpropstrict
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            // search property in scope
            as_object *obj = scope.find_property ( name );
            //Search for a script entry to execute
            as_function *func = m_abc->get_script_function ( name );

            if ( obj == NULL && func != NULL )
            {
                get_global()->set_member ( name, new as_object ( get_player() ) );
                as_environment env ( get_player() );
                call_method ( func, &env, get_global(), 0, 0 );
                obj = get_global();
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: findpropstrict\t %s, obj=0x%p\n", name, obj ) );
            stack.push ( obj );
            break;
        }

        case 0x5E:	// findproperty, Search the scope stack for a property
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            const char *name_space = m_abc->get_multiname_namespace ( index );
            UNUSED ( name_space );
            as_object *obj = scope.find_property ( name );

            if ( obj )
            {
                IF_VERBOSE_ACTION ( log_msg ( "EX: findproperty\t '%s', obj=0x%p\n", name, obj ) );
                stack.push ( obj );
            }

            else
            {
                IF_VERBOSE_ACTION ( log_msg ( "EX: findproperty\t '%s', obj=global\n", name ) );
                stack.push ( get_global() );
            }

            break;
        }

        case 0x60:	// getlex, Find and get a property.
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            // search and get property in scope
            as_value val;
            scope.get_property ( name, &val );

            if ( val.is_undefined() )
            {
                as_function *func = m_abc->get_script_function ( name );

                if ( func != NULL )
                {
                    gc_ptr<as_object> object = new as_object ( get_player() );
                    get_global()->set_member ( name, object.get() );
                    as_environment env ( get_player() );
                    call_method ( func, &env, get_global(), 0, 0 );
                    val.set_as_object ( object );
                }
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: getlex\t %s, value=%s\n", name, val.to_xstring() ) );
            stack.push ( val );
            break;
        }

        case 0x61: // setproperty
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            IF_VERBOSE_ACTION ( log_msg ( "EX: setproperty\t %s.%s, value=%s\n", stack.top ( 1 ).to_xstring(), name, stack.top ( 0 ).to_xstring() ) );
            as_object *object = stack.top ( 1 ).to_object();

            if ( object )
            {
                object->set_member ( name, stack.top ( 0 ) );
            }

            stack.drop ( 2 );
        }
        break;

        case 0x62: // getlocal
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            IF_VERBOSE_ACTION ( log_msg ( "EX: getlocal\t index=%i, value=%s\n", index, lregister[index].to_xstring() ) );
            stack.push ( lregister[index] );
        }
        break;

        case 0x63: // setlocal
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            IF_VERBOSE_ACTION ( log_msg ( "EX: setlocal\t index=%i, value=%s\n", index, stack.top ( 0 ).to_xstring() ) );
            lregister[index] = stack.pop();
        }
        break;

        case 0x65: // getscopeobject
        {
            int index = m_code[ip];
            ++ip;
            assert ( index < scope.size() );
            stack.push ( scope[index] );
            IF_VERBOSE_ACTION ( log_msg ( "EX: getscopeobject\t index=%i, value=%s\n", index, stack.top ( 0 ).to_xstring() ) );
        }
        break;

        case 0x66:	// getproperty
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            tu_string name = get_multiname ( index, stack );
            as_object *obj = stack.top ( 0 ).to_object();

            if ( obj )
            {
                obj->get_member ( name, &stack.top ( 0 ) );
            }

            else
            {
                stack.top ( 0 ).set_undefined();
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: getproperty\t %s, value=%s\n", name.c_str(), stack.top ( 0 ).to_xstring() ) );
            break;
        }

        case 0x68:	// initproperty, Initialize a property.
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *name = m_abc->get_multiname ( index );
            as_value &val = stack.top ( 0 );
            as_object *obj = stack.top ( 1 ).to_object();

            if ( obj )
            {
                obj->set_member ( name, val );
            }

            IF_VERBOSE_ACTION ( log_msg ( "EX: initproperty\t 0x%p.%s=%s\n", obj, name, val.to_xstring() ) );
            stack.drop ( 2 );
            break;
        }

        case 0x73: //convert_i
        {
            stack.top ( 0 ).set_int ( stack.top ( 0 ).to_int() );
            IF_VERBOSE_ACTION ( log_msg ( "EX: convert_i : %i \n", stack.top ( 0 ).to_int() ) );
        }
        break;

        case 0x80: // coerce
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            const char *type_name = m_abc->get_multiname ( index );
            //	stack.push( stack.top( index ) );
            IF_VERBOSE_ACTION ( log_msg ( "EX: coerce : %s todo\n", type_name ) );
        }
        break;

        case 0x85: // coerce_s
        {
            stack.top ( 0 ).set_string ( stack.top ( 0 ).to_string() );
            IF_VERBOSE_ACTION ( log_msg ( "EX: coerce_s : %s\n", stack.top ( 0 ).to_string() ) );
        }
        break;

        case 0x96: // not
        {
            stack.top ( 0 ).set_bool ( !stack.top ( 0 ).to_bool() );
            IF_VERBOSE_ACTION ( log_msg ( "EX: not\n" ) );
        }
        break;

        case 0xA0:	// Add two values
        {
            if ( stack.top ( 0 ).is_string() || stack.top ( 1 ).is_string() )
            {
                tu_string str = stack.top ( 1 ).to_string();
                str += stack.top ( 0 ).to_string();
                stack.top ( 1 ).set_tu_string ( str );
            }

            else
            {
                stack.top ( 1 ) += stack.top ( 0 ).to_number();
            }

            stack.drop ( 1 );
            break;
        }

        case 0xA2: // multiply
        {
            stack.top ( 1 ) = stack.top ( 1 ).to_number() * stack.top ( 0 ).to_number();
            stack.drop ( 1 );
            IF_VERBOSE_ACTION ( log_msg ( "EX: multiply\n" ) );
            break;
        }

        case 0xAB: // equals
        {
            bool result = as_value::abstract_equality_comparison ( stack.top ( 1 ), stack.top ( 0 ) );
            IF_VERBOSE_ACTION ( log_msg ( "EX: equals %s & %s : %s\n", stack.top ( 0 ).to_xstring(), stack.top ( 1 ).to_xstring(), result? "true":"false" ) );
            stack.drop ( 1 );
            stack.top ( 0 ).set_bool ( result );
        }
        break;

        case 0xAD: //lessthan
        {
            as_value result = as_value::abstract_relational_comparison ( stack.top ( 1 ), stack.top ( 0 ) );
            IF_VERBOSE_ACTION ( log_msg ( "EX: lessthan %s & %s : %s\n", stack.top ( 1 ).to_xstring(), stack.top ( 0 ).to_xstring(), result.to_string() ) );
            stack.drop ( 1 );
            stack.top ( 0 ) = result;
        }
        break;

        case 0xC2:  // inclocal_i
        {
            int index;
            ip += read_vu30 ( index, &m_code[ip] );
            as_value &reg = lregister[ index ];
            reg.set_int ( reg.to_int() + 1 );
            IF_VERBOSE_ACTION ( log_msg ( "EX: inclocal_i %i\n", index ) );
        }
        break;

        case 0xD0:	// getlocal_0
        case 0xD1:	// getlocal_1
        case 0xD2:	// getlocal_2
        case 0xD3:	// getlocal_3
        {
            as_value &val = lregister[opcode & 0x03];
            stack.push ( val );
            IF_VERBOSE_ACTION ( log_msg ( "EX: getlocal_%d\t %s\n", opcode & 0x03, val.to_xstring() ) );
            break;
        }

        case 0xD4:	// setlocal_0
        case 0xD5:	// setlocal_1
        case 0xD6:	// setlocal_2
        case 0xD7:	// setlocal_3
        {
            lregister[opcode & 0x03] = stack.pop();
            IF_VERBOSE_ACTION ( log_msg ( "EX: setlocal_%d\t %s\n", opcode & 0x03, lregister[opcode & 0x03].to_xstring() ) );
            break;
        }

        default:
            log_msg ( "TODO opcode 0x%02X\n", opcode );
            return;
        }
    }
    while ( ip < m_code.size() );
}