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

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