SpiderScript - Moved header to directory, ready to remove from tree
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / bytecode_gen.c
index 8ae7f32..aad172d 100644 (file)
 #include <stdio.h>
 #include "bytecode_gen.h"
 #include <string.h>
+#include "bytecode.h"
 
 // === IMPORTS ===
 
 // === STRUCTURES ===
-typedef struct sBC_Op  tBC_Op;
-
-struct sBC_Op
-{
-       tBC_Op  *Next;
-        int    Operation;
-        int    bUseInteger;
-       union {
-               struct {
-                       const char *String;
-                        int    Integer;
-               } StringInt;
-               
-               uint64_t        Integer;
-               double  Real;
-       } Content;
-};
-
-struct sBC_Function
-{
-       const char      *Name;
-       
-        int    LabelCount;
-        int    LabelSpace;
-       tBC_Op  **Labels;
-       
-        int    MaxVariableCount;
-       // NOTE: These fields are invalid after compilation
-        int    VariableCount;
-        int    VariableSpace;
-       const char      **VariableNames;        // Only type needs to be stored
-        int    CurContextDepth;        // Used to get the real var count
-
-        int    OperationCount;
-       tBC_Op  *Operations;
-       tBC_Op  *OperationsEnd;
-
-        int    ArgumentCount;
-       struct {
-               char    *Name;
-                int    Type;
-       }       Arguments[];
-};
 
 // === PROTOTYPES ===
-tBC_Op *Bytecode_int_AllocateOp(int Operation);
+tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes);
+ int   Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name);
 
 // === GLOBALS ===
 
 // === CODE ===
-tBC_Op *Bytecode_int_AllocateOp(int Operation)
+tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes)
 {
        tBC_Op  *ret;
 
-       ret = malloc(sizeof(tBC_Op));
+       ret = malloc(sizeof(tBC_Op) + ExtraBytes);
        if(!ret)        return NULL;
 
        ret->Next = NULL;
        ret->Operation = Operation;
        ret->bUseInteger = 0;
+       ret->bUseString = (ExtraBytes > 0);
+       ret->CacheEnt = NULL;
 
        return ret;
 }
 
-tBC_Function *Bytecode_CreateFunction(const char *Name, int ArgCount, char **ArgNames, int *ArgTypes)
+tBC_Function *Bytecode_CreateFunction(tScript_Function *Fcn)
 {
        tBC_Function *ret;
         int    i;
 
-       ret = malloc(sizeof(tBC_Function) + ArgCount*sizeof(ret->Arguments[0]));
+       ret = malloc(sizeof(tBC_Function));
        if(!ret)        return NULL;
        
-       ret->Name = Name;
        ret->LabelSpace = ret->LabelCount = 0;
        ret->Labels = NULL;
-       
+
+       ret->MaxVariableCount = 0;
+       ret->CurContextDepth = 0;       
        ret->VariableCount = ret->VariableSpace = 0;
        ret->VariableNames = NULL;
 
@@ -98,11 +60,9 @@ tBC_Function *Bytecode_CreateFunction(const char *Name, int ArgCount, char **Arg
        ret->Operations = NULL;
        ret->OperationsEnd = (void*)&ret->Operations;
 
-       ret->ArgumentCount = ArgCount;
-       for( i = 0; i < ArgCount; i ++ )
+       for( i = 0; i < Fcn->ArgumentCount; i ++ )
        {
-               ret->Arguments[i].Name = strdup(ArgNames[i]);
-               ret->Arguments[i].Type = ArgTypes[i];
+               Bytecode_int_AddVariable(ret, Fcn->Arguments[i].Name);
        }
 
        return ret;
@@ -111,11 +71,6 @@ tBC_Function *Bytecode_CreateFunction(const char *Name, int ArgCount, char **Arg
 void Bytecode_DeleteFunction(tBC_Function *Fcn)
 {
        tBC_Op  *op;
-        int    i;
-       for( i = 0; i < Fcn->ArgumentCount; i ++ )
-       {
-               free(Fcn->Arguments[i].Name);
-       }
        for( op = Fcn->Operations; op; )
        {
                tBC_Op  *nextop = op->Next;
@@ -181,11 +136,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)
@@ -205,7 +198,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 ++ )
@@ -230,7 +223,7 @@ 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:
@@ -244,10 +237,10 @@ int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *Labe
                        break;
                // Everthing else just gets handled nicely
                default:
-                       if( op->Content.StringInt.String )
+                       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;
                }
        }
@@ -267,8 +260,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);
 
@@ -316,13 +310,13 @@ void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
        Fcn->OperationsEnd = Op;
 }
 
-void Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
+int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
 {
        if(Handle->VariableCount == Handle->VariableSpace) {
                void    *tmp;
                Handle->VariableSpace += 10;
                tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
-               if(!tmp)        return ;        // TODO: Error
+               if(!tmp)        return -1;      // TODO: Error
                Handle->VariableNames = tmp;
        }
        Handle->VariableNames[Handle->VariableCount] = Name;
@@ -330,85 +324,107 @@ void Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
        // Get max count (used when executing to get the frame size)
        if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
                Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
+//     printf("_AddVariable: %s given %i\n", Name, Handle->VariableCount - Handle->CurContextDepth - 1);
+       return Handle->VariableCount - Handle->CurContextDepth - 1;
 }
 
 int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
 {
-        int    i;
+        int    i, context_depth = Handle->CurContextDepth;
        // Get the start of this context
        for( i = Handle->VariableCount; i --; )
        {
-               if( Handle->VariableNames[i] == NULL )  break;
-       }
-       // Check for duplicate allocation
-       for( ; i < Handle->VariableCount; i ++ )
-       {
+               if( !Handle->VariableNames[i] ) {
+                       context_depth --;
+                       continue ;
+               }
                if( strcmp(Name, Handle->VariableNames[i]) == 0 )
-                       return i;
+                       return i - context_depth;
        }
        return -1;
 }
 
 #define DEF_BC_NONE(_op) { \
-       tBC_Op *op = Bytecode_int_AllocateOp(_op); \
+       tBC_Op *op = Bytecode_int_AllocateOp(_op, 0); \
        op->Content.Integer = 0; \
        op->bUseInteger = 0; \
        Bytecode_int_AppendOp(Handle, op);\
 }
 
+#define DEF_BC_INT(_op, _int) {\
+       tBC_Op *op = Bytecode_int_AllocateOp(_op, 0);\
+       op->Content.StringInt.Integer = _int;\
+       op->bUseInteger = 1;\
+       op->bUseString = 0;\
+       Bytecode_int_AppendOp(Handle, op);\
+}
+
 #define DEF_BC_STRINT(_op, _str, _int) { \
-       tBC_Op *op = Bytecode_int_AllocateOp(_op);\
+       tBC_Op *op = Bytecode_int_AllocateOp(_op, strlen(_str));\
        op->Content.StringInt.Integer = _int;\
-       op->Content.StringInt.String = _str;\
+       strcpy(op->Content.StringInt.String, _str);\
        op->bUseInteger = 1;\
+       op->bUseString = 1;\
        Bytecode_int_AppendOp(Handle, op);\
 }
 #define DEF_BC_STR(_op, _str) {\
-       tBC_Op *op = Bytecode_int_AllocateOp(_op);\
-       op->Content.StringInt.String = _str;\
+       tBC_Op *op = Bytecode_int_AllocateOp(_op, strlen(_str));\
+       strcpy(op->Content.StringInt.String, _str);\
        op->bUseInteger = 0;\
        Bytecode_int_AppendOp(Handle, op);\
 }
 
 // --- Flow Control
 void Bytecode_AppendJump(tBC_Function *Handle, int Label)
-       DEF_BC_STRINT(BC_OP_JUMP, NULL, Label)
+       DEF_BC_INT(BC_OP_JUMP, Label)
 void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
-       DEF_BC_STRINT(BC_OP_JUMPIF, NULL, Label)
+       DEF_BC_INT(BC_OP_JUMPIF, Label)
+void Bytecode_AppendCondJumpNot(tBC_Function *Handle, int Label)
+       DEF_BC_INT(BC_OP_JUMPIFNOT, Label)
 void Bytecode_AppendReturn(tBC_Function *Handle)
        DEF_BC_NONE(BC_OP_RETURN);
 
 // --- Variables
 void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name)
-       DEF_BC_STRINT(BC_OP_LOADVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
+       DEF_BC_INT(BC_OP_LOADVAR, Bytecode_int_GetVarIndex(Handle, Name))
 //     DEF_BC_STR(BC_OP_LOADVAR, Name)
 void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name)    // (Obj->)?var = 
-       DEF_BC_STRINT(BC_OP_SAVEVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
+       DEF_BC_INT(BC_OP_SAVEVAR, Bytecode_int_GetVarIndex(Handle, Name))
 //     DEF_BC_STR(BC_OP_SAVEVAR, Name)
 
 // --- Constants
 void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
 {
-       tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT);
+       tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT, 0);
        op->Content.Integer = Value;
        Bytecode_int_AppendOp(Handle, op);
 }
 void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
 {
-       tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL);
+       tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL, 0);
        op->Content.Real = Value;
        Bytecode_int_AppendOp(Handle, op);
 }
 void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
-       DEF_BC_STRINT(BC_OP_LOADSTR, Data, Length)
+{
+       tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADSTR, Length+1);
+       op->Content.StringInt.Integer = Length;
+       memcpy(op->Content.StringInt.String, Data, Length);
+       op->Content.StringInt.String[Length] = 0;
+       Bytecode_int_AppendOp(Handle, op);
+}
+void Bytecode_AppendConstNull(tBC_Function *Handle)
+       DEF_BC_NONE(BC_OP_LOADNULL)
 
 // --- Indexing / Scoping
-void Bytecode_AppendSubNamespace(tBC_Function *Handle, const char *Name)
-       DEF_BC_STR(BC_OP_SCOPE, Name)
 void Bytecode_AppendElement(tBC_Function *Handle, const char *Name)
        DEF_BC_STR(BC_OP_ELEMENT, Name)
+void Bytecode_AppendSetElement(tBC_Function *Handle, const char *Name)
+       DEF_BC_STR(BC_OP_SETELEMENT, Name)
 void Bytecode_AppendIndex(tBC_Function *Handle)
        DEF_BC_NONE(BC_OP_INDEX)
+void Bytecode_AppendSetIndex(tBC_Function *Handle)
+       DEF_BC_NONE(BC_OP_SETINDEX);
 
 void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount)
        DEF_BC_STRINT(BC_OP_CREATEOBJ, Name, ArgumentCount)
@@ -422,7 +438,11 @@ void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation)
 void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation)
        DEF_BC_NONE(Operation)
 void Bytecode_AppendCast(tBC_Function *Handle, int Type)
-       DEF_BC_STRINT(BC_OP_CAST, NULL, Type)
+       DEF_BC_INT(BC_OP_CAST, Type)
+void Bytecode_AppendDuplicate(tBC_Function *Handle)
+       DEF_BC_NONE(BC_OP_DUPSTACK);
+void Bytecode_AppendDelete(tBC_Function *Handle)
+       DEF_BC_NONE(BC_OP_DELSTACK);
 
 // Does some bookeeping to allocate variable slots at compile time
 void Bytecode_AppendEnterContext(tBC_Function *Handle)
@@ -440,20 +460,31 @@ void Bytecode_AppendLeaveContext(tBC_Function *Handle)
                if( Handle->VariableNames[i] == NULL )  break;
        }
        Handle->CurContextDepth --;
+       Handle->VariableCount = i;
 
-       DEF_BC_NONE(BC_OP_LEAVECONTEXT)
+       DEF_BC_NONE(BC_OP_LEAVECONTEXT);
 }
 //void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
 //     DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
 void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
 {
+        int    i;
        #if 1
-       // Check for duplicates
-       if( Bytecode_int_GetVarIndex(Handle, Name) )
-               return ;        // TODO: Error
+       // Get the start of this context
+       for( i = Handle->VariableCount; i --; )
+       {
+               if( Handle->VariableNames[i] == NULL )  break;
+       }
+       // Check for duplicate allocation
+       for( i ++; i < Handle->VariableCount; i ++ )
+       {
+               if( strcmp(Name, Handle->VariableNames[i]) == 0 )
+                       return ;
+       }
        #endif
 
-       Bytecode_int_AddVariable(Handle, Name);
-       
-       DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, Type)
+       i = Bytecode_int_AddVariable(Handle, Name);
+//     printf("Variable %s given slot %i\n", Name, i); 
+
+       DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))
 }

UCC git Repository :: git.ucc.asn.au