def remove_cls(smpls, tmpl): cnames = sample.decls(smpls).keys() + tmpl.events.keys() + get_artifacts() def marker(cname): cls = class_lookup(cname) if not cls: return if is_marked(cls): return mark(cls) if cls.sup: marker(cls.sup) for itf in cls.itfs: marker(itf) for fld in cls.flds: marker(fld.typ) for mtd in cls.mtds: marker(mtd.typ) for ty, _ in mtd.params: marker(ty) # primitive types marker(C.J.OBJ) # interfaces with constants clss = util.flatten_classes(tmpl.classes, "inners") for itf in ifilter(op.attrgetter("is_itf"), clss): if itf.flds: mark(itf) map(marker, cnames) marked = filter(lambda cls: is_marked(cls), tmpl.classes) diff = list(set(tmpl.classes) - set(marked)) if diff: logging.debug("unnecessary class(es): {}: {}".format(len(diff), diff)) tmpl.classes = marked map(lambda cls: unmark(cls), tmpl.classes)
def reduce_anno(smpls, tmpl): for cls in util.flatten_classes(tmpl.classes, "inners"): for fld in cls.flds: reduce_anno_fld(smpls, tmpl, cls, fld) for mtd in cls.mtds: reduce_anno_mtd(smpls, tmpl, cls, mtd) red_s = map(partial(reduce_anno_s, tmpl, cls, mtd), mtd.body) mtd.body = util.flatten(red_s)
def to_func(mtd): buf = cStringIO.StringIO() if C.mod.GN in mtd.mods: buf.write(C.mod.GN + ' ') elif C.mod.HN in mtd.mods: buf.write(C.mod.HN + ' ') ret_ty = trans_ty(mtd.typ) cname = unicode(repr(mtd.clazz)) mname = mtd.name arg_typs = mtd.param_typs buf.write(ret_ty + ' ' + trans_mname(cname, mname, arg_typs) + '(') @takes(tuple_of(unicode)) @returns(unicode) def trans_param( (ty, nm) ): return ' '.join([trans_ty(ty), nm]) # for instance methods, add "this" pointer into parameters if mtd.is_static: params = mtd.params[:] else: self_ty = trans_ty(unicode(repr(mtd.clazz))) params = [ (self_ty, C.SK.self) ] + mtd.params[:] if len(params) > 0: buf.write(", ".join(map(trans_param, params))) buf.write(") {\n") clss = util.flatten_classes([mtd.clazz], "subs") mid = unicode(repr(mtd)) m_ent = mid + "_ent()" m_ext = mid + "_ext()" is_void = C.J.v == mtd.typ if mtd.body: buf.write('\n'.join(map(partial(trans_s, mtd), mtd.body))) if mtd.is_init: buf.write("\nreturn {};".format(C.SK.self)) buf.write("\n}\n") return buf.getvalue()
def collect_decls(cls, attr): clss = util.flatten_classes([cls], "inners") declss = map(op.attrgetter(attr), clss) return util.flatten(declss)
def to_struct(cls): # make mappings from static fields to corresponding accessors def gen_s_flds_accessors(cls): s_flds = filter(op.attrgetter("is_static"), cls.flds) global _s_flds for fld in ifilterfalse(op.attrgetter("is_private"), s_flds): cname = fld.clazz.name fid = '.'.join([cname, fld.name]) fname = unicode(repr(fld)) logging.debug("{} => {}".format(fid, fname)) _s_flds[fid] = fname cname = util.sanitize_ty(cls.name) global _ty # if this is an interface, merge this into another family of classes # as long as classes that implement this interface are in the same family if cls.is_itf: # interface may have static constants gen_s_flds_accessors(cls) subss = util.flatten_classes(cls.subs, "subs") bases = util.rm_dup(map(lambda sub: find_base(sub), subss)) # filter out interfaces that extend other interfaces, e.g., Action base_clss, _ = util.partition(op.attrgetter("is_class"), bases) if not base_clss: logging.debug("no implementer of {}".format(cname)) elif len(base_clss) > 1: logging.debug("ambiguous inheritance of {}: {}".format(cname, base_clss)) else: # len(base_clss) == 1 base = base_clss[0] base_name = base.name logging.debug("{} => {}".format(cname, base_name)) _ty[cname] = base_name if cls.is_inner: # to handle inner interface w/ outer class name logging.debug("{} => {}".format(repr(cls), base_name)) _ty[unicode(repr(cls))] = base_name return '' # if this is the base class having subclasses, # make a virtual struct first if cls.subs: cls = to_v_struct(cls) cname = cls.name # cls can be modified above, thus generate static fields accessors here gen_s_flds_accessors(cls) # for unique class numbering, add an identity mapping if cname not in _ty: _ty[cname] = cname buf = cStringIO.StringIO() buf.write("struct " + cname + " {\n int hash;\n") # to avoid static fields, which will be bound to a class-representing package _, i_flds = util.partition(op.attrgetter("is_static"), cls.flds) buf.write('\n'.join(map(trans_fld, i_flds))) if len(i_flds) > 0: buf.write('\n') buf.write("}\n") return buf.getvalue()
def to_func(smpls, mtd): buf = cStringIO.StringIO() if C.mod.GN in mtd.mods: buf.write(C.mod.GN + ' ') elif C.mod.HN in mtd.mods: buf.write(C.mod.HN + ' ') ret_ty = trans_ty(mtd.typ) cname = unicode(repr(mtd.clazz)) mname = mtd.name arg_typs = mtd.param_typs buf.write(ret_ty + ' ' + trans_mname(cname, mname, arg_typs) + '(') @takes(tuple_of(unicode)) @returns(unicode) def trans_param( (ty, nm) ): return ' '.join([trans_ty(ty), nm]) # for instance methods, add "this" pointer into parameters if mtd.is_static: params = mtd.params[:] else: self_ty = trans_ty(unicode(repr(mtd.clazz))) params = [ (self_ty, C.SK.self) ] + mtd.params[:] # add "logging" flag into parameters # to check log conformity only if invocations cross the boundary if not mtd.is_init and not mtd.is_clinit: params.append( (C.SK.z, u"logging") ) if len(params) > 0: buf.write(", ".join(map(trans_param, params))) buf.write(") {\n") # once function signature is dumped out, remove "logging" flag if not mtd.is_init and not mtd.is_clinit: params.pop() clss = util.flatten_classes([mtd.clazz], "subs") logged = (not mtd.is_init) and sample.mtd_appears(smpls, clss, mtd.name) mid = unicode(repr(mtd)) m_ent = mid + "_ent()" m_ext = mid + "_ext()" if logged: global _mids _mids.add(mid) if logged: # logging method entry (>) _log_params = map(log_param, params) _retrievals, _hashes = util.split([(u'', m_ent)] + _log_params) ent_retrievals = util.ffilter(_retrievals) ent_hashes = util.ffilter(_hashes) buf.write("""{} int[P] __params = {{ {} }}; if (logging) check_log@log(__params); """.format(u''.join(ent_retrievals), u", ".join(ent_hashes))) is_void = C.J.v == mtd.typ if mtd.body: if not is_void and not mtd.is_init: bodies = mtd.body[:-1] # exclude the last 'return' statement else: bodies = mtd.body buf.write('\n'.join(map(partial(trans_s, mtd), bodies))) if logged: # logging method exit (<) _log_params = [] if mtd.body and not is_void and not mtd.is_init: ret_v = mtd.body[-1].e ret_u = unicode(trans_e(mtd, ret_v)) # retrieve the return value to a temporary variable buf.write(u""" {} __ret = {}; """.format(ret_ty, ret_u)) # then, try to obtain a hash from that temporary variable _log_params.append(log_param( (ret_ty, u"__ret") )) _retrievals, _hashes = util.split([(u'', m_ext)] + _log_params) ext_retrievals = util.ffilter(_retrievals) ext_hashes = util.ffilter(_hashes) buf.write("""{} __params = {{ {} }}; if (logging) check_log@log(__params); """.format(u''.join(ext_retrievals), u", ".join(ext_hashes))) if mtd.body and not is_void and not mtd.is_init: buf.write(os.linesep) if logged: # return the return value stored at the temporary variable buf.write("return __ret;") else: buf.write(trans_s(mtd, mtd.body[-1])) if mtd.is_init: evt_srcs = map(util.sanitize_ty, sample.evt_sources(smpls)) cname = unicode(repr(mtd.clazz)) if cname in evt_srcs: global _inits _inits.add(cname) buf.write("\nreturn {};".format(C.SK.self)) buf.write("\n}\n") return buf.getvalue()
def to_struct(cls): # make mappings from static fields to corresponding accessors def gen_s_flds_accessors(cls): s_flds = filter(op.attrgetter("is_static"), cls.flds) global _s_flds for fld in ifilterfalse(op.attrgetter("is_private"), s_flds): cname = fld.clazz.name fid = '.'.join([cname, fld.name]) fname = unicode(repr(fld)) logging.debug("{} => {}".format(fid, fname)) _s_flds[fid] = fname cname = util.sanitize_ty(cls.name) global _ty # if this is an interface, merge this into another family of classes # as long as classes that implement this interface are in the same family if cls.is_itf: # interface may have static constants gen_s_flds_accessors(cls) subss = util.flatten_classes(cls.subs, "subs") bases = util.rm_dup(map(lambda sub: find_base(sub), subss)) # filter out interfaces that extend other interfaces, e.g., Action base_clss, _ = util.partition(op.attrgetter("is_class"), bases) if not base_clss: logging.debug("no implementer of {}".format(cname)) elif len(base_clss) > 1: logging.debug("ambiguous inheritance of {}: {}".format(cname, base_clss)) else: # len(base_clss) == 1 base = base_clss[0] base_name = base.name logging.debug("{} => {}".format(cname, base_name)) _ty[cname] = base_name if cls.is_inner: # to handle inner interface w/ outer class name logging.debug("{} => {}".format(repr(cls), base_name)) _ty[unicode(repr(cls))] = base_name return '' # if this is the base class having subclasses, # make a virtual struct first if cls.subs and not cls.is_aux: cls = to_v_struct(cls) cname = cls.name # cls can be modified above, thus generate static fields accessors here gen_s_flds_accessors(cls) # for unique class numbering, add an identity mapping if cname not in _ty: _ty[cname] = cname buf = cStringIO.StringIO() buf.write("struct " + cname + " {\n int hash;\n") # to avoid static fields, which will be bound to a class-representing package _, i_flds = util.partition(op.attrgetter("is_static"), cls.flds) buf.write('\n'.join(map(trans_fld, i_flds))) if len(i_flds) > 0: buf.write('\n') buf.write("}\n") return buf.getvalue()
def logged(mtd): if mtd.is_init: return False clss = util.flatten_classes([mtd.clazz], "subs") return sample.mtd_appears(smpls, clss, mtd.name)
def gen_smpl_sk(sk_path, smpl, tmpl, main): buf = cStringIO.StringIO() buf.write("package {};\n".format(smpl.name)) buf.write(_const) buf.write("harness void {} () {{\n".format(smpl.name)) # insert call-return sequences buf.write(""" clear_log@log(); int[P] log = { 0 }; """) global _mids obj_cnt = 0 objs = { C.J.N: 0, C.J.FALSE: 0, C.J.TRUE: 1, } # { @Obj...aaa : 2, ... } for i in xrange(10): objs[str(i)] = i obj_cnt = obj_cnt + 1 call_stack = [] for io in smpl.IOs: # ignore <init> if io.is_init: continue elif isinstance(io, sample.CallExt): # ignore method exits whose counterparts are missed if not call_stack: continue mid = call_stack.pop() # ignore methods that are not declared in the template if not mid: continue else: # sample.CallEnt mid = None # TODO: retrieve arg types mtd = None # find_mtd_by_sig(io.cls, io.mtd, ...) if mtd: # found the method that matches the argument types mid = repr(mtd) if mid not in _mids: continue else: # try other possible methods mtds = find_mtds_by_name(io.cls, io.mtd) argn = len(io.vals) min_gap = argn for mtd in mtds: _gap = abs((argn - (0 if mtd.is_static else 1)) - len(mtd.params)) if _gap <= min_gap: # eq is needed for zero parameter min_gap = _gap mid = repr(mtd) if mid not in _mids: mid = None call_stack.append(mid) # ignore methods that are not declared in the template if not mid: continue if isinstance(io, sample.CallEnt): mid = mid + "_ent()" else: # sample.CallExt mid = mid + "_ext()" vals = [] for val in io.vals: kind = sample.kind(val) if type(kind) is type: val = str(val) # every occurrence of constant string will be uniquely allocated, # hence different hash => assign unique obj_cnt # also, primitive value doesn't have hash, # so we can't compare via obj array; just assign unique obj_cnt ## 1) primitive, including string # 2) this object never occurs #if type(kind) is type or val not in objs: if val not in objs: obj_cnt = obj_cnt + 1 objs[val] = obj_cnt vals.append(str(objs[val])) buf.write(""" log = (int[P]){{ {} }}; write_log@log(log); """.format(", ".join([mid] + vals))) buf.write(""" int len_log = get_log_cnt@log(); reset_log_cnt@log(); """) global max_objs max_objs = max(max_objs, obj_cnt) # invoke class initializers for cls in util.flatten_classes(tmpl.classes, "inners"): clinit = cls.mtd_by_sig(C.J.CLINIT) if not clinit: continue # to only call the base class's <clinit> if clinit.clazz != cls: continue buf.write(" {}();\n".format(trans_mname(unicode(repr(cls)), clinit.name))) # execute template's *main* cname = unicode(repr(main.clazz)) mname = main.name arg_typs = main.param_typs params = main.params + [ (C.J.z, u"logging") ] args = ", ".join(sig_match(params, [])) buf.write("\n {}({});\n".format(trans_mname(cname, mname, arg_typs), args)) buf.write("assert len_log == get_log_cnt@log();") buf.write("\n}\n") with open(sk_path, 'w') as f: f.write(buf.getvalue()) logging.info("encoding " + f.name) buf.close()