3 * by John Hodge (thePowersGang)
10 #include "bytecode_ops.h"
12 #include "bytecode_gen.h"
21 tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes);
22 int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name);
27 tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes)
31 ret = malloc(sizeof(tBC_Op) + ExtraBytes);
35 ret->Operation = Operation;
37 ret->bUseString = (ExtraBytes > 0);
42 tBC_Function *Bytecode_CreateFunction(tScript_Function *Fcn)
47 ret = malloc(sizeof(tBC_Function));
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 for( i = 0; i < Fcn->ArgumentCount; i ++ )
64 Bytecode_int_AddVariable(ret, Fcn->Arguments[i].Name);
70 void Bytecode_DeleteFunction(tBC_Function *Fcn)
73 for( op = Fcn->Operations; op; )
75 tBC_Op *nextop = op->Next;
79 free(Fcn->VariableNames);
84 int StringList_GetString(tStringList *List, const char *String, int Length)
88 for(ent = List->Head; ent; ent = ent->Next, strIdx ++)
90 if(ent->Length == Length && memcmp(ent->Data, String, Length) == 0) break;
96 ent = malloc(sizeof(tString) + Length + 1);
101 memcpy(ent->Data, String, Length);
102 ent->Data[Length] = '\0';
105 List->Tail->Next = ent;
114 int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *LabelOffsets, tStringList *Strings)
117 int len = 0, idx = 0;
120 void _put_byte(uint8_t byte)
122 uint8_t *buf = Output;
123 if(Output) buf[len] = byte;
127 void _put_dword(uint32_t value)
129 uint8_t *buf = 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;
139 void _put_qword(uint64_t value)
141 _put_dword(value & 0xFFFFFFFF);
142 _put_dword(value >> 32);
145 void _put_double(double value)
147 // TODO: Machine agnostic
149 *(double*)( (char*)Output + len ) = value;
151 len += sizeof(double);
154 void _put_string(const char *str, int len)
158 strIdx = StringList_GetString(Strings, str, len);
165 for( op = Function->Operations; op; op = op->Next, idx ++ )
167 // If first run, convert labels into byte offsets
170 for( i = 0; i < Function->LabelCount; i ++ )
172 if(LabelOffsets[i]) continue;
173 if(op != Function->Labels[i]) continue;
175 LabelOffsets[i] = len;
179 _put_byte(op->Operation);
180 switch(op->Operation)
182 // Relocate jumps (the value only matters if `Output` is non-NULL)
185 case BC_OP_JUMPIFNOT:
186 // TODO: Relocations?
187 _put_dword( LabelOffsets[op->Content.StringInt.Integer] );
189 // Special case for inline values
191 _put_qword(op->Content.Integer);
194 _put_double(op->Content.Real);
197 _put_string(op->Content.StringInt.String, op->Content.StringInt.Integer);
199 // Everthing else just gets handled nicely
202 _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
203 if( op->bUseInteger )
204 _put_dword(op->Content.StringInt.Integer);
212 char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings)
218 label_offsets = calloc( sizeof(int), Function->LabelCount );
219 if(!label_offsets) return NULL;
221 len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings);
225 Bytecode_int_Serialize(Function, code, label_offsets, Strings);
234 int Bytecode_AllocateLabel(tBC_Function *Handle)
238 if( Handle->LabelCount == Handle->LabelSpace ) {
240 Handle->LabelSpace += 20; // TODO: Don't hardcode increment
241 tmp = realloc(Handle->Labels, Handle->LabelSpace * sizeof(Handle->Labels[0]));
243 Handle->LabelSpace -= 20;
246 Handle->Labels = tmp;
248 ret = Handle->LabelCount ++;
249 Handle->Labels[ret] = 0;
253 void Bytecode_SetLabel(tBC_Function *Handle, int Label)
255 if(Label < 0) return ;
257 if(Label >= Handle->LabelCount) return ;
259 Handle->Labels[Label] = Handle->OperationsEnd;
263 void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
266 if( Fcn->Operations )
267 Fcn->OperationsEnd->Next = Op;
269 Fcn->Operations = Op;
270 Fcn->OperationsEnd = Op;
273 int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
275 if(Handle->VariableCount == Handle->VariableSpace) {
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;
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;
291 int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
293 int i, context_depth = Handle->CurContextDepth;
294 // Get the start of this context
295 for( i = Handle->VariableCount; i --; )
297 if( !Handle->VariableNames[i] ) {
301 if( strcmp(Name, Handle->VariableNames[i]) == 0 )
302 return i - context_depth;
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);\
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;\
319 Bytecode_int_AppendOp(Handle, op);\
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;\
328 Bytecode_int_AppendOp(Handle, op);\
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);\
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);
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)
356 void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
358 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT, 0);
359 op->Content.Integer = Value;
360 Bytecode_int_AppendOp(Handle, op);
362 void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
364 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL, 0);
365 op->Content.Real = Value;
366 Bytecode_int_AppendOp(Handle, op);
368 void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
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);
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)
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)
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 void Bytecode_AppendDelete(tBC_Function *Handle)
399 DEF_BC_NONE(BC_OP_DELSTACK);
401 // Does some bookeeping to allocate variable slots at compile time
402 void Bytecode_AppendEnterContext(tBC_Function *Handle)
404 Handle->CurContextDepth ++;
405 Bytecode_int_AddVariable(Handle, NULL); // NULL to record the extent of this
407 DEF_BC_NONE(BC_OP_ENTERCONTEXT)
409 void Bytecode_AppendLeaveContext(tBC_Function *Handle)
412 for( i = Handle->VariableCount; i --; )
414 if( Handle->VariableNames[i] == NULL ) break;
416 Handle->CurContextDepth --;
417 Handle->VariableCount = i;
419 DEF_BC_NONE(BC_OP_LEAVECONTEXT);
421 //void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
422 // DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
423 void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
427 // Get the start of this context
428 for( i = Handle->VariableCount; i --; )
430 if( Handle->VariableNames[i] == NULL ) break;
432 // Check for duplicate allocation
433 for( i ++; i < Handle->VariableCount; i ++ )
435 if( strcmp(Name, Handle->VariableNames[i]) == 0 )
440 i = Bytecode_int_AddVariable(Handle, Name);
441 // printf("Variable %s given slot %i\n", Name, i);
443 DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))