From: John Hodge Date: Sun, 15 Apr 2012 04:59:44 +0000 (+0800) Subject: Usermode/libspiderscript - Cleaning code, made bytecode dump smaller X-Git-Tag: rel0.15~714^2~10 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=8941e970e3c4c47b82ba5d1c199a3c9e392088f6;p=tpg%2Facess2.git Usermode/libspiderscript - Cleaning code, made bytecode dump smaller --- diff --git a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c index d9992221..4653145c 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c @@ -208,6 +208,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) if(ret) return ret; } + // Push arguments to the stack for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) { ret = AST_ConvertNode(Block, node, 1); diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c index d6e8ab03..e2b1683d 100644 --- a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c +++ b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c @@ -135,11 +135,49 @@ int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *Labe } len += 4; } - + + void _put_index(uint32_t value) + { + if( !Output && !value ) { + len += 5; + return ; + } + if( value < 0x8000 ) { + _put_byte(value >> 8); + _put_byte(value & 0xFF); + } + else if( value < 0x400000 ) { + _put_byte( (value >> 16) | 0x80 ); + _put_byte(value >> 8); + _put_byte(value & 0xFF); + } + else { + _put_byte( 0xC0 ); + _put_byte(value >> 24); + _put_byte(value >> 16); + _put_byte(value >> 8 ); + _put_byte(value & 0xFF); + } + } + void _put_qword(uint64_t value) { - _put_dword(value & 0xFFFFFFFF); - _put_dword(value >> 32); + if( value < 0x80 ) { // 7 bits into 1 byte + _put_byte(value); + } + else if( !(value >> (8+6)) ) { // 14 bits packed into 2 bytes + _put_byte( 0x80 | ((value >> 8) & 0x3F) ); + _put_byte( value & 0xFF ); + } + else if( !(value >> (32+5)) ) { // 37 bits into 5 bytes + _put_byte( 0xC0 | ((value >> 32) & 0x1F) ); + _put_dword(value & 0xFFFFFFFF); + } + else { + _put_byte( 0xE0 ); // 64 (actually 68) bits into 9 bytes + _put_dword(value & 0xFFFFFFFF); + _put_dword(value >> 32); + } } void _put_double(double value) @@ -159,7 +197,7 @@ int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *Labe } // TODO: Relocations - _put_dword(strIdx); + _put_index(strIdx); } for( op = Function->Operations; op; op = op->Next, idx ++ ) @@ -184,11 +222,11 @@ int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *Labe case BC_OP_JUMPIF: case BC_OP_JUMPIFNOT: // TODO: Relocations? - _put_dword( LabelOffsets[op->Content.StringInt.Integer] ); + _put_index( LabelOffsets[op->Content.StringInt.Integer] ); break; // Special case for inline values case BC_OP_LOADINT: - _put_qword(op->Content.Integer); + _put_index(op->Content.Integer); break; case BC_OP_LOADREAL: _put_double(op->Content.Real); @@ -201,7 +239,7 @@ int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *Labe if( op->bUseString ) _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String)); if( op->bUseInteger ) - _put_dword(op->Content.StringInt.Integer); + _put_index(op->Content.StringInt.Integer); break; } } @@ -221,8 +259,9 @@ char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStr len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings); code = malloc(len); - - Bytecode_int_Serialize(Function, code, label_offsets, Strings); + + // Update length to the correct length (may decrease due to encoding) + len = Bytecode_int_Serialize(Function, code, label_offsets, Strings); free(label_offsets); diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_makefile.c b/Usermode/Libraries/libspiderscript.so_src/bytecode_makefile.c index 5affbef0..f90fb333 100644 --- a/Usermode/Libraries/libspiderscript.so_src/bytecode_makefile.c +++ b/Usermode/Libraries/libspiderscript.so_src/bytecode_makefile.c @@ -42,7 +42,6 @@ int SpiderScript_SaveBytecode(tSpiderScript *Script, const char *DestFile) fp = fopen(DestFile, "wb"); if(!fp) return 1; - // Create header fwrite("SSBC\r\n\xBC\x55", 8, 1, fp); _put32(0); // Function count, to be filled @@ -112,7 +111,7 @@ int SpiderScript_SaveBytecode(tSpiderScript *Script, const char *DestFile) { tString *nextstr = str->Next; fwrite(str->Data, str->Length, 1, fp); - _put8(0); + _put8(0); // NULL separator free(str); str = nextstr; } diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c index 46749aef..78e6740c 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c @@ -482,37 +482,49 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) return ERRPTR; } - if( !op1 || op1->Type != SS_DATATYPE_ARRAY ) + if( !op2 || op2->Type != SS_DATATYPE_INTEGER ) { - // TODO: Implement "operator []" on objects - AST_RuntimeError(Node, "Indexing non-array"); - ret = ERRPTR; - break; + if( !Block->Script->Variant->bImplicitCasts ) { + AST_RuntimeError(Node, "Array index is not an integer"); + ret = ERRPTR; + break; + } + else { + tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2); + SpiderScript_DereferenceValue(op2); + op2 = tmpobj; + } } - - if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) { - AST_RuntimeError(Node, "Array index is not an integer"); + + if( !op1 ) + { + SpiderScript_DereferenceValue(op2); + AST_RuntimeError(Node, "Indexing NULL value"); ret = ERRPTR; break; } - - if( !op2 || op2->Type != SS_DATATYPE_INTEGER ) + + switch( op1->Type ) { - tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2); - SpiderScript_DereferenceValue(op2); - op2 = tmpobj; - } + case SS_DATATYPE_ARRAY: + if( op2->Integer >= op1->Array.Length ) { + AST_RuntimeError(Node, "Array index out of bounds %i >= %i", + op2->Integer, op1->Array.Length); + ret = ERRPTR; + break; + } + + ret = op1->Array.Items[ op2->Integer ]; + SpiderScript_ReferenceValue(ret); + break; - if( op2->Integer >= op1->Array.Length ) { - AST_RuntimeError(Node, "Array index out of bounds %i >= %i", - op2->Integer, op1->Array.Length); + default: + // TODO: Implement "operator []" on objects + AST_RuntimeError(Node, "Indexing non-array"); ret = ERRPTR; break; } - ret = op1->Array.Items[ op2->Integer ]; - SpiderScript_ReferenceValue(ret); - SpiderScript_DereferenceValue(op1); SpiderScript_DereferenceValue(op2); break; diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c index d12cb731..50dfec45 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c @@ -303,6 +303,140 @@ tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const c return ns; } +/** + * \brief Call an external function (may recurse into Bytecode_ExecuteFunction, but may not) + */ +int Bytecode_int_CallExternFunction(tSpiderScript *Script, tBC_Stack *Stack, tSpiderNamespace *DefaultNS, tBC_Op *op ) +{ + const char *name = OP_STRING(op); + int arg_count = OP_INDX(op); + int i, ret = 0; + tSpiderNamespace *ns = NULL; + tSpiderValue *args[arg_count]; + tSpiderValue *rv; + tBC_StackEnt val1; + + DEBUG_F("CALL (general) %s %i args\n", name, arg_count); + + // Read arguments + for( i = arg_count; i --; ) + { + GET_STACKVAL(val1); + args[i] = Bytecode_int_GetSpiderValue(&val1, NULL); + Bytecode_int_DerefStackValue(&val1); + } + + // Resolve namespace into pointer + if( op->Operation != BC_OP_CALLMETHOD ) { + const char *name_orig = name; + 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(DefaultNS, name, &name); + } + if( !ns ) { + AST_RuntimeError(NULL, "Namespace '%s' not found in '%s'", name, name_orig); + return -1; + } + } + + // 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 && val1.Reference->Type == SS_DATATYPE_OBJECT) + obj = val1.Reference->Object; + else { + // Error + AST_RuntimeError(NULL, "OP_CALLMETHOD on non object"); + return -1; + } + 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"); + return -1; + } + // Clean up args + for( i = arg_count; i --; ) + SpiderScript_DereferenceValue(args[i]); + // Get and push return + Bytecode_int_SetSpiderValue(&val1, rv); + PUT_STACKVAL(val1); + // Deref return + SpiderScript_DereferenceValue(rv); + + return ret; +} + +int Bytecode_int_LocalBinOp_Integer(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2) +{ + switch(Operation) + { + case BC_OP_ADD: Val1->Integer = Val1->Integer + Val2->Integer; break; + case BC_OP_SUBTRACT: Val1->Integer = Val1->Integer - Val2->Integer; break; + case BC_OP_MULTIPLY: Val1->Integer = Val1->Integer * Val2->Integer; break; + case BC_OP_DIVIDE: Val1->Integer = Val1->Integer / Val2->Integer; break; + + case BC_OP_EQUALS: Val1->Integer = (Val1->Integer == Val2->Integer); break; + case BC_OP_NOTEQUALS: Val1->Integer = (Val1->Integer != Val2->Integer); break; + case BC_OP_LESSTHAN: Val1->Integer = (Val1->Integer < Val2->Integer); break; + case BC_OP_LESSTHANOREQUAL: Val1->Integer = (Val1->Integer <= Val2->Integer); break; + case BC_OP_GREATERTHAN: Val1->Integer = (Val1->Integer > Val2->Integer); break; + case BC_OP_GREATERTHANOREQUAL: Val1->Integer = (Val1->Integer >= Val2->Integer); break; + + case BC_OP_BITAND: Val1->Integer = Val1->Integer & Val2->Integer; break; + case BC_OP_BITOR: Val1->Integer = Val1->Integer | Val2->Integer; break; + case BC_OP_BITXOR: Val1->Integer = Val1->Integer ^ Val2->Integer; break; + case BC_OP_MODULO: Val1->Integer = Val1->Integer % Val2->Integer; break; + default: AST_RuntimeError(NULL, "Invalid operation on datatype %i", Val1->Type); return -1; + } + return 0; +} + +int Bytecode_int_LocalBinOp_Real(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2) +{ + switch(Operation) + { + case BC_OP_ADD: Val1->Real = Val1->Real + Val2->Real; return 0; + case BC_OP_SUBTRACT: Val1->Real = Val1->Real - Val2->Real; return 0; + case BC_OP_MULTIPLY: Val1->Real = Val1->Real * Val2->Real; return 0; + case BC_OP_DIVIDE: Val1->Real = Val1->Real / Val2->Real; return 0; + + case BC_OP_EQUALS: Val1->Integer = (Val1->Real == Val2->Real); break; + case BC_OP_NOTEQUALS: Val1->Integer = (Val1->Real != Val2->Real); break; + case BC_OP_LESSTHAN: Val1->Integer = (Val1->Real < Val2->Real); break; + case BC_OP_LESSTHANOREQUAL: Val1->Integer = (Val1->Real <= Val2->Real); break; + case BC_OP_GREATERTHAN: Val1->Integer = (Val1->Real > Val2->Real); break; + case BC_OP_GREATERTHANOREQUAL: Val1->Integer = (Val1->Real >= Val2->Real); break; + + default: AST_RuntimeError(NULL, "Invalid operation on datatype %i", Val1->Type); return -1; + } + Val1->Type = SS_DATATYPE_INTEGER; // Becomes logical + return 0; +} + #define STATE_HDR() DEBUG_F("%p %2i ", op, Stack->EntryCount) /** @@ -326,6 +460,7 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t // Pop off arguments if( ArgCount > Fcn->ArgumentCount ) return -1; DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount); + // - Handle optional arguments for( i = Fcn->ArgumentCount; i > ArgCount; ) { i --; @@ -623,39 +758,33 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t DEBUG_F(" ("); PRINT_STACKVAL(val1); DEBUG_F(")"); DEBUG_F(" ("); PRINT_STACKVAL(val2); DEBUG_F(")\n"); - #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.Type=SS_DATATYPE_INTEGER; val1.Integer = (val1._field == val2._field); break; \ - case BC_OP_NOTEQUALS: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = (val1._field != val2._field); break; \ - case BC_OP_LESSTHAN: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field < val2._field; break; \ - case BC_OP_LESSTHANOREQUAL: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field <= val2._field; break; \ - case BC_OP_GREATERTHAN: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field > val2._field; break; \ - case BC_OP_GREATERTHANOREQUAL: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = 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;\ - }\ - DEBUG_F(" - Fast local op\n");\ - PUT_STACKVAL(val1);\ - break;\ + // Perform integer operations locally + if( val1.Type == SS_DATATYPE_INTEGER && val2.Type == SS_DATATYPE_INTEGER ) + { + if( Bytecode_int_LocalBinOp_Integer(op->Operation, &val1, &val2) ) { + nextop = NULL; + break; + } + PUT_STACKVAL(val1); + break; } - PERFORM_NUM_OP(SS_DATATYPE_INTEGER, Integer); - PERFORM_NUM_OP(SS_DATATYPE_REAL, Real); + if(val1. Type == SS_DATATYPE_REAL && val2.Type == SS_DATATYPE_REAL ) + { + if( Bytecode_int_LocalBinOp_Real(op->Operation, &val1, &val2) ) { + nextop = NULL; + break; + } + PUT_STACKVAL(val1); + break; + } pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1); pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2); Bytecode_int_DerefStackValue(&val1); Bytecode_int_DerefStackValue(&val2); + // Hand to AST execution code ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2); if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1); if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2); @@ -673,16 +802,15 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t // Functions etc 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); - + case BC_OP_CALLMETHOD: STATE_HDR(); - DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count); if( op->Operation == BC_OP_CALLFUNCTION ) { + tScript_Function *fcn = NULL; + const char *name = OP_STRING(op); + int arg_count = OP_INDX(op); + DEBUG_F("CALL (local) %s %i args\n", name, arg_count); // Check current script functions (for fast call) for(fcn = Script->Functions; fcn; fcn = fcn->Next) { @@ -697,82 +825,17 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t break; } } - + // Slower call - { - tSpiderNamespace *ns = NULL; - tSpiderValue *args[arg_count]; - tSpiderValue *rv; - // Read arguments - for( i = arg_count; i --; ) - { - GET_STACKVAL(val1); - args[i] = Bytecode_int_GetSpiderValue(&val1, NULL); - Bytecode_int_DerefStackValue(&val1); - } - - // 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); - } - } - - // 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 && 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; - break; - } - // Clean up args - for( i = arg_count; i --; ) - SpiderScript_DereferenceValue(args[i]); - // Get and push return - Bytecode_int_SetSpiderValue(&val1, rv); - PUT_STACKVAL(val1); - // Deref return - SpiderScript_DereferenceValue(rv); + if( Bytecode_int_CallExternFunction( Script, Stack, default_namespace, op ) ) { + nextop = NULL; + break; } - } break; + break; case BC_OP_RETURN: STATE_HDR(); + DEBUG_F("RETURN\n"); nextop = NULL; break; @@ -798,17 +861,19 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t } // - Restore stack -// printf("TODO: Roll back stack\n"); if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START ) Stack->EntryCount --; else { + int n_rolled = 1; GET_STACKVAL(val1); while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START ) { Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] ); + n_rolled ++; } PUT_STACKVAL(val1); + DEBUG_F("Rolled back %i entried\n", n_rolled); }