def inline_short_preamble(self, jump_args, args_no_virtuals, short, patchguardop, target_token, label_op): short_inputargs = short[0].getarglist() short_jump_args = short[-1].getarglist() sb = self.short_preamble_producer if sb is not None: assert isinstance(sb, ExtendedShortPreambleBuilder) if sb.target_token is target_token: # this means we're inlining the short preamble that's being # built. Make sure we modify the correct things in-place self.short_preamble_producer.setup(short_jump_args, short, label_op.getarglist()) # after this call, THE REST OF THIS FUNCTION WILL MODIFY ALL # THE LISTS PROVIDED, POTENTIALLY # We need to make a list of fresh new operations corresponding # to the short preamble operations. We could temporarily forward # the short operations to the fresh ones, but there are obscure # issues: send_extra_operation() below might occasionally invoke # use_box(), which assumes the short operations are not forwarded. # So we avoid such temporary forwarding and just use a dict here. assert len(short_inputargs) == len(jump_args) mapping = {} for i in range(len(jump_args)): mapping[short_inputargs[i]] = jump_args[i] # a fix-point loop, runs only once in almost all cases i = 1 while 1: self._check_no_forwarding([short_inputargs, short], False) while i < len(short) - 1: sop = short[i] arglist = self._map_args(mapping, sop.getarglist()) if sop.is_guard(): op = sop.copy_and_change( sop.getopnum(), arglist, descr=compile.ResumeAtPositionDescr()) assert isinstance(op, GuardResOp) op.rd_resume_position = patchguardop.rd_resume_position else: op = sop.copy_and_change(sop.getopnum(), arglist) mapping[sop] = op i += 1 self.optimizer.send_extra_operation(op) # force all of them except the virtuals for arg in (args_no_virtuals + self._map_args(mapping, short_jump_args)): self.optimizer.force_box(self.get_box_replacement(arg)) self.optimizer.flush() # done unless "short" has grown again if i == len(short) - 1: break return [ self.get_box_replacement(box) for box in self._map_args(mapping, short_jump_args) ]
def jump_to_existing_trace(self, jump_op, label_op, runtime_boxes, force_boxes=False): jitcelltoken = jump_op.getdescr() assert isinstance(jitcelltoken, JitCellToken) virtual_state = self.get_virtual_state(jump_op.getarglist()) args = [self.get_box_replacement(op) for op in jump_op.getarglist()] for target_token in jitcelltoken.target_tokens: target_virtual_state = target_token.virtual_state if target_virtual_state is None: continue try: extra_guards = target_virtual_state.generate_guards( virtual_state, args, runtime_boxes, self.optimizer, force_boxes=force_boxes) patchguardop = self.optimizer.patchguardop for guard in extra_guards.extra_guards: if isinstance(guard, GuardResOp): guard.rd_resume_position = patchguardop.rd_resume_position guard.setdescr(compile.ResumeAtPositionDescr()) self.send_extra_operation(guard) except VirtualStatesCantMatch: continue # When force_boxes == True, creating the virtual args can fail when # components of the virtual state alias. If this occurs, we must # recompute the virtual state as boxes will have been forced. try: args, virtuals = target_virtual_state.make_inputargs_and_virtuals( args, self.optimizer, force_boxes=force_boxes) except VirtualStatesCantMatch: assert force_boxes virtual_state = self.get_virtual_state(args) continue short_preamble = target_token.short_preamble try: extra = self.inline_short_preamble(args + virtuals, args, short_preamble, self.optimizer.patchguardop, target_token, label_op) except KeyError: # SHOULD NOT OCCUR BUT DOES: WHY?? issue #2185 self.optimizer.metainterp_sd.logger_ops.log_short_preamble( [], short_preamble, {}) raise self.send_extra_operation( jump_op.copy_and_change(rop.JUMP, args=args + extra, descr=target_token)) return None # explicit because the return can be non-None return virtual_state
def _inline_short_preamble(self, short_preamble, inliner, patchguardop, assumed_classes): i = 1 # XXX this is intentiontal :-(. short_preamble can change during the # loop in some cases while i < len(short_preamble): shop = short_preamble[i] newop = inliner.inline_op(shop) if newop.is_guard(): if not patchguardop: raise InvalidLoop("would like to have short preamble, but it has a guard and there's no guard_future_condition") assert isinstance(newop, GuardResOp) assert isinstance(patchguardop, GuardResOp) newop.rd_snapshot = patchguardop.rd_snapshot newop.rd_frame_info_list = patchguardop.rd_frame_info_list newop.setdescr(compile.ResumeAtPositionDescr()) self.optimizer.send_extra_operation(newop) if shop.result in assumed_classes: classbox = self.getvalue(newop.result).get_constant_class(self.optimizer.cpu) if not classbox or not classbox.same_constant(assumed_classes[shop.result]): raise InvalidLoop('The class of an opaque pointer before the jump ' + 'does not mach the class ' + 'it has at the start of the target loop') i += 1
def jump_to_already_compiled_trace(self, jumpop, patchguardop): jumpop = jumpop.clone() assert jumpop.getopnum() == rop.JUMP cell_token = jumpop.getdescr() assert isinstance(cell_token, JitCellToken) if not cell_token.target_tokens: return False if not self.inline_short_preamble: assert cell_token.target_tokens[0].virtual_state is None jumpop.setdescr(cell_token.target_tokens[0]) self.optimizer.send_extra_operation(jumpop) return True args = jumpop.getarglist() virtual_state = self.get_virtual_state(args) values = [self.getvalue(arg) for arg in jumpop.getarglist()] debug_start('jit-log-virtualstate') virtual_state.debug_print("Looking for ", metainterp_sd=self.optimizer.metainterp_sd) for target in cell_token.target_tokens: if not target.virtual_state: continue extra_guards = [] try: cpu = self.optimizer.cpu state = target.virtual_state.generate_guards(virtual_state, values, cpu) extra_guards = state.extra_guards if extra_guards: debugmsg = 'Guarded to match ' else: debugmsg = 'Matched ' except VirtualStatesCantMatch, e: debugmsg = 'Did not match:\n%s\n' % (e.msg, ) target.virtual_state.debug_print(debugmsg, e.state.bad, metainterp_sd=self.optimizer.metainterp_sd) continue assert patchguardop is not None or (extra_guards == [] and len(target.short_preamble) == 1) target.virtual_state.debug_print(debugmsg, {}) debug_stop('jit-log-virtualstate') args = target.virtual_state.make_inputargs(values, self.optimizer, keyboxes=True) short_inputargs = target.short_preamble[0].getarglist() inliner = Inliner(short_inputargs, args) for guard in extra_guards: if guard.is_guard(): assert isinstance(patchguardop, GuardResOp) assert isinstance(guard, GuardResOp) guard.rd_snapshot = patchguardop.rd_snapshot guard.rd_frame_info_list = patchguardop.rd_frame_info_list guard.setdescr(compile.ResumeAtPositionDescr()) self.optimizer.send_extra_operation(guard) try: # NB: the short_preamble ends with a jump self._inline_short_preamble(target.short_preamble, inliner, patchguardop, target.assumed_classes) except InvalidLoop: #debug_print("Inlining failed unexpectedly", # "jumping to preamble instead") assert cell_token.target_tokens[0].virtual_state is None jumpop.setdescr(cell_token.target_tokens[0]) self.optimizer.send_extra_operation(jumpop) return True