def process(self, dst, originalNode, code, map, selfarg, args, returnargs): self.localMap = {} self.dst = dst self.originalNode = originalNode self.contextRemap = map self.returnargs = returnargs outp = [] p = code.codeparameters # Do argument transfer if isinstance(p.selfparam, ast.Local): outp.append(ast.Assign(selfarg, [self(p.selfparam)])) for arg, param in zip(args, p.params): if isinstance(param, ast.Local): outp.append(ast.Assign(arg, [self(param)])) assert not isinstance(p.vparam, ast.Local), p.vparam #assert len(args) == len(p.params), "TODO: default arguments." outp.append(self(code.ast)) return outp
def visitAssign(self, node): assert self.locals if any([len(self.localuses[lcl]) > 0 for lcl in node.lcls]): expr = self(node.expr) assert self.locals, node.expr if isinstance(node.expr, ast.Local): # Assign local to local. Nullop for SSA. assert len(node.lcls) == 1 expr = self.reach(expr) self.locals.redefineLocal(node.lcls[0], expr) # Create a merge for exception handling. if self.hasExceptionHandling: el = self.exceptLocal(node.lcls[0]) easgn = ast.Assign(expr, el) easgn.markMerge() return easgn else: return None else: renames = [self.locals.writeLocal(lcl) for lcl in node.lcls] for rename in renames: self.defns[rename] = expr asgn = ast.Assign(expr, renames) if self.hasExceptionHandling: # Create a merge for exception handling. output = [asgn] for lcl, rename in zip(node.lcls, renames): el = self.exceptLocal(lcl) easgn = ast.Assign(rename, el) easgn.markMerge() output.append(easgn) asgn = ast.Suite(output) return asgn elif not node.expr.isPure(): return ast.Discard(self(node.expr)) else: return None
def visitUnpackSequence(self, node): # HACK oh so ugly... does not resemble what actually happens. if True: dc = self.directCall( node, self.exports['interpreter_unpack%d' % len(node.targets)], None, [self(node.expr)]) return ast.Assign(dc, node.targets) else: calls = [] for i, arg in enumerate(node.targets): obj = self.extractor.getObject(i) call = self.directCall( None, self.exports['interpreter_getitem'], None, [self(node.expr), self(ast.Existing(obj))]) calls.append(ast.Assign(call, [arg])) return calls
def visitAssign(self, node): expr = self(node.expr) if isinstance(expr, (ast.Local, ast.Existing)): if len(node.lcls) == 1: # Reach self.currentFrame[node.lcls[0]] = expr return None lcls = [self.clone(lcl, self.currentFrame) for lcl in node.lcls] return ast.Assign(expr, lcls)
def visitReturn(self, node): if self.returnargs is not None: # Inlined into assignment assert len(self.returnargs) == len(node.exprs) return [ ast.Assign(self(src), [dst]) for src, dst in zip(node.exprs, self.returnargs) ] else: # Inlined into discard return []
def methodCallToTypeSwitch(self, node, arg, pos, targets): # TODO if mutable types are allowed, we should be looking at the LowLevel type slot? # TODO localy rebuild read/modify/allocate information using filtered invokes. # TODO should the return value be SSAed? This might interfere with nessled type switches. # If so, retarget the return value and fix up return types groups = self.groupTypes(node, arg, pos) if groups is None or len(groups) <= 1: return None # Don't create trivial type switches cases = [] for group in groups: # Create a filtered version of the argument. name = arg.name if isinstance(arg, ast.Local) else None expr = ast.Local(name) expr.annotation = self.filterReferenceAnnotationByType( arg.annotation, group) # Create the new op opannotation = node.annotation # Kill contexts where the filtered expression has no references. # (In these contexts, the new op will never be evaluated.) mask = self.makeRemapMask(expr.annotation) if -1 in mask: opannotation = opannotation.contextSubset(mask) # Filter out invocations that don't have the right type for the given parameter. opannotation = self.filterOpAnnotationByType( opannotation, group, pos) # Rewrite the op to use expr instead of the original arg. newop = rewrite.rewriteTerm(node, {arg: expr}) assert newop is not node newop.annotation = opannotation # Try to reduce it to a direct call newop = self(newop) # Create the suite for this case stmts = [] if targets is None: stmts.append(ast.Discard(newop)) else: # HACK should SSA it? stmts.append(ast.Assign(newop, list(targets))) suite = ast.Suite(stmts) case = ast.TypeSwitchCase([self.existingFromObj(t) for t in group], expr, suite) cases.append(case) ts = ast.TypeSwitch(arg, cases) return ts
def visitUnpackSequence(self, node): expr = self(node.expr) targets = [self.locals.writeLocal(target) for target in node.targets] out = node.reconstruct(expr, targets) if self.hasExceptionHandling: out = ast.Suite([out]) for oldtgt, newtgt in zip(node.targets, targets): asgn = ast.Assign(newtgt, self.exceptLocal(oldtgt)) asgn.markMerge() out.append(asgn) return out
def visitAssign(self, node): expr = self(node.expr) assert not isinstance(expr, ast.Store), "Must discard stores." # A little strange, but it works because there will only be one target in the cases we care about. for lcl in node.lcls: self.defn[lcl] = expr if expr not in self.specialGlobals: if node.expr == expr: return node else: return ast.Assign(expr, node.lcls) else: return ()
def generateTypeLoad(self, expr, fieldName, refs): pt = refs[0].xtype.obj.pythonType() for ref in refs[1:]: assert ref.xtype.obj.pythonType is pt, "Temporary Limitation" ex = self.generateExisting(self.compiler.extractor.getObject(pt)) name = common.nameForField(self.compiler, fieldName) lcl = ast.Local(name) lcl.annotation = ex.annotation self.statements.append(ast.Assign(ex, [lcl])) return lcl
def generateReplacements(self, signatures): self.newName = {} self.replace = {} for sig, loads in signatures.iteritems(): if len(loads) > 1: dom = self.dominatorSubtree(loads) for op, dominator in dom.iteritems(): if op is not dominator: assert not isinstance(op, ast.Store) assert len(op.lcls) == 1 src = self.getReplacementSource(dominator) self.replace[op] = ast.Assign(src, [op.lcls[0]]) self.eliminated += 1 return self.replace
def generateRewrites(self, code, name, group): lcl, ioname = self.remap[name] for field in group: self.fields[field] = ioname isLoaded = False for load in self.loadLUT.get((code, name), ()): self.rewrites[load] = lcl isLoaded = True storeCount = 0 for store in self.storeLUT.get((code, name), ()): self.rewrites[store] = ast.Assign(store.value, [lcl]) storeCount += 1 if storeCount > 1 or storeCount == 1 and isLoaded: self.ssaBroken = True
def getReplacementSource(self, dominator): if dominator not in self.newName: if isinstance(dominator, ast.Store): old = dominator.value else: assert len(dominator.lcls) == 1 old = dominator.lcls[0] if isinstance(old, ast.Existing): src = ast.Existing(old.object) else: src = ast.Local(old.name) self.replace[dominator] = [dominator, ast.Assign(old, [src])] src.annotation = old.annotation self.newName[dominator] = src else: src = self.newName[dominator] return src
def visitMerge(self, node): if node.phi: for i, (prev, prevName) in enumerate(node.iterprev()): transfer = [(phi.arguments[i], phi.target) for phi in node.phi if phi.arguments[i] is not None] if not transfer: continue # HACK can't handle pushing assignments up into exceptions? assert prevName in ('normal', 'true', 'false', 'entry'), prevName transfer, temps = serializeMerges(transfer, self.createTemp) stmts = [ast.Assign(src, [dst]) for src, dst in transfer] suite = cfg.Suite(prev.region) suite.ops = stmts prev.insertAtExit(prevName, suite, 'normal') node.phi = []
def generateLoad(self, expr, fieldName, refs): if fieldName.type == 'LowLevel' and fieldName.name.pyobj == 'type': # This a kludge until IPA works. return self.generateTypeLoad(expr, fieldName, refs) fields = [] for ref in refs: fields.append(ref.knownField(fieldName)) lcl = common.localForFieldSlot(self.compiler, self.code, fields[0], fields) exname = self.generateExisting(fieldName.name) load = ast.Load(expr, fieldName.type, exname) empty = common.emptyAnnotation(self.code) load.rewriteAnnotation(allocates=empty, modifies=empty, reads=common.annotationFromValues(self.code, fields)) self.statements.append(ast.Assign(load, [lcl])) return lcl
def enterExcept(self, r): self.exceptLevel += 1 rn = {} if self.exceptLevel > 1: rn.update(self.exceptRename[-1]) merges = ast.Suite([]) for lcl in r: if not lcl in rn: old = self(lcl) merge = lcl.clone() rn[lcl] = merge asgn = ast.Assign(old, merge) asgn.markMerge() merges.append(asgn) self.exceptRename.append(rn) return merges
switches.append((cond, ast.Suite(body))) current = ast.Suite([ast.Assert(ast.Existing(compiler.extractor.getObject(False)), None)]) for cond, suite in reversed(switches): current = ast.Switch(ast.Condition(ast.Suite([]), cond), suite, ast.Suite([current])) return [current] uniformGetTemplate = ast.Assign( ast.Call( ast.GetAttr( ast.GetAttr( existingSymbol('cls'), existingSymbol('attr') ), existingConstant('__get__') ), [Symbol('root')], [], None, None ), [Symbol('target')] ) def classAttrFromField(compiler, field): assert field.type == 'Attribute', field name = field.name.pyobj descriptor = compiler.slots.reverse[name] cls = descriptor.__objclass__ attr = descriptor.__name__
def visitAssign(self, node): # Modified bottom up # Avoids folding assignment targets node = ast.Assign(self(node.expr), node.lcls) node = self.strategy(node) return node