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 }
// 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 ® = 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() ); }