def setup(self): self.assembler = AssemblerASMJS(self)
class CPU_ASMJS(AbstractLLCPU): """Quote-unquote 'CPU' for emitting and running asmjs javascript. This inherits from AbstractLLCPU because it interfaces with the rest of the interpreter in the same way, via low-level descrs. But the details of compiling and running a trace are very very different. Rather than mapping executable memory and jumping into it, we build up javascript source code and call external functions to compile and invoke it. """ IS_64_BIT = False JITFRAME_FIXED_SIZE = JITFRAME_FIXED_SIZE supports_floats = True supports_singlefloats = False supports_longlong = False with_threads = False backend_name = "asmjs" def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): AbstractLLCPU.__init__(self, rtyper, stats, opts, translate_support_code, gcdescr) def set_debug(self, flag): return self.assembler.set_debug(flag) def get_failargs_limit(self): if self.opts is not None: return self.opts.failargs_limit else: return 1000 def setup(self): self.assembler = AssemblerASMJS(self) def setup_once(self): self.assembler.setup_once() def finish_once(self): self.assembler.finish_once() def make_execute_token(self, *ARGS): """Build and return a function for executing the given JIT token. Each chunk of compiled code is represented by an integer "function id". We need to look up the id, build the necessary frame, and then call the helper function "jitInvoke" to execute the compiled function. """ # This is mostly copied from llsupport/llmodel.py, but with changes # to invoke the external javascript helper thingy. lst = [(i, history.getkind(ARG)[0]) for i, ARG in enumerate(ARGS)] kinds = unrolling_iterable(lst) def execute_token(executable_token, *args): clt = executable_token.compiled_loop_token assert isinstance(clt, CompiledLoopTokenASMJS) funcid = clt.func.compiled_funcid loopid = clt.compiled_loopid frame_info = clt.func.frame_info frame = self.gc_ll_descr.malloc_jitframe(frame_info) ll_frame = lltype.cast_opaque_ptr(llmemory.GCREF, frame) locs = clt._ll_initial_locs if SANITYCHECK: assert len(locs) == len(args) if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter LLInterpreter.current_interpreter = self.debug_ll_interpreter try: # Store each argument into the frame. for i, kind in kinds: arg = args[i] num = locs[i] if kind == history.INT: self.set_int_value(ll_frame, num, arg) elif kind == history.FLOAT: self.set_float_value(ll_frame, num, arg) else: assert kind == history.REF self.set_ref_value(ll_frame, num, arg) llop.gc_writebarrier(lltype.Void, ll_frame) # Send the threadlocaladdr. if self.translate_support_code: ll_tlref = llop.threadlocalref_addr(llmemory.Address) else: ll_tlref = rffi.cast(llmemory.Address, self._debug_errno_container) # Invoke it via the helper. ll_frameadr = self.cast_ptr_to_int(ll_frame) ll_tladdr = self.cast_adr_to_int(ll_tlref) ll_frameadr = support.jitInvoke(funcid, ll_frameadr, ll_tladdr, loopid) ll_frame = self.cast_int_to_ptr(ll_frameadr, llmemory.GCREF) finally: if not self.translate_support_code: LLInterpreter.current_interpreter = prev_interpreter return ll_frame return execute_token def compile_loop(self, inputargs, operations, looptoken, log=True, name='', logger=None): return self.assembler.assemble_loop(name, inputargs, operations, looptoken, log=log) def compile_bridge(self, faildescr, inputargs, operations, original_loop_token, log=True, logger=None): clt = original_loop_token.compiled_loop_token clt.compiling_a_bridge() return self.assembler.assemble_bridge(faildescr, inputargs, operations, original_loop_token, log=log) def free_loop_and_bridges(self, compiled_loop_token): AbstractLLCPU.free_loop_and_bridges(self, compiled_loop_token) self.assembler.free_loop_and_bridges(compiled_loop_token) def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU_ASMJS.cast_adr_to_int(adr) cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)' cast_ptr_to_int = staticmethod(cast_ptr_to_int) def redirect_call_assembler(self, oldlooptoken, newlooptoken): self.assembler.redirect_call_assembler(oldlooptoken, newlooptoken) def invalidate_loop(self, looptoken): self.assembler.invalidate_loop(looptoken) def _decode_pos(self, deadframe, index): descr = self.get_latest_descr(deadframe) if descr.final_descr: assert index == 0 return 0 return descr._asmjs_faillocs[index]
class CPU_ASMJS(AbstractLLCPU): """Quote-unquote 'CPU' for emitting and running asmjs javascript. This inherits from AbstractLLCPU because it interfaces with the rest of the interpreter in the same way, via low-level descrs. But the details of compiling and running a trace are very very different. Rather than mapping executable memory and jumping into it, we build up javascript source code and call external functions to compile and invoke it. """ IS_64_BIT = False JITFRAME_FIXED_SIZE = JITFRAME_FIXED_SIZE supports_floats = True supports_singlefloats = False supports_longlong = False with_threads = False backend_name = "asmjs" def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): AbstractLLCPU.__init__(self, rtyper, stats, opts, translate_support_code, gcdescr) def set_debug(self, flag): return self.assembler.set_debug(flag) def get_failargs_limit(self): if self.opts is not None: return self.opts.failargs_limit else: return 1000 def setup(self): self.assembler = AssemblerASMJS(self) def setup_once(self): self.assembler.setup_once() def finish_once(self): self.assembler.finish_once() def make_execute_token(self, *ARGS): """Build and return a function for executing the given JIT token. Each chunk of compiled code is represented by an integer "function id". We need to look up the id, build the necessary frame, and then call the helper function "jitInvoke" to execute the compiled function. """ # This is mostly copied from llsupport/llmodel.py, but with changes # to invoke the external javascript helper thingy. lst = [(i, history.getkind(ARG)[0]) for i, ARG in enumerate(ARGS)] kinds = unrolling_iterable(lst) def execute_token(executable_token, *args): clt = executable_token.compiled_loop_token assert isinstance(clt, CompiledLoopTokenASMJS) funcid = clt.func.compiled_funcid loopid = clt.compiled_loopid frame_info = clt.func.frame_info frame = self.gc_ll_descr.malloc_jitframe(frame_info) ll_frame = lltype.cast_opaque_ptr(llmemory.GCREF, frame) locs = clt._ll_initial_locs if SANITYCHECK: assert len(locs) == len(args) if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter LLInterpreter.current_interpreter = self.debug_ll_interpreter try: # Store each argument into the frame. for i, kind in kinds: arg = args[i] num = locs[i] if kind == history.INT: self.set_int_value(ll_frame, num, arg) elif kind == history.FLOAT: self.set_float_value(ll_frame, num, arg) else: assert kind == history.REF self.set_ref_value(ll_frame, num, arg) llop.gc_writebarrier(lltype.Void, ll_frame) # Send the threadlocaladdr. if self.translate_support_code: ll_tlref = llop.threadlocalref_addr( llmemory.Address) else: ll_tlref = rffi.cast(llmemory.Address, self._debug_errno_container) # Invoke it via the helper. ll_frameadr = self.cast_ptr_to_int(ll_frame) ll_tladdr = self.cast_adr_to_int(ll_tlref) ll_frameadr = support.jitInvoke(funcid, ll_frameadr, ll_tladdr, loopid) ll_frame = self.cast_int_to_ptr(ll_frameadr, llmemory.GCREF) finally: if not self.translate_support_code: LLInterpreter.current_interpreter = prev_interpreter return ll_frame return execute_token def compile_loop(self, inputargs, operations, looptoken, log=True, name='', logger=None): return self.assembler.assemble_loop(name, inputargs, operations, looptoken, log=log) def compile_bridge(self, faildescr, inputargs, operations, original_loop_token, log=True, logger=None): clt = original_loop_token.compiled_loop_token clt.compiling_a_bridge() return self.assembler.assemble_bridge(faildescr, inputargs, operations, original_loop_token, log=log) def free_loop_and_bridges(self, compiled_loop_token): AbstractLLCPU.free_loop_and_bridges(self, compiled_loop_token) self.assembler.free_loop_and_bridges(compiled_loop_token) def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU_ASMJS.cast_adr_to_int(adr) cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)' cast_ptr_to_int = staticmethod(cast_ptr_to_int) def redirect_call_assembler(self, oldlooptoken, newlooptoken): self.assembler.redirect_call_assembler(oldlooptoken, newlooptoken) def invalidate_loop(self, looptoken): self.assembler.invalidate_loop(looptoken) def _decode_pos(self, deadframe, index): descr = self.get_latest_descr(deadframe) if descr.final_descr: assert index == 0 return 0 return descr._asmjs_faillocs[index]
class CPU_ASMJS(AbstractLLCPU): """'CPU' for emitting and running asmjs javascript. This inherits from AbstractLLCPU because it interfaces with the rest of the interpreter in the same way, via low-level descrs. But the details of compiling and running a trace are very very different. Rather than mapping executable memory and jumping into it, we build up javascript source code and call external functions to compile and invoke it. """ IS_64_BIT = False JITFRAME_FIXED_SIZE = JITFRAME_FIXED_SIZE supports_floats = True supports_singlefloats = False supports_longlong = False with_threads = False backend_name = "asmjs" def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): AbstractLLCPU.__init__(self, rtyper, stats, opts, translate_support_code, gcdescr) self._make_execute_trampoline_func() def set_debug(self, flag): return self.assembler.set_debug(flag) def get_failargs_limit(self): if self.opts is not None: return self.opts.failargs_limit else: return 1000 def setup(self): self.assembler = AssemblerASMJS(self) def setup_once(self): self.assembler.setup_once() def finish_once(self): self.assembler.finish_once() def make_execute_token(self, *ARGS): """Build and return a function for executing the given JIT token. Each chunk of compiled code is represented by an integer "function id". We need to look up the id, build the necessary frame, and then call the helper function "jitInvoke" to execute the compiled function. The compiled code will return the frame object with jf_force_descr set to indicate control flow. If zero then it's done and we can find the results in the frame; if nonzero then it indicates another compiled function that should be invoked. We loop until it gets set to zero, providing a simple and inefficient simulation of GOTOs between the compiled chunks of code. This little trampoline is necessary because the main interpreter is running in asmjs mode, where it is forbidden to define new functions at runtime. It has to call into helper code hosted outside of the asmjs fast-path. """ # This is mostly copied from llsupport/llmodel.py, but with changes # to invoke the external javascript helper trampoline thingy. lst = [(i, history.getkind(ARG)[0]) for i, ARG in enumerate(ARGS)] kinds = unrolling_iterable(lst) def execute_token(executable_token, *args): clt = executable_token.compiled_loop_token assert isinstance(clt, CompiledLoopTokenASMJS) func_id = clt.compiled_funcid frame_info = clt.frame_info frame = self.gc_ll_descr.malloc_jitframe(frame_info) ll_frame = lltype.cast_opaque_ptr(llmemory.GCREF, frame) locs = clt._ll_initial_locs if SANITYCHECK: assert len(locs) == len(args) if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter LLInterpreter.current_interpreter = self.debug_ll_interpreter try: # Store each argument into the frame. for i, kind in kinds: arg = args[i] num = locs[i] if kind == history.INT: self.set_int_value(ll_frame, num, arg) elif kind == history.FLOAT: self.set_float_value(ll_frame, num, arg) else: assert kind == history.REF self.set_ref_value(ll_frame, num, arg) # Ensure the frame has a valid gcmap, since there's # no guarantee the trampoline won't collect. # XXX TODO need a writebarrier on the frame? frame.jf_gcmap = clt.compiled_blocks[0].initial_gcmap # Invoke the trampoline to execute it. self.set_frame_next_call(ll_frame, func_id, 0) ll_frame_adr = self.cast_ptr_to_int(ll_frame) ll_frame_adr = self._execute_trampoline_func(ll_frame_adr) ll_frame = self.cast_int_to_ptr(ll_frame_adr, llmemory.GCREF) finally: if not self.translate_support_code: LLInterpreter.current_interpreter = prev_interpreter return ll_frame return execute_token def set_frame_next_call(self, ll_frame, funcid, label): offset = self.get_ofs_of_frame_field("jf_extra_stack_depth") next_call = (funcid << 8) | label self.write_int_at_mem(ll_frame, offset, WORD, 0, next_call) def get_frame_next_call(self, ll_frame): offset = self.get_ofs_of_frame_field("jf_extra_stack_depth") return self.read_int_at_mem(ll_frame, offset, WORD, 0) def get_execute_trampoline_adr(self): exeptr = llhelper(self._execute_trampoline_FUNCPTR, self._execute_trampoline_func) return self.cast_ptr_to_int(exeptr) def _make_execute_trampoline_func(self): def execute_trampoline(ll_frame_adr): ll_frame = self.cast_int_to_ptr(ll_frame_adr, llmemory.GCREF) next_call = self.get_frame_next_call(ll_frame) funcid = next_call >> 8 while funcid != 0: label = next_call & 0xFF ll_frame_adr = support.jitInvoke(funcid, label, ll_frame_adr) ll_frame = self.cast_int_to_ptr(ll_frame_adr, llmemory.GCREF) next_call = self.get_frame_next_call(ll_frame) funcid = next_call >> 8 return ll_frame_adr ARGS = [rffi.INT] EXEFUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, rffi.INT)) self._execute_trampoline_func = execute_trampoline self._execute_trampoline_FUNCPTR = EXEFUNCPTR def compile_loop(self, inputargs, operations, looptoken, log=True, name=''): return self.assembler.assemble_loop(name, inputargs, operations, looptoken, log=log) def compile_bridge(self, faildescr, inputargs, operations, original_loop_token, log=True): clt = original_loop_token.compiled_loop_token clt.compiling_a_bridge() return self.assembler.assemble_bridge(faildescr, inputargs, operations, original_loop_token, log=log) def free_loop_and_bridges(self, compiled_loop_token): AbstractLLCPU.free_loop_and_bridges(self, compiled_loop_token) self.assembler.free_loop_and_bridges(compiled_loop_token) def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU_ASMJS.cast_adr_to_int(adr) cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)' cast_ptr_to_int = staticmethod(cast_ptr_to_int) def redirect_call_assembler(self, oldlooptoken, newlooptoken): self.assembler.redirect_call_assembler(oldlooptoken, newlooptoken) def invalidate_loop(self, looptoken): self.assembler.invalidate_loop(looptoken) def _decode_pos(self, deadframe, index): descr = self.get_latest_descr(deadframe) if descr.final_descr: assert index == 0 return 0 return descr._asmjs_faillocs[index]