SpiderScript - Huge changes to introduce bytecode support
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / bytecode_gen.c
1 /*
2  * SpiderScript Library
3  * by John Hodge (thePowersGang)
4  * 
5  * bytecode_gen.c
6  * - Generate bytecode
7  */
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include "bytecode_ops.h"
11 #include <stdio.h>
12 #include "bytecode_gen.h"
13 #include <string.h>
14
15 // === IMPORTS ===
16
17 // === STRUCTURES ===
18 typedef struct sBC_Op   tBC_Op;
19
20 struct sBC_Op
21 {
22         tBC_Op  *Next;
23          int    Operation;
24          int    bUseInteger;
25         union {
26                 struct {
27                         const char *String;
28                          int    Integer;
29                 } StringInt;
30                 
31                 uint64_t        Integer;
32                 double  Real;
33         } Content;
34 };
35
36 struct sBC_Function
37 {
38         const char      *Name;
39         
40          int    LabelCount;
41          int    LabelSpace;
42         tBC_Op  **Labels;
43         
44          int    MaxVariableCount;
45         // NOTE: These fields are invalid after compilation
46          int    VariableCount;
47          int    VariableSpace;
48         const char      **VariableNames;        // Only type needs to be stored
49          int    CurContextDepth;        // Used to get the real var count
50
51          int    OperationCount;
52         tBC_Op  *Operations;
53         tBC_Op  *OperationsEnd;
54
55          int    ArgumentCount;
56         struct {
57                 char    *Name;
58                  int    Type;
59         }       Arguments[];
60 };
61
62 // === PROTOTYPES ===
63 tBC_Op  *Bytecode_int_AllocateOp(int Operation);
64
65 // === GLOBALS ===
66
67 // === CODE ===
68 tBC_Op *Bytecode_int_AllocateOp(int Operation)
69 {
70         tBC_Op  *ret;
71
72         ret = malloc(sizeof(tBC_Op));
73         if(!ret)        return NULL;
74
75         ret->Next = NULL;
76         ret->Operation = Operation;
77         ret->bUseInteger = 0;
78
79         return ret;
80 }
81
82 tBC_Function *Bytecode_CreateFunction(const char *Name, int ArgCount, char **ArgNames, int *ArgTypes)
83 {
84         tBC_Function *ret;
85          int    i;
86
87         ret = malloc(sizeof(tBC_Function) + ArgCount*sizeof(ret->Arguments[0]));
88         if(!ret)        return NULL;
89         
90         ret->Name = Name;
91         ret->LabelSpace = ret->LabelCount = 0;
92         ret->Labels = NULL;
93         
94         ret->VariableCount = ret->VariableSpace = 0;
95         ret->VariableNames = NULL;
96
97         ret->OperationCount = 0;
98         ret->Operations = NULL;
99         ret->OperationsEnd = (void*)&ret->Operations;
100
101         ret->ArgumentCount = ArgCount;
102         for( i = 0; i < ArgCount; i ++ )
103         {
104                 ret->Arguments[i].Name = strdup(ArgNames[i]);
105                 ret->Arguments[i].Type = ArgTypes[i];
106         }
107
108         return ret;
109 }
110
111 void Bytecode_DeleteFunction(tBC_Function *Fcn)
112 {
113         tBC_Op  *op;
114          int    i;
115         for( i = 0; i < Fcn->ArgumentCount; i ++ )
116         {
117                 free(Fcn->Arguments[i].Name);
118         }
119         for( op = Fcn->Operations; op; )
120         {
121                 tBC_Op  *nextop = op->Next;
122                 free(op);
123                 op = nextop;
124         }
125         free(Fcn->VariableNames);
126         free(Fcn->Labels);
127         free(Fcn);
128 }
129
130 int StringList_GetString(tStringList *List, const char *String, int Length)
131 {
132          int    strIdx = 0;
133         tString *ent;
134         for(ent = List->Head; ent; ent = ent->Next, strIdx ++)
135         {
136                 if(ent->Length == Length && memcmp(ent->Data, String, Length) == 0)     break;
137         }
138         if( ent ) {
139                 ent->RefCount ++;
140         }
141         else {
142                 ent = malloc(sizeof(tString) + Length + 1);
143                 if(!ent)        return -1;
144                 ent->Next = NULL;
145                 ent->Length = Length;
146                 ent->RefCount = 1;
147                 memcpy(ent->Data, String, Length);
148                 ent->Data[Length] = '\0';
149                 
150                 if(List->Head)
151                         List->Tail->Next = ent;
152                 else
153                         List->Head = ent;
154                 List->Tail = ent;
155                 List->Count ++;
156         }
157         return strIdx;
158 }
159
160 int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *LabelOffsets, tStringList *Strings)
161 {
162         tBC_Op  *op;
163          int    len = 0, idx = 0;
164          int    i;
165
166         void _put_byte(uint8_t byte)
167         {
168                 uint8_t *buf = Output;
169                 if(Output)      buf[len] = byte;
170                 len ++;
171         }
172
173         void _put_dword(uint32_t value)
174         {
175                 uint8_t *buf = Output;
176                 if(Output) {
177                         buf[len+0] = value & 0xFF;
178                         buf[len+1] = value >> 8;
179                         buf[len+2] = value >> 16;
180                         buf[len+3] = value >> 24;
181                 }
182                 len += 4;
183         }
184         
185         void _put_qword(uint64_t value)
186         {
187                 _put_dword(value & 0xFFFFFFFF);
188                 _put_dword(value >> 32);
189         }
190
191         void _put_double(double value)
192         {
193                 // TODO: Machine agnostic
194                 if(Output) {
195                         *(double*)( (char*)Output + len ) = value;
196                 }
197                 len += sizeof(double);
198         }
199
200         void _put_string(const char *str, int len)
201         {
202                  int    strIdx = 0;
203                 if( Output ) {
204                         strIdx = StringList_GetString(Strings, str, len);
205                 }
206         
207                 // TODO: Relocations    
208                 _put_dword(strIdx);
209         }
210
211         for( op = Function->Operations; op; op = op->Next, idx ++ )
212         {
213                 // If first run, convert labels into byte offsets
214                 if( !Output )
215                 {
216                         for( i = 0; i < Function->LabelCount; i ++ )
217                         {
218                                 if(LabelOffsets[i])     continue;
219                                 if(op != Function->Labels[i])   continue;
220                                 
221                                 LabelOffsets[i] = len;
222                         }
223                 }
224
225                 _put_byte(op->Operation);
226                 switch(op->Operation)
227                 {
228                 // Relocate jumps (the value only matters if `Output` is non-NULL)
229                 case BC_OP_JUMP:
230                 case BC_OP_JUMPIF:
231                 case BC_OP_JUMPIFNOT:
232                         // TODO: Relocations?
233                         _put_dword( LabelOffsets[op->Content.StringInt.Integer] );
234                         break;
235                 // Special case for inline values
236                 case BC_OP_LOADINT:
237                         _put_qword(op->Content.Integer);
238                         break;
239                 case BC_OP_LOADREAL:
240                         _put_double(op->Content.Real);
241                         break;
242                 case BC_OP_LOADSTR:
243                         _put_string(op->Content.StringInt.String, op->Content.StringInt.Integer);
244                         break;
245                 // Everthing else just gets handled nicely
246                 default:
247                         if( op->Content.StringInt.String )
248                                 _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
249                         if( op->bUseInteger )
250                                 _put_dword(op->Content.StringInt.Integer);
251                         break;
252                 }
253         }
254
255         return len;
256 }
257
258 char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings)
259 {
260          int    len;
261          int    *label_offsets;
262         char    *code;
263
264         label_offsets = calloc( sizeof(int), Function->LabelCount );
265         if(!label_offsets)      return NULL;
266
267         len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings);
268
269         code = malloc(len);
270         
271         Bytecode_int_Serialize(Function, code, label_offsets, Strings);
272
273         free(label_offsets);
274
275         *Length = len;
276
277         return code;
278 }
279
280 int Bytecode_AllocateLabel(tBC_Function *Handle)
281 {
282          int    ret;
283         
284         if( Handle->LabelCount == Handle->LabelSpace ) {
285                 void *tmp;
286                 Handle->LabelSpace += 20;       // TODO: Don't hardcode increment
287                 tmp = realloc(Handle->Labels, Handle->LabelSpace * sizeof(Handle->Labels[0]));
288                 if( !tmp ) {
289                         Handle->LabelSpace -= 20;
290                         return -1;
291                 }
292                 Handle->Labels = tmp;
293         }
294         ret = Handle->LabelCount ++;
295         Handle->Labels[ret] = 0;
296         return ret;
297 }
298
299 void Bytecode_SetLabel(tBC_Function *Handle, int Label)
300 {
301         if(Label < 0)   return ;
302         
303         if(Label >= Handle->LabelCount) return ;
304
305         Handle->Labels[Label] = Handle->OperationsEnd;
306         return ;
307 }
308
309 void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
310 {
311         Op->Next = NULL;
312         if( Fcn->Operations )
313                 Fcn->OperationsEnd->Next = Op;
314         else
315                 Fcn->Operations = Op;
316         Fcn->OperationsEnd = Op;
317 }
318
319 void Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
320 {
321         if(Handle->VariableCount == Handle->VariableSpace) {
322                 void    *tmp;
323                 Handle->VariableSpace += 10;
324                 tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
325                 if(!tmp)        return ;        // TODO: Error
326                 Handle->VariableNames = tmp;
327         }
328         Handle->VariableNames[Handle->VariableCount] = Name;
329         Handle->VariableCount ++;
330         // Get max count (used when executing to get the frame size)
331         if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
332                 Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
333 }
334
335 int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
336 {
337          int    i;
338         // Get the start of this context
339         for( i = Handle->VariableCount; i --; )
340         {
341                 if( Handle->VariableNames[i] == NULL )  break;
342         }
343         // Check for duplicate allocation
344         for( ; i < Handle->VariableCount; i ++ )
345         {
346                 if( strcmp(Name, Handle->VariableNames[i]) == 0 )
347                         return i;
348         }
349         return -1;
350 }
351
352 #define DEF_BC_NONE(_op) { \
353         tBC_Op *op = Bytecode_int_AllocateOp(_op); \
354         op->Content.Integer = 0; \
355         op->bUseInteger = 0; \
356         Bytecode_int_AppendOp(Handle, op);\
357 }
358
359 #define DEF_BC_STRINT(_op, _str, _int) { \
360         tBC_Op *op = Bytecode_int_AllocateOp(_op);\
361         op->Content.StringInt.Integer = _int;\
362         op->Content.StringInt.String = _str;\
363         op->bUseInteger = 1;\
364         Bytecode_int_AppendOp(Handle, op);\
365 }
366 #define DEF_BC_STR(_op, _str) {\
367         tBC_Op *op = Bytecode_int_AllocateOp(_op);\
368         op->Content.StringInt.String = _str;\
369         op->bUseInteger = 0;\
370         Bytecode_int_AppendOp(Handle, op);\
371 }
372
373 // --- Flow Control
374 void Bytecode_AppendJump(tBC_Function *Handle, int Label)
375         DEF_BC_STRINT(BC_OP_JUMP, NULL, Label)
376 void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
377         DEF_BC_STRINT(BC_OP_JUMPIF, NULL, Label)
378 void Bytecode_AppendReturn(tBC_Function *Handle)
379         DEF_BC_NONE(BC_OP_RETURN);
380
381 // --- Variables
382 void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name)
383         DEF_BC_STRINT(BC_OP_LOADVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
384 //      DEF_BC_STR(BC_OP_LOADVAR, Name)
385 void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name)     // (Obj->)?var = 
386         DEF_BC_STRINT(BC_OP_SAVEVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
387 //      DEF_BC_STR(BC_OP_SAVEVAR, Name)
388
389 // --- Constants
390 void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
391 {
392         tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT);
393         op->Content.Integer = Value;
394         Bytecode_int_AppendOp(Handle, op);
395 }
396 void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
397 {
398         tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL);
399         op->Content.Real = Value;
400         Bytecode_int_AppendOp(Handle, op);
401 }
402 void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
403         DEF_BC_STRINT(BC_OP_LOADSTR, Data, Length)
404
405 // --- Indexing / Scoping
406 void Bytecode_AppendSubNamespace(tBC_Function *Handle, const char *Name)
407         DEF_BC_STR(BC_OP_SCOPE, Name)
408 void Bytecode_AppendElement(tBC_Function *Handle, const char *Name)
409         DEF_BC_STR(BC_OP_ELEMENT, Name)
410 void Bytecode_AppendIndex(tBC_Function *Handle)
411         DEF_BC_NONE(BC_OP_INDEX)
412
413 void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount)
414         DEF_BC_STRINT(BC_OP_CREATEOBJ, Name, ArgumentCount)
415 void Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
416         DEF_BC_STRINT(BC_OP_CALLMETHOD, Name, ArgumentCount)
417 void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
418         DEF_BC_STRINT(BC_OP_CALLFUNCTION, Name, ArgumentCount)
419
420 void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation)
421         DEF_BC_NONE(Operation)
422 void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation)
423         DEF_BC_NONE(Operation)
424 void Bytecode_AppendCast(tBC_Function *Handle, int Type)
425         DEF_BC_STRINT(BC_OP_CAST, NULL, Type)
426
427 // Does some bookeeping to allocate variable slots at compile time
428 void Bytecode_AppendEnterContext(tBC_Function *Handle)
429 {
430         Handle->CurContextDepth ++;
431         Bytecode_int_AddVariable(Handle, NULL); // NULL to record the extent of this    
432
433         DEF_BC_NONE(BC_OP_ENTERCONTEXT)
434 }
435 void Bytecode_AppendLeaveContext(tBC_Function *Handle)
436 {
437          int    i;
438         for( i = Handle->VariableCount; i --; )
439         {
440                 if( Handle->VariableNames[i] == NULL )  break;
441         }
442         Handle->CurContextDepth --;
443
444         DEF_BC_NONE(BC_OP_LEAVECONTEXT)
445 }
446 //void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
447 //      DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
448 void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
449 {
450         #if 1
451         // Check for duplicates
452         if( Bytecode_int_GetVarIndex(Handle, Name) )
453                 return ;        // TODO: Error
454         #endif
455
456         Bytecode_int_AddVariable(Handle, Name);
457         
458         DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, Type)
459 }

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