def enable(self, space, fileno, period_usec): if self.is_enabled: raise oefmt(space.w_ValueError, "_vmprof already enabled") self.fileno = fileno self.is_enabled = True self.write_header(fileno, period_usec) if not self.ever_enabled: if we_are_translated(): res = pypy_vmprof_init() if res: raise OperationError( space.w_IOError, space.wrap(rffi.charp2str(vmprof_get_error()))) self.ever_enabled = True self.gather_all_code_objs(space) space.register_code_callback(vmprof_register_code) if we_are_translated(): # does not work untranslated res = vmprof_enable(fileno, period_usec, 0, lltype.nullptr(rffi.CCHARP.TO), 0) else: res = 0 if res == -1: raise wrap_oserror(space, OSError(rposix.get_saved_errno(), "_vmprof.enable"))
def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type, orig_inpargs, memo): forget_optimization_info(loop.operations) forget_optimization_info(loop.inputargs) vinfo = jitdriver_sd.virtualizable_info if vinfo is not None: vable = orig_inpargs[jitdriver_sd.index_of_virtualizable].getref_base() patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable) original_jitcell_token = loop.original_jitcell_token globaldata = metainterp_sd.globaldata original_jitcell_token.number = n = globaldata.loopnumbering globaldata.loopnumbering += 1 if not we_are_translated(): show_procedures(metainterp_sd, loop) loop.check_consistency() if metainterp_sd.warmrunnerdesc is not None: hooks = metainterp_sd.warmrunnerdesc.hooks debug_info = JitDebugInfo(jitdriver_sd, metainterp_sd.logger_ops, original_jitcell_token, loop.operations, type, greenkey) hooks.before_compile(debug_info) else: debug_info = None hooks = None operations = get_deep_immutable_oplist(loop.operations) metainterp_sd.profiler.start_backend() debug_start("jit-backend") try: loopname = jitdriver_sd.warmstate.get_location_str(greenkey) unique_id = jitdriver_sd.warmstate.get_unique_id(greenkey) asminfo = do_compile_loop(jitdriver_sd.index, unique_id, metainterp_sd, loop.inputargs, operations, original_jitcell_token, name=loopname, log=have_debug_prints(), memo=memo) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() if hooks is not None: debug_info.asminfo = asminfo hooks.after_compile(debug_info) metainterp_sd.stats.add_new_loop(loop) if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new " + type) # if asminfo is not None: ops_offset = asminfo.ops_offset else: ops_offset = None metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, type, ops_offset, name=loopname) # if metainterp_sd.warmrunnerdesc is not None: # for tests metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(original_jitcell_token)
def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs, operations, original_loop_token): if not we_are_translated(): show_procedures(metainterp_sd) seen = dict.fromkeys(inputargs) TreeLoop.check_consistency_of_branch(operations, seen) if metainterp_sd.warmrunnerdesc is not None: hooks = metainterp_sd.warmrunnerdesc.hooks debug_info = JitDebugInfo( jitdriver_sd, metainterp_sd.logger_ops, original_loop_token, operations, "bridge", fail_descr=faildescr ) hooks.before_compile_bridge(debug_info) else: hooks = None debug_info = None operations = get_deep_immutable_oplist(operations) metainterp_sd.profiler.start_backend() debug_start("jit-backend") try: asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs, operations, original_loop_token) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() if hooks is not None: debug_info.asminfo = asminfo hooks.after_compile_bridge(debug_info) if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new bridge") # if asminfo is not None: ops_offset = asminfo.ops_offset else: ops_offset = None metainterp_sd.logger_ops.log_bridge(inputargs, operations, None, faildescr, ops_offset)
def edge_to(self, to, arg=None, failarg=False, label=None): if self is to: return dep = self.depends_on(to) if not dep: #if force or self.independent(idx_from, idx_to): dep = Dependency(self, to, arg, failarg) self.adjacent_list.append(dep) dep_back = Dependency(to, self, arg, failarg) dep.backward = dep_back to.adjacent_list_back.append(dep_back) if not we_are_translated(): if label is None: label = '' dep.label = label else: if not dep.because_of(arg): dep.add_dependency(self,to,arg) # if a fail argument is overwritten by another normal # dependency it will remove the failarg flag if not (dep.is_failarg() and failarg): dep.set_failarg(False) if not we_are_translated() and label is not None: _label = getattr(dep, 'label', '') dep.label = _label + ", " + label return dep
def f(): state.data = [] state.datalen1 = 0 state.datalen2 = 0 state.datalen3 = 0 state.datalen4 = 0 state.threadlocals = gil.GILThreadLocals() state.threadlocals.setup_threads(space) thread.gc_thread_prepare() subident = thread.start_new_thread(bootstrap, ()) mainident = thread.get_ident() runme(True) still_waiting = 3000 while len(state.data) < 2*N: debug_print(len(state.data)) if not still_waiting: raise ValueError("time out") still_waiting -= 1 if not we_are_translated(): gil.before_external_call() time.sleep(0.01) if not we_are_translated(): gil.after_external_call() debug_print("leaving!") i1 = i2 = 0 for tid, i in state.data: if tid == mainident: assert i == i1; i1 += 1 elif tid == subident: assert i == i2; i2 += 1 else: assert 0 assert i1 == N + skew assert i2 == N - skew return len(state.data)
def emit_store(self, value, addr, typ): """Emit a typed store operation of a value into the heap. Given a jsvalue, a heap address, and a HeapType, this method generates a generic "store to heap" instruction of the following form: HEAPVIEW[(addr) >> shift] = value; """ assert isinstance(addr, jsval.AbstractValue) # When running untranslated, we can't guarantee alignment of doubles. # We have to store it into a properly aligned chunk, then # copy to final destination as two 32-bit ints. tempaddr = None if not we_are_translated() and typ is jsval.Float64: tempaddr = self.allocate_intvar() self.emit_assignment(tempaddr, addr) addr = jsval.tempDoublePtr self.emit(typ.heap_name) self.emit("[(") self.emit_value(addr) self.emit(")>>") self.emit(str(typ.shift)) self.emit("]=") self.emit_value(value) self.emit(";\n") if not we_are_translated() and typ is jsval.Float64: pt1 = jsval.HeapData(jsval.Int32, addr) self.emit_store(pt1, tempaddr, jsval.Int32) pt2 = jsval.HeapData(jsval.Int32, jsval.Plus(addr, jsval.word)) self.emit_store(pt2, jsval.Plus(tempaddr, jsval.word), jsval.Int32) self.free_intvar(tempaddr)
def _really_force(self, optforce): op = self.source_op assert op is not None # ^^^ This case should not occur any more (see test_bug_3). # if not we_are_translated(): op.name = 'FORCE ' + self.source_op.name if self._is_immutable_and_filled_with_constants(): box = optforce.optimizer.constant_fold(op) self.make_constant(box) for ofs, value in self._fields.iteritems(): subbox = value.force_box(optforce) assert isinstance(subbox, Const) execute(optforce.optimizer.cpu, None, rop.SETFIELD_GC, ofs, box, subbox) # keep self._fields, because it's all immutable anyway else: optforce.emit_operation(op) self.box = box = op.result # iteritems = self._fields.iteritems() if not we_are_translated(): #random order is fine, except for tests iteritems = list(iteritems) iteritems.sort(key=lambda (x, y): x.sort_key()) for ofs, value in iteritems: if value.is_null(): continue subbox = value.force_box(optforce) op = ResOperation(rop.SETFIELD_GC, [box, subbox], None, descr=ofs) optforce.emit_operation(op)
def f(): state.data = [] state.datalen1 = 0 state.datalen2 = 0 state.datalen3 = 0 state.datalen4 = 0 state.threadlocals = my_gil_threadlocals state.threadlocals.setup_threads(space) subident = thread.start_new_thread(bootstrap, ()) mainident = thread.get_ident() runme(True) still_waiting = 3000 while len(state.data) < 2*N: debug_print(len(state.data)) if not still_waiting: llop.debug_print(lltype.Void, "timeout. progress: " "%d of 2*N (= %f%%)" % \ (len(state.data), 2*N, 100*len(state.data)/(2.0*N))) raise ValueError("time out") still_waiting -= 1 if not we_are_translated(): rgil.release() time.sleep(0.1) if not we_are_translated(): rgil.acquire() debug_print("leaving!") i1 = i2 = 0 for tid, i in state.data: if tid == mainident: assert i == i1; i1 += 1 elif tid == subident: assert i == i2; i2 += 1 else: assert 0 assert i1 == N + skew assert i2 == N - skew return len(state.data)
def run_load_stdlib(): global stdlib_loaded if stdlib_loaded.is_true(): return import pixie.vm.compiler as compiler import pixie.vm.reader as reader f = open(rpath.rjoin(str(rt.name(load_path.deref())), "pixie/stdlib.pxi")) data = f.read() f.close() rdr = reader.MetaDataReader(reader.StringReader(unicode(data)), u"pixie/stdlib.pxi") result = nil if not we_are_translated(): print "Loading stdlib while interpreted, this will take some time..." with compiler.with_ns(u"pixie.stdlib"): while True: if not we_are_translated(): sys.stdout.write(".") sys.stdout.flush() form = reader.read(rdr, False) if form is reader.eof: break result = compiler.compile(form).invoke([]) if not we_are_translated(): print "done" stdlib_loaded.set_true()
def get_new_loc(self, box): size = self.frame_size(box.type) # frame_depth is rounded up to a multiple of 'size', assuming # that 'size' is a power of two. The reason for doing so is to # avoid obscure issues in jump.py with stack locations that try # to move from position (6,7) to position (7,8). newloc = self.freelist.pop(size, box.type) if newloc is None: # index = self.get_frame_depth() if index & 1 and size == 2: # we can't allocate it at odd position self.freelist._append(index) newloc = self.frame_pos(index + 1, box.type) self.current_frame_depth += 3 index += 1 # for test else: newloc = self.frame_pos(index, box.type) self.current_frame_depth += size # if not we_are_translated(): # extra testing testindex = self.get_loc_index(newloc) assert testindex == index # self.bindings[box] = newloc if not we_are_translated(): self._check_invariants() return newloc
def load_reader(rdr): import pixie.vm.reader as reader import pixie.vm.compiler as compiler import sys if not we_are_translated(): print "Loading file while interpreted, this may take time" val = PXIC_WRITER.deref() if val is nil: pxic_writer = None else: pxic_writer = val.get_pxic_writer() with compiler.with_ns(u"user"): compiler.NS_VAR.deref().include_stdlib() while True: if not we_are_translated(): sys.stdout.write(".") sys.stdout.flush() form = reader.read(rdr, False) if form is reader.eof: return nil compiled = compiler.compile(form) if pxic_writer is not None: pxic_writer.write_object(compiled) compiled.invoke([]) if not we_are_translated(): print "done" return nil
def get_const_ptr_for_string(s): from rpython.rtyper.annlowlevel import llstr if not we_are_translated(): try: return _const_ptr_for_string[s] except KeyError: pass result = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, llstr(s))) if not we_are_translated(): _const_ptr_for_string[s] = result return result
def load_reader(rdr): import pixie.vm.reader as reader import pixie.vm.compiler as compiler import sys if not we_are_translated(): print "Loading file while interpreted, this may take time" val = PXIC_WRITER.deref() if val is nil: pxic_writer = None else: pxic_writer = val.get_pxic_writer() with compiler.with_ns(u"user"): compiler.NS_VAR.deref().include_stdlib() while True: if not we_are_translated(): sys.stdout.write(".") sys.stdout.flush() form = reader.read(rdr, False) if form is reader.eof: return nil try: compiled = compiler.compile(form) except WrappedException as ex: meta = rt.meta(form) if meta is not nil: ci = rt.interpreter_code_info(meta) add_info(ex, ci.__repr__()) add_info(ex, u"Compiling: " + rt.name(rt.str(form))) raise ex try: if pxic_writer is not None: pxic_writer.write_object(compiled) compiled.invoke([]) except WrappedException as ex: meta = rt.meta(form) if meta is not nil: ci = rt.interpreter_code_info(meta) add_info(ex, ci.__repr__()) add_info(ex, u"Running: " + rt.name(rt.str(form))) raise ex if not we_are_translated(): print "done" return nil
def walk_operations(self, inputargs, operations): from rpython.jit.backend.ppc.ppc_assembler import ( operations as asm_operations) i = 0 self.limit_loop_break = (self.assembler.mc.get_relative_pos() + LIMIT_LOOP_BREAK) self.operations = operations while i < len(operations): op = operations[i] self.assembler.mc.mark_op(op) self.rm.position = i self.fprm.position = i self.vrm.position = i opnum = op.opnum if rop.has_no_side_effect(opnum) and op not in self.longevity: i += 1 self.possibly_free_vars_for_op(op) continue # for j in range(op.numargs()): box = op.getarg(j) if box.is_vector(): if box.type != VOID: self.vrm.temp_boxes.append(box) elif box.type != FLOAT: self.rm.temp_boxes.append(box) else: self.fprm.temp_boxes.append(box) # if not we_are_translated() and opnum == rop.FORCE_SPILL: self._consider_force_spill(op) else: arglocs = oplist[opnum](self, op) asm_operations[opnum](self.assembler, op, arglocs, self) self.free_op_vars() self.possibly_free_var(op) self.rm._check_invariants() self.fprm._check_invariants() self.vrm._check_invariants() if self.assembler.mc.get_relative_pos() > self.limit_loop_break: self.assembler.break_long_loop(self) self.limit_loop_break = (self.assembler.mc.get_relative_pos() + LIMIT_LOOP_BREAK) i += 1 assert not self.rm.reg_bindings assert not self.fprm.reg_bindings if not we_are_translated(): self.assembler.mc.trap() self.flush_loop() self.assembler.mc.mark_op(None) # end of the loop self.operations = None for arg in inputargs: self.possibly_free_var(arg)
def get_const_ptr_for_unicode(s): from rpython.rtyper.annlowlevel import llunicode if not we_are_translated(): try: return _const_ptr_for_unicode[s] except KeyError: pass if isinstance(s, str): s = unicode(s) result = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, llunicode(s))) if not we_are_translated(): _const_ptr_for_unicode[s] = result return result
def record_loop_or_bridge(metainterp_sd, loop): """Do post-backend recordings and cleanups on 'loop'. """ # get the original jitcell token corresponding to jitcell form which # this trace starts original_jitcell_token = loop.original_jitcell_token assert original_jitcell_token is not None if metainterp_sd.warmrunnerdesc is not None: # for tests assert original_jitcell_token.generation > 0 # has been registered with memmgr wref = weakref.ref(original_jitcell_token) for op in loop.operations: descr = op.getdescr() if isinstance(descr, ResumeDescr): descr.wref_original_loop_token = wref # stick it there n = descr.index if n >= 0: # we also record the resumedescr number original_jitcell_token.compiled_loop_token.record_faildescr_index(n) elif isinstance(descr, JitCellToken): # for a CALL_ASSEMBLER: record it as a potential jump. if descr is not original_jitcell_token: original_jitcell_token.record_jump_to(descr) descr.exported_state = None op.cleardescr() # clear reference, mostly for tests elif isinstance(descr, TargetToken): # for a JUMP: record it as a potential jump. # (the following test is not enough to prevent more complicated # cases of cycles, but at least it helps in simple tests of # test_memgr.py) if descr.original_jitcell_token is not original_jitcell_token: assert descr.original_jitcell_token is not None original_jitcell_token.record_jump_to(descr.original_jitcell_token) # exported_state is clear by optimizeopt when the short preamble is # constrcucted. if that did not happen the label should not show up # in a trace that will be used assert descr.exported_state is None if not we_are_translated(): op._descr_wref = weakref.ref(op._descr) op.cleardescr() # clear reference to prevent the history.Stats # from keeping the loop alive during tests # record this looptoken on the QuasiImmut used in the code if loop.quasi_immutable_deps is not None: for qmut in loop.quasi_immutable_deps: qmut.register_loop_token(wref) # XXX maybe we should clear the dictionary here # mostly for tests: make sure we don't keep a reference to the LoopToken loop.original_jitcell_token = None if not we_are_translated(): loop._looptoken_number = original_jitcell_token.number
def ffi_prep_callback(tp, f): """(ffi-prep-callback callback-tp fn) Prepares a Pixie function for use as a c callback. callback-tp is a ffi callback type, fn is a pixie function (can be a closure, native fn or any object that implements -invoke. Returns a function pointer that can be passed to c and invoked as a callback.""" affirm(isinstance(tp, CFunctionType), u"First argument to ffi-prep-callback must be a CFunctionType") raw_closure = rffi.cast(rffi.VOIDP, clibffi.closureHeap.alloc()) if not we_are_translated(): unique_id = id_generator.get_next() else: unique_id = rffi.cast(lltype.Signed, raw_closure) res = clibffi.c_ffi_prep_closure(rffi.cast(clibffi.FFI_CLOSUREP, raw_closure), tp.get_cd().cif, invoke_callback, rffi.cast(rffi.VOIDP, unique_id)) if rffi.cast(lltype.Signed, res) != clibffi.FFI_OK: registered_callbacks[unique_id] = None runtime_error(u"libffi failed to build this callback") cb = CCallback(tp, raw_closure, unique_id, f) registered_callbacks[unique_id] = cb return cb
def test_we_are_translated(self): assert we_are_translated() is False def fn(): return we_are_translated() res = self.interpret(fn, []) assert res is True
def failnbail_transformation(msg): msg = '%s\n' % msg if we_are_translated(): llop.debug_print(lltype.Void, msg) else: import pdb; pdb.set_trace() raise NotImplementedError(msg)
def walk_and_emit(self, state): """ Emit all the operations into the oplist parameter. Initiates the scheduling. """ assert isinstance(state, SchedulerState) while state.has_more(): node = self.next(state) if node: if not state.emit(node, self): if not node.emitted: state.pre_emit(node) self.mark_emitted(node, state) if not node.is_imaginary(): op = node.getoperation() state.seen[op] = None state.oplist.append(op) continue # it happens that packs can emit many nodes that have been # added to the scheuldable_nodes list, in this case it could # be that no next exists even though the list contains elements if not state.has_more(): break if self.try_to_trash_pack(state): continue raise AssertionError("schedule failed cannot continue. possible reason: cycle") if not we_are_translated(): for node in state.graph.nodes: assert node.emitted
def setraw(value): if we_are_translated(): _threadlocalref_seeme(self) addr = llop.threadlocalref_addr(llmemory.Address) llop.raw_store(lltype.Void, addr, offset, value) else: self.local.rawvalue = value
def gc_thread_after_fork(result_of_fork, opaqueaddr): """To call just after fork(). """ if we_are_translated(): llop.gc_thread_after_fork(lltype.Void, result_of_fork, opaqueaddr) else: assert opaqueaddr == llmemory.NULL
def __init__(self, translated=None): if translated is None: translated = we_are_translated() if translated: self.init_block_builder() else: self._become_a_plain_block_builder()
def __init__(self, value): if not we_are_translated(): if is_valid_int(value): value = int(value) # bool -> int else: assert isinstance(value, Symbolic) self.value = value
def get_or_make_raw(): if we_are_translated(): _threadlocalref_seeme(self) addr = llop.threadlocalref_addr(llmemory.Address) return llop.raw_load(FIELDTYPE, addr, offset) else: return getattr(self.local, 'rawvalue', zero)
def Py_DecRef(space, obj): if not obj: return assert lltype.typeOf(obj) == PyObject obj.c_ob_refcnt -= 1 if DEBUG_REFCOUNT: debug_refcount("DECREF", obj, obj.c_ob_refcnt, frame_stackdepth=3) if obj.c_ob_refcnt == 0: state = space.fromcache(RefcountState) ptr = rffi.cast(ADDR, obj) if ptr not in state.py_objects_r2w: # this is a half-allocated object, lets call the deallocator # without modifying the r2w/w2r dicts _Py_Dealloc(space, obj) else: w_obj = state.py_objects_r2w[ptr] del state.py_objects_r2w[ptr] w_type = space.type(w_obj) if not w_type.is_cpytype(): _Py_Dealloc(space, obj) del state.py_objects_w2r[w_obj] # if the object was a container for borrowed references state.delete_borrower(w_obj) else: if not we_are_translated() and obj.c_ob_refcnt < 0: message = "Negative refcount for obj %s with type %s" % ( obj, rffi.charp2str(obj.c_ob_type.c_tp_name)) print >>sys.stderr, message assert False, message
def gc_thread_die(): """To call just before the final GIL release done by a dying thread. After a thread_die(), no more gc operation should occur in this thread. """ if we_are_translated(): llop.gc_thread_die(lltype.Void)
def get_location_str(greenkey): greenargs = unwrap_greenkey(greenkey) fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr) llres = fn(*greenargs) if not we_are_translated() and isinstance(llres, str): return llres return hlstr(llres)
def record_interpreter_traceback(self): """Records the current traceback inside the interpreter. This traceback is only useful to debug the interpreter, not the application.""" if not we_are_translated(): if RECORD_INTERPLEVEL_TRACEBACK: self.debug_excs.append(sys.exc_info())
def free_temp_buffers(self, space): for buf in self.to_free: if not we_are_translated(): buf[0] = '\00' # invalidate the buffer, so that # test_keepalive_temp_buffer can fail lltype.free(buf, flavor='raw') self.to_free = []
def warn_missing_slot(space, method_name, slot_name, w_type): if not we_are_translated(): if slot_name not in missing_slots: missing_slots[slot_name] = w_type.getname(space) print "missing slot %r/%r, discovered on %r" % ( method_name, slot_name, w_type.getname(space))
def main(filename, rest_of_args, cgi, gcdump, debugger_pipes=(-1, -1), bench_mode=False, bench_no=-1): space = getspace() interp = Interpreter(space) absname = rpath.abspath(filename) try: ini_data = open('hippy.ini').read(-1) except (OSError, IOError): ini_data = None if ini_data is not None: try: load_ini(interp, ini_data) except: os.write(2, "error reading `hippy.ini`") try: bc = space.bytecode_cache.compile_file(absname, space) except ParseError as e: print 'Parse error: %s' % e return 2 except LexerError as e: print 'Parse error: %s on line %d' % (e.message, e.source_pos + 1) return 2 except IOError as e: print 'Could not open input file: %s' % filename return 2 except Exception as e: print 'Got exception %s with message %s' % (e.__class__.__name__, e) return 2 # if bench_mode: no = bench_no else: no = 1 exitcode = 0 space.ec.init_signals() for i in range(no): # load the ini file situated in the current wc interp.setup(cgi, argv=[filename] + rest_of_args) if bc is None: return 1 # The script originally called is considered an "included file," # so it will be listed together with the files # referenced by include and family. interp.cached_files[filename] = bc # exitcode = 0 try: try: if debugger_pipes != (-1, -1): interp.setup_debugger(debugger_pipes[0], debugger_pipes[1], start_paused=True) interp.run_main(space, bc, top_main=True) finally: interp.shutdown() except InterpreterError, e: tb = e.traceback if tb is not None: tb = tb[:] tb.reverse() for filename, funcname, line, source in tb: os.write( 2, "function %s, file %s:%d\n" % (funcname, filename, line)) os.write(2, source + "\n") if we_are_translated(): os.write(2, "Fatal interpreter error %s\n" % e.msg) else: print >> sys.stderr, "%s: %s\n" % (e.__class__.__name__, e.msg) except ParseError as e: print e.__str__() return 1
def __init__(self, pattern): self.pattern = pattern # check we don't get the old value of MAXREPEAT # during the untranslated tests if not we_are_translated(): assert 65535 not in pattern
def leave_code(s): if not we_are_translated(): assert vmprof_tl_stack.getraw() == s vmprof_tl_stack.setraw(s.c_next) lltype.free(s, flavor='raw')
def dict_allocate(): if not we_are_translated(): count_alloc(+1) return lltype.malloc(DICT, flavor="raw")
def rewrite(self, operations, gcrefs_output_list): # we can only remember one malloc since the next malloc can possibly # collect; but we can try to collapse several known-size mallocs into # one, both for performance and to reduce the number of write # barriers. We do this on each "basic block" of operations, which in # this case means between CALLs or unknown-size mallocs. # self.gcrefs_output_list = gcrefs_output_list self.gcrefs_map = None self.gcrefs_recently_loaded = None operations = self.remove_bridge_exception(operations) self._changed_op = None for i in range(len(operations)): op = operations[i] if op.get_forwarded(): msg = '[rewrite] operations at %d has forwarded info %s\n' % ( i, op.repr({})) if we_are_translated(): llop.debug_print(lltype.Void, msg) raise NotImplementedError(msg) if op.getopnum() == rop.DEBUG_MERGE_POINT: continue if op is self._changed_op: op = self._changed_op_to # ---------- GC_LOAD/STORE transformations -------------- if self.transform_to_gc_load(op): continue # ---------- turn NEWxxx into CALL_MALLOC_xxx ---------- if rop.is_malloc(op.opnum): self.handle_malloc_operation(op) continue if (rop.is_guard(op.opnum) or self.could_merge_with_next_guard(op, i, operations)): self.emit_pending_zeros() elif rop.can_malloc(op.opnum): self.emitting_an_operation_that_can_collect() elif op.getopnum() == rop.LABEL: self.emit_label() # ---------- write barriers ---------- if self.gc_ll_descr.write_barrier_descr is not None: if op.getopnum() == rop.SETFIELD_GC: self.consider_setfield_gc(op) self.handle_write_barrier_setfield(op) continue if op.getopnum() == rop.SETINTERIORFIELD_GC: self.handle_write_barrier_setinteriorfield(op) continue if op.getopnum() == rop.SETARRAYITEM_GC: self.consider_setarrayitem_gc(op) self.handle_write_barrier_setarrayitem(op) continue else: # this is dead code, but in case we have a gc that does # not have a write barrier and does not zero memory, we would # need to call it if op.getopnum() == rop.SETFIELD_GC: self.consider_setfield_gc(op) elif op.getopnum() == rop.SETARRAYITEM_GC: self.consider_setarrayitem_gc(op) # ---------- call assembler ----------- if OpHelpers.is_call_assembler(op.getopnum()): self.handle_call_assembler(op) continue if op.getopnum() == rop.JUMP or op.getopnum() == rop.FINISH: self.emit_pending_zeros() # self.emit_op(op) return self._newops
def spill_or_move_registers_before_call(self, save_sublist, force_store=[], save_all_regs=SAVE_DEFAULT_REGS): """Spill or move some registers before a call. By default, this means: for every register in 'save_sublist', if there is a variable there and it survives longer than the current operation, then it is spilled/moved somewhere else. WARNING: this might do the equivalent of possibly_free_vars() on variables dying in the current operation. It won't immediately overwrite registers that used to be occupied by these variables, though. Use this function *after* you finished calling self.loc() or self.make_sure_var_in_reg(), i.e. when you know the location of all input arguments. These locations stay valid, but only *if they are in self.save_around_call_regs,* not if they are callee-saved registers! 'save_all_regs' can be SAVE_DEFAULT_REGS (default set of registers), SAVE_ALL_REGS (do that for all registers), or SAVE_GCREF_REGS (default + gc ptrs). Overview of what we do (the implementation does it differently, for the same result): * we first check the set of registers that are free: call it F. * possibly_free_vars() is implied for all variables (except the ones listed in force_store): if they don't survive past the current operation, they are forgotten now. (Their register remain not in F, because they are typically arguments to the call, so they should not be overwritten by the next step.) * then for every variable that needs to be spilled/moved: if there is an entry in F that is acceptable, pick it and emit a move. Otherwise, emit a spill. Start doing this with the variables that survive the shortest time, to give them a better change to remain in a register---similar algo as _pick_variable_to_spill(). Note: when a register is moved, it often (but not always) means we could have been more clever and picked a better register in the first place, when we did so earlier. It is done this way anyway, as a local hack in this function, because on x86 CPUs such register-register moves are almost free. """ if not we_are_translated(): # 'save_sublist' is either the whole # 'self.save_around_call_regs', or a sublist thereof, and # then only those registers are spilled/moved. But when # we move them, we never move them to other registers in # 'self.save_around_call_regs', to avoid ping-pong effects # where the same value is constantly moved around. for reg in save_sublist: assert reg in self.save_around_call_regs new_free_regs = [] move_or_spill = [] for v, reg in self.reg_bindings.items(): max_age = self.longevity[v].last_usage if v not in force_store and max_age <= self.position: # variable dies del self.reg_bindings[v] new_free_regs.append(reg) continue if save_all_regs == SAVE_ALL_REGS: # we need to spill all registers in this mode self._bc_spill(v, new_free_regs) # elif save_all_regs == SAVE_GCREF_REGS and v.type == REF: # we need to spill all GC ptrs in this mode self._bc_spill(v, new_free_regs) # elif reg not in save_sublist: continue # in a register like ebx/rbx: it is fine where it is # else: # this is a register like eax/rax, which needs either # spilling or moving. move_or_spill.append(v) if len(move_or_spill) > 0: free_regs = [ reg for reg in self.free_regs if reg not in self.save_around_call_regs ] # chose which to spill using the usual spill heuristics while len(move_or_spill) > len(free_regs): v = self._pick_variable_to_spill([], regs=move_or_spill) self._bc_spill(v, new_free_regs) move_or_spill.remove(v) assert len(move_or_spill) <= len(free_regs) for v in move_or_spill: # search next good reg new_reg = None while True: new_reg = self.free_regs.pop() if new_reg in self.save_around_call_regs: new_free_regs.append(new_reg) # not this register... continue break assert new_reg is not None # must succeed reg = self.reg_bindings[v] self.assembler.num_moves_calls += 1 self.assembler.regalloc_mov(reg, new_reg) self.reg_bindings[v] = new_reg # change the binding new_free_regs.append(reg) # re-add registers in 'new_free_regs', but in reverse order, # so that the last ones (added just above, from # save_around_call_regs) are picked last by future '.pop()' while len(new_free_regs) > 0: self.free_regs.append(new_free_regs.pop())
def _check_type(self, v): if not we_are_translated() and self.box_types is not None: assert isinstance(v, TempVar) or v.type in self.box_types
def not_implemented(msg): msg = '[llsupport/regalloc] %s\n' % msg if we_are_translated(): llop.debug_print(lltype.Void, msg) raise NotImplementedError(msg)
def unicode_escape(s): size = len(s) result = StringBuilder(size) if quotes: if prefix: result.append(prefix) if s.find('\'') != -1 and s.find('\"') == -1: quote = ord('\"') result.append('"') else: quote = ord('\'') result.append('\'') else: quote = 0 if size == 0: return '' pos = 0 while pos < size: oc = codepoint_at_pos(s, pos) ch = s[pos] # Escape quotes if quotes and (oc == quote or ch == '\\'): result.append('\\') next_pos = next_codepoint_pos(s, pos) result.append_slice(s, pos, next_pos) pos = next_pos continue # The following logic is enabled only if MAXUNICODE == 0xffff, or # for testing on top of a host Python where sys.maxunicode == 0xffff if (not we_are_translated() and sys.maxunicode == 0xFFFF and 0xD800 <= oc < 0xDC00 and pos + 3 < size): # Map UTF-16 surrogate pairs to Unicode \UXXXXXXXX escapes pos += 3 oc2 = codepoint_at_pos(s, pos) if 0xDC00 <= oc2 <= 0xDFFF: ucs = (((oc & 0x03FF) << 10) | (oc2 & 0x03FF)) + 0x00010000 char_escape_helper(result, ucs) pos += 3 continue # Fall through: isolated surrogates are copied as-is pos -= 3 # Map special whitespace to '\t', \n', '\r' if ch == '\t': result.append('\\t') elif ch == '\n': result.append('\\n') elif ch == '\r': result.append('\\r') elif ch == '\\': result.append('\\\\') # Map non-printable or non-ascii to '\xhh' or '\uhhhh' elif pass_printable and not (oc <= 0x10ffff and unicodedb.isprintable(oc)): char_escape_helper(result, oc) elif not pass_printable and (oc < 32 or oc >= 0x7F): char_escape_helper(result, oc) # Copy everything else as-is else: if oc < 128: result.append(ch) else: next_pos = next_codepoint_pos(s, pos) result.append_slice(s, pos, next_pos) pos = next_codepoint_pos(s, pos) if quotes: result.append(chr(quote)) return result.build()
def dict_delete(d): dict_delete_entries(d.entries) lltype.free(d, flavor="raw") if not we_are_translated(): count_alloc(-1)
def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type, orig_inpargs, memo): forget_optimization_info(loop.operations) forget_optimization_info(loop.inputargs) vinfo = jitdriver_sd.virtualizable_info if vinfo is not None: vable = orig_inpargs[jitdriver_sd.index_of_virtualizable].getref_base() patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable) original_jitcell_token = loop.original_jitcell_token original_jitcell_token.number = n = metainterp_sd.jitlog.trace_id if not we_are_translated(): show_procedures(metainterp_sd, loop) loop.check_consistency() debug_info = None hooks = None if metainterp_sd.warmrunnerdesc is not None: hooks = metainterp_sd.warmrunnerdesc.hooks if hooks.are_hooks_enabled(): debug_info = JitDebugInfo(jitdriver_sd, metainterp_sd.logger_ops, original_jitcell_token, loop.operations, type, greenkey) hooks.before_compile(debug_info) else: hooks = None operations = get_deep_immutable_oplist(loop.operations) metainterp_sd.profiler.start_backend() debug_start("jit-backend") log = have_debug_prints() or jl.jitlog_enabled() try: loopname = jitdriver_sd.warmstate.get_location_str(greenkey) unique_id = jitdriver_sd.warmstate.get_unique_id(greenkey) asminfo = do_compile_loop(jitdriver_sd.index, unique_id, metainterp_sd, loop.inputargs, operations, original_jitcell_token, name=loopname, log=log, memo=memo) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() if hooks is not None: debug_info.asminfo = asminfo hooks.after_compile(debug_info) metainterp_sd.stats.add_new_loop(loop) if not we_are_translated(): metainterp_sd.stats.compiled() metainterp_sd.log("compiled new " + type) # if asminfo is not None: ops_offset = asminfo.ops_offset else: ops_offset = None metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n, type, ops_offset, name=loopname) # if metainterp_sd.warmrunnerdesc is not None: # for tests metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive( original_jitcell_token)
def assert_stack_index(self, index): if we_are_translated(): return assert self._check_stack_index(index)
continue except jitexc.DoneWithThisFrameVoid: assert result_kind == 'void' return except jitexc.DoneWithThisFrameInt, e: assert result_kind == 'int' return specialize_value(RESULT, e.result) except jitexc.DoneWithThisFrameRef, e: assert result_kind == 'ref' return specialize_value(RESULT, e.result) except jitexc.DoneWithThisFrameFloat, e: assert result_kind == 'float' return specialize_value(RESULT, e.result) except jitexc.ExitFrameWithExceptionRef, e: value = ts.cast_to_baseclass(e.value) if not we_are_translated(): raise LLException(ts.get_typeptr(value), value) else: value = cast_base_ptr_to_instance(Exception, value) raise Exception, value def handle_jitexception(e): # XXX the bulk of this function is mostly a copy-paste from above try: raise e except jitexc.ContinueRunningNormally, e: args = () for ARGTYPE, attrname, count in portalfunc_ARGS: x = getattr(e, attrname)[count] x = specialize_value(ARGTYPE, x) args = args + (x, )
def _write_barrier_fastpath(self, mc, descr, arglocs, regalloc, array=False, is_frame=False): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls a # helper piece of assembler. The latter saves registers as needed # and call the function remember_young_pointer() from the GC. if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) # card_marking_mask = 0 mask = descr.jit_wb_if_flag_singlebyte if array and descr.jit_wb_cards_set != 0: # assumptions the rest of the function depends on: assert ( descr.jit_wb_cards_set_byteofs == descr.jit_wb_if_flag_byteofs) card_marking_mask = descr.jit_wb_cards_set_singlebyte # loc_base = arglocs[0] assert loc_base.is_reg() if is_frame: assert loc_base is r.SPP assert check_imm_value(descr.jit_wb_if_flag_byteofs) mc.LLGC(r.SCRATCH2, l.addr(descr.jit_wb_if_flag_byteofs, loc_base)) mc.LGR(r.SCRATCH, r.SCRATCH2) mc.NILL(r.SCRATCH, l.imm(mask & 0xFF)) jz_location = mc.get_relative_pos() mc.reserve_cond_jump(short=True) # patched later with 'EQ' # for cond_call_gc_wb_array, also add another fast path: # if GCFLAG_CARDS_SET, then we can just set one bit and be done if card_marking_mask: # GCFLAG_CARDS_SET is in the same byte, loaded in r2 already mc.LGR(r.SCRATCH, r.SCRATCH2) mc.NILL(r.SCRATCH, l.imm(card_marking_mask & 0xFF)) js_location = mc.get_relative_pos() mc.reserve_cond_jump() # patched later with 'NE' else: js_location = 0 # Write only a CALL to the helper prepared in advance, passing it as # argument the address of the structure we are writing into # (the first argument to COND_CALL_GC_WB). helper_num = (card_marking_mask != 0) if is_frame: helper_num = 4 elif regalloc.fprm.reg_bindings: helper_num += 2 if self.wb_slowpath[helper_num] == 0: # tests only assert not we_are_translated() assert not is_frame self.cpu.gc_ll_descr.write_barrier_descr = descr self._build_wb_slowpath(card_marking_mask != 0, bool(regalloc.fprm.reg_bindings)) assert self.wb_slowpath[helper_num] != 0 # if not is_frame: mc.LGR(r.r0, loc_base) # unusual argument location mc.load_imm(r.r14, self.wb_slowpath[helper_num]) mc.BASR(r.r14, r.r14) if card_marking_mask: # The helper ends again with a check of the flag in the object. # So here, we can simply write again a beq, which will be # taken if GCFLAG_CARDS_SET is still not set. jns_location = mc.get_relative_pos() mc.reserve_cond_jump(short=True) # # patch the 'NE' above currpos = mc.currpos() pmc = OverwritingBuilder(mc, js_location, 1) pmc.BRCL(c.NE, l.imm(currpos - js_location)) pmc.overwrite() # # case GCFLAG_CARDS_SET: emit a few instructions to do # directly the card flag setting loc_index = arglocs[1] if loc_index.is_reg(): tmp_loc = arglocs[2] n = descr.jit_wb_card_page_shift assert tmp_loc is not loc_index # compute in tmp_loc the byte offset: # tmp_loc = ~(index >> (card_page_shift + 3)) mc.SRLG(tmp_loc, loc_index, l.addr(n + 3)) # invert the bits of tmp_loc # compute in SCRATCH the index of the bit inside the byte: # scratch = (index >> card_page_shift) & 7 # 0x80 sets zero flag. will store 0 into all not selected bits mc.RISBG(r.SCRATCH, loc_index, l.imm(61), l.imm(0x80 | 63), l.imm(64 - n)) mc.LGHI(r.SCRATCH2, l.imm(-1)) mc.XGR(tmp_loc, r.SCRATCH2) # set SCRATCH2 to 1 << r1 mc.LGHI(r.SCRATCH2, l.imm(1)) mc.SLLG(r.SCRATCH2, r.SCRATCH2, l.addr(0, r.SCRATCH)) # set this bit inside the byte of interest addr = l.addr(0, loc_base, tmp_loc) mc.LLGC(r.SCRATCH, addr) mc.OGRK(r.SCRATCH, r.SCRATCH, r.SCRATCH2) mc.STCY(r.SCRATCH, addr) # done else: byte_index = loc_index.value >> descr.jit_wb_card_page_shift byte_ofs = ~(byte_index >> 3) byte_val = 1 << (byte_index & 7) assert check_imm_value(byte_ofs, lower_bound=-2**19, upper_bound=2**19 - 1) addr = l.addr(byte_ofs, loc_base) mc.LLGC(r.SCRATCH, addr) mc.OILL(r.SCRATCH, l.imm(byte_val)) mc.STCY(r.SCRATCH, addr) # # patch the beq just above currpos = mc.currpos() pmc = OverwritingBuilder(mc, jns_location, 1) pmc.BRC(c.EQ, l.imm(currpos - jns_location)) pmc.overwrite() # patch the JZ above currpos = mc.currpos() pmc = OverwritingBuilder(mc, jz_location, 1) pmc.BRC(c.EQ, l.imm(currpos - jz_location)) pmc.overwrite()
def compile_loop(metainterp, greenkey, start, inputargs, jumpargs, use_unroll=True): """Try to compile a new procedure by closing the current history back to the first operation. """ metainterp_sd = metainterp.staticdata jitdriver_sd = metainterp.jitdriver_sd history = metainterp.history trace = history.trace warmstate = jitdriver_sd.warmstate # metainterp_sd.jitlog.start_new_trace(metainterp_sd, faildescr=None, entry_bridge=False) # enable_opts = jitdriver_sd.warmstate.enable_opts jitcell_token = make_jitcell_token(jitdriver_sd) cut_at = history.get_trace_position() history.record(rop.JUMP, jumpargs, None, descr=jitcell_token) if start != (0, 0, 0): trace = trace.cut_trace_from(start, inputargs) if not use_unroll: return compile_simple_loop(metainterp, greenkey, trace, jumpargs, enable_opts, cut_at) call_pure_results = metainterp.call_pure_results preamble_data = PreambleCompileData(trace, jumpargs, call_pure_results=call_pure_results, enable_opts=enable_opts) try: start_state, preamble_ops = preamble_data.optimize_trace( metainterp_sd, jitdriver_sd, metainterp.box_names_memo) except InvalidLoop: metainterp_sd.jitlog.trace_aborted() history.cut(cut_at) return None metainterp_sd = metainterp.staticdata jitdriver_sd = metainterp.jitdriver_sd start_descr = TargetToken(jitcell_token, original_jitcell_token=jitcell_token) jitcell_token.target_tokens = [start_descr] loop_data = UnrolledLoopData(trace, jitcell_token, start_state, call_pure_results=call_pure_results, enable_opts=enable_opts) try: loop_info, loop_ops = loop_data.optimize_trace( metainterp_sd, jitdriver_sd, metainterp.box_names_memo) except InvalidLoop: metainterp_sd.jitlog.trace_aborted() history.cut(cut_at) return None if ((warmstate.vec and jitdriver_sd.vec) or warmstate.vec_all) and \ metainterp.cpu.vector_ext and metainterp.cpu.vector_ext.is_enabled(): from rpython.jit.metainterp.optimizeopt.vector import optimize_vector loop_info, loop_ops = optimize_vector(trace, metainterp_sd, jitdriver_sd, warmstate, loop_info, loop_ops, jitcell_token) # loop = create_empty_loop(metainterp) loop.original_jitcell_token = jitcell_token loop.inputargs = start_state.renamed_inputargs quasi_immutable_deps = {} if start_state.quasi_immutable_deps: quasi_immutable_deps.update(start_state.quasi_immutable_deps) if loop_info.quasi_immutable_deps: quasi_immutable_deps.update(loop_info.quasi_immutable_deps) if quasi_immutable_deps: loop.quasi_immutable_deps = quasi_immutable_deps start_label = ResOperation(rop.LABEL, start_state.renamed_inputargs, descr=start_descr) label_token = loop_info.label_op.getdescr() assert isinstance(label_token, TargetToken) if label_token.short_preamble: metainterp_sd.logger_ops.log_short_preamble([], label_token.short_preamble, metainterp.box_names_memo) loop.operations = ([start_label] + preamble_ops + loop_info.extra_same_as + loop_info.extra_before_label + [loop_info.label_op] + loop_ops) if not we_are_translated(): loop.check_consistency() send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop", inputargs, metainterp.box_names_memo) record_loop_or_bridge(metainterp_sd, loop) loop_info.post_loop_compilation(loop, jitdriver_sd, metainterp, jitcell_token) return start_descr
def __init__(self, error=None): self.error = error if not we_are_translated(): Exception.__init__(self, error)
os.write(2, str + os.linesep) prebuilt_space = objspace.ObjSpace() def safe_entry_point(argv): try: return entry_point(argv) except error.Exit, e: print_error("Exited: %s" % e.msg) return -1 except error.SmalltalkException, e: print_error("Unhandled %s. Message: %s" % (e.exception_type, e.msg)) return -1 except BaseException, e: print_error("Exception: %s" % str(e)) if not objectmodel.we_are_translated(): import traceback traceback.print_exc() return -1 finally: prebuilt_space.strategy_factory.logger.print_aggregated_log() def entry_point(argv): # == Main execution parameters path = None selector = None code = "" number = 0 have_number = False stringarg = None headless = True
def operations(self): if not we_are_translated(): # For tests ops = self.short_boxes.values() ops.sort(key=str, reverse=True) return ops return self.short_boxes.values()
def isVMTranslated(interp, s_frame, w_rcvr): from rpython.rlib.objectmodel import we_are_translated if we_are_translated(): return interp.space.w_true else: return interp.space.w_false
def perform(self, executioncontext, frame): if we_are_translated(): _rawrefcount_perform(self.space)
def bigint_w(self, space, allow_conversion=True): from rpython.rlib.rbigint import rbigint x = 42 if we_are_translated(): x = NonConstant(x) return rbigint.fromint(x)
def compile(self, ctx): if we_are_translated(): raise NotImplementedError else: raise NotImplementedError(type(self).__name__)
def __init__(self, string, match_start, end, flags): FixedMatchContext.__init__(self, match_start, end, flags) self._string = string if not we_are_translated() and isinstance(string, unicode): self.flags |= rsre_char.SRE_FLAG_UNICODE # for rsre_re.py
def round_double(value, ndigits, half_even=False): """Round a float half away from zero. Specify half_even=True to round half even instead. The argument 'value' must be a finite number. This function may return an infinite number in case of overflow (only if ndigits is a very negative integer). """ if ndigits == 0: # fast path for this common case if half_even: return round_half_even(value) else: return round_away(value) if value == 0.0: return 0.0 # The basic idea is very simple: convert and round the double to # a decimal string using _Py_dg_dtoa, then convert that decimal # string back to a double with _Py_dg_strtod. There's one minor # difficulty: Python 2.x expects round to do # round-half-away-from-zero, while _Py_dg_dtoa does # round-half-to-even. So we need some way to detect and correct # the halfway cases. # a halfway value has the form k * 0.5 * 10**-ndigits for some # odd integer k. Or in other words, a rational number x is # exactly halfway between two multiples of 10**-ndigits if its # 2-valuation is exactly -ndigits-1 and its 5-valuation is at # least -ndigits. For ndigits >= 0 the latter condition is # automatically satisfied for a binary float x, since any such # float has nonnegative 5-valuation. For 0 > ndigits >= -22, x # needs to be an integral multiple of 5**-ndigits; we can check # this using fmod. For -22 > ndigits, there are no halfway # cases: 5**23 takes 54 bits to represent exactly, so any odd # multiple of 0.5 * 10**n for n >= 23 takes at least 54 bits of # precision to represent exactly. sign = copysign(1.0, value) value = abs(value) # find 2-valuation value m, expo = math.frexp(value) while m != math.floor(m): m *= 2.0 expo -= 1 # determine whether this is a halfway case. halfway_case = 0 if not half_even and expo == -ndigits - 1: if ndigits >= 0: halfway_case = 1 elif ndigits >= -22: # 22 is the largest k such that 5**k is exactly # representable as a double five_pow = 1.0 for i in range(-ndigits): five_pow *= 5.0 if math.fmod(value, five_pow) == 0.0: halfway_case = 1 # round to a decimal string; use an extra place for halfway case strvalue = formatd(value, 'f', ndigits + halfway_case) if not half_even and halfway_case: buf = [c for c in strvalue] if ndigits >= 0: endpos = len(buf) - 1 else: endpos = len(buf) + ndigits # Sanity checks: there should be exactly ndigits+1 places # following the decimal point, and the last digit in the # buffer should be a '5' if not objectmodel.we_are_translated(): assert buf[endpos] == '5' if '.' in buf: assert endpos == len(buf) - 1 assert buf.index('.') == len(buf) - ndigits - 2 # increment and shift right at the same time i = endpos - 1 carry = 1 while i >= 0: digit = ord(buf[i]) if digit == ord('.'): buf[i + 1] = chr(digit) i -= 1 digit = ord(buf[i]) carry += digit - ord('0') buf[i + 1] = chr(carry % 10 + ord('0')) carry /= 10 i -= 1 buf[0] = chr(carry + ord('0')) if ndigits < 0: buf.append('0') strvalue = ''.join(buf) return sign * rstring_to_float(strvalue)
def move_real_result_and_call_reacqgil_addr(self, fastgil): from rpython.jit.backend.x86 import rx86 # # check if we need to call the reacqgil() function or not # (to acquiring the GIL, remove the asmgcc head from # the chained list, etc.) mc = self.mc restore_edx = False if not self.asm._is_asmgcc(): css = 0 css_value = imm(0) old_value = ecx else: from rpython.memory.gctransform import asmgcroot css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) if IS_X86_32: assert css >= 16 if self.restype == 'L': # long long result: eax/edx if not self.result_value_saved_early: mc.MOV_sr(12, edx.value) restore_edx = True css_value = edx # note: duplicated in ReacqGilSlowPath old_value = ecx # elif IS_X86_64: css_value = edi old_value = esi mc.LEA_rs(css_value.value, css) # # Use XCHG as an atomic test-and-set-lock. It also implicitly # does a memory barrier. mc.MOV(old_value, imm(1)) if rx86.fits_in_32bits(fastgil): mc.XCHG_rj(old_value.value, fastgil) else: mc.MOV_ri(X86_64_SCRATCH_REG.value, fastgil) mc.XCHG_rm(old_value.value, (X86_64_SCRATCH_REG.value, 0)) mc.CMP(old_value, css_value) # gcrootmap = self.asm.cpu.gc_ll_descr.gcrootmap if bool(gcrootmap) and gcrootmap.is_shadow_stack: from rpython.jit.backend.x86.assembler import heap # # When doing a call_release_gil with shadowstack, there # is the risk that the 'rpy_fastgil' was free but the # current shadowstack can be the one of a different # thread. So here we check if the shadowstack pointer # is still the same as before we released the GIL (saved # in 'ebx'), and if not, we fall back to 'reacqgil_addr'. mc.J_il(rx86.Conditions['NE'], 0xfffff) # patched later early_jump_addr = mc.get_relative_pos(break_basic_block=False) # ^^^ this jump will go to almost the same place as the # ReacqGilSlowPath() computes, but one instruction farther, # i.e. just after the "MOV(heap(fastgil), ecx)". # here, ecx (=old_value) is zero (so rpy_fastgil was in 'released' # state before the XCHG, but the XCHG acquired it by writing 1) rst = gcrootmap.get_root_stack_top_addr() mc = self.mc mc.CMP(ebx, heap(rst)) sp = self.ReacqGilSlowPath(mc, rx86.Conditions['NE']) sp.early_jump_addr = early_jump_addr sp.fastgil = fastgil else: sp = self.ReacqGilSlowPath(mc, rx86.Conditions['NE']) sp.callbuilder = self sp.set_continue_addr(mc) self.asm.pending_slowpaths.append(sp) # if restore_edx: mc.MOV_rs(edx.value, 12) # restore this # if self.result_value_saved_early: self.restore_result_value(save_edx=True) # if not we_are_translated(): # for testing: now we can accesss mc.SUB(ebp, imm(1)) # ebp again # # Now that we required the GIL, we can reload a possibly modified ebp if self.asm._is_asmgcc(): # special-case: reload ebp from the css from rpython.memory.gctransform import asmgcroot index_of_ebp = css + WORD * (2 + asmgcroot.INDEX_OF_EBP) mc.MOV_rs(ebp.value, index_of_ebp) # MOV EBP, [css.ebp]
def check_frame(subframe): if we_are_translated(): llinterpcall(lltype.Void, check_ll_frame, subframe)
def prepare_arguments(self): src_locs = [] dst_locs = [] xmm_src_locs = [] xmm_dst_locs = [] singlefloats = None arglocs = self.arglocs argtypes = self.argtypes on_stack = 0 for i in range(len(arglocs)): loc = arglocs[i] if loc.is_float(): tgt = self._unused_xmm() if tgt is None: tgt = RawEspLoc(on_stack * WORD, FLOAT) on_stack += 1 xmm_src_locs.append(loc) xmm_dst_locs.append(tgt) elif i < len(argtypes) and argtypes[i] == 'S': # Singlefloat argument if singlefloats is None: singlefloats = [] tgt = self._unused_xmm() if tgt is None: tgt = RawEspLoc(on_stack * WORD, INT) on_stack += 1 singlefloats.append((loc, tgt)) else: tgt = self._unused_gpr(hint=loc) if tgt is None: tgt = RawEspLoc(on_stack * WORD, INT) on_stack += 1 src_locs.append(loc) dst_locs.append(tgt) if not self.fnloc_is_immediate: self.fnloc = dst_locs[-1] # the last "argument" prepared above if not we_are_translated(): # assert that we got the right stack depth floats = 0 for i in range(len(arglocs)): arg = arglocs[i] if arg.is_float() or (i < len(argtypes) and argtypes[i] == 'S'): floats += 1 all_args = len(arglocs) stack_depth = ( max(all_args - floats - len(self.ARGUMENTS_GPR), 0) + max(floats - len(self.ARGUMENTS_XMM), 0)) assert stack_depth == on_stack self.subtract_esp_aligned(on_stack - self.stack_max) # Handle register arguments: first remap the xmm arguments num_moves = remap_frame_layout(self.asm, xmm_src_locs, xmm_dst_locs, X86_64_XMM_SCRATCH_REG) # Load the singlefloat arguments from main regs or stack to xmm regs if singlefloats is not None: for src, dst in singlefloats: if isinstance(dst, RawEspLoc): # XXX too much special logic if isinstance(src, RawEbpLoc): num_moves += 2 self.mc.MOV32(X86_64_SCRATCH_REG, src) self.mc.MOV32(dst, X86_64_SCRATCH_REG) else: num_moves += 1 self.mc.MOV32(dst, src) continue if isinstance(src, ImmedLoc): num_moves += 1 self.mc.MOV(X86_64_SCRATCH_REG, src) src = X86_64_SCRATCH_REG num_moves += 1 self.mc.MOVD32(dst, src) # Finally remap the arguments in the main regs num_moves += remap_frame_layout(self.asm, src_locs, dst_locs, X86_64_SCRATCH_REG) self.num_moves = num_moves
def dict_delete_entries(entries): lltype.free(entries, flavor="raw") if not we_are_translated(): count_alloc(-1)
def mallocstr(length): ll_assert(length >= 0, "negative string length") r = malloc(TP, length) if not we_are_translated() or not malloc_zero_filled: r.hash = 0 return r