Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/sdks
diff options
context:
space:
mode:
authorKenneth Pouncey <kjpou@pt.lu>2018-08-13 12:41:38 +0300
committerAlexander Köplinger <alex.koeplinger@outlook.com>2018-08-13 12:41:38 +0300
commit6db65716f323a61283017dfab410df15cae85fef (patch)
tree6cabb66933948d5d117fb78017244a108e65f43b /sdks
parent3d4ba670f1fd81952596097054e2163a7d4167e0 (diff)
[wasm] Add support for marshalling ArrayBuffer and TypeArrays (#10023)
* Add support for marshalling ArrayBuffer and TypeArrays from JavaScript to C#. - The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer. More Info ---> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays#ArrayBuffer - JavaScript typed arrays are array-like objects and provide a mechanism for accessing raw binary data. (...). More Info ---> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays - Some examples of API's that use these are Fetch, WebGL, Canvas, Web Audio API, XMLHttpRequests, WebSockets, Web Workers, Media Source API and File APIs. | ArrayBuffer | uint8_t | byte[] | byte or Byte (unsigned byte) | Int8Array | int8_t | sbyte[] | byte or SByte (signed byte) | Uint8Array | uint8_t | byte[] | byte or Byte (unsigned byte) | Uint8ClampedArray| uint8_t | byte[] | byte or Byte (unsigned byte) | Int16Array | int16_t | short[] | short (signed short) | Uint16Array | uint16_t | ushort[] | ushort (unsigned short) | Int32Array | int32_t | int[] | int (signed integer) | Uint32Array | uint32_t | uint[] | uint (unsigned integer) | Float32Array | floa t | float[] | float | Float64Array | double | double[] | double - Added tests to the bindings-test test harness. * Add support for marshalling TypeArrays from C# to JavaScript. - Add tests to test harness.
Diffstat (limited to 'sdks')
-rw-r--r--sdks/wasm/binding_support.js156
-rw-r--r--sdks/wasm/bindings-test.cs419
-rw-r--r--sdks/wasm/driver.c111
3 files changed, 685 insertions, 1 deletions
diff --git a/sdks/wasm/binding_support.js b/sdks/wasm/binding_support.js
index 7e5ca206d4c..280192719a7 100644
--- a/sdks/wasm/binding_support.js
+++ b/sdks/wasm/binding_support.js
@@ -37,6 +37,10 @@ var BindingSupportLib = {
this.mono_obj_array_new = Module.cwrap ('mono_wasm_obj_array_new', 'number', ['number']);
this.mono_obj_array_set = Module.cwrap ('mono_wasm_obj_array_set', 'void', ['number', 'number', 'number']);
+ // receives a byteoffset into allocated Heap with a size.
+ this.mono_typed_array_new = Module.cwrap ('mono_wasm_typed_array_new', 'number', ['number','number','number','number']);
+ this.mono_array_to_heap = Module.cwrap ('mono_wasm_array_to_heap', 'void', ['number','number']);
+
var binding_fqn_asm = this.BINDING_ASM.substring(this.BINDING_ASM.indexOf ("[") + 1, this.BINDING_ASM.indexOf ("]")).trim();
var binding_fqn_class = this.BINDING_ASM.substring (this.BINDING_ASM.indexOf ("]") + 1).trim();
@@ -168,6 +172,19 @@ var BindingSupportLib = {
case 8: // bool
return this.mono_unbox_int (mono_obj) != 0;
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ {
+ var res = this.mono_array_to_js_typedarray(type, mono_obj);
+ return res;
+ }
+
default:
throw new Error ("no idea on how to unbox object kind " + type);
}
@@ -185,6 +202,95 @@ var BindingSupportLib = {
this.call_method (this.set_tcs_failure, null, "os", [ tcs, reason.toString () ]);
},
+ // https://github.com/Planeshifter/emscripten-examples/blob/master/01_PassingArrays/sum_post.js
+ js_typedarray_to_heap: function(typedArray){
+ var numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
+ var ptr = Module._malloc(numBytes);
+ var heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes);
+ heapBytes.set(new Uint8Array(typedArray.buffer));
+ return heapBytes;
+ },
+ mono_array_to_js_typedarray: function(type, mono_array){
+
+ // length of our array
+ var szLength = this.mono_array_length(mono_array);
+
+ // The element size that will need to be allocated
+ var bytes_per_element = 0;
+
+ switch (type)
+ {
+ case 11:
+ bytes_per_element = Int8Array.BYTES_PER_ELEMENT;
+ break;
+ case 12:
+ bytes_per_element = Uint8Array.BYTES_PER_ELEMENT;
+ break;
+ case 13:
+ bytes_per_element = Int16Array.BYTES_PER_ELEMENT;
+ break;
+ case 14:
+ bytes_per_element = Uint16Array.BYTES_PER_ELEMENT;
+ break;
+ case 15:
+ bytes_per_element = Int32Array.BYTES_PER_ELEMENT;
+ break;
+ case 16:
+ bytes_per_element = Uint32Array.BYTES_PER_ELEMENT;
+ break;
+ case 17:
+ bytes_per_element = Float32Array.BYTES_PER_ELEMENT;
+ break;
+ case 18:
+ bytes_per_element = Float64Array.BYTES_PER_ELEMENT;
+ break;
+ }
+
+ // Allocate bytes needed for the array of bytes
+ var bufferSize = szLength * bytes_per_element;
+ var bufferPtr = Module._malloc(bufferSize);
+
+ // blit the mono array to the heap
+ this.mono_array_to_heap(mono_array, bufferPtr);
+
+ // result to be returned
+ var res = null;
+
+ // We now need to create a new typed array based off the heap view
+ switch (type)
+ {
+ case 11:
+ res = Module.HEAP8.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
+ break;
+ case 12:
+ res = Module.HEAPU8.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
+ break;
+ case 13:
+ res = Module.HEAP16.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
+ break;
+ case 14:
+ res = Module.HEAPU16.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
+ break;
+ case 15:
+ res = Module.HEAP32.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
+ break;
+ case 16:
+ res = Module.HEAPU32.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
+ break;
+ case 17:
+ res = Module.HEAPF32.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
+ break;
+ case 18:
+ res = Module.HEAPF64.slice(bufferPtr / bytes_per_element, bufferPtr / bytes_per_element + szLength);
+ break;
+ }
+
+ // free the allocated memory
+ Module._free(bufferPtr);
+ // return new typed array
+ return res;
+
+ },
js_to_mono_obj: function (js_obj) {
this.bindings_lazy_init ();
@@ -216,6 +322,56 @@ var BindingSupportLib = {
return this.get_task_and_bind (tcs, js_obj);
}
+
+ // JavaScript typed arrays are array-like objects and provide a mechanism for accessing
+ // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays
+ // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
+ // is an object representing a chunk of data; it has no format to speak of, and offers no
+ // mechanism for accessing its contents. In order to access the memory contained in a buffer,
+ // you need to use a view. A view provides a context — that is, a data type, starting offset,
+ // and number of elements — that turns the data into an actual typed array.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
+ if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT))
+ {
+ var arrayType = 0;
+ if (js_obj instanceof Int8Array)
+ arrayType = 11;
+ if (js_obj instanceof Uint8Array)
+ arrayType = 12;
+ if (js_obj instanceof Uint8ClampedArray)
+ arrayType = 12;
+ if (js_obj instanceof Int16Array)
+ arrayType = 13;
+ if (js_obj instanceof Uint16Array)
+ arrayType = 14;
+ if (js_obj instanceof Int32Array)
+ arrayType = 15;
+ if (js_obj instanceof Uint32Array)
+ arrayType = 16;
+ if (js_obj instanceof Float32Array)
+ arrayType = 17;
+ if (js_obj instanceof Float64Array)
+ arrayType = 18;
+
+ var heapBytes = this.js_typedarray_to_heap(js_obj);
+ var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, js_obj.length, js_obj.BYTES_PER_ELEMENT, arrayType);
+ Module._free(heapBytes.byteOffset);
+ return bufferArray;
+ }
+ // The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.
+ // You cannot directly manipulate the contents of an ArrayBuffer; instead, you create one of the
+ // typed array objects or a DataView object which represents the buffer in a specific format, and
+ // use that to read and write the contents of the buffer.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays#ArrayBuffer
+ if (ArrayBuffer.isView(js_obj) || js_obj instanceof ArrayBuffer)
+ {
+ var heapBytes = this.js_typedarray_to_heap(new Uint8Array(js_obj));
+
+ var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, heapBytes.length, heapBytes.BYTES_PER_ELEMENT, 2);
+ Module._free(heapBytes.byteOffset);
+ return bufferArray;
+ }
+
return this.extract_mono_obj (js_obj);
},
diff --git a/sdks/wasm/bindings-test.cs b/sdks/wasm/bindings-test.cs
index 120d5bce10e..9b4bccf33a2 100644
--- a/sdks/wasm/bindings-test.cs
+++ b/sdks/wasm/bindings-test.cs
@@ -147,6 +147,129 @@ public class TestClass {
obj.SetObjectProperty ("myBoolean", true, createIfNotExist);
}
+ public static byte[] byteBuffer;
+ public static void MarshalByteBuffer (byte[] buffer) {
+ byteBuffer = buffer;
+ }
+
+ public static int[] intBuffer;
+ public static void MarshalInt32Array (int[] buffer) {
+ intBuffer = buffer;
+ }
+
+ public static void MarshalByteBufferToInts (byte[] buffer) {
+ intBuffer = new int[buffer.Length / sizeof(int)];
+ for (int i = 0; i < buffer.Length; i += sizeof(int))
+ intBuffer[i / sizeof(int)] = BitConverter.ToInt32(buffer, i);
+ }
+
+ public static float[] floatBuffer;
+ public static void MarshalFloat32Array (float[] buffer) {
+ floatBuffer = buffer;
+ }
+
+ public static void MarshalByteBufferToFloats (byte[] buffer) {
+ floatBuffer = new float[buffer.Length / sizeof(float)];
+ for (int i = 0; i < buffer.Length; i += sizeof(float))
+ floatBuffer[i / sizeof(float)] = BitConverter.ToSingle(buffer, i);
+ }
+
+
+ public static double[] doubleBuffer;
+ public static void MarshalFloat64Array (double[] buffer) {
+ doubleBuffer = buffer;
+ }
+
+ public static void MarshalByteBufferToDoubles (byte[] buffer) {
+ doubleBuffer = new double[buffer.Length / sizeof(double)];
+ for (int i = 0; i < buffer.Length; i += sizeof(double))
+ doubleBuffer[i / sizeof(double)] = BitConverter.ToDouble(buffer, i);
+ }
+
+ public static void SetTypedArraySByte (JSObject obj) {
+ sbyte[] buffer = Enumerable.Repeat((sbyte)0x20, 11).ToArray();
+ obj.SetObjectProperty ("typedArray", buffer);
+ }
+
+ public static sbyte[] taSByte;
+ public static void GetTypedArraySByte (JSObject obj) {
+ taSByte = (sbyte[])obj.GetObjectProperty ("typedArray");
+ }
+
+ public static void SetTypedArrayByte (JSObject obj) {
+ var dragons = "hic sunt dracones";
+ byte[] buffer = System.Text.Encoding.ASCII.GetBytes(dragons);
+ obj.SetObjectProperty ("dracones", buffer);
+ }
+
+ public static byte[] taByte;
+ public static void GetTypedArrayByte (JSObject obj) {
+ taByte = (byte[])obj.GetObjectProperty ("dracones");
+ }
+
+ public static void SetTypedArrayShort (JSObject obj) {
+ short[] buffer = Enumerable.Repeat((short)0x20, 13).ToArray();
+ obj.SetObjectProperty ("typedArray", buffer);
+ }
+
+ public static short[] taShort;
+ public static void GetTypedArrayShort (JSObject obj) {
+ taShort = (short[])obj.GetObjectProperty ("typedArray");
+ }
+
+ public static void SetTypedArrayUShort (JSObject obj) {
+ ushort[] buffer = Enumerable.Repeat((ushort)0x20, 14).ToArray();
+ obj.SetObjectProperty ("typedArray", buffer);
+ }
+
+ public static ushort[] taUShort;
+ public static void GetTypedArrayUShort (JSObject obj) {
+ taUShort = (ushort[])obj.GetObjectProperty ("typedArray");
+ }
+
+
+ public static void SetTypedArrayInt (JSObject obj) {
+ int[] buffer = Enumerable.Repeat((int)0x20, 15).ToArray();
+ obj.SetObjectProperty ("typedArray", buffer);
+ }
+
+ public static int[] taInt;
+ public static void GetTypedArrayInt (JSObject obj) {
+ taInt = (int[])obj.GetObjectProperty ("typedArray");
+ }
+
+ public static void SetTypedArrayUInt (JSObject obj) {
+ uint[] buffer = Enumerable.Repeat((uint)0x20, 16).ToArray();
+ obj.SetObjectProperty ("typedArray", buffer);
+ }
+
+ public static uint[] taUInt;
+ public static void GetTypedArrayUInt (JSObject obj) {
+ taUInt = (uint[])obj.GetObjectProperty ("typedArray");
+ }
+
+ public static void SetTypedArrayFloat (JSObject obj) {
+ float[] buffer = Enumerable.Repeat(3.14f, 17).ToArray();
+ obj.SetObjectProperty ("typedArray", buffer);
+ }
+
+ public static float[] taFloat;
+ public static void GetTypedArrayFloat (JSObject obj) {
+ taFloat = (float[])obj.GetObjectProperty ("typedArray");
+ }
+
+
+ public static void SetTypedArrayDouble (JSObject obj) {
+ double[] buffer = Enumerable.Repeat(3.14d, 18).ToArray();
+ obj.SetObjectProperty ("typedArray", buffer);
+ }
+
+ public static double[] taDouble;
+ public static void GetTypedArrayDouble (JSObject obj) {
+ taDouble = (double[])obj.GetObjectProperty ("typedArray");
+ }
+
+
}
[TestFixture]
@@ -502,4 +625,300 @@ public class BindingTests {
}
+ [Test]
+ public static void MarshalArrayBuffer () {
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(16);
+ call_test_method (""MarshalByteBuffer"", ""o"", [ buffer ]);
+ ");
+
+ Assert.AreEqual (16, TestClass.byteBuffer.Length);
+ }
+
+ [Test]
+ public static void MarshalArrayBuffer2Int () {
+ // This really does not work to be honest
+ // The length of the marshalled array is 16 ints but
+ // the first 4 ints will be correct and the rest will
+ // probably be trash from memory
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(16);
+ var int32View = new Int32Array(buffer);
+ for (var i = 0; i < int32View.length; i++) {
+ int32View[i] = i * 2;
+ }
+ call_test_method (""MarshalInt32Array"", ""o"", [ buffer ]);
+ ");
+
+ Assert.AreEqual (16, TestClass.intBuffer.Length);
+ Assert.AreEqual (0, TestClass.intBuffer[0]);
+ Assert.AreEqual (2, TestClass.intBuffer[1]);
+ Assert.AreEqual (4, TestClass.intBuffer[2]);
+ Assert.AreEqual (6, TestClass.intBuffer[3]);
+ }
+
+ [Test]
+ public static void MarshalArrayBuffer2Int2 () {
+
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(16);
+ var int32View = new Int32Array(buffer);
+ for (var i = 0; i < int32View.length; i++) {
+ int32View[i] = i * 2;
+ }
+ call_test_method (""MarshalByteBufferToInts"", ""o"", [ buffer ]);
+ ");
+
+ Assert.AreEqual (4, TestClass.intBuffer.Length);
+ Assert.AreEqual (0, TestClass.intBuffer[0]);
+ Assert.AreEqual (2, TestClass.intBuffer[1]);
+ Assert.AreEqual (4, TestClass.intBuffer[2]);
+ Assert.AreEqual (6, TestClass.intBuffer[3]);
+ }
+
+
+ [Test]
+ public static void MarshalTypedArray () {
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(16);
+ var uint8View = new Uint8Array(buffer);
+ call_test_method (""MarshalByteBuffer"", ""o"", [ uint8View ]);
+ ");
+
+ Assert.AreEqual (16, TestClass.byteBuffer.Length);
+ }
+
+ [Test]
+ public static void MarshalTypedArray2Int () {
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(16);
+ var int32View = new Int32Array(buffer);
+ for (var i = 0; i < int32View.length; i++) {
+ int32View[i] = i * 2;
+ }
+ call_test_method (""MarshalInt32Array"", ""o"", [ int32View ]);
+ ");
+
+ Assert.AreEqual (4, TestClass.intBuffer.Length);
+ Assert.AreEqual (0, TestClass.intBuffer[0]);
+ Assert.AreEqual (2, TestClass.intBuffer[1]);
+ Assert.AreEqual (4, TestClass.intBuffer[2]);
+ Assert.AreEqual (6, TestClass.intBuffer[3]);
+ }
+
+ [Test]
+ public static void MarshalTypedArray2Float () {
+ Runtime.InvokeJS (@"
+ var typedArray = new Float32Array([1, 2.1334, 3, 4.2, 5]);
+ call_test_method (""MarshalFloat32Array"", ""o"", [ typedArray ]);
+ ");
+
+ Assert.AreEqual (1, TestClass.floatBuffer[0]);
+ Assert.AreEqual (2.1334f, TestClass.floatBuffer[1]);
+ Assert.AreEqual (3, TestClass.floatBuffer[2]);
+ Assert.AreEqual (4.2f, TestClass.floatBuffer[3]);
+ Assert.AreEqual (5, TestClass.floatBuffer[4]);
+ }
+
+ [Test]
+ public static void MarshalArrayBuffer2Float () {
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(16);
+ var float32View = new Float32Array(buffer);
+ for (var i = 0; i < float32View.length; i++) {
+ float32View[i] = i * 2.5;
+ }
+ call_test_method (""MarshalByteBufferToFloats"", ""o"", [ buffer ]);
+ ");
+
+ Assert.AreEqual (4, TestClass.floatBuffer.Length);
+ Assert.AreEqual (0, TestClass.floatBuffer[0]);
+ Assert.AreEqual (2.5f, TestClass.floatBuffer[1]);
+ Assert.AreEqual (5, TestClass.floatBuffer[2]);
+ Assert.AreEqual (7.5f, TestClass.floatBuffer[3]);
+ }
+
+ [Test]
+ public static void MarshalArrayBuffer2Float2 () {
+ // This really does not work to be honest
+ // The length of the marshalled array is 16 floats but
+ // the first 4 floats will be correct and the rest will
+ // probably be trash from memory
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(16);
+ var float32View = new Float32Array(buffer);
+ for (var i = 0; i < float32View.length; i++) {
+ float32View[i] = i * 2.5;
+ }
+ call_test_method (""MarshalFloat32Array"", ""o"", [ buffer ]);
+ ");
+
+ Assert.AreEqual (16, TestClass.floatBuffer.Length);
+ Assert.AreEqual (0, TestClass.floatBuffer[0]);
+ Assert.AreEqual (2.5f, TestClass.floatBuffer[1]);
+ Assert.AreEqual (5, TestClass.floatBuffer[2]);
+ Assert.AreEqual (7.5f, TestClass.floatBuffer[3]);
+ }
+
+ [Test]
+ public static void MarshalTypedArray2Double () {
+ Runtime.InvokeJS (@"
+ var typedArray = new Float64Array([1, 2.1334, 3, 4.2, 5]);
+ call_test_method (""MarshalFloat64Array"", ""o"", [ typedArray ]);
+ ");
+
+ Assert.AreEqual (1, TestClass.doubleBuffer[0]);
+ Assert.AreEqual (2.1334d, TestClass.doubleBuffer[1]);
+ Assert.AreEqual (3, TestClass.doubleBuffer[2]);
+ Assert.AreEqual (4.2d, TestClass.doubleBuffer[3]);
+ Assert.AreEqual (5, TestClass.doubleBuffer[4]);
+ }
+
+ [Test]
+ public static void MarshalArrayBuffer2Double () {
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(32);
+ var float64View = new Float64Array(buffer);
+ for (var i = 0; i < float64View.length; i++) {
+ float64View[i] = i * 2.5;
+ }
+ call_test_method (""MarshalByteBufferToDoubles"", ""o"", [ buffer ]);
+ ");
+
+ Assert.AreEqual (4, TestClass.doubleBuffer.Length);
+ Assert.AreEqual (0, TestClass.doubleBuffer[0]);
+ Assert.AreEqual (2.5d, TestClass.doubleBuffer[1]);
+ Assert.AreEqual (5, TestClass.doubleBuffer[2]);
+ Assert.AreEqual (7.5d, TestClass.doubleBuffer[3]);
+ }
+
+ [Test]
+ public static void MarshalArrayBuffer2Double2 () {
+ // This really does not work to be honest
+ // The length of the marshalled array is 32 doubles but
+ // the first 4 doubles will be correct and the rest will
+ // probably be trash from memory
+ Runtime.InvokeJS (@"
+ var buffer = new ArrayBuffer(32);
+ var float64View = new Float64Array(buffer);
+ for (var i = 0; i < float64View.length; i++) {
+ float64View[i] = i * 2.5;
+ }
+ call_test_method (""MarshalFloat64Array"", ""o"", [ buffer ]);
+ ");
+
+ Assert.AreEqual (32, TestClass.doubleBuffer.Length);
+ Assert.AreEqual (0, TestClass.doubleBuffer[0]);
+ Assert.AreEqual (2.5f, TestClass.doubleBuffer[1]);
+ Assert.AreEqual (5, TestClass.doubleBuffer[2]);
+ Assert.AreEqual (7.5f, TestClass.doubleBuffer[3]);
+ }
+
+ [Test]
+ public static void MarshalTypedArraySByte () {
+ TestClass.int_val = 0;
+ Runtime.InvokeJS (@"
+ var obj = { };
+ call_test_method (""SetTypedArraySByte"", ""o"", [ obj ]);
+ call_test_method (""GetTypedArraySByte"", ""o"", [ obj ]);
+ ");
+ Assert.AreEqual (11, TestClass.taSByte.Length);
+ Assert.AreEqual (32, TestClass.taSByte[0]);
+ Assert.AreEqual (32, TestClass.taSByte[TestClass.taSByte.Length - 1]);
+ }
+
+ [Test]
+ public static void MarshalTypedArrayByte () {
+ TestClass.int_val = 0;
+ Runtime.InvokeJS (@"
+ var obj = { };
+ call_test_method (""SetTypedArrayByte"", ""o"", [ obj ]);
+ call_test_method (""GetTypedArrayByte"", ""o"", [ obj ]);
+ ");
+ Assert.AreEqual (17, TestClass.taByte.Length);
+ Assert.AreEqual (104, TestClass.taByte[0]);
+ Assert.AreEqual (115, TestClass.taByte[TestClass.taByte.Length - 1]);
+ Assert.AreEqual ("hic sunt dracones", System.Text.Encoding.Default.GetString(TestClass.taByte));
+ }
+
+ [Test]
+ public static void MarshalTypedArrayShort () {
+ TestClass.int_val = 0;
+ Runtime.InvokeJS (@"
+ var obj = { };
+ call_test_method (""SetTypedArrayShort"", ""o"", [ obj ]);
+ call_test_method (""GetTypedArrayShort"", ""o"", [ obj ]);
+ ");
+ Assert.AreEqual (13, TestClass.taShort.Length);
+ Assert.AreEqual (32, TestClass.taShort[0]);
+ Assert.AreEqual (32, TestClass.taShort[TestClass.taShort.Length - 1]);
+ }
+
+ [Test]
+ public static void MarshalTypedArrayUShort () {
+ TestClass.int_val = 0;
+ Runtime.InvokeJS (@"
+ var obj = { };
+ call_test_method (""SetTypedArrayUShort"", ""o"", [ obj ]);
+ call_test_method (""GetTypedArrayUShort"", ""o"", [ obj ]);
+ ");
+ Assert.AreEqual (14, TestClass.taUShort.Length);
+ Assert.AreEqual (32, TestClass.taUShort[0]);
+ Assert.AreEqual (32, TestClass.taUShort[TestClass.taUShort.Length - 1]);
+ }
+
+
+ [Test]
+ public static void MarshalTypedArrayInt () {
+ TestClass.int_val = 0;
+ Runtime.InvokeJS (@"
+ var obj = { };
+ call_test_method (""SetTypedArrayInt"", ""o"", [ obj ]);
+ call_test_method (""GetTypedArrayInt"", ""o"", [ obj ]);
+ ");
+ Assert.AreEqual (15, TestClass.taInt.Length);
+ Assert.AreEqual (32, TestClass.taInt[0]);
+ Assert.AreEqual (32, TestClass.taInt[TestClass.taInt.Length - 1]);
+ }
+
+ [Test]
+ public static void MarshalTypedArrayUInt () {
+ TestClass.int_val = 0;
+ Runtime.InvokeJS (@"
+ var obj = { };
+ call_test_method (""SetTypedArrayUInt"", ""o"", [ obj ]);
+ call_test_method (""GetTypedArrayUInt"", ""o"", [ obj ]);
+ ");
+ Assert.AreEqual (16, TestClass.taUInt.Length);
+ Assert.AreEqual (32, TestClass.taUInt[0]);
+ Assert.AreEqual (32, TestClass.taUInt[TestClass.taUInt.Length - 1]);
+ }
+
+ [Test]
+ public static void MarshalTypedArrayFloat () {
+ TestClass.int_val = 0;
+ Runtime.InvokeJS (@"
+ var obj = { };
+ call_test_method (""SetTypedArrayFloat"", ""o"", [ obj ]);
+ call_test_method (""GetTypedArrayFloat"", ""o"", [ obj ]);
+ ");
+ Assert.AreEqual (17, TestClass.taFloat.Length);
+ Assert.AreEqual (3.14f, TestClass.taFloat[0]);
+ Assert.AreEqual (3.14f, TestClass.taFloat[TestClass.taFloat.Length - 1]);
+ }
+
+
+ [Test]
+ public static void MarshalTypedArrayDouble () {
+ TestClass.int_val = 0;
+ Runtime.InvokeJS (@"
+ var obj = { };
+ call_test_method (""SetTypedArrayDouble"", ""o"", [ obj ]);
+ call_test_method (""GetTypedArrayDouble"", ""o"", [ obj ]);
+ ");
+ Assert.AreEqual (18, TestClass.taDouble.Length);
+ Assert.AreEqual (3.14d, TestClass.taDouble[0]);
+ Assert.AreEqual (3.14d, TestClass.taDouble[TestClass.taDouble.Length - 1]);
+ }
+
}
diff --git a/sdks/wasm/driver.c b/sdks/wasm/driver.c
index ee339bae7fa..64f152c309a 100644
--- a/sdks/wasm/driver.c
+++ b/sdks/wasm/driver.c
@@ -131,6 +131,15 @@ MonoClass* mono_get_object_class (void);
int mono_class_is_delegate (MonoClass* klass);
const char* mono_class_get_name (MonoClass *klass);
const char* mono_class_get_namespace (MonoClass *klass);
+MonoClass* mono_get_byte_class (void);
+MonoClass* mono_get_sbyte_class (void);
+MonoClass* mono_get_int16_class (void);
+MonoClass* mono_get_uint16_class (void);
+MonoClass* mono_get_int32_class (void);
+MonoClass* mono_get_uint32_class (void);
+MonoClass* mono_get_single_class (void);
+MonoClass* mono_get_double_class (void);
+MonoClass* mono_class_get_element_class(MonoClass *klass);
#define mono_array_get(array,type,index) ( *(type*)mono_array_addr ((array), type, (index)) )
#define mono_array_addr(array,type,index) ((type*)(void*) mono_array_addr_with_size (array, sizeof (type), index))
@@ -144,6 +153,7 @@ const char* mono_class_get_namespace (MonoClass *klass);
char* mono_array_addr_with_size (MonoArray *array, int size, int idx);
int mono_array_length (MonoArray *array);
+int mono_array_element_size(MonoClass *klass);
void mono_gc_wbarrier_set_arrayref (MonoArray *arr, void* slot_ptr, MonoObject* value);
static char*
@@ -296,6 +306,16 @@ class_is_task (MonoClass *klass)
#define MARSHAL_TYPE_OBJECT 7
#define MARSHAL_TYPE_BOOL 8
+// typed array marshalling
+#define MARSHAL_ARRAY_BYTE 11
+#define MARSHAL_ARRAY_UBYTE 12
+#define MARSHAL_ARRAY_SHORT 13
+#define MARSHAL_ARRAY_USHORT 14
+#define MARSHAL_ARRAY_INT 15
+#define MARSHAL_ARRAY_UINT 16
+#define MARSHAL_ARRAY_FLOAT 17
+#define MARSHAL_ARRAY_DOUBLE 18
+
EMSCRIPTEN_KEEPALIVE int
mono_wasm_get_obj_type (MonoObject *obj)
{
@@ -322,6 +342,31 @@ mono_wasm_get_obj_type (MonoObject *obj)
return MARSHAL_TYPE_FP;
case MONO_TYPE_STRING:
return MARSHAL_TYPE_STRING;
+ case MONO_TYPE_SZARRAY: { // simple zero based one-dim-array
+ MonoClass *eklass = mono_class_get_element_class(klass);
+ MonoType *etype = mono_class_get_type (eklass);
+
+ switch (mono_type_get_type (etype)) {
+ case MONO_TYPE_U1:
+ return MARSHAL_ARRAY_UBYTE;
+ case MONO_TYPE_I1:
+ return MARSHAL_ARRAY_BYTE;
+ case MONO_TYPE_U2:
+ return MARSHAL_ARRAY_USHORT;
+ case MONO_TYPE_I2:
+ return MARSHAL_ARRAY_SHORT;
+ case MONO_TYPE_U4:
+ return MARSHAL_ARRAY_UINT;
+ case MONO_TYPE_I4:
+ return MARSHAL_ARRAY_INT;
+ case MONO_TYPE_R4:
+ return MARSHAL_ARRAY_FLOAT;
+ case MONO_TYPE_R8:
+ return MARSHAL_ARRAY_DOUBLE;
+ default:
+ return MARSHAL_TYPE_OBJECT;
+ }
+ }
default:
if (!mono_type_is_reference (type)) //vt
return MARSHAL_TYPE_VT;
@@ -407,4 +452,68 @@ EMSCRIPTEN_KEEPALIVE void
mono_wasm_obj_array_set (MonoArray *array, int idx, MonoObject *obj)
{
mono_array_setref (array, idx, obj);
-} \ No newline at end of file
+}
+
+// Int8Array | int8_t | byte or SByte (signed byte)
+// Uint8Array | uint8_t | byte or Byte (unsigned byte)
+// Uint8ClampedArray| uint8_t | byte or Byte (unsigned byte)
+// Int16Array | int16_t | short (signed short)
+// Uint16Array | uint16_t | ushort (unsigned short)
+// Int32Array | int32_t | int (signed integer)
+// Uint32Array | uint32_t | uint (unsigned integer)
+// Float32Array | float | float
+// Float64Array | double | double
+
+EMSCRIPTEN_KEEPALIVE MonoArray*
+mono_wasm_typed_array_new (char *arr, int length, int size, int type)
+{
+ MonoClass *typeClass = mono_get_byte_class(); // default is Byte
+ switch (type) {
+ case MARSHAL_ARRAY_BYTE:
+ typeClass = mono_get_sbyte_class();
+ break;
+ case MARSHAL_ARRAY_SHORT:
+ typeClass = mono_get_int16_class();
+ break;
+ case MARSHAL_ARRAY_USHORT:
+ typeClass = mono_get_uint16_class();
+ break;
+ case MARSHAL_ARRAY_INT:
+ typeClass = mono_get_int32_class();
+ break;
+ case MARSHAL_ARRAY_UINT:
+ typeClass = mono_get_uint32_class();
+ break;
+ case MARSHAL_ARRAY_FLOAT:
+ typeClass = mono_get_single_class();
+ break;
+ case MARSHAL_ARRAY_DOUBLE:
+ typeClass = mono_get_double_class();
+ break;
+ }
+
+ MonoArray *buffer;
+
+ buffer = mono_array_new (root_domain, typeClass, length);
+ memcpy(mono_array_addr_with_size(buffer, sizeof(char), 0), arr, length * size);
+
+ return buffer;
+}
+
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_array_to_heap (MonoArray *src, char *dest)
+{
+ int element_size;
+ void *source_addr;
+ int arr_length;
+
+ element_size = mono_array_element_size ( mono_object_get_class((MonoObject*)src));
+ //DBG("mono_wasm_to_heap element size %i / length %i\n",element_size, mono_array_length(src));
+
+ // get our src address
+ source_addr = mono_array_addr_with_size (src, element_size, 0);
+ // copy the array memory to heap via ptr dest
+ memcpy (dest, source_addr, mono_array_length(src) * element_size);
+}
+