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(tScript_Function *Fcn)
46 ret = malloc(sizeof(tBC_Function));
49 ret->LabelSpace = ret->LabelCount = 0;
52 ret->MaxVariableCount = 0;
53 ret->CurContextDepth = 0;
54 ret->VariableCount = ret->VariableSpace = 0;
55 ret->VariableNames = NULL;
57 ret->OperationCount = 0;
58 ret->Operations = NULL;
59 ret->OperationsEnd = (void*)&ret->Operations;
61 for( i = 0; i < Fcn->ArgumentCount; i ++ )
63 Bytecode_int_AddVariable(ret, Fcn->Arguments[i].Name);
69 void Bytecode_DeleteFunction(tBC_Function *Fcn)
72 for( op = Fcn->Operations; op; )
74 tBC_Op *nextop = op->Next;
78 free(Fcn->VariableNames);
83 int StringList_GetString(tStringList *List, const char *String, int Length)
87 for(ent = List->Head; ent; ent = ent->Next, strIdx ++)
89 if(ent->Length == Length && memcmp(ent->Data, String, Length) == 0) break;
95 ent = malloc(sizeof(tString) + Length + 1);
100 memcpy(ent->Data, String, Length);
101 ent->Data[Length] = '\0';
104 List->Tail->Next = ent;
113 int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *LabelOffsets, tStringList *Strings)
116 int len = 0, idx = 0;
119 void _put_byte(uint8_t byte)
121 uint8_t *buf = Output;
122 if(Output) buf[len] = byte;
126 void _put_dword(uint32_t value)
128 uint8_t *buf = Output;
130 buf[len+0] = value & 0xFF;
131 buf[len+1] = value >> 8;
132 buf[len+2] = value >> 16;
133 buf[len+3] = value >> 24;
138 void _put_qword(uint64_t value)
140 _put_dword(value & 0xFFFFFFFF);
141 _put_dword(value >> 32);
144 void _put_double(double value)
146 // TODO: Machine agnostic
148 *(double*)( (char*)Output + len ) = value;
150 len += sizeof(double);
153 void _put_string(const char *str, int len)
157 strIdx = StringList_GetString(Strings, str, len);
164 for( op = Function->Operations; op; op = op->Next, idx ++ )
166 // If first run, convert labels into byte offsets
169 for( i = 0; i < Function->LabelCount; i ++ )
171 if(LabelOffsets[i]) continue;
172 if(op != Function->Labels[i]) continue;
174 LabelOffsets[i] = len;
178 _put_byte(op->Operation);
179 switch(op->Operation)
181 // Relocate jumps (the value only matters if `Output` is non-NULL)
184 case BC_OP_JUMPIFNOT:
185 // TODO: Relocations?
186 _put_dword( LabelOffsets[op->Content.StringInt.Integer] );
188 // Special case for inline values
190 _put_qword(op->Content.Integer);
193 _put_double(op->Content.Real);
196 _put_string(op->Content.StringInt.String, op->Content.StringInt.Integer);
198 // Everthing else just gets handled nicely
200 if( op->Content.StringInt.String )
201 _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
202 if( op->bUseInteger )
203 _put_dword(op->Content.StringInt.Integer);
211 char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings)
217 label_offsets = calloc( sizeof(int), Function->LabelCount );
218 if(!label_offsets) return NULL;
220 len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings);
224 Bytecode_int_Serialize(Function, code, label_offsets, Strings);
233 int Bytecode_AllocateLabel(tBC_Function *Handle)
237 if( Handle->LabelCount == Handle->LabelSpace ) {
239 Handle->LabelSpace += 20; // TODO: Don't hardcode increment
240 tmp = realloc(Handle->Labels, Handle->LabelSpace * sizeof(Handle->Labels[0]));
242 Handle->LabelSpace -= 20;
245 Handle->Labels = tmp;
247 ret = Handle->LabelCount ++;
248 Handle->Labels[ret] = 0;
252 void Bytecode_SetLabel(tBC_Function *Handle, int Label)
254 if(Label < 0) return ;
256 if(Label >= Handle->LabelCount) return ;
258 Handle->Labels[Label] = Handle->OperationsEnd;
262 void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
265 if( Fcn->Operations )
266 Fcn->OperationsEnd->Next = Op;
268 Fcn->Operations = Op;
269 Fcn->OperationsEnd = Op;
272 int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
274 if(Handle->VariableCount == Handle->VariableSpace) {
276 Handle->VariableSpace += 10;
277 tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
278 if(!tmp) return -1; // TODO: Error
279 Handle->VariableNames = tmp;
281 Handle->VariableNames[Handle->VariableCount] = Name;
282 Handle->VariableCount ++;
283 // Get max count (used when executing to get the frame size)
284 if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
285 Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
286 return Handle->VariableCount - 1;
289 int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
292 // Get the start of this context
293 for( i = Handle->VariableCount; i --; )
295 if( Handle->VariableNames[i] && strcmp(Name, Handle->VariableNames[i]) == 0 )
301 #define DEF_BC_NONE(_op) { \
302 tBC_Op *op = Bytecode_int_AllocateOp(_op); \
303 op->Content.Integer = 0; \
304 op->bUseInteger = 0; \
305 Bytecode_int_AppendOp(Handle, op);\
308 #define DEF_BC_STRINT(_op, _str, _int) { \
309 tBC_Op *op = Bytecode_int_AllocateOp(_op);\
310 op->Content.StringInt.Integer = _int;\
311 op->Content.StringInt.String = _str;\
312 op->bUseInteger = 1;\
313 Bytecode_int_AppendOp(Handle, op);\
315 #define DEF_BC_STR(_op, _str) {\
316 tBC_Op *op = Bytecode_int_AllocateOp(_op);\
317 op->Content.StringInt.String = _str;\
318 op->bUseInteger = 0;\
319 Bytecode_int_AppendOp(Handle, op);\
323 void Bytecode_AppendJump(tBC_Function *Handle, int Label)
324 DEF_BC_STRINT(BC_OP_JUMP, NULL, Label)
325 void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
326 DEF_BC_STRINT(BC_OP_JUMPIF, NULL, Label)
327 void Bytecode_AppendReturn(tBC_Function *Handle)
328 DEF_BC_NONE(BC_OP_RETURN);
331 void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name)
332 DEF_BC_STRINT(BC_OP_LOADVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
333 // DEF_BC_STR(BC_OP_LOADVAR, Name)
334 void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name) // (Obj->)?var =
335 DEF_BC_STRINT(BC_OP_SAVEVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
336 // DEF_BC_STR(BC_OP_SAVEVAR, Name)
339 void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
341 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT);
342 op->Content.Integer = Value;
343 Bytecode_int_AppendOp(Handle, op);
345 void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
347 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL);
348 op->Content.Real = Value;
349 Bytecode_int_AppendOp(Handle, op);
351 void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
352 DEF_BC_STRINT(BC_OP_LOADSTR, Data, Length)
354 // --- Indexing / Scoping
355 void Bytecode_AppendSubNamespace(tBC_Function *Handle, const char *Name)
356 DEF_BC_STR(BC_OP_SCOPE, Name)
357 void Bytecode_AppendElement(tBC_Function *Handle, const char *Name)
358 DEF_BC_STR(BC_OP_ELEMENT, Name)
359 void Bytecode_AppendIndex(tBC_Function *Handle)
360 DEF_BC_NONE(BC_OP_INDEX)
362 void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount)
363 DEF_BC_STRINT(BC_OP_CREATEOBJ, Name, ArgumentCount)
364 void Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
365 DEF_BC_STRINT(BC_OP_CALLMETHOD, Name, ArgumentCount)
366 void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
367 DEF_BC_STRINT(BC_OP_CALLFUNCTION, Name, ArgumentCount)
369 void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation)
370 DEF_BC_NONE(Operation)
371 void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation)
372 DEF_BC_NONE(Operation)
373 void Bytecode_AppendCast(tBC_Function *Handle, int Type)
374 DEF_BC_STRINT(BC_OP_CAST, NULL, Type)
376 // Does some bookeeping to allocate variable slots at compile time
377 void Bytecode_AppendEnterContext(tBC_Function *Handle)
379 Handle->CurContextDepth ++;
380 Bytecode_int_AddVariable(Handle, NULL); // NULL to record the extent of this
382 DEF_BC_NONE(BC_OP_ENTERCONTEXT)
384 void Bytecode_AppendLeaveContext(tBC_Function *Handle)
387 for( i = Handle->VariableCount; i --; )
389 if( Handle->VariableNames[i] == NULL ) break;
391 Handle->CurContextDepth --;
392 Handle->VariableCount = i;
394 DEF_BC_NONE(BC_OP_LEAVECONTEXT)
396 //void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
397 // DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
398 void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
402 // Get the start of this context
403 for( i = Handle->VariableCount; i --; )
405 if( Handle->VariableNames[i] == NULL ) break;
407 // Check for duplicate allocation
408 for( i ++; i < Handle->VariableCount; i ++ )
410 if( strcmp(Name, Handle->VariableNames[i]) == 0 )
415 i = Bytecode_int_AddVariable(Handle, Name);
417 DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))