X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibspiderscript.so_src%2Fexec_bytecode.c;h=4673bd286759a989061c401a7bff103e79b27143;hb=c43c05ef3234d6118ce601d299df60383d54ac7b;hp=1a74d4c2eae7222a1fce73e1e602ce2bf938c803;hpb=d5540392ca476276630775b5bfd6e4b4b198239e;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c index 1a74d4c2..4673bd28 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c @@ -12,9 +12,15 @@ #include #include #include "ast.h" +#include -//#define DEBUG_F(v...) printf(v) -#define DEBUG_F(v...) +#define TRACE 0 + +#if TRACE +# define DEBUG_F(v...) printf(v) +#else +# define DEBUG_F(v...) +#endif // === IMPORTS === extern void AST_RuntimeError(tAST_Node *Node, const char *Format, ...); @@ -35,8 +41,8 @@ struct sBC_StackEnt { uint8_t Type; union { - uint64_t Integer; - double Real; + int64_t Integer; + double Real; tSpiderValue *Reference; // Used for everything else tSpiderObject *Object; tSpiderNamespace *Namespace; @@ -123,6 +129,7 @@ tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp) AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START"); return NULL; default: + SpiderScript_ReferenceValue(Ent->Reference); return Ent->Reference; } } @@ -147,6 +154,7 @@ void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value) case SS_DATATYPE_OBJECT: Ent->Type = SS_DATATYPE_OBJECT; Ent->Object = Value->Object; + Ent->Object->ReferenceCount ++; break; default: SpiderScript_ReferenceValue(Value); @@ -162,20 +170,75 @@ void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent) { case SS_DATATYPE_INTEGER: case SS_DATATYPE_REAL: + break; + case SS_DATATYPE_OBJECT: + if(Ent->Object) { + Ent->Object->ReferenceCount --; + if(Ent->Object->ReferenceCount == 0) { + Ent->Object->Type->Destructor( Ent->Object ); + } +// printf("Object %p derefed (obj refcount = %i)\n", Ent->Object, Ent->Object->ReferenceCount); + } + Ent->Object = NULL; + break; + default: + if(Ent->Reference) + SpiderScript_DereferenceValue(Ent->Reference); + Ent->Reference = NULL; + break; + } +} +void Bytecode_int_RefStackValue(tBC_StackEnt *Ent) +{ + switch(Ent->Type) + { + case SS_DATATYPE_INTEGER: + case SS_DATATYPE_REAL: + break; + case SS_DATATYPE_OBJECT: + if(Ent->Object) { + Ent->Object->ReferenceCount ++; +// printf("Object %p referenced (count = %i)\n", Ent->Object, Ent->Object->ReferenceCount); + } + break; + default: + if(Ent->Reference) + SpiderScript_ReferenceValue(Ent->Reference); + break; + } +} + +void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent) +{ + switch(Ent->Type) + { + case SS_DATATYPE_INTEGER: + printf("0x%"PRIx64, Ent->Integer); + break; + case SS_DATATYPE_REAL: + printf("%lf", Ent->Real); + break; case SS_DATATYPE_OBJECT: + printf("Obj %p", Ent->Object); break; default: - SpiderScript_DereferenceValue(Ent->Reference); + printf("*%p", Ent->Reference); break; } } +#if TRACE +# define PRINT_STACKVAL(val) Bytecode_int_PrintStackValue(&val) +#else +# define PRINT_STACKVAL(val) +#endif + #define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) { \ AST_RuntimeError(NULL, "Stack pop failed, empty stack");\ return ret; \ } #define PUT_STACKVAL(src) if((ret = Bytecode_int_StackPush(Stack, &src))) { \ - AST_RuntimeError(NULL, "Stack pop failed, empty stack");\ + AST_RuntimeError(NULL, "Stack push failed, full stack");\ return ret; \ } #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer) @@ -255,6 +318,10 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t tSpiderValue tmpVal1, tmpVal2; // temp storage tSpiderValue *pval1, *pval2, *ret_val; tSpiderNamespace *default_namespace = &Script->Variant->RootNamespace; + + // Initialise local vars + for( i = 0; i < local_var_count; i ++ ) + local_vars[i].Type = ET_NULL; // Pop off arguments if( ArgCount > Fcn->ArgumentCount ) return -1; @@ -286,6 +353,8 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t switch(op->Operation) { case BC_OP_NOP: + STATE_HDR(); + DEBUG_F("NOP\n"); break; // Jumps case BC_OP_JUMP: @@ -323,6 +392,10 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t } STATE_HDR(); DEBUG_F("DEFVAR %i of type %i\n", slot, type); + if( local_vars[slot].Type != ET_NULL ) { + Bytecode_int_DerefStackValue( &local_vars[slot] ); + local_vars[slot].Type = ET_NULL; + } memset(&local_vars[slot], 0, sizeof(local_vars[0])); local_vars[slot].Type = type; } break; @@ -339,25 +412,32 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t break; // Variables - case BC_OP_LOADVAR: + case BC_OP_LOADVAR: { + int slot = OP_INDX(op); STATE_HDR(); - DEBUG_F("LOADVAR %i\n", OP_INDX(op)); - if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) { - AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op)); + DEBUG_F("LOADVAR %i ", slot); + if( slot < 0 || slot >= local_var_count ) { + AST_RuntimeError(NULL, "Loading from invalid slot %i", slot); return -1; } - PUT_STACKVAL(local_vars[OP_INDX(op)]); -// DUMP_STACKVAL(local_vars[OP_INDX(op)]); - break; - case BC_OP_SAVEVAR: + DEBUG_F("("); PRINT_STACKVAL(local_vars[slot]); DEBUG_F(")\n"); + PUT_STACKVAL(local_vars[slot]); + Bytecode_int_RefStackValue( &local_vars[slot] ); + } break; + case BC_OP_SAVEVAR: { + int slot = OP_INDX(op); STATE_HDR(); - DEBUG_F("SAVEVAR %i\n", OP_INDX(op)); - if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) { - AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op)); + DEBUG_F("SAVEVAR %i = ", slot); + if( slot < 0 || slot >= local_var_count ) { + AST_RuntimeError(NULL, "Loading from invalid slot %i", slot); return -1; } - GET_STACKVAL(local_vars[OP_INDX(op)]); - break; + DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("] "); + Bytecode_int_DerefStackValue( &local_vars[slot] ); + GET_STACKVAL(local_vars[slot]); + PRINT_STACKVAL(local_vars[slot]); + DEBUG_F("\n"); + } break; // Constants: case BC_OP_LOADINT: @@ -398,7 +478,7 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t PUT_STACKVAL(val2); break; case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER: - val2.Integer = val1.Real; + val2.Real = val1.Integer; PUT_STACKVAL(val2); break; default: { @@ -414,10 +494,20 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t case BC_OP_DUPSTACK: STATE_HDR(); - DEBUG_F("DUPSTACK\n"); + DEBUG_F("DUPSTACK "); GET_STACKVAL(val1); + PRINT_STACKVAL(val1); + DEBUG_F("\n"); PUT_STACKVAL(val1); PUT_STACKVAL(val1); + Bytecode_int_RefStackValue(&val1); + break; + + // Discard the top item from the stack + case BC_OP_DELSTACK: + STATE_HDR(); + DEBUG_F("DELSTACK\n"); + GET_STACKVAL(val1); break; // Unary Operations @@ -439,6 +529,8 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t GET_STACKVAL(val1); pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1); + Bytecode_int_DerefStackValue(&val1); + ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1); if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1); Bytecode_int_SetSpiderValue(&val1, ret_val); @@ -454,6 +546,32 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t if(!ast_op) ast_op = NODETYPE_LOGICALOR, opstr = "LOGICOR"; case BC_OP_LOGICXOR: if(!ast_op) ast_op = NODETYPE_LOGICALXOR, opstr = "LOGICXOR"; + + STATE_HDR(); + DEBUG_F("%s\n", opstr); + + GET_STACKVAL(val1); + GET_STACKVAL(val2); + + switch(op->Operation) + { + case BC_OP_LOGICAND: + i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2); + break; + case BC_OP_LOGICOR: + i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2); + break; + case BC_OP_LOGICXOR: + i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2); + break; + } + Bytecode_int_DerefStackValue(&val1); + Bytecode_int_DerefStackValue(&val2); + + val1.Type = SS_DATATYPE_INTEGER; + val1.Integer = i; + Bytecode_int_StackPush(Stack, &val1); + break; case BC_OP_BITAND: if(!ast_op) ast_op = NODETYPE_BWAND, opstr = "BITAND"; @@ -494,63 +612,138 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t STATE_HDR(); DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation); - GET_STACKVAL(val2); - GET_STACKVAL(val1); + GET_STACKVAL(val2); // Right + GET_STACKVAL(val1); // Left + + #define PERFORM_NUM_OP(_type, _field) if(val1.Type == _type && val1.Type == val2.Type) { \ + switch(op->Operation) { \ + case BC_OP_ADD: val1._field = val1._field + val2._field; break; \ + case BC_OP_SUBTRACT: val1._field = val1._field - val2._field; break; \ + case BC_OP_MULTIPLY: val1._field = val1._field * val2._field; break; \ + case BC_OP_DIVIDE: val1._field = val1._field / val2._field; break; \ + case BC_OP_EQUALS: val1._field = val1._field == val2._field; break; \ + case BC_OP_LESSTHAN: val1._field = val1._field < val2._field; break; \ + case BC_OP_LESSTHANOREQUAL: val1._field = val1._field <= val2._field; break; \ + case BC_OP_GREATERTHAN: val1._field = val1._field > val2._field; break; \ + case BC_OP_GREATERTHANOREQUAL: val1._field = val1._field >= val2._field; break; \ + \ + case BC_OP_BITAND: val1._field = (int64_t)val1._field & (int64_t)val2._field; break; \ + case BC_OP_BITOR: val1._field = (int64_t)val1._field | (int64_t)val2._field; break; \ + case BC_OP_BITXOR: val1._field = (int64_t)val1._field ^ (int64_t)val2._field; break; \ + case BC_OP_MODULO: val1._field = (int64_t)val1._field % (int64_t)val2._field; break; \ + default: AST_RuntimeError(NULL, "Invalid operation on datatype %i", _type); nextop = NULL; break;\ + }\ + PUT_STACKVAL(val1);\ + break;\ + } + + PERFORM_NUM_OP(SS_DATATYPE_INTEGER, Integer); + PERFORM_NUM_OP(SS_DATATYPE_REAL, Real); + pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1); pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2); + Bytecode_int_DerefStackValue(&val1); + Bytecode_int_DerefStackValue(&val2); + ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2); if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1); if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2); + + if(ret_val == ERRPTR) { + AST_RuntimeError(NULL, "_BinOp returned ERRPTR"); + nextop = NULL; + break; + } Bytecode_int_SetSpiderValue(&val1, ret_val); if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val); - Bytecode_int_StackPush(Stack, &val1); + PUT_STACKVAL(val1); break; // Functions etc - case BC_OP_CALLFUNCTION: { - tScript_Function *fcn; + case BC_OP_CREATEOBJ: + case BC_OP_CALLFUNCTION: + case BC_OP_CALLMETHOD: { + tScript_Function *fcn = NULL; const char *name = OP_STRING(op); int arg_count = OP_INDX(op); STATE_HDR(); DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count); - // Check current script functions (for fast call) - for(fcn = Script->Functions; fcn; fcn = fcn->Next) + if( op->Operation == BC_OP_CALLFUNCTION ) { - if(strcmp(name, fcn->Name) == 0) { + // Check current script functions (for fast call) + for(fcn = Script->Functions; fcn; fcn = fcn->Next) + { + if(strcmp(name, fcn->Name) == 0) { + break; + } + } + if(fcn && fcn->BCFcn) + { + DEBUG_F(" - Fast call\n"); + Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count); break; } } - if(fcn && fcn->BCFcn) - { - DEBUG_F(" - Fast call\n"); - Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count); - break; - } // Slower call { tSpiderNamespace *ns = NULL; tSpiderValue *args[arg_count]; tSpiderValue *rv; -// for( i = 0; i < arg_count; i ++ ) + // Read arguments for( i = arg_count; i --; ) { GET_STACKVAL(val1); args[i] = Bytecode_int_GetSpiderValue(&val1, NULL); + Bytecode_int_DerefStackValue(&val1); } - if( name[0] == BC_NS_SEPARATOR ) { - name ++; - ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name); - } - else { - // TODO: Support multiple default namespaces - ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name); + // Resolve namespace into pointer + if( op->Operation != BC_OP_CALLMETHOD ) { + if( name[0] == BC_NS_SEPARATOR ) { + name ++; + ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name); + } + else { + // TODO: Support multiple default namespaces + ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name); + } } - rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args); + // Call the function etc. + if( op->Operation == BC_OP_CALLFUNCTION ) + { + rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args); + } + else if( op->Operation == BC_OP_CREATEOBJ ) + { + rv = SpiderScript_CreateObject(Script, ns, name, arg_count, args); + } + else if( op->Operation == BC_OP_CALLMETHOD ) + { + tSpiderObject *obj; + GET_STACKVAL(val1); + + if(val1.Type == SS_DATATYPE_OBJECT) + obj = val1.Object; + else if(val1.Type == ET_REFERENCE && val1.Reference->Type == SS_DATATYPE_OBJECT) + obj = val1.Reference->Object; + else { + // Error + AST_RuntimeError(NULL, "OP_CALLMETHOD on non object"); + nextop = NULL; + break; + } + rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args); + Bytecode_int_DerefStackValue(&val1); + } + else + { + AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation); + rv = ERRPTR; + } if(rv == ERRPTR) { AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR"); nextop = NULL; @@ -576,7 +769,7 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t default: // TODO: STATE_HDR(); - printf("Unknown operation %i\n", op->Operation); + AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation); nextop = NULL; break; } @@ -585,14 +778,27 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t // Clean up // - Delete local vars - printf("TODO: Clean up local vars\n"); + for( i = 0; i < local_var_count; i ++ ) + { + if( local_vars[i].Type != ET_NULL ) + { + Bytecode_int_DerefStackValue(&local_vars[i]); + } + } // - Restore stack // printf("TODO: Roll back stack\n"); -// while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START ) -// { -// Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] ); -// } + if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START ) + Stack->EntryCount --; + else + { + GET_STACKVAL(val1); + while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START ) + { + Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] ); + } + PUT_STACKVAL(val1); + } return 0;