1. Rewrite reflection of parameter packet in RSExportFunc. In order to
generate the correct call (i.e., all parameters in the call instruction
must match the target function signature) regardless of ABI, we construct type
of parameter packet directly from target function prototype (which may not be
the same as the one declared in the source since Clang may modified it to
the type which is better supported by the target ABI.)
2. Rewrite reflection of RSExportRecordType to use clang::ASTRecordLayout. This
corrects the reflection of struct type when tail padding and field alignment
involve. This improves stability of RSExportRecordType reflection.
diff --git a/slang_rs_backend.cpp b/slang_rs_backend.cpp
index ea138cc..450a686 100644
--- a/slang_rs_backend.cpp
+++ b/slang_rs_backend.cpp
@@ -129,16 +129,45 @@
 
         // Create helper function
         {
-          llvm::PointerType *HelperFunctionParameterTypeP =
-              llvm::PointerType::getUnqual(
-                  EF->getParamPacketType()->getLLVMType());
-          llvm::FunctionType *HelperFunctionType;
-          std::vector<const llvm::Type*> Params;
+          llvm::StructType *HelperFunctionParameterTy = NULL;
 
-          Params.push_back(HelperFunctionParameterTypeP);
-          HelperFunctionType = llvm::FunctionType::get(F->getReturnType(),
-                                                       Params,
-                                                       false);
+          if (!F->getArgumentList().empty()) {
+            std::vector<const llvm::Type*> HelperFunctionParameterTys;
+            for (llvm::Function::arg_iterator AI = F->arg_begin(),
+                 AE = F->arg_end(); AI != AE; AI++)
+              HelperFunctionParameterTys.push_back(AI->getType());
+
+            HelperFunctionParameterTy =
+                llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
+          }
+
+          if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
+            fprintf(stderr, "Failed to export function %s: parameter type "
+                            "mismatch during creation of helper function.\n",
+                    EF->getName().c_str());
+
+            const RSExportRecordType *Expected = EF->getParamPacketType();
+            if (Expected) {
+              fprintf(stderr, "Expected:\n");
+              Expected->getLLVMType()->dump();
+            }
+            if (HelperFunctionParameterTy) {
+              fprintf(stderr, "Got:\n");
+              HelperFunctionParameterTy->dump();
+            }
+          }
+
+          std::vector<const llvm::Type*> Params;
+          if (HelperFunctionParameterTy) {
+            llvm::PointerType *HelperFunctionParameterTyP =
+                llvm::PointerType::getUnqual(HelperFunctionParameterTy);
+            Params.push_back(HelperFunctionParameterTyP);
+          }
+
+          llvm::FunctionType * HelperFunctionType =
+              llvm::FunctionType::get(F->getReturnType(),
+                                      Params,
+                                      /* IsVarArgs = */false);
 
           HelperFunction =
               llvm::Function::Create(HelperFunctionType,
@@ -164,7 +193,7 @@
 
             // getelementptr and load instruction for all elements in
             // parameter .p
-            for (int i = 0; i < EF->getNumParameters(); i++) {
+            for (size_t i = 0; i < EF->getNumParameters(); i++) {
               // getelementptr
               Idx[1] =
                   llvm::ConstantInt::get(
diff --git a/slang_rs_export_func.cpp b/slang_rs_export_func.cpp
index 19d6cee..8e0d160 100644
--- a/slang_rs_export_func.cpp
+++ b/slang_rs_export_func.cpp
@@ -1,11 +1,12 @@
 #include "slang_rs_export_func.h"
 
+#include "llvm/DerivedTypes.h"
 #include "llvm/Target/TargetData.h"
 
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 
 #include "slang_rs_context.h"
-#include "slang_rs_export_type.h"
 
 using namespace slang;
 
@@ -18,98 +19,111 @@
 
   F = new RSExportFunc(Context, Name);
 
-  // Check whether the parameters passed to the function is exportable
-  for (unsigned i = 0, e = FD->getNumParams(); i != e; i++) {
-    const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
-    const llvm::StringRef ParamName = PVD->getName();
+  // Initialize mParamPacketType
+  if (FD->getNumParams() <= 0) {
+    F->mParamPacketType = NULL;
+  } else {
+    clang::ASTContext *Ctx = Context->getASTContext();
 
-    assert(!ParamName.empty() && "Parameter must have a name");
+    std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_func_param:");
+    Id.append(F->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX);
 
-    if (PVD->hasDefaultArg())
-      fprintf(stderr,
-              "Note: parameter '%s' in function '%s' has default value "
-              "will not support\n",
-              ParamName.str().c_str(),
-              Name.str().c_str());
+    clang::RecordDecl *RD =
+        clang::RecordDecl::Create(*Ctx, clang::TTK_Struct,
+                                  Ctx->getTranslationUnitDecl(),
+                                  clang::SourceLocation(),
+                                  &Ctx->Idents.get(Id));
 
-    // Check type
-    RSExportType *PET = RSExportType::CreateFromDecl(Context, PVD);
-    if (PET != NULL) {
-      F->mParams.push_back(new Parameter(PET, ParamName));
-    } else {
-      fprintf(stderr, "Note: parameter '%s' in function '%s' uses unsupported "
-                      "type\n", ParamName.str().c_str(), Name.str().c_str());
+    for (unsigned i = 0; i < FD->getNumParams(); i++) {
+      const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
+      llvm::StringRef ParamName = PVD->getName();
+
+      if (PVD->hasDefaultArg())
+        fprintf(stderr, "Note: parameter '%s' in function '%s' has default "
+                        "value which is not supported\n",
+                        ParamName.str().c_str(),
+                        F->getName().c_str());
+
+      clang::FieldDecl *FD =
+          clang::FieldDecl::Create(*Ctx,
+                                   RD,
+                                   clang::SourceLocation(),
+                                   PVD->getIdentifier(),
+                                   PVD->getOriginalType(),
+                                   NULL,
+                                   /* BitWidth = */NULL,
+                                   /* Mutable = */false);
+      RD->addDecl(FD);
+    }
+
+    RD->completeDefinition();
+
+    clang::QualType T = Ctx->getTagDeclType(RD);
+    assert(!T.isNull());
+
+    RSExportType *ET =
+      RSExportType::Create(Context, T.getTypePtr());
+
+    if (ET == NULL) {
+      fprintf(stderr, "Failed to export the function %s. There's at least one  "
+                      "parameter whose type is not supported by the "
+                      "reflection", F->getName().c_str());
       delete F;
       return NULL;
     }
+
+    assert((ET->getClass() == RSExportType::ExportClassRecord) &&
+           "Parameter packet must be a record");
+
+    F->mParamPacketType = static_cast<RSExportRecordType *>(ET);
   }
 
   return F;
 }
 
-const RSExportRecordType *RSExportFunc::getParamPacketType() const {
-  // Pack parameters
-  if ((mParamPacketType == NULL) && hasParam()) {
-    int Index = 0;
-    RSExportRecordType *ParamPacketType =
-        new RSExportRecordType(mContext,
-                               "",
-                               /* IsPacked = */false,
-                               /* IsArtificial = */true);
+bool
+RSExportFunc::checkParameterPacketType(const llvm::StructType *ParamTy) const {
+  if (ParamTy == NULL)
+    return !hasParam();
+  else if (!hasParam())
+    return false;
 
-    for (const_param_iterator PI = params_begin(),
-             PE = params_end();
-         PI != PE;
-         PI++, Index++) {
-      // For-Loop's body should be:
-      const RSExportFunc::Parameter *P = *PI;
-      std::string nam = P->getName();
-      const RSExportType *typ = P->getType();
-      std::string typNam = typ->getName();
-      // If (type conversion is needed)
-      if (typNam.find("rs_") == 0) {
-        // P's type set to [1 x i32];
-        RSExportConstantArrayType *ECT = new RSExportConstantArrayType
-            (mContext, "addObj",
-             RSExportPrimitiveType::DataTypeSigned32,
-             RSExportPrimitiveType::DataKindUser,
-             false,
-             1);
-        ParamPacketType->mFields.push_back(
-            new RSExportRecordType::Field(ECT,
-                                          nam,
-                                          ParamPacketType,
-                                          Index) );
-      } else {
-        ParamPacketType->mFields.push_back(
-            new RSExportRecordType::Field(P->getType(),
-                                          nam,
-                                          ParamPacketType,
-                                          Index) );
-      }
-    }
+  assert(mParamPacketType != NULL);
 
+  const RSExportRecordType *ERT = mParamPacketType;
+  // must have same number of elements
+  if (ERT->getFields().size() != ParamTy->getNumElements())
+    return false;
 
+  const llvm::StructLayout *ParamTySL =
+      mContext->getTargetData()->getStructLayout(ParamTy);
 
-    ParamPacketType->AllocSize =
-        mContext->getTargetData()->getTypeAllocSize(
-            ParamPacketType->getLLVMType());
+  unsigned Index = 0;
+  for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
+       FE = ERT->fields_end(); FI != FE; FI++, Index++) {
+    const RSExportRecordType::Field *F = *FI;
 
-    mParamPacketType = ParamPacketType;
+    const llvm::Type *T1 = F->getType()->getLLVMType();
+    const llvm::Type *T2 = ParamTy->getTypeAtIndex(Index);
+
+    // Fast check
+    if (T1 == T2)
+      continue;
+
+    // Check offset
+    size_t T1Offset = F->getOffsetInParent();
+    size_t T2Offset = ParamTySL->getElementOffset(Index);
+
+    if (T1Offset != T2Offset)
+      return false;
+
+    // Check size
+    size_t T1Size = RSExportType::GetTypeAllocSize(F->getType());
+    size_t T2Size = mContext->getTargetData()->getTypeAllocSize(T2);
+
+    if (T1Size != T2Size)
+      return false;
   }
 
-  return mParamPacketType;
-}
-
-RSExportFunc::~RSExportFunc() {
-  for (const_param_iterator PI = params_begin(),
-           PE = params_end();
-       PI != params_end();
-       PI++)
-    delete *PI;
-
-  if (mParamPacketType != NULL)
-    delete mParamPacketType;
-
-  return;
+  return true;
 }
diff --git a/slang_rs_export_func.h b/slang_rs_export_func.h
index cbc7aa3..08bd381 100644
--- a/slang_rs_export_func.h
+++ b/slang_rs_export_func.h
@@ -6,45 +6,32 @@
 
 #include "llvm/ADT/StringRef.h"
 
+#include "slang_rs_export_type.h"
+
+namespace llvm {
+  class StructType;
+}
+
 namespace clang {
   class FunctionDecl;
 }   // namespace clang
 
 namespace slang {
 
-  class RSContext;
-  class RSExportType;
-  class RSExportRecordType;
+class RSContext;
 
 class RSExportFunc {
   friend class RSContext;
- public:
-  class Parameter {
-   private:
-    RSExportType *mType;
-    std::string mName;
-
-   public:
-    Parameter(RSExportType *T, const llvm::StringRef &Name)
-        : mType(T),
-          mName(Name.data(), Name.size()) {
-      return;
-    }
-
-    inline const RSExportType *getType() const { return mType; }
-    inline const std::string &getName() const { return mName; }
-  };
 
  private:
   RSContext *mContext;
   std::string mName;
-  std::list<const Parameter*> mParams;
-  mutable RSExportRecordType *mParamPacketType;
+  RSExportRecordType *mParamPacketType;
 
   RSExportFunc(RSContext *Context, const llvm::StringRef &Name)
-      : mContext(Context),
-        mName(Name.data(), Name.size()),
-        mParamPacketType(NULL) {
+    : mContext(Context),
+      mName(Name.data(), Name.size()),
+      mParamPacketType(NULL) {
     return;
   }
 
@@ -52,34 +39,37 @@
   static RSExportFunc *Create(RSContext *Context,
                               const clang::FunctionDecl *FD);
 
-  typedef std::list<const Parameter*>::const_iterator const_param_iterator;
+  typedef RSExportRecordType::const_field_iterator const_param_iterator;
 
   inline const_param_iterator params_begin() const {
-    return this->mParams.begin();
+    assert((mParamPacketType != NULL) &&
+           "Get parameter from export function without parameter!");
+    return mParamPacketType->fields_begin();
   }
   inline const_param_iterator params_end() const {
-    return this->mParams.end();
+    assert((mParamPacketType != NULL) &&
+           "Get parameter from export function without parameter!");
+    return mParamPacketType->fields_end();
   }
 
-  inline const std::string &getName() const {
-    return mName;
-  }
-  inline RSContext *getRSContext() const {
-    return mContext;
-  }
+  inline const std::string &getName() const { return mName; }
+  inline RSContext *getRSContext() const { return mContext; }
 
-  inline bool hasParam() const {
-    return !mParams.empty();
-  }
-  inline int getNumParameters() const {
-    return mParams.size();
-  }
+  inline bool hasParam() const
+    { return (mParamPacketType && !mParamPacketType->getFields().empty()); }
+  inline size_t getNumParameters() const
+    { return ((mParamPacketType) ? mParamPacketType->getFields().size() : 0); }
 
-  const RSExportRecordType *getParamPacketType() const;
+  inline const RSExportRecordType *getParamPacketType() const
+    { return mParamPacketType; }
 
-  ~RSExportFunc();
+  // Check whether the given ParamsPacket type (in LLVM type) is "size
+  // equivalent" to the one obtained from getParamPacketType(). If the @Params
+  // is NULL, means there must be no any parameters.
+  bool checkParameterPacketType(const llvm::StructType *ParamTy) const;
 };  // RSExportFunc
 
+
 }   // namespace slang
 
 #endif  // _SLANG_COMPILER_RS_EXPORT_FUNC_H
diff --git a/slang_rs_export_type.cpp b/slang_rs_export_type.cpp
index 9e7fe9e..a0b94e3 100644
--- a/slang_rs_export_type.cpp
+++ b/slang_rs_export_type.cpp
@@ -36,8 +36,13 @@
 
 const clang::Type
 *RSExportType::GetTypeOfDecl(const clang::DeclaratorDecl *DD) {
-  if (DD && DD->getTypeSourceInfo()) {
-    clang::QualType T = DD->getTypeSourceInfo()->getType();
+  if (DD) {
+    clang::QualType T;
+    if (DD->getTypeSourceInfo())
+      T = DD->getTypeSourceInfo()->getType();
+    else
+      T = DD->getType();
+
     if (T.isNull())
       return NULL;
     else
@@ -197,12 +202,17 @@
                FE = RD->field_end();
            FI != FE;
            FI++) {
-        const clang::Type *FT = GetTypeOfDecl(*FI);
+        const clang::FieldDecl *FD = *FI;
+        const clang::Type *FT = GetTypeOfDecl(FD);
         FT = GET_CANONICAL_TYPE(FT);
 
-        if (!TypeExportable(FT, SPS))
-          // TODO(zonr): warn that is's an unsupported field type
+        if (!TypeExportable(FT, SPS)) {
+          fprintf(stderr, "Field `%s' in Record `%s' contains unsupported "
+                          "type\n", FD->getNameAsString().c_str(),
+                                    RD->getNameAsString().c_str());
+          FT->dump();
           return NULL;
+        }
       }
 
       return T;
@@ -379,12 +389,16 @@
 
 RSExportType::RSExportType(RSContext *Context, const llvm::StringRef &Name)
     : mContext(Context),
-      // Make a copy on Name since data of @Name which is stored in ASTContext
-      // will be destroyed later
+      // Make a copy on Name since memory stored @Name is either allocated in
+      // ASTContext or allocated in GetTypeName which will be destroyed later.
       mName(Name.data(), Name.size()),
       mLLVMType(NULL) {
-  // TODO(zonr): Need to check whether the insertion is successful or not.
-  Context->insertExportType(Name, this);
+  // Don't cache the type whose name start with '<'. Those type failed to
+  // get their name since constructing their name in GetTypeName() requiring
+  // complicated work.
+  if (!Name.startswith(DUMMY_RS_TYPE_NAME_PREFIX))
+    // TODO(zonr): Need to check whether the insertion is successful or not.
+    Context->insertExportType(llvm::StringRef(Name), this);
   return;
 }
 
@@ -941,11 +955,18 @@
     return NULL;
   }
 
-  RSExportRecordType *ERT = new RSExportRecordType(Context,
-                                                   TypeName,
-                                                   RD->
-                                                   hasAttr<clang::PackedAttr>(),
-                                                   mIsArtificial);
+  // Struct layout construct by clang. We rely on this for obtaining the
+  // alloc size of a struct and offset of every field in that struct.
+  const clang::ASTRecordLayout *RL =
+      &Context->getASTContext()->getASTRecordLayout(RD);
+  assert((RL != NULL) && "Failed to retrieve the struct layout from Clang.");
+
+  RSExportRecordType *ERT =
+      new RSExportRecordType(Context,
+                             TypeName,
+                             RD->hasAttr<clang::PackedAttr>(),
+                             mIsArtificial,
+                             (RL->getSize() >> 3));
   unsigned int Index = 0;
 
   for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
@@ -975,19 +996,14 @@
     RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD);
 
     if (ET != NULL)
-      ERT->mFields.push_back(new Field(ET, FD->getName(), ERT, Index));
+      ERT->mFields.push_back(
+          new Field(ET, FD->getName(), ERT,
+                    static_cast<size_t>(RL->getFieldOffset(Index) >> 3)));
     else
       FAILED_CREATE_FIELD(FD->getName().str().c_str());
 #undef FAILED_CREATE_FIELD
   }
 
-  const clang::ASTRecordLayout &ASTRL =
-      Context->getASTContext()->getASTRecordLayout(RD);
-  ERT->AllocSize =
-      (ASTRL.getSize() > ASTRL.getDataSize()) ?
-      (ASTRL.getSize() >> 3) :
-      (ASTRL.getDataSize() >> 3);
-
   return ERT;
 }
 
@@ -1012,12 +1028,3 @@
                                FieldTypes,
                                mIsPacked);
 }
-
-/************************* RSExportRecordType::Field *************************/
-size_t RSExportRecordType::Field::getOffsetInParent() const {
-  // Struct layout obtains below will be cached by LLVM
-  const llvm::StructLayout *SL =
-      mParent->getRSContext()->getTargetData()->getStructLayout(
-          static_cast<const llvm::StructType*>(mParent->getLLVMType()));
-  return SL->getElementOffset(mIndex);
-}
diff --git a/slang_rs_export_type.h b/slang_rs_export_type.h
index 507ea7b..22fcd36 100644
--- a/slang_rs_export_type.h
+++ b/slang_rs_export_type.h
@@ -25,6 +25,8 @@
 #define GET_POINTEE_TYPE(T) \
   (((T) == NULL) ? NULL : \
                    GET_CANONICAL_TYPE((T)->getPointeeType().getTypePtr()))
+#define DUMMY_RS_TYPE_NAME_PREFIX   "<"
+#define DUMMY_RS_TYPE_NAME_POSTFIX  ">"
 
 namespace llvm {
   class Type;
@@ -244,9 +246,7 @@
 
 class RSExportPointerType : public RSExportType {
   friend class RSExportType;
-  friend class RSExportElement;
   friend class RSExportFunc;
-
  private:
   const RSExportType *mPointeeType;
 
@@ -278,7 +278,6 @@
   friend class RSExportType;
   friend class RSExportElement;
   friend class RSExportFunc;
-
  private:
   int mNumElement;   // number of element
 
@@ -382,8 +381,6 @@
 
 class RSExportRecordType : public RSExportType {
   friend class RSExportType;
-  friend class RSExportElement;
-  friend class RSExportFunc;
  public:
   class Field {
    private:
@@ -392,26 +389,25 @@
     std::string mName;
     // Link to the struct that contain this field
     const RSExportRecordType *mParent;
-    // Index in the container
-    unsigned int mIndex;
+    // Offset in the container
+    size_t mOffset;
 
    public:
     Field(const RSExportType *T,
           const llvm::StringRef &Name,
           const RSExportRecordType *Parent,
-          unsigned int Index)
+          size_t Offset)
         : mType(T),
           mName(Name.data(), Name.size()),
           mParent(Parent),
-          mIndex(Index) {
+          mOffset(Offset) {
       return;
     }
 
     inline const RSExportRecordType *getParent() const { return mParent; }
-    inline unsigned int getIndex() const { return mIndex; }
     inline const RSExportType *getType() const { return mType; }
     inline const std::string &getName() const { return mName; }
-    size_t getOffsetInParent() const;
+    inline size_t getOffsetInParent() const { return mOffset; }
   };
 
   typedef std::list<const Field*>::const_iterator const_field_iterator;
@@ -429,15 +425,17 @@
   // Artificial export struct type is not exported by user (and thus it won't
   // get reflected)
   bool mIsArtificial;
-  size_t AllocSize;
+  size_t mAllocSize;
 
   RSExportRecordType(RSContext *Context,
                      const llvm::StringRef &Name,
                      bool IsPacked,
-                     bool IsArtificial = false)
+                     bool IsArtificial,
+                     size_t AllocSize)
       : RSExportType(Context, Name),
         mIsPacked(IsPacked),
-        mIsArtificial(IsArtificial) {
+        mIsArtificial(IsArtificial),
+        mAllocSize(AllocSize) {
     return;
   }
 
@@ -454,9 +452,10 @@
  public:
   virtual ExportClass getClass() const;
 
+  inline const std::list<const Field*>& getFields() const { return mFields; }
   inline bool isPacked() const { return mIsPacked; }
   inline bool isArtificial() const { return mIsArtificial; }
-  inline size_t getAllocSize() const { return AllocSize; }
+  inline size_t getAllocSize() const { return mAllocSize; }
 
   ~RSExportRecordType() {
     for (std::list<const Field*>::iterator I = mFields.begin(),
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index e06c68d..43fac28 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -728,12 +728,14 @@
   // invoke_*()
   Context::ArgTy Args;
 
-  for (RSExportFunc::const_param_iterator I = EF->params_begin(),
-           E = EF->params_end();
-       I != E;
-       I++) {
-    const RSExportFunc::Parameter *P = *I;
-    Args.push_back(make_pair(GetTypeName(P->getType()), P->getName()));
+  if (EF->hasParam()) {
+    for (RSExportFunc::const_param_iterator I = EF->params_begin(),
+             E = EF->params_end();
+         I != E;
+         I++) {
+      Args.push_back(std::make_pair(GetTypeName((*I)->getType()),
+                                    (*I)->getName()));
+    }
   }
 
   C.startFunction(Context::AM_Public,