Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[browser] Bundle assets inside of wasm file #103160

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 46 additions & 25 deletions src/mono/browser/build/BrowserWasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,24 @@
<ProjectCapability Include="DotNetCoreWeb"/>
</ItemGroup>

<Target Name="_GetWasmGenerateAppBundleDependencies">
<Target Name="_BrowserFindIcuToUse">
<ItemGroup Condition="'$(InvariantGlobalization)' != 'true'">
<_HybridGlobalizationDataFiles Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt_hybrid.dat"/>
<_HybridGlobalizationDataFiles Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)segmentation-rules.json"/>
<_IcuAvailableDataFiles Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt_*" Exclude="@(_HybridGlobalizationDataFiles);$(_WasmIcuDataFileName)"/>
<WasmIcuDataFileNames Condition="@(WasmIcuDataFileNames->Count()) == 0 and '$(HybridGlobalization)' == 'true'" Include="@(_HybridGlobalizationDataFiles)"/>
<WasmIcuDataFileNames Condition="@(WasmIcuDataFileNames->Count()) == 0 and '$(WasmIncludeFullIcuData)' == 'true'" Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt.dat"/>
<WasmIcuDataFileNames Condition="@(WasmIcuDataFileNames->Count()) == 0 and '$(_WasmIcuDataFileName)' != ''" Include="$(_WasmIcuDataFileName)"/>
<WasmIcuDataFileNames Condition="@(WasmIcuDataFileNames->Count()) == 0 and '$(WasmSingleFileBundle)' == 'true'" Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt.dat"/>
<WasmIcuDataFileNames Condition="@(WasmIcuDataFileNames->Count()) == 0" Include="@(_IcuAvailableDataFiles)"/>
<WasmNativeAsset Include="@(WasmIcuDataFileNames)" Condition="'$(WasmSingleFileBundle)' != 'true'" />
</ItemGroup>

<Error Condition="'$(InvariantGlobalization)' != 'true' and '$(WasmIncludeFullIcuData)' != 'true' and '$(WasmIcuDataFileName)' != '' and !Exists('$(_WasmIcuDataFileName)')" Text="File in location %24(WasmIcuDataFileName)=$(WasmIcuDataFileName) cannot be found neither when used as absolute path nor a relative runtime pack path. You might want to pass one of the values: @(_IcuAvailableDataFiles->'%(Filename)')."/>
<Error Condition="'$(InvariantGlobalization)' != 'true' and '$(WasmIncludeFullIcuData)' != 'true' and '$(WasmIcuDataFileName)' != '' and !$([System.IO.Path]::GetFileName('$(WasmIcuDataFileName)').StartsWith('icudt'))" Text="Custom ICU file name in path %24(WasmIcuDataFileName)=$(WasmIcuDataFileName) must start with 'icudt'."/>
</Target>

<Target Name="_GetWasmGenerateAppBundleDependencies" DependsOnTargets="_BrowserFindIcuToUse">
<Warning Condition="'$(InvariantGlobalization)' == 'true' and '$(HybridGlobalization)' == 'true'" Text="%24(HybridGlobalization) has no effect when %24(InvariantGlobalization) is set to true." />
<Warning Condition="'$(WasmIcuDataFileName)' != '' and '$(HybridGlobalization)' == 'true'" Text="%24(WasmIcuDataFileName) has no effect when %24(HybridGlobalization) is set to true." />
<Warning Condition="'$(InvariantGlobalization)' != 'true' and '$(WasmIncludeFullIcuData)' == 'true' and '$(WasmIcuDataFileName)' != ''" Text="%24(WasmIcuDataFileName) has no effect when %24(WasmIncludeFullIcuData) is set to true." />
Expand Down Expand Up @@ -99,20 +116,6 @@
<WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.runtime.js.map"
Condition="'$(WasmEmitSourceMap)' != 'false'" />
</ItemGroup>

<ItemGroup Condition="'$(InvariantGlobalization)' != 'true'">
<_HybridGlobalizationDataFiles Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt_hybrid.dat"/>
<_HybridGlobalizationDataFiles Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)segmentation-rules.json"/>
<_IcuAvailableDataFiles Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt_*" Exclude="@(_HybridGlobalizationDataFiles);$(_WasmIcuDataFileName)"/>
<WasmIcuDataFileNames Condition="'$(HybridGlobalization)' == 'true'" Include="@(_HybridGlobalizationDataFiles)"/>
<WasmIcuDataFileNames Condition="'$(HybridGlobalization)' != 'true' and '$(WasmIncludeFullIcuData)' == 'true'" Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt.dat"/>
<WasmIcuDataFileNames Condition="'$(HybridGlobalization)' != 'true' and '$(WasmIncludeFullIcuData)' != 'true' and '$(_WasmIcuDataFileName)' == ''" Include="@(_IcuAvailableDataFiles)"/>
<WasmIcuDataFileNames Condition="'$(HybridGlobalization)' != 'true' and '$(WasmIncludeFullIcuData)' != 'true' and '$(_WasmIcuDataFileName)' != ''" Include="$(_WasmIcuDataFileName)"/>
<WasmNativeAsset Include="@(WasmIcuDataFileNames)"/>
</ItemGroup>

<Error Condition="'$(InvariantGlobalization)' != 'true' and '$(WasmIncludeFullIcuData)' != 'true' and '$(WasmIcuDataFileName)' != '' and !Exists('$(_WasmIcuDataFileName)')" Text="File in location %24(WasmIcuDataFileName)=$(WasmIcuDataFileName) cannot be found neither when used as absolute path nor a relative runtime pack path. You might want to pass one of the values: @(_IcuAvailableDataFiles->'%(Filename)')."/>
<Error Condition="'$(InvariantGlobalization)' != 'true' and '$(WasmIncludeFullIcuData)' != 'true' and '$(WasmIcuDataFileName)' != '' and !$([System.IO.Path]::GetFileName('$(WasmIcuDataFileName)').StartsWith('icudt'))" Text="Custom ICU file name in path %24(WasmIcuDataFileName)=$(WasmIcuDataFileName) must start with 'icudt'."/>
</Target>

<Target Name="_WasmGenerateAppBundle"
Expand All @@ -137,6 +140,7 @@
AppDir="$(WasmAppDir)"
Assemblies="@(_WasmAssembliesInternal)"
MainAssemblyName="$(WasmMainAssemblyFileName)"
IsSingleFileBundle="$(WasmSingleFileBundle)"
HostConfigs="@(HostConfig)"
RuntimeArgsForHost="@(WasmMonoRuntimeArgs)"
DefaultHostConfig="$(DefaultWasmHostConfig)"
Expand Down Expand Up @@ -232,7 +236,7 @@
</PropertyGroup>
</Target>

<Target Name="_PrepareForBrowserWasmBuildNative">
<Target Name="_PrepareForBrowserWasmBuildNative" DependsOnTargets="_BrowserFindIcuToUse">
<Error Condition="'$(_IsToolchainMissing)' == 'true'"
Text="$(_ToolchainMissingErrorMessage) Emscripten SDK is required for building native files." />

Expand Down Expand Up @@ -285,6 +289,7 @@
<WasmAllowUndefinedSymbols Condition="'$(WasmAllowUndefinedSymbols)' == ''">false</WasmAllowUndefinedSymbols>

<WasmClang>$(EmscriptenUpstreamEmscriptenPath)emcc</WasmClang>
<WasmClang Condition="$([MSBuild]::IsOSPlatform('Windows'))">$(WasmClang).bat</WasmClang>
</PropertyGroup>

<ItemGroup>
Expand All @@ -309,6 +314,7 @@
<_EmccCFlags Include="-DDISABLE_PERFTRACING_LISTEN_PORTS=1" />
<_EmccCFlags Include="-DENABLE_AOT=1" Condition="'$(_WasmShouldAOT)' == 'true'" />
<_EmccCFlags Include="-DDRIVER_GEN=1" Condition="'$(_WasmShouldAOT)' == 'true'" />
<_EmccCFlags Include="-DWASM_SINGLE_FILE=1" Condition="'$(WasmSingleFileBundle)' == 'true'" />
<_EmccCFlags Include="-DINVARIANT_GLOBALIZATION=1" Condition="'$(InvariantGlobalization)' == 'true'" />
<_EmccCFlags Include="-DINVARIANT_TIMEZONE=1" Condition="'$(InvariantTimezone)' == 'true'" />
<_EmccCFlags Include="-DLINK_ICALLS=1" Condition="'$(WasmLinkIcalls)' == 'true'" />
Expand Down Expand Up @@ -389,15 +395,15 @@
BundleFile="wasm_bundled_assemblies.o" />

<!-- TODO for single file bundle -->
<!--<_WasmBundleItem-->
<!--Include="@(WasmIcuDataFileNames)"-->
<!--BundleRegistrationFunctionName="mono_register_icu_bundle"-->
<!--BundleFile="wasm_bundled_icu.o" />-->

<!--<_WasmBundleItem-->
<!--Include="$(_ParsedRuntimeConfigFilePath)"-->
<!--BundleRegistrationFunctionName="mono_register_runtimeconfig_bin"-->
<!--BundleFile="wasm_bundled_runtimeconfig_bin.o" />-->
<_WasmBundleItem
Include="@(WasmIcuDataFileNames)"
BundleRegistrationFunctionName="mono_register_icu_bundle"
BundleFile="wasm_bundled_icu.o" />

<_WasmBundleItem
Include="$(_ParsedRuntimeConfigFilePath)"
BundleRegistrationFunctionName="mono_register_runtimeconfig_bin"
BundleFile="wasm_bundled_runtimeconfig_bin.o" />
</ItemGroup>

<MakeDir Directories="$(WasmCachePath)" Condition="'$(WasmCachePath)' != '' and !Exists($(WasmCachePath))" />
Expand All @@ -420,6 +426,21 @@
</ItemGroup>
</Target>

<Target Name="_BrowserWasmIcuFileName" BeforeTargets="_BrowserWasmWriteRspForLinking" DependsOnTargets="_BrowserFindIcuToUse" Condition="'$(WasmSingleFileBundle)' == 'true' and @(WasmIcuDataFileNames->Count()) == 1">
<PropertyGroup>
<_BrowserGetIcuFileName>$(_WasmIntermediateOutputPath)icufilename_$(WasmMainAssemblyFileName).c</_BrowserGetIcuFileName>
</PropertyGroup>
<WriteLinesToFile File="$(_BrowserGetIcuFileName)"
Overwrite="true"
Condition="'$(WasmSingleFileBundle)' == 'true'"
Lines="const char* dotnet_browser_geticufilename() { return &quot;%(WasmIcuDataFileNames.FileName)%(WasmIcuDataFileNames.Extension)&quot;%3B }"
WriteOnlyWhenDifferent="true" />
<ItemGroup>
<FileWrites Include="$(_BrowserGetIcuFileName)" />
<_WasmNativeFileForLinking Include="$(_BrowserGetIcuFileName)" />
</ItemGroup>
</Target>

<Target Name="_BrowserWasmWriteRspForLinking" BeforeTargets="_WasmWriteRspForLinking">
<PropertyGroup>
<_WasmEHLib Condition="'$(WasmEnableExceptionHandling)' == 'true'">libmono-wasm-eh-wasm.a</_WasmEHLib>
Expand Down
55 changes: 52 additions & 3 deletions src/mono/browser/runtime/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ char *mono_method_get_full_name (MonoMethod *method);
#ifndef INVARIANT_TIMEZONE
extern void mono_register_timezones_bundle (void);
#endif /* INVARIANT_TIMEZONE */
#ifdef WASM_SINGLE_FILE
extern void mono_register_assemblies_bundle (void);
extern void mono_register_runtimeconfig_bin (void);
extern mono_bool mono_bundled_resources_get_data_resource_values (const char *id, const uint8_t **data_out, uint32_t *size_out);
#ifndef INVARIANT_GLOBALIZATION
extern void mono_register_icu_bundle (void);
extern int32_t mono_wasm_load_icu_data(const void* pData);
extern const char* dotnet_browser_geticufilename();
#endif /* INVARIANT_GLOBALIZATION */
#endif /* WASM_SINGLE_FILE */
extern void mono_wasm_set_entrypoint_breakpoint (const char* assembly_name, int method_token);

extern void mono_bundled_resources_add_assembly_resource (const char *id, const char *name, const uint8_t *data, uint32_t size, void (*free_func)(void *, void*), void *free_data);
Expand Down Expand Up @@ -180,14 +190,33 @@ cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
free (user_data);
}

void
load_icu ()
{
#ifndef INVARIANT_GLOBALIZATION
#ifdef WASM_SINGLE_FILE
mono_register_icu_bundle ();

const uint8_t *buffer = NULL;
uint32_t data_len = 0;
const char* icu_name = dotnet_browser_geticufilename ();
if (!mono_bundled_resources_get_data_resource_values (icu_name, &buffer, &data_len)) {
printf("Could not load icudt.dat from the bundle");
assert(buffer);
}
assert(mono_wasm_load_icu_data(buffer));
#else
mono_wasm_link_icu_shim ();
#endif
#endif
}

EMSCRIPTEN_KEEPALIVE void
mono_wasm_load_runtime (int debug_level)
{
const char *interp_opts = "";

#ifndef INVARIANT_GLOBALIZATION
mono_wasm_link_icu_shim ();
#endif
load_icu();

// When the list of app context properties changes, please update RuntimeConfigReservedProperties for
// target _WasmGenerateRuntimeConfig in BrowserWasmApp.targets file
Expand All @@ -199,6 +228,22 @@ mono_wasm_load_runtime (int debug_level)
appctx_values [0] = "/";
appctx_values [1] = "browser-wasm";

#ifdef WASM_SINGLE_FILE
mono_register_runtimeconfig_bin ();

const uint8_t *buffer = NULL;
uint32_t data_len = 0;
if (!mono_bundled_resources_get_data_resource_values (RUNTIMECONFIG_BIN_FILE, &buffer, &data_len)) {
printf("Could not load " RUNTIMECONFIG_BIN_FILE " from the bundle\n");
assert(buffer);
}

MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *)malloc (sizeof (MonovmRuntimeConfigArguments));
arg->kind = 1; // kind: image pointer
arg->runtimeconfig.data.data = buffer;
arg->runtimeconfig.data.data_len = data_len;
monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, NULL);
#else
char *file_name = RUNTIMECONFIG_BIN_FILE;
int str_len = strlen (file_name) + 1; // +1 is for the "/"
char *file_path = (char *)malloc (sizeof (char) * (str_len +1)); // +1 is for the terminating null character
Expand All @@ -215,12 +260,16 @@ mono_wasm_load_runtime (int debug_level)
} else {
free (file_path);
}
#endif

monovm_initialize (2, appctx_keys, appctx_values);

#ifndef INVARIANT_TIMEZONE
mono_register_timezones_bundle ();
#endif /* INVARIANT_TIMEZONE */
#ifdef WASM_SINGLE_FILE
mono_register_assemblies_bundle ();
#endif

root_domain = mono_wasm_load_runtime_common (debug_level, wasm_trace_logger, interp_opts);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public LazyLoadingTests(ITestOutputHelper output, SharedBuildPerTestClassFixture
public async Task LoadLazyAssemblyBeforeItIsNeeded(string lazyLoadingTestExtension, string[] allLazyLoadingTestExtensions)
{
CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests", "App");
BuildProject("Debug", extraArgs: $"-p:LazyLoadingTestExtension={lazyLoadingTestExtension}");
BuildProject("Debug", extraArgs: $"-p:LazyLoadingTestExtension={lazyLoadingTestExtension} -p:WasmSingleFileBundle=true -p:_WasmOutputFileName=dotnet.native.wasm");

// We are running the app and passing all possible lazy extensions to test matrix of all possibilities.
// We don't need to rebuild the application to test how client is trying to load the assembly.
Expand Down
Loading
Loading