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_index(uint32_t value)
141 if( !Output && !value ) {
145 if( value < 0x8000 ) {
146 _put_byte(value >> 8);
147 _put_byte(value & 0xFF);
149 else if( value < 0x400000 ) {
150 _put_byte( (value >> 16) | 0x80 );
151 _put_byte(value >> 8);
152 _put_byte(value & 0xFF);
156 _put_byte(value >> 24);
157 _put_byte(value >> 16);
158 _put_byte(value >> 8 );
159 _put_byte(value & 0xFF);
163 void _put_qword(uint64_t value)
165 if( value < 0x80 ) { // 7 bits into 1 byte
168 else if( !(value >> (8+6)) ) { // 14 bits packed into 2 bytes
169 _put_byte( 0x80 | ((value >> 8) & 0x3F) );
170 _put_byte( value & 0xFF );
172 else if( !(value >> (32+5)) ) { // 37 bits into 5 bytes
173 _put_byte( 0xC0 | ((value >> 32) & 0x1F) );
174 _put_dword(value & 0xFFFFFFFF);
177 _put_byte( 0xE0 ); // 64 (actually 68) bits into 9 bytes
178 _put_dword(value & 0xFFFFFFFF);
179 _put_dword(value >> 32);
183 void _put_double(double value)
185 // TODO: Machine agnostic
187 *(double*)( (char*)Output + len ) = value;
189 len += sizeof(double);
192 void _put_string(const char *str, int len)
196 strIdx = StringList_GetString(Strings, str, len);
203 for( op = Function->Operations; op; op = op->Next, idx ++ )
205 // If first run, convert labels into byte offsets
208 for( i = 0; i < Function->LabelCount; i ++ )
210 if(LabelOffsets[i]) continue;
211 if(op != Function->Labels[i]) continue;
213 LabelOffsets[i] = len;
217 _put_byte(op->Operation);
218 switch(op->Operation)
220 // Relocate jumps (the value only matters if `Output` is non-NULL)
223 case BC_OP_JUMPIFNOT:
224 // TODO: Relocations?
225 _put_index( LabelOffsets[op->Content.StringInt.Integer] );
227 // Special case for inline values
229 _put_qword(op->Content.Integer);
232 _put_double(op->Content.Real);
235 _put_string(op->Content.StringInt.String, op->Content.StringInt.Integer);
237 // Everthing else just gets handled nicely
240 _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
241 if( op->bUseInteger )
242 _put_index(op->Content.StringInt.Integer);
250 char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings)
256 label_offsets = calloc( sizeof(int), Function->LabelCount );
257 if(!label_offsets) return NULL;
259 len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings);
263 // Update length to the correct length (may decrease due to encoding)
264 len = Bytecode_int_Serialize(Function, code, label_offsets, Strings);
273 int Bytecode_AllocateLabel(tBC_Function *Handle)
277 if( Handle->LabelCount == Handle->LabelSpace ) {
279 Handle->LabelSpace += 20; // TODO: Don't hardcode increment
280 tmp = realloc(Handle->Labels, Handle->LabelSpace * sizeof(Handle->Labels[0]));
282 Handle->LabelSpace -= 20;
285 Handle->Labels = tmp;
287 ret = Handle->LabelCount ++;
288 Handle->Labels[ret] = 0;
292 void Bytecode_SetLabel(tBC_Function *Handle, int Label)
294 if(Label < 0) return ;
296 if(Label >= Handle->LabelCount) return ;
298 Handle->Labels[Label] = Handle->OperationsEnd;
302 void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
305 if( Fcn->Operations )
306 Fcn->OperationsEnd->Next = Op;
308 Fcn->Operations = Op;
309 Fcn->OperationsEnd = Op;
312 int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
314 if(Handle->VariableCount == Handle->VariableSpace) {
316 Handle->VariableSpace += 10;
317 tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
318 if(!tmp) return -1; // TODO: Error
319 Handle->VariableNames = tmp;
321 Handle->VariableNames[Handle->VariableCount] = Name;
322 Handle->VariableCount ++;
323 // Get max count (used when executing to get the frame size)
324 if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
325 Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
326 // printf("_AddVariable: %s given %i\n", Name, Handle->VariableCount - Handle->CurContextDepth - 1);
327 return Handle->VariableCount - Handle->CurContextDepth - 1;
330 int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
332 int i, context_depth = Handle->CurContextDepth;
333 // Get the start of this context
334 for( i = Handle->VariableCount; i --; )
336 if( !Handle->VariableNames[i] ) {
340 if( strcmp(Name, Handle->VariableNames[i]) == 0 )
341 return i - context_depth;
346 #define DEF_BC_NONE(_op) { \
347 tBC_Op *op = Bytecode_int_AllocateOp(_op, 0); \
348 op->Content.Integer = 0; \
349 op->bUseInteger = 0; \
350 Bytecode_int_AppendOp(Handle, op);\
353 #define DEF_BC_INT(_op, _int) {\
354 tBC_Op *op = Bytecode_int_AllocateOp(_op, 0);\
355 op->Content.StringInt.Integer = _int;\
356 op->bUseInteger = 1;\
358 Bytecode_int_AppendOp(Handle, op);\
361 #define DEF_BC_STRINT(_op, _str, _int) { \
362 tBC_Op *op = Bytecode_int_AllocateOp(_op, strlen(_str));\
363 op->Content.StringInt.Integer = _int;\
364 strcpy(op->Content.StringInt.String, _str);\
365 op->bUseInteger = 1;\
367 Bytecode_int_AppendOp(Handle, op);\
369 #define DEF_BC_STR(_op, _str) {\
370 tBC_Op *op = Bytecode_int_AllocateOp(_op, strlen(_str));\
371 strcpy(op->Content.StringInt.String, _str);\
372 op->bUseInteger = 0;\
373 Bytecode_int_AppendOp(Handle, op);\
377 void Bytecode_AppendJump(tBC_Function *Handle, int Label)
378 DEF_BC_INT(BC_OP_JUMP, Label)
379 void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
380 DEF_BC_INT(BC_OP_JUMPIF, Label)
381 void Bytecode_AppendCondJumpNot(tBC_Function *Handle, int Label)
382 DEF_BC_INT(BC_OP_JUMPIFNOT, Label)
383 void Bytecode_AppendReturn(tBC_Function *Handle)
384 DEF_BC_NONE(BC_OP_RETURN);
387 void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name)
388 DEF_BC_INT(BC_OP_LOADVAR, Bytecode_int_GetVarIndex(Handle, Name))
389 // DEF_BC_STR(BC_OP_LOADVAR, Name)
390 void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name) // (Obj->)?var =
391 DEF_BC_INT(BC_OP_SAVEVAR, Bytecode_int_GetVarIndex(Handle, Name))
392 // DEF_BC_STR(BC_OP_SAVEVAR, Name)
395 void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
397 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT, 0);
398 op->Content.Integer = Value;
399 Bytecode_int_AppendOp(Handle, op);
401 void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
403 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL, 0);
404 op->Content.Real = Value;
405 Bytecode_int_AppendOp(Handle, op);
407 void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
409 tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADSTR, Length+1);
410 op->Content.StringInt.Integer = Length;
411 memcpy(op->Content.StringInt.String, Data, Length);
412 op->Content.StringInt.String[Length] = 0;
413 Bytecode_int_AppendOp(Handle, op);
415 void Bytecode_AppendConstNull(tBC_Function *Handle)
416 DEF_BC_NONE(BC_OP_LOADNULL)
418 // --- Indexing / Scoping
419 void Bytecode_AppendElement(tBC_Function *Handle, const char *Name)
420 DEF_BC_STR(BC_OP_ELEMENT, Name)
421 void Bytecode_AppendSetElement(tBC_Function *Handle, const char *Name)
422 DEF_BC_STR(BC_OP_SETELEMENT, Name)
423 void Bytecode_AppendIndex(tBC_Function *Handle)
424 DEF_BC_NONE(BC_OP_INDEX)
425 void Bytecode_AppendSetIndex(tBC_Function *Handle)
426 DEF_BC_NONE(BC_OP_SETINDEX);
428 void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount)
429 DEF_BC_STRINT(BC_OP_CREATEOBJ, Name, ArgumentCount)
430 void Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
431 DEF_BC_STRINT(BC_OP_CALLMETHOD, Name, ArgumentCount)
432 void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
433 DEF_BC_STRINT(BC_OP_CALLFUNCTION, Name, ArgumentCount)
435 void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation)
436 DEF_BC_NONE(Operation)
437 void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation)
438 DEF_BC_NONE(Operation)
439 void Bytecode_AppendCast(tBC_Function *Handle, int Type)
440 DEF_BC_INT(BC_OP_CAST, Type)
441 void Bytecode_AppendDuplicate(tBC_Function *Handle)
442 DEF_BC_NONE(BC_OP_DUPSTACK);
443 void Bytecode_AppendDelete(tBC_Function *Handle)
444 DEF_BC_NONE(BC_OP_DELSTACK);
446 // Does some bookeeping to allocate variable slots at compile time
447 void Bytecode_AppendEnterContext(tBC_Function *Handle)
449 Handle->CurContextDepth ++;
450 Bytecode_int_AddVariable(Handle, NULL); // NULL to record the extent of this
452 DEF_BC_NONE(BC_OP_ENTERCONTEXT)
454 void Bytecode_AppendLeaveContext(tBC_Function *Handle)
457 for( i = Handle->VariableCount; i --; )
459 if( Handle->VariableNames[i] == NULL ) break;
461 Handle->CurContextDepth --;
462 Handle->VariableCount = i;
464 DEF_BC_NONE(BC_OP_LEAVECONTEXT);
466 //void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
467 // DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
468 void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
472 // Get the start of this context
473 for( i = Handle->VariableCount; i --; )
475 if( Handle->VariableNames[i] == NULL ) break;
477 // Check for duplicate allocation
478 for( i ++; i < Handle->VariableCount; i ++ )
480 if( strcmp(Name, Handle->VariableNames[i]) == 0 )
485 i = Bytecode_int_AddVariable(Handle, Name);
486 // printf("Variable %s given slot %i\n", Name, i);
488 DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))