Beispiel #1
0
    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)
        ]
Beispiel #2
0
    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
Beispiel #3
0
 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
Beispiel #4
0
    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