def _store_map(self, instr): # TOS = k # TOS1 = v # TOS2 = m # TOS3 = m yield instructions.ROT_THREE().steal(instr) # TOS = v # TOS1 = m # TOS2 = k # TOS3 = m yield instructions.ROT_THREE() # TOS = m # TOS1 = k # TOS2 = v # TOS3 = m yield instructions.ROT_TWO() # TOS = k # TOS1 = m # TOS2 = v # TOS3 = m yield instructions.STORE_SUBSCR()
def visit_STORE_MAP(self, instr): # TOS = k # TOS1 = v # TOS2 = m # TOS3 = m yield instructions.ROT_THREE().steal(instr) # TOS = v # TOS1 = m # TOS2 = k # TOS3 = m yield instructions.ROT_THREE() # TOS = m # TOS1 = k # TOS2 = v # TOS3 = m yield instructions.ROT_TWO() # TOS = k # TOS1 = m # TOS2 = v # TOS3 = m yield instructions.STORE_SUBSCR()
def _binary_subscr(self, instr): yield instructions.LOAD_CONST(self._islicer).steal(instr) # TOS = self._islicer # TOS1 = k # TOS2 = m yield instructions.ROT_THREE() # TOS = k # TOS1 = m # TOS2 = self._islicer yield instructions.CALL_FUNCTION(2)
def visit_BINARY_SUBSCR(self, instr): yield self.LOAD_CONST(self._islicer).steal(instr) # TOS = self._islicer # TOS1 = k # TOS2 = m yield instructions.ROT_THREE() # TOS = k # TOS1 = m # TOS2 = self._islicer yield instructions.CALL_FUNCTION(2)
def _build_list(self, instr): if instr.arg == 0: yield instrs.LOAD_CONST(jl.jlist).steal(instr) yield instrs.CALL_FUNCTION(0) elif instr.arg == 1: yield instrs.LOAD_CONST(jl.jlist._from_starargs).steal(instr) yield instrs.ROT_TWO() yield instrs.CALL_FUNCTION(1) elif instr.arg == 2: yield instrs.LOAD_CONST(jl.jlist._from_starargs).steal(instr) yield instrs.ROT_THREE() yield instrs.CALL_FUNCTION(2) else: yield instr yield instrs.LOAD_CONST(jl.jlist) yield instrs.ROT_TWO() yield instrs.CALL_FUNCTION(1)
def pushcfa(): yield instructions.DUP_TOP() yield instructions.LOAD_CONST(Word) yield instructions.LOAD_CONST(isinstance) yield instructions.ROT_THREE() yield instructions.CALL_FUNCTION(2) not_word_instr = instructions.LOAD_CONST(NotAWord) yield instructions.POP_JUMP_IF_FALSE(not_word_instr) yield instructions.LOAD_ATTR('addr') yield next_instruction() yield not_word_instr yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.RAISE_VARARGS(1)
def _build_const_map(self, keys, instr): yield instructions.BUILD_TUPLE(len(keys.arg)).steal(keys) # TOS = (v0, v1, ..., vn) yield keys # TOS = (k0, k1, ..., kn) # TOS1 = (v0, v1, ..., vn) yield instructions.LOAD_CONST(self._construct_const_map) # TOS = self._construct_const_map # TOS1 = (k0, k1, ..., kn) # TOS2 = (v0, v1, ..., vn) yield instructions.ROT_THREE() # TOS = (k0, k1, ..., kn) # TOS1 = (v0, v1, ..., vn) # TOS2 = self._construct_const_map yield instructions.CALL_FUNCTION(2)
def _import_name(self, instr): # TOS fromlist # TOS1 level yield instructions.LOAD_CONST(self._import_wrapper).steal(instr) # TOS self._import_wrapper # TOS1 fromlist # TOS2 level yield instructions.ROT_THREE() # TOS fromlist # TOS1 level # TOS2 self._import_wrapper yield instructions.LOAD_CONST(instr.arg) # TOS name # TOS1 fromlist # TOS2 level # TOS3 self._import_wrapper yield instructions.CALL_FUNCTION(3)
def _compare_op(self, instr): """ Replace the `is` operator to act on the values the thunk represent. This makes `is` lazy. """ if instr.arg != 8: # is yield instr return yield instructions.LOAD_CONST(_lazy_is).steal(instr) # TOS = _lazy_is # TOS1 = a # TOS2 = b # This safe to do because `is` is commutative 100% of the time. # We are doing a pointer compare so we can move the operands # around. This saves us from doing an extra ROT_TWO to preserve the # order. yield instructions.ROT_THREE() # TOS = a # TOS1 = b # TOS2 = _lazy_is yield instructions.CALL_FUNCTION(2)
def _build_list_in_comprehension(self, build_instr, load_instr): yield instrs.LOAD_CONST(jl.jlist).steal(build_instr) yield instrs.CALL_FUNCTION(0) yield instrs.DUP_TOP() yield instrs.DUP_TOP() # TOS = <jlist> # TOS1 = <jlist> # TOS2 = <jlist> yield instrs.LOAD_ATTR('append') yield instrs.STORE_FAST('.append') # TOS = <jlist> # TOS1 = <jlist> yield load_instr # TOS = .0 # TOS1 = <jlist> # TOS2 = <jlist> yield instrs.DUP_TOP() # TOS = .0 # TOS1 = .0 # TOS2 = <jlist> # TOS3 = <jlist> yield instrs.ROT_THREE() # TOS = .0 # TOS1 = <jlist> # TOS2 = .0 # TOS3 = <jlist> yield instrs.LOAD_CONST(operator.length_hint) yield instrs.ROT_TWO() yield instrs.CALL_FUNCTION(1) # TOS = <length_hint> # TOS1 = <jlist> # TOS2 = .0 # TOS3 = <jlist> yield instrs.ROT_TWO() # TOS = <jlist> # TOS1 = <length_hint> # TOS2 = .0 # TOS3 = <jlist> if sys.version_info >= (3, 7): yield instrs.LOAD_METHOD('_reserve') # TOS = <jlist._reserve> # TOS1 = <length_hint> # TOS2 = .0 # TOS3 = <jlist> yield instrs.ROT_TWO() # TOS = <length_hint> # TOS1 = <jlist._reserve> # TOS2 = .0 # TOS3 = <jlist> yield instrs.CALL_METHOD(1) # TOS = None # TOS1 = .0 # TOS3 = <jlist> else: yield instrs.LOAD_ATTR('_reserve') # TOS = <jlist._reserve> # TOS1 = <length_hint> # TOS2 = .0 # TOS3 = <jlist> yield instrs.ROT_TWO() # TOS = <length_hint> # TOS1 = <jlist._reserve> # TOS2 = .0 # TOS3 = <jlist> yield instrs.CALL_FUNCTION(1) # TOS = None # TOS1 = .0 # TOS3 = <jlist> yield instrs.POP_TOP()
def _nrot(): yield instructions.ROT_THREE() yield instructions.ROT_THREE()
def py_getattr(): yield instructions.LOAD_CONST(getattr) yield instructions.ROT_THREE() yield instructions.CALL_FUNCTION(2) yield next_instruction()
def _divmod(): yield instructions.LOAD_CONST(divmod) yield instructions.ROT_THREE() yield instructions.CALL_FUNCTION() yield next_instruction()
def over(): yield instructions.ROT_TWO() yield instructions.DUP_TOP() yield instructions.ROT_THREE() yield next_instruction()
def bwrite(): yield instructions.LOAD_CONST(bwrite_impl) yield instructions.ROT_THREE() yield instructions.CALL_FUNCTION(2) yield instructions.POP_TOP() yield next_instruction()
def __start(*, counting_run=False): yield setup_except_instr first = instructions.LOAD_CONST(push_return_addr) yield first yield instructions.CALL_FUNCTION() yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs['word'][0]) # We need to duplicate the word on the stack for proper error handling # later. # We dup it twice giving us 3 copies on the stack for: # find # literal lookup # unknown word error yield instructions.DUP_TOP() yield instructions.DUP_TOP() yield instructions.LOAD_CONST(push_return_addr) yield instructions.CALL_FUNCTION(0) yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs['find'][0]) yield instructions.DUP_TOP() yield instructions.LOAD_CONST(None) yield instructions.COMPARE_OP.IS process_lit_instr = instructions.POP_TOP() yield instructions.POP_JUMP_IF_TRUE(process_lit_instr) # clear the word strings from the stack yield instructions.ROT_THREE() yield instructions.POP_TOP() yield instructions.POP_TOP() yield instructions.DUP_TOP() yield instructions.LOAD_ATTR('addr') yield instructions.LOAD_CONST(1) yield instructions.BINARY_SUBTRACT() yield instructions.LOAD_FAST('immediate') immediate_with_nip_instr = instructions.ROT_TWO() yield instructions.POP_JUMP_IF_TRUE(immediate_with_nip_instr) yield instructions.ROT_TWO() yield instructions.LOAD_ATTR('immediate') immediate_instr = instructions.LOAD_CONST(push_return_addr) yield instructions.POP_JUMP_IF_TRUE(immediate_instr) yield instructions.LOAD_CONST(push_return_addr) yield instructions.CALL_FUNCTION(0) yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs[','][0]) yield instructions.JUMP_ABSOLUTE(first) yield immediate_with_nip_instr yield instructions.POP_TOP() yield immediate_instr yield instructions.CALL_FUNCTION() yield instructions.POP_TOP() yield instructions.YIELD_VALUE() # We need to add some padding so that the return adress gets # computed correctly. Maybe we should have two functions like: # push_return_jmp_addr/push_return_yield_addr to handle this. yield instructions.NOP() yield instructions.NOP() yield instructions.JUMP_ABSOLUTE(first) yield process_lit_instr yield instructions.LOAD_CONST(process_lit) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.DUP_TOP() yield instructions.LOAD_CONST(NotImplemented) yield instructions.COMPARE_OP.IS unknown_word_instr = instructions.POP_TOP() yield instructions.POP_JUMP_IF_TRUE(unknown_word_instr) # clear the word string left for the unknown word case yield from _nip() yield instructions.LOAD_FAST('immediate') yield instructions.POP_JUMP_IF_TRUE(first) yield instructions.LOAD_CONST(append_lit) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield from inline_write_short( None if counting_run else len(list(_sparse_args(__start(counting_run=True)))) - 1, ) yield from inline_write_short_from_stack() yield instructions.JUMP_ABSOLUTE(first) yield unknown_word_instr yield instructions.LOAD_CONST(UnknownWord) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.RAISE_VARARGS(1) # this is the bytecode side of the literal implementation which # appears to be dead code but does get jumped to if counting_run: return yield instructions.LOAD_CONST(lit_impl) yield instructions.LOAD_CONST(pop_return_addr) yield instructions.CALL_FUNCTION(0) yield instructions.CALL_FUNCTION(1) yield instructions.UNPACK_SEQUENCE(2) yield instructions.YIELD_VALUE()