The Program class is created for each loaded program. It is responsible for executing the program on the device. As an example, here is a CPUProgram implementation which loads program and runs it.
def__init__(self,dev:CPUDevice,obj:TinyELF):self.dev,self.name,self.signature,self.profile_key=dev,obj.name,obj.signature,obj.profile_keyself.lvp=obj.target.renderer=="LVP"ifdev.remoteisnotNone:self.fxn:Any=dev.remote.rpc(RemoteCmd.LOAD_PROG,len(obj.lib),payload=obj.lib)[0]else:self.buf=dev.allocator.alloc(len(obj.lib),BufferSpec(nolru=True))loaded=self._load(obj.lib,self.buf.buf)unwrap(self.buf.host)[:len(loaded)]=loaded# RWX pages are unrepresentable on apple silicon (https://blog.svenpeter.dev/posts/m1_sprr_gxf/), so flip the written pages to R-Xlibc.mprotect(ctypes.c_void_p(self.buf.buf),len(obj.lib),libc.PROT_READ|libc.PROT_EXEC)# __clear_cache isn't a normal libc function, but a compiler support routine found in libgcc_s for gcc and compiler-rt for clang.# libgcc_s comes as shared library but compiler-rt is only a bunch of static library archives which we can't directly load, but fortunately# it somehow found its way into libSystem on macos (likely because it used __builtin_clear_cache) and libgcc_s is ~always present on linux# Using ["name"] instead of .name because otherwise name is getting mangled: https://docs.python.org/3.12/reference/expressions.html#index-5if'rt'inDLL._loaded_:CPUProgram.rt_lib["__clear_cache"](ctypes.c_void_p(self.buf.buf),ctypes.c_void_p(self.buf.buf+len(loaded)))else:# msync should be a universal POSIX way to do thislibc.msync(ctypes.c_void_p(self.buf.buf),len(loaded),libc.MS_SYNC|libc.MS_INVALIDATE)self.fxn=ctypes.CFUNCTYPE(None,ctypes.c_void_p)(self.buf.buf)
defcompile_cached(self,src:str)->bytes:ifself.cachekeyisNoneor(lib:=diskcache_get(self.cachekey,src))isNone:assertnotgetenv("ASSERT_COMPILE"),f"tried to compile with ASSERT_COMPILE set\n{src}"lib=self.compile(src)ifself.cachekeyisnotNone:diskcache_put(self.cachekey,src,lib)returnlib