WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

Commit 9e415060 authored by Kunshan Wang's avatar Kunshan Wang
Browse files

WIP: Trap handling...

parent 8a7d6825
......@@ -137,6 +137,10 @@ CMuCallConv = ctypes.c_int
MU_DEFAULT = 0x00
_MIN_SINT64 = (-1)<<63
_MAX_SINT64 = (1<<63)-1
_MAX_UINT64 = (1<<64)-1
#### High-level types which does type checking at run time.
class _LowLevelTypeWrapper(object):
......@@ -200,6 +204,31 @@ class MuTagRef64Value (MuValue): _ctype_ = CMuTagRef64Value
class MuUPtrValue (MuValue): _ctype_ = CMuUPtrValue
class MuUFPValue (MuValue): _ctype_ = CMuUFPValue
class TrapHandlerResult(object):
def __init__(self):
raise NotImplementedError()
class ThreadExit(TrapHandlerResult):
def __init__(self):
pass
class Rebind(TrapHandlerResult):
def __init__(self, stack, how_to_resume):
self.stack = stack
self.how_to_resume = how_to_resume
class HowToResume(object):
def __init__(self, *values):
raise NotImplementedError()
class PassValues(HowToResume):
def __init__(self, *values):
self.values = values
class ThrowExc(HowToResume):
def __inti__(self, exc):
self.exc = exc
class _StructOfMethodsWrapper(_LowLevelTypeWrapper):
""" High-level wrapper of "struct-of-method" types. """
......@@ -244,10 +273,100 @@ class _StructOfMethodsWrapper(_LowLevelTypeWrapper):
def __repr__(self):
return str(self)
class MuTrapHandler(object):
def handle_trap(self, ctx, thread, stack, wpid):
"""Handle trap.
This method is called when a trap is triggered by the micro VM. This
method should handle the trap and tell the micro VM thread how to
resume.
Args:
ctx: The MuCtx created by the micro VM for the trap handler to use.
The trap handler should not close it.
thread: A MuThreadRefValue of the thread that triggered the trap.
stack: A MuStackRefValue of the current stack of the thread which
triggered the trap.
wpid: The watch-point ID if the trap is triggered by a WATCHPOINT.
If it is triggered by TRAP, wpid==0.
Returns:
A TrapHandlerResult object which specifies how the thread that
caused the trap should continue. Possible values are:
ThreadExit(): The thread stops. The stack remains unbound.
Rebind(new_stack, how_to_resume): The thread re-binds to a stack.
In the case of Rebind:
new_stack: The new stack the current thread should bind to after
this trap. It may or may not be the same as the stack argument.
how_to_resume: A HowToResume object which specifies how to bind a
thread to the new_stack. Possible values are:
PassValues(values...): The stack will continue normally, and the
stack receives the list of values.
ThrowExc(exc): The stack will continue exceptionally. exc is a
MuRefValue which refers to the exception to be thrown to the
stack.
"""
raise NotImplementedError()
def _the_low_level_trap_handler(
c_ctx, c_thread, c_stack, c_wpid,
c_result, c_new_stack, c_values, c_nvalues, c_freer, c_freerdata,
c_exception,
c_userdata_key):
userdata = MuVM._user_data_exposer_.get(c_userdata_key)
muvm, trap_handler = userdata
ctx = MuCtx(c_ctx, muvm)
thread = MuThreadRefValue(c_thread, ctx)
stack = MuStackRefValue(c_stack, ctx)
wpid = c_wpid
result = trap_handler.handle_trap(ctx, thread, stack, wpid)
# TODO: handle result
return
_THE_LOW_LEVEL_TRAP_HANDLER_PTR = CMuTrapHandler(_the_low_level_trap_handler)
class _ObjectExposer(object):
def __init__(self):
self._dic = {}
self._next_key = 1
def _get_key(self):
while True:
key = self._next_key()
self._next_key = (self._next_key + 1) & _MAX_UINT64
if key not in self._dic:
break
return key
def expose(self, obj):
key = self._get_key()
self._dic[key] = obj
return key
def get(self, key):
return self._dic[key]
def unexpose(self, key):
if key in self._dic:
del self._dic[key]
class MuVM(_StructOfMethodsWrapper):
_c_struct_type_ = CMuVM
_ctype_ = ctypes.POINTER(_c_struct_type_)
_user_data_exposer_ = _ObjectExposer()
def __init__(self, struct_ptr, dll):
super(self.__class__, self).__init__(struct_ptr, dll)
......@@ -255,15 +374,34 @@ class MuVM(_StructOfMethodsWrapper):
self._mu_error_addr = self._low_level_func("get_mu_error_ptr_")(struct_ptr)
self._mu_error = ctypes.c_int.from_address(self._mu_error_addr)
self._cur_user_data_key = None
# Mu writes to the memory location self._mu_error_addr when it throws an
# exception before returning to C.
def get_mu_error(self):
return self._mu_error.value
def set_mu_error(self, v):
self._mu_error.value = v
_MIN_SINT64 = (-1)<<63
_MAX_SINT64 = (1<<63)-1
_MAX_UINT64 = (1<<64)-1
## The following overrides the C functions to make them more Pythonic
def set_trap_handler(self, trap_handler):
"""Set the trap handler of this MuVM.
trap_handler is a Python MuTrapHandler object.
"""
userdata = (self, trap_handler)
old_key = self._cur_user_data_key
new_key = self._user_data_exposer_.expose(userdata)
self.set_trap_handler_(_THE_LOW_LEVEL_TRAP_HANDLER_PTR, new_key)
self._user_data_exposer_.unexpose(old_key)
self._cur_user_data_key = new_key
class MuCtx(_StructOfMethodsWrapper):
_c_struct_type_ = CMuCtx
......@@ -285,7 +423,7 @@ class MuCtx(_StructOfMethodsWrapper):
self.close_context()
## The following extends the C functions to make it more Pythonic
## The following overrides the C functions to make them more Pythonic
def load_bundle(self, bundle_str):
_assert_instance(bundle_str, str, unicode)
......@@ -343,6 +481,26 @@ class MuCtx(_StructOfMethodsWrapper):
def fence(self, ord=MU_SEQ_CST):
return self.fence_(ord)
def new_thread(self, stack, how_to_resume):
_assert_instance(how_to_resume, HowToResume)
if isinstance(how_to_resume, PassValues):
htr = MU_REBIND_PASS_VALUES
values = how_to_resume.values
cvals_ty = CMuValue * len(values)
cvals = cvals_ty()
for i,v in enumerate(values):
cvals[i] = v.c_mu_value
cnvals = len(values)
cexc = 0
else:
htr = MU_REBIND_THROW_EXC
exc = how_to_resume.exc
cvals = None
cnvals = 0
cexc = exc.c_mu_value
return self.new_thread_(stack, htr, cvals, cnvals, cexc)
def _to_low_level_type(ty):
return (None if ty == None else
ty._ctype_ if issubclass(ty, _LowLevelTypeWrapper) else
......@@ -518,7 +676,8 @@ _initialize_methods(MuCtx, [
("fence_" , None , [CMuMemOrd]),
("new_stack" , MuStackRefValue , [MuFuncRefValue]),
("new_thread" , MuThreadRefValue , [MuStackRefValue, CMuHowToResume, MuValue, ctypes.c_int, MuRefValue]),
("new_thread_" , MuThreadRefValue , [MuStackRefValue, CMuHowToResume,
ctypes.POINTER(CMuValue), ctypes.c_int, CMuRefValue]),
("kill_stack" , None , [MuStackRefValue]),
("new_cursor" , MuFCRefValue , [MuStackRefValue]),
......
......@@ -39,6 +39,16 @@ with mu.new_context() as ctx:
.const @V1 <@4xi32> = {@I32_11 @I32_12 @I32_13 @I32_14}
.typedef @h1 = hybrid<@i32 @i64 @i8>
.global @main_rv <@i32>
.funcsig @main.sig = (@i32) -> ()
.funcdef @main VERSION %v1 <@main.sig> {
%entry(<@i32> %n):
%n2 = ADD <@i32> %n @I32_1
STORE <@i32> @main_rv %n2
COMMINST @uvm.thread_exit
}
""")
class TestRefImpl2CBinding(unittest.TestCase):
......@@ -200,3 +210,20 @@ class TestRefImpl2CBinding(unittest.TestCase):
self.assertEqual(v3, 200)
self.assertEqual(v4, 500)
def test_stack_thread(self):
ctx = self.ctx
id_of = ctx.id_of
forty_two = ctx.handle_from_int(42, 32)
main = ctx.handle_from_func(id_of("@main"))
st = ctx.new_stack(main)
th = ctx.new_thread(st, PassValues(forty_two))
mu.execute()
loc = ctx.handle_from_global(id_of("@main_rv"))
hv = ctx.load(loc).cast(MuIntValue)
v = ctx.handle_to_sint(hv)
self.assertEqual(v, 43)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment