Ver código fonte

[flutter] Add web_ffi fork, fix .wasm/.js size

The fork is required as Emscripten produces a .wasm file that the upstream web_ffi can't parse correctly to extract exported symbols.
Mario Zechner 2 anos atrás
pai
commit
934e374724

+ 4 - 0
spine-cpp/spine-cpp/src/spine/Extension.cpp

@@ -104,6 +104,7 @@ void DefaultSpineExtension::_free(void *mem, const char *file, int line) {
 }
 }
 
 
 char *DefaultSpineExtension::_readFile(const String &path, int *length) {
 char *DefaultSpineExtension::_readFile(const String &path, int *length) {
+#ifndef __EMSCRIPTEN__
 	char *data;
 	char *data;
 	FILE *file = fopen(path.buffer(), "rb");
 	FILE *file = fopen(path.buffer(), "rb");
 	if (!file) return 0;
 	if (!file) return 0;
@@ -117,6 +118,9 @@ char *DefaultSpineExtension::_readFile(const String &path, int *length) {
 	fclose(file);
 	fclose(file);
 
 
 	return data;
 	return data;
+#else
+	return nullptr;
+#endif
 }
 }
 
 
 DefaultSpineExtension::DefaultSpineExtension() : SpineExtension() {
 DefaultSpineExtension::DefaultSpineExtension() : SpineExtension() {

+ 15 - 2
spine-flutter/README.md

@@ -14,6 +14,21 @@ In order to distribute your software containing the Spine Runtimes to others tha
 
 
 For the official legal terms governing the Spine Runtimes, please read the [Spine Runtimes License Agreement](http://esotericsoftware.com/spine-runtimes-license) and Section 2 of the [Spine Editor License Agreement](http://esotericsoftware.com/spine-editor-license#s2).
 For the official legal terms governing the Spine Runtimes, please read the [Spine Runtimes License Agreement](http://esotericsoftware.com/spine-runtimes-license) and Section 2 of the [Spine Editor License Agreement](http://esotericsoftware.com/spine-editor-license#s2).
 
 
+### Licensing web_ffi
+spine-flutter includes a modified fork of [https://github.com/EPNW/web_ffi](web_ffi) by Eric Prokop und Nils Wieler Hard- und Softwareentwicklung GbR, which is licensed under the [BSD 2-Clause "Simplified" License](https://github.com/EPNW/web_ffi/blob/master/LICENSE).
+
+```
+Copyright 2021 Eric Prokop und Nils Wieler Hard- und Softwareentwicklung GbR
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+```
+
 ## Spine version
 ## Spine version
 
 
 spine-flutter works with data exported from Spine 4.1.xx.
 spine-flutter works with data exported from Spine 4.1.xx.
@@ -37,5 +52,3 @@ The example in this repository is directly depending on the spine-flutter source
 Once installed, run the `setup.sh` script in the `spine-flutter` folder. This will copy [spine-cpp](../spine-cpp) to the appropriate locations.
 Once installed, run the `setup.sh` script in the `spine-flutter` folder. This will copy [spine-cpp](../spine-cpp) to the appropriate locations.
 
 
 You can then open `spine-flutter` in an IDE or editor of your choice that supports Flutter, like [IntelliJ IDEA/Android Studio](https://docs.flutter.dev/get-started/editor?tab=androidstudio) or [Visual Studio Code](https://docs.flutter.dev/get-started/editor?tab=vscode) to inspect and run the example. Alternatively, you can run the example from the [command line](https://docs.flutter.dev/get-started/test-drive?tab=terminal).
 You can then open `spine-flutter` in an IDE or editor of your choice that supports Flutter, like [IntelliJ IDEA/Android Studio](https://docs.flutter.dev/get-started/editor?tab=androidstudio) or [Visual Studio Code](https://docs.flutter.dev/get-started/editor?tab=vscode) to inspect and run the example. Alternatively, you can run the example from the [command line](https://docs.flutter.dev/get-started/test-drive?tab=terminal).
-
-  

+ 0 - 7
spine-flutter/example/pubspec.lock

@@ -172,13 +172,6 @@ packages:
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
     version: "2.1.2"
     version: "2.1.2"
-  web_ffi:
-    dependency: transitive
-    description:
-      name: web_ffi
-      url: "https://pub.dartlang.org"
-    source: hosted
-    version: "0.7.2"
 sdks:
 sdks:
   dart: ">=2.17.6 <3.0.0"
   dart: ">=2.17.6 <3.0.0"
   flutter: ">=2.11.0"
   flutter: ">=2.11.0"

+ 1 - 1
spine-flutter/lib/ffi_proxy.dart

@@ -1 +1 @@
-export 'dart:ffi' if (dart.library.html) 'package:web_ffi/web_ffi.dart';
+export 'dart:ffi' if (dart.library.html) 'web_ffi/web_ffi.dart';

+ 2 - 2
spine-flutter/lib/init_web.dart

@@ -1,8 +1,8 @@
 import 'package:flutter/services.dart';
 import 'package:flutter/services.dart';
 import 'package:inject_js/inject_js.dart' as js;
 import 'package:inject_js/inject_js.dart' as js;
 import 'package:spine_flutter/ffi_utf8.dart';
 import 'package:spine_flutter/ffi_utf8.dart';
-import 'package:web_ffi/web_ffi.dart';
-import 'package:web_ffi/web_ffi_modules.dart';
+import 'web_ffi/web_ffi.dart';
+import 'web_ffi/web_ffi_modules.dart';
 import 'spine_flutter_bindings_generated.dart';
 import 'spine_flutter_bindings_generated.dart';
 
 
 Module? _module;
 Module? _module;

+ 284 - 0
spine-flutter/lib/web_ffi/ffi/extensions.dart

@@ -0,0 +1,284 @@
+import 'dart:typed_data';
+import 'types.dart';
+
+import '../modules/memory.dart';
+import '../modules/module.dart';
+import '../internal/marshaller.dart';
+
+import '../web_ffi_meta.dart';
+
+/// Extension on [Pointer] specialized for the type argument [NativeFunction].
+extension NativeFunctionPointer<NF extends Function>
+    on Pointer<NativeFunction<NF>> {
+  /// Convert to Dart function, automatically marshalling the arguments and return value.
+  ///
+  /// There are several rules that apply for the return type of `DF`, see
+  /// the list of [allowed return types](https://github.com/EPNW/web_ffi/blob/master/return_types.md).
+  /// If marshalling failes, a [MarshallingException] is thrown.
+  ///
+  /// If this is called on a pointer that does not point to a function,
+  /// a [ArgumentError](https://api.dart.dev/stable/dart-core/ArgumentError-class.html) is thrown.
+  DF asFunction<DF extends Function>() {
+    WasmSymbol symbol = symbolByAddress(boundMemory, address);
+    if (symbol is FunctionDescription) {
+      return marshall<NF, DF>(symbol.function, boundMemory);
+    } else {
+      throw ArgumentError(
+          'No function at address $address was found (but a global symbol)!');
+    }
+  }
+}
+
+extension DynamicLibraryExtension on DynamicLibrary {
+  /// Helper that combines lookup and cast to a Dart function.
+  ///
+  /// This simply calles [DynamicLibrary.lookup] and [NativeFunctionPointer.asFunction]
+  /// internally, so see this two methods for additional insights.
+  F lookupFunction<T extends Function, F extends Function>(String name) =>
+      this.lookup<NativeFunction<T>>(name).asFunction<F>();
+}
+
+/// Extension on [Allocator] to provide allocation with [NativeType].
+extension AllocatorAlloc on Allocator {
+  /// Allocates `sizeOf<T>() * count` bytes of memory using [Allocator.allocate].
+  ///
+  /// Since this calls [sizeOf<T>] internally, an exception will be thrown if this
+  /// method is called with an @[unsized] type or before [Memory.init] was called.
+  Pointer<T> call<T extends NativeType>([int count = 1]) =>
+      allocate(sizeOf<T>() * count);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Float].
+extension FloatPointer on Pointer<Float> {
+  /// The float at address.
+  double get value => this[0];
+  void set value(double value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Float32List asTypedList(int length) =>
+      boundMemory.buffer.asFloat32List(address, length);
+
+  /// The float at `address + size * index`.
+  double operator [](int index) =>
+      viewSingle(index).getFloat32(0, Memory.endianess);
+  void operator []=(int index, double value) =>
+      viewSingle(index).setFloat32(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Double].
+extension DoublePointer on Pointer<Double> {
+  /// The double at address.
+  double get value => this[0];
+  void set value(double value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Float64List asTypedList(int length) =>
+      boundMemory.buffer.asFloat64List(address, length);
+
+  /// The double at `address + size * index`.
+  double operator [](int index) =>
+      viewSingle(index).getFloat64(0, Memory.endianess);
+  void operator []=(int index, double value) =>
+      viewSingle(index).setFloat64(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int8].
+extension Int8Pointer on Pointer<Int8> {
+  /// The 8-bit integer at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Int8List asTypedList(int length) =>
+      boundMemory.buffer.asInt8List(address, length);
+
+  /// The 8-bit integer at `address + size * index`.
+  int operator [](int index) => viewSingle(index).getInt8(0);
+  void operator []=(int index, int value) =>
+      viewSingle(index).setInt8(0, value);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int16].
+extension Int16Pointer on Pointer<Int16> {
+  /// The 16-bit integer at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Int16List asTypedList(int length) =>
+      boundMemory.buffer.asInt16List(address, length);
+
+  /// The 16-bit integer at `address + size * index`.
+  int operator [](int index) => viewSingle(index).getInt16(0, Memory.endianess);
+  void operator []=(int index, int value) =>
+      viewSingle(index).setInt16(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int32].
+extension Int32Pointer on Pointer<Int32> {
+  /// The 32-bit integer at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Int32List asTypedList(int length) =>
+      boundMemory.buffer.asInt32List(address, length);
+
+  /// The 32-bit integer at `address + size * index`.
+  int operator [](int index) => viewSingle(index).getInt32(0, Memory.endianess);
+  void operator []=(int index, int value) =>
+      viewSingle(index).setInt32(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int64].
+extension Int64Pointer on Pointer<Int64> {
+  /// The 64-bit integer at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Int64List asTypedList(int length) =>
+      boundMemory.buffer.asInt64List(address, length);
+
+  /// The 64-bit integer at `address + size * index`.
+  int operator [](int index) => viewSingle(index).getInt64(0, Memory.endianess);
+  void operator []=(int index, int value) =>
+      viewSingle(index).setInt64(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint8].
+extension Uint8Pointer on Pointer<Uint8> {
+  /// The 8-bit unsigned integer at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Uint8List asTypedList(int length) =>
+      boundMemory.buffer.asUint8List(address, length);
+
+  /// The 8-bit unsigned integer at `address + size * index`.
+  int operator [](int index) => viewSingle(index).getUint8(0);
+  void operator []=(int index, int value) =>
+      viewSingle(index).setUint8(0, value);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint16].
+extension Uint16Pointer on Pointer<Uint16> {
+  /// The 16-bit unsigned integer at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Uint16List asTypedList(int length) =>
+      boundMemory.buffer.asUint16List(address, length);
+
+  /// The 16-bit unsigned integer at `address + size * index`.
+  int operator [](int index) =>
+      viewSingle(index).getUint16(0, Memory.endianess);
+  void operator []=(int index, int value) =>
+      viewSingle(index).setUint16(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint32].
+extension Uint32Pointer on Pointer<Uint32> {
+  /// The 32-bit unsigned integer at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Uint32List asTypedList(int length) =>
+      boundMemory.buffer.asUint32List(address, length);
+
+  /// The 32-bit unsigned integer at `address + size * index`.
+  int operator [](int index) =>
+      viewSingle(index).getUint32(0, Memory.endianess);
+  void operator []=(int index, int value) =>
+      viewSingle(index).setUint32(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint64].
+extension Uint64Pointer on Pointer<Uint64> {
+  /// The 64-bit unsigned integer at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range
+  /// from address to `address + size * length`.
+  Uint64List asTypedList(int length) =>
+      boundMemory.buffer.asUint64List(address, length);
+
+  /// The 64-bit unsigned integer at `address + size * index`.
+  int operator [](int index) =>
+      viewSingle(index).getUint64(0, Memory.endianess);
+  void operator []=(int index, int value) =>
+      viewSingle(index).setUint64(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [IntPtr].
+extension IntPtrPointer on Pointer<IntPtr> {
+  /// The 32-bit or 64-bit value at `address`.
+  int get value => this[0];
+  void set value(int value) => this[0] = value;
+
+  /// Returns `true` if the size of a pointer is 64-bit, `false` otherwise.
+  @extra
+  bool get is64Bit => size == 8;
+
+  /// The 32-bit or 64-bit integer at `address + size * index`.
+  int operator [](int index) => is64Bit
+      ? viewSingle(index).getUint64(0, Memory.endianess)
+      : viewSingle(index).getUint32(0, Memory.endianess);
+  void operator []=(int index, int value) => is64Bit
+      ? viewSingle(index).setUint64(0, value, Memory.endianess)
+      : viewSingle(index).setUint32(0, value, Memory.endianess);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Pointer].
+extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
+  /// The pointer at `address`.
+  Pointer<T> get value => this[0];
+  void set value(Pointer<T> value) => this[0] = value;
+
+  /// Returns `true` if the size of a pointer is 64-bit, `false` otherwise.
+  @extra
+  bool get is64Bit => size == 8;
+
+  /// The pointer at `address + size * index`.
+  Pointer<T> operator [](int index) => new Pointer<T>.fromAddress(
+      is64Bit
+          ? viewSingle(index).getUint64(0, Memory.endianess)
+          : viewSingle(index).getUint32(0, Memory.endianess),
+      boundMemory);
+  void operator []=(int index, Pointer<T> value) => is64Bit
+      ? viewSingle(index).setUint64(0, value.address, Memory.endianess)
+      : viewSingle(index).setUint32(0, value.address, Memory.endianess);
+}

+ 326 - 0
spine-flutter/lib/web_ffi/ffi/types.dart

@@ -0,0 +1,326 @@
+import 'dart:typed_data';
+import 'package:meta/meta.dart';
+
+import '../modules/module.dart';
+import '../modules/memory.dart';
+import '../modules/null_memory.dart';
+
+import '../internal/type_utils.dart';
+
+import '../web_ffi_meta.dart';
+
+/// Represents a pointer into the native C memory corresponding to "NULL",
+/// e.g. a pointer with address 0.
+///
+/// You can compare any other pointer with this pointer using == to check
+/// if it's also an nullpointer.
+///
+/// Any other operation than comparing (e.g. calling [Pointer.cast])
+/// will result in exceptions.
+final Pointer<Never> nullptr = new Pointer<Never>._null();
+
+/// Number of bytes used by native type T.
+///
+/// MUST NOT be called with types annoteted with @[unsized] or
+/// before [Memory.init()] was called or else an exception will be thrown.
+int sizeOf<T extends NativeType>() {
+  int? size;
+  if (isPointerType<T>()) {
+    size = sizeMap[IntPtr];
+  } else {
+    size = sizeMap[T];
+  }
+  if (size != null) {
+    return size;
+  } else {
+    throw new ArgumentError('The type $T is not known!');
+  }
+}
+
+bool _isUnsizedType<T extends NativeType>() {
+  return isNativeFunctionType<T>() || isVoidType<T>();
+}
+
+/// [NativeType]'s subtypes represent a native type in C.
+///
+/// [NativeType]'s subtypes (except [Pointer]) are not constructible
+/// in the Dart code and serve purely as markers in type signatures.
+@sealed
+@notConstructible
+class NativeType {}
+
+/// Represents a native 64 bit double in C.
+///
+/// Double is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Double extends NativeType {}
+
+/// Represents a native 32 bit float in C.
+///
+/// Float is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Float extends NativeType {}
+
+/// Represents a native signed 8 bit integer in C.
+///
+/// Int8 is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Int8 extends NativeType {}
+
+/// Represents a native signed 16 bit integer in C.
+///
+/// Int16 is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Int16 extends NativeType {}
+
+/// Represents a native signed 32 bit integer in C.
+///
+/// Int32 is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Int32 extends NativeType {}
+
+/// Represents a native signed 64 bit integer in C.
+///
+/// Int64 is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Int64 extends NativeType {}
+
+/// Represents a native unsigned 8 bit integer in C.
+///
+/// Uint8 is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Uint8 extends NativeType {}
+
+/// Represents a native unsigned 16 bit integer in C.
+///
+/// Uint16 is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Uint16 extends NativeType {}
+
+/// Represents a native unsigned 32 bit integer in C.
+///
+/// Uint32 is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Uint32 extends NativeType {}
+
+/// Represents a native unsigned 64 bit integer in C.
+///
+/// Uint64 is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class Uint64 extends NativeType {}
+
+/// Represents a native pointer-sized integer in C.
+///
+/// IntPtr is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+class IntPtr extends NativeType {}
+
+/// Represents a function type in C.
+///
+/// NativeFunction is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+@unsized
+class NativeFunction<T extends Function> extends NativeType {}
+
+/// Opaque's subtypes represent opaque types in C.
+///
+/// Classes that extend Opaque MUST NOT have a type argument!
+///
+/// Opaque's subtypes are not constructible in the Dart code and serve
+/// purely as markers in type signatures.
+@noGeneric
+@notConstructible
+class Opaque extends NativeType {}
+
+/// Represents a void type in C.
+///
+/// Void is not constructible in the Dart code and serves
+/// purely as marker in type signatures.
+@sealed
+@notConstructible
+@unsized
+class Void extends NativeType {}
+
+/// Represents a pointer into the native C memory. Cannot be extended.
+@sealed
+class Pointer<T extends NativeType> extends NativeType {
+  //static Pointer<NativeFunction<T>> fromFunction<T extends Function>(Function f,
+  //       [Object? exceptionalReturn]) =>
+  //   throw new UnimplementedError();
+
+  /// Access to the raw pointer value.
+  final int address;
+
+  /// The [Memory] object this pointer is bound to.
+  ///
+  /// The `Memory` object backs this pointer, if the value of
+  /// this pointer is accessed.
+  @extra
+  final Memory boundMemory;
+
+  /// How much memory in bytes the type this pointer points to occupies,
+  /// or `null` for @[unsized] types.
+  @extra
+  final int? size;
+
+  factory Pointer._null() {
+    return new Pointer._(0, new NullMemory(), null);
+  }
+
+  /// Constructs a pointer from an address.
+  ///
+  /// The optional parameter `bindTo` can be ommited, if and only if
+  /// [Memory.global] is set, which is then used as `Memory` to bind to.
+  factory Pointer.fromAddress(int ptr, [Memory? bindTo]) {
+    bindTo = Memory.global;
+    Memory m;
+    if (bindTo != null) {
+      m = bindTo;
+    } else {
+      throw new StateError(
+          'No global memory set and no explcity memory to bind to given!');
+    }
+    return new Pointer._(ptr, m, _isUnsizedType<T>() ? null : sizeOf<T>());
+  }
+
+  Pointer._(this.address, this.boundMemory, this.size);
+
+  /// Casts this pointer to an other type.
+  Pointer<U> cast<U extends NativeType>() => new Pointer<U>._(
+      address, boundMemory, _isUnsizedType<U>() ? null : sizeOf<U>());
+
+  /// Pointer arithmetic (takes element size into account).
+  ///
+  /// Throws an [UnsupportedError] if called on a pointer with an @[unsized]
+  /// type argument.
+  Pointer<T> elementAt(int index) {
+    int? s = size;
+    if (s != null) {
+      return new Pointer<T>._(address + index * s, boundMemory, s);
+    } else {
+      throw new UnsupportedError(
+          'elementAt is not supported for unsized types!');
+    }
+  }
+
+  /// The hash code for a Pointer only depends on its address.
+  @override
+  int get hashCode => address;
+
+  /// Two pointers are equal if their address is the same, independently
+  /// of their type argument and of the memory they are bound to.
+  @override
+  bool operator ==(Object other) =>
+      (other is Pointer && other.address == address);
+
+  /// Returns a view of a single element at [index] (takes element
+  /// size into account).
+  ///
+  /// Any modifications to the data will also alter the [Memory] object.
+  ///
+  /// Throws an [UnsupportedError] if called on a pointer with an @[unsized]
+  /// type argument.
+  @extra
+  ByteData viewSingle(int index) {
+    int? s = size;
+    if (s != null) {
+      return boundMemory.buffer.asByteData(address + index * s, s);
+    } else {
+      throw new UnsupportedError(
+          'viewSingle is not supported for unsized types!');
+    }
+  }
+}
+
+/// Represents a dynamically loaded C library.
+class DynamicLibrary {
+  @extra
+  final Memory boundMemory;
+
+  /// Creates a new instance based on the given module.
+  ///
+  /// While for each [DynamicLibrary] a new [Memory] object is
+  /// created, the [Memory] objects share the backing memory if
+  /// they are created based on the same module.
+  ///
+  /// The [registerMode] parameter can be used to control if the
+  /// newly created [Memory] object should be registered as
+  /// [Memory.global].
+  @extra
+  factory DynamicLibrary.fromModule(Module module,
+      [MemoryRegisterMode registerMode =
+          MemoryRegisterMode.onlyIfGlobalNotSet]) {
+    Memory memory = createMemory(module);
+    switch (registerMode) {
+      case MemoryRegisterMode.yes:
+        Memory.global = memory;
+        break;
+      case MemoryRegisterMode.no:
+        break;
+      case MemoryRegisterMode.onlyIfGlobalNotSet:
+        if (Memory.global == null) {
+          Memory.global = memory;
+        }
+        break;
+    }
+    return new DynamicLibrary._(memory);
+  }
+
+  DynamicLibrary._(this.boundMemory);
+
+  /// Looks up a symbol in the DynamicLibrary and returns its address in memory.
+  ///
+  /// Throws an [ArgumentError] if it fails to lookup the symbol.
+  ///
+  /// While this method checks if the underyling wasm symbol is a actually
+  /// a function when you lookup a [NativeFunction]`<T>`, it does not check if
+  /// the return type and parameters of `T` match the wasm function.
+  Pointer<T> lookup<T extends NativeType>(String name) {
+    WasmSymbol symbol = symbolByName(boundMemory, name);
+    if (isNativeFunctionType<T>()) {
+      if (symbol is FunctionDescription) {
+        return new Pointer<T>.fromAddress(symbol.tableIndex, boundMemory);
+      } else {
+        throw new ArgumentError(
+            'Tried to look up $name as a function, but it seems it is NOT a function!');
+      }
+    } else {
+      return new Pointer<T>.fromAddress(symbol.address, boundMemory);
+    }
+  }
+}
+
+/// Manages memory on the native heap.
+abstract class Allocator {
+  /// Allocates byteCount bytes of memory on the native heap.
+  ///
+  /// The parameter `alignment` is ignored.
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment});
+
+  /// Releases memory allocated on the native heap.
+  void free(Pointer<NativeType> pointer);
+}

+ 1091 - 0
spine-flutter/lib/web_ffi/internal/invoker_generated.dart

@@ -0,0 +1,1091 @@
+import '../ffi/types.dart';
+import '../modules/memory.dart';
+import 'marshaller.dart' show execute;
+
+/// https://stackoverflow.com/questions/26122009/is-there-a-maximum-number-of-parameters-for-functions-in-c-with-the-gcc-resp-m
+/// the C Standard 5.2.4.1 says:
+/// 4095 characters in a logical source line
+/// 127 parameters in one function definition
+/// 127 arguments in one function call
+
+class OpaqueInvokeHelper<T extends Opaque> extends InvokeHelper<Pointer<T>> {
+  OpaqueInvokeHelper(Function? base, Memory? memory) : super(base, memory);
+
+  @override
+  InvokeHelper<Pointer<T>> copyWith(Function base, Memory memory) {
+    return new OpaqueInvokeHelper<T>(base, memory);
+  }
+
+  @override
+  Pointer<T> run(
+          [dynamic arg0,
+          dynamic arg1,
+          dynamic arg2,
+          dynamic arg3,
+          dynamic arg4,
+          dynamic arg5,
+          dynamic arg6,
+          dynamic arg7,
+          dynamic arg8,
+          dynamic arg9,
+          dynamic arg10,
+          dynamic arg11,
+          dynamic arg12,
+          dynamic arg13,
+          dynamic arg14,
+          dynamic arg15,
+          dynamic arg16,
+          dynamic arg17,
+          dynamic arg18,
+          dynamic arg19,
+          dynamic arg20,
+          dynamic arg21,
+          dynamic arg22,
+          dynamic arg23,
+          dynamic arg24,
+          dynamic arg25,
+          dynamic arg26,
+          dynamic arg27,
+          dynamic arg28,
+          dynamic arg29,
+          dynamic arg30,
+          dynamic arg31,
+          dynamic arg32,
+          dynamic arg33,
+          dynamic arg34,
+          dynamic arg35,
+          dynamic arg36,
+          dynamic arg37,
+          dynamic arg38,
+          dynamic arg39,
+          dynamic arg40,
+          dynamic arg41,
+          dynamic arg42,
+          dynamic arg43,
+          dynamic arg44,
+          dynamic arg45,
+          dynamic arg46,
+          dynamic arg47,
+          dynamic arg48,
+          dynamic arg49,
+          dynamic arg50,
+          dynamic arg51,
+          dynamic arg52,
+          dynamic arg53,
+          dynamic arg54,
+          dynamic arg55,
+          dynamic arg56,
+          dynamic arg57,
+          dynamic arg58,
+          dynamic arg59,
+          dynamic arg60,
+          dynamic arg61,
+          dynamic arg62,
+          dynamic arg63,
+          dynamic arg64,
+          dynamic arg65,
+          dynamic arg66,
+          dynamic arg67,
+          dynamic arg68,
+          dynamic arg69,
+          dynamic arg70,
+          dynamic arg71,
+          dynamic arg72,
+          dynamic arg73,
+          dynamic arg74,
+          dynamic arg75,
+          dynamic arg76,
+          dynamic arg77,
+          dynamic arg78,
+          dynamic arg79,
+          dynamic arg80,
+          dynamic arg81,
+          dynamic arg82,
+          dynamic arg83,
+          dynamic arg84,
+          dynamic arg85,
+          dynamic arg86,
+          dynamic arg87,
+          dynamic arg88,
+          dynamic arg89,
+          dynamic arg90,
+          dynamic arg91,
+          dynamic arg92,
+          dynamic arg93,
+          dynamic arg94,
+          dynamic arg95,
+          dynamic arg96,
+          dynamic arg97,
+          dynamic arg98,
+          dynamic arg99,
+          dynamic arg100,
+          dynamic arg101,
+          dynamic arg102,
+          dynamic arg103,
+          dynamic arg104,
+          dynamic arg105,
+          dynamic arg106,
+          dynamic arg107,
+          dynamic arg108,
+          dynamic arg109,
+          dynamic arg110,
+          dynamic arg111,
+          dynamic arg112,
+          dynamic arg113,
+          dynamic arg114,
+          dynamic arg115,
+          dynamic arg116,
+          dynamic arg117,
+          dynamic arg118,
+          dynamic arg119,
+          dynamic arg120,
+          dynamic arg121,
+          dynamic arg122,
+          dynamic arg123,
+          dynamic arg124,
+          dynamic arg125,
+          dynamic arg126]) =>
+      new InvokeHelper<Pointer<Opaque>>(_base, _memory)
+          .run(
+              arg0,
+              arg1,
+              arg2,
+              arg3,
+              arg4,
+              arg5,
+              arg6,
+              arg7,
+              arg8,
+              arg9,
+              arg10,
+              arg11,
+              arg12,
+              arg13,
+              arg14,
+              arg15,
+              arg16,
+              arg17,
+              arg18,
+              arg19,
+              arg20,
+              arg21,
+              arg22,
+              arg23,
+              arg24,
+              arg25,
+              arg26,
+              arg27,
+              arg28,
+              arg29,
+              arg30,
+              arg31,
+              arg32,
+              arg33,
+              arg34,
+              arg35,
+              arg36,
+              arg37,
+              arg38,
+              arg39,
+              arg40,
+              arg41,
+              arg42,
+              arg43,
+              arg44,
+              arg45,
+              arg46,
+              arg47,
+              arg48,
+              arg49,
+              arg50,
+              arg51,
+              arg52,
+              arg53,
+              arg54,
+              arg55,
+              arg56,
+              arg57,
+              arg58,
+              arg59,
+              arg60,
+              arg61,
+              arg62,
+              arg63,
+              arg64,
+              arg65,
+              arg66,
+              arg67,
+              arg68,
+              arg69,
+              arg70,
+              arg71,
+              arg72,
+              arg73,
+              arg74,
+              arg75,
+              arg76,
+              arg77,
+              arg78,
+              arg79,
+              arg80,
+              arg81,
+              arg82,
+              arg83,
+              arg84,
+              arg85,
+              arg86,
+              arg87,
+              arg88,
+              arg89,
+              arg90,
+              arg91,
+              arg92,
+              arg93,
+              arg94,
+              arg95,
+              arg96,
+              arg97,
+              arg98,
+              arg99,
+              arg100,
+              arg101,
+              arg102,
+              arg103,
+              arg104,
+              arg105,
+              arg106,
+              arg107,
+              arg108,
+              arg109,
+              arg110,
+              arg111,
+              arg112,
+              arg113,
+              arg114,
+              arg115,
+              arg116,
+              arg117,
+              arg118,
+              arg119,
+              arg120,
+              arg121,
+              arg122,
+              arg123,
+              arg124,
+              arg125,
+              arg126)
+          .cast<T>();
+}
+
+class OpaqueInvokeHelperSquare<T extends Opaque>
+    extends InvokeHelper<Pointer<Pointer<T>>> {
+  OpaqueInvokeHelperSquare(Function? base, Memory? memory)
+      : super(base, memory);
+
+  @override
+  InvokeHelper<Pointer<Pointer<T>>> copyWith(Function base, Memory memory) {
+    return new OpaqueInvokeHelperSquare<T>(base, memory);
+  }
+
+  @override
+  Pointer<Pointer<T>> run(
+          [dynamic arg0,
+          dynamic arg1,
+          dynamic arg2,
+          dynamic arg3,
+          dynamic arg4,
+          dynamic arg5,
+          dynamic arg6,
+          dynamic arg7,
+          dynamic arg8,
+          dynamic arg9,
+          dynamic arg10,
+          dynamic arg11,
+          dynamic arg12,
+          dynamic arg13,
+          dynamic arg14,
+          dynamic arg15,
+          dynamic arg16,
+          dynamic arg17,
+          dynamic arg18,
+          dynamic arg19,
+          dynamic arg20,
+          dynamic arg21,
+          dynamic arg22,
+          dynamic arg23,
+          dynamic arg24,
+          dynamic arg25,
+          dynamic arg26,
+          dynamic arg27,
+          dynamic arg28,
+          dynamic arg29,
+          dynamic arg30,
+          dynamic arg31,
+          dynamic arg32,
+          dynamic arg33,
+          dynamic arg34,
+          dynamic arg35,
+          dynamic arg36,
+          dynamic arg37,
+          dynamic arg38,
+          dynamic arg39,
+          dynamic arg40,
+          dynamic arg41,
+          dynamic arg42,
+          dynamic arg43,
+          dynamic arg44,
+          dynamic arg45,
+          dynamic arg46,
+          dynamic arg47,
+          dynamic arg48,
+          dynamic arg49,
+          dynamic arg50,
+          dynamic arg51,
+          dynamic arg52,
+          dynamic arg53,
+          dynamic arg54,
+          dynamic arg55,
+          dynamic arg56,
+          dynamic arg57,
+          dynamic arg58,
+          dynamic arg59,
+          dynamic arg60,
+          dynamic arg61,
+          dynamic arg62,
+          dynamic arg63,
+          dynamic arg64,
+          dynamic arg65,
+          dynamic arg66,
+          dynamic arg67,
+          dynamic arg68,
+          dynamic arg69,
+          dynamic arg70,
+          dynamic arg71,
+          dynamic arg72,
+          dynamic arg73,
+          dynamic arg74,
+          dynamic arg75,
+          dynamic arg76,
+          dynamic arg77,
+          dynamic arg78,
+          dynamic arg79,
+          dynamic arg80,
+          dynamic arg81,
+          dynamic arg82,
+          dynamic arg83,
+          dynamic arg84,
+          dynamic arg85,
+          dynamic arg86,
+          dynamic arg87,
+          dynamic arg88,
+          dynamic arg89,
+          dynamic arg90,
+          dynamic arg91,
+          dynamic arg92,
+          dynamic arg93,
+          dynamic arg94,
+          dynamic arg95,
+          dynamic arg96,
+          dynamic arg97,
+          dynamic arg98,
+          dynamic arg99,
+          dynamic arg100,
+          dynamic arg101,
+          dynamic arg102,
+          dynamic arg103,
+          dynamic arg104,
+          dynamic arg105,
+          dynamic arg106,
+          dynamic arg107,
+          dynamic arg108,
+          dynamic arg109,
+          dynamic arg110,
+          dynamic arg111,
+          dynamic arg112,
+          dynamic arg113,
+          dynamic arg114,
+          dynamic arg115,
+          dynamic arg116,
+          dynamic arg117,
+          dynamic arg118,
+          dynamic arg119,
+          dynamic arg120,
+          dynamic arg121,
+          dynamic arg122,
+          dynamic arg123,
+          dynamic arg124,
+          dynamic arg125,
+          dynamic arg126]) =>
+      new InvokeHelper<Pointer<Pointer<Opaque>>>(_base, _memory)
+          .run(
+              arg0,
+              arg1,
+              arg2,
+              arg3,
+              arg4,
+              arg5,
+              arg6,
+              arg7,
+              arg8,
+              arg9,
+              arg10,
+              arg11,
+              arg12,
+              arg13,
+              arg14,
+              arg15,
+              arg16,
+              arg17,
+              arg18,
+              arg19,
+              arg20,
+              arg21,
+              arg22,
+              arg23,
+              arg24,
+              arg25,
+              arg26,
+              arg27,
+              arg28,
+              arg29,
+              arg30,
+              arg31,
+              arg32,
+              arg33,
+              arg34,
+              arg35,
+              arg36,
+              arg37,
+              arg38,
+              arg39,
+              arg40,
+              arg41,
+              arg42,
+              arg43,
+              arg44,
+              arg45,
+              arg46,
+              arg47,
+              arg48,
+              arg49,
+              arg50,
+              arg51,
+              arg52,
+              arg53,
+              arg54,
+              arg55,
+              arg56,
+              arg57,
+              arg58,
+              arg59,
+              arg60,
+              arg61,
+              arg62,
+              arg63,
+              arg64,
+              arg65,
+              arg66,
+              arg67,
+              arg68,
+              arg69,
+              arg70,
+              arg71,
+              arg72,
+              arg73,
+              arg74,
+              arg75,
+              arg76,
+              arg77,
+              arg78,
+              arg79,
+              arg80,
+              arg81,
+              arg82,
+              arg83,
+              arg84,
+              arg85,
+              arg86,
+              arg87,
+              arg88,
+              arg89,
+              arg90,
+              arg91,
+              arg92,
+              arg93,
+              arg94,
+              arg95,
+              arg96,
+              arg97,
+              arg98,
+              arg99,
+              arg100,
+              arg101,
+              arg102,
+              arg103,
+              arg104,
+              arg105,
+              arg106,
+              arg107,
+              arg108,
+              arg109,
+              arg110,
+              arg111,
+              arg112,
+              arg113,
+              arg114,
+              arg115,
+              arg116,
+              arg117,
+              arg118,
+              arg119,
+              arg120,
+              arg121,
+              arg122,
+              arg123,
+              arg124,
+              arg125,
+              arg126)
+          .cast<Pointer<T>>();
+}
+
+class InvokeHelper<T> {
+  final Memory? _memory;
+  final Function? _base;
+
+  const InvokeHelper(this._base, this._memory);
+
+  InvokeHelper<T> copyWith(Function base, Memory memory) {
+    return new InvokeHelper(base, memory);
+  }
+
+  T run(
+      [dynamic arg0,
+      dynamic arg1,
+      dynamic arg2,
+      dynamic arg3,
+      dynamic arg4,
+      dynamic arg5,
+      dynamic arg6,
+      dynamic arg7,
+      dynamic arg8,
+      dynamic arg9,
+      dynamic arg10,
+      dynamic arg11,
+      dynamic arg12,
+      dynamic arg13,
+      dynamic arg14,
+      dynamic arg15,
+      dynamic arg16,
+      dynamic arg17,
+      dynamic arg18,
+      dynamic arg19,
+      dynamic arg20,
+      dynamic arg21,
+      dynamic arg22,
+      dynamic arg23,
+      dynamic arg24,
+      dynamic arg25,
+      dynamic arg26,
+      dynamic arg27,
+      dynamic arg28,
+      dynamic arg29,
+      dynamic arg30,
+      dynamic arg31,
+      dynamic arg32,
+      dynamic arg33,
+      dynamic arg34,
+      dynamic arg35,
+      dynamic arg36,
+      dynamic arg37,
+      dynamic arg38,
+      dynamic arg39,
+      dynamic arg40,
+      dynamic arg41,
+      dynamic arg42,
+      dynamic arg43,
+      dynamic arg44,
+      dynamic arg45,
+      dynamic arg46,
+      dynamic arg47,
+      dynamic arg48,
+      dynamic arg49,
+      dynamic arg50,
+      dynamic arg51,
+      dynamic arg52,
+      dynamic arg53,
+      dynamic arg54,
+      dynamic arg55,
+      dynamic arg56,
+      dynamic arg57,
+      dynamic arg58,
+      dynamic arg59,
+      dynamic arg60,
+      dynamic arg61,
+      dynamic arg62,
+      dynamic arg63,
+      dynamic arg64,
+      dynamic arg65,
+      dynamic arg66,
+      dynamic arg67,
+      dynamic arg68,
+      dynamic arg69,
+      dynamic arg70,
+      dynamic arg71,
+      dynamic arg72,
+      dynamic arg73,
+      dynamic arg74,
+      dynamic arg75,
+      dynamic arg76,
+      dynamic arg77,
+      dynamic arg78,
+      dynamic arg79,
+      dynamic arg80,
+      dynamic arg81,
+      dynamic arg82,
+      dynamic arg83,
+      dynamic arg84,
+      dynamic arg85,
+      dynamic arg86,
+      dynamic arg87,
+      dynamic arg88,
+      dynamic arg89,
+      dynamic arg90,
+      dynamic arg91,
+      dynamic arg92,
+      dynamic arg93,
+      dynamic arg94,
+      dynamic arg95,
+      dynamic arg96,
+      dynamic arg97,
+      dynamic arg98,
+      dynamic arg99,
+      dynamic arg100,
+      dynamic arg101,
+      dynamic arg102,
+      dynamic arg103,
+      dynamic arg104,
+      dynamic arg105,
+      dynamic arg106,
+      dynamic arg107,
+      dynamic arg108,
+      dynamic arg109,
+      dynamic arg110,
+      dynamic arg111,
+      dynamic arg112,
+      dynamic arg113,
+      dynamic arg114,
+      dynamic arg115,
+      dynamic arg116,
+      dynamic arg117,
+      dynamic arg118,
+      dynamic arg119,
+      dynamic arg120,
+      dynamic arg121,
+      dynamic arg122,
+      dynamic arg123,
+      dynamic arg124,
+      dynamic arg125,
+      dynamic arg126]) {
+    if (_base == null || _memory == null) {
+      throw StateError('Call copyWith first!');
+    }
+    Function base = _base!;
+    Memory memory = _memory!;
+    List<Object> args = [];
+    if (arg0 != null) {
+      args.add(arg0);
+      if (arg1 != null) {
+        args.add(arg1);
+        if (arg2 != null) {
+          args.add(arg2);
+          if (arg3 != null) {
+            args.add(arg3);
+            if (arg4 != null) {
+              args.add(arg4);
+              if (arg5 != null) {
+                args.add(arg5);
+                if (arg6 != null) {
+                  args.add(arg6);
+                  if (arg7 != null) {
+                    args.add(arg7);
+                    if (arg8 != null) {
+                      args.add(arg8);
+                      if (arg9 != null) {
+                        args.add(arg9);
+                        if (arg10 != null) {
+                          args.add(arg10);
+                          if (arg11 != null) {
+                            args.add(arg11);
+                            if (arg12 != null) {
+                              args.add(arg12);
+                              if (arg13 != null) {
+                                args.add(arg13);
+                                if (arg14 != null) {
+                                  args.add(arg14);
+                                  if (arg15 != null) {
+                                    args.add(arg15);
+                                    if (arg16 != null) {
+                                      args.add(arg16);
+                                      if (arg17 != null) {
+                                        args.add(arg17);
+                                        if (arg18 != null) {
+                                          args.add(arg18);
+                                          if (arg19 != null) {
+                                            args.add(arg19);
+                                            if (arg20 != null) {
+                                              args.add(arg20);
+                                              if (arg21 != null) {
+                                                args.add(arg21);
+                                                if (arg22 != null) {
+                                                  args.add(arg22);
+                                                  if (arg23 != null) {
+                                                    args.add(arg23);
+                                                    if (arg24 != null) {
+                                                      args.add(arg24);
+                                                      if (arg25 != null) {
+                                                        args.add(arg25);
+                                                        if (arg26 != null) {
+                                                          args.add(arg26);
+                                                          if (arg27 != null) {
+                                                            args.add(arg27);
+                                                            if (arg28 != null) {
+                                                              args.add(arg28);
+                                                              if (arg29 !=
+                                                                  null) {
+                                                                args.add(arg29);
+                                                                if (arg30 !=
+                                                                    null) {
+                                                                  args.add(
+                                                                      arg30);
+                                                                  if (arg31 !=
+                                                                      null) {
+                                                                    args.add(
+                                                                        arg31);
+                                                                    if (arg32 !=
+                                                                        null) {
+                                                                      args.add(
+                                                                          arg32);
+                                                                      if (arg33 !=
+                                                                          null) {
+                                                                        args.add(
+                                                                            arg33);
+                                                                        if (arg34 !=
+                                                                            null) {
+                                                                          args.add(
+                                                                              arg34);
+                                                                          if (arg35 !=
+                                                                              null) {
+                                                                            args.add(arg35);
+                                                                            if (arg36 !=
+                                                                                null) {
+                                                                              args.add(arg36);
+                                                                              if (arg37 != null) {
+                                                                                args.add(arg37);
+                                                                                if (arg38 != null) {
+                                                                                  args.add(arg38);
+                                                                                  if (arg39 != null) {
+                                                                                    args.add(arg39);
+                                                                                    if (arg40 != null) {
+                                                                                      args.add(arg40);
+                                                                                      if (arg41 != null) {
+                                                                                        args.add(arg41);
+                                                                                        if (arg42 != null) {
+                                                                                          args.add(arg42);
+                                                                                          if (arg43 != null) {
+                                                                                            args.add(arg43);
+                                                                                            if (arg44 != null) {
+                                                                                              args.add(arg44);
+                                                                                              if (arg45 != null) {
+                                                                                                args.add(arg45);
+                                                                                                if (arg46 != null) {
+                                                                                                  args.add(arg46);
+                                                                                                  if (arg47 != null) {
+                                                                                                    args.add(arg47);
+                                                                                                    if (arg48 != null) {
+                                                                                                      args.add(arg48);
+                                                                                                      if (arg49 != null) {
+                                                                                                        args.add(arg49);
+                                                                                                        if (arg50 != null) {
+                                                                                                          args.add(arg50);
+                                                                                                          if (arg51 != null) {
+                                                                                                            args.add(arg51);
+                                                                                                            if (arg52 != null) {
+                                                                                                              args.add(arg52);
+                                                                                                              if (arg53 != null) {
+                                                                                                                args.add(arg53);
+                                                                                                                if (arg54 != null) {
+                                                                                                                  args.add(arg54);
+                                                                                                                  if (arg55 != null) {
+                                                                                                                    args.add(arg55);
+                                                                                                                    if (arg56 != null) {
+                                                                                                                      args.add(arg56);
+                                                                                                                      if (arg57 != null) {
+                                                                                                                        args.add(arg57);
+                                                                                                                        if (arg58 != null) {
+                                                                                                                          args.add(arg58);
+                                                                                                                          if (arg59 != null) {
+                                                                                                                            args.add(arg59);
+                                                                                                                            if (arg60 != null) {
+                                                                                                                              args.add(arg60);
+                                                                                                                              if (arg61 != null) {
+                                                                                                                                args.add(arg61);
+                                                                                                                                if (arg62 != null) {
+                                                                                                                                  args.add(arg62);
+                                                                                                                                  if (arg63 != null) {
+                                                                                                                                    args.add(arg63);
+                                                                                                                                    if (arg64 != null) {
+                                                                                                                                      args.add(arg64);
+                                                                                                                                      if (arg65 != null) {
+                                                                                                                                        args.add(arg65);
+                                                                                                                                        if (arg66 != null) {
+                                                                                                                                          args.add(arg66);
+                                                                                                                                          if (arg67 != null) {
+                                                                                                                                            args.add(arg67);
+                                                                                                                                            if (arg68 != null) {
+                                                                                                                                              args.add(arg68);
+                                                                                                                                              if (arg69 != null) {
+                                                                                                                                                args.add(arg69);
+                                                                                                                                                if (arg70 != null) {
+                                                                                                                                                  args.add(arg70);
+                                                                                                                                                  if (arg71 != null) {
+                                                                                                                                                    args.add(arg71);
+                                                                                                                                                    if (arg72 != null) {
+                                                                                                                                                      args.add(arg72);
+                                                                                                                                                      if (arg73 != null) {
+                                                                                                                                                        args.add(arg73);
+                                                                                                                                                        if (arg74 != null) {
+                                                                                                                                                          args.add(arg74);
+                                                                                                                                                          if (arg75 != null) {
+                                                                                                                                                            args.add(arg75);
+                                                                                                                                                            if (arg76 != null) {
+                                                                                                                                                              args.add(arg76);
+                                                                                                                                                              if (arg77 != null) {
+                                                                                                                                                                args.add(arg77);
+                                                                                                                                                                if (arg78 != null) {
+                                                                                                                                                                  args.add(arg78);
+                                                                                                                                                                  if (arg79 != null) {
+                                                                                                                                                                    args.add(arg79);
+                                                                                                                                                                    if (arg80 != null) {
+                                                                                                                                                                      args.add(arg80);
+                                                                                                                                                                      if (arg81 != null) {
+                                                                                                                                                                        args.add(arg81);
+                                                                                                                                                                        if (arg82 != null) {
+                                                                                                                                                                          args.add(arg82);
+                                                                                                                                                                          if (arg83 != null) {
+                                                                                                                                                                            args.add(arg83);
+                                                                                                                                                                            if (arg84 != null) {
+                                                                                                                                                                              args.add(arg84);
+                                                                                                                                                                              if (arg85 != null) {
+                                                                                                                                                                                args.add(arg85);
+                                                                                                                                                                                if (arg86 != null) {
+                                                                                                                                                                                  args.add(arg86);
+                                                                                                                                                                                  if (arg87 != null) {
+                                                                                                                                                                                    args.add(arg87);
+                                                                                                                                                                                    if (arg88 != null) {
+                                                                                                                                                                                      args.add(arg88);
+                                                                                                                                                                                      if (arg89 != null) {
+                                                                                                                                                                                        args.add(arg89);
+                                                                                                                                                                                        if (arg90 != null) {
+                                                                                                                                                                                          args.add(arg90);
+                                                                                                                                                                                          if (arg91 != null) {
+                                                                                                                                                                                            args.add(arg91);
+                                                                                                                                                                                            if (arg92 != null) {
+                                                                                                                                                                                              args.add(arg92);
+                                                                                                                                                                                              if (arg93 != null) {
+                                                                                                                                                                                                args.add(arg93);
+                                                                                                                                                                                                if (arg94 != null) {
+                                                                                                                                                                                                  args.add(arg94);
+                                                                                                                                                                                                  if (arg95 != null) {
+                                                                                                                                                                                                    args.add(arg95);
+                                                                                                                                                                                                    if (arg96 != null) {
+                                                                                                                                                                                                      args.add(arg96);
+                                                                                                                                                                                                      if (arg97 != null) {
+                                                                                                                                                                                                        args.add(arg97);
+                                                                                                                                                                                                        if (arg98 != null) {
+                                                                                                                                                                                                          args.add(arg98);
+                                                                                                                                                                                                          if (arg99 != null) {
+                                                                                                                                                                                                            args.add(arg99);
+                                                                                                                                                                                                            if (arg100 != null) {
+                                                                                                                                                                                                              args.add(arg100);
+                                                                                                                                                                                                              if (arg101 != null) {
+                                                                                                                                                                                                                args.add(arg101);
+                                                                                                                                                                                                                if (arg102 != null) {
+                                                                                                                                                                                                                  args.add(arg102);
+                                                                                                                                                                                                                  if (arg103 != null) {
+                                                                                                                                                                                                                    args.add(arg103);
+                                                                                                                                                                                                                    if (arg104 != null) {
+                                                                                                                                                                                                                      args.add(arg104);
+                                                                                                                                                                                                                      if (arg105 != null) {
+                                                                                                                                                                                                                        args.add(arg105);
+                                                                                                                                                                                                                        if (arg106 != null) {
+                                                                                                                                                                                                                          args.add(arg106);
+                                                                                                                                                                                                                          if (arg107 != null) {
+                                                                                                                                                                                                                            args.add(arg107);
+                                                                                                                                                                                                                            if (arg108 != null) {
+                                                                                                                                                                                                                              args.add(arg108);
+                                                                                                                                                                                                                              if (arg109 != null) {
+                                                                                                                                                                                                                                args.add(arg109);
+                                                                                                                                                                                                                                if (arg110 != null) {
+                                                                                                                                                                                                                                  args.add(arg110);
+                                                                                                                                                                                                                                  if (arg111 != null) {
+                                                                                                                                                                                                                                    args.add(arg111);
+                                                                                                                                                                                                                                    if (arg112 != null) {
+                                                                                                                                                                                                                                      args.add(arg112);
+                                                                                                                                                                                                                                      if (arg113 != null) {
+                                                                                                                                                                                                                                        args.add(arg113);
+                                                                                                                                                                                                                                        if (arg114 != null) {
+                                                                                                                                                                                                                                          args.add(arg114);
+                                                                                                                                                                                                                                          if (arg115 != null) {
+                                                                                                                                                                                                                                            args.add(arg115);
+                                                                                                                                                                                                                                            if (arg116 != null) {
+                                                                                                                                                                                                                                              args.add(arg116);
+                                                                                                                                                                                                                                              if (arg117 != null) {
+                                                                                                                                                                                                                                                args.add(arg117);
+                                                                                                                                                                                                                                                if (arg118 != null) {
+                                                                                                                                                                                                                                                  args.add(arg118);
+                                                                                                                                                                                                                                                  if (arg119 != null) {
+                                                                                                                                                                                                                                                    args.add(arg119);
+                                                                                                                                                                                                                                                    if (arg120 != null) {
+                                                                                                                                                                                                                                                      args.add(arg120);
+                                                                                                                                                                                                                                                      if (arg121 != null) {
+                                                                                                                                                                                                                                                        args.add(arg121);
+                                                                                                                                                                                                                                                        if (arg122 != null) {
+                                                                                                                                                                                                                                                          args.add(arg122);
+                                                                                                                                                                                                                                                          if (arg123 != null) {
+                                                                                                                                                                                                                                                            args.add(arg123);
+                                                                                                                                                                                                                                                            if (arg124 != null) {
+                                                                                                                                                                                                                                                              args.add(arg124);
+                                                                                                                                                                                                                                                              if (arg125 != null) {
+                                                                                                                                                                                                                                                                args.add(arg125);
+                                                                                                                                                                                                                                                                if (arg126 != null) {
+                                                                                                                                                                                                                                                                  args.add(arg126);
+                                                                                                                                                                                                                                                                }
+                                                                                                                                                                                                                                                              }
+                                                                                                                                                                                                                                                            }
+                                                                                                                                                                                                                                                          }
+                                                                                                                                                                                                                                                        }
+                                                                                                                                                                                                                                                      }
+                                                                                                                                                                                                                                                    }
+                                                                                                                                                                                                                                                  }
+                                                                                                                                                                                                                                                }
+                                                                                                                                                                                                                                              }
+                                                                                                                                                                                                                                            }
+                                                                                                                                                                                                                                          }
+                                                                                                                                                                                                                                        }
+                                                                                                                                                                                                                                      }
+                                                                                                                                                                                                                                    }
+                                                                                                                                                                                                                                  }
+                                                                                                                                                                                                                                }
+                                                                                                                                                                                                                              }
+                                                                                                                                                                                                                            }
+                                                                                                                                                                                                                          }
+                                                                                                                                                                                                                        }
+                                                                                                                                                                                                                      }
+                                                                                                                                                                                                                    }
+                                                                                                                                                                                                                  }
+                                                                                                                                                                                                                }
+                                                                                                                                                                                                              }
+                                                                                                                                                                                                            }
+                                                                                                                                                                                                          }
+                                                                                                                                                                                                        }
+                                                                                                                                                                                                      }
+                                                                                                                                                                                                    }
+                                                                                                                                                                                                  }
+                                                                                                                                                                                                }
+                                                                                                                                                                                              }
+                                                                                                                                                                                            }
+                                                                                                                                                                                          }
+                                                                                                                                                                                        }
+                                                                                                                                                                                      }
+                                                                                                                                                                                    }
+                                                                                                                                                                                  }
+                                                                                                                                                                                }
+                                                                                                                                                                              }
+                                                                                                                                                                            }
+                                                                                                                                                                          }
+                                                                                                                                                                        }
+                                                                                                                                                                      }
+                                                                                                                                                                    }
+                                                                                                                                                                  }
+                                                                                                                                                                }
+                                                                                                                                                              }
+                                                                                                                                                            }
+                                                                                                                                                          }
+                                                                                                                                                        }
+                                                                                                                                                      }
+                                                                                                                                                    }
+                                                                                                                                                  }
+                                                                                                                                                }
+                                                                                                                                              }
+                                                                                                                                            }
+                                                                                                                                          }
+                                                                                                                                        }
+                                                                                                                                      }
+                                                                                                                                    }
+                                                                                                                                  }
+                                                                                                                                }
+                                                                                                                              }
+                                                                                                                            }
+                                                                                                                          }
+                                                                                                                        }
+                                                                                                                      }
+                                                                                                                    }
+                                                                                                                  }
+                                                                                                                }
+                                                                                                              }
+                                                                                                            }
+                                                                                                          }
+                                                                                                        }
+                                                                                                      }
+                                                                                                    }
+                                                                                                  }
+                                                                                                }
+                                                                                              }
+                                                                                            }
+                                                                                          }
+                                                                                        }
+                                                                                      }
+                                                                                    }
+                                                                                  }
+                                                                                }
+                                                                              }
+                                                                            }
+                                                                          }
+                                                                        }
+                                                                      }
+                                                                    }
+                                                                  }
+                                                                }
+                                                              }
+                                                            }
+                                                          }
+                                                        }
+                                                      }
+                                                    }
+                                                  }
+                                                }
+                                              }
+                                            }
+                                          }
+                                        }
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    return execute<T>(base, args, memory);
+  }
+}

+ 271 - 0
spine-flutter/lib/web_ffi/internal/marshaller.dart

@@ -0,0 +1,271 @@
+import 'package:meta/meta.dart';
+
+import '../ffi/types.dart';
+import '../modules/exceptions.dart';
+import '../modules/memory.dart';
+import 'invoker_generated.dart';
+import 'type_utils.dart';
+
+// Called from the invokers
+T execute<T>(Function base, List<Object> args, Memory memory) {
+  if (T == DartVoidType) {
+    Function.apply(base, args.map(_toJsType).toList());
+    return null as T;
+  } else {
+    Object result = Function.apply(base, args.map(_toJsType).toList());
+    return _toDartType<T>(result, memory);
+  }
+}
+
+DF marshall<NF extends Function, DF extends Function>(
+    Function base, Memory memory) {
+  return _inferFromSignature(DF.toString()).copyWith(base, memory).run as DF;
+}
+
+Object _toJsType(Object dartObject) {
+  if (dartObject is int || dartObject is double || dartObject is bool) {
+    return dartObject;
+  } else if (dartObject is Pointer) {
+    return dartObject.address;
+  } else {
+    throw new MarshallingException(
+        'Could not convert dart type ${dartObject.runtimeType} to a JavaScript type!');
+  }
+}
+
+InvokeHelper _inferFromSignature(String signature) {
+  String returnType = signature.split('=>').last.trim();
+  if (returnType.startsWith(pointerPointerPointerPrefix)) {
+    throw new MarshallingException(
+        'Nesting pointers is only supported to a deepth of 2!' +
+            '\nThis means that you can write Pointer<Pointer<X>> but not Pointer<Pointer<Pointer<X>>>, ...');
+  }
+  InvokeHelper? h = _knownTypes[returnType];
+  if (h != null) {
+    return h;
+  } else {
+    if (returnType.startsWith(pointerNativeFunctionPrefix)) {
+      throw new MarshallingException(
+          'Using pointers to native functions as return type is only allowed if the type of the native function is dynamic!' +
+              '\nThis means that only Pointer<NativeFunction<dynamic>> is allowed!');
+    } else {
+      throw new MarshallingException(
+          'Unknown type $returnType (infered from $signature), all marshallable types: ${listKnownTypes()}');
+    }
+  }
+}
+
+@visibleForTesting
+List<String> listKnownTypes() =>
+    new List<String>.of(_knownTypes.keys, growable: false);
+
+final Map<String, InvokeHelper> _knownTypes = {
+  typeString<int>(): new InvokeHelper<int>(null, null),
+  typeString<double>(): new InvokeHelper<double>(null, null),
+  typeString<bool>(): new InvokeHelper<bool>(null, null),
+  typeString<void>(): new InvokeHelper<void>(null, null)
+};
+
+void registerNativeMarshallerType<T extends NativeType>() {
+  _knownTypes[typeString<Pointer<T>>()] =
+      new InvokeHelper<Pointer<T>>(null, null);
+  _knownTypes[typeString<Pointer<Pointer<T>>>()] =
+      new InvokeHelper<Pointer<Pointer<T>>>(null, null);
+}
+
+void registerNativeMarshallerOpaque<T extends Opaque>() {
+  _knownTypes[typeString<Pointer<T>>()] = new OpaqueInvokeHelper<T>(null, null);
+  _knownTypes[typeString<Pointer<Pointer<T>>>()] =
+      new OpaqueInvokeHelperSquare<T>(null, null);
+}
+
+T _toDartType<T>(Object o, Memory bind) {
+  if (T == int) {
+    if (o is int) {
+      return o as T;
+    } else {
+      throw new MarshallingException.typeMissmatch(T, o);
+    }
+  } else if (T == double) {
+    if (o is double) {
+      return o as T;
+    } else {
+      throw new MarshallingException.typeMissmatch(T, o);
+    }
+  } else if (T == bool) {
+    if (o is bool) {
+      return o as T;
+    } else {
+      throw new MarshallingException.typeMissmatch(T, o);
+    }
+  } else {
+    if (T == Pointer_Void) {
+      if (o is int) {
+        return new Pointer<Void>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_IntPtr) {
+      if (o is int) {
+        return new Pointer<IntPtr>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Int8) {
+      if (o is int) {
+        return new Pointer<Int8>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Int16) {
+      if (o is int) {
+        return new Pointer<Int16>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Int32) {
+      if (o is int) {
+        return new Pointer<Int32>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Int64) {
+      if (o is int) {
+        return new Pointer<Int64>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Double) {
+      if (o is int) {
+        return new Pointer<Double>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Uint8) {
+      if (o is int) {
+        return new Pointer<Uint8>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Uint16) {
+      if (o is int) {
+        return new Pointer<Uint16>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Uint32) {
+      if (o is int) {
+        return new Pointer<Uint32>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Uint64) {
+      if (o is int) {
+        return new Pointer<Uint64>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Float) {
+      if (o is int) {
+        return new Pointer<Float>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_Opaque) {
+      if (o is int) {
+        return new Pointer<Opaque>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else if (T == Pointer_NativeFunction_dynamic) {
+      if (o is int) {
+        return new Pointer<NativeFunction<dynamic>>.fromAddress(o, bind) as T;
+      } else {
+        throw new MarshallingException.noAddress(o);
+      }
+    } else {
+      if (T == Pointer_Pointer_Void) {
+        if (o is int) {
+          return new Pointer<Pointer<Void>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_IntPtr) {
+        if (o is int) {
+          return new Pointer<Pointer<IntPtr>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Int8) {
+        if (o is int) {
+          return new Pointer<Pointer<Int8>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Int16) {
+        if (o is int) {
+          return new Pointer<Pointer<Int16>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Int32) {
+        if (o is int) {
+          return new Pointer<Pointer<Int32>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Int64) {
+        if (o is int) {
+          return new Pointer<Pointer<Int64>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Double) {
+        if (o is int) {
+          return new Pointer<Pointer<Double>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Uint8) {
+        if (o is int) {
+          return new Pointer<Pointer<Uint8>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Uint16) {
+        if (o is int) {
+          return new Pointer<Pointer<Uint16>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Uint32) {
+        if (o is int) {
+          return new Pointer<Pointer<Uint32>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Uint64) {
+        if (o is int) {
+          return new Pointer<Pointer<Uint64>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Float) {
+        if (o is int) {
+          return new Pointer<Pointer<Float>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else if (T == Pointer_Pointer_Opaque) {
+        if (o is int) {
+          return new Pointer<Pointer<Opaque>>.fromAddress(o, bind) as T;
+        } else {
+          throw new MarshallingException.noAddress(o);
+        }
+      } else {
+        throw new MarshallingException(
+            'Can not back-marshall to type $T (object type is ${o.runtimeType}');
+      }
+    }
+  }
+}

+ 62 - 0
spine-flutter/lib/web_ffi/internal/type_utils.dart

@@ -0,0 +1,62 @@
+import '../ffi/types.dart';
+
+/// Hacky workadround, see https://github.com/dart-lang/language/issues/123
+Type _extractType<T>() => T;
+String typeString<T>() => _extractType<T>().toString();
+
+// Variable names begin with a capital letter on purpose (opposing dart conventions) to hilight that
+// they are treated like types (which are written with a captial letter in dart).
+final Type Pointer_IntPtr = _extractType<Pointer<IntPtr>>();
+final Type Pointer_Void = _extractType<Pointer<Void>>();
+final Type Pointer_Int8 = _extractType<Pointer<Int8>>();
+final Type Pointer_Int16 = _extractType<Pointer<Int16>>();
+final Type Pointer_Int32 = _extractType<Pointer<Int32>>();
+final Type Pointer_Int64 = _extractType<Pointer<Int64>>();
+final Type Pointer_Double = _extractType<Pointer<Double>>();
+final Type Pointer_Uint8 = _extractType<Pointer<Uint8>>();
+final Type Pointer_Uint16 = _extractType<Pointer<Uint16>>();
+final Type Pointer_Uint32 = _extractType<Pointer<Uint32>>();
+final Type Pointer_Uint64 = _extractType<Pointer<Uint64>>();
+final Type Pointer_Float = _extractType<Pointer<Float>>();
+final Type Pointer_Opaque = _extractType<Pointer<Opaque>>();
+final Type Pointer_Pointer_IntPtr = _extractType<Pointer<Pointer<IntPtr>>>();
+final Type Pointer_Pointer_Void = _extractType<Pointer<Pointer<Void>>>();
+final Type Pointer_Pointer_Int8 = _extractType<Pointer<Pointer<Int8>>>();
+final Type Pointer_Pointer_Int16 = _extractType<Pointer<Pointer<Int16>>>();
+final Type Pointer_Pointer_Int32 = _extractType<Pointer<Pointer<Int32>>>();
+final Type Pointer_Pointer_Int64 = _extractType<Pointer<Pointer<Int64>>>();
+final Type Pointer_Pointer_Double = _extractType<Pointer<Pointer<Double>>>();
+final Type Pointer_Pointer_Uint8 = _extractType<Pointer<Pointer<Uint8>>>();
+final Type Pointer_Pointer_Uint16 = _extractType<Pointer<Pointer<Uint16>>>();
+final Type Pointer_Pointer_Uint32 = _extractType<Pointer<Pointer<Uint32>>>();
+final Type Pointer_Pointer_Uint64 = _extractType<Pointer<Pointer<Uint64>>>();
+final Type Pointer_Pointer_Float = _extractType<Pointer<Pointer<Float>>>();
+final Type Pointer_Pointer_Opaque = _extractType<Pointer<Pointer<Opaque>>>();
+final Type Pointer_NativeFunction_dynamic =
+    _extractType<Pointer<NativeFunction<dynamic>>>();
+final Type DartVoidType = _extractType<void>();
+final Type FfiVoidType = _extractType<Void>();
+
+final String _dynamicTypeString = typeString<dynamic>();
+
+final String pointerPointerPointerPrefix =
+    typeString<Pointer<Pointer<Pointer<dynamic>>>>()
+        .split(_dynamicTypeString)
+        .first;
+
+final String pointerNativeFunctionPrefix =
+    typeString<Pointer<NativeFunction<dynamic>>>()
+        .split(_dynamicTypeString)
+        .first;
+
+final String _nativeFunctionPrefix =
+    typeString<NativeFunction<dynamic>>().split(_dynamicTypeString).first;
+bool isNativeFunctionType<T extends NativeType>() =>
+    typeString<T>().startsWith(_nativeFunctionPrefix);
+
+final String _pointerPrefix =
+    typeString<Pointer<dynamic>>().split(_dynamicTypeString).first;
+bool isPointerType<T extends NativeType>() =>
+    typeString<T>().startsWith(_pointerPrefix);
+
+bool isVoidType<T extends NativeType>() => _extractType<T>() == FfiVoidType;

+ 35 - 0
spine-flutter/lib/web_ffi/meta/meta.dart

@@ -0,0 +1,35 @@
+class _Extra {
+  const _Extra();
+}
+
+/// A class, field or method annotated with extra is present in `web_ffi`,
+/// but not in `dart:ffi`.
+const _Extra extra = const _Extra();
+
+class _NoGeneric {
+  const _NoGeneric();
+}
+
+/// If a class which is annotead with [noGeneric] is extended or implemented,
+/// the derived class MUST NOT impose a type argument!
+const _NoGeneric noGeneric = const _NoGeneric();
+
+class _NotConstructible {
+  const _NotConstructible();
+}
+
+/// A [NativeType] annotated with unsized should not be instantiated.
+///
+/// However, they are not marked as `abstract` to meet the dart:ffi API.
+const _NotConstructible notConstructible = const _NotConstructible();
+
+class _Unsized {
+  const _Unsized();
+}
+
+/// A [NativeType] annotated with unsized does not have a predefined size.
+///
+/// Unsized [NativeType]s do not support [sizeOf] because their size is unknown,
+/// so calling [sizeOf] with an @[unsized] [NativeType] will throw an exception.
+/// Consequently, [Pointer.elementAt] is not available and will also throw an exception.
+const _Unsized unsized = const _Unsized();

+ 192 - 0
spine-flutter/lib/web_ffi/modules/emscripten/emscripten_module.dart

@@ -0,0 +1,192 @@
+@JS()
+library emscripten_module;
+
+import 'dart:typed_data';
+import 'package:js/js.dart';
+import 'package:js/js_util.dart';
+import '../module.dart';
+import '../../web_ffi_meta.dart';
+
+@JS('globalThis')
+external Object get _globalThis;
+
+@JS('Object.entries')
+external List? _entries(Object? o);
+
+@JS()
+@anonymous
+class _EmscriptenModuleJs {
+  external Uint8List? get wasmBinary;
+  external Uint8List? get HEAPU8;
+  external Object? get asm;
+
+  // Must have an unnamed factory constructor with named arguments.
+  external factory _EmscriptenModuleJs({Uint8List wasmBinary});
+}
+
+const String _github = r'https://github.com/EPNW/web_ffi';
+String _adu(WasmSymbol? original, WasmSymbol? tried) =>
+    'CRITICAL EXCEPTION! Address double use! This should never happen, please report this issue on github immediately at $_github' +
+    '\r\nOriginal: $original' +
+    '\r\nTried: $tried';
+
+typedef int _Malloc(int size);
+typedef void _Free(int address);
+
+FunctionDescription _fromWasmFunction(String name, Function func) {
+  String? s = getProperty(func, 'name');
+  if (s != null) {
+    int? index = int.tryParse(s);
+    if (index != null) {
+      int? length = getProperty(func, 'length');
+      if (length != null) {
+        return new FunctionDescription(
+            tableIndex: index,
+            name: name,
+            function: func,
+            argumentCount: length);
+      } else {
+        throw new ArgumentError('$name does not seem to be a function symbol!');
+      }
+    } else {
+      throw new ArgumentError('$name does not seem to be a function symbol!');
+    }
+  } else {
+    throw new ArgumentError('$name does not seem to be a function symbol!');
+  }
+}
+
+/// Documentation is in `emscripten_module_stub.dart`!
+@extra
+class EmscriptenModule extends Module {
+  static Function _moduleFunction(String moduleName) {
+    Function? moduleFunction = getProperty(_globalThis, moduleName);
+    if (moduleFunction != null) {
+      return moduleFunction;
+    } else {
+      throw StateError('Could not find a emscripten module named $moduleName');
+    }
+  }
+
+  /// Documentation is in `emscripten_module_stub.dart`!
+  static Future<EmscriptenModule> process(String moduleName) async {
+    Function moduleFunction = _moduleFunction(moduleName);
+    _EmscriptenModuleJs module = new _EmscriptenModuleJs();
+    Object? o = moduleFunction(module);
+    if (o != null) {
+      await promiseToFuture(o);
+      return new EmscriptenModule._fromJs(module);
+    } else {
+      throw new StateError('Could not instantiate an emscripten module!');
+    }
+  }
+
+  /// Documentation is in `emscripten_module_stub.dart`!
+  static Future<EmscriptenModule> compile(
+      Uint8List wasmBinary, String moduleName) async {
+    Function moduleFunction = _moduleFunction(moduleName);
+    _EmscriptenModuleJs module =
+        new _EmscriptenModuleJs(wasmBinary: wasmBinary);
+    Object? o = moduleFunction(module);
+    if (o != null) {
+      await promiseToFuture(o);
+      return new EmscriptenModule._fromJs(module);
+    } else {
+      throw new StateError('Could not instantiate an emscripten module!');
+    }
+  }
+
+  final _EmscriptenModuleJs _emscriptenModuleJs;
+  final List<WasmSymbol> _exports;
+  final _Malloc _malloc;
+  final _Free _free;
+
+  @override
+  List<WasmSymbol> get exports => _exports;
+
+  EmscriptenModule._(
+      this._emscriptenModuleJs, this._exports, this._malloc, this._free);
+
+  factory EmscriptenModule._fromJs(_EmscriptenModuleJs module) {
+    Object? asm = module.asm;
+    if (asm != null) {
+      Map<int, WasmSymbol> knownAddresses = {};
+      _Malloc? malloc;
+      _Free? free;
+      List<WasmSymbol> exports = [];
+      List? entries = _entries(asm);
+      if (entries != null) {
+        for (dynamic entry in entries) {
+          if (entry is List) {
+            Object value = entry.last;
+            if (value is int) {
+              Global g =
+                  new Global(address: value, name: entry.first as String);
+              if (knownAddresses.containsKey(value) &&
+                  knownAddresses[value] is! Global) {
+                throw new StateError(_adu(knownAddresses[value], g));
+              }
+              knownAddresses[value] = g;
+              exports.add(g);
+            } else if (value is Function) {
+              FunctionDescription description =
+                  _fromWasmFunction(entry.first as String, value);
+              // It might happen that there are two different c functions that do nothing else than calling the same underlying c function
+              // In this case, a compiler might substitute both functions with the underlying c function
+              // So we got two functions with different names at the same table index
+              // So it is actually ok if there are two things at the same address, as long as they are both functions
+              if (knownAddresses.containsKey(description.tableIndex) &&
+                  knownAddresses[description.tableIndex]
+                      is! FunctionDescription) {
+                throw new StateError(
+                    _adu(knownAddresses[description.tableIndex], description));
+              }
+              knownAddresses[description.tableIndex] = description;
+              exports.add(description);
+              if (description.name == 'malloc') {
+                malloc = description.function as _Malloc;
+              } else if (description.name == 'free') {
+                free = description.function as _Free;
+              }
+            }
+          } else {
+            throw new StateError(
+                'Unexpected entry in entries(Module[\'asm\'])!');
+          }
+        }
+        if (malloc != null) {
+          if (free != null) {
+            return new EmscriptenModule._(module, exports, malloc, free);
+          } else {
+            throw new StateError('Module does not export the free function!');
+          }
+        } else {
+          throw new StateError('Module does not export the malloc function!');
+        }
+      } else {
+        throw new StateError(
+            'JavaScript error: Could not access entries of Module[\'asm\']!');
+      }
+    } else {
+      throw new StateError(
+          'Could not access Module[\'asm\'], are your sure your module was compiled using emscripten?');
+    }
+  }
+
+  @override
+  void free(int pointer) => _free(pointer);
+
+  @override
+  ByteBuffer get heap => _getHeap();
+  ByteBuffer _getHeap() {
+    Uint8List? h = _emscriptenModuleJs.HEAPU8;
+    if (h != null) {
+      return h.buffer;
+    } else {
+      throw StateError('Unexpected memory error!');
+    }
+  }
+
+  @override
+  int malloc(int size) => _malloc(size);
+}

+ 71 - 0
spine-flutter/lib/web_ffi/modules/emscripten/emscripten_module_stub.dart

@@ -0,0 +1,71 @@
+import 'dart:typed_data';
+import '../module.dart';
+
+import '../../web_ffi_meta.dart';
+
+/// Provides access to WebAssembly compiled with [emscripten](https://emscripten.org).
+///
+/// WebAssembly compiled with emscripten comes with an `<moduleName>.wasm`
+/// and an additional `<moduleName>.js` glue JavaScript file. The later is
+/// required to be loaded on the page before calling any of this classes
+/// functions.
+///
+/// The WebAssembly must have been compiled with the `-s MODULARIZE=1`
+/// and `-s EXPORT_NAME=<moduleName>` flags. Futhermore the `<moduleName.js>`
+/// must contain all exported WebAssembly functions that should be usable from
+/// dart, so using `-s MAIN_MODULE=1` might be advisable.
+///
+/// For a detailed walkthrough on how to create and inject these files,
+/// see the [example](https://github.com/EPNW/web_ffi/blob/master/example/README.md).
+///
+/// On platforms where [dart:js](https://api.dart.dev/stable/dart-js/dart-js-library.html)
+/// is not available, all methods throw [UnsupportedError]s.
+@extra
+class EmscriptenModule extends Module {
+  /// Connects to the JavaScript glue of the emscripten module.
+  ///
+  /// This happens in the following way:
+  /// First, a JavaScript property named `moduleName` of the global object
+  /// is accessed, which should contain a function. Then this function is
+  /// called and expected to return a JavaScript emscripten module.
+  ///
+  /// The JavaScript emscripten module is responsible for retriving the
+  /// WebAssembly and compile it accordingly.
+  ///
+  /// On platforms where [dart:js](https://api.dart.dev/stable/dart-js/dart-js-library.html)
+  /// is not available, an [UnsupportedError] is thrown.
+  static Future<EmscriptenModule> process(String moduleName) =>
+      throw new UnsupportedError(
+          'Emscripten operations are only allowed on the web (where dart:js is present)!');
+
+  /// Connects to the JavaScript glue of the emscripten module.
+  ///
+  /// Works like [process], except that the bytes of the WebAssembly
+  /// are passed to the JavaScript emscripten module, so it is
+  /// your responsibility to fetch it.
+  ///
+  /// On platforms where [dart:js](https://api.dart.dev/stable/dart-js/dart-js-library.html)
+  /// is not available, an [UnsupportedError] is thrown.
+  static Future<EmscriptenModule> compile(
+          Uint8List wasmBinary, String moduleName) =>
+      throw new UnsupportedError(
+          'Emscripten operations are only allowed on the web (where dart:js is present)!');
+
+  EmscriptenModule._();
+
+  @override
+  List<WasmSymbol> get exports => throw new UnsupportedError(
+      'Emscripten operations are only allowed on the web (where dart:js is present)!');
+
+  @override
+  void free(int pointer) => throw new UnsupportedError(
+      'Emscripten operations are only allowed on the web (where dart:js is present)!');
+
+  @override
+  ByteBuffer get heap => throw new UnsupportedError(
+      'Emscripten operations are only allowed on the web (where dart:js is present)!');
+
+  @override
+  int malloc(int size) => throw new UnsupportedError(
+      'Emscripten operations are only allowed on the web (where dart:js is present)!');
+}

+ 18 - 0
spine-flutter/lib/web_ffi/modules/exceptions.dart

@@ -0,0 +1,18 @@
+/// Occures if it's not possible to convert dart types to JavaScript types.
+///
+/// This usually happens if a not allowed type is uses as a [NativeType]'s
+/// type argument, or a not allowed return value of a [NativeFunction] is
+/// used.
+class MarshallingException implements Exception {
+  final dynamic message;
+  const MarshallingException([this.message]);
+
+  MarshallingException.noAddress(Object o)
+      : this('Expected a address (int) but found ${o.runtimeType}');
+
+  MarshallingException.typeMissmatch(Type t, Object o)
+      : this('Expected a type of $t but object has type ${o.runtimeType}');
+
+  @override
+  String toString() => new Exception(message).toString();
+}

+ 116 - 0
spine-flutter/lib/web_ffi/modules/memory.dart

@@ -0,0 +1,116 @@
+import 'dart:typed_data';
+import 'package:meta/meta.dart';
+
+import 'module.dart';
+import '../ffi/types.dart';
+import '../internal/marshaller.dart';
+import '../web_ffi_meta.dart';
+
+final Map<Type, int> sizeMap = {};
+
+/// Must be called with each type that extends Opaque before
+/// attemtping to use that type.
+@extra
+void registerOpaqueType<T extends Opaque>() {
+  sizeMap[T] = sizeOf<Opaque>();
+  registerNativeMarshallerOpaque<T>();
+}
+
+void _registerType<T extends NativeType>(int size) {
+  sizeMap[T] = size;
+  registerNativeMarshallerType<T>();
+}
+
+/// Represents the native heap.
+@extra
+class Memory implements Allocator {
+  /// The endianess of data stored.
+  ///
+  /// The WebAssembly speficiation defines little endianess, so this is a constant.
+  static const Endian endianess = Endian.little;
+
+  /// Must be called before working with `web_ffi` to initalize all type sizes.
+  ///
+  /// The optional parameter [pointerSizeBytes] can be used to adjust the size
+  /// of pointers. It defaults to `4` since WebAssembly usually uses 32 bit pointers.
+  /// If you want to use wasm64, set [pointerSizeBytes] to `8` to denote 64 bit pointers.
+  static void init([int pointerSizeBytes = 4]) {
+    _registerType<Float>(4);
+    _registerType<Double>(8);
+    _registerType<Int8>(1);
+    _registerType<Uint8>(1);
+    _registerType<Int16>(2);
+    _registerType<Uint16>(2);
+    _registerType<Int32>(4);
+    _registerType<Uint32>(4);
+    _registerType<Int64>(8);
+    _registerType<Uint64>(8);
+    _registerType<IntPtr>(pointerSizeBytes);
+    _registerType<Opaque>(pointerSizeBytes);
+    registerNativeMarshallerType<Void>();
+    registerNativeMarshallerType<NativeFunction<dynamic>>();
+  }
+
+  /// The default [Memory] object to use.
+  ///
+  /// This field is null until it is either manually set to a [Memory] object,
+  /// or automatically set by [DynamicLibrary.fromModule].
+  ///
+  /// This is most notably used when creating a pointer using [Pointer.fromAddress]
+  /// with no explicite memory to bind to given.
+  static Memory? global;
+
+  /// Can be used to directly access the memory of this object.
+  ///
+  /// The value of this field should not be stored in a state variable,
+  /// since the returned buffer may change over time.
+  @doNotStore
+  ByteBuffer get buffer => _module.heap;
+
+  final Module _module;
+  final Map<String, WasmSymbol> _symbolsByName;
+  final Map<int, WasmSymbol> _symbolsByAddress;
+
+  Memory._(this._module)
+      : _symbolsByAddress = new Map<int, WasmSymbol>.fromEntries(_module.exports
+            .map<MapEntry<int, WasmSymbol>>((WasmSymbol symbol) =>
+                new MapEntry<int, WasmSymbol>(symbol.address, symbol))),
+        _symbolsByName = new Map<String, WasmSymbol>.fromEntries(_module.exports
+            .map<MapEntry<String, WasmSymbol>>((WasmSymbol symbol) =>
+                new MapEntry<String, WasmSymbol>(symbol.name, symbol)));
+
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    return new Pointer<T>.fromAddress(_module.malloc(byteCount), this);
+  }
+
+  @override
+  void free(Pointer<NativeType> pointer) {
+    _module.free(pointer.address);
+  }
+}
+
+Memory createMemory(Module module) => new Memory._(module);
+
+WasmSymbol symbolByAddress(Memory m, int address) {
+  WasmSymbol? s = m._symbolsByAddress[address];
+  if (s != null) {
+    return s;
+  } else {
+    throw new ArgumentError('Could not find symbol at $address!');
+  }
+}
+
+WasmSymbol symbolByName(Memory m, String name) {
+  WasmSymbol? s = m._symbolsByName[name];
+  if (s != null) {
+    return s;
+  } else {
+    throw new ArgumentError('Could not find symbol $name!');
+  }
+}
+
+/// Used on [DynamicLibrary] creation to control if the therby newly created
+/// [Memory] object should be registered as [Memory.global].
+@extra
+enum MemoryRegisterMode { yes, no, onlyIfGlobalNotSet }

+ 114 - 0
spine-flutter/lib/web_ffi/modules/module.dart

@@ -0,0 +1,114 @@
+import 'dart:typed_data';
+import 'package:meta/meta.dart';
+import '../web_ffi_meta.dart';
+
+/// Base class to interact with the WebAssembly.
+///
+/// Currently, only [emscripten](https://emscripten.org) compiled WebAssembly is supported,
+/// so the only concrete implementation if this class is [EmscriptenModule].
+///
+/// To support additional mechanisms/frameworks/compilers, create a subclass of
+/// [Module].
+@extra
+abstract class Module {
+  /// Provides access to the malloc function in WebAssembly.
+  ///
+  /// Allocates `size` bytes of memory and returns the corresponding
+  /// address.
+  ///
+  /// Memory allocated by this should be [free]d afterwards.
+  int malloc(int size);
+
+  /// Provides access to the free function in WebAssembly.
+  ///
+  /// Frees the memory region at `pointer` that was previously
+  /// allocated with [malloc].
+  void free(int pointer);
+
+  /// Provides access to the [WebAssemblys memory](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory) buffer.
+  ///
+  /// The actual [ByteBuffer] object returned by this getter is allowed to change;
+  /// It should not be cached in a state variable and is thus annotated with @[doNotStore].
+  @doNotStore
+  ByteBuffer get heap;
+
+  /// A list containing everything exported by the underlying
+  /// [WebAssembly instance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance).
+  List<WasmSymbol> get exports;
+}
+
+/// Describes something exported by the WebAssembly.
+@extra
+@sealed
+abstract class WasmSymbol {
+  /// The address of the exported thing.
+  final int address;
+
+  /// The name of the exported thing.
+  final String name;
+
+  const WasmSymbol({required this.address, required this.name});
+
+  @override
+  int get hashCode => toString().hashCode;
+
+  @override
+  String toString() => '[address=$address\tname=$name]';
+}
+
+/// A global is a symbol exported by the WebAssembly,
+/// that is not a function.
+@extra
+@sealed
+class Global extends WasmSymbol {
+  const Global({required int address, required String name})
+      : super(address: address, name: name);
+
+  @override
+  bool operator ==(dynamic other) {
+    if (other != null && other is Global) {
+      return name == other.name && address == other.address;
+    } else {
+      return false;
+    }
+  }
+}
+
+/// Describes a function exported from WebAssembly.
+@extra
+@sealed
+class FunctionDescription extends WasmSymbol {
+  /// The index of this function in the [WebAssembly table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table).
+  /// This is the same as its address.
+  int get tableIndex => address;
+
+  /// The amount of arguments the underyling function has.
+  final int argumentCount;
+
+  /// The actual function.
+  final Function function;
+  const FunctionDescription(
+      {required int tableIndex,
+      required String name,
+      required this.argumentCount,
+      required this.function})
+      : super(address: tableIndex, name: name);
+
+  @override
+  int get hashCode => '$name$argumentCount$tableIndex'.hashCode;
+
+  @override
+  bool operator ==(dynamic other) {
+    if (other != null && other is FunctionDescription) {
+      return argumentCount == other.argumentCount &&
+          name == other.name &&
+          tableIndex == other.tableIndex;
+    } else {
+      return false;
+    }
+  }
+
+  @override
+  String toString() =>
+      '[tableIndex=$tableIndex\tname=$name\targumentCount=$argumentCount\tfunction=$function]';
+}

+ 20 - 0
spine-flutter/lib/web_ffi/modules/null_memory.dart

@@ -0,0 +1,20 @@
+import 'dart:typed_data';
+import 'memory.dart';
+import '../ffi/types.dart';
+
+class NullMemory implements Memory {
+  @override
+  Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
+    throw new UnsupportedError(
+        'Can not use the null memory to allocate space!');
+  }
+
+  @override
+  ByteBuffer get buffer =>
+      throw new UnsupportedError('The null memory has no buffer!');
+
+  @override
+  void free(Pointer<NativeType> pointer) {
+    throw new UnsupportedError('Can not use the null memory to free pointers!');
+  }
+}

+ 6 - 0
spine-flutter/lib/web_ffi/web_ffi.dart

@@ -0,0 +1,6 @@
+/// Provides mechanisms to use a [dart:ffi 2.12.0](https://api.dart.dev/stable/2.12.0/dart-ffi/dart-ffi-library.html) like API on the web but using [dart:js](https://api.dart.dev/stable/dart-js/dart-js-library.html).
+/// While some things are missing, new things were added, identifiable by the @[extra] annotation.
+library web_ffi;
+
+export 'ffi/types.dart';
+export 'ffi/extensions.dart';

+ 4 - 0
spine-flutter/lib/web_ffi/web_ffi_meta.dart

@@ -0,0 +1,4 @@
+/// This library contains and explains the annotations for `web_ffi`.
+library web_ffi_meta;
+
+export 'meta/meta.dart';

+ 12 - 0
spine-flutter/lib/web_ffi/web_ffi_modules.dart

@@ -0,0 +1,12 @@
+/// Provides additional classes that are needed for web_ffi,
+/// but are not present in [dart:ffi](https://api.dart.dev/stable/2.12.0/dart-ffi/dart-ffi-library.html).
+library web_ffi_modules;
+
+export 'modules/exceptions.dart';
+export 'modules/module.dart';
+export 'modules/memory.dart'
+    show registerOpaqueType, Memory, MemoryRegisterMode;
+
+export 'modules/emscripten/emscripten_module_stub.dart'
+    if (dart.library.js) 'modules/emscripten/emscripten_module.dart'
+    show EmscriptenModule;

+ 2 - 1
spine-flutter/pubspec.yaml

@@ -12,8 +12,9 @@ dependencies:
     sdk: flutter
     sdk: flutter
   plugin_platform_interface: ^2.0.2
   plugin_platform_interface: ^2.0.2
   ffi: ^2.0.1
   ffi: ^2.0.1
-  web_ffi: ^0.7.2
   inject_js: ^2.0.0
   inject_js: ^2.0.0
+  js: ^0.6.3
+  meta: ^1.3.0
   http: ^0.13.5
   http: ^0.13.5
 
 
 dev_dependencies:
 dev_dependencies:

+ 9 - 3
spine-flutter/src/compile-wasm.sh

@@ -2,15 +2,21 @@
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
 pushd $dir > /dev/null
 pushd $dir > /dev/null
 mkdir -p ../lib/assets/
 mkdir -p ../lib/assets/
+# Need to use -O2, as -O3 applies the Closure compiler to native function names.
+# The entries for exported functions in Module.asm will be scrambled so
+# EmscriptenModule._fromJs() is unable to parse them and link them with original
+# names set on the module, e.g. Module._spine_get_major_version.
 emcc \
 emcc \
 	-Ispine-cpp/include \
 	-Ispine-cpp/include \
-	--closure 1 -O3 -fno-rtti -fno-exceptions \
-	-s MAIN_MODULE=1 \
+	-O2 --closure 1 -fno-rtti -fno-exceptions -lc++abi -lc++ \
+	-s STRICT=1 \
+	-s LLD_REPORT_UNDEFINED \
 	-s MODULARIZE=1 \
 	-s MODULARIZE=1 \
 	-s ALLOW_MEMORY_GROWTH=1 \
 	-s ALLOW_MEMORY_GROWTH=1 \
 	-s ALLOW_TABLE_GROWTH \
 	-s ALLOW_TABLE_GROWTH \
 	-s MALLOC=emmalloc \
 	-s MALLOC=emmalloc \
-	-s ENVIRONMENT=web \
+	-s EXPORT_ALL=1 \
+	-s EXPORTED_FUNCTIONS='["_malloc", "_free"]' \
 	--no-entry \
 	--no-entry \
 	-s EXPORT_NAME=libspine_flutter \
 	-s EXPORT_NAME=libspine_flutter \
 	spine_flutter.cpp `find spine-cpp/src -type f` \
 	spine_flutter.cpp `find spine-cpp/src -type f` \

Diferenças do arquivo suprimidas por serem muito extensas
+ 164 - 158
spine-flutter/src/spine_flutter.cpp


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff