[wasm] Fix a signature.
[mono-project.git] / sdks / wasm / binding_support.js
blob912e88644acc1783949154cfda0a0632b0882896
2 var BindingSupportLib = {
3         $BINDING__postset: 'BINDING.export_functions (Module);',
4         $BINDING: {
5                 BINDING_ASM: "[binding_tests]WebAssembly.Runtime",
6                 mono_wasm_object_registry: [],
7                 mono_wasm_ref_counter: 0,
8                 mono_wasm_free_list: [],
9                 mono_bindings_init: function (binding_asm) {
10                         this.BINDING_ASM = binding_asm;
11                 },
13                 export_functions: function (module) {
14                         module ["mono_bindings_init"] = BINDING.mono_bindings_init.bind(BINDING);
15                         module ["mono_method_invoke"] = BINDING.call_method.bind(BINDING);
16                         module ["mono_method_get_call_signature"] = BINDING.mono_method_get_call_signature.bind(BINDING);
17                         module ["mono_method_resolve"] = BINDING.resolve_method_fqn.bind(BINDING);
18                         module ["mono_bind_static_method"] = BINDING.bind_static_method.bind(BINDING);
19                         module ["mono_call_static_method"] = BINDING.call_static_method.bind(BINDING);
20                 },
22                 bindings_lazy_init: function () {
23                         if (this.init)
24                                 return;
25                 
26                         this.assembly_load = Module.cwrap ('mono_wasm_assembly_load', 'number', ['string']);
27                         this.find_class = Module.cwrap ('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']);
28                         this.find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']);
29                         this.invoke_method = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number', 'number']);
30                         this.mono_string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'number', ['number']);
31                         this.js_string_to_mono_string = Module.cwrap ('mono_wasm_string_from_js', 'number', ['string']);
32                         this.mono_get_obj_type = Module.cwrap ('mono_wasm_get_obj_type', 'number', ['number']);
33                         this.mono_unbox_int = Module.cwrap ('mono_unbox_int', 'number', ['number']);
34                         this.mono_unbox_float = Module.cwrap ('mono_wasm_unbox_float', 'number', ['number']);
35                         this.mono_array_length = Module.cwrap ('mono_wasm_array_length', 'number', ['number']);
36                         this.mono_array_get = Module.cwrap ('mono_wasm_array_get', 'number', ['number', 'number']);
37                         this.mono_obj_array_new = Module.cwrap ('mono_wasm_obj_array_new', 'number', ['number']);
38                         this.mono_obj_array_set = Module.cwrap ('mono_wasm_obj_array_set', 'void', ['number', 'number', 'number']);
40                         // receives a byteoffset into allocated Heap with a size.
41                         this.mono_typed_array_new = Module.cwrap ('mono_wasm_typed_array_new', 'number', ['number','number','number','number']);
42                         this.mono_array_to_heap = Module.cwrap ('mono_wasm_array_to_heap', 'void', ['number','number']);
44                         var binding_fqn_asm = this.BINDING_ASM.substring(this.BINDING_ASM.indexOf ("[") + 1, this.BINDING_ASM.indexOf ("]")).trim();
45                         var binding_fqn_class = this.BINDING_ASM.substring (this.BINDING_ASM.indexOf ("]") + 1).trim();
46                         
47                         this.binding_module = this.assembly_load (binding_fqn_asm);
48                         if (!this.binding_module)
49                                 throw "Can't find bindings module assembly: " + binding_fqn_asm;
51                         if (binding_fqn_class !== null && typeof binding_fqn_class !== "undefined")
52                         {
53                                 var namespace = "WebAssembly";
54                                 var classname = binding_fqn_class.length > 0 ? binding_fqn_class : "Runtime";
55                                 if (binding_fqn_class.indexOf(".") != -1) {
56                                         var idx = binding_fqn_class.lastIndexOf(".");
57                                         namespace = binding_fqn_class.substring (0, idx);
58                                         classname = binding_fqn_class.substring (idx + 1);
59                                 }
60                         }
62                         var wasm_runtime_class = this.find_class (this.binding_module, namespace, classname)
63                         if (!wasm_runtime_class)
64                                 throw "Can't find " + binding_fqn_class + " class";
66                         var get_method = function(method_name) {
67                                 var res = BINDING.find_method (wasm_runtime_class, method_name, -1)
68                                 if (!res)
69                                         throw "Can't find method " + namespace + "." + classname + ":" + method_name;
70                                 return res;
71                         }
72                         this.bind_js_obj = get_method ("BindJSObject");
73                         this.bind_existing_obj = get_method ("BindExistingObject");
74                         this.unbind_js_obj = get_method ("UnBindJSObject");
75                         this.unbind_js_obj_and_fee = get_method ("UnBindJSObjectAndFree");                      
76                         this.get_js_id = get_method ("GetJSObjectId");
77                         this.get_raw_mono_obj = get_method ("GetMonoObject");
79                         this.box_js_int = get_method ("BoxInt");
80                         this.box_js_double = get_method ("BoxDouble");
81                         this.box_js_bool = get_method ("BoxBool");
82                         this.setup_js_cont = get_method ("SetupJSContinuation");
84                         this.create_tcs = get_method ("CreateTaskSource");
85                         this.set_tcs_result = get_method ("SetTaskSourceResult");
86                         this.set_tcs_failure = get_method ("SetTaskSourceFailure");
87                         this.tcs_get_task_and_bind = get_method ("GetTaskAndBind");
88                         this.get_call_sig = get_method ("GetCallSignature");
90                         this.init = true;
91                 },              
93                 get_js_obj: function (js_handle) {
94                         if (js_handle > 0)
95                                 return this.mono_wasm_require_handle(js_handle);
96                         return null;
97                 },
98                 
99                 //FIXME this is wastefull, we could remove the temp malloc by going the UTF16 route
100                 //FIXME this is unsafe, cuz raw objects could be GC'd.
101                 conv_string: function (mono_obj) {
102                         if (mono_obj == 0)
103                                 return null;
104                         var raw = this.mono_string_get_utf8 (mono_obj);
105                         var res = Module.UTF8ToString (raw);
106                         Module._free (raw);
108                         return res;
109                 },
110                 
111                 mono_array_to_js_array: function (mono_array) {
112                         if (mono_array == 0)
113                                 return null;
115                         var res = [];
116                         var len = this.mono_array_length (mono_array);
117                         for (var i = 0; i < len; ++i)
118                                 res.push (this.unbox_mono_obj (this.mono_array_get (mono_array, i)));
120                         return res;
121                 },
123                 js_array_to_mono_array: function (js_array) {
124                         var mono_array = this.mono_obj_array_new (js_array.length);
125                         for (var i = 0; i < js_array.length; ++i) {
126                                 this.mono_obj_array_set (mono_array, i, this.js_to_mono_obj (js_array [i]));
127                         }
128                         return mono_array;
129                 },
131                 unbox_mono_obj: function (mono_obj) {
132                         if (mono_obj == 0)
133                                 return undefined;
134                         var type = this.mono_get_obj_type (mono_obj);
135                         //See MARSHAL_TYPE_ defines in driver.c
136                         switch (type) {
137                         case 1: // int
138                                 return this.mono_unbox_int (mono_obj);
139                         case 2: // float
140                                 return this.mono_unbox_float (mono_obj);
141                         case 3: //string
142                                 return this.conv_string (mono_obj);
143                         case 4: //vts
144                                 throw new Error ("no idea on how to unbox value types");
145                         case 5: { // delegate
146                                 var obj = this.extract_js_obj (mono_obj);
147                                 return function () {
148                                         return BINDING.invoke_delegate (obj, arguments);
149                                 };
150                         }
151                         case 6: {// Task
153                                 if (typeof Promise === "undefined" || typeof Promise.resolve === "undefined")
154                                         throw new Error ("Promises are not supported thus C# Tasks can not work in this context.");
156                                 var obj = this.extract_js_obj (mono_obj);
157                                 var cont_obj = null;
158                                 var promise = new Promise (function (resolve, reject) {
159                                         cont_obj = {
160                                                 resolve: resolve,
161                                                 reject: reject
162                                         };
163                                 });
165                                 this.call_method (this.setup_js_cont, null, "mo", [ mono_obj, cont_obj ]);
166                                 return promise;
167                         }
169                         case 7: // ref type
170                                 return this.extract_js_obj (mono_obj);
172                         case 8: // bool
173                                 return this.mono_unbox_int (mono_obj) != 0;
175                         case 11: 
176                         case 12: 
177                         case 13: 
178                         case 14: 
179                         case 15: 
180                         case 16: 
181                         case 17: 
182                         case 18:
183                         {
184                                 var res =  this.mono_array_to_js_typedarray(type, mono_obj); 
185                                 return res;
186                         }                       
187         
188                         default:
189                                 throw new Error ("no idea on how to unbox object kind " + type);
190                         }
191                 },
193                 create_task_completion_source: function () {
194                         return this.call_method (this.create_tcs, null, "i", [ -1 ]);
195                 },
197                 set_task_result: function (tcs, result) {
198                         this.call_method (this.set_tcs_result, null, "oo", [ tcs, result ]);
199                 },
201                 set_task_failure: function (tcs, reason) {
202                         this.call_method (this.set_tcs_failure, null, "os", [ tcs, reason.toString () ]);
203                 },
205                 // https://github.com/Planeshifter/emscripten-examples/blob/master/01_PassingArrays/sum_post.js
206                 js_typedarray_to_heap: function(typedArray){
207                         var numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
208                         var ptr = Module._malloc(numBytes);
209                         var heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes);
210                         heapBytes.set(new Uint8Array(typedArray.buffer));
211                         return heapBytes;
212                 },
213                 mono_array_to_js_typedarray: function(type, mono_array){
215                         // length of our array
216                         var szLength = this.mono_array_length(mono_array);
217                                 
218                         // The element size that will need to be allocated
219                         var bytes_per_element = 0;
221                         switch (type)
222                         {
223                                 case 11: 
224                                         bytes_per_element = Int8Array.BYTES_PER_ELEMENT; 
225                                         break;
226                                 case 12: 
227                                         bytes_per_element = Uint8Array.BYTES_PER_ELEMENT; 
228                                         break;
229                                 case 13: 
230                                         bytes_per_element = Int16Array.BYTES_PER_ELEMENT; 
231                                         break;
232                                 case 14: 
233                                         bytes_per_element = Uint16Array.BYTES_PER_ELEMENT; 
234                                         break;
235                                 case 15: 
236                                         bytes_per_element = Int32Array.BYTES_PER_ELEMENT; 
237                                         break;
238                                 case 16: 
239                                         bytes_per_element = Uint32Array.BYTES_PER_ELEMENT; 
240                                         break;
241                                 case 17: 
242                                         bytes_per_element = Float32Array.BYTES_PER_ELEMENT; 
243                                         break;
244                                 case 18:
245                                         bytes_per_element = Float64Array.BYTES_PER_ELEMENT;
246                                         break;
247                         }
248                         
249                         // Allocate bytes needed for the array of bytes
250                         var bufferSize = szLength * bytes_per_element;
251                         var bufferPtr = Module._malloc(bufferSize);
253                         // blit the mono array to the heap
254                         this.mono_array_to_heap(mono_array, bufferPtr);
256                         // result to be returned
257                         var res = null;
259                         // We now need to create a new typed array based off the heap view
260                         switch (type)
261                         {
262                                 case 11: 
263                                         res = Module.HEAP8.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
264                                         break;
265                                 case 12: 
266                                         res = Module.HEAPU8.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
267                                         break;
268                                 case 13: 
269                                         res = Module.HEAP16.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
270                                         break;
271                                 case 14: 
272                                         res = Module.HEAPU16.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
273                                         break;
274                                 case 15: 
275                                         res = Module.HEAP32.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
276                                         break;
277                                 case 16: 
278                                         res = Module.HEAPU32.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
279                                         break;
280                                 case 17: 
281                                         res = Module.HEAPF32.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
282                                         break;
283                                 case 18:
284                                         res = Module.HEAPF64.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
285                                         break;
286                         }
288                         // free the allocated memory
289                         Module._free(bufferPtr);
290                         // return new typed array
291                         return res;
292                         
293                 },
294                 js_to_mono_obj: function (js_obj) {
295                         this.bindings_lazy_init ();
297                         if (js_obj == null || js_obj == undefined)
298                                 return 0;
299                         if (typeof js_obj == 'number') {
300                                 if (parseInt(js_obj) == js_obj)
301                                         return this.call_method (this.box_js_int, null, "im", [ js_obj ]);
302                                 return this.call_method (this.box_js_double, null, "dm", [ js_obj ]);
303                         }
304                         if (typeof js_obj == 'string')
305                                 return this.js_string_to_mono_string (js_obj);
307                         if (typeof js_obj == 'boolean')
308                                 return this.call_method (this.box_js_bool, null, "im", [ js_obj ]);
310                         if (Promise.resolve(js_obj) === js_obj) {
311                                 var the_task = this.try_extract_mono_obj (js_obj);
312                                 if (the_task)
313                                         return the_task;
314                                 var tcs = this.create_task_completion_source ();
315                                 //FIXME dispose the TCS once the promise completes
316                                 js_obj.then (function (result) {
317                                         BINDING.set_task_result (tcs, result);
318                                 }, function (reason) {
319                                         BINDING.set_task_failure (tcs, reason);
320                                 })
322                                 return this.get_task_and_bind (tcs, js_obj);
323                         }
326                         // JavaScript typed arrays are array-like objects and provide a mechanism for accessing 
327                         // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays 
328                         // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
329                         //  is an object representing a chunk of data; it has no format to speak of, and offers no 
330                         // mechanism for accessing its contents. In order to access the memory contained in a buffer, 
331                         // you need to use a view. A view provides a context â€” that is, a data type, starting offset, 
332                         // and number of elements â€” that turns the data into an actual typed array.
333                         // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
334                         if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT)) 
335                         {
336                                 var arrayType = 0;      
337                                 if (js_obj instanceof Int8Array)
338                                         arrayType = 11;
339                                 if (js_obj instanceof Uint8Array)
340                                         arrayType = 12;
341                                 if (js_obj instanceof Uint8ClampedArray)
342                                         arrayType = 12;
343                                 if (js_obj instanceof Int16Array)
344                                         arrayType = 13;
345                                 if (js_obj instanceof Uint16Array)
346                                         arrayType = 14;
347                                 if (js_obj instanceof Int32Array)
348                                         arrayType = 15;
349                                 if (js_obj instanceof Uint32Array)
350                                         arrayType = 16;
351                                 if (js_obj instanceof Float32Array)
352                                         arrayType = 17;
353                                 if (js_obj instanceof Float64Array)
354                                         arrayType = 18;
356                                 var heapBytes = this.js_typedarray_to_heap(js_obj);
357                                 var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, js_obj.length, js_obj.BYTES_PER_ELEMENT, arrayType);
358                                 Module._free(heapBytes.byteOffset);
359                                 return bufferArray;
360                         }
361                         // The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer. 
362                         // You cannot directly manipulate the contents of an ArrayBuffer; instead, you create one of the 
363                         // typed array objects or a DataView object which represents the buffer in a specific format, and 
364                         // use that to read and write the contents of the buffer.
365                         // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays#ArrayBuffer
366                         if (ArrayBuffer.isView(js_obj) || js_obj instanceof ArrayBuffer)
367                         {
368                                 var heapBytes = this.js_typedarray_to_heap(new Uint8Array(js_obj));
370                                 var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, heapBytes.length, heapBytes.BYTES_PER_ELEMENT, 2);
371                                 Module._free(heapBytes.byteOffset);
372                                 return bufferArray;
373                         }
375                         return this.extract_mono_obj (js_obj);
376                 },
378                 wasm_binding_obj_new: function (js_obj_id)
379                 {
380                         return this.call_method (this.bind_js_obj, null, "i", [js_obj_id]);
381                 },
383                 wasm_bind_existing: function (mono_obj, js_id)
384                 {
385                         return this.call_method (this.bind_existing_obj, null, "mi", [mono_obj, js_id]);
386                 },
388                 wasm_unbind_js_obj: function (js_obj_id)
389                 {
390                         return this.call_method (this.unbind_js_obj, null, "i", [js_obj_id]);
391                 },              
393                 wasm_unbind_js_obj_and_free: function (js_obj_id)
394                 {
395                         return this.call_method (this.unbind_js_obj_and_fee, null, "i", [js_obj_id]);
396                 },              
398                 wasm_get_js_id: function (mono_obj)
399                 {
400                         return this.call_method (this.get_js_id, null, "m", [mono_obj]);
401                 },
403                 wasm_get_raw_obj: function (gchandle)
404                 {
405                         return this.call_method (this.get_raw_mono_obj, null, "im", [gchandle]);
406                 },
408                 try_extract_mono_obj:function (js_obj) {
409                         if (js_obj === null || typeof js_obj === "undefined" || typeof js_obj.__mono_gchandle__ === "undefined")
410                                 return 0;
411                         return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
412                 },
414                 mono_method_get_call_signature: function(method) {
415                         this.bindings_lazy_init ();
417                         return this.call_method (this.get_call_sig, null, "i", [ method ]);
418                 },
420                 get_task_and_bind: function (tcs, js_obj) {
421                         var gc_handle = this.mono_wasm_free_list.length ? this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
422                         var task_gchandle = this.call_method (this.tcs_get_task_and_bind, null, "oi", [ tcs, gc_handle + 1 ]);
423                         js_obj.__mono_gchandle__ = task_gchandle;
424                         this.mono_wasm_object_registry[gc_handle] = js_obj;
425                         return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
426                 },
428                 extract_mono_obj: function (js_obj) {
429                         //help JS ppl, is this enough?
430                         if (js_obj === null || typeof js_obj === "undefined")
431                                 return 0;
433                         if (!js_obj.__mono_gchandle__) {
434                                 this.mono_wasm_register_obj(js_obj);
435                         }
437                         return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
438                 },
440                 extract_js_obj: function (mono_obj) {
441                         if (mono_obj == 0)
442                                 return null;
444                         var js_id = this.wasm_get_js_id (mono_obj);
445                         if (js_id > 0)
446                                 return this.mono_wasm_require_handle(js_id);
448                         var gcHandle = this.mono_wasm_free_list.length ? this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
449                         var js_obj = {
450                                 __mono_gchandle__: this.wasm_bind_existing(mono_obj, gcHandle + 1),
451                                 is_mono_bridged_obj: true
452                         };
454                         this.mono_wasm_object_registry[gcHandle] = js_obj;
455                         return js_obj;
456                 },
458                 /*
459                 args_marshal is a string with one character per parameter that tells how to marshal it, here are the valid values:
461                 i: int32
462                 l: int64
463                 f: float
464                 d: double
465                 s: string
466                 o: js object will be converted to a C# object (this will box numbers/bool/promises)
467                 m: raw mono object. Don't use it unless you know what you're doing
469                 additionally you can append 'm' to args_marshal beyond `args.length` if you don't want the return value marshaled
470                 */
471                 call_method: function (method, this_arg, args_marshal, args) {
472                         this.bindings_lazy_init ();
474                         var extra_args_mem = 0;
475                         for (var i = 0; i < args.length; ++i) {
476                                 //long/double memory must be 8 bytes aligned and I'm being lazy here
477                                 if (args_marshal[i] == 'i' || args_marshal[i] == 'f' || args_marshal[i] == 'l' || args_marshal[i] == 'd')
478                                         extra_args_mem += 8;
479                         }
481                         var extra_args_mem = extra_args_mem ? Module._malloc (extra_args_mem) : 0;
482                         var extra_arg_idx = 0;
483                         var args_mem = Module._malloc (args.length * 4);
484                         var eh_throw = Module._malloc (4);
485                         for (var i = 0; i < args.length; ++i) {
486                                 if (args_marshal[i] == 's') {
487                                         Module.setValue (args_mem + i * 4, this.js_string_to_mono_string (args [i]), "i32");
488                                 } else if (args_marshal[i] == 'm') {
489                                         Module.setValue (args_mem + i * 4, args [i], "i32");
490                                 } else if (args_marshal[i] == 'o') {
491                                         Module.setValue (args_mem + i * 4, this.js_to_mono_obj (args [i]), "i32");
492                                 } else if (args_marshal[i] == 'i' || args_marshal[i] == 'f' || args_marshal[i] == 'l' || args_marshal[i] == 'd') {
493                                         var extra_cell = extra_args_mem + extra_arg_idx;
494                                         extra_arg_idx += 8;
496                                         if (args_marshal[i] == 'i')
497                                                 Module.setValue (extra_cell, args [i], "i32");
498                                         else if (args_marshal[i] == 'l')
499                                                 Module.setValue (extra_cell, args [i], "i64");
500                                         else if (args_marshal[i] == 'f')
501                                                 Module.setValue (extra_cell, args [i], "float");
502                                         else
503                                                 Module.setValue (extra_cell, args [i], "double");
505                                         Module.setValue (args_mem + i * 4, extra_cell, "i32");
506                                 }
507                         }
508                         Module.setValue (eh_throw, 0, "i32");
510                         var res = this.invoke_method (method, this_arg, args_mem, eh_throw);
512                         var eh_res = Module.getValue (eh_throw, "i32");
514                         if (extra_args_mem)
515                                 Module._free (extra_args_mem);
516                         Module._free (args_mem);
517                         Module._free (eh_throw);
519                         if (eh_res != 0) {
520                                 var msg = this.conv_string (res);
521                                 throw new Error (msg); //the convention is that invoke_method ToString () any outgoing exception
522                         }
524                         if (args_marshal.length >= args.length && args_marshal [args.length] == 'm')
525                                 return res;
526                         return this.unbox_mono_obj (res);
527                 },
529                 invoke_delegate: function (delegate_obj, js_args) {
530                         this.bindings_lazy_init ();
532                         if (!this.delegate_dynamic_invoke) {
533                                 if (!this.corlib)
534                                         this.corlib = this.assembly_load ("mscorlib");
535                                 if (!this.delegate_class)
536                                         this.delegate_class = this.find_class (this.corlib, "System", "Delegate");
537                                 this.delegate_dynamic_invoke = this.find_method (this.delegate_class, "DynamicInvoke", -1);
538                         }
539                         var mono_args = this.js_array_to_mono_array (js_args);
540                         return this.call_method (this.delegate_dynamic_invoke, this.extract_mono_obj (delegate_obj), "m", [ mono_args ]);
541                 },
542                 
543                 resolve_method_fqn: function (fqn) {
544                         var assembly = fqn.substring(fqn.indexOf ("[") + 1, fqn.indexOf ("]")).trim();
545                         fqn = fqn.substring (fqn.indexOf ("]") + 1).trim();
547                         var methodname = fqn.substring(fqn.indexOf (":") + 1);
548                         fqn = fqn.substring (0, fqn.indexOf (":")).trim ();
550                         var namespace = "";
551                         var classname = fqn;
552                         if (fqn.indexOf(".") != -1) {
553                                 var idx = fqn.lastIndexOf(".");
554                                 namespace = fqn.substring (0, idx);
555                                 classname = fqn.substring (idx + 1);
556                         }
558                         var asm = this.assembly_load (assembly);
559                         if (!asm)
560                                 throw new Error ("Could not find assembly: " + assembly);
562                         var klass = this.find_class(asm, namespace, classname);
563                         if (!klass)
564                                 throw new Error ("Could not find class: " + namespace + ":" +classname);
566                         var method = this.find_method (klass, methodname, -1);
567                         if (!method)
568                                 throw new Error ("Could not find method: " + methodname);
569                         return method;
570                 },
572                 call_static_method: function (fqn, args, signature) {
573                         this.bindings_lazy_init ();
575                         var method = this.resolve_method_fqn (fqn);
577                         if (typeof signature === "undefined")
578                                 signature = Module.mono_method_get_call_signature (method);
580                         return this.call_method (method, null, signature, args);
581                 },
583                 bind_static_method: function (fqn, signature) {
584                         this.bindings_lazy_init ();
586                         var method = this.resolve_method_fqn (fqn);
588                         if (typeof signature === "undefined")
589                                 signature = Module.mono_method_get_call_signature (method);
591                         return function() {
592                                 return BINDING.call_method (method, null, signature, arguments);
593                         };
594                 },
595                 // Object wrapping helper functions to handle reference handles that will
596                 // be used in managed code.
597                 mono_wasm_register_obj: function(obj) {
599                         var gc_handle = undefined;
600                         if (obj !== null && typeof obj !== "undefined") {
601                                 gc_handle = obj.__mono_gchandle__;
602                                 if (typeof gc_handle === "undefined") {
603                                         var handle = this.mono_wasm_free_list.length ?
604                                                                 this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
605                                         gc_handle = handle + 1;
606                                         obj.__mono_gchandle__ = this.wasm_binding_obj_new(gc_handle);
607                                                 
608                                 }
609                                 this.mono_wasm_object_registry[handle] = obj;
610                         }
611                         return gc_handle;
612                 },
613                 mono_wasm_require_handle: function(handle) {
614                         if (handle > 0)
615                                 return this.mono_wasm_object_registry[handle - 1];
616                         return null;
617                 },
618                 mono_wasm_unregister_obj: function(js_id) {
619                         var obj = this.mono_wasm_object_registry[js_id - 1]
620                         if (typeof obj  !== "undefined" && obj !== null) {
621                                 var gc_handle = obj.__mono_gchandle__;
622                                 if (typeof gc_handle  !== "undefined") {
623                                         this.wasm_unbind_js_obj_and_free(js_id);
624                                         delete obj.__mono_gchandle__;
625                                         this.mono_wasm_free_list.push(js_id - 1);
626                                         return obj;
627                                 }
628                         }
629                         return null;
630                 },
631                 mono_wasm_free_handle: function(handle) {
632                         this.mono_wasm_unregister_obj(handle);
633                 },
634         },
636         mono_wasm_invoke_js_with_args: function(js_handle, method_name, args, is_exception) {
637                 BINDING.bindings_lazy_init ();
639                 var obj = BINDING.get_js_obj (js_handle);
640                 if (!obj) {
641                         setValue (is_exception, 1, "i32");
642                         return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
643                 }
645                 var js_name = BINDING.conv_string (method_name);
646                 if (!js_name) {
647                         setValue (is_exception, 1, "i32");
648                         return BINDING.js_string_to_mono_string ("Invalid method name object '" + method_name + "'");
649                 }
651                 var js_args = BINDING.mono_array_to_js_array(args);
653                 var res;
654                 try {
655                         var m = obj [js_name];
656                         var res = m.apply (obj, js_args);
657                         return BINDING.js_to_mono_obj (res);
658                 } catch (e) {
659                         var res = e.toString ();
660                         setValue (is_exception, 1, "i32");
661                         if (res === null || res === undefined)
662                                 res = "unknown exception";
663                         return BINDING.js_string_to_mono_string (res);
664                 }
665         },
666         mono_wasm_get_object_property: function(js_handle, property_name, is_exception) {
667                 BINDING.bindings_lazy_init ();
669                 var obj = BINDING.mono_wasm_require_handle (js_handle);
670                 if (!obj) {
671                         setValue (is_exception, 1, "i32");
672                         return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
673                 }
675                 var js_name = BINDING.conv_string (property_name);
676                 if (!js_name) {
677                         setValue (is_exception, 1, "i32");
678                         return BINDING.js_string_to_mono_string ("Invalid property name object '" + js_name + "'");
679                 }
681                 var res;
682                 try {
683                         var m = obj [js_name];
684                         if (m === Object(m) && obj.__is_mono_proxied__)
685                                 m.__is_mono_proxied__ = true;
686                                 
687                         return BINDING.js_to_mono_obj (m);
688                 } catch (e) {
689                         var res = e.toString ();
690                         setValue (is_exception, 1, "i32");
691                         if (res === null || typeof res === "undefined")
692                                 res = "unknown exception";
693                         return BINDING.js_string_to_mono_string (res);
694                 }
695         },
696     mono_wasm_set_object_property: function (js_handle, property_name, value, createIfNotExist, hasOwnProperty, is_exception) {
698                 BINDING.bindings_lazy_init ();
700                 var requireObject = BINDING.mono_wasm_require_handle (js_handle);
701                 if (!requireObject) {
702                         setValue (is_exception, 1, "i32");
703                         return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
704                 }
706                 var property = BINDING.conv_string (property_name);
707                 if (!property) {
708                         setValue (is_exception, 1, "i32");
709                         return BINDING.js_string_to_mono_string ("Invalid property name object '" + property_name + "'");
710                 }
712         var result = false;
714                 var js_value = BINDING.unbox_mono_obj(value);
716         if (createIfNotExist) {
717             requireObject[property] = js_value;
718             result = true;
719         }
720         else {
721                         result = false;
722                         if (!createIfNotExist)
723                         {
724                                 if (!requireObject.hasOwnProperty(property))
725                                         return false;
726                         }
727             if (hasOwnProperty === true) {
728                 if (requireObject.hasOwnProperty(property)) {
729                     requireObject[property] = js_value;
730                     result = true;
731                 }
732             }
733             else {
734                 requireObject[property] = js_value;
735                 result = true;
736             }
737         
738         }
739         return BINDING.call_method (BINDING.box_js_bool, null, "im", [ result ]);
740     },
744 autoAddDeps(BindingSupportLib, '$BINDING')
745 mergeInto(LibraryManager.library, BindingSupportLib)