diff options
author | Thays Grazia <thaystg@gmail.com> | 2020-09-21 20:35:16 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-21 20:35:16 +0300 |
commit | 2bfbac18b6168a58d1e37749bb0bb0ccdda2ac20 (patch) | |
tree | 99595fae0bfb3fb539736206158d0f3cbbf2437d /sdks | |
parent | e0437b3ec116bf0f40789773ee418c0785f590ae (diff) |
[wasm][debugger] Fix wasm compilation error on mono/mono (#20414)
* Adding function to fix compilation error
* Trying to compile
* Add mini-wasm-debugger
* Adding function on driver.c
* Removing debugger tests.
Diffstat (limited to 'sdks')
-rw-r--r-- | sdks/wasm/src/dotnet_support.js | 31 | ||||
-rw-r--r-- | sdks/wasm/src/driver.c | 18 | ||||
-rw-r--r-- | sdks/wasm/src/library_mono.js | 477 |
3 files changed, 439 insertions, 87 deletions
diff --git a/sdks/wasm/src/dotnet_support.js b/sdks/wasm/src/dotnet_support.js index 42555da6e79..9b353f1b5f0 100644 --- a/sdks/wasm/src/dotnet_support.js +++ b/sdks/wasm/src/dotnet_support.js @@ -1,3 +1,5 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. var DotNetSupportLib = { $DOTNET: { @@ -27,7 +29,28 @@ var DotNetSupportLib = { return MONO.string_decoder.copy (mono_obj); } }, - mono_wasm_invoke_js_marshalled: function(exceptionMessage, asyncHandleLongPtr, functionName, argsJson) { + + mono_wasm_invoke_js_blazor: function(exceptionMessage, callInfo, arg0, arg1, arg2) { + var mono_string = DOTNET._dotnet_get_global()._mono_string_cached + || (DOTNET._dotnet_get_global()._mono_string_cached = Module.cwrap('mono_wasm_string_from_js', 'number', ['string'])); + + try { + var blazorExports = DOTNET._dotnet_get_global().Blazor; + if (!blazorExports) { + throw new Error('The blazor.webassembly.js library is not loaded.'); + } + + return blazorExports._internal.invokeJSFromDotNet(callInfo, arg0, arg1, arg2); + } catch (ex) { + var exceptionJsString = ex.message + '\n' + ex.stack; + var exceptionSystemString = mono_string(exceptionJsString); + setValue (exceptionMessage, exceptionSystemString, 'i32'); // *exceptionMessage = exceptionSystemString; + return 0; + } + }, + + // This is for back-compat only and will eventually be removed + mono_wasm_invoke_js_marshalled: function(exceptionMessage, asyncHandleLongPtr, functionName, argsJson, treatResultAsVoid) { var mono_string = DOTNET._dotnet_get_global()._mono_string_cached || (DOTNET._dotnet_get_global()._mono_string_cached = Module.cwrap('mono_wasm_string_from_js', 'number', ['string'])); @@ -52,10 +75,10 @@ var DotNetSupportLib = { } if (asyncHandleJsNumber) { - dotNetExports.jsCallDispatcher.beginInvokeJSFromDotNet(asyncHandleJsNumber, funcNameJsString, argsJsonJsString); + dotNetExports.jsCallDispatcher.beginInvokeJSFromDotNet(asyncHandleJsNumber, funcNameJsString, argsJsonJsString, treatResultAsVoid); return 0; } else { - var resultJson = dotNetExports.jsCallDispatcher.invokeJSFromDotNet(funcNameJsString, argsJsonJsString); + var resultJson = dotNetExports.jsCallDispatcher.invokeJSFromDotNet(funcNameJsString, argsJsonJsString, treatResultAsVoid); return resultJson === null ? 0 : mono_string(resultJson); } } catch (ex) { @@ -65,6 +88,8 @@ var DotNetSupportLib = { return 0; } }, + + // This is for back-compat only and will eventually be removed mono_wasm_invoke_js_unmarshalled: function(exceptionMessage, funcName, arg0, arg1, arg2) { try { // Get the function you're trying to invoke diff --git a/sdks/wasm/src/driver.c b/sdks/wasm/src/driver.c index 5812bfb81e4..c4dd20b42a3 100644 --- a/sdks/wasm/src/driver.c +++ b/sdks/wasm/src/driver.c @@ -27,6 +27,8 @@ extern void* mono_wasm_invoke_js_unmarshalled (MonoString **exceptionMessage, Mo void mono_wasm_enable_debugging (int); +int mono_wasm_assembly_already_added (const char *assembly_name); + void mono_ee_interp_init (const char *opts); void mono_marshal_ilgen_init (void); void mono_method_builder_ilgen_init (void); @@ -161,6 +163,22 @@ mono_wasm_add_assembly (const char *name, const unsigned char *data, unsigned in return mono_has_pdb_checksum ((char*)data, size); } +EMSCRIPTEN_KEEPALIVE int +mono_wasm_assembly_already_added (const char *assembly_name) +{ + if (assembly_count == 0) + return 0; + + WasmAssembly *entry = assemblies; + while (entry != NULL) { + if (strcmp (entry->assembly.name, assembly_name) == 0) + return 1; + entry = entry->next; + } + + return 0; +} + EMSCRIPTEN_KEEPALIVE void mono_wasm_setenv (const char *name, const char *value) { diff --git a/sdks/wasm/src/library_mono.js b/sdks/wasm/src/library_mono.js index eccc137f7b1..4ae04e16048 100644 --- a/sdks/wasm/src/library_mono.js +++ b/sdks/wasm/src/library_mono.js @@ -40,6 +40,13 @@ * @type {number} - address in wasm memory */ +/** + * @typedef Event + * @type {object} + * @property {string} eventName - name of the event being raised + * @property {object} eventArgs - arguments for the event itself + */ + var MonoSupportLib = { $MONO__postset: 'MONO.export_functions (Module);', $MONO: { @@ -71,6 +78,7 @@ var MonoSupportLib = { module ["mono_load_runtime_and_bcl_args"] = MONO.mono_load_runtime_and_bcl_args; module ["mono_wasm_load_bytes_into_heap"] = MONO.mono_wasm_load_bytes_into_heap; module ["mono_wasm_load_icu_data"] = MONO.mono_wasm_load_icu_data; + module ["mono_wasm_get_icudt_name"] = MONO.mono_wasm_get_icudt_name; module ["mono_wasm_globalization_init"] = MONO.mono_wasm_globalization_init; module ["mono_wasm_get_loaded_files"] = MONO.mono_wasm_get_loaded_files; module ["mono_wasm_new_root_buffer"] = MONO.mono_wasm_new_root_buffer; @@ -79,6 +87,113 @@ var MonoSupportLib = { module ["mono_wasm_release_roots"] = MONO.mono_wasm_release_roots; }, + _base64Converter: { + // Code from JSIL: + // https://github.com/sq/JSIL/blob/1d57d5427c87ab92ffa3ca4b82429cd7509796ba/JSIL.Libraries/Includes/Bootstrap/Core/Classes/System.Convert.js#L149 + // Thanks to Katelyn Gadd @kg + + _base64Table: [ + 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', + 'Y', 'Z', + 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', + 'y', 'z', + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', + '+', '/' + ], + + _makeByteReader: function (bytes, index, count) { + var position = (typeof (index) === "number") ? index : 0; + var endpoint; + + if (typeof (count) === "number") + endpoint = (position + count); + else + endpoint = (bytes.length - position); + + var result = { + read: function () { + if (position >= endpoint) + return false; + + var nextByte = bytes[position]; + position += 1; + return nextByte; + } + }; + + Object.defineProperty(result, "eof", { + get: function () { + return (position >= endpoint); + }, + configurable: true, + enumerable: true + }); + + return result; + }, + + toBase64StringImpl: function (inArray, offset, length) { + var reader = this._makeByteReader(inArray, offset, length); + var result = ""; + var ch1 = 0, ch2 = 0, ch3 = 0, bits = 0, equalsCount = 0, sum = 0; + var mask1 = (1 << 24) - 1, mask2 = (1 << 18) - 1, mask3 = (1 << 12) - 1, mask4 = (1 << 6) - 1; + var shift1 = 18, shift2 = 12, shift3 = 6, shift4 = 0; + + while (true) { + ch1 = reader.read(); + ch2 = reader.read(); + ch3 = reader.read(); + + if (ch1 === false) + break; + if (ch2 === false) { + ch2 = 0; + equalsCount += 1; + } + if (ch3 === false) { + ch3 = 0; + equalsCount += 1; + } + + // Seems backwards, but is right! + sum = (ch1 << 16) | (ch2 << 8) | (ch3 << 0); + + bits = (sum & mask1) >> shift1; + result += this._base64Table[bits]; + bits = (sum & mask2) >> shift2; + result += this._base64Table[bits]; + + if (equalsCount < 2) { + bits = (sum & mask3) >> shift3; + result += this._base64Table[bits]; + } + + if (equalsCount === 2) { + result += "=="; + } else if (equalsCount === 1) { + result += "="; + } else { + bits = (sum & mask4) >> shift4; + result += this._base64Table[bits]; + } + } + + return result; + }, + }, + _mono_wasm_root_buffer_prototype: { _check_in_range: function (index) { if ((index >= this.__count) || (index < 0)) @@ -362,43 +477,108 @@ var MonoSupportLib = { var i = 0; while (i < var_list.length) { let o = var_list [i]; - const name = o.name; - if (name == null || name == undefined) { - i ++; - out_list.push (o); - continue; - } + const this_has_name = o.name !== undefined; + let next_has_value_or_get_set = false; if (i + 1 < var_list.length) { + const next = var_list [i+1]; + next_has_value_or_get_set = next.value !== undefined || next.get !== undefined || next.set !== undefined; + } + + if (!this_has_name) { + // insert the object as-is + // Eg. in case of locals, the names are added + // later + i ++; + } else if (next_has_value_or_get_set) { + // found a {name} followed by a {value/get} o = Object.assign (o, var_list [i + 1]); + i += 2; + } else { + // missing value/get, so add a placeholder one + o.value = { + type: "symbol", + value: "<unreadable value>", + description: "<unreadable value>" + }; + i ++; } out_list.push (o); - i += 2; } return out_list; }, - _filter_automatic_properties: function (props) { - let names_found = {}; - let final_var_list = []; + _filter_automatic_properties: function (props, accessors_only=false) { + // Note: members in @props, have derived class members, followed by + // those from parent classes - for (var i in props) { - var p = props [i]; - if (p.name in names_found) - continue; + // Note: Auto-properties have backing fields, named with a special suffix. + // @props here will have the backing field, *and* the getter. + // + // But we want to return only one name/value pair: + // [name of the auto-property] = value of the backing field - if (p.name.endsWith ("k__BackingField")) - p.name = p.name.replace ("k__BackingField", "") - .replace ('<', '') - .replace ('>', ''); + let getters = {}; + let all_fields_except_backing_fields = {}; + let backing_fields = {}; - names_found [p.name] = p.name; - final_var_list.push (p); - } + // Split props into the 3 groups - backing_fields, getters, and all_fields_except_backing_fields + props.forEach(p => { + if (p.name === undefined) { + console.debug(`Bug: Found a member with no name. Skipping it. p: ${JSON.stringify(p)}`); + return; + } + + if (p.name.endsWith('k__BackingField')) { + const auto_prop_name = p.name.replace ('k__BackingField', '') + .replace ('<', '') + .replace ('>', ''); + + // Only take the first one, as that is overriding others + if (!(auto_prop_name in backing_fields)) + backing_fields[auto_prop_name] = Object.assign(p, { name: auto_prop_name }); + + } else if (p.get !== undefined) { + // if p wasn't overridden by a getter or a field, + // from a more derived class + if (!(p.name in getters) && !(p.name in all_fields_except_backing_fields)) + getters[p.name] = p; + + } else if (!(p.name in all_fields_except_backing_fields)) { + all_fields_except_backing_fields[p.name] = p; + } + }); + + // Filter/merge backing fields, and getters + Object.values(backing_fields).forEach(backing_field => { + const auto_prop_name = backing_field.name; + const getter = getters[auto_prop_name]; + + if (getter === undefined) { + // backing field with no getter + // eg. when a field overrides/`new string foo=..` + // an autoproperty + return; + } + + if (auto_prop_name in all_fields_except_backing_fields) { + delete getters[auto_prop_name]; + } else if (getter.__args.owner_class === backing_field.__args.owner_class) { + // getter+backing_field are from the same class. + // Add the backing_field value as a field + all_fields_except_backing_fields[auto_prop_name] = backing_field; + + // .. and drop the auto-prop getter + delete getters[auto_prop_name]; + } + }); + + if (accessors_only) + return Object.values(getters); - return final_var_list; + return Object.values(all_fields_except_backing_fields).concat(Object.values(getters)); }, /** Given `dotnet:object:foo:bar`, @@ -507,23 +687,32 @@ var MonoSupportLib = { * @param {WasmId} id * @returns {object[]} */ - _get_vt_properties: function (id) { - let entry = this._id_table [id.idStr]; - if (entry !== undefined && entry.members !== undefined) - return entry.members; - - if (!isNaN (id.o.containerId)) - this._get_object_properties (id.o.containerId, true); - else if (!isNaN (id.o.arrayId)) - this._get_array_values (id, Number (id.o.arrayIdx), 1, true); - else - throw new Error (`Invalid valuetype id (${id.idStr}). Can't get properties for it.`); + _get_vt_properties: function (id, args={}) { + let entry = this._get_id_props (id.idStr); + + if (entry === undefined || entry.members === undefined) { + if (!isNaN (id.o.containerId)) { + // We are expanding, so get *all* the members. + // Which ones to return based on @args, can be determined + // at the time of return + this._get_object_properties (id.o.containerId, { expandValueTypes: true }); + } else if (!isNaN (id.o.arrayId)) + this._get_array_values (id, Number (id.o.arrayIdx), 1, true); + else + throw new Error (`Invalid valuetype id (${id.idStr}). Can't get properties for it.`); + } + // Let's try again entry = this._get_id_props (id.idStr); - if (entry !== undefined && entry.members !== undefined) + + if (entry !== undefined && entry.members !== undefined) { + if (args.accessorPropertiesOnly === true) + return entry.accessors; + return entry.members; + } - throw new Error (`Unknown valuetype id: ${id.idStr}`); + throw new Error (`Unknown valuetype id: ${id.idStr}. Failed to get properties for it.`); }, /** @@ -597,17 +786,37 @@ var MonoSupportLib = { return res; }, + // Keep in sync with the flags in mini-wasm-debugger.c + _get_properties_args_to_gpflags: function (args) { + let gpflags =0; + /* + Disabled for now. Instead, we ask debugger.c to return + ~all~ the members, and then handle the filtering in mono.js . + + if (args.ownProperties) + gpflags |= 1; + if (args.accessorPropertiesOnly) + gpflags |= 2; + */ + if (args.expandValueTypes) + gpflags |= 4; + + return gpflags; + }, + /** * @param {number} idNum * @param {boolean} expandValueTypes * @returns {object} */ - _get_object_properties: function(idNum, expandValueTypes) { - let { res_ok, res } = this.mono_wasm_get_object_properties_info (idNum, expandValueTypes); + _get_object_properties: function(idNum, args={}) { + let gpflags = this._get_properties_args_to_gpflags (args); + + let { res_ok, res } = this.mono_wasm_get_object_properties_info (idNum, gpflags); if (!res_ok) throw new Error (`Failed to get properties for ${idNum}`); - res = MONO._filter_automatic_properties (res); + res = MONO._filter_automatic_properties (res, args.accessorPropertiesOnly === true); res = this._assign_vt_ids (res, v => ({ containerId: idNum, fieldOffset: v.fieldOffset })); res = this._post_process_details (res); @@ -625,7 +834,8 @@ var MonoSupportLib = { if (isNaN (id.o.arrayId) || isNaN (startIdx)) throw new Error (`Invalid array id: ${id.idStr}`); - let { res_ok, res } = this.mono_wasm_get_array_values_info (id.o.arrayId, startIdx, count, expandValueTypes); + let gpflags = this._get_properties_args_to_gpflags({ expandValueTypes }); + let { res_ok, res } = this.mono_wasm_get_array_values_info (id.o.arrayId, startIdx, count, gpflags); if (!res_ok) throw new Error (`Failed to get properties for array id ${id.idStr}`); @@ -647,6 +857,8 @@ var MonoSupportLib = { if (details.length > 0) this._extract_and_cache_value_types(details); + // remove __args added by add_properties_var + details.forEach(d => delete d.__args); return details; }, @@ -682,12 +894,20 @@ var MonoSupportLib = { if (value.type != "object" || value.isValueType != true || value.expanded != true) // undefined would also give us false continue; + if (value.members === undefined) { + // this could happen for valuetypes that maybe + // we were not able to describe, like `ref` parameters + // So, skip that + continue; + } + // Generate objectId for expanded valuetypes value.objectId = value.objectId || this._new_or_add_id_props ({ scheme: 'valuetype' }); this._extract_and_cache_value_types (value.members); - const new_props = Object.assign ({ members: value.members }, value.__extra_vt_props); + const accessors = value.members.filter(m => m.get !== undefined); + const new_props = Object.assign ({ members: value.members, accessors }, value.__extra_vt_props); this._new_or_add_id_props ({ objectId: value.objectId, props: new_props }); delete value.members; @@ -837,7 +1057,7 @@ var MonoSupportLib = { return res; }, - mono_wasm_get_details: function (objectId, args) { + mono_wasm_get_details: function (objectId, args={}) { let id = this._parse_object_id (objectId, true); switch (id.scheme) { @@ -845,14 +1065,15 @@ var MonoSupportLib = { if (isNaN (id.value)) throw new Error (`Invalid objectId: ${objectId}. Expected a numeric id.`); - return this._get_object_properties(id.value, false); + args.expandValueTypes = false; + return this._get_object_properties(id.value, args); } case "array": return this._get_array_values (id); case "valuetype": - return this._get_vt_properties(id); + return this._get_vt_properties(id, args); case "cfo_res": return this._get_cfo_res_details (objectId, args); @@ -1082,8 +1303,8 @@ var MonoSupportLib = { this._call_function_res_cache = {}; this._c_fn_table = {}; - this._register_c_var_fn ('mono_wasm_get_object_properties', 'bool', [ 'number', 'bool' ]); - this._register_c_var_fn ('mono_wasm_get_array_values', 'bool', [ 'number', 'number', 'number', 'bool' ]); + this._register_c_var_fn ('mono_wasm_get_object_properties', 'bool', [ 'number', 'number' ]); + this._register_c_var_fn ('mono_wasm_get_array_values', 'bool', [ 'number', 'number', 'number', 'number' ]); this._register_c_var_fn ('mono_wasm_invoke_getter_on_object', 'bool', [ 'number', 'string' ]); this._register_c_var_fn ('mono_wasm_invoke_getter_on_value', 'bool', [ 'number', 'number', 'string' ]); this._register_c_var_fn ('mono_wasm_get_local_vars', 'bool', [ 'number', 'number', 'number']); @@ -1219,6 +1440,7 @@ var MonoSupportLib = { var offset = null; switch (asset.behavior) { + case "resource": case "assembly": ctx.loaded_files.push ({ url: url, file: virtualName}); case "heap": @@ -1278,6 +1500,9 @@ var MonoSupportLib = { else console.error ("Error loading ICU asset", asset.name); } + else if (asset.behavior === "resource") { + ctx.mono_wasm_add_satellite_assembly (virtualName, asset.culture, offset, bytes.length); + } }, // deprecated @@ -1321,6 +1546,7 @@ var MonoSupportLib = { // behavior: (required) determines how the asset will be handled once loaded: // "heap": store asset into the native heap // "assembly": load asset as a managed assembly (or debugging information) + // "resource": load asset as a managed resource assembly // "icu": load asset as an ICU data archive // "vfs": load asset into the virtual filesystem (for fopen, File.Open, etc) // load_remote: (optional) if true, an attempt will be made to load the asset @@ -1379,6 +1605,14 @@ var MonoSupportLib = { return ok; }, + // Get icudt.dat exact filename that matches given culture, examples: + // "ja" -> "icudt_CJK.dat" + // "en_US" (or "en-US" or just "en") -> "icudt_EFIGS.dat" + // etc, see "mono_wasm_get_icudt_name" implementation in pal_icushim_static.c + mono_wasm_get_icudt_name: function (culture) { + return Module.ccall ('mono_wasm_get_icudt_name', 'string', ['string'], [culture]); + }, + _finalize_startup: function (args, ctx) { var loaded_files_with_debug_info = []; @@ -1431,6 +1665,7 @@ var MonoSupportLib = { tracing: args.diagnostic_tracing || false, pending_count: args.assets.length, mono_wasm_add_assembly: Module.cwrap ('mono_wasm_add_assembly', 'number', ['string', 'number', 'number']), + mono_wasm_add_satellite_assembly: Module.cwrap ('mono_wasm_add_satellite_assembly', 'void', ['string', 'string', 'number', 'number']), loaded_assets: Object.create (null), // dlls and pdbs, used by blazor and the debugger loaded_files: [], @@ -1523,6 +1758,10 @@ var MonoSupportLib = { if (sourcePrefix.trim() === "") { if (asset.behavior === "assembly") attemptUrl = locateFile (args.assembly_root + "/" + asset.name); + else if (asset.behavior === "resource") { + var path = asset.culture !== '' ? `${asset.culture}/${asset.name}` : asset.name; + attemptUrl = locateFile (args.assembly_root + "/" + path); + } else attemptUrl = asset.name; } else { @@ -1609,7 +1848,7 @@ var MonoSupportLib = { }, _mono_wasm_add_string_var: function(var_value) { - if (var_value == 0) { + if (var_value === 0) { MONO.mono_wasm_add_null_var ("string"); return; } @@ -1623,31 +1862,20 @@ var MonoSupportLib = { }); }, - _mono_wasm_add_getter_var: function(className, invokable) { + _mono_wasm_add_getter_var: function(className) { const fixed_class_name = MONO._mono_csharp_fixup_class_name (className); - if (invokable != 0) { - var name; - if (MONO.var_info.length > 0) - name = MONO.var_info [MONO.var_info.length - 1].name; - name = (name === undefined) ? "" : name; - - MONO.var_info.push({ - get: { - className: "Function", - description: `get ${name} () {}`, - type: "function", - } - }); - } else { - var value = `${fixed_class_name} { get; }`; - MONO.var_info.push({ - value: { - type: "symbol", - description: value, - value: value, - } - }); - } + var name; + if (MONO.var_info.length > 0) + name = MONO.var_info [MONO.var_info.length - 1].name; + name = (name === undefined) ? "" : name; + + MONO.var_info.push({ + get: { + className: "Function", + description: `get ${name} () {}`, + type: "function", + } + }); }, _mono_wasm_add_array_var: function(className, objectId, length) { @@ -1692,7 +1920,7 @@ var MonoSupportLib = { value: { type : "object", className : fixed_class_name, - description : (toString == 0 ? fixed_class_name: Module.UTF8ToString (toString)), + description : (toString === 0 ? fixed_class_name: Module.UTF8ToString (toString)), expanded : true, isValueType : true, __extra_vt_props: { klass: args.klass, value64: base64String }, @@ -1734,17 +1962,36 @@ var MonoSupportLib = { value: { type: "object", className: fixed_class_name, - description: (toString == 0 ? fixed_class_name : Module.UTF8ToString (toString)), + description: (toString === 0 ? fixed_class_name : Module.UTF8ToString (toString)), isValueType: true } }); }, + mono_wasm_add_properties_var: function (name, args) { + if (typeof args !== 'object') + args = { field_offset: args }; + + if (args.owner_class !== undefined && args.owner_class !== 0) + args.owner_class = Module.UTF8ToString(args.owner_class); + + let name_obj = { + name: Module.UTF8ToString (name), + fieldOffset: args.field_offset, + __args: args + }; + if (args.is_own) + name_obj.isOwn = true; + + MONO.var_info.push(name_obj); + }, mono_wasm_add_typed_value: function (type, str_value, value) { let type_str = type; if (typeof type != 'string') type_str = Module.UTF8ToString (type); + + if (str_value !== 0) str_value = Module.UTF8ToString (str_value); switch (type_str) { @@ -1787,7 +2034,7 @@ var MonoSupportLib = { break; case "getter": - MONO._mono_wasm_add_getter_var (str_value, value); + MONO._mono_wasm_add_getter_var (str_value); break; case "array": @@ -1830,6 +2077,20 @@ var MonoSupportLib = { } break; + case "symbol": { + if (typeof value === 'object' && value.isClassName) + str_value = MONO._mono_csharp_fixup_class_name (str_value); + + MONO.var_info.push ({ + value: { + type: "symbol", + value: str_value, + description: str_value + } + }); + } + break; + default: { const msg = `'${str_value}' ${value}`; @@ -1903,18 +2164,34 @@ var MonoSupportLib = { data = data.slice(length); } return true; - } + }, + + /** + * Raises an event for the debug proxy + * + * @param {Event} event - event to be raised + * @param {object} args - arguments for raising this event, eg. `{trace: true}` + */ + mono_wasm_raise_debug_event: function(event, args={}) { + if (typeof event !== 'object') + throw new Error(`event must be an object, but got ${JSON.stringify(event)}`); + + if (event.eventName === undefined) + throw new Error(`event.eventName is a required parameter, in event: ${JSON.stringify(event)}`); + + if (typeof args !== 'object') + throw new Error(`args must be an object, but got ${JSON.stringify(args)}`); + + console.debug('mono_wasm_debug_event_raised:aef14bca-5519-4dfe-b35a-f867abc123ae', JSON.stringify(event), JSON.stringify(args)); + }, }, mono_wasm_add_typed_value: function (type, str_value, value) { MONO.mono_wasm_add_typed_value (type, str_value, value); }, - mono_wasm_add_properties_var: function(name, field_offset) { - MONO.var_info.push({ - name: Module.UTF8ToString (name), - fieldOffset: field_offset - }); + mono_wasm_add_properties_var: function(name, args) { + MONO.mono_wasm_add_properties_var (name, args); }, mono_wasm_set_is_async_method: function(objectId) { @@ -1962,7 +2239,7 @@ var MonoSupportLib = { value: { type: "object", className: fixed_class_name, - description: (toString == 0 ? fixed_class_name : Module.UTF8ToString (toString)), + description: (toString === 0 ? fixed_class_name : Module.UTF8ToString (toString)), objectId: "dotnet:object:"+ objectId, } }); @@ -1993,14 +2270,15 @@ var MonoSupportLib = { var args_sig = parts.splice (1).join (', '); return `${ret_sig} ${method_name} (${args_sig})`; } - let tgt_sig; if (targetName != 0) tgt_sig = args_to_sig (Module.UTF8ToString (targetName)); const type_name = MONO._mono_csharp_fixup_class_name (Module.UTF8ToString (className)); + if (tgt_sig === undefined) + tgt_sig = type_name; - if (objectId == -1) { + if (objectId == -1 || targetName === 0) { // Target property MONO.var_info.push ({ value: { @@ -2021,14 +2299,15 @@ var MonoSupportLib = { } }, - mono_wasm_add_frame: function(il, method, assembly_name, method_full_name) { + mono_wasm_add_frame: function(il, method, frame_id, assembly_name, method_full_name) { var parts = Module.UTF8ToString (method_full_name).split (":", 2); MONO.active_frames.push( { il_pos: il, method_token: method, assembly_name: Module.UTF8ToString (assembly_name), // Extract just the method name from `{class_name}:{method_name}` - method_name: parts [parts.length - 1] + method_name: parts [parts.length - 1], + frame_id }); }, @@ -2080,6 +2359,36 @@ var MonoSupportLib = { }; debugger; }, + + mono_wasm_asm_loaded: function (assembly_name, assembly_ptr, assembly_len, pdb_ptr, pdb_len) { + // Only trigger this codepath for assemblies loaded after app is ready + if (MONO.mono_wasm_runtime_is_ready !== true) + return; + + if (!this.mono_wasm_assembly_already_added) + this.mono_wasm_assembly_already_added = Module.cwrap ("mono_wasm_assembly_already_added", 'number', ['string']); + + // And for assemblies that have not already been loaded + const assembly_name_str = assembly_name !== 0 ? Module.UTF8ToString(assembly_name).concat('.dll') : ''; + if (this.mono_wasm_assembly_already_added(assembly_name_str)) + return; + + const assembly_data = new Uint8Array(Module.HEAPU8.buffer, assembly_ptr, assembly_len); + const assembly_b64 = MONO._base64Converter.toBase64StringImpl(assembly_data); + + let pdb_b64; + if (pdb_ptr) { + const pdb_data = new Uint8Array(Module.HEAPU8.buffer, pdb_ptr, pdb_len); + pdb_b64 = MONO._base64Converter.toBase64StringImpl(pdb_data); + } + + MONO.mono_wasm_raise_debug_event({ + eventName: 'AssemblyLoaded', + assembly_name: assembly_name_str, + assembly_b64, + pdb_b64 + }); + }, }; autoAddDeps(MonoSupportLib, '$MONO') |