Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
192 lines (174 sloc) 6.36 KB
class Rosella.Reflect.Deserializer
{
// TODO: Do we need this to be a class or can it be a utility namespace?
function Deserializer() {}
function get_instructions(var pf, int start_offs, int end_offs)
{
// TODO: Be smarter. Allow pf param to be a Packfile, PackfileView or
// Module.
var module = Rosella.Reflect.get_module_from_packfile(pf);
pf = module.get_packfile_builder();
// TODO: Try to break all this logic up into more usable sub-components
var bc_seg = self.__get_pf_segment(pf, "PackfileBytecodeSegment");
var const_seg = self.__get_pf_segment(pf, "PackfileConstantTable");
var const_table = self.get_constants(const_seg);
var opmap = bc_seg.opmap();
var oplibs = opmap.oplibs();
int size = int(opmap);
var map = [];
for (int i = 0; i < size; ++i) {
string name = opmap[i];
map[i] = opmap[name];
}
opmap = map;
var bc = self.get_bytecode_raw(bc_seg, start_offs, end_offs);
var ins = [];
for (int i = 0; i < elements(bc);) {
:(var instr, int j) = self.__decode_op(const_table, opmap, oplibs, bc, i);
push(ins, instr);
//Rosella.IO.sayf("Adding %d to i", j);
i += j;
}
return ins;
}
function get_bytecode_raw(var bc_seg, int start_offs, int end_offs)
{
int bc[] = [];
if (start_offs > end_offs ||
(start_offs == end_offs && start_offs != 0) ||
start_offs > elements(bc_seg) || end_offs > elements(bc_seg) ||
start_offs < 0 || end_offs < 0)
Rosella.Error.invalid(__FUNCTION__, "Cannot get bytecode from offset range [%d, %d]", start_offs, end_offs);
if (start_offs == 0 && end_offs == 0) {
for (int i = start_offs; i < elements(bc_seg); i++) {
int val = bc_seg[i];
bc[i - start_offs] = val;
}
} else if (start_offs != end_offs) {
for (int i = start_offs; i < elements(bc_seg) && i < end_offs; i++) {
int val = bc_seg[i];
bc[i - start_offs] = val;
}
}
return bc;
}
function __get_pf_segment(var pf, string type)
{
var dir = pf.get_directory();
for (string name in dir) {
var seg = dir[name];
if (typeof(seg) == type)
return seg;
}
return null;
}
function get_constants(var const_seg)
{
var c = new Rosella.Reflect.Constants();
int size = const_seg.pmc_count();
var p = c.pmcs;
for (int i = 0; i < size; i++) {
var pc = var(const_seg[i]);
//Rosella.IO.sayf("CONST_PMC(%d): %s", i, typeof(pc));
p[i] = pc;
}
size = const_seg.str_count();
var s = c.strings;
for (int i = 0; i < size; i++) {
string sc = string(const_seg[i]);
//Rosella.IO.sayf("CONST_STR(%d): '%s'", i, sc);
s[i] = sc;
}
size = const_seg.num_count();
var n = c.nums;
for (int i = 0; i < size; i++)
n[i] = float(const_seg[i]);
return c;
}
function __decode_op(var const_seg, var opmap, var oplibs, var bc, int i)
{
var op = opmap[bc[i]];
string name = op.family_name();
int nargs = elements(op);
int j = 1;
var args = [];
switch (name) {
case 'set_args':
case 'get_results':
case 'get_params':
case 'set_returns':
int sig_idx = bc[i + 1];
var arg_types = const_seg.pmcs[sig_idx];
args[0] = new Rosella.Reflect.OpArg.PMCConst(const_seg, sig_idx);
int narg_types = elements(arg_types);
for (j = 0; j < narg_types; ++j ) {
var arg = self.__decode_arg(const_seg, int(arg_types[j]), int(bc[i + j + 2]), i + j + 2);
args[j + 1] = arg;
}
j += 2;
break;
default:
for (j = 0; j < nargs; j++) {
var arg = self.__decode_arg(const_seg, int(op[j]), int(bc[i + j + 1]), i + j + 1);
args[j] = arg;
}
j += 1;
break;
}
var ins = new Rosella.Reflect.Instruction(i, op, args);
return ins, j;
}
function __decode_arg(var const_seg, int type, int arg, int pc)
{
int cons = type & TYPE_CONST;
int keyd = type & TYPE_KEYED;
int named = type & TYPE_NAME;
int is_optional = type & TYPE_OPTIONAL;
int is_opt_flag = type & TYPE_OPT_FLAG;
type = type & TYPE_MASK;
if (cons) {
switch (type) {
case TYPE_INT:
return new Rosella.Reflect.OpArg.IntegerConst(arg);
case TYPE_STR:
return new Rosella.Reflect.OpArg.StringConst(const_seg, arg);
case TYPE_PMC:
return new Rosella.Reflect.OpArg.PMCConst(const_seg, arg);
case TYPE_NUM:
return new Rosella.Reflect.OpArg.NumberConst(const_seg, arg);
default:
Rosella.Error.invalid(__FUNCTION__, "Unknown argument type %d at PC %d", type, pc);
}
} else {
switch (type) {
case TYPE_INT:
return new Rosella.Reflect.OpArg.IntegerReg(arg);
case TYPE_STR:
return new Rosella.Reflect.OpArg.StringReg(arg);
case TYPE_PMC:
return new Rosella.Reflect.OpArg.PMCReg(arg);
case TYPE_NUM:
return new Rosella.Reflect.OpArg.StringReg(arg);
default:
Rosella.Error.invalid(__FUNCTION__, "Unknow argument type %d at PC %d", type, pc);
}
}
Rosella.Error.invalid("SOMETHING BAD HAPPENED %d %d %d", type, arg, pc);
return null;
}
}
// TODO: Do we need this or can we access from the const_seg directly?
class Rosella.Reflect.Constants
{
var pmcs;
var strings;
var nums;
function Constants()
{
self.pmcs = [];
string strings[] = [];
self.strings = [];
float floats[] = [];
self.nums = floats;
}
}
Jump to Line
Something went wrong with that request. Please try again.