def switch_to_smalltalk(self, interp, s_frame, first_call=False): self.post_resume() log('Switching to Smalltalk...') if self.is_done(): return self._create_return_frame(interp.space) # import pdb; pdb.set_trace() if first_call: # attach s_frame with resume method for the first time s_resume_frame = self._build_resume_method(interp.space, is_eval=True) s_resume_frame.store_s_sender(s_frame) elif s_frame.w_method() is self.resume_method.get(): s_resume_frame = self._build_resume_method(interp.space) eval_frame = s_frame.s_sender() # Ensure #resume: method with closure = nil if (eval_frame.w_method() is self.eval_method.get() and eval_frame.closure is not None): # instead of chaining resume frames, store original sender s_resume_frame.store_s_sender(eval_frame) else: print('Unexpected eval_frame found:\n%s' % s_frame.print_stack()) s_resume_frame.store_s_sender(s_frame) else: print 'Unexpected s_frame found:\n%s' % s_frame.print_stack() s_resume_frame = s_frame interp.quick_check_for_interrupt(s_resume_frame, dec=interp.interrupt_counter_size) # this will raise a ProcessSwitch if there are interrupts or timers ... return s_resume_frame
def _create_return_frame(self, space): from rsqueakvm.storage_contexts import ContextPartShadow log('Language has finished and returned a result.') # we want evalInThread and resumePython to return new frames, # so we don't build up stack, but we also don't raise to the # top-level loop all the time. # For resuming, we obviously need a new frame, because that's # how the Smalltalk scheduler knows how to continue back to Python. # Unfortunately, a primitive can only EITHER always return a new # frame OR a result. So when we get a result, we cannot simply # return it. Instead, we need to build a frame that simply returns # the result if space.is_spur.is_set(): w_cm = objectmodel.instantiate(W_SpurCompiledMethod) else: w_cm = objectmodel.instantiate(W_PreSpurCompiledMethod) w_resume_class = self.foreign_process_class() w_cm.header = 0 w_cm._primitive = 0 w_cm.literalsize = 3 w_cm.islarge = False w_cm._tempsize = 0 w_cm.argsize = 0 w_cm.compiledin_class = w_resume_class.getclass(space) w_cm.lookup_selector = 'fakeReturnResult' w_cm.bytes = [ chr(b) for b in [ 0x20, # push constant 0x7C, # return stack top ] ] w_cm.literals = [self.get_result(), space.w_nil, w_cm.compiledin_class] return ContextPartShadow.build_method_context(space, w_cm, w_resume_class)
def switch_to_smalltalk(self, interp, s_frame, first_call=False): self.post_resume() log('Switching to Smalltalk...') if self.is_done(): return self._create_return_frame(interp.space) # import pdb; pdb.set_trace() if first_call: # attach s_frame with resume method for the first time s_resume_frame = self._build_resume_method( interp.space, is_eval=True) s_resume_frame.store_s_sender(s_frame) elif s_frame.w_method() is self.resume_method.get(): s_resume_frame = self._build_resume_method(interp.space) eval_frame = s_frame.s_sender() # Ensure #resume: method with closure = nil if (eval_frame.w_method() is self.eval_method.get() and eval_frame.closure is not None): # instead of chaining resume frames, store original sender s_resume_frame.store_s_sender(eval_frame) else: print ('Unexpected eval_frame found:\n%s' % s_frame.print_stack()) s_resume_frame.store_s_sender(s_frame) else: print 'Unexpected s_frame found:\n%s' % s_frame.print_stack() s_resume_frame = s_frame interp.quick_check_for_interrupt(s_resume_frame, dec=interp.interrupt_counter_size) # this will raise a ProcessSwitch if there are interrupts or timers ... return s_resume_frame
def _create_return_frame(self, space): from rsqueakvm.storage_contexts import ContextPartShadow log('Language has finished and returned a result.') # we want evalInThread and resumePython to return new frames, # so we don't build up stack, but we also don't raise to the # top-level loop all the time. # For resuming, we obviously need a new frame, because that's # how the Smalltalk scheduler knows how to continue back to Python. # Unfortunately, a primitive can only EITHER always return a new # frame OR a result. So when we get a result, we cannot simply # return it. Instead, we need to build a frame that simply returns # the result if space.is_spur.is_set(): w_cm = objectmodel.instantiate(W_SpurCompiledMethod) else: w_cm = objectmodel.instantiate(W_PreSpurCompiledMethod) w_resume_class = self.foreign_process_class() w_cm.header = 0 w_cm._primitive = 0 w_cm.literalsize = 3 w_cm.islarge = False w_cm._tempsize = 0 w_cm.argsize = 0 w_cm.compiledin_class = w_resume_class.getclass(space) w_cm.lookup_selector = 'fakeReturnResult' w_cm.bytes = [chr(b) for b in [ 0x20, # push constant 0x7C, # return stack top ]] w_cm.literals = [self.get_result(), space.w_nil, w_cm.compiledin_class] return ContextPartShadow.build_method_context( space, w_cm, w_resume_class)
def _switch_to_handle(self): if not self._has_valid_handle(): print 'handle not valid: %s' % self.handle return self.handle = self.sthread.switch(self.handle) if self.handle is self.sthread.get_null_handle(): log('language_process thread has finished (handle is null)') if self.sthread.is_empty_handle(self.handle): log('language_process thread has finished (handle is empty)')
def setup(self): try: self.counter_size.set( int(os.environ.get('TOPAZ_CHECK_INTERVAL') or '10000')) self.interrupts_disabled.set( bool(os.environ.get('TOPAZ_DISABLE_INTERRUPTS'))) except: pass if self.interrupts_disabled.get(): log('TOPAZ_DISABLE_INTERRUPTS set.') else: log('TOPAZ_CHECK_INTERVAL set to %s.' % self.counter_size.get())
def setup(self): try: self.counter_size.set(int( os.environ.get('TOPAZ_CHECK_INTERVAL') or '10000')) self.interrupts_disabled.set(bool( os.environ.get('TOPAZ_DISABLE_INTERRUPTS'))) except: pass if self.interrupts_disabled.get(): log('TOPAZ_DISABLE_INTERRUPTS set.') else: log('TOPAZ_CHECK_INTERVAL set to %s.' % self.counter_size.get())
def new_stacklet_callback(h, arg): log('new_stacklet_callback: %s' % h) self = global_execution_state.origin self.handle = h global_execution_state.clear() # stacklets start immediate, so yield back before executing any code, # code is only executed when the resume primitive is used, # eval primitive only creates a new language process self.return_to_smalltalk() self.language_process().safe_run() global_execution_state.origin = self return self.handle # return to Smalltalk when done
def get_restart_pycode(source, filename='<string>', cmd='exec'): log('Trying to patch:\n%s' % source) try: py_code = py_compiling.compile(py_space, py_space.newtext(source), filename, cmd) if not isinstance(py_code, PyCode): print 'py_code not an instance of PyCode' return if cmd == 'eval': return py_code co_consts_w_len = len(py_code.co_consts_w) if co_consts_w_len >= 1: if co_consts_w_len > 1: log('More than 1 const produced: %s' % co_consts_w_len) first_consts_w = py_code.co_consts_w[0] if not isinstance(first_consts_w, PyCode): log('First const is not a PyCode') return py_code return first_consts_w except OperationError as e: # import pdb; pdb.set_trace() print 'Failed to compile new frame: %s' % e.errorstr(py_space)
def __init__(self, language_process): log('Starting %s...' % language_process) self._language_process = language_process
def resume(self): log('Resuming %s...' % self.language_process()) self.language_process().pre_resume() self._resume_thread()