Skip to content

Instantly share code, notes, and snippets.

@KirinDave
Created May 17, 2010 19:15
Show Gist options
  • Select an option

  • Save KirinDave/404113 to your computer and use it in GitHub Desktop.

Select an option

Save KirinDave/404113 to your computer and use it in GitHub Desktop.
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