Reattaching imported functions
Closed this issue · 2 comments
I call a runtime instance several times, but each time I need to reattach env functions (because apparently, the old ones refer to outdated data). On first try
runtime.imps = newimps
does not seem to work. Is this possible? I'd prefer to do this without having to reload the entire runtime (which would necessitate loading the .wasm binary from the filessystem again etc.)
You should directly modify the relevant elements in the store object, because WebAssembly has an initialization step, and the imps parameter will not be used after this step.
https://github.com/mohanson/pywasm/blob/master/pywasm/execution.py#L296
https://github.com/mohanson/pywasm/blob/master/pywasm/execution.py#L205
But I don't approve of this usage. You may be able to add a reset()
function, or some other things, to solve it at the application layer.
My problem is that the functions need to refer to some data in an object distance, which may be different for every invocation.
Because there may be many threads/interleaved invocations of several interpreters, I can't declare this instance to be global inside the function. I tried the nonlocal keyword, but it seems to refer to the old data anyway, it is apparently bound when the function is defined.
I also can't reinstantiate the Runtime because I need the memory to be preserved.
I'll try to modify it directly. Update:
import pywasm
data = board = legal = None
def env_abort(_: pywasm.Ctx):
return
def env_board(ctx: pywasm.Ctx, index: int):
return data[index]
def env_rights(ctx: pywasm.Ctx):
r_3f = int(board.can_claim_threefold_repetition())
r_50 = int(board.can_claim_fifty_moves())
r_K = int(board.has_kingside_castling_rights(chess.WHITE))
r_Q = int(board.has_queenside_castling_rights(chess.WHITE))
r_k = int(board.has_kingside_castling_rights(chess.WHITE))
r_q = int(board.has_queenside_castling_rights(chess.WHITE))
if board.has_legal_en_passant():
epdata = board.ep_square
else:
epdata = 0
return r3f << 6 | r_50 << 5 | epdata << 4 | r_K << 3 | r_Q << 2 | r_k << 1 | r_q
def env_randint(ctx: pywasm.Ctx, max: int):
return randint(0, max-1)
print("OUTSIDE", legal)
def env_legal(ctx: pywasm.Ctx, index: int):
print("INSIDE", legal)
return legal[index]
def env_maxlegal(ctx: pywasm.Ctx):
return len(legal)
def env_color(ctx: pywasm.Ctx):
return 1 if board.turn == chess.WHITE else 0
def env_log(ctx: pywasm.Ctx, msg: int):
print("Msg", msg)
return 0
imps = {
'env': {
'abort': env_abort,
"color": env_color,
"board": env_board,
"rights": env_rights,
"maxlegal": env_maxlegal,
"randint": env_randint,
"legal": env_legal,
"log": env_log
}
}
# Update data (only for visualization purposes)
data = board = legal = 1
# Redefine functions
def env_maxlegal(ctx: pywasm.Ctx):
return len(legal)
# [...]
runtime = "players/b/random.wasm"
runtime = pywasm.load(runtime, imps)
for index, thing in enumerate(runtime.store.function_list):
if isinstance(thing, pywasm.execution.HostFunc):
runtime.store.function_list[index].hostcode = locals()[thing.hostcode.__name__]
I'm sorry you had to witness this absolute hack, haha
It works! Thank you :)