@@ -798,7 +798,15 @@ def fullname(cls):
798798
799799 self .stages_info = self .bmSuite .stages_info
800800 assert not self .stages_info .failed , "In case of a failed benchmark, no further calls into the VM should be made"
801- assert self .stages_info .vm_used_for_stages == self , f"VM used to prepare stages ({ self .stages_info .vm_used_for_stages } ) cannot be different from the VM used to run the suite ({ self } )!"
801+ vm_used_for_stages = self .stages_info .vm_used_for_stages
802+ same_vm = vm_used_for_stages == self
803+ host_and_guest_used = (
804+ isinstance (vm_used_for_stages , mx_benchmark .GuestVm )
805+ and vm_used_for_stages .host_vm () == self
806+ )
807+ assert same_vm or host_and_guest_used , (
808+ f"VM used to prepare stages ({ vm_used_for_stages } ) cannot be different from the VM used to run the suite ({ self } )!"
809+ )
802810
803811 def get_required_benchmark_suite_mixin_class (self ):
804812 return StageAwareBenchmarkMixin
@@ -2062,6 +2070,120 @@ def get_stage_runner(self) -> SimpleStageRunner:
20622070 return SimpleStageRunner (self .stages_info , self .bmSuite , self .stages_context )
20632071
20642072
2073+ class PolyBenchEmscriptenHostVm (PolyBenchStagingVm ):
2074+ """Host VM that implements Emscripten used for running staged PolyBench programs through a guest-provided launcher."""
2075+ def run_stage_run (self ):
2076+ vm = bm_exec_context ().get ("vm" )
2077+ if not isinstance (vm , PolyBenchEmscriptenGuestVm ):
2078+ mx .abort (f"{ self .__class__ .__name__ } expects a PolyBenchEmscriptenGuestVm guest VM in the execution context." )
2079+ if vm .host_vm () != self :
2080+ mx .abort (f"Guest VM '{ vm .name ()} :{ vm .config_name ()} ' is not hosted by '{ self .name ()} :{ self .config_name ()} '." )
2081+
2082+ guest_launcher = vm .guest_launcher (self )
2083+ if not Path (guest_launcher ).is_file ():
2084+ raise ValueError (f"Guest launcher '{ guest_launcher } ' does not resolve to a file!" )
2085+ with self .get_stage_runner () as s :
2086+ cmd = [self .launcher , guest_launcher , str (self .staged_program_file_path )]
2087+ s .execute_command (self , cmd )
2088+
2089+
2090+ class PolyBenchEmscriptenGuestVm (mx_benchmark .GuestVm ):
2091+ """Abstract PolyBench Guest VM entry for running on an Emscripten host VM."""
2092+ def __init__ (self , host_vm = None ):
2093+ super ().__init__ (host_vm )
2094+ self ._guest_run_on_java_home_value = None
2095+ self ._guest_run_on_java_home_set = False
2096+
2097+ def guest_launcher (self , host_vm : PolyBenchEmscriptenHostVm ) -> str :
2098+ """
2099+ Return the launcher executable that the Emscripten host should invoke for this guest.
2100+ The returned path must resolve to a file and is used as the first command element.
2101+ """
2102+ raise NotImplementedError ()
2103+
2104+ def set_run_on_java_home (self , value ):
2105+ self ._guest_run_on_java_home_value = value
2106+ self ._guest_run_on_java_home_set = True
2107+ host = self .host_vm ()
2108+ if host is not None and hasattr (host , "set_run_on_java_home" ):
2109+ host .set_run_on_java_home (value )
2110+
2111+ def run_on_java_home (self ):
2112+ if self ._guest_run_on_java_home_set :
2113+ return self ._guest_run_on_java_home_value
2114+ host = self .host_vm ()
2115+ if host is not None and hasattr (host , "run_on_java_home" ):
2116+ return host .run_on_java_home ()
2117+ return None
2118+
2119+
2120+ class PolyBenchPyodideGuestVm (PolyBenchEmscriptenGuestVm ):
2121+ """
2122+ Guest VM entry for Pyodide running on an Emscripten host VM.
2123+ Relies on the PYODIDE_BOOTSTRAP env var to point to the Pyodide bootstrap module.
2124+ """
2125+ HOSTED_INSTANCE = "PolyBenchPyodideGuestVm.hosted="
2126+ BOOTSTRAP_LAUNCHER = "$PYODIDE_BOOTSTRAP"
2127+
2128+ def __init__ (self , config_name , extra_java_args = None , extra_launcher_args = None , host_vm = None ):
2129+ super ().__init__ (host_vm )
2130+ self ._config_name = self .canonical_config_name (config_name )
2131+
2132+ def name (self ):
2133+ return "pyodide"
2134+
2135+ def config_name (self ):
2136+ return self ._config_name
2137+
2138+ def with_host_vm (self , host_vm ):
2139+ hosted_name = f"{ self .HOSTED_INSTANCE } { self .name ()} :{ self .config_name ()} @{ host_vm .name ()} :{ host_vm .config_name ()} "
2140+ if not bm_exec_context ().has (hosted_name ):
2141+ # Ensure the selected host VM is actually attached to the guest VM instance
2142+ hosted_instance = self .__class__ (self .config_name (), host_vm = host_vm )
2143+ bm_exec_context ().add_context_value (hosted_name , ConstantContextValue (hosted_instance ))
2144+ hosted_instance = bm_exec_context ().get (hosted_name )
2145+ if self ._guest_run_on_java_home_set :
2146+ hosted_instance .set_run_on_java_home (self ._guest_run_on_java_home_value )
2147+ return hosted_instance
2148+
2149+ @staticmethod
2150+ def canonical_config_name (config_name ):
2151+ return config_name if config_name else "default"
2152+
2153+ def hosting_registry (self ):
2154+ return mx_benchmark .java_vm_registry
2155+
2156+ def guest_launcher (self , host_vm : PolyBenchEmscriptenHostVm ) -> str :
2157+ """
2158+ Return the custom bootstrap script that starts a JavaScript module inside the
2159+ selected Emscripten host and forwards the staged Python benchmark into Pyodide.
2160+ Pyodide is embedded in that Emscripten environment rather than exposed as a
2161+ standalone terminal launcher, so the benchmark needs this adapter entry point.
2162+ """
2163+ return PolyBenchStagingVm ._resolve_possible_env_var (self .BOOTSTRAP_LAUNCHER )
2164+
2165+ def _host_vm_for_execution (self ) -> PolyBenchEmscriptenHostVm :
2166+ host = self .host_vm ()
2167+ if host is None :
2168+ mx .abort ("Pyodide guest VM requires a host VM; none was provided." )
2169+ if not isinstance (host , PolyBenchEmscriptenHostVm ):
2170+ mx .abort (f"Pyodide guest VM requires PolyBenchEmscriptenHostVm host; got { host .__class__ .__name__ } ." )
2171+ return host
2172+
2173+ def run (self , cwd , args ):
2174+ host = self ._host_vm_for_execution ()
2175+ return host .runWithSuite (self .bmSuite , cwd , args )
2176+
2177+ def prepare_stages (self , bm_suite : NativeImageBenchmarkMixin , bm_suite_args ):
2178+ host = self ._host_vm_for_execution ()
2179+ effective_stages , complete_stage_list = host .prepare_stages (bm_suite , bm_suite_args )
2180+ return effective_stages , complete_stage_list
2181+
2182+ def runWithSuite (self , bmSuite , cwd , args ):
2183+ host = self ._host_vm_for_execution ()
2184+ return host .runWithSuite (bmSuite , cwd , args )
2185+
2186+
20652187class GraalHostPolyBenchStagingVm (PolyBenchStagingVm ):
20662188 """
20672189 Stages a PolyBench benchmark and configures a GraalHost boot script that runs the benchmark.
@@ -2207,6 +2329,8 @@ def register_graalvm_vms():
22072329 mx_benchmark .add_java_vm (PolyBenchStagingVm ('cpython' , 'default' , "Python" , "python" , "py" ), _suite , 2 )
22082330 mx_benchmark .add_java_vm (PolyBenchStagingVm ('cpython' , 'graalos-ee' , "Python" , "$GRAALOS_CPYTHON" , "py" ), _suite , 2 )
22092331 mx_benchmark .add_java_vm (GraalHostPolyBenchStagingVm ('cpython' , 'graalhost-graalos-ee' , "Python" , "$GRAALOS_CPYTHON" , "py" ), _suite , 2 )
2332+ mx_benchmark .add_java_vm (PolyBenchEmscriptenHostVm ('nodejs' , 'default' , "Python" , "node" , "py" ), _suite , 2 )
2333+ mx_benchmark .add_java_vm (PolyBenchPyodideGuestVm ('default' ), _suite , 2 )
22102334
22112335
22122336class ObjdumpSectionRule (mx_benchmark .StdOutRule ):
0 commit comments