shithub: openh264

Download patch

ref: 4cc4f364d6a6a77cc92ee46dd497acb4091944ed
parent: aaa5bcc1579d6c7177afb6cf09e178df2cb6f9b8
parent: 0bc0b71ef3dd8c0d56f2d8d0832a5b8296b81565
author: ruil2 <ruil2@cisco.com>
date: Wed Jun 18 07:17:25 EDT 2014

Merge pull request #981 from ethanhugg/gmp_rollup

Rollup of Gecko Media Plugin patches

diff: cannot open b/module//null: file does not exist: 'b/module//null'
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,5 +5,19 @@
 before_install:
   - sudo apt-get update -qq
   - sudo apt-get install -qq nasm g++-4.6-multilib gcc-multilib libc6-dev-i386
-install: make gtest-bootstrap
-script: make -B ENABLE64BIT=Yes && make test && make -B ENABLE64BIT=Yes BUILDTYPE=Debug && make test && make -B ENABLE64BIT=No && make test && make -B ENABLE64BIT=No BUILDTYPE=Debug && make test
+install:
+  - make gmp-bootstrap
+  - make gtest-bootstrap
+script:
+  - make -B ENABLE64BIT=Yes
+  - make -B ENABLE64BIT=Yes plugin
+  - make -B ENABLE64BIT=Yes test
+  - make -B ENABLE64BIT=Yes BUILDTYPE=Debug
+  - make -B ENABLE64BIT=Yes BUILDTYPE=Debug plugin
+  - make -B ENABLE64BIT=Yes test
+  - make -B ENABLE64BIT=No
+  - make -B ENABLE64BIT=No plugin
+  - make -B ENABLE64BIT=No test
+  - make -B ENABLE64BIT=No BUILDTYPE=Debug
+  - make -B ENABLE64BIT=No BUILDTYPE=Debug plugin
+  - make -B ENABLE64BIT=No test
--- a/Makefile
+++ b/Makefile
@@ -15,8 +15,15 @@
 SHARED=-shared
 OBJ=o
 PROJECT_NAME=openh264
+MODULE_NAME=gmpopenh264
 CCASFLAGS=$(CFLAGS)
 
+ifeq (,$(wildcard ./gmp-api))
+HAVE_GMP_API=No
+else
+HAVE_GMP_API=Yes
+endif
+
 ifeq (,$(wildcard ./gtest))
 HAVE_GTEST=No
 else
@@ -98,6 +105,8 @@
 PROCESSING_UNITTEST_INCLUDES = $(CODEC_UNITTEST_INCLUDES) $(PROCESSING_INCLUDES) -Itest -Itest/processing
 API_TEST_INCLUDES = $(CODEC_UNITTEST_INCLUDES) -Itest -Itest/api
 COMMON_UNITTEST_INCLUDES = $(CODEC_UNITTEST_INCLUDES) $(DECODER_INCLUDES) -Itest -Itest/common
+MODULE_INCLUDES = -Igmp-api
+
 .PHONY: test gtest-bootstrap clean
 
 all:	libraries binaries
@@ -108,6 +117,9 @@
 endif
 	$(QUIET)rm -f $(OBJS) $(OBJS:.$(OBJ)=.d) $(LIBRARIES) $(BINARIES)
 
+gmp-bootstrap:
+	git clone https://github.com/mozilla/gmp-api gmp-api
+
 gtest-bootstrap:
 	svn co https://googletest.googlecode.com/svn/trunk/ gtest
 
@@ -131,6 +143,10 @@
 include codec/encoder/targets.mk
 include codec/processing/targets.mk
 
+ifeq ($(HAVE_GMP_API),Yes)
+include module/targets.mk
+endif
+
 ifneq (android, $(OS))
 ifneq (ios, $(OS))
 include codec/console/dec/targets.mk
@@ -151,6 +167,19 @@
 	$(QUIET_AR)$(AR) $(AR_OPTS) $+
 
 $(LIBPREFIX)$(PROJECT_NAME).$(SHAREDLIBSUFFIX): $(ENCODER_OBJS) $(DECODER_OBJS) $(PROCESSING_OBJS) $(COMMON_OBJS)
+	$(QUIET)rm -f $@
+	$(QUIET_CXX)$(CXX) $(SHARED) $(LDFLAGS) $(CXX_LINK_O) $+ $(SHLDFLAGS)
+
+ifeq ($(HAVE_GMP_API),Yes)
+plugin: $(LIBPREFIX)$(MODULE_NAME).$(SHAREDLIBSUFFIX)
+PLUGINS += $(LIBPREFIX)$(MODULE_NAME).$(SHAREDLIBSUFFIX)
+else
+plugin:
+	@echo "./gmp-api : No such file or directory."
+	@echo "You do not have gmp-api.  Run make gmp-bootstrap to get the gmp-api headers."
+endif
+
+$(LIBPREFIX)$(MODULE_NAME).$(SHAREDLIBSUFFIX): $(MODULE_OBJS) $(ENCODER_OBJS) $(DECODER_OBJS) $(PROCESSING_OBJS) $(COMMON_OBJS)
 	$(QUIET)rm -f $@
 	$(QUIET_CXX)$(CXX) $(SHARED) $(LDFLAGS) $(CXX_LINK_O) $+ $(SHLDFLAGS)
 
--- a/build/mktargets.sh
+++ b/build/mktargets.sh
@@ -11,4 +11,5 @@
 python build/mktargets.py --directory test/decoder --prefix decoder_unittest
 python build/mktargets.py --directory test/processing --prefix processing_unittest
 python build/mktargets.py --directory test/api --prefix api_test
+python build/mktargets.py --directory module --library module
 python build/mktargets.py --directory gtest --library gtest --out build/gtest-targets.mk --cpp-suffix .cc --include gtest-all.cc
--- /dev/null
+++ b/gmpopenh264.info
@@ -1,0 +1,4 @@
+Name: gmpopenh264
+Description: GMP Plugin for OpenH264.
+Version: 1.0
+APIs: encode-video[h264:vp8], decode-video[h264:vp8]
--- /dev/null
+++ b/module/gmp-openh264.cpp
@@ -1,0 +1,703 @@
+/*!
+ * \copy
+ *     Copyright (c)  2009-2014, Cisco Systems
+ *     All rights reserved.
+ *
+ *     Redistribution and use in source and binary forms, with or without
+ *     modification, are permitted provided that the following conditions
+ *     are met:
+ *
+ *        * Redistributions of source code must retain the above copyright
+ *          notice, this list of conditions and the following disclaimer.
+ *
+ *        * 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.
+ *
+ *
+ *************************************************************************************
+ */
+
+#include <stdint.h>
+#include <time.h>
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+#include <memory>
+#include <assert.h>
+#include <limits.h>
+
+#include "gmp-platform.h"
+#include "gmp-video-host.h"
+#include "gmp-video-encode.h"
+#include "gmp-video-decode.h"
+#include "gmp-video-frame-i420.h"
+#include "gmp-video-frame-encoded.h"
+
+#include "codec_def.h"
+#include "codec_app_def.h"
+#include "codec_api.h"
+
+#include "task_utils.h"
+
+#if defined(_MSC_VER)
+#define PUBLIC_FUNC __declspec(dllexport)
+#else
+#define PUBLIC_FUNC
+#endif
+
+// This is for supporting older versions which do not have support for nullptr.
+#if defined(__clang__)
+# ifndef __has_extension
+# define __has_extension __has_feature
+# endif
+
+# if __has_extension(cxx_nullptr)
+# define GMP_HAVE_NULLPTR
+# endif
+
+#elif defined(__GNUC__)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
+# if (__GNU_C__ >=4)
+# if (__GNU_C_MINOR__ >= 6)
+# define GMP_HAVE_NULLPTR
+# endif
+# endif
+# endif
+
+#elif defined(_MSC_VER)
+# define GMP_HAVE_NULLPTR
+#endif
+
+#if !defined (GMP_HAVE_NULLPTR)
+# define nullptr __null
+#endif
+
+static int g_log_level = 0;
+
+#define GMPLOG(l, x) do { \
+        if (l <= g_log_level) { \
+        const char *log_string = "unknown"; \
+        if ((l >= 0) && (l <= 3)) {               \
+        log_string = kLogStrings[l];            \
+        } \
+        std::cerr << log_string << ": " << x << std::endl; \
+        } \
+    } while(0)
+
+#define GL_CRIT 0
+#define GL_ERROR 1
+#define GL_INFO  2
+#define GL_DEBUG 3
+
+const char *kLogStrings[] = {
+  "Critical",
+  "Error",
+  "Info",
+  "Debug"
+};
+
+
+static GMPPlatformAPI* g_platform_api = nullptr;
+
+class OpenH264VideoEncoder;
+
+template <typename T> class SelfDestruct {
+ public:
+  SelfDestruct(T* t) : t_(t) {}
+  ~SelfDestruct() {
+    if (t_) {
+      t_->Destroy();
+    }
+  }
+
+  T* forget() {
+    T* t = t_;
+    t_ = nullptr;
+
+    return t;
+  }
+
+ private:
+  T* t_;
+};
+
+class FrameStats {
+ public:
+  FrameStats(const char *type) :
+      frames_in_(0),
+      frames_out_(0),
+      start_time_(time(0)),
+      last_time_(start_time_),
+      type_(type) {}
+
+  void FrameIn() {
+    ++frames_in_;
+    time_t now = time(0);
+
+    if (now == last_time_) {
+      return;
+    }
+
+    if (!(frames_in_ % 10)) {
+      GMPLOG(GL_INFO, type_ << ": " << now << " Frame count "
+          << frames_in_
+          << "(" << (frames_in_ / (now - start_time_)) << "/"
+          << (30 / (now - last_time_)) << ")"
+          << " -- " << frames_out_);
+      last_time_ = now;
+    }
+  }
+
+  void FrameOut() {
+    ++frames_out_;
+  }
+
+ private:
+  uint64_t frames_in_;
+  uint64_t frames_out_;
+  time_t start_time_;
+  time_t last_time_;
+  const std::string type_;
+};
+
+class OpenH264VideoEncoder : public GMPVideoEncoder
+{
+ public:
+  OpenH264VideoEncoder(GMPVideoHost *hostAPI) :
+      host_(hostAPI),
+      worker_thread_(nullptr),
+      encoder_(nullptr),
+      max_payload_size_(0),
+      callback_(nullptr),
+      stats_("Encoder") {}
+
+  virtual ~OpenH264VideoEncoder() {
+    worker_thread_->Join();
+  }
+
+  virtual GMPVideoErr InitEncode(const GMPVideoCodec& codecSettings,
+                                 GMPEncoderCallback* callback,
+                                 int32_t numberOfCores,
+                                 uint32_t maxPayloadSize) {
+    GMPErr err = g_platform_api->createthread(&worker_thread_);
+    if (err != GMPNoErr) {
+      GMPLOG(GL_ERROR, "Couldn't create new thread");
+      return GMPVideoGenericErr;
+    }
+
+    int rv = WelsCreateSVCEncoder(&encoder_);
+    if (rv) {
+      return GMPVideoGenericErr;
+    }
+
+    SEncParamBase param;
+    memset(&param, 0, sizeof(param));
+
+    GMPLOG(GL_INFO, "Initializing encoder at "
+            << codecSettings.mWidth
+            << "x"
+            << codecSettings.mHeight
+            << "@"
+            << static_cast<int>(codecSettings.mMaxFramerate)
+            << "max payload size="
+           << maxPayloadSize);
+
+    // Translate parameters.
+    param.iUsageType = CAMERA_VIDEO_REAL_TIME;
+    param.iPicWidth = codecSettings.mWidth;
+    param.iPicHeight = codecSettings.mHeight;
+    param.iTargetBitrate = codecSettings.mStartBitrate * 1000;
+    GMPLOG(GL_INFO, "Initializing Bit Rate at: Start: "
+           << codecSettings.mStartBitrate
+           << "; Min: "
+           << codecSettings.mMinBitrate
+           << "; Max: "
+           << codecSettings.mMaxBitrate);
+    param.iRCMode = RC_BITRATE_MODE;
+
+    // TODO(ekr@rtfm.com). Scary conversion from unsigned char to float below.
+    param.fMaxFrameRate = static_cast<float>(codecSettings.mMaxFramerate);
+    param.iInputCsp = videoFormatI420;
+
+    rv = encoder_->Initialize(&param);
+    if (rv) {
+      GMPLOG(GL_ERROR, "Couldn't initialize encoder");
+      return GMPVideoGenericErr;
+    }
+
+    max_payload_size_ = maxPayloadSize;
+    callback_ = callback;
+
+    GMPLOG(GL_INFO, "Initialized encoder");
+
+    return GMPVideoNoErr;
+  }
+
+  virtual GMPVideoErr Encode(GMPVideoi420Frame* inputImage,
+                             const GMPCodecSpecificInfo& codecSpecificInfo,
+                             const std::vector<GMPVideoFrameType>& frameTypes)
+      {
+    GMPLOG(GL_DEBUG,
+           __FUNCTION__
+           << " size="
+           << inputImage->Width() << "x" << inputImage->Height());
+
+    stats_.FrameIn();
+
+    assert(!frameTypes.empty());
+    if (frameTypes.empty()) {
+      GMPLOG(GL_ERROR, "No frame types provided");
+      return GMPVideoGenericErr;
+    }
+
+    worker_thread_->Post(WrapTask(
+          this, &OpenH264VideoEncoder::Encode_w,
+          inputImage,
+          (frameTypes)[0]));
+
+    return GMPVideoGenericErr;
+  }
+
+  void Encode_w(GMPVideoi420Frame* inputImage,
+                GMPVideoFrameType frame_type) {
+    SFrameBSInfo encoded;
+
+    SSourcePicture src;
+
+    src.iColorFormat = videoFormatI420;
+    src.iStride[0] = inputImage->Stride(kGMPYPlane);
+    src.pData[0] = reinterpret_cast<unsigned char*>(
+        const_cast<uint8_t *>(inputImage->Buffer(kGMPYPlane)));
+    src.iStride[1] = inputImage->Stride(kGMPUPlane);
+    src.pData[1] = reinterpret_cast<unsigned char*>(
+        const_cast<uint8_t *>(inputImage->Buffer(kGMPUPlane)));
+    src.iStride[2] = inputImage->Stride(kGMPVPlane);
+    src.pData[2] = reinterpret_cast<unsigned char*>(
+        const_cast<uint8_t *>(inputImage->Buffer(kGMPVPlane)));
+    src.iStride[3] = 0;
+    src.pData[3] = nullptr;
+    src.iPicWidth = inputImage->Width();
+    src.iPicHeight = inputImage->Height();
+
+    const SSourcePicture* pics = &src;
+
+    int result = encoder_->EncodeFrame(pics, &encoded);
+    if (result != cmResultSuccess) {
+      GMPLOG(GL_ERROR, "Couldn't encode frame. Error = " << result);
+    }
+
+
+    // Translate int to enum
+    GMPVideoFrameType encoded_type;
+    bool has_frame = false;
+
+    switch (encoded.eOutputFrameType) {
+      case videoFrameTypeIDR:
+        encoded_type = kGMPKeyFrame;
+        has_frame = true;
+        break;
+      case videoFrameTypeI:
+        encoded_type = kGMPKeyFrame;
+        has_frame = true;
+        break;
+      case videoFrameTypeP:
+        encoded_type = kGMPDeltaFrame;
+        has_frame = true;
+        break;
+      case videoFrameTypeSkip:
+        // Can skip the call back since no actual bitstream will be generated
+        break;
+      case videoFrameTypeIPMixed://this type is currently not suppported
+      case videoFrameTypeInvalid:
+        GMPLOG(GL_ERROR, "Couldn't encode frame. Type = "
+               << encoded.eOutputFrameType);
+        break;
+      default:
+        // The API is defined as returning a type.
+        assert(false);
+        break;
+    }
+
+    if (!has_frame) {
+      return;
+    }
+
+    // Synchronously send this back to the main thread for delivery.
+    g_platform_api->syncrunonmainthread(WrapTask(
+        this,
+        &OpenH264VideoEncoder::Encode_m,
+        inputImage,
+        &encoded,
+        encoded_type));
+  }
+
+  void Encode_m(GMPVideoi420Frame* frame, SFrameBSInfo* encoded,
+                GMPVideoFrameType frame_type) {
+    // Now return the encoded data back to the parent.
+    GMPVideoFrame* ftmp;
+    GMPVideoErr err = host_->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
+    if (err != GMPVideoNoErr) {
+      GMPLOG(GL_ERROR, "Error creating encoded frame");
+      return;
+    }
+
+    GMPVideoEncodedFrame* f = static_cast<GMPVideoEncodedFrame*>(ftmp);
+    // Buffer up the data.
+    uint32_t length = 0;
+    std::vector<uint32_t> lengths;
+
+    for (int i=0; i<encoded->iLayerNum; ++i) {
+      lengths.push_back(0);
+      for (int j=0; j<encoded->sLayerInfo[i].iNalCount; ++j) {
+        lengths[i] += encoded->sLayerInfo[i].pNalLengthInByte[j];
+        length += encoded->sLayerInfo[i].pNalLengthInByte[j];
+      }
+    }
+
+    // TODO start-code to length conversion here when gmp
+    // stops doing it for us before this call.
+
+    err = f->CreateEmptyFrame(length);
+    if (err != GMPVideoNoErr) {
+      GMPLOG(GL_ERROR, "Error allocating frame data");
+      f->Destroy();
+      return;
+    }
+
+    // Copy the data.
+    // Here we concatenate into one big buffer
+    uint8_t* tmp = f->Buffer();
+    for (int i=0; i<encoded->iLayerNum; ++i) {
+      memcpy(tmp, encoded->sLayerInfo[i].pBsBuf, lengths[i]);
+      tmp += lengths[i];
+    }
+
+    f->SetEncodedWidth(frame->Width());
+    f->SetEncodedHeight(frame->Height());
+    f->SetTimeStamp(frame->Timestamp());
+    f->SetFrameType(frame_type);
+    f->SetCompleteFrame(true);
+
+    GMPLOG(GL_DEBUG, "Encoding complete. type= "
+           << f->FrameType()
+           << " length="
+           << f->Size()
+           << " timestamp="
+           << f->TimeStamp());
+
+    // Destroy the frame.
+    frame->Destroy();
+
+    // Return the encoded frame.
+    GMPCodecSpecificInfo info;
+    memset(&info, 0, sizeof(info));
+    // TODO need to set what goes in this info structure.
+    callback_->Encoded(f, info);
+
+    stats_.FrameOut();
+  }
+
+  virtual GMPVideoErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) {
+    return GMPVideoNoErr;
+  }
+
+  virtual GMPVideoErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) {
+    GMPLOG(GL_INFO, "[SetRates] Begin with: "
+           << aNewBitRate << " , "<< aFrameRate);
+    //update bitrate if needed
+    const int32_t newBitRate = aNewBitRate*1000; //kbps->bps
+    SBitrateInfo existEncoderBitRate;
+    existEncoderBitRate.iLayer = SPATIAL_LAYER_ALL;
+    int rv = encoder_->GetOption(ENCODER_OPTION_BITRATE, &existEncoderBitRate);
+    if (rv!=cmResultSuccess) {
+      GMPLOG(GL_ERROR, "[SetRates] Error in Getting Bit Rate at Layer:"
+             << rv
+             << " ; Layer = "
+             << existEncoderBitRate.iLayer
+             << " ; BR = "
+             << existEncoderBitRate.iBitrate);
+      return GMPVideoGenericErr;
+    }
+    if ( rv==cmResultSuccess && existEncoderBitRate.iBitrate!=newBitRate ) {
+      SBitrateInfo newEncoderBitRate;
+      newEncoderBitRate.iLayer = SPATIAL_LAYER_ALL;
+      newEncoderBitRate.iBitrate = newBitRate;
+      rv = encoder_->SetOption(ENCODER_OPTION_BITRATE, &newEncoderBitRate);
+      if (rv==cmResultSuccess) {
+        GMPLOG(GL_INFO, "[SetRates] Update Encoder Bandwidth (AllLayers): ReturnValue: "
+                  << rv
+                  << "BitRate(kbps): "
+                  << aNewBitRate);
+      } else {
+        GMPLOG(GL_ERROR, "[SetRates] Error in Setting Bit Rate at Layer:"
+               << rv
+               << " ; Layer = "
+               << newEncoderBitRate.iLayer
+               << " ; BR = "
+               << newEncoderBitRate.iBitrate);
+        return GMPVideoGenericErr;
+      }
+    }
+    //update framerate if needed
+    float existFrameRate = 0;
+    rv = encoder_->GetOption(ENCODER_OPTION_FRAME_RATE, &existFrameRate);
+    if (rv!=cmResultSuccess) {
+      GMPLOG(GL_ERROR, "[SetRates] Error in Getting Frame Rate:"
+             << rv << " FrameRate: " << existFrameRate);
+      return GMPVideoGenericErr;
+    }
+    if ( rv==cmResultSuccess &&
+        ( aFrameRate-existFrameRate > 0.001f ||
+          existFrameRate-aFrameRate > 0.001f ) ) {
+      float newFrameRate = static_cast<float>(aFrameRate);
+      rv = encoder_->SetOption(ENCODER_OPTION_FRAME_RATE, &newFrameRate);
+      if (rv==cmResultSuccess) {
+        GMPLOG(GL_INFO, "[SetRates] Update Encoder Frame Rate: ReturnValue: "
+               << rv << " FrameRate: " << aFrameRate);
+      } else {
+        GMPLOG(GL_ERROR, "[SetRates] Error in Setting Frame Rate: ReturnValue: "
+               << rv << " FrameRate: " << aFrameRate);
+        return GMPVideoGenericErr;
+      }
+    }
+    return GMPVideoNoErr;
+  }
+
+  virtual GMPVideoErr SetPeriodicKeyFrames(bool aEnable) {
+    return GMPVideoNoErr;
+  }
+
+  virtual void EncodingComplete() {
+    delete this;
+  }
+
+private:
+  GMPVideoHost* host_;
+  GMPThread* worker_thread_;
+  ISVCEncoder* encoder_;
+  uint32_t max_payload_size_;
+  GMPEncoderCallback* callback_;
+  FrameStats stats_;
+};
+
+class OpenH264VideoDecoder : public GMPVideoDecoder {
+public:
+  OpenH264VideoDecoder(GMPVideoHost *hostAPI) :
+      host_(hostAPI),
+      worker_thread_(nullptr),
+      callback_(nullptr),
+      decoder_(nullptr),
+      stats_("Decoder") {}
+
+  virtual ~OpenH264VideoDecoder() {
+  }
+
+  virtual GMPVideoErr InitDecode(const GMPVideoCodec& codecSettings,
+                                 GMPDecoderCallback* callback,
+                                 int32_t coreCount) {
+    GMPLOG(GL_INFO, "InitDecode");
+
+    GMPErr err = g_platform_api->createthread(&worker_thread_);
+    if (err != GMPNoErr) {
+      GMPLOG(GL_ERROR, "Couldn't create new thread");
+      return GMPVideoGenericErr;
+    }
+
+    if (WelsCreateDecoder(&decoder_)) {
+      GMPLOG(GL_ERROR, "Couldn't create decoder");
+      return GMPVideoGenericErr;
+    }
+
+    if (!decoder_) {
+      GMPLOG(GL_ERROR, "Couldn't create decoder");
+      return GMPVideoGenericErr;
+    }
+
+    SDecodingParam param;
+    memset(&param, 0, sizeof(param));
+    param.iOutputColorFormat = videoFormatI420;
+    param.uiTargetDqLayer = UCHAR_MAX;  // Default value
+    param.uiEcActiveFlag = 1; // Error concealment on.
+    param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
+
+    if (decoder_->Initialize(&param)) {
+      GMPLOG(GL_ERROR, "Couldn't initialize decoder");
+      return GMPVideoGenericErr;
+    }
+
+    callback_ = callback;
+    return GMPVideoNoErr;
+  }
+
+  virtual GMPVideoErr Decode(GMPVideoEncodedFrame* inputFrame,
+                             bool missingFrames,
+                             const GMPCodecSpecificInfo& codecSpecificInfo,
+                             int64_t renderTimeMs = -1) {
+    GMPLOG(GL_DEBUG, __FUNCTION__
+           << "Decoding frame size=" << inputFrame->Size()
+           << " timestamp=" << inputFrame->TimeStamp());
+    stats_.FrameIn();
+
+    worker_thread_->Post(WrapTask(
+        this, &OpenH264VideoDecoder::Decode_w,
+        inputFrame,
+        missingFrames,
+        renderTimeMs));
+
+    return GMPVideoNoErr;
+  }
+
+  virtual GMPVideoErr Reset() {
+    return GMPVideoNoErr;
+  }
+
+  virtual GMPVideoErr Drain() {
+    return GMPVideoNoErr;
+  }
+
+  virtual void DecodingComplete() {
+    delete this;
+  }
+
+private:
+  void Decode_w(GMPVideoEncodedFrame* inputFrame,
+                bool missingFrames,
+                int64_t renderTimeMs = -1) {
+    GMPLOG(GL_DEBUG, "Frame decode on worker thread length = "
+           << inputFrame->Size());
+
+    SBufferInfo decoded;
+    bool valid = false;
+    memset(&decoded, 0, sizeof(decoded));
+    unsigned char *data[3] = {nullptr, nullptr, nullptr};
+
+    int rv = decoder_->DecodeFrame2(inputFrame->Buffer(),
+                                    inputFrame->Size(),
+                                    data,
+                                    &decoded);
+
+    if (rv) {
+      GMPLOG(GL_ERROR, "Decoding error rv=" << rv);
+    } else {
+      valid = true;
+    }
+
+    g_platform_api->syncrunonmainthread(WrapTask(
+        this,
+        &OpenH264VideoDecoder::Decode_m,
+        inputFrame,
+        &decoded,
+        data,
+        renderTimeMs,
+        valid));
+  }
+
+  // Return the decoded data back to the parent.
+  void Decode_m(GMPVideoEncodedFrame* inputFrame,
+                SBufferInfo* decoded,
+                unsigned char* data[3],
+                int64_t renderTimeMs,
+                bool valid) {
+    // Attach a self-destructor so that this dies on return.
+    SelfDestruct<GMPVideoEncodedFrame> ifd(inputFrame);
+
+    // If we don't actually have data, just abort.
+    if (!valid) {
+      return;
+    }
+
+    if (decoded->iBufferStatus != 1) {
+      return;
+    }
+
+    int width = decoded->UsrData.sSystemBuffer.iWidth;
+    int height = decoded->UsrData.sSystemBuffer.iHeight;
+    int ystride = decoded->UsrData.sSystemBuffer.iStride[0];
+    int uvstride = decoded->UsrData.sSystemBuffer.iStride[1];
+
+    GMPLOG(GL_DEBUG, "Video frame ready for display "
+           << width
+           << "x"
+           << height
+           << " timestamp="
+           << inputFrame->TimeStamp());
+
+    GMPVideoFrame* ftmp = nullptr;
+
+    // Translate the image.
+    GMPVideoErr err = host_->CreateFrame(kGMPI420VideoFrame, &ftmp);
+    if (err != GMPVideoNoErr) {
+      GMPLOG(GL_ERROR, "Couldn't allocate empty I420 frame");
+      return;
+    }
+
+
+    GMPVideoi420Frame* frame = static_cast<GMPVideoi420Frame*>(ftmp);
+    err = frame->CreateFrame(
+        ystride * height, static_cast<uint8_t *>(data[0]),
+        uvstride * height/2, static_cast<uint8_t *>(data[1]),
+        uvstride * height/2, static_cast<uint8_t *>(data[2]),
+        width, height,
+        ystride, uvstride, uvstride);
+    if (err != GMPVideoNoErr) {
+      GMPLOG(GL_ERROR, "Couldn't make decoded frame");
+      return;
+    }
+
+    GMPLOG(GL_DEBUG, "Allocated size = "
+           << frame->AllocatedSize(kGMPYPlane));
+    frame->SetTimestamp(inputFrame->TimeStamp());
+    frame->SetRenderTime_ms(renderTimeMs);
+    callback_->Decoded(frame);
+
+    stats_.FrameOut();
+  }
+
+  GMPVideoHost* host_;
+  GMPThread* worker_thread_;
+  GMPDecoderCallback* callback_;
+  ISVCDecoder* decoder_;
+  FrameStats stats_;
+};
+
+extern "C" {
+
+PUBLIC_FUNC GMPErr
+GMPInit(GMPPlatformAPI* aPlatformAPI) {
+  g_platform_api = aPlatformAPI;
+  return GMPNoErr;
+}
+
+PUBLIC_FUNC GMPErr
+GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginApi) {
+  if (!strcmp(aApiName, "decode-video")) {
+    *aPluginApi = new OpenH264VideoDecoder(static_cast<GMPVideoHost*>(aHostAPI));
+    return GMPNoErr;
+  } else if (!strcmp(aApiName, "encode-video")) {
+    *aPluginApi = new OpenH264VideoEncoder(static_cast<GMPVideoHost*>(aHostAPI));
+    return GMPNoErr;
+  }
+  return GMPGenericErr;
+}
+
+PUBLIC_FUNC void
+GMPShutdown(void) {
+  g_platform_api = nullptr;
+}
+
+} // extern "C"
--- /dev/null
+++ b/module/targets.mk
@@ -1,0 +1,16 @@
+MODULE_SRCDIR=module
+MODULE_CPP_SRCS=\
+	$(MODULE_SRCDIR)/gmp-openh264.cpp\
+
+MODULE_OBJS += $(MODULE_CPP_SRCS:.cpp=.$(OBJ))
+
+OBJS += $(MODULE_OBJS)
+$(MODULE_SRCDIR)/%.$(OBJ): $(MODULE_SRCDIR)/%.cpp
+	$(QUIET_CXX)$(CXX) $(CFLAGS) $(CXXFLAGS) $(INCLUDES) $(MODULE_CFLAGS) $(MODULE_INCLUDES) -c $(CXX_O) $<
+
+$(LIBPREFIX)module.$(LIBSUFFIX): $(MODULE_OBJS)
+	$(QUIET)rm -f $@
+	$(QUIET_AR)$(AR) $(AR_OPTS) $+
+
+plugin: $(LIBPREFIX)module.$(LIBSUFFIX)
+LIBRARIES += $(LIBPREFIX)module.$(LIBSUFFIX)
--- /dev/null
+++ b/module/task_utils.h
@@ -1,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Original author: ekr@rtfm.com
+
+#ifndef task_utils_h__
+#define task_utils_h__
+
+
+class gmp_args_base : public GMPTask {
+ public:
+  void Run() = 0;
+};
+
+// The generated file contains four major function templates
+// (in variants for arbitrary numbers of arguments up to 10,
+// which is why it is machine generated). The four templates
+// are:
+//
+// WrapTask(o, m, ...) -- wraps a member function m of an object ptr o
+// WrapTaskRet(o, m, ..., r) -- wraps a member function m of an object ptr o
+//                              the function returns something that can
+//                              be assigned to *r
+// WrapTaskNM(f, ...) -- wraps a function f
+// WrapTaskNMRet(f, ..., r) -- wraps a function f that returns something
+//                             that can be assigned to *r
+//
+// All of these template functions return a Task* which can be passed
+// to Post().
+#include "task_utils_generated.h"
+
+#endif
--- /dev/null
+++ b/module/task_utils.py
@@ -1,0 +1,171 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+MAX_ARGS = 15
+
+boilerplate = "/* This Source Code Form is subject to the terms of the Mozilla Public\n\
+ * License, v. 2.0. If a copy of the MPL was not distributed with this\n\
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n"
+
+def gen_args_type(args, member):
+    if member:
+        ret = ["C o"]
+    else:
+        ret = []
+    ret.append("M m")
+    for arg in range(0, args):
+        ret.append("A%d a%d"%(arg, arg))
+    return ", ".join(ret)
+
+def gen_args(args, member):
+    if member:
+        ret = ["o"]
+    else:
+        ret = []
+    ret.append("m")
+    for arg in range(0, args):
+        ret.append("a%d"%(arg))
+    return ", ".join(ret)
+
+def gen_args_(args):
+    ret = []
+    for arg in range(0, args):
+        ret.append("a%d_"%(arg))
+    return ", ".join(ret)
+
+def gen_init(args, r = False, member = False):
+    if member:
+        ret = ["o_(o)"]
+    else:
+        ret = []
+    ret.append("m_(m)")
+
+    if r:
+        ret.append("r_(r)")
+
+    for arg in range(0, args):
+        ret.append("a%d_(a%d)"%(arg, arg))
+    return ", ".join(ret)
+
+def gen_typenames(args, member):
+    if member:
+        ret = ["typename C"]
+    else:
+        ret = []
+    ret.append("typename M")
+
+    for arg in range(0, args):
+        ret.append("typename A%d"%(arg))
+    return ", ".join(ret)
+
+def gen_types(args, member):
+    if member:
+        ret = ["C"]
+    else:
+        ret = []
+    ret.append("M")
+    for arg in range(0, args):
+        ret.append("A%d"%(arg))
+    return ", ".join(ret)
+
+
+def generate_class_template(args, ret = False, member = True):
+    print "// %d arguments --"%args
+    if member:
+        nm = "m"
+    else:
+        nm = "nm"
+
+    if not ret:
+        print "template<"+ gen_typenames(args, member) + "> class gmp_args_%s_%d : public gmp_args_base {"%(nm, args)
+    else:
+        print "template<"+ gen_typenames(args, member) + ", typename R> class gmp_args_%s_%d_ret : public gmp_args_base {"%(nm, args)
+
+    print " public:"
+
+    if not ret:
+        print "  gmp_args_%s_%d("%(nm, args) + gen_args_type(args, member) + ") :"
+        print "    " + gen_init(args, False, member) + "  {}"
+    else:
+        print "  gmp_args_%s_%d_ret("%(nm, args) + gen_args_type(args, member) + ", R *r) :"
+        print "    " + gen_init(args, True, member) + "  {}"
+        print "  virtual bool returns_value() const { return true; }"
+    print
+    print "  void Run() {"
+    if ret:
+        print "    *r_ =",
+    else:
+        print "   ",
+    if member:
+        print "((*o_).*m_)(" + gen_args_(args) + ");"
+    else:
+        print "m_(" + gen_args_(args) + ");"
+    print "  }"
+    print
+    print " private:"
+    if member:
+        print "  C o_;"
+    print "  M m_;"
+    if ret:
+        print "  R* r_;"
+    for arg in range(0, args):
+        print "  A%d a%d_;"%(arg, arg)
+    print "};"
+    print
+    print
+    print
+
+def generate_function_template(args, member):
+    if member:
+        nm = "m"
+        NM = "";
+    else:
+        nm = "nm"
+        NM = "NM";
+
+    print "// %d arguments --"%args
+    print "template<" + gen_typenames(args, member) + ">"
+    print "gmp_args_%s_%d<"%(nm, args) + gen_types(args, member) + ">* WrapTask%s("%NM + gen_args_type(args, member) + ") {"
+    print "  return new gmp_args_%s_%d<"%(nm, args) + gen_types(args, member) + ">"
+    print "    (" + gen_args(args, member) + ");"
+    print "}"
+    print
+
+def generate_function_template_ret(args, member):
+    if member:
+        nm = "m"
+        NM = "";
+    else:
+        nm = "nm"
+        NM = "NM";
+    print "// %d arguments --"%args
+    print "template<" + gen_typenames(args, member) + ", typename R>"
+    print "gmp_args_%s_%d_ret<"%(nm, args) + gen_types(args, member) + ", R>* WrapTask%sRet("%NM + gen_args_type(args, member) + ", R* r) {"
+    print "  return new gmp_args_%s_%d_ret<"%(nm, args) + gen_types(args, member) + ", R>"
+    print "    (" + gen_args(args, member) + ", r);"
+    print "}"
+    print
+
+
+print boilerplate
+print
+
+for num_args in range (0, MAX_ARGS):
+    generate_class_template(num_args, False, False)
+    generate_class_template(num_args, True, False)
+    generate_class_template(num_args, False, True)
+    generate_class_template(num_args, True, True)
+
+
+print
+print
+print
+
+for num_args in range(0, MAX_ARGS):
+    generate_function_template(num_args, False)
+    generate_function_template_ret(num_args, False)
+    generate_function_template(num_args, True)
+    generate_function_template_ret(num_args, True)
+
+
+
--- /dev/null
+++ b/module/task_utils_generated.h
@@ -1,0 +1,1898 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// 0 arguments --
+template<typename M> class gmp_args_nm_0 : public gmp_args_base {
+ public:
+  gmp_args_nm_0(M m) :
+    m_(m)  {}
+
+  void Run() {
+    m_();
+  }
+
+ private:
+  M m_;
+};
+
+
+
+// 0 arguments --
+template<typename M, typename R> class gmp_args_nm_0_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_0_ret(M m, R *r) :
+    m_(m), r_(r)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_();
+  }
+
+ private:
+  M m_;
+  R* r_;
+};
+
+
+
+// 0 arguments --
+template<typename C, typename M> class gmp_args_m_0 : public gmp_args_base {
+ public:
+  gmp_args_m_0(C o, M m) :
+    o_(o), m_(m)  {}
+
+  void Run() {
+    ((*o_).*m_)();
+  }
+
+ private:
+  C o_;
+  M m_;
+};
+
+
+
+// 0 arguments --
+template<typename C, typename M, typename R> class gmp_args_m_0_ret : public gmp_args_base {
+ public:
+  gmp_args_m_0_ret(C o, M m, R *r) :
+    o_(o), m_(m), r_(r)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)();
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+};
+
+
+
+// 1 arguments --
+template<typename M, typename A0> class gmp_args_nm_1 : public gmp_args_base {
+ public:
+  gmp_args_nm_1(M m, A0 a0) :
+    m_(m), a0_(a0)  {}
+
+  void Run() {
+    m_(a0_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+};
+
+
+
+// 1 arguments --
+template<typename M, typename A0, typename R> class gmp_args_nm_1_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_1_ret(M m, A0 a0, R *r) :
+    m_(m), r_(r), a0_(a0)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+};
+
+
+
+// 1 arguments --
+template<typename C, typename M, typename A0> class gmp_args_m_1 : public gmp_args_base {
+ public:
+  gmp_args_m_1(C o, M m, A0 a0) :
+    o_(o), m_(m), a0_(a0)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+};
+
+
+
+// 1 arguments --
+template<typename C, typename M, typename A0, typename R> class gmp_args_m_1_ret : public gmp_args_base {
+ public:
+  gmp_args_m_1_ret(C o, M m, A0 a0, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+};
+
+
+
+// 2 arguments --
+template<typename M, typename A0, typename A1> class gmp_args_nm_2 : public gmp_args_base {
+ public:
+  gmp_args_nm_2(M m, A0 a0, A1 a1) :
+    m_(m), a0_(a0), a1_(a1)  {}
+
+  void Run() {
+    m_(a0_, a1_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+};
+
+
+
+// 2 arguments --
+template<typename M, typename A0, typename A1, typename R> class gmp_args_nm_2_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_2_ret(M m, A0 a0, A1 a1, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+};
+
+
+
+// 2 arguments --
+template<typename C, typename M, typename A0, typename A1> class gmp_args_m_2 : public gmp_args_base {
+ public:
+  gmp_args_m_2(C o, M m, A0 a0, A1 a1) :
+    o_(o), m_(m), a0_(a0), a1_(a1)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+};
+
+
+
+// 2 arguments --
+template<typename C, typename M, typename A0, typename A1, typename R> class gmp_args_m_2_ret : public gmp_args_base {
+ public:
+  gmp_args_m_2_ret(C o, M m, A0 a0, A1 a1, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+};
+
+
+
+// 3 arguments --
+template<typename M, typename A0, typename A1, typename A2> class gmp_args_nm_3 : public gmp_args_base {
+ public:
+  gmp_args_nm_3(M m, A0 a0, A1 a1, A2 a2) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+};
+
+
+
+// 3 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename R> class gmp_args_nm_3_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_3_ret(M m, A0 a0, A1 a1, A2 a2, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+};
+
+
+
+// 3 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2> class gmp_args_m_3 : public gmp_args_base {
+ public:
+  gmp_args_m_3(C o, M m, A0 a0, A1 a1, A2 a2) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+};
+
+
+
+// 3 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename R> class gmp_args_m_3_ret : public gmp_args_base {
+ public:
+  gmp_args_m_3_ret(C o, M m, A0 a0, A1 a1, A2 a2, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+};
+
+
+
+// 4 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3> class gmp_args_nm_4 : public gmp_args_base {
+ public:
+  gmp_args_nm_4(M m, A0 a0, A1 a1, A2 a2, A3 a3) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+};
+
+
+
+// 4 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename R> class gmp_args_nm_4_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_4_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+};
+
+
+
+// 4 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3> class gmp_args_m_4 : public gmp_args_base {
+ public:
+  gmp_args_m_4(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+};
+
+
+
+// 4 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename R> class gmp_args_m_4_ret : public gmp_args_base {
+ public:
+  gmp_args_m_4_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+};
+
+
+
+// 5 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4> class gmp_args_nm_5 : public gmp_args_base {
+ public:
+  gmp_args_nm_5(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+};
+
+
+
+// 5 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R> class gmp_args_nm_5_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_5_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+};
+
+
+
+// 5 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4> class gmp_args_m_5 : public gmp_args_base {
+ public:
+  gmp_args_m_5(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+};
+
+
+
+// 5 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R> class gmp_args_m_5_ret : public gmp_args_base {
+ public:
+  gmp_args_m_5_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+};
+
+
+
+// 6 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5> class gmp_args_nm_6 : public gmp_args_base {
+ public:
+  gmp_args_nm_6(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+};
+
+
+
+// 6 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R> class gmp_args_nm_6_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_6_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+};
+
+
+
+// 6 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5> class gmp_args_m_6 : public gmp_args_base {
+ public:
+  gmp_args_m_6(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+};
+
+
+
+// 6 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R> class gmp_args_m_6_ret : public gmp_args_base {
+ public:
+  gmp_args_m_6_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+};
+
+
+
+// 7 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> class gmp_args_nm_7 : public gmp_args_base {
+ public:
+  gmp_args_nm_7(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+};
+
+
+
+// 7 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R> class gmp_args_nm_7_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_7_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+};
+
+
+
+// 7 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> class gmp_args_m_7 : public gmp_args_base {
+ public:
+  gmp_args_m_7(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+};
+
+
+
+// 7 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R> class gmp_args_m_7_ret : public gmp_args_base {
+ public:
+  gmp_args_m_7_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+};
+
+
+
+// 8 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> class gmp_args_nm_8 : public gmp_args_base {
+ public:
+  gmp_args_nm_8(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+};
+
+
+
+// 8 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R> class gmp_args_nm_8_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_8_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+};
+
+
+
+// 8 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> class gmp_args_m_8 : public gmp_args_base {
+ public:
+  gmp_args_m_8(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+};
+
+
+
+// 8 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R> class gmp_args_m_8_ret : public gmp_args_base {
+ public:
+  gmp_args_m_8_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+};
+
+
+
+// 9 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> class gmp_args_nm_9 : public gmp_args_base {
+ public:
+  gmp_args_nm_9(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+};
+
+
+
+// 9 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R> class gmp_args_nm_9_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_9_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+};
+
+
+
+// 9 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> class gmp_args_m_9 : public gmp_args_base {
+ public:
+  gmp_args_m_9(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+};
+
+
+
+// 9 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R> class gmp_args_m_9_ret : public gmp_args_base {
+ public:
+  gmp_args_m_9_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+};
+
+
+
+// 10 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> class gmp_args_nm_10 : public gmp_args_base {
+ public:
+  gmp_args_nm_10(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+};
+
+
+
+// 10 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R> class gmp_args_nm_10_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_10_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+};
+
+
+
+// 10 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> class gmp_args_m_10 : public gmp_args_base {
+ public:
+  gmp_args_m_10(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+};
+
+
+
+// 10 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R> class gmp_args_m_10_ret : public gmp_args_base {
+ public:
+  gmp_args_m_10_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+};
+
+
+
+// 11 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10> class gmp_args_nm_11 : public gmp_args_base {
+ public:
+  gmp_args_nm_11(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+};
+
+
+
+// 11 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R> class gmp_args_nm_11_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_11_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+};
+
+
+
+// 11 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10> class gmp_args_m_11 : public gmp_args_base {
+ public:
+  gmp_args_m_11(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+};
+
+
+
+// 11 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R> class gmp_args_m_11_ret : public gmp_args_base {
+ public:
+  gmp_args_m_11_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+};
+
+
+
+// 12 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11> class gmp_args_nm_12 : public gmp_args_base {
+ public:
+  gmp_args_nm_12(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+};
+
+
+
+// 12 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R> class gmp_args_nm_12_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_12_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+};
+
+
+
+// 12 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11> class gmp_args_m_12 : public gmp_args_base {
+ public:
+  gmp_args_m_12(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+};
+
+
+
+// 12 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R> class gmp_args_m_12_ret : public gmp_args_base {
+ public:
+  gmp_args_m_12_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+};
+
+
+
+// 13 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12> class gmp_args_nm_13 : public gmp_args_base {
+ public:
+  gmp_args_nm_13(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+};
+
+
+
+// 13 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R> class gmp_args_nm_13_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_13_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+};
+
+
+
+// 13 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12> class gmp_args_m_13 : public gmp_args_base {
+ public:
+  gmp_args_m_13(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+};
+
+
+
+// 13 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R> class gmp_args_m_13_ret : public gmp_args_base {
+ public:
+  gmp_args_m_13_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+};
+
+
+
+// 14 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13> class gmp_args_nm_14 : public gmp_args_base {
+ public:
+  gmp_args_nm_14(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) :
+    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
+
+  void Run() {
+    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
+  }
+
+ private:
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+  A13 a13_;
+};
+
+
+
+// 14 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R> class gmp_args_nm_14_ret : public gmp_args_base {
+ public:
+  gmp_args_nm_14_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) :
+    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
+  }
+
+ private:
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+  A13 a13_;
+};
+
+
+
+// 14 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13> class gmp_args_m_14 : public gmp_args_base {
+ public:
+  gmp_args_m_14(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) :
+    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
+
+  void Run() {
+    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+  A13 a13_;
+};
+
+
+
+// 14 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R> class gmp_args_m_14_ret : public gmp_args_base {
+ public:
+  gmp_args_m_14_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) :
+    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
+  virtual bool returns_value() const { return true; }
+
+  void Run() {
+    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
+  }
+
+ private:
+  C o_;
+  M m_;
+  R* r_;
+  A0 a0_;
+  A1 a1_;
+  A2 a2_;
+  A3 a3_;
+  A4 a4_;
+  A5 a5_;
+  A6 a6_;
+  A7 a7_;
+  A8 a8_;
+  A9 a9_;
+  A10 a10_;
+  A11 a11_;
+  A12 a12_;
+  A13 a13_;
+};
+
+
+
+
+
+
+// 0 arguments --
+template<typename M>
+gmp_args_nm_0<M>* WrapTaskNM(M m) {
+  return new gmp_args_nm_0<M>
+    (m);
+}
+
+// 0 arguments --
+template<typename M, typename R>
+gmp_args_nm_0_ret<M, R>* WrapTaskNMRet(M m, R* r) {
+  return new gmp_args_nm_0_ret<M, R>
+    (m, r);
+}
+
+// 0 arguments --
+template<typename C, typename M>
+gmp_args_m_0<C, M>* WrapTask(C o, M m) {
+  return new gmp_args_m_0<C, M>
+    (o, m);
+}
+
+// 0 arguments --
+template<typename C, typename M, typename R>
+gmp_args_m_0_ret<C, M, R>* WrapTaskRet(C o, M m, R* r) {
+  return new gmp_args_m_0_ret<C, M, R>
+    (o, m, r);
+}
+
+// 1 arguments --
+template<typename M, typename A0>
+gmp_args_nm_1<M, A0>* WrapTaskNM(M m, A0 a0) {
+  return new gmp_args_nm_1<M, A0>
+    (m, a0);
+}
+
+// 1 arguments --
+template<typename M, typename A0, typename R>
+gmp_args_nm_1_ret<M, A0, R>* WrapTaskNMRet(M m, A0 a0, R* r) {
+  return new gmp_args_nm_1_ret<M, A0, R>
+    (m, a0, r);
+}
+
+// 1 arguments --
+template<typename C, typename M, typename A0>
+gmp_args_m_1<C, M, A0>* WrapTask(C o, M m, A0 a0) {
+  return new gmp_args_m_1<C, M, A0>
+    (o, m, a0);
+}
+
+// 1 arguments --
+template<typename C, typename M, typename A0, typename R>
+gmp_args_m_1_ret<C, M, A0, R>* WrapTaskRet(C o, M m, A0 a0, R* r) {
+  return new gmp_args_m_1_ret<C, M, A0, R>
+    (o, m, a0, r);
+}
+
+// 2 arguments --
+template<typename M, typename A0, typename A1>
+gmp_args_nm_2<M, A0, A1>* WrapTaskNM(M m, A0 a0, A1 a1) {
+  return new gmp_args_nm_2<M, A0, A1>
+    (m, a0, a1);
+}
+
+// 2 arguments --
+template<typename M, typename A0, typename A1, typename R>
+gmp_args_nm_2_ret<M, A0, A1, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, R* r) {
+  return new gmp_args_nm_2_ret<M, A0, A1, R>
+    (m, a0, a1, r);
+}
+
+// 2 arguments --
+template<typename C, typename M, typename A0, typename A1>
+gmp_args_m_2<C, M, A0, A1>* WrapTask(C o, M m, A0 a0, A1 a1) {
+  return new gmp_args_m_2<C, M, A0, A1>
+    (o, m, a0, a1);
+}
+
+// 2 arguments --
+template<typename C, typename M, typename A0, typename A1, typename R>
+gmp_args_m_2_ret<C, M, A0, A1, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, R* r) {
+  return new gmp_args_m_2_ret<C, M, A0, A1, R>
+    (o, m, a0, a1, r);
+}
+
+// 3 arguments --
+template<typename M, typename A0, typename A1, typename A2>
+gmp_args_nm_3<M, A0, A1, A2>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2) {
+  return new gmp_args_nm_3<M, A0, A1, A2>
+    (m, a0, a1, a2);
+}
+
+// 3 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename R>
+gmp_args_nm_3_ret<M, A0, A1, A2, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, R* r) {
+  return new gmp_args_nm_3_ret<M, A0, A1, A2, R>
+    (m, a0, a1, a2, r);
+}
+
+// 3 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2>
+gmp_args_m_3<C, M, A0, A1, A2>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2) {
+  return new gmp_args_m_3<C, M, A0, A1, A2>
+    (o, m, a0, a1, a2);
+}
+
+// 3 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename R>
+gmp_args_m_3_ret<C, M, A0, A1, A2, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, R* r) {
+  return new gmp_args_m_3_ret<C, M, A0, A1, A2, R>
+    (o, m, a0, a1, a2, r);
+}
+
+// 4 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3>
+gmp_args_nm_4<M, A0, A1, A2, A3>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3) {
+  return new gmp_args_nm_4<M, A0, A1, A2, A3>
+    (m, a0, a1, a2, a3);
+}
+
+// 4 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename R>
+gmp_args_nm_4_ret<M, A0, A1, A2, A3, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) {
+  return new gmp_args_nm_4_ret<M, A0, A1, A2, A3, R>
+    (m, a0, a1, a2, a3, r);
+}
+
+// 4 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3>
+gmp_args_m_4<C, M, A0, A1, A2, A3>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) {
+  return new gmp_args_m_4<C, M, A0, A1, A2, A3>
+    (o, m, a0, a1, a2, a3);
+}
+
+// 4 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename R>
+gmp_args_m_4_ret<C, M, A0, A1, A2, A3, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) {
+  return new gmp_args_m_4_ret<C, M, A0, A1, A2, A3, R>
+    (o, m, a0, a1, a2, a3, r);
+}
+
+// 5 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4>
+gmp_args_nm_5<M, A0, A1, A2, A3, A4>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+  return new gmp_args_nm_5<M, A0, A1, A2, A3, A4>
+    (m, a0, a1, a2, a3, a4);
+}
+
+// 5 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R>
+gmp_args_nm_5_ret<M, A0, A1, A2, A3, A4, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) {
+  return new gmp_args_nm_5_ret<M, A0, A1, A2, A3, A4, R>
+    (m, a0, a1, a2, a3, a4, r);
+}
+
+// 5 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4>
+gmp_args_m_5<C, M, A0, A1, A2, A3, A4>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+  return new gmp_args_m_5<C, M, A0, A1, A2, A3, A4>
+    (o, m, a0, a1, a2, a3, a4);
+}
+
+// 5 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R>
+gmp_args_m_5_ret<C, M, A0, A1, A2, A3, A4, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) {
+  return new gmp_args_m_5_ret<C, M, A0, A1, A2, A3, A4, R>
+    (o, m, a0, a1, a2, a3, a4, r);
+}
+
+// 6 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
+gmp_args_nm_6<M, A0, A1, A2, A3, A4, A5>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
+  return new gmp_args_nm_6<M, A0, A1, A2, A3, A4, A5>
+    (m, a0, a1, a2, a3, a4, a5);
+}
+
+// 6 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R>
+gmp_args_nm_6_ret<M, A0, A1, A2, A3, A4, A5, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) {
+  return new gmp_args_nm_6_ret<M, A0, A1, A2, A3, A4, A5, R>
+    (m, a0, a1, a2, a3, a4, a5, r);
+}
+
+// 6 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
+gmp_args_m_6<C, M, A0, A1, A2, A3, A4, A5>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
+  return new gmp_args_m_6<C, M, A0, A1, A2, A3, A4, A5>
+    (o, m, a0, a1, a2, a3, a4, a5);
+}
+
+// 6 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R>
+gmp_args_m_6_ret<C, M, A0, A1, A2, A3, A4, A5, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) {
+  return new gmp_args_m_6_ret<C, M, A0, A1, A2, A3, A4, A5, R>
+    (o, m, a0, a1, a2, a3, a4, a5, r);
+}
+
+// 7 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
+gmp_args_nm_7<M, A0, A1, A2, A3, A4, A5, A6>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
+  return new gmp_args_nm_7<M, A0, A1, A2, A3, A4, A5, A6>
+    (m, a0, a1, a2, a3, a4, a5, a6);
+}
+
+// 7 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R>
+gmp_args_nm_7_ret<M, A0, A1, A2, A3, A4, A5, A6, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) {
+  return new gmp_args_nm_7_ret<M, A0, A1, A2, A3, A4, A5, A6, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, r);
+}
+
+// 7 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
+gmp_args_m_7<C, M, A0, A1, A2, A3, A4, A5, A6>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
+  return new gmp_args_m_7<C, M, A0, A1, A2, A3, A4, A5, A6>
+    (o, m, a0, a1, a2, a3, a4, a5, a6);
+}
+
+// 7 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R>
+gmp_args_m_7_ret<C, M, A0, A1, A2, A3, A4, A5, A6, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) {
+  return new gmp_args_m_7_ret<C, M, A0, A1, A2, A3, A4, A5, A6, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, r);
+}
+
+// 8 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
+gmp_args_nm_8<M, A0, A1, A2, A3, A4, A5, A6, A7>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) {
+  return new gmp_args_nm_8<M, A0, A1, A2, A3, A4, A5, A6, A7>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7);
+}
+
+// 8 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R>
+gmp_args_nm_8_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) {
+  return new gmp_args_nm_8_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, r);
+}
+
+// 8 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
+gmp_args_m_8<C, M, A0, A1, A2, A3, A4, A5, A6, A7>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) {
+  return new gmp_args_m_8<C, M, A0, A1, A2, A3, A4, A5, A6, A7>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7);
+}
+
+// 8 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R>
+gmp_args_m_8_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) {
+  return new gmp_args_m_8_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, r);
+}
+
+// 9 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
+gmp_args_nm_9<M, A0, A1, A2, A3, A4, A5, A6, A7, A8>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) {
+  return new gmp_args_nm_9<M, A0, A1, A2, A3, A4, A5, A6, A7, A8>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+}
+
+// 9 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R>
+gmp_args_nm_9_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) {
+  return new gmp_args_nm_9_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r);
+}
+
+// 9 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
+gmp_args_m_9<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) {
+  return new gmp_args_m_9<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+}
+
+// 9 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R>
+gmp_args_m_9_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) {
+  return new gmp_args_m_9_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r);
+}
+
+// 10 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
+gmp_args_nm_10<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) {
+  return new gmp_args_nm_10<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
+
+// 10 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R>
+gmp_args_nm_10_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) {
+  return new gmp_args_nm_10_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r);
+}
+
+// 10 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
+gmp_args_m_10<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) {
+  return new gmp_args_m_10<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
+
+// 10 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R>
+gmp_args_m_10_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) {
+  return new gmp_args_m_10_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r);
+}
+
+// 11 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
+gmp_args_nm_11<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) {
+  return new gmp_args_nm_11<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+}
+
+// 11 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R>
+gmp_args_nm_11_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) {
+  return new gmp_args_nm_11_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r);
+}
+
+// 11 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
+gmp_args_m_11<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) {
+  return new gmp_args_m_11<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+}
+
+// 11 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R>
+gmp_args_m_11_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) {
+  return new gmp_args_m_11_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r);
+}
+
+// 12 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
+gmp_args_nm_12<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) {
+  return new gmp_args_nm_12<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+}
+
+// 12 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R>
+gmp_args_nm_12_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) {
+  return new gmp_args_nm_12_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r);
+}
+
+// 12 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
+gmp_args_m_12<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) {
+  return new gmp_args_m_12<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
+}
+
+// 12 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R>
+gmp_args_m_12_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) {
+  return new gmp_args_m_12_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r);
+}
+
+// 13 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
+gmp_args_nm_13<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) {
+  return new gmp_args_nm_13<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
+}
+
+// 13 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R>
+gmp_args_nm_13_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) {
+  return new gmp_args_nm_13_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r);
+}
+
+// 13 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
+gmp_args_m_13<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) {
+  return new gmp_args_m_13<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
+}
+
+// 13 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R>
+gmp_args_m_13_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) {
+  return new gmp_args_m_13_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r);
+}
+
+// 14 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13>
+gmp_args_nm_14<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) {
+  return new gmp_args_nm_14<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
+}
+
+// 14 arguments --
+template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R>
+gmp_args_nm_14_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) {
+  return new gmp_args_nm_14_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>
+    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r);
+}
+
+// 14 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13>
+gmp_args_m_14<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) {
+  return new gmp_args_m_14<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
+}
+
+// 14 arguments --
+template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R>
+gmp_args_m_14_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) {
+  return new gmp_args_m_14_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>
+    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r);
+}
+