3 * by John Hodge (thePowersGang)
10 #include "bytecode_ops.h"
12 #include "bytecode_gen.h"
21 tBC_Op *Bytecode_int_AllocateOp(int Operation);
22 int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name);
27 tBC_Op *Bytecode_int_AllocateOp(int Operation)
31 ret = malloc(sizeof(tBC_Op));
35 ret->Operation = Operation;
41 tBC_Function *Bytecode_CreateFunction(const char *Name, int ArgCount, char **ArgNames, int *ArgTypes)
46 ret = malloc(sizeof(tBC_Function) + ArgCount*sizeof(ret->Arguments[0]));
50 ret->LabelSpace = ret->LabelCount = 0;
53 ret->MaxVariableCount = 0;
54 ret->CurContextDepth = 0;
55 ret->VariableCount = ret->VariableSpace = 0;
56 ret->VariableNames = NULL;
58 ret->OperationCount = 0;
59 ret->Operations = NULL;
60 ret->OperationsEnd = (void*)&ret->Operations;
62 ret->ArgumentCount = ArgCount;
63 for( i = 0; i < ArgCount; i ++ )
65 ret->Arguments[i].Name = strdup(ArgNames[i]);
66 ret->Arguments[i].Type = ArgTypes[i];
67 Bytecode_int_AddVariable(ret, ret->Arguments[i].Name);
73 void Bytecode_DeleteFunction(tBC_Function *Fcn)
77 for( i = 0; i < Fcn->ArgumentCount; i ++ )
79 free(Fcn->Arguments[i].Name);
81 for( op = Fcn->Operations; op; )
83 tBC_Op *nextop = op->Next;
87 free(Fcn->VariableNames);
92 int StringList_GetString(tStringList *List, const char *String, int Length)
96 for(ent = List->Head; ent; ent = ent->Next, strIdx ++)
98 if(ent->Length == Length && memcmp(ent->Data, String, Length) == 0) break;
104 ent = malloc(sizeof(tString) + Length + 1);
107 ent->Length = Length;
109 memcpy(ent->Data, String, Length);
110 ent->Data[Length] = '\0';
113 List->Tail->Next = ent;
122 int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *LabelOffsets, tStringList *Strings)
125 int len = 0, idx = 0;
128 void _put_byte(uint8_t byte)
130 uint8_t *buf = Output;
131 if(Output) buf[len] = byte;
135 void _put_dword(uint32_t value)
137 uint8_t *buf = Output;
139 buf[len+0] = value & 0xFF;
140 buf[len+1] = value >> 8;
141 buf[len+2] = value >> 16;
142 buf[len+3] = value >> 24;
147 void _put_qword(uint64_t value)
149 _put_dword(value & 0xFFFFFFFF);
150 _put_dword(value >> 32);
153 void _put_double(double value)
155 // TODO: Machine agnostic
157 *(double*)( (char*)Output + len ) = value;
159 len += sizeof(double);
162 void _put_string(const char *str, int len)
166 strIdx = StringList_GetString(Strings, str, len);
173 for( op = Function->Operations; op; op = op->Next, idx ++ )
175 // If first run, convert labels into byte offsets
178 for( i = 0; i < Function->LabelCount; i ++ )
180 if(LabelOffsets[i]) continue;
181 if(op != Function->Labels[i]) continue;
183 LabelOffsets[i] = len;
187 _put_byte(op->Operation);
188 switch(op->Operation)
190 // Relocate jumps (the value only matters if `Output` is non-NULL)
193 case BC_OP_JUMPIFNOT:
194 // TODO: Relocations?
195 _put_dword( LabelOffsets[op->Content.StringInt.Integer] );
197 // Special case for inline values
199 _put_qword(op->Content.Integer);
202 _put_double(op->Content.Real);
205 _put_string(op->Content.StringInt.String, op->Content.StringInt.Integer);
207 // Everthing else just gets handled nicely
209 if( op->Content.StringInt.String )
210 _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
211 if( op->bUseInteger )
212 _put_dword(op->Content.StringInt.Integer);
220 char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings)
226 label_offsets = calloc( sizeof(int), Function->LabelCount );
227 if(!label_offsets) return NULL;
229 len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings);
233 Bytecode_int_Serialize(Function, code, label_offsets, Strings);
242 int Bytecode_AllocateLabel(tBC_Function *Handle)
246 if( Handle->LabelCount == Handle->LabelSpace ) {
248 Handle->LabelSpace += 20; // TODO: Don't hardcode increment
249 tmp = realloc(Handle->Labels, Handle->LabelSpace * sizeof(Handle->Labels[0]));
251 Handle->LabelSpace -= 20;
254 Handle->Labels = tmp;
256 ret = Handle->LabelCount ++;
257 Handle->Labels[ret] = 0;
261 void Bytecode_SetLabel(tBC_Function *Handle, int Label)
263 if(Label < 0) return ;
265 if(Label >= Handle->LabelCount) return ;
267 Handle->Labels[Label] = Handle->OperationsEnd;
271 void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
274 if( Fcn->Operations )
275 Fcn->OperationsEnd->Next = Op;
277 Fcn->Operations = Op;
278 Fcn->OperationsEnd = Op;
281 int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
283 if(Handle->VariableCount == Handle->VariableSpace) {
285 Handle->VariableSpace += 10;
286 tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
287 if(!tmp) return -1; // TODO: Error
288 Handle->VariableNames = tmp;
290 Handle->VariableNames[Handle->VariableCount] = Name;
291 Handle->VariableCount ++;
292 // Get max count (used when executing to get the frame size)
293 if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
294 Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
295 return Handle->VariableCount - 1;
298 int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
301 // Get the start of this context
302 for( i = Handle->VariableCount; i --; )
304 if( Handle->VariableNames[i] && strcmp(Name, Handle->VariableNames[i]) == 0 )
310 #define DEF_BC_NONE(_op) { \
311 tBC_Op *op = Bytecode_int_AllocateOp(_op); \
312 op->Content.Integer = 0; \
313 op->bUseInteger = 0; \
314 Bytecode_int_AppendOp(Handle, op);\
317 #define DEF_BC_STRINT(_op, _str, _int) { \
318 tBC_Op *op = Bytecode_int_AllocateOp(_op);\
319 op->Content.StringInt.Integer = _int;\
320 op->Content.StringInt.String = _str;\
321 op->bUseInteger = 1;\
322 Bytecode_int_AppendOp(Handle, op);\
324 #define DEF_BC_STR(_op, _str) {\
325 tBC_Op *op = Bytecode_int_AllocateOp(_op);\
326 op->Content.StringInt.String = _str;\
327 op->bUseInteger = 0;\
328 Bytecode_int_AppendOp(Handle, op);\
332 void Bytecode_AppendJump(tBC_Function *Handle, int Label)
333 DEF_BC_STRINT(BC_OP_JUMP, NULL, Label)
334 void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
335 DEF_BC_STRINT(BC_OP_JUMPIF, NULL, Label)
336 void Bytecode_AppendReturn(tBC_Function *Handle)
337 DEF_BC_NONE(BC_OP_RETURN);
340 void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name)
341 DEF_BC_STRINT(BC_OP_LOADVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
342 // DEF_BC_STR(BC_OP_LOADVAR, Name)
343 void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name) // (Obj->)?var =
344 DEF_BC_STRINT(BC_OP_SAVEVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
345 // DEF_BC_STR(BC_OP_SAVEVAR, Name)
348 void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
350 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT);
351 op->Content.Integer = Value;
352 Bytecode_int_AppendOp(Handle, op);
354 void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
356 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL);
357 op->Content.Real = Value;
358 Bytecode_int_AppendOp(Handle, op);
360 void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
361 DEF_BC_STRINT(BC_OP_LOADSTR, Data, Length)
363 // --- Indexing / Scoping
364 void Bytecode_AppendSubNamespace(tBC_Function *Handle, const char *Name)
365 DEF_BC_STR(BC_OP_SCOPE, Name)
366 void Bytecode_AppendElement(tBC_Function *Handle, const char *Name)
367 DEF_BC_STR(BC_OP_ELEMENT, Name)
368 void Bytecode_AppendIndex(tBC_Function *Handle)
369 DEF_BC_NONE(BC_OP_INDEX)
371 void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount)
372 DEF_BC_STRINT(BC_OP_CREATEOBJ, Name, ArgumentCount)
373 void Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
374 DEF_BC_STRINT(BC_OP_CALLMETHOD, Name, ArgumentCount)
375 void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
376 DEF_BC_STRINT(BC_OP_CALLFUNCTION, Name, ArgumentCount)
378 void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation)
379 DEF_BC_NONE(Operation)
380 void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation)
381 DEF_BC_NONE(Operation)
382 void Bytecode_AppendCast(tBC_Function *Handle, int Type)
383 DEF_BC_STRINT(BC_OP_CAST, NULL, Type)
385 // Does some bookeeping to allocate variable slots at compile time
386 void Bytecode_AppendEnterContext(tBC_Function *Handle)
388 Handle->CurContextDepth ++;
389 Bytecode_int_AddVariable(Handle, NULL); // NULL to record the extent of this
391 DEF_BC_NONE(BC_OP_ENTERCONTEXT)
393 void Bytecode_AppendLeaveContext(tBC_Function *Handle)
396 for( i = Handle->VariableCount; i --; )
398 if( Handle->VariableNames[i] == NULL ) break;
400 Handle->CurContextDepth --;
401 Handle->VariableCount = i;
403 DEF_BC_NONE(BC_OP_LEAVECONTEXT)
405 //void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
406 // DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
407 void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
411 // Get the start of this context
412 for( i = Handle->VariableCount; i --; )
414 if( Handle->VariableNames[i] == NULL ) break;
416 // Check for duplicate allocation
417 for( i ++; i < Handle->VariableCount; i ++ )
419 if( strcmp(Name, Handle->VariableNames[i]) == 0 )
424 i = Bytecode_int_AddVariable(Handle, Name);
426 DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))