Created
May 17, 2010 19:15
-
-
Save KirinDave/404114 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| int_val neko_interp_loop( neko_vm *VM_ARG, neko_module *m, int_val _acc, int_val *_pc ) { | |
| register int_val acc ACC_REG = _acc; | |
| register int_val *pc PC_REG = _pc; | |
| # ifdef VM_REG | |
| register neko_vm *vm VM_REG = VM_ARG; | |
| # endif | |
| # ifdef NEKO_THREADED | |
| static void *instructions[] = { | |
| # undef _NEKO_OPCODES_H | |
| # undef OPBEGIN | |
| # undef OPEND | |
| # undef OP | |
| # define OPBEGIN | |
| # define OPEND | |
| # define OP(x) &&Label##x | |
| # include "opcodes.h" | |
| }; | |
| if( m == NULL ) return (int_val)instructions; | |
| # endif | |
| register int_val *sp SP_REG = vm->sp; | |
| register int_val *csp CSP_REG = vm->csp; | |
| #ifdef NEKO_THREADED | |
| Next; {{ | |
| #else | |
| while( true ) { | |
| # ifdef NEKO_PROF | |
| if( *pc != Last ) pc[PROF_SIZE]++; | |
| # endif | |
| switch( *pc++ ) { | |
| #endif | |
| Instr(AccNull) | |
| acc = (int_val)val_null; | |
| Next; | |
| Instr(AccTrue) | |
| acc = (int_val)val_true; | |
| Next; | |
| Instr(AccFalse) | |
| acc = (int_val)val_false; | |
| Next; | |
| Instr(AccThis) | |
| acc = (int_val)vm->vthis; | |
| Next; | |
| Instr(AccInt) | |
| acc = *pc++; | |
| Next; | |
| Instr(AccStack0) | |
| acc = *sp; | |
| Next; | |
| Instr(AccStack1) | |
| acc = sp[1]; | |
| Next; | |
| Instr(AccStack) | |
| acc = sp[*pc++]; | |
| Next; | |
| Instr(AccGlobal) | |
| acc = *(int_val*)(*pc++); | |
| Next; | |
| Instr(AccEnv) | |
| if( *pc >= val_array_size(vm->env) ) RuntimeError("Reading Outside Env",true); | |
| acc = (int_val)val_array_ptr(vm->env)[*pc++]; | |
| Next; | |
| Instr(AccField) | |
| if( val_is_object(acc) ) { | |
| value *f; | |
| value old = (value)acc, tacc = (value)acc; | |
| do { | |
| f = otable_find(&((vobject*)acc)->table,(field)*pc); | |
| if( f ) | |
| break; | |
| acc = (int_val)((vobject*)tacc)->proto; | |
| tacc = (value)acc; | |
| } while( acc ); | |
| if( f ) | |
| acc = (int_val)*f; | |
| else if( vm->resolver ) { | |
| BeginCall(); | |
| acc = (int_val)val_call2(vm->resolver,old,alloc_int(*pc)); | |
| EndCall(); | |
| } else | |
| acc = (int_val)val_null; | |
| } else | |
| InvalidFieldAccess(); | |
| pc++; | |
| Next; | |
| Instr(AccArray) | |
| if( val_is_int(acc) && val_is_array(*sp) ) { | |
| int k = val_int(acc); | |
| if( k < 0 || k >= val_array_size(*sp) ) | |
| acc = (int_val)val_null; | |
| else | |
| acc = (int_val)val_array_ptr(*sp)[k]; | |
| } else if( val_is_object(*sp) ) | |
| ObjectOp(*sp,acc,id_get) | |
| else | |
| RuntimeError("Invalid array access",false); | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(AccIndex0) | |
| if( val_is_array(acc) ) { | |
| if( val_array_size(acc) ) | |
| acc = (int_val)*val_array_ptr(acc); | |
| else | |
| acc = (int_val)val_null; | |
| } else if( val_is_object(acc) ) | |
| ObjectOp(acc,alloc_int(0),id_get) | |
| else | |
| RuntimeError("Invalid array access",false); | |
| Next; | |
| Instr(AccIndex1) | |
| if( val_is_array(acc) ) { | |
| if( val_array_size(acc) > 1 ) | |
| acc = (int_val)val_array_ptr(acc)[1]; | |
| else | |
| acc = (int_val)val_null; | |
| } else if( val_is_object(acc) ) | |
| ObjectOp(acc,alloc_int(1),id_get) | |
| else | |
| RuntimeError("Invalid array access",false); | |
| Next; | |
| Instr(AccIndex) | |
| if( val_is_array(acc) ) { | |
| if( *pc < 0 || *pc >= val_array_size(acc) ) | |
| acc = (int_val)val_null; | |
| else | |
| acc = (int_val)val_array_ptr(acc)[*pc]; | |
| pc++; | |
| } else if( val_is_object(acc) ) | |
| ObjectOp(acc,alloc_int(*pc++),id_get) | |
| else | |
| RuntimeError("Invalid array access",true); | |
| Next; | |
| Instr(AccBuiltin) | |
| acc = *pc++; | |
| Next; | |
| Instr(SetStack) | |
| sp[*pc++] = acc; | |
| Next; | |
| Instr(SetGlobal) | |
| *(int_val*)(*pc++) = acc; | |
| Next; | |
| Instr(SetEnv) | |
| if( *pc >= val_array_size(vm->env) ) RuntimeError("Writing Outside Env",true); | |
| val_array_ptr(vm->env)[*pc++] = (value)acc; | |
| Next; | |
| Instr(SetField) | |
| if( val_is_object(*sp) ) { | |
| ACC_BACKUP; | |
| otable_replace(&((vobject*)*sp)->table,(field)*pc,(value)acc); | |
| ACC_RESTORE; | |
| } else | |
| InvalidFieldAccess(); | |
| *sp++ = ERASE; | |
| pc++; | |
| Next; | |
| Instr(SetArray) | |
| if( val_is_array(*sp) && val_is_int(sp[1]) ) { | |
| int k = val_int(sp[1]); | |
| if( k >= 0 && k < val_array_size(*sp) ) | |
| val_array_ptr(*sp)[k] = (value)acc; | |
| } else if( val_is_object(*sp) ) { | |
| value args[] = { (value)sp[1], (value)acc }; | |
| value f = val_field((value)*sp,id_set); | |
| if( f == val_null ) | |
| RuntimeError("Unsupported operation",false); | |
| BeginCall(); | |
| val_callEx((value)*sp,f,args,2,NULL); | |
| EndCall(); | |
| acc = (int_val)args[1]; | |
| } else | |
| RuntimeError("Invalid array access",false); | |
| *sp++ = ERASE; | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(SetIndex) | |
| if( val_is_array(*sp) ) { | |
| if( *pc >= 0 && *pc < val_array_size(*sp) ) | |
| val_array_ptr(*sp)[*pc] = (value)acc; | |
| } else if( val_is_object(*sp) ) { | |
| value args[] = { (value)alloc_int(*pc), (value)acc }; | |
| value f = val_field((value)*sp,id_set); | |
| if( f == val_null ) | |
| RuntimeError("Unsupported operation",true); | |
| BeginCall(); | |
| val_callEx((value)*sp,f,args,2,NULL); | |
| EndCall(); | |
| acc = (int_val)args[1]; | |
| } else | |
| RuntimeError("Invalid array access",true); | |
| pc++; | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(SetThis) | |
| vm->vthis = (value)acc; | |
| Next; | |
| Instr(Push) | |
| --sp; | |
| if( sp <= csp ) STACK_EXPAND; | |
| *sp = acc; | |
| Next; | |
| Instr(Pop) | |
| PopMacro(*pc++) | |
| Next; | |
| Instr(Apply) | |
| if( !val_is_function(acc) ) | |
| RuntimeError("$apply",true); | |
| { | |
| int fargs = val_fun_nargs(acc); | |
| if( fargs == *pc || fargs == VAR_ARGS ) | |
| goto do_call; | |
| if( *pc > fargs ) | |
| RuntimeError("$apply",true); | |
| { | |
| int i = fargs; | |
| ACC_BACKUP | |
| value env = alloc_array(fargs + 1); | |
| ACC_RESTORE; | |
| val_array_ptr(env)[0] = (value)acc; | |
| while( i > *pc ) | |
| val_array_ptr(env)[i--] = val_null; | |
| while( i ) { | |
| val_array_ptr(env)[i--] = (value)*sp; | |
| *sp++ = ERASE; | |
| } | |
| acc = (int_val)neko_alloc_apply((int)(fargs - *pc++),env); | |
| } | |
| } | |
| Next; | |
| Instr(TailCall) | |
| { | |
| int stack = (int)((*pc) >> 3); | |
| int nargs = (int)((*pc) & 7); | |
| int i = nargs; | |
| value cur_this = vm->vthis; | |
| stack -= nargs; | |
| sp += nargs; | |
| while( i > 0 ) { | |
| sp--; | |
| sp[stack] = *sp; | |
| i--; | |
| } | |
| while( stack-- > 0 ) | |
| *sp++ = ERASE; | |
| // preserve 'this' through the call | |
| PopInfos(true); | |
| DoCall(cur_this,nargs); | |
| } | |
| Next; | |
| Instr(Call) | |
| do_call: | |
| pc++; | |
| DoCall(vm->vthis,pc[-1]); | |
| Next; | |
| Instr(ObjCall) | |
| { | |
| value vtmp = (value)*sp; | |
| *sp++ = ERASE; | |
| pc++; | |
| DoCall(vtmp,pc[-1]); | |
| } | |
| Next; | |
| Instr(Jump) | |
| pc = (int_val*)*pc; | |
| Next; | |
| Instr(JumpIf) | |
| if( acc == (int_val)val_true ) | |
| pc = (int_val*)*pc; | |
| else | |
| pc++; | |
| Next; | |
| Instr(JumpIfNot) | |
| if( acc != (int_val)val_true ) | |
| pc = (int_val*)*pc; | |
| else | |
| pc++; | |
| Next; | |
| Instr(Trap) | |
| sp -= 6; | |
| if( sp <= csp ) STACK_EXPAND; | |
| sp[0] = (int_val)alloc_int((int_val)(csp - vm->spmin)); | |
| sp[1] = (int_val)vm->vthis; | |
| sp[2] = (int_val)vm->env; | |
| sp[3] = address_int(*pc); | |
| sp[4] = address_int(m); | |
| sp[5] = (int_val)alloc_int(vm->trap); | |
| vm->trap = vm->spmax - sp; | |
| pc++; | |
| Next; | |
| Instr(EndTrap) | |
| if( vm->spmax - vm->trap != sp ) RuntimeError("Invalid End Trap",false); | |
| vm->trap = val_int(sp[5]); | |
| PopMacro(6); | |
| Next; | |
| Instr(Ret) | |
| PopMacro( *pc++ ); | |
| PopInfos(true); | |
| Next; | |
| Instr(MakeEnv) | |
| { | |
| int n = (int)(*pc++); | |
| ACC_BACKUP | |
| int_val tmp = (int_val)alloc_array(n); | |
| ACC_RESTORE; | |
| while( n-- ) { | |
| val_array_ptr(tmp)[n] = (value)*sp; | |
| *sp++ = ERASE; | |
| } | |
| if( val_is_int(acc) || val_tag(acc) != VAL_FUNCTION ) | |
| RuntimeError("Invalid environment",false); | |
| acc = (int_val)neko_alloc_module_function(((vfunction*)acc)->module,(int_val)((vfunction*)acc)->addr,((vfunction*)acc)->nargs); | |
| ((vfunction*)acc)->env = (value)tmp; | |
| } | |
| Next; | |
| Instr(MakeArray) | |
| { | |
| int n = (int)*pc++; | |
| ACC_BACKUP | |
| value arr = alloc_array(n+1); | |
| ACC_RESTORE; | |
| while( n ) { | |
| val_array_ptr(arr)[n] = (value)*sp; | |
| *sp++ = ERASE; | |
| n--; | |
| } | |
| val_array_ptr(arr)[0] = (value)acc; | |
| acc = (int_val)arr; | |
| } | |
| Next; | |
| Instr(Bool) | |
| acc = (acc == (int_val)val_false || acc == (int_val)val_null || acc == 1)?(int_val)val_false:(int_val)val_true; | |
| Next; | |
| Instr(Not) | |
| acc = (acc == (int_val)val_false || acc == (int_val)val_null || acc == 1)?(int_val)val_true:(int_val)val_false; | |
| Next; | |
| Instr(IsNull) | |
| acc = (int_val)((acc == (int_val)val_null)?val_true:val_false); | |
| Next; | |
| Instr(IsNotNull) | |
| acc = (int_val)((acc == (int_val)val_null)?val_false:val_true); | |
| Next; | |
| Instr(Add) | |
| if( (acc & 1) && (*sp & 1) ) | |
| acc = (int_val)alloc_int(val_int(*sp) + val_int(acc)); | |
| else if( acc & 1 ) { | |
| if( val_tag(*sp) == VAL_FLOAT ) | |
| acc = (int_val)alloc_float(val_float(*sp) + val_int(acc)); | |
| else if( (val_tag(*sp)&7) == VAL_STRING ) | |
| acc = (int_val)neko_append_int(vm,(value)*sp,val_int(acc),true); | |
| else if( val_tag(*sp) == VAL_OBJECT ) | |
| ObjectOp(*sp,acc,id_add) | |
| else | |
| RuntimeError("+",false); | |
| } else if( *sp & 1 ) { | |
| if( val_tag(acc) == VAL_FLOAT ) | |
| acc = (int_val)alloc_float(val_int(*sp) + val_float(acc)); | |
| else if( (val_tag(acc)&7) == VAL_STRING ) | |
| acc = (int_val)neko_append_int(vm,(value)acc,val_int(*sp),false); | |
| else if( val_tag(acc) == VAL_OBJECT ) | |
| ObjectOp(acc,*sp,id_radd) | |
| else | |
| RuntimeError("+",false); | |
| } else if( val_tag(acc) == VAL_FLOAT && val_tag(*sp) == VAL_FLOAT ) | |
| acc = (int_val)alloc_float(val_float(*sp) + val_float(acc)); | |
| else if( (val_tag(acc)&7) == VAL_STRING && (val_tag(*sp)&7) == VAL_STRING ) | |
| acc = (int_val)neko_append_strings((value)*sp,(value)acc); | |
| else if( val_tag(*sp) == VAL_OBJECT ) | |
| ObjectOpGen(*sp,acc,id_add,goto add_2) | |
| else { | |
| add_2: | |
| if( val_tag(acc) == VAL_OBJECT ) | |
| ObjectOpGen(acc,*sp,id_radd,goto add_3) | |
| else { | |
| add_3: | |
| if( (val_tag(acc)&7) == VAL_STRING || (val_tag(*sp)&7) == VAL_STRING ) { | |
| ACC_BACKUP | |
| buffer b = alloc_buffer(NULL); | |
| BeginCall(); | |
| val_buffer(b,(value)*sp); | |
| ACC_RESTORE; | |
| val_buffer(b,(value)acc); | |
| EndCall(); | |
| acc = (int_val)buffer_to_string(b); | |
| } else | |
| RuntimeError("+",false); | |
| } | |
| } | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(Sub) | |
| NumberOp(-,SUB,id_sub,id_rsub) | |
| Instr(Mult) | |
| NumberOp(*,MULT,id_mult,id_rmult) | |
| Instr(Div) | |
| if( val_is_number(acc) && val_is_number(*sp) ) | |
| acc = (int_val)alloc_float( ((tfloat)val_number(*sp)) / val_number(acc) ); | |
| else if( val_is_object(*sp) ) | |
| ObjectOpGen(*sp,acc,id_div,goto div_next) | |
| else { | |
| div_next: | |
| if( val_is_object(acc) ) | |
| ObjectOp(acc,*sp,id_rdiv) | |
| else | |
| RuntimeError("/",false); | |
| } | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(Mod) | |
| if( acc == 1 && val_is_int(*sp) ) | |
| RuntimeError("%",false); | |
| NumberOp(%,fmod,id_mod,id_rmod); | |
| Instr(Shl) | |
| IntOp(<<); | |
| Instr(Shr) | |
| IntOp(>>); | |
| Instr(UShr) | |
| if( (acc & 1) && (*sp & 1) ) | |
| acc = (int_val)alloc_int(((unsigned int)val_int(*sp)) >> val_int(acc)); | |
| else | |
| RuntimeError(">>>",false); | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(Or) | |
| IntOp(|); | |
| Instr(And) | |
| IntOp(&); | |
| Instr(Xor) | |
| IntOp(^); | |
| Instr(Eq) | |
| Test(==) | |
| Instr(Neq) | |
| BeginCall(); | |
| acc = (int_val)((val_compare((value)*sp,(value)acc) == 0)?val_false:val_true); | |
| EndCall(); | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(Lt) | |
| Test(<) | |
| Instr(Lte) | |
| Test(<=) | |
| Instr(Gt) | |
| Test(>) | |
| Instr(Gte) | |
| Test(>=) | |
| Instr(TypeOf) | |
| acc = (int_val)(val_is_int(acc) ? alloc_int(1) : NEKO_TYPEOF[val_tag(acc)&7]); | |
| Next; | |
| Instr(Compare) | |
| BeginCall(); | |
| acc = (int_val)val_compare((value)*sp,(value)acc); | |
| EndCall(); | |
| acc = (int_val)((acc == invalid_comparison)?val_null:alloc_int(acc)); | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(PhysCompare) | |
| acc = (int_val)(( *sp > acc )?alloc_int(1):(( *sp < acc )?alloc_int(-1):alloc_int(0))); | |
| *sp++ = ERASE; | |
| Next; | |
| Instr(Hash) | |
| if( val_is_string(acc) ) { | |
| BeginCall(); | |
| acc = (int_val)alloc_int( val_id(val_string(acc)) ); | |
| } else | |
| RuntimeError("$hash",false); | |
| Next; | |
| Instr(New) | |
| BeginCall(); | |
| acc = (int_val)alloc_object((value)acc); | |
| Next; | |
| Instr(JumpTable) | |
| if( val_is_int(acc) && ((unsigned)acc) < ((unsigned)*pc) ) | |
| pc += acc; | |
| else | |
| pc += *pc + 1; | |
| Next; | |
| Instr(Last) | |
| goto end; | |
| #ifdef NEKO_VCC | |
| default: | |
| __assume(0); | |
| #endif | |
| }} | |
| end: | |
| vm->sp = sp; | |
| vm->csp = csp; | |
| return acc; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment