def gen_type_sk(sk_dir, bases): buf = cStringIO.StringIO() buf.write("package type;\n") buf.write(_const) cols, decls = util.partition(lambda c: util.is_collection(c.name), bases) decls = filter(lambda c: not util.is_array(c.name), decls) itfs, clss = util.partition(op.attrgetter("is_itf"), decls) logging.debug("# interface(s): {}".format(len(itfs))) logging.debug("# class(es): {}".format(len(clss))) # convert interfaces first, then usual classes buf.write('\n'.join(util.ffilter(map(to_struct, itfs)))) buf.write('\n'.join(util.ffilter(map(to_struct, clss)))) # convert collections at last logging.debug("# collection(s): {}".format(len(cols))) buf.write('\n'.join(map(col_to_struct, cols))) # argument number of methods arg_num = map(lambda mtd: len(mtd.params), methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.argNum, ", ".join(map(str, arg_num)))) # argument types of methods def get_args_typ(mtd): def get_arg_typ(param): return str(class_lookup(param[0]).id) return '{' + ", ".join(map(get_arg_typ, mtd.params)) + '}' args_typ = map(get_args_typ, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id, int idx) {{ return _{0}[id][idx]; }} """.format(C.typ.argType, ", ".join(args_typ))) # return type of methods def get_ret_typ(mtd): cls = class_lookup(mtd.typ) if cls: return cls.id else: return -1 ret_typ = map(get_ret_typ, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.retType, ", ".join(map(str, ret_typ)))) # belonging class of methods belongs = map(lambda mtd: mtd.clazz.id, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.belongsTo, ", ".join(map(str, belongs)))) subcls = \ map(lambda cls_i: '{' + ", ".join( \ map(lambda cls_j: str(cls_i <= cls_j).lower(), classes()) \ ) + '}', classes()) buf.write(""" #define _{0} {{ {1} }} bit {0}(int i, int j) {{ return _{0}[i][j]; }} """.format(C.typ.subcls, ", ".join(subcls))) ## sub type relations #subcls = [] #for cls_i in classes(): # row = [] # for cls_j in classes(): # row.append(int(cls_i <= cls_j)) # subcls.append(row) ## sub type relations in yale format #_, IA, JA = util.yale_format(subcls) #li, lj = len(IA), len(JA) #si = ", ".join(map(str, IA)) #sj = ", ".join(map(str, JA)) #buf.write(""" # #define _iA {{ {si} }} # #define _jA {{ {sj} }} # int iA(int i) {{ # return _iA[i]; # }} # int jA(int j) {{ # return _jA[j]; # }} # bit subcls(int i, int j) {{ # int col_i = iA(i); # int col_j = iA(i+1); # for (int col = col_i; col < col_j; col++) {{ # if (j == jA(col)) return true; # }} # return false; # }} #""".format(**locals())) with open(os.path.join(sk_dir, "type.sk"), 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()
def gen_type_sk(sk_dir, bases): buf = cStringIO.StringIO() buf.write("package type;\n") buf.write(_const) buf.write(trans_lib()) buf.write('\n') cols, decls = util.partition(lambda c: util.is_collection(c.name), bases) decls = filter(lambda c: not util.is_array(c.name), decls) itfs, clss = util.partition(op.attrgetter("is_itf"), decls) logging.debug("# interface(s): {}".format(len(itfs))) logging.debug("# class(es): {}".format(len(clss))) # convert interfaces first, then usual classes buf.write('\n'.join(util.ffilter(map(to_struct, itfs)))) buf.write('\n'.join(util.ffilter(map(to_struct, clss)))) # convert collections at last logging.debug("# collection(s): {}".format(len(cols))) buf.write('\n'.join(map(col_to_struct, cols))) # argument number of methods arg_num = map(lambda mtd: len(mtd.params), methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.argNum, ", ".join(map(str, arg_num)))) # argument types of methods def get_args_typ(mtd): def get_arg_typ(param): return str(class_lookup(param[0]).id) return '{' + ", ".join(map(get_arg_typ, mtd.params)) + '}' args_typ = map(get_args_typ, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id, int idx) {{ return _{0}[id][idx]; }} """.format(C.typ.argType, ", ".join(args_typ))) # return type of methods def get_ret_typ(mtd): cls = class_lookup(mtd.typ) if cls: return cls.id else: return -1 ret_typ = map(get_ret_typ, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.retType, ", ".join(map(str, ret_typ)))) # belonging class of methods belongs = map(lambda mtd: mtd.clazz.id, methods()) buf.write(""" #define _{0} {{ {1} }} int {0}(int id) {{ return _{0}[id]; }} """.format(C.typ.belongsTo, ", ".join(map(str, belongs)))) subcls = \ map(lambda cls_i: '{' + ", ".join( \ map(lambda cls_j: str(cls_i <= cls_j).lower(), classes()) \ ) + '}', classes()) buf.write(""" #define _{0} {{ {1} }} bit {0}(int i, int j) {{ return _{0}[i][j]; }} """.format(C.typ.subcls, ", ".join(subcls))) ## sub type relations #subcls = [] #for cls_i in classes(): # row = [] # for cls_j in classes(): # row.append(int(cls_i <= cls_j)) # subcls.append(row) ## sub type relations in yale format #_, IA, JA = util.yale_format(subcls) #li, lj = len(IA), len(JA) #si = ", ".join(map(str, IA)) #sj = ", ".join(map(str, JA)) #buf.write(""" # #define _iA {{ {si} }} # #define _jA {{ {sj} }} # int iA(int i) {{ # return _iA[i]; # }} # int jA(int j) {{ # return _jA[j]; # }} # bit subcls(int i, int j) {{ # int col_i = iA(i); # int col_j = iA(i+1); # for (int col = col_i; col < col_j; col++) {{ # if (j == jA(col)) return true; # }} # return false; # }} #""".format(**locals())) with open(os.path.join(sk_dir, "type.sk"), 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()
def to_sk(pgr, sk_dir): # clean up result directory if os.path.isdir(sk_dir): util.clean_dir(sk_dir) else: os.makedirs(sk_dir) # reset global variables so that we can run this encoding phase per demo reset() # update global constants # TODO: conservative analysis of possible length of collections # TODO: counting .add() calls or something? magic_S = 7 global _const _const = u""" int S = {}; // length of arrays for Java collections """.format(magic_S) # type.sk logging.info("building class hierarchy") pgr.consist() # merge all classes and interfaces, except for primitive types clss, _ = util.partition(lambda c: util.is_class_name(c.name), classes()) bases = rm_subs(clss) gen_type_sk(sk_dir, bases) # cls.sk cls_sks = [] for cls in pgr.classes: # skip the collections, which will be encoded at type.sk if repr(cls).split('_')[0] in C.collections: continue cls_sk = gen_cls_sk(sk_dir, cls) if cls_sk: cls_sks.append(cls_sk) # log.sk gen_log_sk(sk_dir, pgr) # main.sk that imports all the other sketch files buf = cStringIO.StringIO() # --bnd-cbits: the number of bits for integer holes bits = max(5, int(math.ceil(math.log(len(methods()), 2)))) buf.write("pragma options \"--bnd-cbits {}\";\n".format(bits)) # --bnd-unroll-amnt: the unroll amount for loops unroll_amnt = None # use a default value if not set unroll_amnt = magic_S # TODO: other criteria? if unroll_amnt: buf.write("pragma options \"--bnd-unroll-amnt {}\";\n".format(unroll_amnt)) # --bnd-inline-amnt: bounds inlining to n levels of recursion inline_amnt = None # use a default value if not set # setting it 1 means there is no recursion if inline_amnt: buf.write("pragma options \"--bnd-inline-amnt {}\";\n".format(inline_amnt)) buf.write("pragma options \"--bnd-bound-mode CALLSITE\";\n") sks = ["log.sk", "type.sk"] + cls_sks for sk in sks: buf.write("include \"{}\";\n".format(sk)) # TODO: make harness (if not exists) with open(os.path.join(sk_dir, "main.sk"), 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()
def to_sk(cmd, smpls, tmpl, sk_dir): # clean up result directory if os.path.isdir(sk_dir): util.clean_dir(sk_dir) else: os.makedirs(sk_dir) # reset global variables so that we can run this encoding phase per demo reset() # update global constants def logged(mtd): if mtd.is_init: return False clss = util.flatten_classes([mtd.clazz], "subs") return sample.mtd_appears(smpls, clss, mtd.name) mtds = filter(logged, methods()) if mtds: n_params = 2 + max(map(len, map(op.attrgetter("params"), mtds))) else: # no meaningful logs in the sample? n_params = 2 n_evts = sample.max_evts(smpls) if cmd == "android": n_views = sample.max_views(smpls) magic_S = max(3, n_evts + 1, n_views) else: magic_S = max(5, n_evts + 1) # at least 5, just in case n_ios = sample.max_IOs(smpls) global _const _const = u""" int P = {}; // length of parameters (0: (>|<)mid, 1: receiver, 2...) int S = {}; // length of arrays for Java collections int N = {}; // length of logs """.format(n_params, magic_S, n_ios) # type.sk logging.info("building class hierarchy") tmpl.consist() # merge all classes and interfaces, except for primitive types clss, _ = util.partition(lambda c: util.is_class_name(c.name), classes()) bases = rm_subs(clss) gen_type_sk(sk_dir, bases) # cls.sk cls_sks = [] for cls in tmpl.classes: # skip the collections, which will be encoded at type.sk if repr(cls).split('_')[0] in C.collections: continue cls_sk = gen_cls_sk(sk_dir, smpls, cls) if cls_sk: cls_sks.append(cls_sk) # sample_x.sk smpl_sks = [] for smpl in smpls: smpl_sk = "sample_" + smpl.name + ".sk" smpl_sks.append(smpl_sk) sk_path = os.path.join(sk_dir, smpl_sk) gen_smpl_sk(sk_path, smpl, tmpl, tmpl.harness(smpl.name)) # log.sk gen_log_sk(sk_dir, tmpl) # sample.sk that imports all the other sketch files buf = cStringIO.StringIO() # deprecated as we use regex generator for class/method roles ## --bnd-cbits: the number of bits for integer holes #bits = max(5, int(math.ceil(math.log(len(methods()), 2)))) #buf.write("pragma options \"--bnd-cbits {}\";\n".format(bits)) # --bnd-unroll-amnt: the unroll amount for loops unroll_amnt = max(n_params, magic_S) buf.write("pragma options \"--bnd-unroll-amnt {}\";\n".format(unroll_amnt)) # --bnd-inline-amnt: bounds inlining to n levels of recursion inline_amnt = None # use a default value if not set if cmd == "android": #inline_amnt = 2 # depth of View hierarchy (at findViewByTraversal) inline_amnt = 1 # no recursion for flat Views elif cmd == "gui": # setting it 1 means there is no recursion inline_amnt = 1 if inline_amnt: buf.write("pragma options \"--bnd-inline-amnt {}\";\n".format(inline_amnt)) buf.write("pragma options \"--bnd-bound-mode CALLSITE\";\n") sks = ["log.sk", "type.sk"] + cls_sks + smpl_sks for sk in sks: buf.write("include \"{}\";\n".format(sk)) with open(os.path.join(sk_dir, "sample.sk"), 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()