Improve Java reflection for 32-bit versus 64-bit differences.

Bug: 32780232
Bug: 20260865
Bug: 21597073

By default, when targeting API L or above, we support both 32-bit and
64-bit targets.  We do so by running two compilation passes -- a
32-bit compilation pass followed by a 64-bit compilation pass.  We
generate reflected Java code as part of the 64-bit compilation pass.
This can cause problems if there are "significant" differences between
the user's script (.rs file) as seen during 32-bit compilation
compared to 64-bit compilation -- for example, rs object handles (such
as rs_allocation and rs_element) are different sizes, the type size_t
is a different size, and a user can create arbitrary differences by
using the __LP64__ macro.  If any of those differences affect
reflected code (for example, by changing exported types), then we may
get incorrect runtime behavior on 32-bit targets.

At present we do have some special processing for rs object handles.
However, we don't properly address all cases -- for example, when an
rs object handle is a field of a struct or an argument to an invokable
function, reflected code does not get the layout of the struct or
argument list correct on 32-bit targets.  We also make no attempt to
address any other differences (such as size_t or __LP64__).

This CL is intended to fully address 32-bit versus 64-bit reflection
issues:

1) Fully handle rs object handle size differences when laying out data
   (such as structs and invokable function argument lists).

2) Emit errors for any other differences between 32-bit and 64-bit
   compilation that would require changes to reflected code (for
   example, no exported global may be of type size_t).

We solve these problems as follows:

a) As part of the 32-bit compilation pass, execute (most of) the same
   code paths we would use to generate reflected code, but instead of
   actually generating reflected code, collect information for later.

b) When we generate reflected code as part of the 64-bit compilation
   pass, we consult the information collected during the 32-bit
   compilation pass in order to do target sensitive data layout and to
   emit errors for intolerable 32-bit versus 64-bit differences.

This CL requires changes to the compatibility library (in
frameworks/rs).

Test: many
- slang/lit-tests
- slang/test
- RsTest aosp_x86_64-eng (aosp, emulator) 32-bit and 64-bit
- cts aosp_x86_64-eng (aosp, emulator) RenderScript and CtsRsCppTestCases
- RSTestBackward
  - aosp_arm-eng
    - n9 LMP MR1 Release (LM)
    - angler MNC DR Release (MD)
  - aosp_arm64-eng
    - n9 LMP MR1 Release (LM)
    - angler MNC DR Release (MD)
- RSTest_Backward19
  - aosp_arm-eng
    - n5 KLP MR2 Release (KT)
    - n9 LMP MR1 Release (LM)
    - angler MNC DR Release (MD)
- RSTest_CompatLib
  - aosp_arm-eng
    - n9 LMP MR1 Release (LM)
    - angler MNC DR Release (MD)
  - aosp_arm64-eng
    - n9 LMP MR1 Release (LM)
    - angler MNC DR Release (MD)
  - aosp_x86-eng
    - emulator aosp
  - aosp_x86_64-eng
    - emulator aosp
- RSTest_Compat19
  - aosp_arm-eng
    - n5 KLP MR2 Release (KT)
    - n9 LMP MR1 Release (LM)
    - angler MNC DR Release (MD)
  - aosp_x86
    - emulator aosp

Change-Id: I5d1fc51e35693588dff05afa48e1a4902859036e
diff --git a/Android.bp b/Android.bp
index 72c5acf..c01ce93 100644
--- a/Android.bp
+++ b/Android.bp
@@ -171,6 +171,7 @@
         "slang_rs_object_ref_count.cpp",
         "slang_rs_reflection.cpp",
         "slang_rs_reflection_cpp.cpp",
+        "slang_rs_reflection_state.cpp",
         "slang_rs_reflect_utils.cpp",
         "slang_rs_special_func.cpp",
         "slang_rs_special_kernel_param.cpp",
diff --git a/llvm-rs-cc.cpp b/llvm-rs-cc.cpp
index 2a2e486..7870fe5 100644
--- a/llvm-rs-cc.cpp
+++ b/llvm-rs-cc.cpp
@@ -42,6 +42,7 @@
 #include "slang_assert.h"
 #include "slang_diagnostic_buffer.h"
 #include "slang_rs_reflect_utils.h"
+#include "slang_rs_reflection_state.h"
 
 #include <list>
 #include <set>
@@ -267,6 +268,8 @@
 
   llvm::install_fatal_error_handler(LLVMErrorHandler, &DiagEngine);
 
+  slang::ReflectionState Reflection;
+
   // Compile the 32 bit version
   NamePairList IOFiles32;
   NamePairList DepFiles32;
@@ -280,7 +283,7 @@
       std::unique_ptr<slang::Slang> Compiler(
           new slang::Slang(32, &DiagEngine, &DiagsBuffer));
       CompileFailed =
-          !Compiler->compile(IOFiles32, IOFiles32, DepFiles32, Opts, *DiagOpts);
+          !Compiler->compile(IOFiles32, IOFiles32, DepFiles32, Opts, *DiagOpts, &Reflection);
   }
 
   // Handle the 64-bit case too!
@@ -294,7 +297,7 @@
     std::unique_ptr<slang::Slang> Compiler(
         new slang::Slang(64, &DiagEngine, &DiagsBuffer));
     CompileFailed =
-        !Compiler->compile(IOFiles64, IOFiles32, DepFiles64, Opts, *DiagOpts);
+        !Compiler->compile(IOFiles64, IOFiles32, DepFiles64, Opts, *DiagOpts, &Reflection);
   }
 
   llvm::errs() << DiagsBuffer.str();
diff --git a/slang.cpp b/slang.cpp
index aaac196..5b6aff7 100644
--- a/slang.cpp
+++ b/slang.cpp
@@ -82,7 +82,7 @@
 
 #include "slang_rs_reflection.h"
 #include "slang_rs_reflection_cpp.h"
-
+#include "slang_rs_reflection_state.h"
 
 namespace {
 
@@ -574,7 +574,8 @@
     const std::list<std::pair<const char*, const char*> > &IOFiles32,
     const std::list<std::pair<const char*, const char*> > &DepFiles,
     const RSCCOptions &Opts,
-    clang::DiagnosticOptions &DiagOpts) {
+    clang::DiagnosticOptions &DiagOpts,
+    ReflectionState *RState) {
   if (IOFiles32.empty())
     return true;
 
@@ -632,11 +633,28 @@
   // a single pass over the input file.
   bool SuppressAllWarnings = (Opts.mOutputType != Slang::OT_Dependency);
 
+  bool doReflection = true;
+  if (Opts.mEmit3264 && (Opts.mBitWidth == 32)) {
+    // Skip reflection on the 32-bit path if we are going to emit it on the
+    // 64-bit path.
+    doReflection = false;
+  }
+
   std::list<std::pair<const char*, const char*> >::const_iterator
       IOFile64Iter = IOFiles64.begin(),
       IOFile32Iter = IOFiles32.begin(),
       DepFileIter = DepFiles.begin();
 
+  ReflectionState::Tentative TentativeRState(RState);
+  if (Opts.mEmit3264) {
+    if (Opts.mBitWidth == 32)
+      RState->openJava32(IOFiles32.size());
+    else {
+      slangAssert(Opts.mBitWidth == 64);
+      RState->openJava64();
+    }
+  }
+
   for (unsigned i = 0, e = IOFiles32.size(); i != e; i++) {
     InputFile = IOFile64Iter->first;
     Output64File = IOFile64Iter->second;
@@ -665,21 +683,17 @@
     const std::string &RealPackageName =
         mRSContext->getReflectJavaPackageName();
 
-    bool doReflection = true;
-    if (Opts.mEmit3264 && (Opts.mBitWidth == 32)) {
-      // Skip reflection on the 32-bit path if we are going to emit it on the
-      // 64-bit path.
-      doReflection = false;
-    }
-    if (Opts.mOutputType != Slang::OT_Dependency && doReflection) {
+    if (Opts.mOutputType != Slang::OT_Dependency) {
 
       if (Opts.mBitcodeStorage == BCST_CPP_CODE) {
-        const std::string &outputFileName = (Opts.mBitWidth == 64) ?
-                                            mOutputFileName : mOutput32FileName;
-        RSReflectionCpp R(mRSContext, Opts.mJavaReflectionPathBase,
-                          getInputFileName(), outputFileName);
-        if (!R.reflect()) {
+        if (doReflection) {
+          const std::string &outputFileName = (Opts.mBitWidth == 64) ?
+              mOutputFileName : mOutput32FileName;
+          RSReflectionCpp R(mRSContext, Opts.mJavaReflectionPathBase,
+                            getInputFileName(), outputFileName);
+          if (!R.reflect()) {
             return false;
+          }
         }
       } else {
         if (!Opts.mRSPackageName.empty()) {
@@ -690,7 +704,8 @@
         RSReflectionJava R(mRSContext, &generatedFileNames,
                            Opts.mJavaReflectionPathBase, getInputFileName(),
                            mOutputFileName,
-                           Opts.mBitcodeStorage == BCST_JAVA_CODE);
+                           Opts.mBitcodeStorage == BCST_JAVA_CODE,
+                           RState);
         if (!R.reflect()) {
           // TODO Is this needed or will the error message have been printed
           // already? and why not for the C++ case?
@@ -700,22 +715,24 @@
           return false;
         }
 
-        for (std::vector<std::string>::const_iterator
-                 I = generatedFileNames.begin(), E = generatedFileNames.end();
-             I != E;
-             I++) {
-          std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath(
-              Opts.mJavaReflectionPathBase.c_str(),
-              (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str());
-          appendGeneratedFileName(ReflectedName + ".java");
-        }
+        if (doReflection) {
+          for (std::vector<std::string>::const_iterator
+                   I = generatedFileNames.begin(), E = generatedFileNames.end();
+               I != E;
+               I++) {
+            std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath(
+                Opts.mJavaReflectionPathBase.c_str(),
+                (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str());
+            appendGeneratedFileName(ReflectedName + ".java");
+          }
 
-        if ((Opts.mOutputType == Slang::OT_Bitcode) &&
-            (Opts.mBitcodeStorage == BCST_JAVA_CODE) &&
-            !generateJavaBitcodeAccessor(Opts.mJavaReflectionPathBase,
-                                         RealPackageName.c_str(),
-                                         mRSContext->getLicenseNote())) {
-          return false;
+          if ((Opts.mOutputType == Slang::OT_Bitcode) &&
+              (Opts.mBitcodeStorage == BCST_JAVA_CODE) &&
+              !generateJavaBitcodeAccessor(Opts.mJavaReflectionPathBase,
+                                           RealPackageName.c_str(),
+                                           mRSContext->getLicenseNote())) {
+            return false;
+          }
         }
       }
     }
@@ -747,6 +764,17 @@
     IOFile64Iter++;
     IOFile32Iter++;
   }
+
+  if (Opts.mEmit3264) {
+    if (Opts.mBitWidth == 32)
+      RState->closeJava32();
+    else {
+      slangAssert(Opts.mBitWidth == 64);
+      RState->closeJava64();
+    }
+  }
+  TentativeRState.ok();
+
   return true;
 }
 
diff --git a/slang.h b/slang.h
index fcff79a..55a9ec2 100644
--- a/slang.h
+++ b/slang.h
@@ -68,6 +68,7 @@
 
 namespace slang {
 
+class ReflectionState;
 class RSCCOptions;
 class RSContext;
 class RSExportRecordType;
@@ -275,12 +276,15 @@
   //             with the same number of pairs given in @IOFiles.
   //
   // @Opts - Selection of options defined from invoking llvm-rs-cc
+  //
+  // @Reflection - Carries reflection information from 32-bit compile to 64-bit compile.
   bool
   compile(const std::list<std::pair<const char *, const char *>> &IOFiles64,
           const std::list<std::pair<const char *, const char *>> &IOFiles32,
           const std::list<std::pair<const char *, const char *>> &DepFiles,
           const RSCCOptions &Opts,
-          clang::DiagnosticOptions &DiagOpts);
+          clang::DiagnosticOptions &DiagOpts,
+          ReflectionState *Reflection);
 
   clang::ModuleLoadResult loadModule(clang::SourceLocation ImportLoc,
                                      clang::ModuleIdPath Path,
diff --git a/slang_rs_context.cpp b/slang_rs_context.cpp
index 53da2ef..b58c7a8 100644
--- a/slang_rs_context.cpp
+++ b/slang_rs_context.cpp
@@ -64,7 +64,8 @@
       version(0),
       mMangleCtx(Ctx.createMangleContext()),
       mIs64Bit(Target.getPointerWidth(0) == 64),
-      mNextSlot(1) {
+      mNextSlot(1),
+      mNextForEachOrdinal(0) {
 
   AddPragmaHandlers(PP, this);
 
diff --git a/slang_rs_context.h b/slang_rs_context.h
index 7ba4a13..a1017d1 100644
--- a/slang_rs_context.h
+++ b/slang_rs_context.h
@@ -111,6 +111,11 @@
   int getForEachSlotNumber(const clang::StringRef& funcName);
   unsigned mNextSlot;
 
+  // For diagnostic purposes, we record the order in which we parse
+  // foreach kernels -- which is not necessarily the same order in
+  // which they appear in mExportForEach.
+  unsigned mNextForEachOrdinal;
+
   ExportVarList mExportVars;
   ExportFuncList mExportFuncs;
   std::map<llvm::StringRef, unsigned> mExportForEachMap;
@@ -198,6 +203,7 @@
   }
 
   bool addForEach(const clang::FunctionDecl* FD);
+
   bool processExports();
   inline void newExportable(RSExportable *E) {
     if (E != nullptr)
@@ -221,6 +227,9 @@
   inline bool hasExportVar() const {
     return !mExportVars.empty();
   }
+  size_t export_vars_size() const {
+    return mExportVars.size();
+  }
 
   typedef ExportFuncList::const_iterator const_export_func_iterator;
   const_export_func_iterator export_funcs_begin() const {
@@ -230,6 +239,9 @@
     return mExportFuncs.end();
   }
   inline bool hasExportFunc() const { return !mExportFuncs.empty(); }
+  size_t export_funcs_size() const {
+    return mExportFuncs.size();
+  }
 
   typedef ExportForEachVector::const_iterator const_export_foreach_iterator;
   const_export_foreach_iterator export_foreach_begin() const {
@@ -241,6 +253,10 @@
   inline bool hasExportForEach() const { return !mExportForEach.empty(); }
   int getForEachSlotNumber(const clang::FunctionDecl* FD);
 
+  // count up from zero
+  unsigned getNextForEachOrdinal() { return mNextForEachOrdinal++; }
+  unsigned getNumAssignedForEachOrdinals() const { return mNextForEachOrdinal; }
+
   typedef ExportReduceList::const_iterator const_export_reduce_iterator;
   const_export_reduce_iterator export_reduce_begin() const {
     return mExportReduce.begin();
@@ -248,6 +264,9 @@
   const_export_reduce_iterator export_reduce_end() const {
     return mExportReduce.end();
   }
+  size_t export_reduce_size() const {
+    return mExportReduce.size();
+  }
   inline bool hasExportReduce() const { return !mExportReduce.empty(); }
   void addExportReduce(RSExportReduce *Reduce) {
     mExportReduce.push_back(Reduce);
diff --git a/slang_rs_export_foreach.cpp b/slang_rs_export_foreach.cpp
index 3b14aff..8fc693b 100644
--- a/slang_rs_export_foreach.cpp
+++ b/slang_rs_export_foreach.cpp
@@ -315,6 +315,7 @@
   slangAssert(!Name.empty() && "Function must have a name");
 
   FE = new RSExportForEach(Context, Name, FD->getLocation());
+  FE->mOrdinal = Context->getNextForEachOrdinal();
 
   if (!FE->validateAndConstructParams(Context, FD)) {
     return nullptr;
@@ -391,6 +392,7 @@
 
       // It is not an error if we don't export an input type for legacy
       // kernel arguments. This can happen in the case of a void pointer.
+      // See ReflectionState::addForEachIn().
       if (FE->mIsKernelStyle && !InExportType) {
         TypeExportError = true;
       }
diff --git a/slang_rs_export_foreach.h b/slang_rs_export_foreach.h
index eb973f5..4622e24 100644
--- a/slang_rs_export_foreach.h
+++ b/slang_rs_export_foreach.h
@@ -34,8 +34,7 @@
 
 namespace slang {
 
-// Base class for reflecting control-side forEach (currently for root()
-// functions that fit appropriate criteria)
+// Base class for reflecting control-side forEach
 class RSExportForEach : public RSExportable {
  public:
 
@@ -47,6 +46,11 @@
 
  private:
   std::string mName;
+
+  // For diagnostic purposes, we record the order in which we parse
+  // foreach kernels.  Does not apply to a dummy root.
+  unsigned mOrdinal;
+
   RSExportRecordType *mParamPacketType;
   llvm::SmallVector<const RSExportType*, 16> mInTypes;
   RSExportType *mOutType;
@@ -70,7 +74,8 @@
   // TODO(all): Add support for LOD/face when we have them
   RSExportForEach(RSContext *Context, const llvm::StringRef &Name, clang::SourceLocation Loc)
     : RSExportable(Context, RSExportable::EX_FOREACH, Loc),
-      mName(Name.data(), Name.size()), mParamPacketType(nullptr),
+      mName(Name.data(), Name.size()), mOrdinal(~unsigned(0)),
+      mParamPacketType(nullptr),
       mOutType(nullptr), numParams(0), mSignatureMetadata(0),
       mOut(nullptr), mUsrData(nullptr), mSpecialParameterSignatureMetadata(0),
       mResultType(clang::QualType()), mHasReturnType(false),
@@ -102,6 +107,11 @@
     return mName;
   }
 
+  inline unsigned getOrdinal() const {
+    slangAssert(!mDummyRoot);
+    return mOrdinal;
+  }
+
   inline size_t getNumParameters() const {
     return numParams;
   }
@@ -146,6 +156,11 @@
     return mDummyRoot;
   }
 
+  // is this a pass-by-value kernel?
+  inline bool isKernelStyle() const {
+    return mIsKernelStyle;
+  }
+
   typedef RSExportRecordType::const_field_iterator const_param_iterator;
 
   inline const_param_iterator params_begin() const {
@@ -159,6 +174,9 @@
                 "Get parameter from export foreach having no parameter!");
     return mParamPacketType->fields_end();
   }
+  inline size_t params_count() const {
+    return (mParamPacketType ? mParamPacketType->fields_size() : 0);
+  }
 
   static bool isRSForEachFunc(unsigned int targetAPI,
                               const clang::FunctionDecl *FD);
diff --git a/slang_rs_export_type.cpp b/slang_rs_export_type.cpp
index 21f85a0..afeb6c5 100644
--- a/slang_rs_export_type.cpp
+++ b/slang_rs_export_type.cpp
@@ -83,18 +83,18 @@
 
 // RS object types are 32 bits in 32-bit RS, but 256 bits in 64-bit RS.
 // This is handled specially by the GetElementSizeInBits() method.
-{ObjectDataType, _,          "RS_ELEMENT",          "ELEMENT", 32,         "Element",         "Element", _, _, _, false},
-{ObjectDataType, _,             "RS_TYPE",             "TYPE", 32,            "Type",            "Type", _, _, _, false},
-{ObjectDataType, _,       "RS_ALLOCATION",       "ALLOCATION", 32,      "Allocation",      "Allocation", _, _, _, false},
-{ObjectDataType, _,          "RS_SAMPLER",          "SAMPLER", 32,         "Sampler",         "Sampler", _, _, _, false},
-{ObjectDataType, _,           "RS_SCRIPT",           "SCRIPT", 32,          "Script",          "Script", _, _, _, false},
-{ObjectDataType, _,             "RS_MESH",             "MESH", 32,            "Mesh",            "Mesh", _, _, _, false},
-{ObjectDataType, _,             "RS_PATH",             "PATH", 32,            "Path",            "Path", _, _, _, false},
-{ObjectDataType, _, "RS_PROGRAM_FRAGMENT", "PROGRAM_FRAGMENT", 32, "ProgramFragment", "ProgramFragment", _, _, _, false},
-{ObjectDataType, _,   "RS_PROGRAM_VERTEX",   "PROGRAM_VERTEX", 32,   "ProgramVertex",   "ProgramVertex", _, _, _, false},
-{ObjectDataType, _,   "RS_PROGRAM_RASTER",   "PROGRAM_RASTER", 32,   "ProgramRaster",   "ProgramRaster", _, _, _, false},
-{ObjectDataType, _,    "RS_PROGRAM_STORE",    "PROGRAM_STORE", 32,    "ProgramStore",    "ProgramStore", _, _, _, false},
-{ObjectDataType, _,             "RS_FONT",             "FONT", 32,            "Font",            "Font", _, _, _, false},
+{ObjectDataType,          "rs_element",          "RS_ELEMENT",          "ELEMENT", 32,         "Element",         "Element", _, _, _, false},
+{ObjectDataType,             "rs_type",             "RS_TYPE",             "TYPE", 32,            "Type",            "Type", _, _, _, false},
+{ObjectDataType,       "rs_allocation",       "RS_ALLOCATION",       "ALLOCATION", 32,      "Allocation",      "Allocation", _, _, _, false},
+{ObjectDataType,          "rs_sampler",          "RS_SAMPLER",          "SAMPLER", 32,         "Sampler",         "Sampler", _, _, _, false},
+{ObjectDataType,           "rs_script",           "RS_SCRIPT",           "SCRIPT", 32,          "Script",          "Script", _, _, _, false},
+{ObjectDataType,             "rs_mesh",             "RS_MESH",             "MESH", 32,            "Mesh",            "Mesh", _, _, _, false},
+{ObjectDataType,             "rs_path",             "RS_PATH",             "PATH", 32,            "Path",            "Path", _, _, _, false},
+{ObjectDataType, "rs_program_fragment", "RS_PROGRAM_FRAGMENT", "PROGRAM_FRAGMENT", 32, "ProgramFragment", "ProgramFragment", _, _, _, false},
+{ObjectDataType,   "rs_program_vertex",   "RS_PROGRAM_VERTEX",   "PROGRAM_VERTEX", 32,   "ProgramVertex",   "ProgramVertex", _, _, _, false},
+{ObjectDataType,   "rs_program_raster",   "RS_PROGRAM_RASTER",   "PROGRAM_RASTER", 32,   "ProgramRaster",   "ProgramRaster", _, _, _, false},
+{ObjectDataType,    "rs_program_store",    "RS_PROGRAM_STORE",    "PROGRAM_STORE", 32,    "ProgramStore",    "ProgramStore", _, _, _, false},
+{ObjectDataType,             "rs_font",             "RS_FONT",             "FONT", 32,            "Font",            "Font", _, _, _, false},
 #undef _
 };
 
diff --git a/slang_rs_export_type.h b/slang_rs_export_type.h
index 57d0973..f55afcc 100644
--- a/slang_rs_export_type.h
+++ b/slang_rs_export_type.h
@@ -627,6 +627,9 @@
   inline const_field_iterator fields_end() const {
     return this->mFields.end();
   }
+  inline size_t fields_size() const {
+    return this->mFields.size();
+  }
 
  private:
   std::list<const Field*> mFields;
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index c5d2bc5..b2d226b 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -36,6 +36,7 @@
 #include "slang_rs_export_func.h"
 #include "slang_rs_export_reduce.h"
 #include "slang_rs_reflect_utils.h"
+#include "slang_rs_reflection_state.h"
 #include "slang_version.h"
 
 #define RS_SCRIPT_CLASS_NAME_PREFIX "ScriptC_"
@@ -75,27 +76,37 @@
 
 namespace slang {
 
+static void genCheck64BitInternal(const RSContext *Context, ReflectionState *State,
+                                  GeneratedFile &Out, bool Parens);
+
 class RSReflectionJavaElementBuilder {
 public:
   RSReflectionJavaElementBuilder(const char *ElementBuilderName,
                                  const RSExportRecordType *ERT,
                                  const char *RenderScriptVar,
                                  GeneratedFile *Out, const RSContext *RSContext,
-                                 RSReflectionJava *Reflection);
+                                 RSReflectionJava *Reflection,
+                                 ReflectionState *RState);
   void generate();
 
 private:
   void genAddElement(const RSExportType *ET, const std::string &VarName,
                      unsigned ArraySize);
   void genAddStatementStart();
-  void genAddStatementEnd(const std::string &VarName, unsigned ArraySize);
-  void genAddPadding(int PaddingSize);
+  void genAddStatementEnd(const std::string &VarName, unsigned ArraySize,
+                          unsigned Which = RSReflectionJava::FieldIndex | RSReflectionJava::Field32Index);
+  void genAddPadding(int PaddingSize, unsigned Which);  // Which: See RSReflectionJava::incFieldIndex()
+  void genAddPadding(int PaddingSize, ReflectionState::Val32 Field32PaddingSize);
   // TODO Will remove later due to field name information is not necessary for
   // C-reflect-to-Java
   std::string createPaddingField() {
     return mPaddingPrefix + llvm::itostr(mPaddingFieldIndex++);
   }
 
+  void genCheck64Bit(bool Parens) {
+    genCheck64BitInternal(mRSContext, mState, *mOut, Parens);
+  }
+
   const char *mElementBuilderName;
   const RSExportRecordType *mERT;
   const char *mRenderScriptVar;
@@ -104,17 +115,19 @@
   int mPaddingFieldIndex;
   const RSContext *mRSContext;
   RSReflectionJava *mReflection;
+  ReflectionState *mState;
 };
 
-static const char *GetMatrixTypeName(const RSExportMatrixType *EMT) {
-  static const char *MatrixTypeJavaNameMap[] = {/* 2x2 */ "Matrix2f",
-                                                /* 3x3 */ "Matrix3f",
-                                                /* 4x4 */ "Matrix4f",
+enum MatrixLanguage { ML_Java, ML_Script };
+static const char *GetMatrixTypeName(const RSExportMatrixType *EMT, MatrixLanguage lang) {
+  static const char *MatrixTypeJavaNameMap[3][2] = {/* 2x2 */ { "Matrix2f", "rs_matrix2x2" },
+                                                    /* 3x3 */ { "Matrix3f", "rs_matrix3x3" },
+                                                    /* 4x4 */ { "Matrix4f", "rs_matrix4x4" }
   };
   unsigned Dim = EMT->getDim();
 
   if ((Dim - 2) < (sizeof(MatrixTypeJavaNameMap) / sizeof(const char *)))
-    return MatrixTypeJavaNameMap[EMT->getDim() - 2];
+    return MatrixTypeJavaNameMap[EMT->getDim() - 2][lang];
 
   slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension");
   return nullptr;
@@ -320,11 +333,16 @@
 }
 
 std::string RSReflectionJava::GetTypeName(const RSExportType *ET, unsigned Style) {
+  slangAssert((Style & (TypeNameC|TypeNamePseudoC)) != (TypeNameC|TypeNamePseudoC));
+  slangAssert(!(Style & TypeNamePseudoC) || (Style == TypeNamePseudoC));
+
+  const bool CLike = Style & (TypeNameC|TypeNamePseudoC);
+
   switch (ET->getClass()) {
   case RSExportType::ExportClassPrimitive: {
     const auto ReflectionType =
         RSExportPrimitiveType::getRSReflectionType(static_cast<const RSExportPrimitiveType *>(ET));
-    return (Style & TypeNameC ? ReflectionType->s_name : ReflectionType->java_name);
+    return (CLike ? ReflectionType->s_name : ReflectionType->java_name);
   }
   case RSExportType::ExportClassPointer: {
     slangAssert(!(Style & TypeNameC) &&
@@ -332,7 +350,9 @@
     const RSExportType *PointeeType =
         static_cast<const RSExportPointerType *>(ET)->getPointeeType();
 
-    if (PointeeType->getClass() != RSExportType::ExportClassRecord)
+    if (Style & TypeNamePseudoC)
+      return GetTypeName(PointeeType, Style) + "*";
+    else if (PointeeType->getClass() != RSExportType::ExportClassRecord)
       return "Allocation";
     else
       return PointeeType->getElementName();
@@ -341,20 +361,23 @@
     const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET);
     const auto ReflectionType = EVT->getRSReflectionType(EVT);
     std::stringstream VecName;
-    VecName << (Style & TypeNameC ? ReflectionType->s_name : ReflectionType->rs_java_vector_prefix)
+    VecName << (CLike ? ReflectionType->s_name : ReflectionType->rs_java_vector_prefix)
             << EVT->getNumElement();
     return VecName.str();
   }
   case RSExportType::ExportClassMatrix: {
-    slangAssert(!(Style & TypeNameC) &&
-                "No need to support C type names for matrix types yet");
-    return GetMatrixTypeName(static_cast<const RSExportMatrixType *>(ET));
+    return GetMatrixTypeName(static_cast<const RSExportMatrixType *>(ET), CLike ? ML_Script : ML_Java);
   }
   case RSExportType::ExportClassConstantArray: {
     const RSExportConstantArrayType *CAT =
         static_cast<const RSExportConstantArrayType *>(ET);
     std::string ElementTypeName = GetTypeName(CAT->getElementType(), Style);
-    if (Style & TypeNameWithConstantArrayBrackets) {
+    if (Style & TypeNamePseudoC) {
+      std::stringstream ArrayName;
+      ArrayName << ElementTypeName << '[' << CAT->getNumElement() << ']';
+      return ArrayName.str();
+    }
+    else if (Style & TypeNameWithConstantArrayBrackets) {
       slangAssert(!(Style & TypeNameC) &&
                   "No need to support C type names for array types with brackets yet");
       ElementTypeName.append("[]");
@@ -364,7 +387,9 @@
   case RSExportType::ExportClassRecord: {
     slangAssert(!(Style & TypeNameC) &&
                 "No need to support C type names for record types yet");
-    if (Style & TypeNameWithRecordElementName)
+    if (Style & TypeNamePseudoC)
+      return "struct " + ET->getName();
+    else if (Style & TypeNameWithRecordElementName)
       return ET->getElementName() + "." RS_TYPE_ITEM_CLASS_NAME;
     else
       return ET->getName();
@@ -375,14 +400,105 @@
   return "";
 }
 
+void RSReflectionJava::genConditionalVal(const std::string &Prefix, bool Parens,
+                                         size_t Val, ReflectionState::Val32 Val32) {
+  if (Prefix.empty() || (Val != 0) || (Val32.first && (Val32.second != 0 ))) {
+    mOut << Prefix;
+
+    if (!Val32.first || (Val == Val32.second)) {
+      // Either we're ignoring the 32-bit case, or 32-bit and 64-bit
+      // values are the same.
+      mOut << Val;
+    } else {
+      // We cannot ignore the 32-bit case, and 32-bit and 64-bit
+      // values differ.
+      if (Parens)
+        mOut << '(';
+      genCheck64Bit(true);
+      mOut << " ? " << Val << " : " << Val32.second;
+      if (Parens)
+        mOut << ')';
+    }
+  }
+}
+
+static void genCheck64BitInternal(const RSContext *Context, ReflectionState *State,
+                                  GeneratedFile &Out, bool Parens) {
+  State->setOutputClassDivergent();
+  if (Context->isCompatLib()) {
+    if (Parens)
+      Out << '(';
+    Out << "RenderScript.getPointerSize() == 8";
+    if (Parens)
+      Out << ')';
+  }
+  else
+    Out << "sIs64Bit";
+}
+
+void RSReflectionJava::genCheck64Bit(bool Parens) {
+  genCheck64BitInternal(mRSContext, mState, mOut, Parens);
+}
+
+void RSReflectionJava::genCompute64Bit() {
+  if (mRSContext->isCompatLib()) {
+    // We can rely on RenderScript class in lockstep with llvm-rs-cc
+    // and hence in lockstep with the generated code, so we don't need
+    // any complicated logic to determine pointer size.
+    return;
+  }
+
+  // Note that Android L is the first release to support 64-bit
+  // targets.  When RenderScript is compiled with "-target-api $v"
+  // with "$v < 21" (L is API level 21), we only compile for 32-bit,
+  // and we reflect during that compile, so there are no divergent
+  // structs, and we will not get here.
+
+  slangAssert(mRSContext->getTargetAPI() >= SLANG_L_TARGET_API);
+
+  mOut.indent() << "private static boolean sIs64Bit;\n\n";
+  mOut.indent() << "static";
+  mOut.startBlock();
+  mOut.indent() << "if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)";
+  mOut.startBlock();
+  mOut.indent() << "sIs64Bit = Process.is64Bit();\n";
+  mOut.endBlock();
+  mOut.indent() << "else";
+  mOut.startBlock();
+  mOut.indent() << "try";
+  mOut.startBlock();
+  mOut.indent() << "Field f = RenderScript.class.getDeclaredField(\"sPointerSize\");\n";
+  mOut.indent() << "f.setAccessible(true);\n";
+  mOut.indent() << "sIs64Bit = (f.getInt(null) == 8);\n";
+  mOut.endBlock();
+
+  // If reflection fails, assume we're on a 32-bit-only device
+  // (64-bit-only is not allowed).  This should only happen if the
+  // device is L-or-later but has been customized in some way so that
+  // the field "sPointerSize" -- introduced in L -- is not present.
+  //
+  // Alternatively, we could treat this as 64-bit (reverting to the
+  // behavior prior to the fix for http://b/32780232) or we could
+  // decide we have no idea what's going on and throw an exception.
+  mOut.indent() << "catch (Throwable e)";
+  mOut.startBlock();
+  mOut.indent() << "sIs64Bit = false;\n";
+  mOut.endBlock();
+
+  mOut.endBlock();
+  mOut.endBlock();
+}
+
 /********************** Methods to generate script class **********************/
 RSReflectionJava::RSReflectionJava(const RSContext *Context,
                                    std::vector<std::string> *GeneratedFileNames,
                                    const std::string &OutputBaseDirectory,
                                    const std::string &RSSourceFileName,
                                    const std::string &BitCodeFileName,
-                                   bool EmbedBitcodeInJava)
-    : mRSContext(Context), mPackageName(Context->getReflectJavaPackageName()),
+                                   bool EmbedBitcodeInJava,
+                                   ReflectionState *RState)
+    : mRSContext(Context), mState(RState), mCollecting(RState->isCollecting()),
+      mPackageName(Context->getReflectJavaPackageName()),
       mRSPackageName(Context->getRSPackageName()),
       mOutputBaseDirectory(OutputBaseDirectory),
       mRSSourceFileName(RSSourceFileName), mBitCodeFileName(BitCodeFileName),
@@ -394,7 +510,7 @@
       mEmbedBitcodeInJava(EmbedBitcodeInJava), mNextExportVarSlot(0),
       mNextExportFuncSlot(0), mNextExportForEachSlot(0),
       mNextExportReduceSlot(0), mLastError(""),
-      mGeneratedFileNames(GeneratedFileNames), mFieldIndex(0) {
+  mGeneratedFileNames(GeneratedFileNames), mFieldIndex(0), mField32Index(0) {
   slangAssert(mGeneratedFileNames && "Must supply GeneratedFileNames");
   slangAssert(!mPackageName.empty() && mPackageName != "-");
 
@@ -408,52 +524,74 @@
   } else {
       mItemSizeof = RS_TYPE_ITEM_SIZEOF_LEGACY;
   }
+
+  mState->nextFile(mRSContext, mPackageName, mRSSourceFileName);
 }
 
 bool RSReflectionJava::genScriptClass(const std::string &ClassName,
                                       std::string &ErrorMsg) {
-  if (!startClass(AM_Public, false, ClassName, RS_SCRIPT_CLASS_SUPER_CLASS_NAME,
-                  ErrorMsg))
-    return false;
+  if (!mCollecting) {
+    if (!startClass(AM_Public, false, ClassName, RS_SCRIPT_CLASS_SUPER_CLASS_NAME,
+                    ErrorMsg))
+      return false;
 
-  genScriptClassConstructor();
+    mState->beginOutputClass();
+    genScriptClassConstructor();
+  }
 
   // Reflect exported variables
+  mState->beginVariables(mRSContext->export_vars_size());
   for (auto I = mRSContext->export_vars_begin(),
             E = mRSContext->export_vars_end();
        I != E; I++)
     genExportVariable(*I);
+  mState->endVariables();
 
   // Reflect exported forEach functions (only available on ICS+)
   if (mRSContext->getTargetAPI() >= SLANG_ICS_TARGET_API) {
+    mState->beginForEaches(mRSContext->getNumAssignedForEachOrdinals());
     for (auto I = mRSContext->export_foreach_begin(),
               E = mRSContext->export_foreach_end();
          I != E; I++) {
       genExportForEach(*I);
     }
+    mState->endForEaches();
   }
 
-  // Reflect exported new-style reduce functions
-  for (const RSExportType *ResultType : mRSContext->getReduceResultTypes(
-           // FilterIn
-           exportableReduce,
+  // Reflect exported reduce functions
+  if (!mCollecting) {
+    for (const RSExportType *ResultType : mRSContext->getReduceResultTypes(
+             // FilterIn
+             exportableReduce,
 
-           // Compare
-           [](const RSExportType *A, const RSExportType *B)
-           { return GetReduceResultTypeName(A) < GetReduceResultTypeName(B); }))
-    genExportReduceResultType(ResultType);
+             // Compare
+             [](const RSExportType *A, const RSExportType *B)
+             { return GetReduceResultTypeName(A) < GetReduceResultTypeName(B); }))
+      genExportReduceResultType(ResultType);
+  }
+  mState->beginReduces(mRSContext->export_reduce_size());
   for (auto I = mRSContext->export_reduce_begin(),
             E = mRSContext->export_reduce_end();
        I != E; ++I)
     genExportReduce(*I);
+  mState->endReduces();
 
   // Reflect exported functions (invokable)
+  mState->beginInvokables(mRSContext->export_funcs_size());
   for (auto I = mRSContext->export_funcs_begin(),
             E = mRSContext->export_funcs_end();
        I != E; ++I)
     genExportFunction(*I);
+  mState->endInvokables();
 
-  endClass();
+  if (!mCollecting) {
+    if (mState->endOutputClass())
+      genCompute64Bit();
+
+    endClass();
+
+    mGeneratedFileNames->push_back(mScriptClassName);
+  }
 
   return true;
 }
@@ -499,7 +637,8 @@
     mOut.indent() << "super(rs, resources, id);\n";
   }
 
-  // If an exported variable has initial value, reflect it
+  // If an exported variable has initial value, reflect it.
+  // Keep this in sync with initialization handling in ReflectionState::declareVariable().
 
   for (auto I = mRSContext->export_vars_begin(),
             E = mRSContext->export_vars_end();
@@ -721,6 +860,12 @@
 void RSReflectionJava::genExportVariable(const RSExportVar *EV) {
   const RSExportType *ET = EV->getType();
 
+  const ReflectionState::Val32
+      AllocSize32 = mState->declareVariable(EV);
+
+  if (mCollecting)
+    return;
+
   mOut.indent() << "private final static int " << RS_EXPORT_VAR_INDEX_PREFIX
                 << EV->getName() << " = " << getNextExportVarSlot() << ";\n";
 
@@ -742,69 +887,83 @@
     break;
   }
   case RSExportType::ExportClassConstantArray: {
-    genConstantArrayTypeExportVariable(EV);
+    genConstantArrayTypeExportVariable(EV, AllocSize32);
     break;
   }
   case RSExportType::ExportClassRecord: {
-    genRecordTypeExportVariable(EV);
+    genRecordTypeExportVariable(EV, AllocSize32);
     break;
   }
   default: { slangAssert(false && "Unknown class of type"); }
   }
 }
 
+// Keep this in sync with Invokable analysis in ReflectionState::declareInvokable().
 void RSReflectionJava::genExportFunction(const RSExportFunc *EF) {
-  mOut.indent() << "private final static int " << RS_EXPORT_FUNC_INDEX_PREFIX
-                << EF->getName() << " = " << getNextExportFuncSlot() << ";\n";
+  mState->declareInvokable(EF);
+
+  if (!mCollecting) {
+    mOut.indent() << "private final static int " << RS_EXPORT_FUNC_INDEX_PREFIX
+                  << EF->getName() << " = " << getNextExportFuncSlot() << ";\n";
+  }
 
   // invoke_*()
   ArgTy Args;
 
-  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()));
+  if (!mCollecting) {
+    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()));
+      }
     }
+
+    if (mRSContext->getTargetAPI() >= SLANG_M_TARGET_API) {
+      startFunction(AM_Public, false, "Script.InvokeID",
+                    "getInvokeID_" + EF->getName(), 0);
+
+      mOut.indent() << "return createInvokeID(" << RS_EXPORT_FUNC_INDEX_PREFIX
+                    << EF->getName() << ");\n";
+
+      endFunction();
+    }
+
+    startFunction(AM_Public, false, "void",
+                  "invoke_" + EF->getName(/*Mangle=*/false),
+                  // We are using un-mangled name since Java
+                  // supports method overloading.
+                  Args);
   }
 
-  if (mRSContext->getTargetAPI() >= SLANG_M_TARGET_API) {
-    startFunction(AM_Public, false, "Script.InvokeID",
-                  "getInvokeID_" + EF->getName(), 0);
-
-    mOut.indent() << "return createInvokeID(" << RS_EXPORT_FUNC_INDEX_PREFIX
-                  << EF->getName() << ");\n";
-
-    endFunction();
-  }
-
-  startFunction(AM_Public, false, "void",
-                "invoke_" + EF->getName(/*Mangle=*/false),
-                // We are using un-mangled name since Java
-                // supports method overloading.
-                Args);
-
   if (!EF->hasParam()) {
-    mOut.indent() << "invoke(" << RS_EXPORT_FUNC_INDEX_PREFIX << EF->getName()
-                  << ");\n";
+    if (!mCollecting)
+      mOut.indent() << "invoke(" << RS_EXPORT_FUNC_INDEX_PREFIX << EF->getName()
+                    << ");\n";
   } else {
     const RSExportRecordType *ERT = EF->getParamPacketType();
+
+    // NOTE: This type isn't on the RSContext::export_types* list.
+    mState->declareRecord(ERT, false);
+
     std::string FieldPackerName = EF->getName() + "_fp";
 
-    if (genCreateFieldPacker(ERT, FieldPackerName.c_str()))
+    if (genCreateFieldPacker(ERT, FieldPackerName.c_str(),
+                             mState->getRecord32(ERT).getRecordAllocSize()))
       genPackVarOfType(ERT, nullptr, FieldPackerName.c_str());
 
-    mOut.indent() << "invoke(" << RS_EXPORT_FUNC_INDEX_PREFIX << EF->getName()
-                  << ", " << FieldPackerName << ");\n";
+    if (!mCollecting)
+      mOut.indent() << "invoke(" << RS_EXPORT_FUNC_INDEX_PREFIX << EF->getName()
+                    << ", " << FieldPackerName << ");\n";
   }
 
-  endFunction();
+  if (!mCollecting)
+    endFunction();
 }
 
 void RSReflectionJava::genPairwiseDimCheck(const std::string &name0,
                                            const std::string &name1) {
-
   mOut.indent() << "// Verify dimensions\n";
   mOut.indent() << "t0 = " << name0 << ".getType();\n";
   mOut.indent() << "t1 = " << name1 << ".getType();\n";
@@ -839,19 +998,28 @@
   mOut.indent() << "}\n";
 }
 
+// Keep this in sync with ForEach analysis in ReflectionState::beginForEach()
+// and other ReflectionState::*ForEach*() methods.
 void RSReflectionJava::genExportForEach(const RSExportForEach *EF) {
   if (EF->isDummyRoot()) {
-    // Skip reflection for dummy root() kernels. Note that we have to
-    // advance the next slot number for ForEach, however.
-    mOut.indent() << "//private final static int "
-                  << RS_EXPORT_FOREACH_INDEX_PREFIX << EF->getName() << " = "
-                  << getNextExportForEachSlot() << ";\n";
+    mState->declareForEachDummyRoot(EF);
+
+    if (!mCollecting) {
+      // Skip reflection for dummy root() kernels. Note that we have to
+      // advance the next slot number for ForEach, however.
+      mOut.indent() << "//private final static int "
+                    << RS_EXPORT_FOREACH_INDEX_PREFIX << EF->getName() << " = "
+                    << getNextExportForEachSlot() << ";\n";
+    }
+
     return;
   }
 
-  mOut.indent() << "private final static int " << RS_EXPORT_FOREACH_INDEX_PREFIX
-                << EF->getName() << " = " << getNextExportForEachSlot()
-                << ";\n";
+  if (!mCollecting) {
+    mOut.indent() << "private final static int " << RS_EXPORT_FOREACH_INDEX_PREFIX
+                  << EF->getName() << " = " << getNextExportForEachSlot()
+                  << ";\n";
+  }
 
   // forEach_*()
   ArgTy Args;
@@ -860,130 +1028,159 @@
   const RSExportForEach::InVec     &Ins     = EF->getIns();
   const RSExportForEach::InTypeVec &InTypes = EF->getInTypes();
   const RSExportType               *OET     = EF->getOutType();
+  const RSExportRecordType         *ERT     = EF->getParamPacketType();
+
+  mState->beginForEach(EF);
+
+  for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end();
+       BI != EI; BI++) {
+    mState->addForEachIn(EF, *BI);
+  }
 
   if (Ins.size() == 1) {
     HasAllocation = true;
-    Args.push_back(std::make_pair("Allocation", "ain"));
-
+    if (!mCollecting)
+      Args.push_back(std::make_pair("Allocation", "ain"));
   } else if (Ins.size() > 1) {
     HasAllocation = true;
-    for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); BI != EI;
-         BI++) {
-
-      Args.push_back(std::make_pair("Allocation",
-                                    "ain_" + (*BI)->getName().str()));
+    if (!mCollecting) {
+      for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); BI != EI;
+           BI++) {
+        Args.push_back(std::make_pair("Allocation",
+                                      "ain_" + (*BI)->getName().str()));
+      }
     }
   }
 
   if (EF->hasOut() || EF->hasReturn()) {
     HasAllocation = true;
-    Args.push_back(std::make_pair("Allocation", "aout"));
+    if (!mCollecting)
+      Args.push_back(std::make_pair("Allocation", "aout"));
   }
 
-  const RSExportRecordType *ERT = EF->getParamPacketType();
   if (ERT) {
     for (RSExportForEach::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()));
+      mState->addForEachParam(EF, (*I)->getType());
+      if (!mCollecting)
+        Args.push_back(
+            std::make_pair(GetTypeName((*I)->getType()), (*I)->getName()));
     }
   }
 
   if (mRSContext->getTargetAPI() >= SLANG_JB_MR1_TARGET_API) {
-    startFunction(AM_Public, false, "Script.KernelID",
-                  "getKernelID_" + EF->getName(), 0);
+    mState->addForEachSignatureMetadata(EF, EF->getSignatureMetadata());
 
-    // TODO: add element checking
-    mOut.indent() << "return createKernelID(" << RS_EXPORT_FOREACH_INDEX_PREFIX
-                  << EF->getName() << ", " << EF->getSignatureMetadata()
-                  << ", null, null);\n";
+    if (!mCollecting) {
+      startFunction(AM_Public, false, "Script.KernelID",
+                    "getKernelID_" + EF->getName(), 0);
 
-    endFunction();
-  }
-
-  if (mRSContext->getTargetAPI() >= SLANG_JB_MR2_TARGET_API) {
-    if (HasAllocation) {
-      startFunction(AM_Public, false, "void", "forEach_" + EF->getName(), Args);
-
-      mOut.indent() << "forEach_" << EF->getName();
-      mOut << "(";
-
-      if (Ins.size() == 1) {
-        mOut << "ain, ";
-
-      } else if (Ins.size() > 1) {
-        for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); BI != EI;
-             BI++) {
-
-          mOut << "ain_" << (*BI)->getName().str() << ", ";
-        }
-      }
-
-      if (EF->hasOut() || EF->hasReturn()) {
-        mOut << "aout, ";
-      }
-
-      if (EF->hasUsrData()) {
-        mOut << Args.back().second << ", ";
-      }
-
-      // No clipped bounds to pass in.
-      mOut << "null);\n";
+      // TODO: add element checking
+      mOut.indent() << "return createKernelID(" << RS_EXPORT_FOREACH_INDEX_PREFIX
+                    << EF->getName() << ", " << EF->getSignatureMetadata()
+                    << ", null, null);\n";
 
       endFunction();
     }
-
-    // Add the clipped kernel parameters to the Args list.
-    Args.push_back(std::make_pair("Script.LaunchOptions", "sc"));
   }
 
-  startFunction(AM_Public, false, "void", "forEach_" + EF->getName(), Args);
+  if (!mCollecting) {
+    if (mRSContext->getTargetAPI() >= SLANG_JB_MR2_TARGET_API) {
+      if (HasAllocation) {
+        startFunction(AM_Public, false, "void", "forEach_" + EF->getName(), Args);
 
-  if (InTypes.size() == 1) {
-    if (InTypes.front() != nullptr) {
-      genTypeCheck(InTypes.front(), "ain");
+        mOut.indent() << "forEach_" << EF->getName();
+        mOut << "(";
+
+        if (Ins.size() == 1) {
+          mOut << "ain, ";
+
+        } else if (Ins.size() > 1) {
+          for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); BI != EI;
+               BI++) {
+
+            mOut << "ain_" << (*BI)->getName().str() << ", ";
+          }
+        }
+
+        if (EF->hasOut() || EF->hasReturn()) {
+          mOut << "aout, ";
+        }
+
+        if (EF->hasUsrData()) {
+          mOut << Args.back().second << ", ";
+        }
+
+        // No clipped bounds to pass in.
+        mOut << "null);\n";
+
+        endFunction();
+      }
+
+      // Add the clipped kernel parameters to the Args list.
+      Args.push_back(std::make_pair("Script.LaunchOptions", "sc"));
     }
+  }
 
-  } else if (InTypes.size() > 1) {
-    size_t Index = 0;
-    for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end();
-         BI != EI; BI++, ++Index) {
+  if (!mCollecting) {
+    startFunction(AM_Public, false, "void", "forEach_" + EF->getName(), Args);
 
-      if (*BI != nullptr) {
-        genTypeCheck(*BI, ("ain_" + Ins[Index]->getName()).str().c_str());
+    if (InTypes.size() == 1) {
+      if (InTypes.front() != nullptr) {
+        genTypeCheck(InTypes.front(), "ain");
+      }
+
+    } else if (InTypes.size() > 1) {
+      size_t Index = 0;
+      for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end();
+           BI != EI; BI++, ++Index) {
+
+        if (*BI != nullptr) {
+          genTypeCheck(*BI, ("ain_" + Ins[Index]->getName()).str().c_str());
+        }
       }
     }
-  }
 
-  if (OET) {
-    genTypeCheck(OET, "aout");
-  }
-
-  if (Ins.size() == 1 && (EF->hasOut() || EF->hasReturn())) {
-    mOut.indent() << "Type t0, t1;";
-    genPairwiseDimCheck("ain", "aout");
-
-  } else if (Ins.size() > 1) {
-    mOut.indent() << "Type t0, t1;";
-
-    std::string In0Name = "ain_" + Ins[0]->getName().str();
-
-    for (size_t index = 1; index < Ins.size(); ++index) {
-      genPairwiseDimCheck(In0Name, "ain_" + Ins[index]->getName().str());
+    if (OET) {
+      genTypeCheck(OET, "aout");
     }
 
-    if (EF->hasOut() || EF->hasReturn()) {
-      genPairwiseDimCheck(In0Name, "aout");
+    if (Ins.size() == 1 && (EF->hasOut() || EF->hasReturn())) {
+      mOut.indent() << "Type t0, t1;";
+      genPairwiseDimCheck("ain", "aout");
+
+    } else if (Ins.size() > 1) {
+      mOut.indent() << "Type t0, t1;";
+
+      std::string In0Name = "ain_" + Ins[0]->getName().str();
+
+      for (size_t index = 1; index < Ins.size(); ++index) {
+        genPairwiseDimCheck(In0Name, "ain_" + Ins[index]->getName().str());
+      }
+
+      if (EF->hasOut() || EF->hasReturn()) {
+        genPairwiseDimCheck(In0Name, "aout");
+      }
     }
   }
 
   std::string FieldPackerName = EF->getName() + "_fp";
   if (ERT) {
-    if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
+    // NOTE: This type isn't on the RSContext::export_types* list.
+    mState->declareRecord(ERT, false);
+
+    if (genCreateFieldPacker(ERT, FieldPackerName.c_str(),
+                             mState->getRecord32(ERT).getRecordAllocSize())) {
       genPackVarOfType(ERT, nullptr, FieldPackerName.c_str());
     }
   }
+
+  mState->endForEach();
+
+  if (mCollecting)
+    return;
+
   mOut.indent() << "forEach(" << RS_EXPORT_FOREACH_INDEX_PREFIX
                 << EF->getName();
 
@@ -1074,8 +1271,17 @@
 
 } // end anonymous namespace
 
+// Keep this in sync with Reduce analysis in ReflectionState::declareReduce().
 void RSReflectionJava::genExportReduce(const RSExportReduce *ER) {
-  if (!exportableReduce(ER->getResultType()))
+  const bool IsExportable = exportableReduce(ER->getResultType());
+
+  // Need to track even a non-exportable reduce, both so that we get
+  // the count of reduction kernels correct, and so that we can
+  // intelligently diagnose cases where 32-bit and 64-bit compiles
+  // disagree as to whether a reduction kernel is exportable.
+  mState->declareReduce(ER, IsExportable);
+
+  if (!IsExportable || mCollecting)
     return;
 
   // Generate the reflected function index.
@@ -1816,7 +2022,7 @@
                   TypeName.c_str(), "v");
     mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n";
 
-    if (genCreateFieldPacker(ET, FieldPackerName))
+    if (genCreateFieldPacker(ET, FieldPackerName, ReflectionState::NoVal32()))
       genPackVarOfType(ET, "v", FieldPackerName);
     mOut.indent() << "setVar(" RS_EXPORT_VAR_INDEX_PREFIX << VarName << ", "
                   << FieldPackerName << ");\n";
@@ -1829,7 +2035,8 @@
 }
 
 void
-RSReflectionJava::genConstantArrayTypeExportVariable(const RSExportVar *EV) {
+RSReflectionJava::genConstantArrayTypeExportVariable(const RSExportVar *EV,
+                                                     ReflectionState::Val32 AllocSize32) {
   const RSExportType *const ET = EV->getType();
   slangAssert(
       (ET->getClass() == RSExportType::ExportClassConstantArray) &&
@@ -1839,12 +2046,15 @@
   std::string VarName = EV->getName();
 
   genPrivateExportVariable(TypeName, VarName);
-  genSetExportVariable(TypeName, EV, static_cast<const RSExportConstantArrayType *>(ET)->getNumElement());
+  genSetExportVariable(TypeName, EV,
+                       static_cast<const RSExportConstantArrayType *>(ET)->getNumElement(),
+                       AllocSize32);
   genGetExportVariable(TypeName, VarName);
   genGetFieldID(VarName);
 }
 
-void RSReflectionJava::genRecordTypeExportVariable(const RSExportVar *EV) {
+void RSReflectionJava::genRecordTypeExportVariable(const RSExportVar *EV,
+                                                   ReflectionState::Val32 AllocSize32) {
   slangAssert((EV->getType()->getClass() == RSExportType::ExportClassRecord) &&
               "Variable should be type of struct here");
 
@@ -1852,7 +2062,7 @@
   std::string VarName = EV->getName();
 
   genPrivateExportVariable(TypeName, VarName);
-  genSetExportVariable(TypeName, EV, 1);
+  genSetExportVariable(TypeName, EV, 1, AllocSize32);
   genGetExportVariable(TypeName, VarName);
   genGetFieldID(VarName);
 }
@@ -1866,7 +2076,8 @@
 // Dimension = array element count; otherwise, 1.
 void RSReflectionJava::genSetExportVariable(const std::string &TypeName,
                                             const RSExportVar *EV,
-                                            unsigned Dimension) {
+                                            unsigned Dimension,
+                                            ReflectionState::Val32 AllocSize32) {
   if (!EV->isConst()) {
     const char *FieldPackerName = "fp";
     const std::string &VarName = EV->getName();
@@ -1875,7 +2086,7 @@
                   TypeName.c_str(), "v");
     mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n";
 
-    if (genCreateFieldPacker(ET, FieldPackerName))
+    if (genCreateFieldPacker(ET, FieldPackerName, AllocSize32))
       genPackVarOfType(ET, "v", FieldPackerName);
 
     if (mRSContext->getTargetAPI() < SLANG_JB_TARGET_API) {
@@ -1921,11 +2132,17 @@
 /******************* Methods to generate script class /end *******************/
 
 bool RSReflectionJava::genCreateFieldPacker(const RSExportType *ET,
-                                            const char *FieldPackerName) {
+                                            const char *FieldPackerName,
+                                            ReflectionState::Val32 AllocSize32) {
   size_t AllocSize = ET->getAllocSize();
-  if (AllocSize > 0)
-    mOut.indent() << "FieldPacker " << FieldPackerName << " = new FieldPacker("
-                  << AllocSize << ");\n";
+  slangAssert(!AllocSize32.first || ((AllocSize == 0) == (AllocSize32.second == 0)));
+  if (AllocSize > 0) {
+    if (!mCollecting) {
+      mOut.indent() << "FieldPacker " << FieldPackerName << " = new FieldPacker(";
+      genConditionalVal("", false, AllocSize, AllocSize32);
+      mOut << ");\n";
+    }
+  }
   else
     return false;
   return true;
@@ -1934,6 +2151,9 @@
 void RSReflectionJava::genPackVarOfType(const RSExportType *ET,
                                         const char *VarName,
                                         const char *FieldPackerName) {
+  if (mCollecting)
+    return;
+
   switch (ET->getClass()) {
   case RSExportType::ExportClassPrimitive:
   case RSExportType::ExportClassVector: {
@@ -1993,13 +2213,33 @@
     break;
   }
   case RSExportType::ExportClassRecord: {
+    // Keep struct/field layout in sync with ReflectionState::declareRecord()
+
     const RSExportRecordType *ERT = static_cast<const RSExportRecordType *>(ET);
+    const ReflectionState::Record32 Record32 = mState->getRecord32(ERT);
+
+    auto emitSkip = [this, &FieldPackerName](size_t At, size_t Need,
+                                             ReflectionState::Val32 Padding32) {
+      if ((Need > At) || (Padding32.first && (Padding32.second != 0))) {
+        size_t Padding = Need - At;
+        mOut.indent() << FieldPackerName << ".skip(";
+        if (!Padding32.first || (Padding == Padding32.second))
+          mOut << Padding;
+        else {
+          genCheck64Bit(true);
+          mOut << " ? " << Padding << " : " << Padding32.second;
+        }
+        mOut << ");\n";
+      }
+    };
+
     // Relative pos from now on in field packer
     unsigned Pos = 0;
 
+    unsigned FieldNum = 0;
     for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(),
                                                   E = ERT->fields_end();
-         I != E; I++) {
+         I != E; I++, FieldNum++) {
       const RSExportRecordType::Field *F = *I;
       std::string FieldName;
       size_t FieldOffset = F->getOffsetInParent();
@@ -2007,32 +2247,25 @@
       size_t FieldStoreSize = T->getStoreSize();
       size_t FieldAllocSize = T->getAllocSize();
 
+      const auto Field32PreAndPostPadding = Record32.getFieldPreAndPostPadding(FieldNum);
+
       if (VarName != nullptr)
         FieldName = VarName + ("." + F->getName());
       else
         FieldName = F->getName();
 
-      if (FieldOffset > Pos) {
-        mOut.indent() << FieldPackerName << ".skip(" << (FieldOffset - Pos)
-                      << ");\n";
-      }
+      emitSkip(Pos, FieldOffset, Field32PreAndPostPadding.first /* pre */);
 
       genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName);
 
-      // There is padding in the field type
-      if (FieldAllocSize > FieldStoreSize) {
-        mOut.indent() << FieldPackerName << ".skip("
-                      << (FieldAllocSize - FieldStoreSize) << ");\n";
-      }
+      // There is padding in the field type?
+      emitSkip(FieldStoreSize, FieldAllocSize, Field32PreAndPostPadding.second /* post */);
 
       Pos = FieldOffset + FieldAllocSize;
     }
 
     // There maybe some padding after the struct
-    if (ERT->getAllocSize() > Pos) {
-      mOut.indent() << FieldPackerName << ".skip(" << ERT->getAllocSize() - Pos
-                    << ");\n";
-    }
+    emitSkip(Pos, ERT->getAllocSize(), Record32.getRecordPostPadding());
     break;
   }
   default: { slangAssert(false && "Unknown class of type"); }
@@ -2109,6 +2342,10 @@
 /********************** Methods to generate type class  **********************/
 bool RSReflectionJava::genTypeClass(const RSExportRecordType *ERT,
                                     std::string &ErrorMsg) {
+  mState->declareRecord(ERT);
+  if (mCollecting)
+    return true;
+
   std::string ClassName = ERT->getElementName();
   std::string superClassName = getRSPackageName();
   superClassName += RS_TYPE_CLASS_SUPER_CLASS_NAME;
@@ -2119,6 +2356,8 @@
 
   mGeneratedFileNames->push_back(ClassName);
 
+  mState->beginOutputClass();
+
   genTypeItemClass(ERT);
 
   // Declare item buffer and item buffer packer
@@ -2143,6 +2382,9 @@
     genTypeClassResize();
   }
 
+  if (mState->endOutputClass())
+    genCompute64Bit();
+
   endClass();
 
   resetFieldIndex();
@@ -2200,7 +2442,7 @@
   //            << ".get();\n";
   // mOut.indent() << "if (e != null) return e;\n";
   RSReflectionJavaElementBuilder builder("eb", ERT, RenderScriptVar, &mOut,
-                                         mRSContext, this);
+                                         mRSContext, this, mState);
   builder.generate();
 
   mOut.indent() << "return eb.create();\n";
@@ -2359,13 +2601,18 @@
 
 void
 RSReflectionJava::genTypeClassComponentSetter(const RSExportRecordType *ERT) {
+  const ReflectionState::Record32 Record32 = mState->getRecord32(ERT);
+
+  unsigned FieldNum = 0;
   for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
                                                 FE = ERT->fields_end();
-       FI != FE; FI++) {
+       FI != FE; FI++, FieldNum++) {
     const RSExportRecordType::Field *F = *FI;
     size_t FieldOffset = F->getOffsetInParent();
     size_t FieldStoreSize = F->getType()->getStoreSize();
-    unsigned FieldIndex = getFieldIndex(F);
+    std::pair<unsigned, unsigned> FieldIndex = getFieldIndex(F);
+
+    const auto Field32OffsetAndStoreSize = Record32.getFieldOffsetAndStoreSize(FieldNum);
 
     startFunction(AM_PublicSynchronized, false, "void", "set_" + F->getName(),
                   3, "int", "index", GetTypeName(F->getType()).c_str(), "v",
@@ -2378,21 +2625,22 @@
     mOut.indent() << "if (copyNow) ";
     mOut.startBlock();
 
-    if (FieldOffset > 0) {
-      mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << ".reset(index * "
-                    << mItemSizeof << " + " << FieldOffset
-                    << ");\n";
-    } else {
-      mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << ".reset(index * "
-                    << mItemSizeof << ");\n";
-    }
+    mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << ".reset(index * "
+                  << mItemSizeof;
+    genConditionalVal(" + ", true, FieldOffset, Field32OffsetAndStoreSize.first /* offset */);
+    mOut << ");\n";
+
     genPackVarOfType(F->getType(), "v", RS_TYPE_ITEM_BUFFER_PACKER_NAME);
 
-    mOut.indent() << "FieldPacker fp = new FieldPacker(" << FieldStoreSize
-                  << ");\n";
+    mOut.indent() << "FieldPacker fp = new FieldPacker(";
+    genConditionalVal("", false, FieldStoreSize, Field32OffsetAndStoreSize.second /* size */);
+    mOut << ");\n";
+
     genPackVarOfType(F->getType(), "v", "fp");
-    mOut.indent() << "mAllocation.setFromFieldPacker(index, " << FieldIndex
-                  << ", fp);\n";
+    mOut.indent() << "mAllocation.setFromFieldPacker(index, ";
+    genConditionalVal("", false, FieldIndex.first,
+                      ReflectionState::Val32(Field32OffsetAndStoreSize.first.first, FieldIndex.second));
+    mOut << ", fp);\n";
 
     // End of if (copyNow)
     mOut.endBlock();
@@ -2460,10 +2708,10 @@
 RSReflectionJavaElementBuilder::RSReflectionJavaElementBuilder(
     const char *ElementBuilderName, const RSExportRecordType *ERT,
     const char *RenderScriptVar, GeneratedFile *Out, const RSContext *RSContext,
-    RSReflectionJava *Reflection)
+    RSReflectionJava *Reflection, ReflectionState *RState)
     : mElementBuilderName(ElementBuilderName), mERT(ERT),
       mRenderScriptVar(RenderScriptVar), mOut(Out), mPaddingFieldIndex(1),
-      mRSContext(RSContext), mReflection(Reflection) {
+      mRSContext(RSContext), mReflection(Reflection), mState(RState) {
   if (mRSContext->getTargetAPI() < SLANG_ICS_TARGET_API) {
     mPaddingPrefix = "#padding_";
   } else {
@@ -2543,18 +2791,26 @@
       //
       // TODO(zonr): Generalize these two function such that there's no
       //             duplicated codes.
+
+      // Keep struct/field layout in sync with ReflectionState::declareRecord()
+
       const RSExportRecordType *ERT =
           static_cast<const RSExportRecordType *>(ET);
+      const ReflectionState::Record32 Record32 = mState->getRecord32(ERT);
+
       int Pos = 0; // relative pos from now on
 
+      unsigned FieldNum = 0;
       for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(),
                                                     E = ERT->fields_end();
-           I != E; I++) {
+           I != E; I++, FieldNum++) {
         const RSExportRecordType::Field *F = *I;
-        int FieldOffset = F->getOffsetInParent();
+        size_t FieldOffset = F->getOffsetInParent();
         const RSExportType *T = F->getType();
-        int FieldStoreSize = T->getStoreSize();
-        int FieldAllocSize = T->getAllocSize();
+        size_t FieldStoreSize = T->getStoreSize();
+        size_t FieldAllocSize = T->getAllocSize();
+
+        const auto Field32PreAndPostPadding = Record32.getFieldPreAndPostPadding(FieldNum);
 
         std::string FieldName;
         if (!VarName.empty())
@@ -2563,7 +2819,7 @@
           FieldName = F->getName();
 
         // Alignment
-        genAddPadding(FieldOffset - Pos);
+        genAddPadding(FieldOffset - Pos, Field32PreAndPostPadding.first /* pre */);
 
         // eb.add(...)
         mReflection->addFieldIndexMapping(F);
@@ -2578,7 +2834,7 @@
         if (mRSContext->getTargetAPI() < SLANG_ICS_TARGET_API) {
           // There is padding within the field type. This is only necessary
           // for HC-targeted APIs.
-          genAddPadding(FieldAllocSize - FieldStoreSize);
+          genAddPadding(FieldAllocSize - FieldStoreSize, Field32PreAndPostPadding.second /* post */);
         }
 
         Pos = FieldOffset + FieldAllocSize;
@@ -2586,8 +2842,7 @@
 
       // There maybe some padding after the struct
       size_t RecordAllocSize = ERT->getAllocSize();
-
-      genAddPadding(RecordAllocSize - Pos);
+      genAddPadding(RecordAllocSize - Pos, Record32.getRecordPostPadding());
       break;
     }
     default:
@@ -2597,7 +2852,7 @@
   }
 }
 
-void RSReflectionJavaElementBuilder::genAddPadding(int PaddingSize) {
+void RSReflectionJavaElementBuilder::genAddPadding(int PaddingSize, unsigned Which) {
   while (PaddingSize > 0) {
     const std::string &VarName = createPaddingField();
     genAddStatementStart();
@@ -2611,17 +2866,60 @@
       *mOut << "Element.U8(" << mRenderScriptVar << ")";
       PaddingSize -= 1;
     }
-    genAddStatementEnd(VarName, 0);
+    genAddStatementEnd(VarName, 0, Which);
   }
 }
 
+void RSReflectionJavaElementBuilder::genAddPadding(int PaddingSize,
+                                                   ReflectionState::Val32 Field32PaddingSize) {
+  if (!Field32PaddingSize.first || (PaddingSize == Field32PaddingSize.second)) {
+    // Either we're ignoring the 32-bit case, or 32-bit and 64-bit
+    // padding are the same.
+    genAddPadding(PaddingSize, RSReflectionJava::FieldIndex | RSReflectionJava::Field32Index);
+    return;
+  }
+
+  // We cannot ignore the 32-bit case, and 32-bit and 64-bit padding differ.
+
+  if ((PaddingSize == 0) != (Field32PaddingSize.second == 0)) {
+    // Only pad one of the two cases.
+
+    mOut->indent() << "if (";
+    if (PaddingSize == 0)
+      *mOut << '!';
+    genCheck64Bit(PaddingSize == 0);
+    *mOut << ')';
+
+    mOut->startBlock();
+    if (PaddingSize != 0)
+      genAddPadding(PaddingSize, RSReflectionJava::FieldIndex);
+    else
+      genAddPadding(Field32PaddingSize.second, RSReflectionJava::Field32Index);
+    mOut->endBlock();
+    return;
+  }
+
+  // Pad both of the two cases, differently.
+  mOut->indent() << "if (";
+  genCheck64Bit(false);
+  *mOut << ')';
+  mOut->startBlock();
+  genAddPadding(PaddingSize, RSReflectionJava::FieldIndex);
+  mOut->endBlock();
+  mOut->indent() << "else";
+  mOut->startBlock();
+  genAddPadding(Field32PaddingSize.second, RSReflectionJava::Field32Index);
+  mOut->endBlock();
+}
+
 void RSReflectionJavaElementBuilder::genAddStatementStart() {
   mOut->indent() << mElementBuilderName << ".add(";
 }
 
 void
 RSReflectionJavaElementBuilder::genAddStatementEnd(const std::string &VarName,
-                                                   unsigned ArraySize) {
+                                                   unsigned ArraySize,
+                                                   unsigned Which) {
   *mOut << ", \"" << VarName << "\"";
   if (ArraySize > 0) {
     *mOut << ", " << ArraySize;
@@ -2630,12 +2928,16 @@
   // TODO Review incFieldIndex.  It's probably better to assign the numbers at
   // the start rather
   // than as we're generating the code.
-  mReflection->incFieldIndex();
+  mReflection->incFieldIndex(Which);
 }
 
 /******** Methods to create Element in Java of given record type /end ********/
 
 bool RSReflectionJava::reflect() {
+  // Note that we may issue declareRecord() in many places during the
+  // reflection process.
+  mState->beginRecords();
+
   std::string ErrorMsg;
   if (!genScriptClass(mScriptClassName, ErrorMsg)) {
     std::cerr << "Failed to generate class " << mScriptClassName << " ("
@@ -2643,8 +2945,6 @@
     return false;
   }
 
-  mGeneratedFileNames->push_back(mScriptClassName);
-
   // class ScriptField_<TypeName>
   for (RSContext::const_export_type_iterator
            TI = mRSContext->export_types_begin(),
@@ -2664,6 +2964,8 @@
     }
   }
 
+  mState->endRecords();
+
   return true;
 }
 
@@ -2706,6 +3008,17 @@
   mOut << "\n";
 
   // Imports
+  //
+  // The first few imports are only needed for divergent classes, but
+  // at this point we don't know whether we are emitting a divergent
+  // class.
+  //
+  if (!mRSContext->isCompatLib()) {
+    mOut << "import android.os.Build;\n";
+    mOut << "import android.os.Process;\n";
+    mOut << "import java.lang.reflect.Field;\n";
+  }
+  // (End of imports needed for divergent classes.)
   mOut << "import " << mRSPackageName << ".*;\n";
   if (getEmbedBitcodeInJava()) {
     mOut << "import " << mPackageName << "."
diff --git a/slang_rs_reflection.h b/slang_rs_reflection.h
index b5859fd..4d2f795 100644
--- a/slang_rs_reflection.h
+++ b/slang_rs_reflection.h
@@ -29,6 +29,7 @@
 #include "slang_assert.h"
 #include "slang_rs_export_type.h"
 #include "slang_rs_reflect_utils.h"
+#include "slang_rs_reflection_state.h"
 
 namespace slang {
 
@@ -41,6 +42,13 @@
 private:
   const RSContext *mRSContext;
 
+  ReflectionState *mState;
+
+  // If we're in the "collecting" state (according to mState), we
+  // don't actually generate code, but we do want to keep track of
+  // some information about what we WOULD generate.
+  const bool mCollecting;
+
   // The name of the Java package name we're creating this file for,
   // e.g. com.example.android.rs.flashlight
   std::string mPackageName;
@@ -69,7 +77,6 @@
   // e.g. ScriptC_flashlight
   std::string mScriptClassName;
 
-
   // This is set by startClass() and will change for the multiple classes generated.
   std::string mClassName;
 
@@ -90,10 +97,16 @@
 
   // A mapping from a field in a record type to its index in the rsType
   // instance. Only used when generates TypeClass (ScriptField_*).
-  typedef std::map<const RSExportRecordType::Field *, unsigned> FieldIndexMapTy;
+  //
+  // .first = field index
+  // .second = when compiling for both 32-bit and 64-bit (RSCCOptions::mEmit3264),
+  //           and we are reflecting 64-bit code, this is field index for 32-bit;
+  //           otherwise, it is undefined
+  typedef std::map<const RSExportRecordType::Field *, std::pair<unsigned,unsigned> > FieldIndexMapTy;
   FieldIndexMapTy mFieldIndexMap;
   // Field index of current processing TypeClass.
-  unsigned mFieldIndex;
+  unsigned mFieldIndex;    // corresponds to FieldIndexMapTy::mapped_type.first
+  unsigned mField32Index;  // corresponds to FieldIndexMapTy::mapped_type.second
 
   inline void setError(const std::string &Error) { mLastError = Error; }
 
@@ -152,17 +165,22 @@
   void startTypeClass(const std::string &ClassName);
   void endTypeClass();
 
-  inline void incFieldIndex() { mFieldIndex++; }
+  enum { FieldIndex = 0x1, Field32Index = 0x2 };  // bitmask
+  inline void incFieldIndex(unsigned Which) {
+    slangAssert(!(Which & ~(FieldIndex | Field32Index)));
+    if (Which & FieldIndex  ) mFieldIndex++;
+    if (Which & Field32Index) mField32Index++;
+  }
 
-  inline void resetFieldIndex() { mFieldIndex = 0; }
+  inline void resetFieldIndex() { mFieldIndex = mField32Index = 0; }
 
   inline void addFieldIndexMapping(const RSExportRecordType::Field *F) {
     slangAssert((mFieldIndexMap.find(F) == mFieldIndexMap.end()) &&
                 "Nested structure never occurs in C language.");
-    mFieldIndexMap.insert(std::make_pair(F, mFieldIndex));
+    mFieldIndexMap.insert(std::make_pair(F, std::make_pair(mFieldIndex, mField32Index)));
   }
 
-  inline unsigned getFieldIndex(const RSExportRecordType::Field *F) const {
+  inline std::pair<unsigned, unsigned> getFieldIndex(const RSExportRecordType::Field *F) const {
     FieldIndexMapTy::const_iterator I = mFieldIndexMap.find(F);
     slangAssert((I != mFieldIndexMap.end()) &&
                 "Requesting field is out of scope.");
@@ -174,7 +192,15 @@
   enum {
     TypeNameWithConstantArrayBrackets = 0x01,
     TypeNameWithRecordElementName     = 0x02,
-    TypeNameC                         = 0x04, // else Java
+
+    // Three major flavors of types:
+    // - Java
+    // - C
+    // - PseudoC -- Identical to C for all types supported by C;
+    //              for other types, uses a simplified C-like syntax
+    TypeNameC                         = 0x04,
+    TypeNamePseudoC                   = 0x08,
+
     TypeNameDefault                   = TypeNameWithConstantArrayBrackets|TypeNameWithRecordElementName
   };
   static std::string GetTypeName(const RSExportType *ET, unsigned Style = TypeNameDefault);
@@ -197,11 +223,12 @@
   void genPointerTypeExportVariable(const RSExportVar *EV);
   void genVectorTypeExportVariable(const RSExportVar *EV);
   void genMatrixTypeExportVariable(const RSExportVar *EV);
-  void genConstantArrayTypeExportVariable(const RSExportVar *EV);
-  void genRecordTypeExportVariable(const RSExportVar *EV);
+  void genConstantArrayTypeExportVariable(const RSExportVar *EV, ReflectionState::Val32 AllocSize32);
+  void genRecordTypeExportVariable(const RSExportVar *EV, ReflectionState::Val32 AllocSize32);
   void genPrivateExportVariable(const std::string &TypeName,
                                 const std::string &VarName);
-  void genSetExportVariable(const std::string &TypeName, const RSExportVar *EV, unsigned Dimension);
+  void genSetExportVariable(const std::string &TypeName, const RSExportVar *EV, unsigned Dimension,
+                            ReflectionState::Val32 AllocSize32 = ReflectionState::NoVal32());
   void genGetExportVariable(const std::string &TypeName,
                             const std::string &VarName);
   void genGetFieldID(const std::string &VarName);
@@ -235,6 +262,14 @@
   void genTypeClassCopyAll(const RSExportRecordType *ERT);
   void genTypeClassResize();
 
+  // emits an expression that evaluates to true on a 64-bit target and
+  // false on a 32-bit target
+  void genCheck64Bit(bool Parens);
+
+  // emits a fragment of the class definition needed to set up for
+  // genCheck64Bit()
+  void genCompute64Bit();
+
   void genBuildElement(const char *ElementBuilderName,
                        const RSExportRecordType *ERT,
                        const char *RenderScriptVar, bool IsInline);
@@ -244,7 +279,8 @@
                                      const char *RenderScriptVar,
                                      unsigned ArraySize);
 
-  bool genCreateFieldPacker(const RSExportType *T, const char *FieldPackerName);
+  bool genCreateFieldPacker(const RSExportType *T, const char *FieldPackerName,
+                            ReflectionState::Val32 AllocSize32);
   void genPackVarOfType(const RSExportType *T, const char *VarName,
                         const char *FieldPackerName);
   void genAllocateVarOfType(const RSExportType *T, const std::string &VarName);
@@ -255,13 +291,26 @@
   void genVectorLengthCompatibilityCheck(const std::string &ArrayName, unsigned VecSize);
   void genNullArrayCheck(const std::string &ArrayName);
 
+  // NOTE
+  //
+  // If there's a nonempty Prefix, then:
+  // - If there's a nonzero value to emit, then emit the prefix followed by the value.
+  // - Otherwise, emit nothing.
+  //
+  // If there's an empty Prefix, then
+  // - Always emit a value, even if zero.
+  //
+  void genConditionalVal(const std::string &Prefix, bool Parens,
+                         size_t Val, ReflectionState::Val32 Val32);
+
 public:
   RSReflectionJava(const RSContext *Context,
                    std::vector<std::string> *GeneratedFileNames,
                    const std::string &OutputBaseDirectory,
                    const std::string &RSSourceFilename,
                    const std::string &BitCodeFileName,
-                   bool EmbedBitcodeInJava);
+                   bool EmbedBitcodeInJava,
+                   ReflectionState *RState);
 
   bool reflect();
 
diff --git a/slang_rs_reflection_state.cpp b/slang_rs_reflection_state.cpp
new file mode 100644
index 0000000..0d233b1
--- /dev/null
+++ b/slang_rs_reflection_state.cpp
@@ -0,0 +1,1123 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <string>
+
+#include "clang/AST/APValue.h"
+
+#include "slang_assert.h"
+#include "slang_rs_export_foreach.h"
+#include "slang_rs_export_func.h"
+#include "slang_rs_export_reduce.h"
+#include "slang_rs_export_type.h"
+#include "slang_rs_export_var.h"
+#include "slang_rs_reflection.h"
+#include "slang_rs_reflection_state.h"
+
+#include "bcinfo/MetadataExtractor.h"
+
+namespace slang {
+
+static bool equal(const clang::APValue &a, const clang::APValue &b) {
+  if (a.getKind() != b.getKind())
+    return false;
+  switch (a.getKind()) {
+    case clang::APValue::Float:
+      return a.getFloat().bitwiseIsEqual(b.getFloat());
+    case clang::APValue::Int:
+      return a.getInt() == b.getInt();
+    case clang::APValue::Vector: {
+      unsigned NumElements = a.getVectorLength();
+      if (NumElements != b.getVectorLength())
+        return false;
+      for (unsigned i = 0; i < NumElements; ++i) {
+        if (!equal(a.getVectorElt(i), b.getVectorElt(i)))
+          return false;
+      }
+      return true;
+    }
+    default:
+      slangAssert(false && "unexpected APValue kind");
+      return false;
+  }
+}
+
+ReflectionState::~ReflectionState() {
+  slangAssert(mState==S_Initial || mState==S_ClosedJava64 || mState==S_Bad);
+  delete mStringSet;
+}
+
+void ReflectionState::openJava32(size_t NumFiles) {
+  if (kDisabled)
+    return;
+  slangAssert(mState==S_Initial);
+  mState = S_OpenJava32;
+  mStringSet = new llvm::StringSet<>;
+  mFiles.BeginCollecting(NumFiles);
+}
+
+void ReflectionState::closeJava32() {
+  if (kDisabled)
+    return;
+  slangAssert(mState==S_OpenJava32 && (mForEachOpen < 0) && !mOutputClassOpen && (mRecordsState != RS_Open));
+  mState = S_ClosedJava32;
+  mRSC = nullptr;
+}
+
+void ReflectionState::openJava64() {
+  if (kDisabled)
+    return;
+  slangAssert(mState==S_ClosedJava32);
+  mState = S_OpenJava64;
+  mFiles.BeginUsing();
+}
+
+void ReflectionState::closeJava64() {
+  if (kDisabled)
+    return;
+  slangAssert(mState==S_OpenJava64 && (mForEachOpen < 0) && !mOutputClassOpen && (mRecordsState != RS_Open));
+  mState = S_ClosedJava64;
+  mRSC = nullptr;
+}
+
+llvm::StringRef ReflectionState::canon(const std::string &String) {
+  slangAssert(isCollecting());
+  return mStringSet->insert(String).first->getKey();
+}
+
+std::string ReflectionState::getUniqueTypeName(const RSExportType *T) {
+  return RSReflectionJava::GetTypeName(T, RSReflectionJava::TypeNamePseudoC);
+}
+
+void ReflectionState::nextFile(const RSContext *RSC,
+                               const std::string &PackageName,
+                               const std::string &RSSourceFileName) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  mRSC = RSC;
+
+  slangAssert(mRecordsState != RS_Open);
+  mRecordsState = RS_Initial;
+
+  if (isCollecting()) {
+    File &file = mFiles.CollectNext();
+    file.mPackageName = PackageName;
+    file.mRSSourceFileName = RSSourceFileName;
+  }
+  if (isUsing()) {
+    File &file = mFiles.UseNext();
+    slangAssert(file.mRSSourceFileName == RSSourceFileName);
+    if (file.mPackageName != PackageName)
+      mRSC->ReportError("in file '%0' Java package name is '%1' for 32-bit targets "
+                        "but '%2' for 64-bit targets")
+          << RSSourceFileName << file.mPackageName << PackageName;
+  }
+}
+
+void ReflectionState::dump() {
+  const size_t NumFiles = mFiles.Size();
+  for (int i = 0; i < NumFiles; ++i) {
+    const File &file = mFiles[i];
+    std::cout << "file = \"" << file.mRSSourceFileName << "\", "
+              << "package = \"" << file.mPackageName << "\"" << std::endl;
+
+    // NOTE: "StringMap iteration order, however, is not guaranteed to
+    // be deterministic".  So sort before dumping.
+    typedef const llvm::StringMap<File::Record>::MapEntryTy *RecordsEntryTy;
+    std::vector<RecordsEntryTy> Records;
+    Records.reserve(file.mRecords.size());
+    for (auto I = file.mRecords.begin(), E = file.mRecords.end(); I != E; I++)
+      Records.push_back(&(*I));
+    std::sort(Records.begin(), Records.end(),
+              [](RecordsEntryTy a, RecordsEntryTy b) { return a->getKey().compare(b->getKey())==-1; });
+    for (auto Record : Records) {
+      const auto &Val = Record->getValue();
+      std::cout << "  (Record) name=\"" << Record->getKey().str() << "\""
+                << " allocSize=" << Val.mAllocSize
+                << " postPadding=" << Val.mPostPadding
+                << " ordinary=" << Val.mOrdinary
+                << " matchedByName=" << Val.mMatchedByName
+                << std::endl;
+      const size_t NumFields = Val.mFieldCount;
+      for (int fieldIdx = 0; fieldIdx < NumFields; ++fieldIdx) {
+        const auto &field = Val.mFields[fieldIdx];
+        std::cout << "    (Field) name=\"" << field.mName << "\" ("
+                  << field.mPrePadding << ", \"" << field.mType.str()
+                  << "\"(" << field.mStoreSize << ")@" << field.mOffset
+                  << ", " << field.mPostPadding << ")" << std::endl;
+      }
+    }
+
+    const size_t NumVars = file.mVariables.Size();
+    for (int varIdx = 0; varIdx < NumVars; ++varIdx) {
+      const auto &var = file.mVariables[varIdx];
+      std::cout << "  (Var) name=\"" << var.mName << "\" type=\"" << var.mType.str()
+                << "\" const=" << var.mIsConst << " initialized=" << (var.mInitializerCount != 0)
+                << " allocSize=" << var.mAllocSize << std::endl;
+    }
+
+    for (int feIdx = 0; feIdx < file.mForEachCount; ++feIdx) {
+      const auto &fe = file.mForEaches[feIdx];
+      std::cout << "  (ForEach) ordinal=" << feIdx << " state=";
+      switch (fe.mState) {
+        case File::ForEach::S_Initial:
+          std::cout << "initial" << std::endl;
+          continue;
+        case File::ForEach::S_Collected:
+          std::cout << "collected";
+          break;
+        case File::ForEach::S_UseMatched:
+          std::cout << "usematched";
+          break;
+        default:
+          std::cout << fe.mState;
+          break;
+      }
+      std::cout << " name=\"" << fe.mName << "\" kernel=" << fe.mIsKernel
+                << " hasOut=" << fe.mHasOut << " out=\"" << fe.mOut.str()
+                << "\" metadata=0x" << std::hex << fe.mSignatureMetadata << std::dec
+                << std::endl;
+      const size_t NumIns = fe.mIns.Size();
+      for (int insIdx = 0; insIdx < NumIns; ++insIdx)
+        std::cout << "    (In) " << fe.mIns[insIdx].str() << std::endl;
+      const size_t NumParams = fe.mParams.Size();
+      for (int paramsIdx = 0; paramsIdx < NumParams; ++paramsIdx)
+        std::cout << "    (Param) " << fe.mParams[paramsIdx].str() << std::endl;
+    }
+
+    for (auto feBad : mForEachesBad) {
+      std::cout << "  (ForEachBad) ordinal=" << feBad->getOrdinal()
+                << " name=\"" << feBad->getName() << "\""
+                << std::endl;
+    }
+
+    const size_t NumInvokables = file.mInvokables.Size();
+    for (int invIdx = 0; invIdx < NumInvokables; ++invIdx) {
+      const auto &inv = file.mInvokables[invIdx];
+      std::cout << "  (Invokable) name=\"" << inv.mName << "\"" << std::endl;
+      const size_t NumParams = inv.mParamCount;
+      for (int paramsIdx = 0; paramsIdx < NumParams; ++paramsIdx)
+        std::cout << "    (Param) " << inv.mParams[paramsIdx].str() << std::endl;
+    }
+
+    const size_t NumReduces = file.mReduces.Size();
+    for (int redIdx = 0; redIdx < NumReduces; ++redIdx) {
+      const auto &red = file.mReduces[redIdx];
+      std::cout << "  (Reduce) name=\"" << red.mName
+                << "\" result=\"" << red.mResult.str()
+                << "\" exportable=" << red.mIsExportable
+                << std::endl;
+      const size_t NumIns = red.mAccumInCount;
+      for (int insIdx = 0; insIdx < NumIns; ++insIdx)
+        std::cout << "    (In) " << red.mAccumIns[insIdx].str() << std::endl;
+    }
+  }
+}
+
+// ForEach /////////////////////////////////////////////////////////////////////////////////////
+
+void ReflectionState::beginForEaches(size_t Count) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  if (isCollecting()) {
+    auto &file = mFiles.Current();
+    file.mForEaches = new File::ForEach[Count];
+    file.mForEachCount = Count;
+  }
+  if (isUsing()) {
+    slangAssert(mForEachesBad.empty());
+    mNumForEachesMatchedByOrdinal = 0;
+  }
+}
+
+// Keep this in sync with RSReflectionJava::genExportForEach().
+void ReflectionState::beginForEach(const RSExportForEach *EF) {
+  slangAssert(!isClosed() && (mForEachOpen < 0));
+  if (!isActive())
+    return;
+
+  const bool IsKernel = EF->isKernelStyle();
+  const std::string Name = EF->getName();
+  const unsigned Ordinal = EF->getOrdinal();
+  const size_t InCount = EF->getInTypes().size();
+  const size_t ParamCount = EF->params_count();
+
+  const RSExportType *OET = EF->getOutType();
+  if (OET && !IsKernel) {
+    slangAssert(OET->getClass() == RSExportType::ExportClassPointer);
+    OET = static_cast<const RSExportPointerType *>(OET)->getPointeeType();
+  }
+  const std::string OutType = (OET ? getUniqueTypeName(OET) : "");
+  const bool HasOut = (EF->hasOut() || EF->hasReturn());
+
+  mForEachOpen = Ordinal;
+  mForEachFatal = true;  // we'll set this to false if everything looks ok
+
+  auto &file = mFiles.Current();
+  auto &foreaches = file.mForEaches;
+  if (isCollecting()) {
+    slangAssert(Ordinal < file.mForEachCount);
+    auto &foreach = foreaches[Ordinal];
+    slangAssert(foreach.mState == File::ForEach::S_Initial);
+    foreach.mState = File::ForEach::S_Collected;
+    foreach.mName = Name;
+    foreach.mIns.BeginCollecting(InCount);
+    foreach.mParams.BeginCollecting(ParamCount);
+    foreach.mOut = canon(OutType);
+    foreach.mHasOut = HasOut;
+    foreach.mSignatureMetadata = 0;
+    foreach.mIsKernel = IsKernel;
+  }
+  if (isUsing()) {
+    if (Ordinal >= file.mForEachCount) {
+      mForEachesBad.push_back(EF);
+      return;
+    }
+
+    auto &foreach = foreaches[Ordinal];
+    slangAssert(foreach.mState == File::ForEach::S_Collected);
+    foreach.mState = File::ForEach::S_UseMatched;
+    ++mNumForEachesMatchedByOrdinal;
+
+    if (foreach.mName != Name) {
+      // Order matters because it determines slot number
+      mForEachesBad.push_back(EF);
+      return;
+    }
+
+    // At this point, we have matching ordinal and matching name.
+
+    if (foreach.mIsKernel != IsKernel) {
+      mRSC->ReportError(EF->getLocation(),
+                        "foreach kernel '%0' has __attribute__((kernel)) for %select{32|64}1-bit targets "
+                        "but not for %select{64|32}1-bit targets")
+          << Name << IsKernel;
+      return;
+    }
+
+    if ((foreach.mHasOut != HasOut) || !foreach.mOut.equals(OutType)) {
+      // There are several different patterns we need to handle:
+      // (1) Two different non-void* output types
+      // (2) One non-void* output type, one void* output type
+      // (3) One non-void* output type, one no-output
+      // (4) One void* output type, one no-output
+      if (foreach.mHasOut && HasOut) {
+        if (foreach.mOut.size() && OutType.size()) {
+          // (1) Two different non-void* output types
+          mRSC->ReportError(EF->getLocation(),
+                            "foreach kernel '%0' has output type '%1' for 32-bit targets "
+                            "but output type '%2' for 64-bit targets")
+              << Name << foreach.mOut.str() << OutType;
+        } else {
+          // (2) One non-void* return type, one void* output type
+          const bool hasTyped64 = OutType.size();
+          mRSC->ReportError(EF->getLocation(),
+                            "foreach kernel '%0' has output type '%1' for %select{32|64}2-bit targets "
+                            "but has untyped output for %select{64|32}2-bit targets")
+              << Name << (foreach.mOut.str() + OutType) << hasTyped64;
+        }
+      } else {
+        const std::string CombinedOutType = (foreach.mOut.str() + OutType);
+        if (CombinedOutType.size()) {
+          // (3) One non-void* output type, one no-output
+          mRSC->ReportError(EF->getLocation(),
+                            "foreach kernel '%0' has output type '%1' for %select{32|64}2-bit targets "
+                            "but no output for %select{64|32}2-bit targets")
+              << Name << CombinedOutType << HasOut;
+        } else {
+          // (4) One void* output type, one no-output
+          mRSC->ReportError(EF->getLocation(),
+                            "foreach kernel '%0' has untyped output for %select{32|64}1-bit targets "
+                            "but no output for %select{64|32}1-bit targets")
+              << Name << HasOut;
+        }
+      }
+    }
+
+    bool BadCount = false;
+    if (foreach.mIns.Size() != InCount) {
+      mRSC->ReportError(EF->getLocation(),
+                        "foreach kernel '%0' has %1 input%s1 for 32-bit targets "
+                        "but %2 input%s2 for 64-bit targets")
+          << Name << unsigned(foreach.mIns.Size()) << unsigned(InCount);
+      BadCount = true;
+    }
+    if (foreach.mParams.Size() != ParamCount) {
+      mRSC->ReportError(EF->getLocation(),
+                        "foreach kernel '%0' has %1 usrData parameter%s1 for 32-bit targets "
+                        "but %2 usrData parameter%s2 for 64-bit targets")
+          << Name << unsigned(foreach.mParams.Size()) << unsigned(ParamCount);
+      BadCount = true;
+    }
+
+    if (BadCount)
+      return;
+
+    foreach.mIns.BeginUsing();
+    foreach.mParams.BeginUsing();
+  }
+
+  mForEachFatal = false;
+}
+
+void ReflectionState::addForEachIn(const RSExportForEach *EF, const RSExportType *Type) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  slangAssert(mForEachOpen == EF->getOrdinal());
+
+  // Type may be nullptr in the case of void*.  See RSExportForEach::Create().
+  if (Type && !EF->isKernelStyle()) {
+    slangAssert(Type->getClass() == RSExportType::ExportClassPointer);
+    Type = static_cast<const RSExportPointerType *>(Type)->getPointeeType();
+  }
+  const std::string TypeName = (Type ? getUniqueTypeName(Type) : std::string());
+
+  auto &ins = mFiles.Current().mForEaches[EF->getOrdinal()].mIns;
+  if (isCollecting()) {
+    ins.CollectNext() = canon(TypeName);
+  }
+  if (isUsing()) {
+    if (mForEachFatal)
+      return;
+
+    if (!ins.UseNext().equals(TypeName)) {
+      if (ins.Current().size() && TypeName.size()) {
+        mRSC->ReportError(EF->getLocation(),
+                          "%ordinal0 input of foreach kernel '%1' "
+                          "has type '%2' for 32-bit targets "
+                          "but type '%3' for 64-bit targets")
+            << unsigned(ins.CurrentIdx() + 1)
+            << EF->getName()
+            << ins.Current().str()
+            << TypeName;
+      } else {
+        const bool hasType64 = TypeName.size();
+        mRSC->ReportError(EF->getLocation(),
+                          "%ordinal0 input of foreach kernel '%1' "
+                          "has type '%2' for %select{32|64}3-bit targets "
+                          "but is untyped for %select{64|32}3-bit targets")
+            << unsigned(ins.CurrentIdx() + 1)
+            << EF->getName()
+            << (ins.Current().str() + TypeName)
+            << hasType64;
+      }
+    }
+  }
+}
+
+void ReflectionState::addForEachParam(const RSExportForEach *EF, const RSExportType *Type) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  slangAssert(mForEachOpen == EF->getOrdinal());
+
+  const std::string TypeName = getUniqueTypeName(Type);
+
+  auto &params = mFiles.Current().mForEaches[EF->getOrdinal()].mParams;
+  if (isCollecting()) {
+    params.CollectNext() = canon(TypeName);
+  }
+  if (isUsing()) {
+    if (mForEachFatal)
+      return;
+
+    if (!params.UseNext().equals(TypeName)) {
+      mRSC->ReportError(EF->getLocation(),
+                        "%ordinal0 usrData parameter of foreach kernel '%1' "
+                        "has type '%2' for 32-bit targets "
+                        "but type '%3' for 64-bit targets")
+          << unsigned(params.CurrentIdx() + 1)
+          << EF->getName()
+          << params.Current().str()
+          << TypeName;
+    }
+  }
+}
+
+void ReflectionState::addForEachSignatureMetadata(const RSExportForEach *EF, unsigned Metadata) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  slangAssert(mForEachOpen == EF->getOrdinal());
+
+  // These are properties in the metadata that we need to check.
+  const unsigned SpecialParameterBits = bcinfo::MD_SIG_X|bcinfo::MD_SIG_Y|bcinfo::MD_SIG_Z|bcinfo::MD_SIG_Ctxt;
+
+  // These are properties in the metadata that we already check in
+  // some other way.
+  const unsigned BoringBits = bcinfo::MD_SIG_In|bcinfo::MD_SIG_Out|bcinfo::MD_SIG_Usr|bcinfo::MD_SIG_Kernel;
+
+  slangAssert((Metadata & ~(SpecialParameterBits | BoringBits)) == 0);
+
+  auto &mSignatureMetadata = mFiles.Current().mForEaches[EF->getOrdinal()].mSignatureMetadata;
+  if (isCollecting()) {
+    mSignatureMetadata = Metadata;
+  }
+  if (isUsing()) {
+    if (mForEachFatal)
+      return;
+
+    if ((mSignatureMetadata & SpecialParameterBits) != (Metadata & SpecialParameterBits)) {
+      mRSC->ReportError(EF->getLocation(),
+                        "foreach kernel '%0' has different special parameters "
+                        "for 32-bit targets than for 64-bit targets")
+          << EF->getName();
+    }
+  }
+}
+
+void ReflectionState::endForEach() {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  slangAssert(mForEachOpen >= 0);
+  if (isUsing() && !mForEachFatal) {
+    slangAssert(mFiles.Current().mForEaches[mForEachOpen].mIns.isFinished());
+    slangAssert(mFiles.Current().mForEaches[mForEachOpen].mParams.isFinished());
+  }
+
+  mForEachOpen = -1;
+}
+
+void ReflectionState::endForEaches() {
+  slangAssert(mForEachOpen < 0);
+  if (!isUsing())
+    return;
+
+  const auto &file = mFiles.Current();
+
+  if (!mForEachesBad.empty()) {
+    std::sort(mForEachesBad.begin(), mForEachesBad.end(),
+         [](const RSExportForEach *a, const RSExportForEach *b) { return a->getOrdinal() < b->getOrdinal(); });
+    // Note that after the sort, all kernels that are bad because of
+    // name mismatch precede all kernels that are bad because of
+    // too-high ordinal.
+
+    // 32-bit and 64-bit compiles need to see foreach kernels in the
+    // same order, because of slot number assignment.  Once we see the
+    // first name mismatch in the sequence of foreach kernels, it
+    // doesn't make sense to issue further diagnostics regarding
+    // foreach kernels except those that still happen to match by name
+    // and ordinal (we already handled those diagnostics between
+    // beginForEach() and endForEach()).
+    bool ForEachesOrderFatal = false;
+
+    for (const RSExportForEach *EF : mForEachesBad) {
+      if (EF->getOrdinal() >= file.mForEachCount) {
+        mRSC->ReportError(EF->getLocation(),
+                          "foreach kernel '%0' is only present for 64-bit targets")
+            << EF->getName();
+      } else {
+        mRSC->ReportError(EF->getLocation(),
+                          "%ordinal0 foreach kernel is '%1' for 32-bit targets "
+                          "but '%2' for 64-bit targets")
+            << (EF->getOrdinal() + 1)
+            << mFiles.Current().mForEaches[EF->getOrdinal()].mName
+            << EF->getName();
+        ForEachesOrderFatal = true;
+        break;
+      }
+    }
+
+    mForEachesBad.clear();
+
+    if (ForEachesOrderFatal)
+      return;
+  }
+
+  if (mNumForEachesMatchedByOrdinal == file.mForEachCount)
+    return;
+  for (unsigned ord = 0; ord < file.mForEachCount; ord++) {
+    const auto &fe = file.mForEaches[ord];
+    if (fe.mState == File::ForEach::S_Collected) {
+      mRSC->ReportError("in file '%0' foreach kernel '%1' is only present for 32-bit targets")
+          << file.mRSSourceFileName << fe.mName;
+    }
+  }
+}
+
+// Invokable ///////////////////////////////////////////////////////////////////////////////////
+
+// Keep this in sync with RSReflectionJava::genExportFunction().
+void ReflectionState::declareInvokable(const RSExportFunc *EF) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  const std::string Name = EF->getName(/*Mangle=*/false);
+  const size_t ParamCount = EF->getNumParameters();
+
+  auto &invokables = mFiles.Current().mInvokables;
+  if (isCollecting()) {
+    auto &invokable = invokables.CollectNext();
+    invokable.mName = Name;
+    invokable.mParamCount = ParamCount;
+    if (EF->hasParam()) {
+      unsigned FieldIdx = 0;
+      invokable.mParams = new llvm::StringRef[ParamCount];
+      for (RSExportFunc::const_param_iterator I = EF->params_begin(),
+                                              E = EF->params_end();
+           I != E; I++, FieldIdx++) {
+        invokable.mParams[FieldIdx] = canon(getUniqueTypeName((*I)->getType()));
+      }
+    }
+  }
+  if (isUsing()) {
+    if (mInvokablesOrderFatal)
+      return;
+
+    if (invokables.isFinished()) {
+      // This doesn't actually break reflection, but that's a
+      // coincidence of the fact that we reflect during the 64-bit
+      // compilation pass rather than the 32-bit compilation pass, and
+      // of the fact that the "extra" invokable(s) are at the end.
+      mRSC->ReportError(EF->getLocation(),
+                        "invokable function '%0' is only present for 64-bit targets")
+          << Name;
+      return;
+    }
+
+    auto &invokable = invokables.UseNext();
+
+    if (invokable.mName != Name) {
+      // Order matters because it determines slot number
+      mRSC->ReportError(EF->getLocation(),
+                        "%ordinal0 invokable function is '%1' for 32-bit targets "
+                        "but '%2' for 64-bit targets")
+          << unsigned(invokables.CurrentIdx() + 1)
+          << invokable.mName
+          << Name;
+      mInvokablesOrderFatal = true;
+      return;
+    }
+
+    if (invokable.mParamCount != ParamCount) {
+      mRSC->ReportError(EF->getLocation(),
+                        "invokable function '%0' has %1 parameter%s1 for 32-bit targets "
+                        "but %2 parameter%s2 for 64-bit targets")
+          << Name << unsigned(invokable.mParamCount) << unsigned(ParamCount);
+      return;
+    }
+    if (EF->hasParam()) {
+      unsigned FieldIdx = 0;
+      for (RSExportFunc::const_param_iterator I = EF->params_begin(),
+                                              E = EF->params_end();
+           I != E; I++, FieldIdx++) {
+        const std::string Type = getUniqueTypeName((*I)->getType());
+        if (!invokable.mParams[FieldIdx].equals(Type)) {
+          mRSC->ReportError(EF->getLocation(),
+                            "%ordinal0 parameter of invokable function '%1' "
+                            "has type '%2' for 32-bit targets "
+                            "but type '%3' for 64-bit targets")
+              << (FieldIdx + 1)
+              << Name
+              << invokable.mParams[FieldIdx].str()
+              << Type;
+        }
+      }
+    }
+  }
+}
+
+void ReflectionState::endInvokables() {
+  if (!isUsing() || mInvokablesOrderFatal)
+    return;
+
+  auto &invokables = mFiles.Current().mInvokables;
+  while (!invokables.isFinished()) {
+    const auto &invokable = invokables.UseNext();
+    mRSC->ReportError("in file '%0' invokable function '%1' is only present for 32-bit targets")
+        << mFiles.Current().mRSSourceFileName << invokable.mName;
+  }
+}
+
+// Record //////////////////////////////////////////////////////////////////////////////////////
+
+void ReflectionState::beginRecords() {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  slangAssert(mRecordsState != RS_Open);
+  mRecordsState = RS_Open;
+  mNumRecordsMatchedByName = 0;
+}
+
+void ReflectionState::endRecords() {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  slangAssert(mRecordsState == RS_Open);
+  mRecordsState = RS_Closed;
+
+  if (isUsing()) {
+    const File &file = mFiles.Current();
+    if (mNumRecordsMatchedByName == file.mRecords.size())
+      return;
+    // NOTE: "StringMap iteration order, however, is not guaranteed to
+    // be deterministic".  So sort by name before reporting.
+    // Alternatively, if we record additional information, we could
+    // sort by source location or by order in which we discovered the
+    // need to export.
+    std::vector<llvm::StringRef> Non64RecordNames;
+    for (auto I = file.mRecords.begin(), E = file.mRecords.end(); I != E; I++)
+      if (!I->getValue().mMatchedByName && I->getValue().mOrdinary)
+        Non64RecordNames.push_back(I->getKey());
+    std::sort(Non64RecordNames.begin(), Non64RecordNames.end(),
+              [](llvm::StringRef a, llvm::StringRef b) { return a.compare(b)==-1; });
+    for (auto N : Non64RecordNames)
+      mRSC->ReportError("in file '%0' structure '%1' is exported only for 32-bit targets")
+          << file.mRSSourceFileName << N.str();
+  }
+}
+
+void ReflectionState::declareRecord(const RSExportRecordType *ERT, bool Ordinary) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  slangAssert(mRecordsState == RS_Open);
+
+  auto &records = mFiles.Current().mRecords;
+  if (isCollecting()) {
+    // Keep struct/field layout in sync with
+    // RSReflectionJava::genPackVarOfType() and
+    // RSReflectionJavaElementBuilder::genAddElement()
+
+    // Save properties of record
+
+    const size_t FieldCount = ERT->fields_size();
+    File::Record::Field *Fields = new File::Record::Field[FieldCount];
+
+    size_t Pos = 0;  // Relative position of field within record
+    unsigned FieldIdx = 0;
+    for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), E = ERT->fields_end();
+         I != E; I++, FieldIdx++) {
+      const RSExportRecordType::Field *FieldExport = *I;
+      size_t FieldOffset = FieldExport->getOffsetInParent();
+      const RSExportType *T = FieldExport->getType();
+      size_t FieldStoreSize = T->getStoreSize();
+      size_t FieldAllocSize = T->getAllocSize();
+
+      slangAssert(FieldOffset >= Pos);
+      slangAssert(FieldAllocSize >= FieldStoreSize);
+
+      auto &FieldState = Fields[FieldIdx];
+      FieldState.mName = FieldExport->getName();
+      FieldState.mType = canon(getUniqueTypeName(T));
+      FieldState.mPrePadding = FieldOffset - Pos;
+      FieldState.mPostPadding = FieldAllocSize - FieldStoreSize;
+      FieldState.mOffset = FieldOffset;
+      FieldState.mStoreSize = FieldStoreSize;
+
+      Pos = FieldOffset + FieldAllocSize;
+    }
+
+    slangAssert(ERT->getAllocSize() >= Pos);
+
+    // Insert record into map
+
+    slangAssert(records.find(ERT->getName()) == records.end());
+    File::Record &record = records[ERT->getName()];
+    record.mFields = Fields;
+    record.mFieldCount = FieldCount;
+    record.mPostPadding = ERT->getAllocSize() - Pos;
+    record.mAllocSize = ERT->getAllocSize();
+    record.mOrdinary = Ordinary;
+    record.mMatchedByName = false;
+  }
+  if (isUsing()) {
+    if (!Ordinary)
+      return;
+
+    const auto RIT = records.find(ERT->getName());
+    if (RIT == records.end()) {
+      // This doesn't actually break reflection, but that's a
+      // coincidence of the fact that we reflect during the 64-bit
+      // compilation pass rather than the 32-bit compilation pass, so
+      // a record that's only classified as exported during the 64-bit
+      // compilation pass doesn't cause any problems.
+      mRSC->ReportError(ERT->getLocation(), "structure '%0' is exported only for 64-bit targets")
+          << ERT->getName();
+      return;
+    }
+    File::Record &record = RIT->getValue();
+    record.mMatchedByName = true;
+    ++mNumRecordsMatchedByName;
+    slangAssert(record.mOrdinary);
+
+    if (ERT->fields_size() != record.mFieldCount) {
+      mRSC->ReportError(ERT->getLocation(),
+                        "exported structure '%0' has %1 field%s1 for 32-bit targets "
+                        "but %2 field%s2 for 64-bit targets")
+          << ERT->getName() << unsigned(record.mFieldCount) << unsigned(ERT->fields_size());
+      return;
+    }
+
+    // Note that we are deliberately NOT comparing layout properties
+    // (such as Field offsets and sizes, or Record allocation size);
+    // we need to tolerate layout differences between 32-bit
+    // compilation and 64-bit compilation.
+
+    unsigned FieldIdx = 0;
+    for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), E = ERT->fields_end();
+         I != E; I++, FieldIdx++) {
+      const RSExportRecordType::Field &FieldExport = **I;
+      const File::Record::Field &FieldState = record.mFields[FieldIdx];
+      if (FieldState.mName != FieldExport.getName()) {
+        mRSC->ReportError(ERT->getLocation(),
+                          "%ordinal0 field of exported structure '%1' "
+                          "is '%2' for 32-bit targets "
+                          "but '%3' for 64-bit targets")
+            << (FieldIdx + 1) << ERT->getName() << FieldState.mName << FieldExport.getName();
+        return;
+      }
+      const std::string FieldExportType = getUniqueTypeName(FieldExport.getType());
+      if (!FieldState.mType.equals(FieldExportType)) {
+        mRSC->ReportError(ERT->getLocation(),
+                          "field '%0' of exported structure '%1' "
+                          "has type '%2' for 32-bit targets "
+                          "but type '%3' for 64-bit targets")
+            << FieldState.mName << ERT->getName() << FieldState.mType.str() << FieldExportType;
+      }
+    }
+  }
+}
+
+ReflectionState::Record32
+ReflectionState::getRecord32(const RSExportRecordType *ERT) {
+  if (isUsing()) {
+    const auto &Records = mFiles.Current().mRecords;
+    const auto RIT = Records.find(ERT->getName());
+    if (RIT != Records.end())
+      return Record32(&RIT->getValue());
+  }
+  return Record32();
+}
+
+// Reduce //////////////////////////////////////////////////////////////////////////////////////
+
+void ReflectionState::declareReduce(const RSExportReduce *ER, bool IsExportable) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return;
+
+  auto &reduces = mFiles.Current().mReduces;
+  if (isCollecting()) {
+    auto &reduce = reduces.CollectNext();
+    reduce.mName = ER->getNameReduce();
+
+    const auto &InTypes = ER->getAccumulatorInTypes();
+    const size_t InTypesSize = InTypes.size();
+    reduce.mAccumInCount = InTypesSize;
+    reduce.mAccumIns = new llvm::StringRef[InTypesSize];
+    unsigned InTypesIdx = 0;
+    for (const auto &InType : InTypes)
+      reduce.mAccumIns[InTypesIdx++] = canon(getUniqueTypeName(InType));
+
+    reduce.mResult = canon(getUniqueTypeName(ER->getResultType()));
+    reduce.mIsExportable = IsExportable;
+  }
+  if (isUsing()) {
+    if (mReducesOrderFatal)
+      return;
+
+    const std::string Name = ER->getNameReduce();
+
+    if (reduces.isFinished()) {
+      // This doesn't actually break reflection, but that's a
+      // coincidence of the fact that we reflect during the 64-bit
+      // compilation pass rather than the 32-bit compilation pass, and
+      // of the fact that the "extra" reduction kernel(s) are at the
+      // end.
+      mRSC->ReportError(ER->getLocation(),
+                        "reduction kernel '%0' is only present for 64-bit targets")
+          << Name;
+      return;
+    }
+
+    auto &reduce = reduces.UseNext();
+
+    if (reduce.mName != Name) {
+      // Order matters because it determines slot number.  We might be
+      // able to tolerate certain cases if we ignore non-exportable
+      // kernels in the two sequences (32-bit and 64-bit) -- non-exportable
+      // kernels do not take up slot numbers.
+      mRSC->ReportError(ER->getLocation(),
+                        "%ordinal0 reduction kernel is '%1' for 32-bit targets "
+                        "but '%2' for 64-bit targets")
+          << unsigned(reduces.CurrentIdx() + 1)
+          << reduce.mName
+          << Name;
+      mReducesOrderFatal = true;
+      return;
+    }
+
+    // If at least one of the two kernels (32-bit or 64-bit) is not
+    // exporable, then there will be no reflection for that kernel,
+    // and so any mismatch in result type or in inputs is irrelevant.
+    // However, we may make more kernels exportable in the future.
+    // Therefore, we'll forbid mismatches anyway.
+
+    if (reduce.mIsExportable != IsExportable) {
+      mRSC->ReportError(ER->getLocation(),
+                        "reduction kernel '%0' is reflected in Java only for %select{32|64}1-bit targets")
+          << reduce.mName
+          << IsExportable;
+    }
+
+    const std::string ResultType = getUniqueTypeName(ER->getResultType());
+    if (!reduce.mResult.equals(ResultType)) {
+      mRSC->ReportError(ER->getLocation(),
+                        "reduction kernel '%0' has result type '%1' for 32-bit targets "
+                        "but result type '%2' for 64-bit targets")
+          << reduce.mName << reduce.mResult.str() << ResultType;
+    }
+
+    const auto &InTypes = ER->getAccumulatorInTypes();
+    if (reduce.mAccumInCount != InTypes.size()) {
+      mRSC->ReportError(ER->getLocation(),
+                        "reduction kernel '%0' has %1 input%s1 for 32-bit targets "
+                        "but %2 input%s2 for 64-bit targets")
+          << Name << unsigned(reduce.mAccumInCount) << unsigned(InTypes.size());
+      return;
+    }
+    unsigned FieldIdx = 0;
+    for (const auto &InType : InTypes) {
+      const std::string InTypeName = getUniqueTypeName(InType);
+      const llvm::StringRef StateInTypeName = reduce.mAccumIns[FieldIdx++];
+      if (!StateInTypeName.equals(InTypeName)) {
+        mRSC->ReportError(ER->getLocation(),
+                          "%ordinal0 input of reduction kernel '%1' "
+                          "has type '%2' for 32-bit targets "
+                          "but type '%3' for 64-bit targets")
+            << FieldIdx
+            << Name
+            << StateInTypeName.str()
+            << InTypeName;
+      }
+    }
+  }
+}
+
+void ReflectionState::endReduces() {
+  if (!isUsing() || mReducesOrderFatal)
+    return;
+
+  auto &reduces = mFiles.Current().mReduces;
+  while (!reduces.isFinished()) {
+    const auto &reduce = reduces.UseNext();
+    mRSC->ReportError("in file '%0' reduction kernel '%1' is only present for 32-bit targets")
+        << mFiles.Current().mRSSourceFileName << reduce.mName;
+  }
+}
+
+// Variable ////////////////////////////////////////////////////////////////////////////////////
+
+// Keep this in sync with initialization handling in
+// RSReflectionJava::genScriptClassConstructor().
+ReflectionState::Val32 ReflectionState::declareVariable(const RSExportVar *EV) {
+  slangAssert(!isClosed());
+  if (!isActive())
+    return NoVal32();
+
+  auto &variables = mFiles.Current().mVariables;
+  if (isCollecting()) {
+    auto &variable = variables.CollectNext();
+    variable.mName = EV->getName();
+    variable.mType = canon(getUniqueTypeName(EV->getType()));
+    variable.mAllocSize = EV->getType()->getAllocSize();
+    variable.mIsConst = EV->isConst();
+    if (!EV->getInit().isUninit()) {
+      variable.mInitializerCount = 1;
+      variable.mInitializers = new clang::APValue[1];
+      variable.mInitializers[0] = EV->getInit();
+    } else if (EV->getArraySize()) {
+      variable.mInitializerCount = EV->getNumInits();
+      variable.mInitializers = new clang::APValue[variable.mInitializerCount];
+      for (size_t i = 0; i < variable.mInitializerCount; ++i)
+        variable.mInitializers[i] = EV->getInitArray(i);
+    } else {
+      variable.mInitializerCount = 0;
+    }
+    return NoVal32();
+  }
+
+  /*-- isUsing() -----------------------------------------------------------*/
+
+  slangAssert(isUsing());
+
+  if (mVariablesOrderFatal)
+    return NoVal32();
+
+  if (variables.isFinished()) {
+    // This doesn't actually break reflection, but that's a
+    // coincidence of the fact that we reflect during the 64-bit
+    // compilation pass rather than the 32-bit compilation pass, and
+    // of the fact that the "extra" variable(s) are at the end.
+    mRSC->ReportError(EV->getLocation(), "global variable '%0' is only present for 64-bit targets")
+        << EV->getName();
+    return NoVal32();
+  }
+
+  const auto &variable = variables.UseNext();
+
+  if (variable.mName != EV->getName()) {
+    // Order matters because it determines slot number
+    mRSC->ReportError(EV->getLocation(),
+                      "%ordinal0 global variable is '%1' for 32-bit targets "
+                      "but '%2' for 64-bit targets")
+        << unsigned(variables.CurrentIdx() + 1)
+        << variable.mName
+        << EV->getName();
+    mVariablesOrderFatal = true;
+    return NoVal32();
+  }
+
+  const std::string TypeName = getUniqueTypeName(EV->getType());
+
+  if (!variable.mType.equals(TypeName)) {
+    mRSC->ReportError(EV->getLocation(),
+                      "global variable '%0' has type '%1' for 32-bit targets "
+                      "but type '%2' for 64-bit targets")
+        << EV->getName()
+        << variable.mType.str()
+        << TypeName;
+    return NoVal32();
+  }
+
+  if (variable.mIsConst != EV->isConst()) {
+    mRSC->ReportError(EV->getLocation(),
+                      "global variable '%0' has inconsistent 'const' qualification "
+                      "between 32-bit targets and 64-bit targets")
+        << EV->getName();
+    return NoVal32();
+  }
+
+  // NOTE: Certain syntactically different but semantically
+  // equivalent initialization patterns are unnecessarily rejected
+  // as errors.
+  //
+  // Background:
+  //
+  // . A vector initialized with a scalar value is treated
+  //   by reflection as if all elements of the vector are
+  //   initialized with the scalar value.
+  // . A vector may be initialized with a vector of greater
+  //   length; reflection ignores the extra initializers.
+  // . If only the beginning of a vector is explicitly
+  //   initialized, reflection treats it as if trailing elements are
+  //   initialized to zero (by issuing explicit assignments to those
+  //   trailing elements).
+  // . If only the beginning of an array is explicitly initialized,
+  //   reflection treats it as if trailing elements are initialized
+  //   to zero (by Java rules for newly-created arrays).
+  //
+  // Unnecessarily rejected as errors:
+  //
+  // . One compile initializes a vector with a scalar, and
+  //   another initializes it with a vector whose elements
+  //   are the scalar, as in
+  //
+  //     int2 x =
+  //     #ifdef __LP64__
+  //       1
+  //     #else
+  //       { 1, 1 }
+  //     #endif
+  //
+  // . Compiles initialize a vector with vectors of different
+  //   lengths, but the initializers agree up to the length
+  //   of the variable being initialized, as in
+  //
+  //     int2 x = { 1, 2
+  //     #ifdef __LP64__
+  //       3
+  //     #else
+  //       4
+  //     #endif
+  //     };
+  //
+  // . Two compiles agree with the initializer for a vector or
+  //   array, except that one has some number of explicit trailing
+  //   zeroes, as in
+  //
+  //     int x[4] = { 3, 2, 1
+  //     #ifdef __LP64__
+  //       , 0
+  //     #endif
+  //     };
+
+  bool MismatchedInitializers = false;
+  if (!EV->getInit().isUninit()) {
+    // Use phase has a scalar initializer.
+    // Make sure that Collect phase had a matching scalar initializer.
+    if ((variable.mInitializerCount != 1) ||
+        !equal(variable.mInitializers[0], EV->getInit()))
+      MismatchedInitializers = true;
+  } else if (EV->getArraySize()) {
+    const size_t UseSize = EV->getNumInits();
+    if (variable.mInitializerCount != UseSize)
+      MismatchedInitializers = true;
+    else {
+      for (int i = 0; i < UseSize; ++i)
+        if (!equal(variable.mInitializers[i], EV->getInitArray(i))) {
+          MismatchedInitializers = true;
+          break;
+        }
+    }
+  } else if (variable.mInitializerCount != 0) {
+    // Use phase does not have a scalar initializer, variable is not
+    // an array, and Collect phase has an initializer.  This is an error.
+    MismatchedInitializers = true;
+  }
+
+  if (MismatchedInitializers) {
+    mRSC->ReportError(EV->getLocation(),
+                      "global variable '%0' is initialized differently for 32-bit targets "
+                      "than for 64-bit targets")
+        << EV->getName();
+    return NoVal32();
+  }
+
+  return Val32(true, variable.mAllocSize);
+}
+
+void ReflectionState::endVariables() {
+  if (!isUsing() || mVariablesOrderFatal)
+    return;
+
+  auto &variables = mFiles.Current().mVariables;
+  while (!variables.isFinished()) {
+    const auto &variable = variables.UseNext();
+    mRSC->ReportError("in file '%0' global variable '%1' is only present for 32-bit targets")
+        << mFiles.Current().mRSSourceFileName << variable.mName;
+  }
+}
+
+}  // namespace slang
diff --git a/slang_rs_reflection_state.h b/slang_rs_reflection_state.h
new file mode 100644
index 0000000..d937be8
--- /dev/null
+++ b/slang_rs_reflection_state.h
@@ -0,0 +1,776 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _FRAMEWORKS_COMPILE_SLANG_REFLECTION_STATE_H_  // NOLINT
+#define _FRAMEWORKS_COMPILE_SLANG_REFLECTION_STATE_H_
+
+#include <string>
+#include <utility>
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "clang/AST/APValue.h"
+
+#include "slang_assert.h"
+
+namespace slang {
+
+class RSContext;
+class RSExportForEach;
+class RSExportFunc;
+class RSExportRecordType;
+class RSExportReduce;
+class RSExportType;
+class RSExportVar;
+
+// ---------------------
+// class ReflectionState
+// ---------------------
+//
+// This class is used to collect data from 32-bit compilation for use
+// during the reflected code generation that occurs during 64-bit
+// compilation.  The data is used for two purposes:
+//
+// 1) Accommodating rs object handle size differences when laying out
+//    data (in particular, variables and records).
+// 2) Emitting errors when differences between 32-bit and 64-bit
+//    compilation cannot be tolerated in the reflected code (for
+//    example, size_t has different sizes, and so cannot be part
+//    of any exportable).
+//
+// The model for using this class is as follows:
+// a) Instantiate a class instance.  The instance is in the S_Initial
+//    state.
+// b) Call openJava32() to move the instance to the S_OpenJava32
+//    ("Collecting") state.
+// c) Run the reflection pass on all files in 32-bit mode.  Do not
+//    actually generate reflected code; but call various methods on
+//    the instance (begin*(), declare*(), end*(), etc.) to collect
+//    information.
+// d) Call closeJava32() to move the instance to the S_ClosedJava32
+//    state.
+// e) Call openJava64() to move the instance to the S_OpenJava64
+//    ("Using") state.
+// f) Run the reflection pass on all files in 64-bit mode.  Call the
+//    same methods as in step (c), as well as some further methods to
+//    query the information collected in step (c) in order to handle
+//    layout differences.  All error reporting for 32-bit versus
+//    64-bit differences is handled in the methods themselves.
+// g) Call closeJava64 to move the instance to the S_ClosedJava64
+//    state.
+// h) Destroy the instance.
+//
+// There are two exceptions to this model:
+//
+// 1) If not doing both 32-bit and 64-bit compilation, then skip steps
+//    (b), (d), (e), and (g).  (This is what happens if reflecting C++
+//    instead of Java, or reflecting Java but using the -m32 or -m64
+//    option.)  In this case, the methods called in steps (c) and (f)
+//    are no-ops: They do not collect information, they do not report
+//    errors, and they return "no information available" when step (f)
+//    asks for 32-bit layout related information.
+// 2) The class instance can be moved to the S_Bad state by class
+//    ReflectionState::Tentative (see that class for more information)
+//    when reflection itself aborts due to some error.  The only legal
+//    thing to do with an instance in this state is invoke its
+//    destructor.
+//
+// All exported entities except for Records have slot numbers assigned
+// in reflection order.  These slot numbers must match up between
+// 32-bit and 64-bit compilation.  Therefore, we (generally) require
+// that entities be presented to ReflectionState (via begin*() or
+// declare*()) in the same order during the Collecting and Using
+// phases.  This presentation order is generally the same as lexical
+// order in the user code, which makes it simple to emit meaningful
+// diagnostics when the order is inconsistent (for example, 32-bit and
+// 64-bit compilation disagree on the name of the kernel in a
+// particular slot).  ReflectionState generally builds up an array of
+// each sort of entity, in the presentation order.  There are two
+// exceptions:
+//
+// a) Records, as mentioned above.  Exported Records have no slot
+//    number, and therefore reflection order doesn't matter.  In
+//    practice, Records aren't necessarily reflected in consistent
+//    order, because they are determined to be exported as a
+//    consequence of determining that other entities are to be
+//    exported; and variations between 32-bit and 64-bit compilation
+//    can therefore result in inconsistent Record reflection order.
+//    Therefore, ReflectionState builds up a map of Records.
+// b) ForEach kernels.  ForEach kernels are not necessarily reflected
+//    in lexical order (there is some sorting to segregate root
+//    kernel, old-style kernels, and new-style kernels).  In order to
+//    give meaningful diagnostics for slot order mismatches, it's
+//    enough to solve the simpler problem of giving meaningful
+//    diagnostics for lexical order mismatches (although this is
+//    stricter than necessary because of the sorting that occurs
+//    before slot assignment).  Therefore, ReflectionState builds up
+//    an array of ForEaches in lexical order rather than in
+//    presentation (slot) order, and accesses the array randomly
+//    rather than sequentially.
+//
+class ReflectionState {
+ private:
+  // Set this to true to turn everything into a no-op, just as if none
+  // of the open*() or close*() methods were ever called.
+  static const bool kDisabled = false;
+
+ public:
+  ReflectionState() :
+      mRSC(nullptr),
+      mState(S_Initial),
+      mForEachOpen(-1),
+      mOutputClassOpen(false),
+      mRecordsState(RS_Initial),
+      mStringSet(nullptr) { }
+  ~ReflectionState();
+
+  ReflectionState(const ReflectionState &) = delete;
+  void operator=(const ReflectionState &) = delete;
+
+  // For use in the debugger.
+  void dump();
+
+  // A possibly-present value describing a property for a 32-bit target.
+  // When .first is false, the value is absent, and .second is unspecified.
+  typedef std::pair<bool, size_t> Val32;
+  static Val32 NoVal32() { return Val32(false, ~size_t(0)); }
+
+  void openJava32(size_t NumFiles);
+  void closeJava32();
+  void openJava64();
+  void closeJava64();
+
+  bool isCollecting() const { return mState==S_OpenJava32; }
+
+  // ----------------------------------------------------------------------
+
+  // Use these methods during the "Collecting" phase to track
+  // information about a class being generated -- a script class or a
+  // type class.  We call such a class "Divergent" if it needs to have
+  // at least one runtime check to distinguish between 32-bit and
+  // 64-bit targets.
+  //
+  //   Indicate that we are beginning to generate the class.
+  //
+  void beginOutputClass() {
+    slangAssert(!mOutputClassOpen && !isClosed());
+    mOutputClassOpen = true;
+    mOutputClassDivergent = false;
+  }
+  //
+  //   Record the fact that we've learned the class is divergent.
+  //
+  void setOutputClassDivergent() {
+    slangAssert(mOutputClassOpen);
+    mOutputClassDivergent = true;
+  }
+  //
+  //   Indicate that we've finished generating the class.  Returns
+  //   true IFF we've learned the class is divergent.
+  //
+  bool endOutputClass() {
+    slangAssert(mOutputClassOpen);
+    mOutputClassOpen = false;
+    return mOutputClassDivergent;
+  }
+
+  // ----------------------------------------------------------------------
+
+  // --------------------------------
+  // class ReflectionState::Tentative
+  // --------------------------------
+  //
+  // This class aids in error handling.  The model is as follows:
+  // a) Instantiate the class with a pointer to a ReflectionState
+  //    instance.
+  // b) Before destroying the class instance, if there have been no
+  //    errors, call the ok() method on the instance.
+  // c) When the instance is destroyed, if ok() has not been called on
+  //    it, this class will put the ReflectionState into the S_Bad
+  //    state.
+  //
+  // The idea is to "poison" the ReflectionState if we quit reflection
+  // early because of some error -- we don't want to get in a
+  // situation where we only have partial information from the
+  // Collecting phase (because of quitting early) but try to use it
+  // during the Using phase.
+  //
+  friend class Tentative;
+  class Tentative {
+   public:
+    Tentative(ReflectionState *state) : mState(state) { }
+    ~Tentative() { if (mState) mState->mState = ReflectionState::S_Bad; }
+
+    void ok() { mState = nullptr; }
+
+    Tentative(const Tentative &) = delete;
+    void operator=(const Tentative &) = delete;
+
+   private:
+    ReflectionState *mState;
+  };
+
+  // ----------------------------------------------------------------------
+
+  // Model for ForEach kernels (per File):
+  //
+  // a) beginForEaches(number_of_non_dummy_root_kernels_in_file)
+  // b) mixture of declareForEachDummyRoot() calls and
+  //    beginForEach()..endForEach() calls
+  // c) endForEaches()
+  //
+  // For a given ForEach kernel:
+  //
+  // b1) beginForEach()
+  // b2) call any number of addForEachIn() (one per input)
+  // b3) call any number of addForEachParam() (one per param)
+  // b4) call addForEachSignatureMetadata() (if it's reflected)
+  // b5) call endForEach()
+  //
+  // b2, b3, b4 can occur in any order
+
+  void beginForEaches(size_t Count);
+
+  void declareForEachDummyRoot(const RSExportForEach *) { /* we don't care */ };
+
+  void beginForEach(const RSExportForEach *EF);
+
+  void addForEachIn(const RSExportForEach *EF, const RSExportType *Type);
+
+  void addForEachParam(const RSExportForEach *EF, const RSExportType *Type);
+
+  void addForEachSignatureMetadata(const RSExportForEach *EF, unsigned Metadata);
+
+  void endForEach();
+
+  void endForEaches();
+
+  // ----------------------------------------------------------------------
+
+  // Model for Invokable functions (per File):
+  //
+  // a) beginInvokables(number_of_invokables_in_file)
+  // b) declareInvokable() for each Invokable (order must be
+  //    consistent between 32-bit and 64-bit compile)
+  // c) endInvokables()
+
+  void beginInvokables(size_t Count) {
+    mInvokablesOrderFatal = false;
+    begin(&File::mInvokables, Count);
+  }
+
+  void declareInvokable(const RSExportFunc *EF);
+
+  void endInvokables();
+
+  // ----------------------------------------------------------------------
+
+  // Model for reduction kernels (per File):
+  //
+  // a) beginReduces(number_of_reduction_kernels_in_file)
+  // b) declareReduce() for each reduction kernel (order must be
+  //    consistent between 32-bit and 64-bit compile)
+  // c) endReduces()
+
+  void beginReduces(size_t Count) {
+    mReducesOrderFatal = false;
+    begin(&File::mReduces, Count);
+  }
+
+  void declareReduce(const RSExportReduce *ER, bool IsExportable);
+
+  void endReduces();
+
+  // ----------------------------------------------------------------------
+
+  // Model for records (per File):
+  //
+  // a) beginRecords()
+  // b) declareRecord() for each Record (order doesn't matter)
+  // c) endRecords()
+  //
+  // And at any time during the Using phase, can call getRecord32() to
+  // get information from the 32-bit compile (Collecting phase).
+
+  void beginRecords();
+
+  // An "Ordinary" record is anything other than an
+  // internally-synthesized helper record.  We do not emit diagnostics
+  // for mismatched helper records -- we assume that the constructs
+  // from which those helper records were derived are also mismatched,
+  // and that we'll get diagnostics for those constructs.
+  void declareRecord(const RSExportRecordType *ERT, bool Ordinary = true);
+
+  void endRecords();
+
+  class Record32;
+
+  // During the Using phase, obtain information about a Record from
+  // the Collecting phase.  ERT should be from the Using phase, not
+  // the Collecting phase.  The value returned from this function is
+  // valid for the lifetime of the ReflectionState instance.
+  Record32 getRecord32(const RSExportRecordType *ERT);
+
+  // ----------------------------------------------------------------------
+
+  // Model for Variables (per file):
+  //
+  // a) beginVariables(number_of_exported_variables_in_file)
+  // b) declareVariable() for each Variable (order must be consistent
+  //    between 32-bit and 64-bit); in the Using phase, returns some
+  //    information about the Variable from 32-bit compilation
+  // c) endVariables()
+
+  void beginVariables(size_t Count) {
+    mVariablesOrderFatal = false;
+    begin(&File::mVariables, Count);
+  }
+
+  // If isUsing(), returns variable's 32-bit AllocSize; otherwise, returns NoVal32().
+  Val32 declareVariable(const RSExportVar *EV);
+
+  void endVariables();
+
+  // ----------------------------------------------------------------------
+
+  // ReflectionState has a notion of "current file".  After an
+  // openJava*() or closeJava*() call, there is no current file.
+  // Calling the nextFile() method when in the Collecting or Using
+  // state "advances" to the next file in the list of files being
+  // compiled, whose properties are specified by the arguments to
+  // nextFile().  All of the various begin*(), declare*(), end*()
+  // etc. calls implicitly refer to entities in the current file.
+  //
+  // RSC must remain valid until the next call to nextFile() or the
+  // next S_* state change.
+  void nextFile(const RSContext *RSC, const std::string &PackageName, const std::string &RSSourceFileName);
+
+  // ----------------------------------------------------------------------
+
+ private:
+  enum State {
+    S_Initial,          // No captured information
+    S_OpenJava32,       // Capturing information for 32-bit Java
+    S_ClosedJava32,     // Captured  information for 32-bit Java
+    S_OpenJava64,       // Capturing information for 64-bit Java
+    S_ClosedJava64,     // Captured  information for 64-bit Java
+    S_Bad,              // Abnormal termination
+  };
+
+  // context associated with compilation of the current file
+  const RSContext *mRSC;
+
+  State mState;
+
+  /*== ForEach ==================================================================*/
+
+  // The data in this section is transient during ForEach processing
+  // for each File.
+
+  int mForEachOpen;    // if nonnegative, then ordinal of beginForEach() without matching endForEach()
+  bool mForEachFatal;  // fatal mismatch in comparing ForEach; do no further comparisons for it
+
+  // Tracks mismatches discovered during the Use phase.
+  // There are two possibilities:
+  // - if (ordinal + 1) is greater than the number of ForEaches from the Collecting phase,
+  //   then this is an "extra" ForEach discovered during the Use phase
+  // - otherwise the Collecting phase and the Use phase disagree on the name of the
+  //   ForEach at this ordinal position (the Collecting phase's kernel name is
+  //   available in mFiles.Current().mForEaches[ordinal].mName)
+  llvm::SmallVector<const RSExportForEach *, 0> mForEachesBad;
+
+  // During the Use phase, keep track of how many ForEach ordinals we
+  // have seen that correspond to ordinals seen during the Collect
+  // phase.  This helps determine whether we have to issue errors at
+  // endForEaches().
+  size_t mNumForEachesMatchedByOrdinal;
+
+  /*== Invokable ================================================================*/
+
+  // 32-bit and 64-bit compiles need to see invokables in the same
+  // order, because of slot number assignment.  Once we see the first
+  // name mismatch in the sequence of invokables for a given File, it
+  // doesn't make sense to issue further diagnostics regarding
+  // invokables for that File.
+  bool mInvokablesOrderFatal;
+
+  /*== OutputClass ==============================================================*/
+
+  // This data tracks information about a class being generated -- a
+  // script class or a type class.  We call such a class "Divergent"
+  // if it needs to have at least one runtime check to distinguish
+  // between 32-bit and 64-bit targets.
+
+  bool mOutputClassOpen;  // beginOutputClass() without matching endOutputClass()
+  bool mOutputClassDivergent;  // has class been marked divergent?
+
+  /*== Record ===================================================================*/
+
+  // This field enforces necessary discipline on the use of
+  // beginRecords()/declareRecord()/endRecord().
+  enum {
+    RS_Initial,  // no beginRecords() yet for current File
+    RS_Open,     // beginRecords() but no endRecords() for current File
+    RS_Closed    // endRecords() for current File
+  } mRecordsState;
+
+  // During the Use phase, keep track of how many records we have seen
+  // that have same-named counterparts seen during the Collect phase.
+  // This helps determine whether we have to issue errors at
+  // endRecords().
+  size_t mNumRecordsMatchedByName;
+
+  /*== Reduce ===================================================================*/
+
+  // 32-bit and 64-bit compiles need to see reduction kernels in the
+  // same order, because of slot number assignment.  Once we see the
+  // first name mismatch in the sequence of reduction kernels for a
+  // given File, it doesn't make sense to issue further diagnostics
+  // regarding reduction kernels for that File.
+  bool mReducesOrderFatal;
+
+  /*== Variable =================================================================*/
+
+  // 32-bit and 64-bit compiles need to see variables in the same
+  // order, because of slot number assignment.  Once we see the first
+  // name mismatch in the sequence of variables for a given File, it
+  // doesn't make sense to issue further diagnostics regarding
+  // variables for that File.
+  bool mVariablesOrderFatal;
+
+  /*=============================================================================*/
+
+  bool isActive() const { return isCollecting() || isUsing(); }
+  bool isClosed() const { return mState==S_ClosedJava32 || mState==S_ClosedJava64; }
+  bool isUsing() const { return mState==S_OpenJava64; }
+
+  // For anything with a type (such as a Variable or a Record field),
+  // the type is represented via its name.  To save space, we don't
+  // create multiple instances of the same name -- we have a canonical
+  // instance in mStringSet, and use a StringRef to refer to it.  The
+  // method canon() returns a StringRef to the canonical
+  // instance, creating the instance if necessary.
+  llvm::StringRef canon(const std::string &String);
+  llvm::StringSet<> *mStringSet;
+
+  // Synthesize a name for the specified type.  There should be a
+  // one-to-one correspondence between the name and a C type (after
+  // typedefs and integer expressions have been "flattened", and
+  // considering a struct type to be identified solely by its name).
+  static std::string getUniqueTypeName(const RSExportType *T);
+
+  // ------------------------------
+  // template class ArrayWithCursor
+  // ------------------------------
+  //
+  // This class represents a fixed-length dynamically-allocated array
+  // (length is specified by a method call after instantiation) along
+  // with a cursor that traverses the array.  The behavior of the
+  // class is very specific to the needs of ReflectionState.
+  //
+  // The model for using this class is as follows:
+  // a) Instantiate a class instance.  The instance is in the
+  //    S_Initial state.
+  // b) Call BeginCollecting() with an array capacity.  This allocates
+  //    the array members and moves the instance to the S_Collecting
+  //    state.  The array size (contrast with capacity) is zero, and
+  //    the cursor has not been placed.
+  // c) Call CollectNext() a number of times equal to the capacity.
+  //    Each time CollectNext() is called, it extends the array size
+  //    by 1, and advances the cursor to the "new" member.  The idea
+  //    is to set the value of the "new" member at this time.
+  // d) Call BeginUsing().  This moves the instance to the S_Using
+  //    state and "unplaces" the cursor.
+  // e) Call UseNext() a number of times equal to the capacity.  Each
+  //    time UseNext() is called, it advances the cursor to the next
+  //    member (first member, the first time it is called).
+  //    The cursor is stepping through the members that were "created"
+  //    by CollectNext() during the S_Collecting state; the idea is to
+  //    look at their values.
+  // f) Destroy the instance.
+  //
+  template <typename Member> class ArrayWithCursor {
+   public:
+    ArrayWithCursor() : mState(S_Initial), mMembers(nullptr), mCapacity(0), mSize(0), mCursor(~size_t(0)) { }
+
+    ~ArrayWithCursor() { delete [] mMembers; }
+
+    ArrayWithCursor(const ArrayWithCursor &) = delete;
+    void operator=(const ArrayWithCursor &) = delete;
+
+    void BeginCollecting(size_t Size) {
+      slangAssert(mState == S_Initial);
+      mState = S_Collecting;
+      mMembers = new Member[Size];
+      mCapacity = Size;
+    }
+    // Increments the array size, advances the cursor to the new
+    // member, and returns a reference to that member.
+    Member &CollectNext() {
+      slangAssert((mState == S_Collecting) && (mCursor + 1 == mSize) && (mSize < mCapacity));
+      ++mSize;
+      return mMembers[++mCursor];
+    }
+
+    void BeginUsing() {
+      slangAssert((mState == S_Collecting) && (mCursor + 1 == mSize) && (mSize == mCapacity));
+      mState = S_Using;
+      mCursor = ~size_t(0);
+    }
+    // Advances the cursor to the next member, and returns a reference
+    // to that member.
+    Member &UseNext() {
+      slangAssert((mState == S_Using) && (mCursor + 1 < mSize));
+      return mMembers[++mCursor];
+    }
+
+    // Is the cursor on the last array member?
+    bool isFinished() const {
+      return mCursor + 1 == mSize;
+    }
+
+    size_t Size() const { return mSize; }
+
+    // Return a reference to the member under the cursor.
+    Member &Current() {
+      slangAssert(mCursor < mSize);
+      return mMembers[mCursor];
+    }
+    const Member &Current() const {
+      slangAssert(mCursor < mSize);
+      return mMembers[mCursor];
+    }
+    // Return the cursor position (zero-based).  Cursor must have been
+    // placed (i.e., if we're Collecting, we must have called
+    // CollectNext() at least once; and if we're Using, we must have
+    // called UseNext() at least once).
+    size_t CurrentIdx() const {
+      slangAssert(mCursor < mSize);
+      return mCursor;
+    }
+
+    // Return a reference to the specified member.  Must be within the
+    // array size (not merely within its capacity).
+    Member &operator[](size_t idx) {
+      slangAssert(idx < mSize);
+      return mMembers[idx];
+    }
+    const Member &operator[](size_t idx) const {
+      slangAssert(idx < mSize);
+      return mMembers[idx];
+    }
+
+   private:
+    enum State { S_Initial, S_Collecting, S_Using };
+    State mState;
+
+    Member *mMembers;
+    size_t mCapacity;
+    size_t mSize;
+    size_t mCursor;
+  };
+
+
+  struct File {
+    File() : mForEaches(nullptr) { }
+    ~File() { delete [] mForEaches; }
+
+    File(const File &) = delete;
+    void operator=(const File &) = delete;
+
+    std::string mPackageName;
+    std::string mRSSourceFileName;
+
+    struct ForEach {
+      ForEach() : mState(S_Initial) { }
+      ForEach(const ForEach &) = delete;
+      void operator=(const ForEach &) = delete;
+
+      enum {
+        S_Initial,    // ForEach has been instantiated
+        S_Collected,  // beginForEach() has been called while Collecting
+        S_UseMatched  // beginForEach() has been called while Using,
+                      //   and found this ForEach
+      } mState;
+
+      std::string mName;
+
+      // Types.  mIns[] and mOut can be null in case we have an
+      // old-style kernel with a void* input or output.
+      ArrayWithCursor<llvm::StringRef> mIns;
+      ArrayWithCursor<llvm::StringRef> mParams;
+      llvm::StringRef mOut;
+      bool mHasOut;  // to distinguish between no output and void* output.
+
+      unsigned mSignatureMetadata;
+      bool mIsKernel;  // new-style (by-value) rather than old-style
+    };
+    ForEach *mForEaches;  // indexed by ordinal (lexical order)
+    size_t mForEachCount;
+
+    struct Invokable {
+      Invokable() : mParams(nullptr) { }
+      ~Invokable() { delete [] mParams; }
+
+      Invokable(const Invokable &) = delete;
+      void operator=(const Invokable &) = delete;
+
+      std::string mName;
+      llvm::StringRef *mParams;  // Types
+      size_t mParamCount;
+    };
+    ArrayWithCursor<Invokable> mInvokables;
+
+    // There are two things we need to do with a Record:
+    // - Support structure sizes and layouts that differ between
+    //   32-bit and 64-bit compilation.
+    // - Do consistency checking between 32-bit and 64-bit compilation.
+    //
+    // TODO: Move this out of File to avoid duplication?  That is,
+    //       instead of tracking Records on a per-File basis, instead
+    //       track them globally?
+    //
+    //       (Because of ODR, we shouldn't have inconsistencies
+    //       between Files.)
+    //
+    struct Record {
+      Record() : mFields(nullptr) { }
+      ~Record() { delete [] mFields; }
+
+      Record(const Record &) = delete;
+      void operator=(const Record &) = delete;
+
+      struct Field {
+        std::string mName;
+        llvm::StringRef mType;
+        size_t mPrePadding;   // this.OffsetInParent - (prev.OffsetInParent + prev.AllocSize)
+        size_t mPostPadding;  // this.AllocSize - this.StoreSize
+        size_t mOffset;       // this.OffsetInParent
+        size_t mStoreSize;    // this.StoreSize
+      };
+      Field *mFields;
+      size_t mFieldCount;
+      size_t mPostPadding;    // padding after the end of the padded
+                              //   last field
+      size_t mAllocSize;
+      bool mOrdinary;         // anything other than an
+                              //   internally-synthesized helper
+                              //   record.  We do not emit diagnostics
+                              //   for inconsistent helper records.
+      bool mMatchedByName;    // has declareRecord() been called on
+                              //   this record during the Using phase?
+    };
+    llvm::StringMap<Record> mRecords;
+
+    struct Reduce {
+      Reduce() : mAccumIns(nullptr) { }
+      ~Reduce() { delete [] mAccumIns; }
+
+      Reduce(const Reduce &) = delete;
+      void operator=(const Reduce &) = delete;
+
+      std::string mName;
+
+      // only apply to exportable
+      llvm::StringRef *mAccumIns;  // Types
+      size_t mAccumInCount;
+      llvm::StringRef mResult;  // Type
+
+      bool mIsExportable;
+    };
+    ArrayWithCursor<Reduce> mReduces;
+
+    struct Variable {
+      Variable() : mInitializers(nullptr) { }
+      ~Variable() { delete [] mInitializers; }
+
+      Variable(const Variable &) = delete;
+      void operator=(const Variable &) = delete;
+
+      std::string mName;
+      llvm::StringRef mType;
+      clang::APValue *mInitializers;
+      size_t mInitializerCount;
+      size_t mAllocSize;
+      bool mIsConst;
+    };
+    ArrayWithCursor<Variable> mVariables;
+
+  };
+  ArrayWithCursor<File> mFiles;
+
+  // Utility template -- common pattern used by many begin*() methods.
+  template <typename Member>
+  void begin(ArrayWithCursor<Member> File::*Array, size_t Count) {
+    slangAssert(!isClosed());
+    if (!isActive())
+      return;
+
+    auto &file = mFiles.Current();
+    if (isCollecting())
+      (file.*Array).BeginCollecting(Count);
+    if (isUsing())
+      (file.*Array).BeginUsing();
+  }
+
+ public:
+
+  // This class represents 32-bit layout information built up during
+  // the Collecting phase, for use during the Using phase.  It
+  // provides an interface between class ReflectionState and client
+  // code that actually performs reflection.
+  class Record32 {
+    friend class ReflectionState;
+
+   public:
+    Record32() : mRecord(nullptr) { }
+
+    Val32 getRecordPostPadding() const {
+      if (!mRecord)
+        return NoVal32();
+      return Val32(true, mRecord->mPostPadding);
+    }
+
+    Val32 getRecordAllocSize() const {
+      if (!mRecord)
+        return NoVal32();
+      return Val32(true, mRecord->mAllocSize);
+    }
+
+    std::pair<Val32, Val32> getFieldPreAndPostPadding(unsigned idx) const {
+      if (!mRecord || idx >= mRecord->mFieldCount)
+        return std::make_pair(NoVal32(), NoVal32());
+      const File::Record::Field &field = mRecord->mFields[idx];
+      return std::make_pair(Val32(true, field.mPrePadding), Val32(true, field.mPostPadding));
+    }
+
+    std::pair<Val32, Val32> getFieldOffsetAndStoreSize(unsigned idx) const {
+      if (!mRecord || idx >= mRecord->mFieldCount)
+        return std::make_pair(NoVal32(), NoVal32());
+      const File::Record::Field &field = mRecord->mFields[idx];
+      return std::make_pair(Val32(true, field.mOffset), Val32(true, field.mStoreSize));
+    }
+
+   private:
+    Record32(const File::Record *Record) : mRecord(Record) { }
+    const File::Record *mRecord;
+  };
+};
+
+}
+
+#endif  // _FRAMEWORKS_COMPILE_SLANG_REFLECTION_STATE_H_  NOLINT
diff --git a/slang_version.h b/slang_version.h
index d56d175..aae7d04 100644
--- a/slang_version.h
+++ b/slang_version.h
@@ -39,6 +39,7 @@
   SLANG_JB_MR1_TARGET_API = 17,
   SLANG_JB_MR2_TARGET_API = 18,
   SLANG_KK_TARGET_API = 19,
+  SLANG_L_TARGET_API = 21,
   SLANG_M_TARGET_API = 23,
   SLANG_N_TARGET_API = 24,
   SLANG_N_MR1_TARGET_API = 25,
diff --git a/tests/F_reflection3264_foreach_mismatch/reflection3264_foreach_mismatch.rs b/tests/F_reflection3264_foreach_mismatch/reflection3264_foreach_mismatch.rs
new file mode 100644
index 0000000..c8e4a6d
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch/reflection3264_foreach_mismatch.rs
@@ -0,0 +1,141 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+// disagree on RS_KERNEL
+
+#ifdef __LP64__
+void aa(int *aout) { }
+#else
+void RS_KERNEL aa(double in) { }
+#endif
+
+#ifdef __LP64__
+int RS_KERNEL bb(float fin, double din) { return 0; }
+#else
+void bb(const long *ain) { }
+#endif
+
+// two different non-void* output types
+
+void cc(size_t *out) { }
+
+size_t RS_KERNEL dd() { return 0; }
+
+// one non-void* output type, one void* output type
+
+#ifdef __LP64__
+void ee(const int *in, short *out) { }
+void ff(const int *in, void *out) { }
+#else
+void ee(const int *in, void *out) { }
+void ff(const int *in, short *out) { }
+#endif
+
+// one non-void* output type, one no-output
+
+#ifdef __LP64__
+void gg(const int *in, int *out) { }
+void hh(const int *in) { }
+int RS_KERNEL ii(int v) { return 0; }
+void RS_KERNEL jj(int v) { }
+#else
+void gg(const int *in) { }
+void hh(const int *in, int *out) { }
+void RS_KERNEL ii(int v) { }
+int RS_KERNEL jj(int v) { return 0; }
+#endif
+
+// one void* output type, one no-output
+
+#ifdef __LP64__
+void kk(const int *in, void *out) { }
+void ll(const int *in) { }
+#else
+void kk(const int *in) { }
+void ll(const int *in, void *out) { }
+#endif
+
+// disagree on input count
+
+void mm(
+#ifdef __LP64__
+const int *in,
+#endif
+  double *out) { }
+
+void RS_KERNEL nn(
+#ifdef __LP64__
+int in0,
+#endif
+  size_t v) { }
+
+// disagree on param count
+
+void oo(const size_t *in, size_t *out
+#ifdef __LP64__
+            , const char *d
+#endif
+            ) { }
+
+// disagree on special parameters
+
+void pp(const int *in,
+#ifdef __LP64__
+          int x,
+#endif
+          int y) { }
+
+void RS_KERNEL qq(int in0, long in1,
+#ifdef __LP64__
+int x
+#else
+int y
+#endif
+                      ) { }
+
+// disagree on input types
+
+void rr(const size_t *in) { }
+
+void ss(
+#ifdef __LP64__
+const void *in
+#else
+const char *in
+#endif
+) { }
+
+void tt(
+#ifdef __LP64__
+const short *in
+#else
+const void *in
+#endif
+) { }
+
+struct S { int f; } s;
+struct T { int f; } t;
+#ifdef __LP64__
+#define QQTYPE struct T
+#else
+#define QQTYPE struct S
+#endif
+
+void RS_KERNEL uu(int a, size_t b, char c, QQTYPE d) { }
+
+// disagree on param types
+
+void vv(const int *a, const size_t *b) { }
+
+// ... note that today, a void* param is ignored for reflection
+#ifdef __LP64__
+void ww(const int *a, const void *b) { }
+void xx(const int *a, const float *b) { }
+void yy(const int *a, const void *b) { }
+void zz(const int *a) { }
+#else
+void ww(const int *a, const float *b) { }
+void xx(const int *a, const void *b) { }
+void yy(const int *a) { }
+void zz(const int *a, const void *b) { }
+#endif
diff --git a/tests/F_reflection3264_foreach_mismatch/stderr.txt.expect b/tests/F_reflection3264_foreach_mismatch/stderr.txt.expect
new file mode 100644
index 0000000..e24f176
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch/stderr.txt.expect
@@ -0,0 +1,26 @@
+reflection3264_foreach_mismatch.rs:13:15: error: foreach kernel 'bb' has __attribute__((kernel)) for 64-bit targets but not for 32-bit targets
+reflection3264_foreach_mismatch.rs:22:18: error: foreach kernel 'dd' has output type 'uint' for 32-bit targets but output type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch.rs:39:15: error: foreach kernel 'ii' has output type 'int' for 64-bit targets but no output for 32-bit targets
+reflection3264_foreach_mismatch.rs:40:16: error: foreach kernel 'jj' has output type 'int' for 32-bit targets but no output for 64-bit targets
+reflection3264_foreach_mismatch.rs:66:16: error: foreach kernel 'nn' has 1 input for 32-bit targets but 2 inputs for 64-bit targets
+reflection3264_foreach_mismatch.rs:88:16: error: foreach kernel 'qq' has different special parameters for 32-bit targets than for 64-bit targets
+reflection3264_foreach_mismatch.rs:124:16: error: 2nd input of foreach kernel 'uu' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch.rs:124:16: error: 4th input of foreach kernel 'uu' has type 'struct S' for 32-bit targets but type 'struct T' for 64-bit targets
+reflection3264_foreach_mismatch.rs:133:6: error: foreach kernel 'xx' has 0 usrData parameters for 32-bit targets but 1 usrData parameter for 64-bit targets
+reflection3264_foreach_mismatch.rs:132:6: error: foreach kernel 'ww' has 1 usrData parameter for 32-bit targets but 0 usrData parameters for 64-bit targets
+reflection3264_foreach_mismatch.rs:128:6: error: 1st usrData parameter of foreach kernel 'vv' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch.rs:108:6: error: 1st input of foreach kernel 'tt' has type 'short' for 64-bit targets but is untyped for 32-bit targets
+reflection3264_foreach_mismatch.rs:100:6: error: 1st input of foreach kernel 'ss' has type 'char' for 32-bit targets but is untyped for 64-bit targets
+reflection3264_foreach_mismatch.rs:98:6: error: 1st input of foreach kernel 'rr' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch.rs:82:6: error: foreach kernel 'pp' has different special parameters for 32-bit targets than for 64-bit targets
+reflection3264_foreach_mismatch.rs:74:6: error: foreach kernel 'oo' has output type 'uint' for 32-bit targets but output type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch.rs:74:6: error: foreach kernel 'oo' has 0 usrData parameters for 32-bit targets but 1 usrData parameter for 64-bit targets
+reflection3264_foreach_mismatch.rs:60:6: error: foreach kernel 'mm' has 0 inputs for 32-bit targets but 1 input for 64-bit targets
+reflection3264_foreach_mismatch.rs:52:6: error: foreach kernel 'll' has untyped output for 32-bit targets but no output for 64-bit targets
+reflection3264_foreach_mismatch.rs:51:6: error: foreach kernel 'kk' has untyped output for 64-bit targets but no output for 32-bit targets
+reflection3264_foreach_mismatch.rs:38:6: error: foreach kernel 'hh' has output type 'int' for 32-bit targets but no output for 64-bit targets
+reflection3264_foreach_mismatch.rs:37:6: error: foreach kernel 'gg' has output type 'int' for 64-bit targets but no output for 32-bit targets
+reflection3264_foreach_mismatch.rs:28:6: error: foreach kernel 'ff' has output type 'short' for 32-bit targets but has untyped output for 64-bit targets
+reflection3264_foreach_mismatch.rs:27:6: error: foreach kernel 'ee' has output type 'short' for 64-bit targets but has untyped output for 32-bit targets
+reflection3264_foreach_mismatch.rs:20:6: error: foreach kernel 'cc' has output type 'uint' for 32-bit targets but output type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch.rs:7:6: error: foreach kernel 'aa' has __attribute__((kernel)) for 32-bit targets but not for 64-bit targets
diff --git a/tests/F_reflection3264_foreach_mismatch/stdout.txt.expect b/tests/F_reflection3264_foreach_mismatch/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch/stdout.txt.expect
diff --git a/tests/F_reflection3264_foreach_mismatch_extra32/reflection3264_foreach_mismatch_extra32.rs b/tests/F_reflection3264_foreach_mismatch_extra32/reflection3264_foreach_mismatch_extra32.rs
new file mode 100644
index 0000000..8bf08c3
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_extra32/reflection3264_foreach_mismatch_extra32.rs
@@ -0,0 +1,14 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void aa(const int *in) { }
+
+void RS_KERNEL bb(int in) { }
+
+#ifndef __LP64__
+
+void cc(const int *in) { }
+
+void RS_KERNEL dd(int in) { }
+
+#endif
diff --git a/tests/F_reflection3264_foreach_mismatch_extra32/stderr.txt.expect b/tests/F_reflection3264_foreach_mismatch_extra32/stderr.txt.expect
new file mode 100644
index 0000000..a5c8588
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_extra32/stderr.txt.expect
@@ -0,0 +1,2 @@
+error: in file 'reflection3264_foreach_mismatch_extra32.rs' foreach kernel 'cc' is only present for 32-bit targets
+error: in file 'reflection3264_foreach_mismatch_extra32.rs' foreach kernel 'dd' is only present for 32-bit targets
diff --git a/tests/F_reflection3264_foreach_mismatch_extra32/stdout.txt.expect b/tests/F_reflection3264_foreach_mismatch_extra32/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_extra32/stdout.txt.expect
diff --git a/tests/F_reflection3264_foreach_mismatch_extra64/reflection3264_foreach_mismatch_extra64.rs b/tests/F_reflection3264_foreach_mismatch_extra64/reflection3264_foreach_mismatch_extra64.rs
new file mode 100644
index 0000000..469ec99
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_extra64/reflection3264_foreach_mismatch_extra64.rs
@@ -0,0 +1,14 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void aa(const int *in) { }
+
+void RS_KERNEL bb(int in) { }
+
+#ifdef __LP64__
+
+void cc(const int *in) { }
+
+void RS_KERNEL dd(int in) { }
+
+#endif
diff --git a/tests/F_reflection3264_foreach_mismatch_extra64/stderr.txt.expect b/tests/F_reflection3264_foreach_mismatch_extra64/stderr.txt.expect
new file mode 100644
index 0000000..4e8160e
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_extra64/stderr.txt.expect
@@ -0,0 +1,2 @@
+reflection3264_foreach_mismatch_extra64.rs:10:6: error: foreach kernel 'cc' is only present for 64-bit targets
+reflection3264_foreach_mismatch_extra64.rs:12:16: error: foreach kernel 'dd' is only present for 64-bit targets
diff --git a/tests/F_reflection3264_foreach_mismatch_extra64/stdout.txt.expect b/tests/F_reflection3264_foreach_mismatch_extra64/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_extra64/stdout.txt.expect
diff --git a/tests/F_reflection3264_foreach_mismatch_name32/reflection3264_foreach_mismatch_name32.rs b/tests/F_reflection3264_foreach_mismatch_name32/reflection3264_foreach_mismatch_name32.rs
new file mode 100644
index 0000000..89b597b
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_name32/reflection3264_foreach_mismatch_name32.rs
@@ -0,0 +1,23 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+// There are multiple name mismatches (cc*, dd*) but only the first is
+// reported.  This reporting doesn't prevent errors for kernels with
+// matched names from being reported.
+
+void aa(const size_t *in) { }
+
+#ifdef __LP64__
+void cc64(const int *in) { }
+void dd64(const int *in) { }
+#else
+void cc32(const float *in) { }
+void dd32(const float *in) { }
+#endif
+
+void RS_KERNEL bb(size_t in) { }
+
+// extra kernel goes unreported because of cc* name mismatch
+#ifndef __LP64__
+void e(const int *in) { }
+#endif
diff --git a/tests/F_reflection3264_foreach_mismatch_name32/stderr.txt.expect b/tests/F_reflection3264_foreach_mismatch_name32/stderr.txt.expect
new file mode 100644
index 0000000..1d58483
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_name32/stderr.txt.expect
@@ -0,0 +1,3 @@
+reflection3264_foreach_mismatch_name32.rs:18:16: error: 1st input of foreach kernel 'bb' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch_name32.rs:8:6: error: 1st input of foreach kernel 'aa' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch_name32.rs:11:6: error: 2nd foreach kernel is 'cc32' for 32-bit targets but 'cc64' for 64-bit targets
diff --git a/tests/F_reflection3264_foreach_mismatch_name32/stdout.txt.expect b/tests/F_reflection3264_foreach_mismatch_name32/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_name32/stdout.txt.expect
diff --git a/tests/F_reflection3264_foreach_mismatch_name64/reflection3264_foreach_mismatch_name64.rs b/tests/F_reflection3264_foreach_mismatch_name64/reflection3264_foreach_mismatch_name64.rs
new file mode 100644
index 0000000..59646f5
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_name64/reflection3264_foreach_mismatch_name64.rs
@@ -0,0 +1,23 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+// There are multiple name mismatches (cc*, dd*) but only the first is
+// reported.  This reporting doesn't prevent errors for kernels with
+// matched names from being reported.
+
+void aa(const size_t *in) { }
+
+#ifdef __LP64__
+void cc64(const int *in) { }
+void dd64(const int *in) { }
+#else
+void cc32(const float *in) { }
+void dd32(const float *in) { }
+#endif
+
+void RS_KERNEL bb(size_t in) { }
+
+// extra kernel goes unreported because of cc* name mismatch
+#ifdef __LP64__
+void e(const int *in) { }
+#endif
diff --git a/tests/F_reflection3264_foreach_mismatch_name64/stderr.txt.expect b/tests/F_reflection3264_foreach_mismatch_name64/stderr.txt.expect
new file mode 100644
index 0000000..2175d70
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_name64/stderr.txt.expect
@@ -0,0 +1,3 @@
+reflection3264_foreach_mismatch_name64.rs:18:16: error: 1st input of foreach kernel 'bb' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch_name64.rs:8:6: error: 1st input of foreach kernel 'aa' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_foreach_mismatch_name64.rs:11:6: error: 2nd foreach kernel is 'cc32' for 32-bit targets but 'cc64' for 64-bit targets
diff --git a/tests/F_reflection3264_foreach_mismatch_name64/stdout.txt.expect b/tests/F_reflection3264_foreach_mismatch_name64/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_foreach_mismatch_name64/stdout.txt.expect
diff --git a/tests/F_reflection3264_invokable_extra32/reflection3264_invokable_extra32.rs b/tests/F_reflection3264_invokable_extra32/reflection3264_invokable_extra32.rs
new file mode 100644
index 0000000..18ce97f
--- /dev/null
+++ b/tests/F_reflection3264_invokable_extra32/reflection3264_invokable_extra32.rs
@@ -0,0 +1,16 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void a() { }
+
+void b() { }
+
+void c() { }
+
+#ifndef __LP64__
+
+void d() { }
+
+void e() { }
+
+#endif
diff --git a/tests/F_reflection3264_invokable_extra32/stderr.txt.expect b/tests/F_reflection3264_invokable_extra32/stderr.txt.expect
new file mode 100644
index 0000000..ba0f30a
--- /dev/null
+++ b/tests/F_reflection3264_invokable_extra32/stderr.txt.expect
@@ -0,0 +1,2 @@
+error: in file 'reflection3264_invokable_extra32.rs' invokable function 'd' is only present for 32-bit targets
+error: in file 'reflection3264_invokable_extra32.rs' invokable function 'e' is only present for 32-bit targets
diff --git a/tests/F_reflection3264_invokable_extra32/stdout.txt.expect b/tests/F_reflection3264_invokable_extra32/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_invokable_extra32/stdout.txt.expect
diff --git a/tests/F_reflection3264_invokable_extra64/reflection3264_invokable_extra64.rs b/tests/F_reflection3264_invokable_extra64/reflection3264_invokable_extra64.rs
new file mode 100644
index 0000000..e9c1e1f
--- /dev/null
+++ b/tests/F_reflection3264_invokable_extra64/reflection3264_invokable_extra64.rs
@@ -0,0 +1,16 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void a() { }
+
+void b() { }
+
+void c() { }
+
+#ifdef __LP64__
+
+void d() { }
+
+void e() { }
+
+#endif
diff --git a/tests/F_reflection3264_invokable_extra64/stderr.txt.expect b/tests/F_reflection3264_invokable_extra64/stderr.txt.expect
new file mode 100644
index 0000000..4f0d9f9
--- /dev/null
+++ b/tests/F_reflection3264_invokable_extra64/stderr.txt.expect
@@ -0,0 +1,2 @@
+reflection3264_invokable_extra64.rs:12:6: error: invokable function 'd' is only present for 64-bit targets
+reflection3264_invokable_extra64.rs:14:6: error: invokable function 'e' is only present for 64-bit targets
diff --git a/tests/F_reflection3264_invokable_extra64/stdout.txt.expect b/tests/F_reflection3264_invokable_extra64/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_invokable_extra64/stdout.txt.expect
diff --git a/tests/F_reflection3264_invokable_mismatch/reflection3264_invokable_mismatch.rs b/tests/F_reflection3264_invokable_mismatch/reflection3264_invokable_mismatch.rs
new file mode 100644
index 0000000..5b3527b
--- /dev/null
+++ b/tests/F_reflection3264_invokable_mismatch/reflection3264_invokable_mismatch.rs
@@ -0,0 +1,33 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+#ifdef __LP64__
+void a(float f) { }
+#else
+void a(double f, float g) { }
+#endif
+
+void b(int j, size_t k, int l, ssize_t m) { }
+
+#ifdef __LP64__
+void c64() { }
+#else
+void c32() { }
+#endif
+
+// the errors after this point should go unreported, because of the
+// invokable name mismatch above (c32 versus c64)
+
+#ifdef __LP64__
+void z(float f) { }
+#else
+void z(double f, float g) { }
+#endif
+
+void y(int j, size_t k, int l, ssize_t m) { }
+
+#ifdef __LP64__
+void x64() { }
+#else
+void x32() { }
+#endif
diff --git a/tests/F_reflection3264_invokable_mismatch/stderr.txt.expect b/tests/F_reflection3264_invokable_mismatch/stderr.txt.expect
new file mode 100644
index 0000000..868ec30
--- /dev/null
+++ b/tests/F_reflection3264_invokable_mismatch/stderr.txt.expect
@@ -0,0 +1,4 @@
+reflection3264_invokable_mismatch.rs:5:6: error: invokable function 'a' has 2 parameters for 32-bit targets but 1 parameter for 64-bit targets
+reflection3264_invokable_mismatch.rs:10:6: error: 2nd parameter of invokable function 'b' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_invokable_mismatch.rs:10:6: error: 4th parameter of invokable function 'b' has type 'int' for 32-bit targets but type 'long' for 64-bit targets
+reflection3264_invokable_mismatch.rs:13:6: error: 3rd invokable function is 'c32' for 32-bit targets but 'c64' for 64-bit targets
diff --git a/tests/F_reflection3264_invokable_mismatch/stdout.txt.expect b/tests/F_reflection3264_invokable_mismatch/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_invokable_mismatch/stdout.txt.expect
diff --git a/tests/F_reflection3264_multifile/reflection3264_multifile_1.rs b/tests/F_reflection3264_multifile/reflection3264_multifile_1.rs
new file mode 100644
index 0000000..8ea1418
--- /dev/null
+++ b/tests/F_reflection3264_multifile/reflection3264_multifile_1.rs
@@ -0,0 +1,10 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+// no errors in this file, so we should compile reflection3264_multifile_2.rs
+
+int v;
+
+int w;
+
+void f1(int a) { }
diff --git a/tests/F_reflection3264_multifile/reflection3264_multifile_2.rs b/tests/F_reflection3264_multifile/reflection3264_multifile_2.rs
new file mode 100644
index 0000000..2b5be58
--- /dev/null
+++ b/tests/F_reflection3264_multifile/reflection3264_multifile_2.rs
@@ -0,0 +1,16 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+short v;
+
+short w;
+
+void f2(int a) { }
+
+// error: invokable is only present for 32-bit targets
+#ifndef __LP64__
+void g() { }
+#endif
+
+// error: 'in2' has different types for 32-bit and 64-bit targets
+void RS_KERNEL m(int in1, size_t in2) { }
diff --git a/tests/F_reflection3264_multifile/reflection3264_multifile_3.rs b/tests/F_reflection3264_multifile/reflection3264_multifile_3.rs
new file mode 100644
index 0000000..7bf2788
--- /dev/null
+++ b/tests/F_reflection3264_multifile/reflection3264_multifile_3.rs
@@ -0,0 +1,8 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+// we stop compiling after the first file with an error;
+// reflection3264_multifile_2.rs has errors, so we never get here, and
+// never report errors for this file's 'v' and 'w'.
+
+size_t v, w;
diff --git a/tests/F_reflection3264_multifile/stderr.txt.expect b/tests/F_reflection3264_multifile/stderr.txt.expect
new file mode 100644
index 0000000..31c4d5f
--- /dev/null
+++ b/tests/F_reflection3264_multifile/stderr.txt.expect
@@ -0,0 +1,2 @@
+reflection3264_multifile_2.rs:16:16: error: 2nd input of foreach kernel 'm' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+error: in file 'reflection3264_multifile_2.rs' invokable function 'g' is only present for 32-bit targets
diff --git a/tests/F_reflection3264_multifile/stdout.txt.expect b/tests/F_reflection3264_multifile/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_multifile/stdout.txt.expect
diff --git a/tests/F_reflection3264_package_mismatch/reflection3264_package_mismatch.rs b/tests/F_reflection3264_package_mismatch/reflection3264_package_mismatch.rs
new file mode 100644
index 0000000..d0452f8
--- /dev/null
+++ b/tests/F_reflection3264_package_mismatch/reflection3264_package_mismatch.rs
@@ -0,0 +1,8 @@
+#pragma version(1)
+
+#ifdef __LP64__
+#pragma rs java_package_name(sixty_four)
+#else
+#pragma rs java_package_name(thirty_two)
+#endif
+
diff --git a/tests/F_reflection3264_package_mismatch/stderr.txt.expect b/tests/F_reflection3264_package_mismatch/stderr.txt.expect
new file mode 100644
index 0000000..030f573
--- /dev/null
+++ b/tests/F_reflection3264_package_mismatch/stderr.txt.expect
@@ -0,0 +1 @@
+error: in file 'reflection3264_package_mismatch.rs' Java package name is 'thirty_two' for 32-bit targets but 'sixty_four' for 64-bit targets
diff --git a/tests/F_reflection3264_package_mismatch/stdout.txt.expect b/tests/F_reflection3264_package_mismatch/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_package_mismatch/stdout.txt.expect
diff --git a/tests/F_reflection3264_reduce_extra32/reflection3264_reduce_extra32.rs b/tests/F_reflection3264_reduce_extra32/reflection3264_reduce_extra32.rs
new file mode 100644
index 0000000..e734158
--- /dev/null
+++ b/tests/F_reflection3264_reduce_extra32/reflection3264_reduce_extra32.rs
@@ -0,0 +1,12 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+static void accum(int *a, int v) { }
+
+#pragma rs reduce(aa) accumulator(accum)
+#pragma rs reduce(bb) accumulator(accum)
+
+#ifndef __LP64__
+#pragma rs reduce(cc) accumulator(accum)
+#pragma rs reduce(dd) accumulator(accum)
+#endif
diff --git a/tests/F_reflection3264_reduce_extra32/stderr.txt.expect b/tests/F_reflection3264_reduce_extra32/stderr.txt.expect
new file mode 100644
index 0000000..c058403
--- /dev/null
+++ b/tests/F_reflection3264_reduce_extra32/stderr.txt.expect
@@ -0,0 +1,2 @@
+error: in file 'reflection3264_reduce_extra32.rs' reduction kernel 'cc' is only present for 32-bit targets
+error: in file 'reflection3264_reduce_extra32.rs' reduction kernel 'dd' is only present for 32-bit targets
diff --git a/tests/F_reflection3264_reduce_extra32/stdout.txt.expect b/tests/F_reflection3264_reduce_extra32/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_reduce_extra32/stdout.txt.expect
diff --git a/tests/F_reflection3264_reduce_extra64/reflection3264_reduce_extra64.rs b/tests/F_reflection3264_reduce_extra64/reflection3264_reduce_extra64.rs
new file mode 100644
index 0000000..c653d50
--- /dev/null
+++ b/tests/F_reflection3264_reduce_extra64/reflection3264_reduce_extra64.rs
@@ -0,0 +1,12 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+static void accum(int *a, int v) { }
+
+#pragma rs reduce(aa) accumulator(accum)
+#pragma rs reduce(bb) accumulator(accum)
+
+#ifdef __LP64__
+#pragma rs reduce(cc) accumulator(accum)
+#pragma rs reduce(dd) accumulator(accum)
+#endif
diff --git a/tests/F_reflection3264_reduce_extra64/stderr.txt.expect b/tests/F_reflection3264_reduce_extra64/stderr.txt.expect
new file mode 100644
index 0000000..864c196
--- /dev/null
+++ b/tests/F_reflection3264_reduce_extra64/stderr.txt.expect
@@ -0,0 +1,2 @@
+reflection3264_reduce_extra64.rs:10:12: error: reduction kernel 'cc' is only present for 64-bit targets
+reflection3264_reduce_extra64.rs:11:12: error: reduction kernel 'dd' is only present for 64-bit targets
diff --git a/tests/F_reflection3264_reduce_extra64/stdout.txt.expect b/tests/F_reflection3264_reduce_extra64/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_reduce_extra64/stdout.txt.expect
diff --git a/tests/F_reflection3264_reduce_mismatch/reflection3264_reduce_mismatch.rs b/tests/F_reflection3264_reduce_mismatch/reflection3264_reduce_mismatch.rs
new file mode 100644
index 0000000..10b3d85
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch/reflection3264_reduce_mismatch.rs
@@ -0,0 +1,71 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+struct S { int f; } ss;
+
+// accumulator types need not match; function names need not match
+#ifdef __LP64__
+#pragma rs reduce(aa) accumulator(aaAccum) combiner(aaCombAlpha) outconverter(aaOut)
+#else
+#pragma rs reduce(aa) accumulator(aaAccum) combiner(aaCombBeta) outconverter(aaOut)
+#endif
+static void aaAccum(size_t *a, int v) { }
+static void
+#ifdef __LP64__
+aaCombAlpha
+#else
+aaCombBeta
+#endif
+(size_t *a, const size_t *other) { }
+static void aaOut(int *out, const size_t *a) { }
+
+// which functions are present need not match; special arguments need not match
+#ifdef __LP64__
+#pragma rs reduce(bb) accumulator(bbAccum) combiner(bbComb) outconverter(bbOut)
+static void bbOut(int *out, const int *accum) { }
+#else
+#pragma rs reduce(bb) accumulator(bbAccum) combiner(bbComb)
+#endif
+static void bbAccum(int *a, int v,
+#ifdef __LP64__
+                    int x,
+#endif
+                    int y) { }
+static void bbComb(int *a, const int *b) { }
+
+// result type must match; ordinary argument types must match
+#pragma rs reduce(cc) accumulator(ccAccum) combiner(ccComb) outconverter(ccOut)
+static void ccAccum(int *accum, char i, size_t j, short k, size_t l) { }
+static void ccComb(int *accum, const int *other) { }
+static void ccOut(size_t *out, const int *accum) { }
+
+// accumulators must have same number of inputs
+#pragma rs reduce(dd) accumulator(ddAccum) combiner(ddComb)
+#ifdef __LP64__
+static void ddAccum(int *accum, char c) { }
+#else
+static void ddAccum(int *accum, short a, float b) { }
+#endif
+static void ddComb(int *accum, const int *other) { }
+
+// here, 32-bit kernel, 64-bit kernel, or both are not reflected in Java
+#pragma rs reduce(ee) accumulator(eeAccum) combiner(eeComb) outconverter(eeOut)
+#pragma rs reduce(ff) accumulator(ffAccum) combiner(ffComb) outconverter(ffOut)
+#pragma rs reduce(gg) accumulator(ggAccum) outconverter(ggOut)
+#ifdef __LP64__
+#define EETYPE struct S
+#define FFTYPE int
+#define FFINEXTRA int j
+#else
+#define EETYPE int
+#define FFTYPE struct S
+#define FFINEXTRA int j, int k
+#endif
+static void eeAccum(int *a, int v, size_t k) { }
+static void eeComb(int *a, const int *other) { }
+static void eeOut(EETYPE *out, const int *a) { }
+static void ffAccum(int *a, int v, FFINEXTRA) { }
+static void ffComb(int *a, const int *other) { }
+static void ffOut(FFTYPE *out, const int *a) { }
+static void ggAccum(size_t *a, size_t v) { }
+static void ggOut(struct S *out, const size_t *a) { }
diff --git a/tests/F_reflection3264_reduce_mismatch/stderr.txt.expect b/tests/F_reflection3264_reduce_mismatch/stderr.txt.expect
new file mode 100644
index 0000000..9c9a577
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch/stderr.txt.expect
@@ -0,0 +1,11 @@
+reflection3264_reduce_mismatch.rs:37:12: error: reduction kernel 'cc' has result type 'uint' for 32-bit targets but result type 'ulong' for 64-bit targets
+reflection3264_reduce_mismatch.rs:37:12: error: 2nd input of reduction kernel 'cc' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_reduce_mismatch.rs:37:12: error: 4th input of reduction kernel 'cc' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_reduce_mismatch.rs:43:12: error: reduction kernel 'dd' has 2 inputs for 32-bit targets but 1 input for 64-bit targets
+reflection3264_reduce_mismatch.rs:52:12: error: reduction kernel 'ee' is reflected in Java only for 32-bit targets
+reflection3264_reduce_mismatch.rs:52:12: error: reduction kernel 'ee' has result type 'int' for 32-bit targets but result type 'struct S' for 64-bit targets
+reflection3264_reduce_mismatch.rs:52:12: error: 2nd input of reduction kernel 'ee' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_reduce_mismatch.rs:53:12: error: reduction kernel 'ff' is reflected in Java only for 64-bit targets
+reflection3264_reduce_mismatch.rs:53:12: error: reduction kernel 'ff' has result type 'struct S' for 32-bit targets but result type 'int' for 64-bit targets
+reflection3264_reduce_mismatch.rs:53:12: error: reduction kernel 'ff' has 3 inputs for 32-bit targets but 2 inputs for 64-bit targets
+reflection3264_reduce_mismatch.rs:54:12: error: 1st input of reduction kernel 'gg' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
diff --git a/tests/F_reflection3264_reduce_mismatch/stdout.txt.expect b/tests/F_reflection3264_reduce_mismatch/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch/stdout.txt.expect
diff --git a/tests/F_reflection3264_reduce_mismatch_name_exp/reflection3264_reduce_mismatch_name_exp.rs b/tests/F_reflection3264_reduce_mismatch_name_exp/reflection3264_reduce_mismatch_name_exp.rs
new file mode 100644
index 0000000..7548cfe
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch_name_exp/reflection3264_reduce_mismatch_name_exp.rs
@@ -0,0 +1,15 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+static void accumBad(size_t *a, size_t v) { }
+
+#ifdef __LP64__
+#pragma rs reduce(a64) accumulator(accumBad)
+#else
+#pragma rs reduce(a32) accumulator(accumBad)
+#endif
+
+// the errors after this point should go unreported, because of the
+// name mismatch above (a32 versus a64)
+
+#pragma rs reduce(b) accumulator(accumBad)
diff --git a/tests/F_reflection3264_reduce_mismatch_name_exp/stderr.txt.expect b/tests/F_reflection3264_reduce_mismatch_name_exp/stderr.txt.expect
new file mode 100644
index 0000000..c5527b1
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch_name_exp/stderr.txt.expect
@@ -0,0 +1 @@
+reflection3264_reduce_mismatch_name_exp.rs:7:12: error: 1st reduction kernel is 'a32' for 32-bit targets but 'a64' for 64-bit targets
diff --git a/tests/F_reflection3264_reduce_mismatch_name_exp/stdout.txt.expect b/tests/F_reflection3264_reduce_mismatch_name_exp/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch_name_exp/stdout.txt.expect
diff --git a/tests/F_reflection3264_reduce_mismatch_name_noexp/reflection3264_reduce_mismatch_name_noexp.rs b/tests/F_reflection3264_reduce_mismatch_name_noexp/reflection3264_reduce_mismatch_name_noexp.rs
new file mode 100644
index 0000000..496ff01
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch_name_noexp/reflection3264_reduce_mismatch_name_noexp.rs
@@ -0,0 +1,18 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+struct S { int f; };
+
+static void accumGood(struct S *a, struct S v) { }
+static void accumBad(size_t *a, size_t v) { }
+
+#ifdef __LP64__
+#pragma rs reduce(a64) accumulator(accumGood)
+#else
+#pragma rs reduce(a32) accumulator(accumGood)
+#endif
+
+// the errors after this point should go unreported, because of the
+// name mismatch above (a32 versus a64)
+
+#pragma rs reduce(b) accumulator(accumBad)
diff --git a/tests/F_reflection3264_reduce_mismatch_name_noexp/stderr.txt.expect b/tests/F_reflection3264_reduce_mismatch_name_noexp/stderr.txt.expect
new file mode 100644
index 0000000..940684f
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch_name_noexp/stderr.txt.expect
@@ -0,0 +1 @@
+reflection3264_reduce_mismatch_name_noexp.rs:10:12: error: 1st reduction kernel is 'a32' for 32-bit targets but 'a64' for 64-bit targets
diff --git a/tests/F_reflection3264_reduce_mismatch_name_noexp/stdout.txt.expect b/tests/F_reflection3264_reduce_mismatch_name_noexp/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_reduce_mismatch_name_noexp/stdout.txt.expect
diff --git a/tests/F_reflection3264_struct_mismatch/reflection3264_struct_mismatch.rs b/tests/F_reflection3264_struct_mismatch/reflection3264_struct_mismatch.rs
new file mode 100644
index 0000000..5858add
--- /dev/null
+++ b/tests/F_reflection3264_struct_mismatch/reflection3264_struct_mismatch.rs
@@ -0,0 +1,81 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+struct t { int f; };
+
+struct q { int f; };
+
+struct b { int f; };
+
+struct j { int f; };
+
+struct f { int f; };
+
+struct o { int f; };
+
+// disagreement as to which struct types are exported
+
+#ifdef __LP64__
+struct t aa;
+struct q bb;
+struct b cc;
+int dd;
+int ee;
+int ff;
+#else
+int aa;
+int bb;
+int cc;
+struct j dd;
+struct f ee;
+struct o ff;
+#endif
+
+// disagreeement as to how many fields in an exported struct
+
+#ifdef __LP64__
+struct FieldCount {
+  int a;
+  float b;
+};
+#else
+struct FieldCount {
+  double c;
+};
+#endif
+
+struct FieldCount gg;
+
+// disagreement as to field name in an exported struct
+// (after first mismatched name, we do not report
+// any other errors for the struct)
+
+#ifdef __LP64__
+struct FieldName {
+  int a;
+  int b;
+  int c;
+  int d;
+};
+#else
+struct FieldName {
+  int a;
+  int e;
+  float c;
+  int f;
+};
+#endif
+
+struct FieldName hh;
+
+// disagreement as to field types in an exported struct
+
+struct FieldType {
+  int a;
+  size_t b;
+  rs_allocation c;
+  float d;
+  char e[sizeof(size_t)];
+};
+
+struct FieldType ii;
diff --git a/tests/F_reflection3264_struct_mismatch/stderr.txt.expect b/tests/F_reflection3264_struct_mismatch/stderr.txt.expect
new file mode 100644
index 0000000..4c70112
--- /dev/null
+++ b/tests/F_reflection3264_struct_mismatch/stderr.txt.expect
@@ -0,0 +1,16 @@
+reflection3264_struct_mismatch.rs:19:10: error: global variable 'aa' has type 'int' for 32-bit targets but type 'struct t' for 64-bit targets
+reflection3264_struct_mismatch.rs:20:10: error: global variable 'bb' has type 'int' for 32-bit targets but type 'struct q' for 64-bit targets
+reflection3264_struct_mismatch.rs:21:10: error: global variable 'cc' has type 'int' for 32-bit targets but type 'struct b' for 64-bit targets
+reflection3264_struct_mismatch.rs:22:5: error: global variable 'dd' has type 'struct j' for 32-bit targets but type 'int' for 64-bit targets
+reflection3264_struct_mismatch.rs:23:5: error: global variable 'ee' has type 'struct f' for 32-bit targets but type 'int' for 64-bit targets
+reflection3264_struct_mismatch.rs:24:5: error: global variable 'ff' has type 'struct o' for 32-bit targets but type 'int' for 64-bit targets
+reflection3264_struct_mismatch.rs:6:8: error: structure 'q' is exported only for 64-bit targets
+reflection3264_struct_mismatch.rs:8:8: error: structure 'b' is exported only for 64-bit targets
+reflection3264_struct_mismatch.rs:4:8: error: structure 't' is exported only for 64-bit targets
+reflection3264_struct_mismatch.rs:54:8: error: 2nd field of exported structure 'FieldName' is 'e' for 32-bit targets but 'b' for 64-bit targets
+reflection3264_struct_mismatch.rs:73:8: error: field 'b' of exported structure 'FieldType' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_struct_mismatch.rs:73:8: error: field 'e' of exported structure 'FieldType' has type 'char[4]' for 32-bit targets but type 'char[8]' for 64-bit targets
+reflection3264_struct_mismatch.rs:37:8: error: exported structure 'FieldCount' has 1 field for 32-bit targets but 2 fields for 64-bit targets
+error: in file 'reflection3264_struct_mismatch.rs' structure 'f' is exported only for 32-bit targets
+error: in file 'reflection3264_struct_mismatch.rs' structure 'j' is exported only for 32-bit targets
+error: in file 'reflection3264_struct_mismatch.rs' structure 'o' is exported only for 32-bit targets
diff --git a/tests/F_reflection3264_struct_mismatch/stdout.txt.expect b/tests/F_reflection3264_struct_mismatch/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_struct_mismatch/stdout.txt.expect
diff --git a/tests/F_reflection3264_variable_extra32/reflection3264_variable_extra32.rs b/tests/F_reflection3264_variable_extra32/reflection3264_variable_extra32.rs
new file mode 100644
index 0000000..a26178f
--- /dev/null
+++ b/tests/F_reflection3264_variable_extra32/reflection3264_variable_extra32.rs
@@ -0,0 +1,16 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int a;
+
+size_t b;
+
+double c;
+
+#ifndef __LP64__
+
+char d;
+
+short e = 1;
+
+#endif
diff --git a/tests/F_reflection3264_variable_extra32/stderr.txt.expect b/tests/F_reflection3264_variable_extra32/stderr.txt.expect
new file mode 100644
index 0000000..ec0b242
--- /dev/null
+++ b/tests/F_reflection3264_variable_extra32/stderr.txt.expect
@@ -0,0 +1,3 @@
+reflection3264_variable_extra32.rs:6:8: error: global variable 'b' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+error: in file 'reflection3264_variable_extra32.rs' global variable 'd' is only present for 32-bit targets
+error: in file 'reflection3264_variable_extra32.rs' global variable 'e' is only present for 32-bit targets
diff --git a/tests/F_reflection3264_variable_extra32/stdout.txt.expect b/tests/F_reflection3264_variable_extra32/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_variable_extra32/stdout.txt.expect
diff --git a/tests/F_reflection3264_variable_extra64/reflection3264_variable_extra64.rs b/tests/F_reflection3264_variable_extra64/reflection3264_variable_extra64.rs
new file mode 100644
index 0000000..4b9e946
--- /dev/null
+++ b/tests/F_reflection3264_variable_extra64/reflection3264_variable_extra64.rs
@@ -0,0 +1,16 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int a;
+
+size_t b;
+
+double c;
+
+#ifdef __LP64__
+
+char d;
+
+short e = 1;
+
+#endif
diff --git a/tests/F_reflection3264_variable_extra64/stderr.txt.expect b/tests/F_reflection3264_variable_extra64/stderr.txt.expect
new file mode 100644
index 0000000..6888f90
--- /dev/null
+++ b/tests/F_reflection3264_variable_extra64/stderr.txt.expect
@@ -0,0 +1,3 @@
+reflection3264_variable_extra64.rs:6:8: error: global variable 'b' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_variable_extra64.rs:12:6: error: global variable 'd' is only present for 64-bit targets
+reflection3264_variable_extra64.rs:14:7: error: global variable 'e' is only present for 64-bit targets
diff --git a/tests/F_reflection3264_variable_extra64/stdout.txt.expect b/tests/F_reflection3264_variable_extra64/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_variable_extra64/stdout.txt.expect
diff --git a/tests/F_reflection3264_variable_mismatch/reflection3264_variable_mismatch.rs b/tests/F_reflection3264_variable_mismatch/reflection3264_variable_mismatch.rs
new file mode 100644
index 0000000..b203751
--- /dev/null
+++ b/tests/F_reflection3264_variable_mismatch/reflection3264_variable_mismatch.rs
@@ -0,0 +1,66 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+struct Foo { int f; } foo;
+struct Bar { int f; } bar;
+
+size_t a;
+
+int b[sizeof(void*)];
+
+rs_allocation c;
+
+#ifdef __LP64__
+const
+#endif
+int d = 0;
+
+#ifndef __LP64__
+const
+#endif
+int e = 0;
+
+#ifdef __LP64__
+struct Foo f;
+#else
+struct Bar f;
+#endif
+
+size_t g[10];
+
+#ifdef __LP64__
+int h64;
+#else
+int h32;
+#endif
+
+// the errors after this point should go unreported, because of the
+// variable name mismatch above (h32 versus h64)
+
+size_t z;
+
+int y[sizeof(void*)];
+
+rs_allocation x;
+
+#ifdef __LP64__
+const
+#endif
+int w = 0;
+
+#ifndef __LP64__
+const
+#endif
+int v = 0;
+
+#ifdef __LP64__
+struct Foo u;
+#else
+struct Bar u;
+#endif
+
+#ifdef __LP64__
+int t64;
+#else
+int t32;
+#endif
diff --git a/tests/F_reflection3264_variable_mismatch/stderr.txt.expect b/tests/F_reflection3264_variable_mismatch/stderr.txt.expect
new file mode 100644
index 0000000..bc28bc5
--- /dev/null
+++ b/tests/F_reflection3264_variable_mismatch/stderr.txt.expect
@@ -0,0 +1,7 @@
+reflection3264_variable_mismatch.rs:7:8: error: global variable 'a' has type 'uint' for 32-bit targets but type 'ulong' for 64-bit targets
+reflection3264_variable_mismatch.rs:9:5: error: global variable 'b' has type 'int[4]' for 32-bit targets but type 'int[8]' for 64-bit targets
+reflection3264_variable_mismatch.rs:16:5: error: global variable 'd' has inconsistent 'const' qualification between 32-bit targets and 64-bit targets
+reflection3264_variable_mismatch.rs:21:5: error: global variable 'e' has inconsistent 'const' qualification between 32-bit targets and 64-bit targets
+reflection3264_variable_mismatch.rs:24:12: error: global variable 'f' has type 'struct Bar' for 32-bit targets but type 'struct Foo' for 64-bit targets
+reflection3264_variable_mismatch.rs:29:8: error: global variable 'g' has type 'uint[10]' for 32-bit targets but type 'ulong[10]' for 64-bit targets
+reflection3264_variable_mismatch.rs:32:5: error: 10th global variable is 'h32' for 32-bit targets but 'h64' for 64-bit targets
diff --git a/tests/F_reflection3264_variable_mismatch/stdout.txt.expect b/tests/F_reflection3264_variable_mismatch/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_variable_mismatch/stdout.txt.expect
diff --git a/tests/F_reflection3264_variable_mismatch_init/reflection3264_variable_mismatch_init.rs b/tests/F_reflection3264_variable_mismatch_init/reflection3264_variable_mismatch_init.rs
new file mode 100644
index 0000000..2aa142c
--- /dev/null
+++ b/tests/F_reflection3264_variable_mismatch_init/reflection3264_variable_mismatch_init.rs
@@ -0,0 +1,76 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+float a = 1.23f;
+
+float b = 4.56f + sizeof(void*);
+
+double c = 7.89;
+
+double d = 98.7 * sizeof(void*);
+
+char e = 'e';
+
+char f = sizeof(void*);
+
+int2 g = { 1, 2 };
+
+int2 h = { 3, sizeof(void*) };
+
+float4 i = { 1.2f, 3.4f, 5.6f, 7.8f };
+
+float4 j = { 1.2f, 3.4f,  // vector component initialized differently
+#ifdef __LP64__
+             5.6f,
+#else
+             6.5f,
+#endif
+             7.8f };
+
+int k
+#ifdef __LP64__
+= 0  // we get an error even though explicit zero initialization is redundant
+#endif
+    ;
+
+int l[10] = { 1, 2, 3 };
+
+int m[10] = { 1, 2, 3
+#ifdef __LP64__
+              , 4  // array with a different number of initializers
+#endif
+              , 5
+};
+
+int2 n = { 1
+#ifdef __LP64__
+           , 2  // vector with different number of initializers
+#endif
+};
+
+float4 jj = { 1.2f, 3.4f,  // vector component initialized differently
+#ifndef __LP64__
+             5.6f,
+#else
+             6.5f,
+#endif
+             7.8f };
+
+int kk
+#ifndef __LP64__
+= 0  // we get an error even though explicit zero initialization is redundant
+#endif
+    ;
+
+int mm[10] = { 1, 2, 3
+#ifndef __LP64__
+              , 4  // array with a different number of initializers
+#endif
+              , 5
+};
+
+int2 nn = { 1
+#ifndef __LP64__
+            , 2  // vector with a different number of initializers
+#endif
+};
diff --git a/tests/F_reflection3264_variable_mismatch_init/stderr.txt.expect b/tests/F_reflection3264_variable_mismatch_init/stderr.txt.expect
new file mode 100644
index 0000000..c342a62
--- /dev/null
+++ b/tests/F_reflection3264_variable_mismatch_init/stderr.txt.expect
@@ -0,0 +1,12 @@
+reflection3264_variable_mismatch_init.rs:6:7: error: global variable 'b' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:10:8: error: global variable 'd' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:14:6: error: global variable 'f' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:18:6: error: global variable 'h' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:22:8: error: global variable 'j' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:30:5: error: global variable 'k' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:38:5: error: global variable 'm' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:45:6: error: global variable 'n' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:51:8: error: global variable 'jj' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:59:5: error: global variable 'kk' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:65:5: error: global variable 'mm' is initialized differently for 32-bit targets than for 64-bit targets
+reflection3264_variable_mismatch_init.rs:72:6: error: global variable 'nn' is initialized differently for 32-bit targets than for 64-bit targets
diff --git a/tests/F_reflection3264_variable_mismatch_init/stdout.txt.expect b/tests/F_reflection3264_variable_mismatch_init/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_reflection3264_variable_mismatch_init/stdout.txt.expect
diff --git a/tests/P_reduce_general_accumulator/ScriptC_reduce_general_accumulator.java.expect b/tests/P_reduce_general_accumulator/ScriptC_reduce_general_accumulator.java.expect
index c39ce7c..e742b69 100644
--- a/tests/P_reduce_general_accumulator/ScriptC_reduce_general_accumulator.java.expect
+++ b/tests/P_reduce_general_accumulator/ScriptC_reduce_general_accumulator.java.expect
@@ -21,6 +21,9 @@
 
 package accumulator;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import accumulator.reduce_general_accumulatorBitCode;
 
diff --git a/tests/P_reduce_general_duplicate_array/ScriptC_reduce_general_duplicate_array.java.expect b/tests/P_reduce_general_duplicate_array/ScriptC_reduce_general_duplicate_array.java.expect
index c4d88ab..f582ddc 100644
--- a/tests/P_reduce_general_duplicate_array/ScriptC_reduce_general_duplicate_array.java.expect
+++ b/tests/P_reduce_general_duplicate_array/ScriptC_reduce_general_duplicate_array.java.expect
@@ -21,6 +21,9 @@
 
 package array;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import array.reduce_general_duplicate_arrayBitCode;
 
diff --git a/tests/P_reduce_general_examples/ScriptC_reduce_general_examples.java.expect b/tests/P_reduce_general_examples/ScriptC_reduce_general_examples.java.expect
index 74b295e..129b785 100644
--- a/tests/P_reduce_general_examples/ScriptC_reduce_general_examples.java.expect
+++ b/tests/P_reduce_general_examples/ScriptC_reduce_general_examples.java.expect
@@ -21,6 +21,9 @@
 
 package examples;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import examples.reduce_general_examplesBitCode;
 
diff --git a/tests/P_reduce_general_examples_backward/ScriptC_reduce_general_examples_backward.java.expect b/tests/P_reduce_general_examples_backward/ScriptC_reduce_general_examples_backward.java.expect
index 50437f3..49c5ede 100644
--- a/tests/P_reduce_general_examples_backward/ScriptC_reduce_general_examples_backward.java.expect
+++ b/tests/P_reduce_general_examples_backward/ScriptC_reduce_general_examples_backward.java.expect
@@ -21,6 +21,9 @@
 
 package examples;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import examples.reduce_general_examples_backwardBitCode;
 
diff --git a/tests/P_reduce_general_examples_explicit/ScriptC_reduce_general_examples_explicit.java.expect b/tests/P_reduce_general_examples_explicit/ScriptC_reduce_general_examples_explicit.java.expect
index 013838e..adcba0c 100644
--- a/tests/P_reduce_general_examples_explicit/ScriptC_reduce_general_examples_explicit.java.expect
+++ b/tests/P_reduce_general_examples_explicit/ScriptC_reduce_general_examples_explicit.java.expect
@@ -21,6 +21,9 @@
 
 package examples;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import examples.reduce_general_examples_explicitBitCode;
 
diff --git a/tests/P_reduce_general_examples_halter/ScriptC_reduce_general_examples_halter.java.expect b/tests/P_reduce_general_examples_halter/ScriptC_reduce_general_examples_halter.java.expect
index 0b2f3da..5a8966a 100644
--- a/tests/P_reduce_general_examples_halter/ScriptC_reduce_general_examples_halter.java.expect
+++ b/tests/P_reduce_general_examples_halter/ScriptC_reduce_general_examples_halter.java.expect
@@ -21,6 +21,9 @@
 
 package examples;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import examples.reduce_general_examples_halterBitCode;
 
diff --git a/tests/P_reduce_general_input/ScriptC_reduce_general_input.java.expect b/tests/P_reduce_general_input/ScriptC_reduce_general_input.java.expect
index bc151f1..56d10b2 100644
--- a/tests/P_reduce_general_input/ScriptC_reduce_general_input.java.expect
+++ b/tests/P_reduce_general_input/ScriptC_reduce_general_input.java.expect
@@ -21,6 +21,9 @@
 
 package input;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import input.reduce_general_inputBitCode;
 
diff --git a/tests/P_reduce_general_input/ScriptField_MyStruct.java.expect b/tests/P_reduce_general_input/ScriptField_MyStruct.java.expect
index ec10677..8f3859b 100644
--- a/tests/P_reduce_general_input/ScriptField_MyStruct.java.expect
+++ b/tests/P_reduce_general_input/ScriptField_MyStruct.java.expect
@@ -21,6 +21,9 @@
 
 package input;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import input.reduce_general_inputBitCode;
 
diff --git a/tests/P_reduce_general_inputs/ScriptC_reduce_general_inputs.java.expect b/tests/P_reduce_general_inputs/ScriptC_reduce_general_inputs.java.expect
index 05b80ad..198f438 100644
--- a/tests/P_reduce_general_inputs/ScriptC_reduce_general_inputs.java.expect
+++ b/tests/P_reduce_general_inputs/ScriptC_reduce_general_inputs.java.expect
@@ -21,6 +21,9 @@
 
 package inputs;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import inputs.reduce_general_inputsBitCode;
 
diff --git a/tests/P_reduce_general_inputs/ScriptField_MyStruct.java.expect b/tests/P_reduce_general_inputs/ScriptField_MyStruct.java.expect
index 182f920..95c1c50 100644
--- a/tests/P_reduce_general_inputs/ScriptField_MyStruct.java.expect
+++ b/tests/P_reduce_general_inputs/ScriptField_MyStruct.java.expect
@@ -21,6 +21,9 @@
 
 package inputs;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import inputs.reduce_general_inputsBitCode;
 
diff --git a/tests/P_reduce_general_result/ScriptC_reduce_general_result.java.expect b/tests/P_reduce_general_result/ScriptC_reduce_general_result.java.expect
index c1bd6d5..bbd40ba 100644
--- a/tests/P_reduce_general_result/ScriptC_reduce_general_result.java.expect
+++ b/tests/P_reduce_general_result/ScriptC_reduce_general_result.java.expect
@@ -21,6 +21,9 @@
 
 package result;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import result.reduce_general_resultBitCode;
 
diff --git a/tests/P_reduce_general_result/ScriptField_MyStruct.java.expect b/tests/P_reduce_general_result/ScriptField_MyStruct.java.expect
index 9943781..834c865 100644
--- a/tests/P_reduce_general_result/ScriptField_MyStruct.java.expect
+++ b/tests/P_reduce_general_result/ScriptField_MyStruct.java.expect
@@ -21,6 +21,9 @@
 
 package result;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import result.reduce_general_resultBitCode;
 
diff --git a/tests/P_reduce_general_struct/ScriptC_reduce_general_struct.java.expect b/tests/P_reduce_general_struct/ScriptC_reduce_general_struct.java.expect
index 983ea39..d2d15da 100644
--- a/tests/P_reduce_general_struct/ScriptC_reduce_general_struct.java.expect
+++ b/tests/P_reduce_general_struct/ScriptC_reduce_general_struct.java.expect
@@ -21,6 +21,9 @@
 
 package struct;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import struct.reduce_general_structBitCode;
 
diff --git a/tests/P_reflection3264_divergent/ScriptC_reflection3264_divergent.java.expect b/tests/P_reflection3264_divergent/ScriptC_reflection3264_divergent.java.expect
new file mode 100644
index 0000000..9f1eefe
--- /dev/null
+++ b/tests/P_reflection3264_divergent/ScriptC_reflection3264_divergent.java.expect
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_divergent.rs
+ */
+
+package foo;
+
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
+import android.renderscript.*;
+import foo.reflection3264_divergentBitCode;
+
+/**
+ * @hide
+ */
+public class ScriptC_reflection3264_divergent extends ScriptC {
+    private static final String __rs_resource_name = "reflection3264_divergent";
+    // Constructor
+    public  ScriptC_reflection3264_divergent(RenderScript rs) {
+        super(rs,
+              __rs_resource_name,
+              reflection3264_divergentBitCode.getBitCode32(),
+              reflection3264_divergentBitCode.getBitCode64());
+        __I32 = Element.I32(rs);
+        __@@INVALID@@ = Element.@@INVALID@@(rs);
+        __ALLOCATION = Element.ALLOCATION(rs);
+        __ScriptField_NonDivergent = ScriptField_NonDivergent.createElement(rs);
+        __ScriptField_Divergent = ScriptField_Divergent.createElement(rs);
+        __ScriptField_DivergentNest = ScriptField_DivergentNest.createElement(rs);
+    }
+
+    private Element __@@INVALID@@;
+    private Element __ALLOCATION;
+    private Element __I32;
+    private Element __ScriptField_Divergent;
+    private Element __ScriptField_DivergentNest;
+    private Element __ScriptField_NonDivergent;
+    private FieldPacker __rs_fp_@@INVALID@@;
+    private FieldPacker __rs_fp_ALLOCATION;
+    private FieldPacker __rs_fp_I32;
+    private FieldPacker __rs_fp_ScriptField_Divergent;
+    private FieldPacker __rs_fp_ScriptField_DivergentNest;
+    private FieldPacker __rs_fp_ScriptField_NonDivergent;
+    private final static int mExportVarIdx_intVar = 0;
+    private int mExportVar_intVar;
+    public synchronized void set_intVar(int v) {
+        setVar(mExportVarIdx_intVar, v);
+        mExportVar_intVar = v;
+    }
+
+    public int get_intVar() {
+        return mExportVar_intVar;
+    }
+
+    public Script.FieldID getFieldID_intVar() {
+        return createFieldID(mExportVarIdx_intVar, null);
+    }
+
+    private final static int mExportVarIdx_intArray = 1;
+    private int[] mExportVar_intArray;
+    public synchronized void set_intArray(int[] v) {
+        mExportVar_intArray = v;
+        FieldPacker fp = new FieldPacker(40);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_intArray, fp, __I32, __dimArr);
+    }
+
+    public int[] get_intArray() {
+        return mExportVar_intArray;
+    }
+
+    public Script.FieldID getFieldID_intArray() {
+        return createFieldID(mExportVarIdx_intArray, null);
+    }
+
+    private final static int mExportVarIdx_matVar = 2;
+    private Matrix2f mExportVar_matVar;
+    public synchronized void set_matVar(Matrix2f v) {
+        mExportVar_matVar = v;
+        FieldPacker fp = new FieldPacker(16);
+        fp.addMatrix(v);
+        setVar(mExportVarIdx_matVar, fp);
+    }
+
+    public Matrix2f get_matVar() {
+        return mExportVar_matVar;
+    }
+
+    public Script.FieldID getFieldID_matVar() {
+        return createFieldID(mExportVarIdx_matVar, null);
+    }
+
+    private final static int mExportVarIdx_matArray = 3;
+    private Matrix2f[] mExportVar_matArray;
+    public synchronized void set_matArray(Matrix2f[] v) {
+        mExportVar_matArray = v;
+        FieldPacker fp = new FieldPacker(160);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addMatrix(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_matArray, fp, __@@INVALID@@, __dimArr);
+    }
+
+    public Matrix2f[] get_matArray() {
+        return mExportVar_matArray;
+    }
+
+    public Script.FieldID getFieldID_matArray() {
+        return createFieldID(mExportVarIdx_matArray, null);
+    }
+
+    private final static int mExportVarIdx_allocVar = 4;
+    private Allocation mExportVar_allocVar;
+    public synchronized void set_allocVar(Allocation v) {
+        setVar(mExportVarIdx_allocVar, v);
+        mExportVar_allocVar = v;
+    }
+
+    public Allocation get_allocVar() {
+        return mExportVar_allocVar;
+    }
+
+    public Script.FieldID getFieldID_allocVar() {
+        return createFieldID(mExportVarIdx_allocVar, null);
+    }
+
+    private final static int mExportVarIdx_allocArray = 5;
+    private Allocation[] mExportVar_allocArray;
+    public synchronized void set_allocArray(Allocation[] v) {
+        mExportVar_allocArray = v;
+        FieldPacker fp = new FieldPacker(sIs64Bit ? 320 : 40);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addObj(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_allocArray, fp, __ALLOCATION, __dimArr);
+    }
+
+    public Allocation[] get_allocArray() {
+        return mExportVar_allocArray;
+    }
+
+    public Script.FieldID getFieldID_allocArray() {
+        return createFieldID(mExportVarIdx_allocArray, null);
+    }
+
+    private final static int mExportVarIdx_ndVar = 6;
+    private ScriptField_NonDivergent.Item mExportVar_ndVar;
+    public synchronized void set_ndVar(ScriptField_NonDivergent.Item v) {
+        mExportVar_ndVar = v;
+        FieldPacker fp = new FieldPacker(8);
+        fp.addI32(v.i);
+        fp.addI32(v.j);
+        int []__dimArr = new int[1];
+        __dimArr[0] = 1;
+        setVar(mExportVarIdx_ndVar, fp, __ScriptField_NonDivergent, __dimArr);
+    }
+
+    public ScriptField_NonDivergent.Item get_ndVar() {
+        return mExportVar_ndVar;
+    }
+
+    public Script.FieldID getFieldID_ndVar() {
+        return createFieldID(mExportVarIdx_ndVar, null);
+    }
+
+    private final static int mExportVarIdx_ndArray = 7;
+    private ScriptField_NonDivergent.Item[] mExportVar_ndArray;
+    public synchronized void set_ndArray(ScriptField_NonDivergent.Item[] v) {
+        mExportVar_ndArray = v;
+        FieldPacker fp = new FieldPacker(80);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1].i);
+            fp.addI32(v[ct1].j);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_ndArray, fp, __ScriptField_NonDivergent, __dimArr);
+    }
+
+    public ScriptField_NonDivergent.Item[] get_ndArray() {
+        return mExportVar_ndArray;
+    }
+
+    public Script.FieldID getFieldID_ndArray() {
+        return createFieldID(mExportVarIdx_ndArray, null);
+    }
+
+    private final static int mExportVarIdx_dVar = 8;
+    private ScriptField_Divergent.Item mExportVar_dVar;
+    public synchronized void set_dVar(ScriptField_Divergent.Item v) {
+        mExportVar_dVar = v;
+        FieldPacker fp = new FieldPacker(sIs64Bit ? 48 : 12);
+        fp.addI32(v.i);
+        fp.skip(sIs64Bit ? 4 : 0);
+        fp.addObj(v.a);
+        fp.addI32(v.j);
+        fp.skip(sIs64Bit ? 4 : 0);
+        int []__dimArr = new int[1];
+        __dimArr[0] = 1;
+        setVar(mExportVarIdx_dVar, fp, __ScriptField_Divergent, __dimArr);
+    }
+
+    public ScriptField_Divergent.Item get_dVar() {
+        return mExportVar_dVar;
+    }
+
+    public Script.FieldID getFieldID_dVar() {
+        return createFieldID(mExportVarIdx_dVar, null);
+    }
+
+    private final static int mExportVarIdx_dArray = 9;
+    private ScriptField_Divergent.Item[] mExportVar_dArray;
+    public synchronized void set_dArray(ScriptField_Divergent.Item[] v) {
+        mExportVar_dArray = v;
+        FieldPacker fp = new FieldPacker(sIs64Bit ? 400 : 120);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1].i);
+            fp.skip(sIs64Bit ? 4 : 0);
+            fp.addObj(v[ct1].a);
+            fp.addI32(v[ct1].j);
+            fp.skip(sIs64Bit ? 4 : 0);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_dArray, fp, __ScriptField_Divergent, __dimArr);
+    }
+
+    public ScriptField_Divergent.Item[] get_dArray() {
+        return mExportVar_dArray;
+    }
+
+    public Script.FieldID getFieldID_dArray() {
+        return createFieldID(mExportVarIdx_dArray, null);
+    }
+
+    private final static int mExportVarIdx_dnVar = 10;
+    private ScriptField_DivergentNest.Item mExportVar_dnVar;
+    public synchronized void set_dnVar(ScriptField_DivergentNest.Item v) {
+        mExportVar_dnVar = v;
+        FieldPacker fp = new FieldPacker(sIs64Bit ? 64 : 20);
+        fp.addI32(v.x);
+        fp.skip(sIs64Bit ? 4 : 0);
+        fp.addI32(v.d.i);
+        fp.skip(sIs64Bit ? 4 : 0);
+        fp.addObj(v.d.a);
+        fp.addI32(v.d.j);
+        fp.skip(sIs64Bit ? 4 : 0);
+        fp.addI32(v.y);
+        fp.skip(sIs64Bit ? 4 : 0);
+        int []__dimArr = new int[1];
+        __dimArr[0] = 1;
+        setVar(mExportVarIdx_dnVar, fp, __ScriptField_DivergentNest, __dimArr);
+    }
+
+    public ScriptField_DivergentNest.Item get_dnVar() {
+        return mExportVar_dnVar;
+    }
+
+    public Script.FieldID getFieldID_dnVar() {
+        return createFieldID(mExportVarIdx_dnVar, null);
+    }
+
+    private final static int mExportVarIdx_dnArray = 11;
+    private ScriptField_DivergentNest.Item[] mExportVar_dnArray;
+    public synchronized void set_dnArray(ScriptField_DivergentNest.Item[] v) {
+        mExportVar_dnArray = v;
+        FieldPacker fp = new FieldPacker(sIs64Bit ? 480 : 200);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1].x);
+            fp.skip(sIs64Bit ? 4 : 0);
+            fp.addI32(v[ct1].d.i);
+            fp.skip(sIs64Bit ? 4 : 0);
+            fp.addObj(v[ct1].d.a);
+            fp.addI32(v[ct1].d.j);
+            fp.skip(sIs64Bit ? 4 : 0);
+            fp.addI32(v[ct1].y);
+            fp.skip(sIs64Bit ? 4 : 0);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_dnArray, fp, __ScriptField_DivergentNest, __dimArr);
+    }
+
+    public ScriptField_DivergentNest.Item[] get_dnArray() {
+        return mExportVar_dnArray;
+    }
+
+    public Script.FieldID getFieldID_dnArray() {
+        return createFieldID(mExportVarIdx_dnArray, null);
+    }
+
+    //private final static int mExportForEachIdx_root = 0;
+    private final static int mExportForEachIdx_dnFe = 1;
+    public Script.KernelID getKernelID_dnFe() {
+        return createKernelID(mExportForEachIdx_dnFe, 7, null, null);
+    }
+
+    public void forEach_dnFe(Allocation ain, Allocation aout, ScriptField_DivergentNest.Item data) {
+        forEach_dnFe(ain, aout, data, null);
+    }
+
+    public void forEach_dnFe(Allocation ain, Allocation aout, ScriptField_DivergentNest.Item data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker dnFe_fp = new FieldPacker(sIs64Bit ? 64 : 20);
+        dnFe_fp.addI32(data.x);
+        dnFe_fp.skip(sIs64Bit ? 4 : 0);
+        dnFe_fp.addI32(data.d.i);
+        dnFe_fp.skip(sIs64Bit ? 4 : 0);
+        dnFe_fp.addObj(data.d.a);
+        dnFe_fp.addI32(data.d.j);
+        dnFe_fp.skip(sIs64Bit ? 4 : 0);
+        dnFe_fp.addI32(data.y);
+        dnFe_fp.skip(sIs64Bit ? 4 : 0);
+        forEach(mExportForEachIdx_dnFe, ain, aout, dnFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_dFe = 2;
+    public Script.KernelID getKernelID_dFe() {
+        return createKernelID(mExportForEachIdx_dFe, 7, null, null);
+    }
+
+    public void forEach_dFe(Allocation ain, Allocation aout, ScriptField_Divergent.Item data) {
+        forEach_dFe(ain, aout, data, null);
+    }
+
+    public void forEach_dFe(Allocation ain, Allocation aout, ScriptField_Divergent.Item data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker dFe_fp = new FieldPacker(sIs64Bit ? 48 : 12);
+        dFe_fp.addI32(data.i);
+        dFe_fp.skip(sIs64Bit ? 4 : 0);
+        dFe_fp.addObj(data.a);
+        dFe_fp.addI32(data.j);
+        dFe_fp.skip(sIs64Bit ? 4 : 0);
+        forEach(mExportForEachIdx_dFe, ain, aout, dFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_ndFe = 3;
+    public Script.KernelID getKernelID_ndFe() {
+        return createKernelID(mExportForEachIdx_ndFe, 7, null, null);
+    }
+
+    public void forEach_ndFe(Allocation ain, Allocation aout, ScriptField_NonDivergent.Item data) {
+        forEach_ndFe(ain, aout, data, null);
+    }
+
+    public void forEach_ndFe(Allocation ain, Allocation aout, ScriptField_NonDivergent.Item data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker ndFe_fp = new FieldPacker(8);
+        ndFe_fp.addI32(data.i);
+        ndFe_fp.addI32(data.j);
+        forEach(mExportForEachIdx_ndFe, ain, aout, ndFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_allocFe = 4;
+    public Script.KernelID getKernelID_allocFe() {
+        return createKernelID(mExportForEachIdx_allocFe, 7, null, null);
+    }
+
+    public void forEach_allocFe(Allocation ain, Allocation aout, Allocation data) {
+        forEach_allocFe(ain, aout, data, null);
+    }
+
+    public void forEach_allocFe(Allocation ain, Allocation aout, Allocation data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker allocFe_fp = new FieldPacker(sIs64Bit ? 32 : 4);
+        allocFe_fp.addObj(data);
+        forEach(mExportForEachIdx_allocFe, ain, aout, allocFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_matFe = 5;
+    public Script.KernelID getKernelID_matFe() {
+        return createKernelID(mExportForEachIdx_matFe, 7, null, null);
+    }
+
+    public void forEach_matFe(Allocation ain, Allocation aout, Matrix2f data) {
+        forEach_matFe(ain, aout, data, null);
+    }
+
+    public void forEach_matFe(Allocation ain, Allocation aout, Matrix2f data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker matFe_fp = new FieldPacker(16);
+        matFe_fp.addMatrix(data);
+        forEach(mExportForEachIdx_matFe, ain, aout, matFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_intFe = 6;
+    public Script.KernelID getKernelID_intFe() {
+        return createKernelID(mExportForEachIdx_intFe, 7, null, null);
+    }
+
+    public void forEach_intFe(Allocation ain, Allocation aout, int data) {
+        forEach_intFe(ain, aout, data, null);
+    }
+
+    public void forEach_intFe(Allocation ain, Allocation aout, int data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker intFe_fp = new FieldPacker(4);
+        intFe_fp.addI32(data);
+        forEach(mExportForEachIdx_intFe, ain, aout, intFe_fp, sc);
+    }
+
+    private final static int mExportFuncIdx_ndInv = 0;
+    public Script.InvokeID getInvokeID_ndInv() {
+        return createInvokeID(mExportFuncIdx_ndInv);
+    }
+
+    public void invoke_ndInv(int i, int j) {
+        FieldPacker ndInv_fp = new FieldPacker(8);
+        ndInv_fp.addI32(i);
+        ndInv_fp.addI32(j);
+        invoke(mExportFuncIdx_ndInv, ndInv_fp);
+    }
+
+    private final static int mExportFuncIdx_dInv = 1;
+    public Script.InvokeID getInvokeID_dInv() {
+        return createInvokeID(mExportFuncIdx_dInv);
+    }
+
+    public void invoke_dInv(int i, Allocation a, int j) {
+        FieldPacker dInv_fp = new FieldPacker(sIs64Bit ? 48 : 12);
+        dInv_fp.addI32(i);
+        dInv_fp.skip(sIs64Bit ? 4 : 0);
+        dInv_fp.addObj(a);
+        dInv_fp.addI32(j);
+        dInv_fp.skip(sIs64Bit ? 4 : 0);
+        invoke(mExportFuncIdx_dInv, dInv_fp);
+    }
+
+    private final static int mExportFuncIdx_dnInv = 2;
+    public Script.InvokeID getInvokeID_dnInv() {
+        return createInvokeID(mExportFuncIdx_dnInv);
+    }
+
+    public void invoke_dnInv(int x, ScriptField_Divergent.Item d, int y) {
+        FieldPacker dnInv_fp = new FieldPacker(sIs64Bit ? 64 : 20);
+        dnInv_fp.addI32(x);
+        dnInv_fp.skip(sIs64Bit ? 4 : 0);
+        dnInv_fp.addI32(d.i);
+        dnInv_fp.skip(sIs64Bit ? 4 : 0);
+        dnInv_fp.addObj(d.a);
+        dnInv_fp.addI32(d.j);
+        dnInv_fp.skip(sIs64Bit ? 4 : 0);
+        dnInv_fp.addI32(y);
+        dnInv_fp.skip(sIs64Bit ? 4 : 0);
+        invoke(mExportFuncIdx_dnInv, dnInv_fp);
+    }
+
+    private static boolean sIs64Bit;
+
+    static {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            sIs64Bit = Process.is64Bit();
+        }
+
+        else {
+            try {
+                Field f = RenderScript.class.getDeclaredField("sPointerSize");
+                f.setAccessible(true);
+                sIs64Bit = (f.getInt(null) == 8);
+            }
+
+            catch (Throwable e) {
+                sIs64Bit = false;
+            }
+
+        }
+
+    }
+
+}
+
diff --git a/tests/P_reflection3264_divergent/ScriptField_Divergent.java.expect b/tests/P_reflection3264_divergent/ScriptField_Divergent.java.expect
new file mode 100644
index 0000000..1be4ac2
--- /dev/null
+++ b/tests/P_reflection3264_divergent/ScriptField_Divergent.java.expect
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_divergent.rs
+ */
+
+package foo;
+
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
+import android.renderscript.*;
+import foo.reflection3264_divergentBitCode;
+
+/**
+ * @hide
+ */
+public class ScriptField_Divergent extends android.renderscript.Script.FieldBase {
+    static public class Item {
+
+        int i;
+        Allocation a;
+        int j;
+
+        Item() {
+        }
+
+    }
+
+    private Item mItemArray[];
+    private FieldPacker mIOBuffer;
+    private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null);
+    public static Element createElement(RenderScript rs) {
+        Element.Builder eb = new Element.Builder(rs);
+        eb.add(Element.I32(rs), "i");
+        if (sIs64Bit) {
+            eb.add(Element.U32(rs), "#rs_padding_1");
+        }
+
+        eb.add(Element.ALLOCATION(rs), "a");
+        eb.add(Element.I32(rs), "j");
+        if (sIs64Bit) {
+            eb.add(Element.U32(rs), "#rs_padding_2");
+        }
+
+        return eb.create();
+    }
+
+    private  ScriptField_Divergent(RenderScript rs) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+    }
+
+    public  ScriptField_Divergent(RenderScript rs, int count) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count);
+    }
+
+    public  ScriptField_Divergent(RenderScript rs, int count, int usages) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count, usages);
+    }
+
+    public static ScriptField_Divergent create1D(RenderScript rs, int dimX, int usages) {
+        ScriptField_Divergent obj = new ScriptField_Divergent(rs);
+        obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages);
+        return obj;
+    }
+
+    public static ScriptField_Divergent create1D(RenderScript rs, int dimX) {
+        return create1D(rs, dimX, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_Divergent create2D(RenderScript rs, int dimX, int dimY) {
+        return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_Divergent create2D(RenderScript rs, int dimX, int dimY, int usages) {
+        ScriptField_Divergent obj = new ScriptField_Divergent(rs);
+        Type.Builder b = new Type.Builder(rs, obj.mElement);
+        b.setX(dimX);
+        b.setY(dimY);
+        Type t = b.create();
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    public static Type.Builder createTypeBuilder(RenderScript rs) {
+        Element e = createElement(rs);
+        return new Type.Builder(rs, e);
+    }
+
+    public static ScriptField_Divergent createCustom(RenderScript rs, Type.Builder tb, int usages) {
+        ScriptField_Divergent obj = new ScriptField_Divergent(rs);
+        Type t = tb.create();
+        if (t.getElement() != obj.mElement) {
+            throw new RSIllegalArgumentException("Type.Builder did not match expected element type.");
+        }
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    private void copyToArrayLocal(Item i, FieldPacker fp) {
+        fp.addI32(i.i);
+        fp.skip(sIs64Bit ? 4 : 0);
+        fp.addObj(i.a);
+        fp.addI32(i.j);
+        fp.skip(sIs64Bit ? 4 : 0);
+    }
+
+    private void copyToArray(Item i, int index) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        mIOBuffer.reset(index * mElement.getBytesSize());
+        copyToArrayLocal(i, mIOBuffer);
+    }
+
+    public synchronized void set(Item i, int index, boolean copyNow) {
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        mItemArray[index] = i;
+        if (copyNow)  {
+            copyToArray(i, index);
+            FieldPacker fp = new FieldPacker(mElement.getBytesSize());
+            copyToArrayLocal(i, fp);
+            mAllocation.setFromFieldPacker(index, fp);
+        }
+
+    }
+
+    public synchronized Item get(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index];
+    }
+
+    public synchronized void set_i(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].i = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize());
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, 0, fp);
+        }
+
+    }
+
+    public synchronized void set_a(int index, Allocation v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].a = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + (sIs64Bit ? 8 : 4));
+            mIOBuffer.addObj(v);
+            FieldPacker fp = new FieldPacker(sIs64Bit ? 32 : 4);
+            fp.addObj(v);
+            mAllocation.setFromFieldPacker(index, sIs64Bit ? 2 : 1, fp);
+        }
+
+    }
+
+    public synchronized void set_j(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].j = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + (sIs64Bit ? 40 : 8));
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, sIs64Bit ? 3 : 2, fp);
+        }
+
+    }
+
+    public synchronized int get_i(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].i;
+    }
+
+    public synchronized Allocation get_a(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index].a;
+    }
+
+    public synchronized int get_j(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].j;
+    }
+
+    public synchronized void copyAll() {
+        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
+        mAllocation.setFromFieldPacker(0, mIOBuffer);
+    }
+
+    public synchronized void resize(int newSize) {
+        if (mItemArray != null)  {
+            int oldSize = mItemArray.length;
+            int copySize = Math.min(oldSize, newSize);
+            if (newSize == oldSize) return;
+            Item ni[] = new Item[newSize];
+            System.arraycopy(mItemArray, 0, ni, 0, copySize);
+            mItemArray = ni;
+        }
+
+        mAllocation.resize(newSize);
+        if (mIOBuffer != null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+    }
+
+    private static boolean sIs64Bit;
+
+    static {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            sIs64Bit = Process.is64Bit();
+        }
+
+        else {
+            try {
+                Field f = RenderScript.class.getDeclaredField("sPointerSize");
+                f.setAccessible(true);
+                sIs64Bit = (f.getInt(null) == 8);
+            }
+
+            catch (Throwable e) {
+                sIs64Bit = false;
+            }
+
+        }
+
+    }
+
+}
+
diff --git a/tests/P_reflection3264_divergent/ScriptField_DivergentNest.java.expect b/tests/P_reflection3264_divergent/ScriptField_DivergentNest.java.expect
new file mode 100644
index 0000000..18ba85a
--- /dev/null
+++ b/tests/P_reflection3264_divergent/ScriptField_DivergentNest.java.expect
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_divergent.rs
+ */
+
+package foo;
+
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
+import android.renderscript.*;
+import foo.reflection3264_divergentBitCode;
+
+/**
+ * @hide
+ */
+public class ScriptField_DivergentNest extends android.renderscript.Script.FieldBase {
+    static public class Item {
+
+        int x;
+        ScriptField_Divergent.Item d;
+        int y;
+
+        Item() {
+            d = new ScriptField_Divergent.Item();
+        }
+
+    }
+
+    private Item mItemArray[];
+    private FieldPacker mIOBuffer;
+    private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null);
+    public static Element createElement(RenderScript rs) {
+        Element.Builder eb = new Element.Builder(rs);
+        eb.add(Element.I32(rs), "x");
+        if (sIs64Bit) {
+            eb.add(Element.U32(rs), "#rs_padding_1");
+        }
+
+        eb.add(ScriptField_Divergent.createElement(rs), "d");
+        eb.add(Element.I32(rs), "y");
+        if (sIs64Bit) {
+            eb.add(Element.U32(rs), "#rs_padding_2");
+        }
+
+        return eb.create();
+    }
+
+    private  ScriptField_DivergentNest(RenderScript rs) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+    }
+
+    public  ScriptField_DivergentNest(RenderScript rs, int count) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count);
+    }
+
+    public  ScriptField_DivergentNest(RenderScript rs, int count, int usages) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count, usages);
+    }
+
+    public static ScriptField_DivergentNest create1D(RenderScript rs, int dimX, int usages) {
+        ScriptField_DivergentNest obj = new ScriptField_DivergentNest(rs);
+        obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages);
+        return obj;
+    }
+
+    public static ScriptField_DivergentNest create1D(RenderScript rs, int dimX) {
+        return create1D(rs, dimX, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_DivergentNest create2D(RenderScript rs, int dimX, int dimY) {
+        return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_DivergentNest create2D(RenderScript rs, int dimX, int dimY, int usages) {
+        ScriptField_DivergentNest obj = new ScriptField_DivergentNest(rs);
+        Type.Builder b = new Type.Builder(rs, obj.mElement);
+        b.setX(dimX);
+        b.setY(dimY);
+        Type t = b.create();
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    public static Type.Builder createTypeBuilder(RenderScript rs) {
+        Element e = createElement(rs);
+        return new Type.Builder(rs, e);
+    }
+
+    public static ScriptField_DivergentNest createCustom(RenderScript rs, Type.Builder tb, int usages) {
+        ScriptField_DivergentNest obj = new ScriptField_DivergentNest(rs);
+        Type t = tb.create();
+        if (t.getElement() != obj.mElement) {
+            throw new RSIllegalArgumentException("Type.Builder did not match expected element type.");
+        }
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    private void copyToArrayLocal(Item i, FieldPacker fp) {
+        fp.addI32(i.x);
+        fp.skip(sIs64Bit ? 4 : 0);
+        fp.addI32(i.d.i);
+        fp.skip(sIs64Bit ? 4 : 0);
+        fp.addObj(i.d.a);
+        fp.addI32(i.d.j);
+        fp.skip(sIs64Bit ? 4 : 0);
+        fp.addI32(i.y);
+        fp.skip(sIs64Bit ? 4 : 0);
+    }
+
+    private void copyToArray(Item i, int index) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        mIOBuffer.reset(index * mElement.getBytesSize());
+        copyToArrayLocal(i, mIOBuffer);
+    }
+
+    public synchronized void set(Item i, int index, boolean copyNow) {
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        mItemArray[index] = i;
+        if (copyNow)  {
+            copyToArray(i, index);
+            FieldPacker fp = new FieldPacker(mElement.getBytesSize());
+            copyToArrayLocal(i, fp);
+            mAllocation.setFromFieldPacker(index, fp);
+        }
+
+    }
+
+    public synchronized Item get(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index];
+    }
+
+    public synchronized void set_x(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].x = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize());
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, 0, fp);
+        }
+
+    }
+
+    public synchronized void set_d(int index, ScriptField_Divergent.Item v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].d = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + (sIs64Bit ? 8 : 4));
+            mIOBuffer.addI32(v.i);
+            mIOBuffer.skip(sIs64Bit ? 4 : 0);
+            mIOBuffer.addObj(v.a);
+            mIOBuffer.addI32(v.j);
+            mIOBuffer.skip(sIs64Bit ? 4 : 0);
+            FieldPacker fp = new FieldPacker(sIs64Bit ? 48 : 12);
+            fp.addI32(v.i);
+            fp.skip(sIs64Bit ? 4 : 0);
+            fp.addObj(v.a);
+            fp.addI32(v.j);
+            fp.skip(sIs64Bit ? 4 : 0);
+            mAllocation.setFromFieldPacker(index, sIs64Bit ? 2 : 1, fp);
+        }
+
+    }
+
+    public synchronized void set_y(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].y = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + (sIs64Bit ? 56 : 16));
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, sIs64Bit ? 3 : 2, fp);
+        }
+
+    }
+
+    public synchronized int get_x(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].x;
+    }
+
+    public synchronized ScriptField_Divergent.Item get_d(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index].d;
+    }
+
+    public synchronized int get_y(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].y;
+    }
+
+    public synchronized void copyAll() {
+        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
+        mAllocation.setFromFieldPacker(0, mIOBuffer);
+    }
+
+    public synchronized void resize(int newSize) {
+        if (mItemArray != null)  {
+            int oldSize = mItemArray.length;
+            int copySize = Math.min(oldSize, newSize);
+            if (newSize == oldSize) return;
+            Item ni[] = new Item[newSize];
+            System.arraycopy(mItemArray, 0, ni, 0, copySize);
+            mItemArray = ni;
+        }
+
+        mAllocation.resize(newSize);
+        if (mIOBuffer != null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+    }
+
+    private static boolean sIs64Bit;
+
+    static {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            sIs64Bit = Process.is64Bit();
+        }
+
+        else {
+            try {
+                Field f = RenderScript.class.getDeclaredField("sPointerSize");
+                f.setAccessible(true);
+                sIs64Bit = (f.getInt(null) == 8);
+            }
+
+            catch (Throwable e) {
+                sIs64Bit = false;
+            }
+
+        }
+
+    }
+
+}
+
diff --git a/tests/P_reflection3264_divergent/ScriptField_NonDivergent.java.expect b/tests/P_reflection3264_divergent/ScriptField_NonDivergent.java.expect
new file mode 100644
index 0000000..437b9c5
--- /dev/null
+++ b/tests/P_reflection3264_divergent/ScriptField_NonDivergent.java.expect
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_divergent.rs
+ */
+
+package foo;
+
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
+import android.renderscript.*;
+import foo.reflection3264_divergentBitCode;
+
+/**
+ * @hide
+ */
+public class ScriptField_NonDivergent extends android.renderscript.Script.FieldBase {
+    static public class Item {
+
+        int i;
+        int j;
+
+        Item() {
+        }
+
+    }
+
+    private Item mItemArray[];
+    private FieldPacker mIOBuffer;
+    private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null);
+    public static Element createElement(RenderScript rs) {
+        Element.Builder eb = new Element.Builder(rs);
+        eb.add(Element.I32(rs), "i");
+        eb.add(Element.I32(rs), "j");
+        return eb.create();
+    }
+
+    private  ScriptField_NonDivergent(RenderScript rs) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+    }
+
+    public  ScriptField_NonDivergent(RenderScript rs, int count) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count);
+    }
+
+    public  ScriptField_NonDivergent(RenderScript rs, int count, int usages) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count, usages);
+    }
+
+    public static ScriptField_NonDivergent create1D(RenderScript rs, int dimX, int usages) {
+        ScriptField_NonDivergent obj = new ScriptField_NonDivergent(rs);
+        obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages);
+        return obj;
+    }
+
+    public static ScriptField_NonDivergent create1D(RenderScript rs, int dimX) {
+        return create1D(rs, dimX, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_NonDivergent create2D(RenderScript rs, int dimX, int dimY) {
+        return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_NonDivergent create2D(RenderScript rs, int dimX, int dimY, int usages) {
+        ScriptField_NonDivergent obj = new ScriptField_NonDivergent(rs);
+        Type.Builder b = new Type.Builder(rs, obj.mElement);
+        b.setX(dimX);
+        b.setY(dimY);
+        Type t = b.create();
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    public static Type.Builder createTypeBuilder(RenderScript rs) {
+        Element e = createElement(rs);
+        return new Type.Builder(rs, e);
+    }
+
+    public static ScriptField_NonDivergent createCustom(RenderScript rs, Type.Builder tb, int usages) {
+        ScriptField_NonDivergent obj = new ScriptField_NonDivergent(rs);
+        Type t = tb.create();
+        if (t.getElement() != obj.mElement) {
+            throw new RSIllegalArgumentException("Type.Builder did not match expected element type.");
+        }
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    private void copyToArrayLocal(Item i, FieldPacker fp) {
+        fp.addI32(i.i);
+        fp.addI32(i.j);
+    }
+
+    private void copyToArray(Item i, int index) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        mIOBuffer.reset(index * mElement.getBytesSize());
+        copyToArrayLocal(i, mIOBuffer);
+    }
+
+    public synchronized void set(Item i, int index, boolean copyNow) {
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        mItemArray[index] = i;
+        if (copyNow)  {
+            copyToArray(i, index);
+            FieldPacker fp = new FieldPacker(mElement.getBytesSize());
+            copyToArrayLocal(i, fp);
+            mAllocation.setFromFieldPacker(index, fp);
+        }
+
+    }
+
+    public synchronized Item get(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index];
+    }
+
+    public synchronized void set_i(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].i = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize());
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, 0, fp);
+        }
+
+    }
+
+    public synchronized void set_j(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].j = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + 4);
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, 1, fp);
+        }
+
+    }
+
+    public synchronized int get_i(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].i;
+    }
+
+    public synchronized int get_j(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].j;
+    }
+
+    public synchronized void copyAll() {
+        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
+        mAllocation.setFromFieldPacker(0, mIOBuffer);
+    }
+
+    public synchronized void resize(int newSize) {
+        if (mItemArray != null)  {
+            int oldSize = mItemArray.length;
+            int copySize = Math.min(oldSize, newSize);
+            if (newSize == oldSize) return;
+            Item ni[] = new Item[newSize];
+            System.arraycopy(mItemArray, 0, ni, 0, copySize);
+            mItemArray = ni;
+        }
+
+        mAllocation.resize(newSize);
+        if (mIOBuffer != null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+    }
+
+}
+
diff --git a/tests/P_reflection3264_divergent/reflection3264_divergent.rs b/tests/P_reflection3264_divergent/reflection3264_divergent.rs
new file mode 100644
index 0000000..05a43a5
--- /dev/null
+++ b/tests/P_reflection3264_divergent/reflection3264_divergent.rs
@@ -0,0 +1,75 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+// "Divergent" = reflected code must have a runtime check for 32-bit
+// versus 64-bit target.
+
+// non-divergent
+int intVar;
+
+// non-divergent
+int intArray[10];
+
+// non-divergent
+rs_matrix2x2 matVar;
+
+// non-divergent
+rs_matrix2x2 matArray[10];
+
+// divergent
+rs_allocation allocVar;
+
+// divergent
+rs_allocation allocArray[10];
+
+struct NonDivergent {
+  int i;
+  int j;
+};
+
+struct NonDivergent ndVar;
+
+struct NonDivergent ndArray[10];
+
+// 32-bit: 12 bytes; 64-bit: 48 bytes
+struct Divergent {
+  int i;
+  rs_allocation a;
+  int j;
+};
+
+struct Divergent dVar;
+
+struct Divergent dArray[10];
+
+// 32-bit: 20 bytes; 64-bit: 64 bytes
+struct DivergentNest {
+  int x;
+  struct Divergent d;
+  int y;
+};
+
+struct DivergentNest dnVar;
+
+struct DivergentNest dnArray[10];
+
+void intFe(const int *in, int *out, const int *data) { }
+
+void matFe(const int *in, int *out, const rs_matrix2x2 *data) { }
+
+void allocFe(const int *in, int *out, const rs_allocation *data) { }
+
+void ndFe(const int *in, int *out, const struct NonDivergent *data) { }
+
+void dFe(const int *in, int *out, const struct Divergent *data) { }
+
+void dnFe(const int *in, int *out, const struct DivergentNest *data) { }
+
+// for arguments, should get a helper struct that looks like struct NonDivergent
+void ndInv(int i, int j) { }
+
+// for arguments, should get a helper struct that looks like struct Divergent
+void dInv(int i, rs_allocation a, int j) { }
+
+// for arguments, should get a helper struct that looks like struct DivergentNest
+void dnInv(int x, struct Divergent d, int y) { }
diff --git a/tests/P_reflection3264_divergent/stderr.txt.expect b/tests/P_reflection3264_divergent/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_reflection3264_divergent/stderr.txt.expect
diff --git a/tests/P_reflection3264_divergent/stdout.txt.expect b/tests/P_reflection3264_divergent/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_reflection3264_divergent/stdout.txt.expect
diff --git a/tests/P_reflection3264_divergent_support/ScriptC_reflection3264_divergent.java.expect b/tests/P_reflection3264_divergent_support/ScriptC_reflection3264_divergent.java.expect
new file mode 100644
index 0000000..6d68c35
--- /dev/null
+++ b/tests/P_reflection3264_divergent_support/ScriptC_reflection3264_divergent.java.expect
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_divergent.rs
+ */
+
+package foo;
+
+import android.support.v8.renderscript.*;
+import foo.reflection3264_divergentBitCode;
+
+/**
+ * @hide
+ */
+public class ScriptC_reflection3264_divergent extends ScriptC {
+    private static final String __rs_resource_name = "reflection3264_divergent";
+    // Constructor
+    public  ScriptC_reflection3264_divergent(RenderScript rs) {
+        super(rs,
+              __rs_resource_name,
+              reflection3264_divergentBitCode.getBitCode32(),
+              reflection3264_divergentBitCode.getBitCode64());
+        __I32 = Element.I32(rs);
+        __@@INVALID@@ = Element.@@INVALID@@(rs);
+        __ALLOCATION = Element.ALLOCATION(rs);
+        __ScriptField_NonDivergent = ScriptField_NonDivergent.createElement(rs);
+        __ScriptField_Divergent = ScriptField_Divergent.createElement(rs);
+        __ScriptField_DivergentNest = ScriptField_DivergentNest.createElement(rs);
+    }
+
+    private Element __@@INVALID@@;
+    private Element __ALLOCATION;
+    private Element __I32;
+    private Element __ScriptField_Divergent;
+    private Element __ScriptField_DivergentNest;
+    private Element __ScriptField_NonDivergent;
+    private FieldPacker __rs_fp_@@INVALID@@;
+    private FieldPacker __rs_fp_ALLOCATION;
+    private FieldPacker __rs_fp_I32;
+    private FieldPacker __rs_fp_ScriptField_Divergent;
+    private FieldPacker __rs_fp_ScriptField_DivergentNest;
+    private FieldPacker __rs_fp_ScriptField_NonDivergent;
+    private final static int mExportVarIdx_intVar = 0;
+    private int mExportVar_intVar;
+    public synchronized void set_intVar(int v) {
+        setVar(mExportVarIdx_intVar, v);
+        mExportVar_intVar = v;
+    }
+
+    public int get_intVar() {
+        return mExportVar_intVar;
+    }
+
+    public Script.FieldID getFieldID_intVar() {
+        return createFieldID(mExportVarIdx_intVar, null);
+    }
+
+    private final static int mExportVarIdx_intArray = 1;
+    private int[] mExportVar_intArray;
+    public synchronized void set_intArray(int[] v) {
+        mExportVar_intArray = v;
+        FieldPacker fp = new FieldPacker(40);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_intArray, fp, __I32, __dimArr);
+    }
+
+    public int[] get_intArray() {
+        return mExportVar_intArray;
+    }
+
+    public Script.FieldID getFieldID_intArray() {
+        return createFieldID(mExportVarIdx_intArray, null);
+    }
+
+    private final static int mExportVarIdx_matVar = 2;
+    private Matrix2f mExportVar_matVar;
+    public synchronized void set_matVar(Matrix2f v) {
+        mExportVar_matVar = v;
+        FieldPacker fp = new FieldPacker(16);
+        fp.addMatrix(v);
+        setVar(mExportVarIdx_matVar, fp);
+    }
+
+    public Matrix2f get_matVar() {
+        return mExportVar_matVar;
+    }
+
+    public Script.FieldID getFieldID_matVar() {
+        return createFieldID(mExportVarIdx_matVar, null);
+    }
+
+    private final static int mExportVarIdx_matArray = 3;
+    private Matrix2f[] mExportVar_matArray;
+    public synchronized void set_matArray(Matrix2f[] v) {
+        mExportVar_matArray = v;
+        FieldPacker fp = new FieldPacker(160);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addMatrix(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_matArray, fp, __@@INVALID@@, __dimArr);
+    }
+
+    public Matrix2f[] get_matArray() {
+        return mExportVar_matArray;
+    }
+
+    public Script.FieldID getFieldID_matArray() {
+        return createFieldID(mExportVarIdx_matArray, null);
+    }
+
+    private final static int mExportVarIdx_allocVar = 4;
+    private Allocation mExportVar_allocVar;
+    public synchronized void set_allocVar(Allocation v) {
+        setVar(mExportVarIdx_allocVar, v);
+        mExportVar_allocVar = v;
+    }
+
+    public Allocation get_allocVar() {
+        return mExportVar_allocVar;
+    }
+
+    public Script.FieldID getFieldID_allocVar() {
+        return createFieldID(mExportVarIdx_allocVar, null);
+    }
+
+    private final static int mExportVarIdx_allocArray = 5;
+    private Allocation[] mExportVar_allocArray;
+    public synchronized void set_allocArray(Allocation[] v) {
+        mExportVar_allocArray = v;
+        FieldPacker fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 320 : 40);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addObj(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_allocArray, fp, __ALLOCATION, __dimArr);
+    }
+
+    public Allocation[] get_allocArray() {
+        return mExportVar_allocArray;
+    }
+
+    public Script.FieldID getFieldID_allocArray() {
+        return createFieldID(mExportVarIdx_allocArray, null);
+    }
+
+    private final static int mExportVarIdx_ndVar = 6;
+    private ScriptField_NonDivergent.Item mExportVar_ndVar;
+    public synchronized void set_ndVar(ScriptField_NonDivergent.Item v) {
+        mExportVar_ndVar = v;
+        FieldPacker fp = new FieldPacker(8);
+        fp.addI32(v.i);
+        fp.addI32(v.j);
+        int []__dimArr = new int[1];
+        __dimArr[0] = 1;
+        setVar(mExportVarIdx_ndVar, fp, __ScriptField_NonDivergent, __dimArr);
+    }
+
+    public ScriptField_NonDivergent.Item get_ndVar() {
+        return mExportVar_ndVar;
+    }
+
+    public Script.FieldID getFieldID_ndVar() {
+        return createFieldID(mExportVarIdx_ndVar, null);
+    }
+
+    private final static int mExportVarIdx_ndArray = 7;
+    private ScriptField_NonDivergent.Item[] mExportVar_ndArray;
+    public synchronized void set_ndArray(ScriptField_NonDivergent.Item[] v) {
+        mExportVar_ndArray = v;
+        FieldPacker fp = new FieldPacker(80);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1].i);
+            fp.addI32(v[ct1].j);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_ndArray, fp, __ScriptField_NonDivergent, __dimArr);
+    }
+
+    public ScriptField_NonDivergent.Item[] get_ndArray() {
+        return mExportVar_ndArray;
+    }
+
+    public Script.FieldID getFieldID_ndArray() {
+        return createFieldID(mExportVarIdx_ndArray, null);
+    }
+
+    private final static int mExportVarIdx_dVar = 8;
+    private ScriptField_Divergent.Item mExportVar_dVar;
+    public synchronized void set_dVar(ScriptField_Divergent.Item v) {
+        mExportVar_dVar = v;
+        FieldPacker fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 48 : 12);
+        fp.addI32(v.i);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        fp.addObj(v.a);
+        fp.addI32(v.j);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        int []__dimArr = new int[1];
+        __dimArr[0] = 1;
+        setVar(mExportVarIdx_dVar, fp, __ScriptField_Divergent, __dimArr);
+    }
+
+    public ScriptField_Divergent.Item get_dVar() {
+        return mExportVar_dVar;
+    }
+
+    public Script.FieldID getFieldID_dVar() {
+        return createFieldID(mExportVarIdx_dVar, null);
+    }
+
+    private final static int mExportVarIdx_dArray = 9;
+    private ScriptField_Divergent.Item[] mExportVar_dArray;
+    public synchronized void set_dArray(ScriptField_Divergent.Item[] v) {
+        mExportVar_dArray = v;
+        FieldPacker fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 400 : 120);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1].i);
+            fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+            fp.addObj(v[ct1].a);
+            fp.addI32(v[ct1].j);
+            fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_dArray, fp, __ScriptField_Divergent, __dimArr);
+    }
+
+    public ScriptField_Divergent.Item[] get_dArray() {
+        return mExportVar_dArray;
+    }
+
+    public Script.FieldID getFieldID_dArray() {
+        return createFieldID(mExportVarIdx_dArray, null);
+    }
+
+    private final static int mExportVarIdx_dnVar = 10;
+    private ScriptField_DivergentNest.Item mExportVar_dnVar;
+    public synchronized void set_dnVar(ScriptField_DivergentNest.Item v) {
+        mExportVar_dnVar = v;
+        FieldPacker fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 64 : 20);
+        fp.addI32(v.x);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        fp.addI32(v.d.i);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        fp.addObj(v.d.a);
+        fp.addI32(v.d.j);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        fp.addI32(v.y);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        int []__dimArr = new int[1];
+        __dimArr[0] = 1;
+        setVar(mExportVarIdx_dnVar, fp, __ScriptField_DivergentNest, __dimArr);
+    }
+
+    public ScriptField_DivergentNest.Item get_dnVar() {
+        return mExportVar_dnVar;
+    }
+
+    public Script.FieldID getFieldID_dnVar() {
+        return createFieldID(mExportVarIdx_dnVar, null);
+    }
+
+    private final static int mExportVarIdx_dnArray = 11;
+    private ScriptField_DivergentNest.Item[] mExportVar_dnArray;
+    public synchronized void set_dnArray(ScriptField_DivergentNest.Item[] v) {
+        mExportVar_dnArray = v;
+        FieldPacker fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 480 : 200);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1].x);
+            fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+            fp.addI32(v[ct1].d.i);
+            fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+            fp.addObj(v[ct1].d.a);
+            fp.addI32(v[ct1].d.j);
+            fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+            fp.addI32(v[ct1].y);
+            fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_dnArray, fp, __ScriptField_DivergentNest, __dimArr);
+    }
+
+    public ScriptField_DivergentNest.Item[] get_dnArray() {
+        return mExportVar_dnArray;
+    }
+
+    public Script.FieldID getFieldID_dnArray() {
+        return createFieldID(mExportVarIdx_dnArray, null);
+    }
+
+    //private final static int mExportForEachIdx_root = 0;
+    private final static int mExportForEachIdx_dnFe = 1;
+    public Script.KernelID getKernelID_dnFe() {
+        return createKernelID(mExportForEachIdx_dnFe, 7, null, null);
+    }
+
+    public void forEach_dnFe(Allocation ain, Allocation aout, ScriptField_DivergentNest.Item data) {
+        forEach_dnFe(ain, aout, data, null);
+    }
+
+    public void forEach_dnFe(Allocation ain, Allocation aout, ScriptField_DivergentNest.Item data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker dnFe_fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 64 : 20);
+        dnFe_fp.addI32(data.x);
+        dnFe_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        dnFe_fp.addI32(data.d.i);
+        dnFe_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        dnFe_fp.addObj(data.d.a);
+        dnFe_fp.addI32(data.d.j);
+        dnFe_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        dnFe_fp.addI32(data.y);
+        dnFe_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        forEach(mExportForEachIdx_dnFe, ain, aout, dnFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_dFe = 2;
+    public Script.KernelID getKernelID_dFe() {
+        return createKernelID(mExportForEachIdx_dFe, 7, null, null);
+    }
+
+    public void forEach_dFe(Allocation ain, Allocation aout, ScriptField_Divergent.Item data) {
+        forEach_dFe(ain, aout, data, null);
+    }
+
+    public void forEach_dFe(Allocation ain, Allocation aout, ScriptField_Divergent.Item data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker dFe_fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 48 : 12);
+        dFe_fp.addI32(data.i);
+        dFe_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        dFe_fp.addObj(data.a);
+        dFe_fp.addI32(data.j);
+        dFe_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        forEach(mExportForEachIdx_dFe, ain, aout, dFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_ndFe = 3;
+    public Script.KernelID getKernelID_ndFe() {
+        return createKernelID(mExportForEachIdx_ndFe, 7, null, null);
+    }
+
+    public void forEach_ndFe(Allocation ain, Allocation aout, ScriptField_NonDivergent.Item data) {
+        forEach_ndFe(ain, aout, data, null);
+    }
+
+    public void forEach_ndFe(Allocation ain, Allocation aout, ScriptField_NonDivergent.Item data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker ndFe_fp = new FieldPacker(8);
+        ndFe_fp.addI32(data.i);
+        ndFe_fp.addI32(data.j);
+        forEach(mExportForEachIdx_ndFe, ain, aout, ndFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_allocFe = 4;
+    public Script.KernelID getKernelID_allocFe() {
+        return createKernelID(mExportForEachIdx_allocFe, 7, null, null);
+    }
+
+    public void forEach_allocFe(Allocation ain, Allocation aout, Allocation data) {
+        forEach_allocFe(ain, aout, data, null);
+    }
+
+    public void forEach_allocFe(Allocation ain, Allocation aout, Allocation data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker allocFe_fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 32 : 4);
+        allocFe_fp.addObj(data);
+        forEach(mExportForEachIdx_allocFe, ain, aout, allocFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_matFe = 5;
+    public Script.KernelID getKernelID_matFe() {
+        return createKernelID(mExportForEachIdx_matFe, 7, null, null);
+    }
+
+    public void forEach_matFe(Allocation ain, Allocation aout, Matrix2f data) {
+        forEach_matFe(ain, aout, data, null);
+    }
+
+    public void forEach_matFe(Allocation ain, Allocation aout, Matrix2f data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker matFe_fp = new FieldPacker(16);
+        matFe_fp.addMatrix(data);
+        forEach(mExportForEachIdx_matFe, ain, aout, matFe_fp, sc);
+    }
+
+    private final static int mExportForEachIdx_intFe = 6;
+    public Script.KernelID getKernelID_intFe() {
+        return createKernelID(mExportForEachIdx_intFe, 7, null, null);
+    }
+
+    public void forEach_intFe(Allocation ain, Allocation aout, int data) {
+        forEach_intFe(ain, aout, data, null);
+    }
+
+    public void forEach_intFe(Allocation ain, Allocation aout, int data, Script.LaunchOptions sc) {
+        // check ain
+        if (!ain.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        // check aout
+        if (!aout.getType().getElement().isCompatible(__I32)) {
+            throw new RSRuntimeException("Type mismatch with I32!");
+        }
+        Type t0, t1;        // Verify dimensions
+        t0 = ain.getType();
+        t1 = aout.getType();
+        if ((t0.getCount() != t1.getCount()) ||
+            (t0.getX() != t1.getX()) ||
+            (t0.getY() != t1.getY()) ||
+            (t0.getZ() != t1.getZ()) ||
+            (t0.hasFaces()   != t1.hasFaces()) ||
+            (t0.hasMipmaps() != t1.hasMipmaps())) {
+            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
+        }
+
+        FieldPacker intFe_fp = new FieldPacker(4);
+        intFe_fp.addI32(data);
+        forEach(mExportForEachIdx_intFe, ain, aout, intFe_fp, sc);
+    }
+
+    private final static int mExportFuncIdx_ndInv = 0;
+    public Script.InvokeID getInvokeID_ndInv() {
+        return createInvokeID(mExportFuncIdx_ndInv);
+    }
+
+    public void invoke_ndInv(int i, int j) {
+        FieldPacker ndInv_fp = new FieldPacker(8);
+        ndInv_fp.addI32(i);
+        ndInv_fp.addI32(j);
+        invoke(mExportFuncIdx_ndInv, ndInv_fp);
+    }
+
+    private final static int mExportFuncIdx_dInv = 1;
+    public Script.InvokeID getInvokeID_dInv() {
+        return createInvokeID(mExportFuncIdx_dInv);
+    }
+
+    public void invoke_dInv(int i, Allocation a, int j) {
+        FieldPacker dInv_fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 48 : 12);
+        dInv_fp.addI32(i);
+        dInv_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        dInv_fp.addObj(a);
+        dInv_fp.addI32(j);
+        dInv_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        invoke(mExportFuncIdx_dInv, dInv_fp);
+    }
+
+    private final static int mExportFuncIdx_dnInv = 2;
+    public Script.InvokeID getInvokeID_dnInv() {
+        return createInvokeID(mExportFuncIdx_dnInv);
+    }
+
+    public void invoke_dnInv(int x, ScriptField_Divergent.Item d, int y) {
+        FieldPacker dnInv_fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 64 : 20);
+        dnInv_fp.addI32(x);
+        dnInv_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        dnInv_fp.addI32(d.i);
+        dnInv_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        dnInv_fp.addObj(d.a);
+        dnInv_fp.addI32(d.j);
+        dnInv_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        dnInv_fp.addI32(y);
+        dnInv_fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        invoke(mExportFuncIdx_dnInv, dnInv_fp);
+    }
+
+}
+
diff --git a/tests/P_reflection3264_divergent_support/ScriptField_Divergent.java.expect b/tests/P_reflection3264_divergent_support/ScriptField_Divergent.java.expect
new file mode 100644
index 0000000..dc5e6c0
--- /dev/null
+++ b/tests/P_reflection3264_divergent_support/ScriptField_Divergent.java.expect
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_divergent.rs
+ */
+
+package foo;
+
+import android.support.v8.renderscript.*;
+import foo.reflection3264_divergentBitCode;
+
+/**
+ * @hide
+ */
+public class ScriptField_Divergent extends android.support.v8.renderscript.Script.FieldBase {
+    static public class Item {
+
+        int i;
+        Allocation a;
+        int j;
+
+        Item() {
+        }
+
+    }
+
+    private Item mItemArray[];
+    private FieldPacker mIOBuffer;
+    private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null);
+    public static Element createElement(RenderScript rs) {
+        Element.Builder eb = new Element.Builder(rs);
+        eb.add(Element.I32(rs), "i");
+        if (RenderScript.getPointerSize() == 8) {
+            eb.add(Element.U32(rs), "#rs_padding_1");
+        }
+
+        eb.add(Element.ALLOCATION(rs), "a");
+        eb.add(Element.I32(rs), "j");
+        if (RenderScript.getPointerSize() == 8) {
+            eb.add(Element.U32(rs), "#rs_padding_2");
+        }
+
+        return eb.create();
+    }
+
+    private  ScriptField_Divergent(RenderScript rs) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+    }
+
+    public  ScriptField_Divergent(RenderScript rs, int count) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count);
+    }
+
+    public  ScriptField_Divergent(RenderScript rs, int count, int usages) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count, usages);
+    }
+
+    public static ScriptField_Divergent create1D(RenderScript rs, int dimX, int usages) {
+        ScriptField_Divergent obj = new ScriptField_Divergent(rs);
+        obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages);
+        return obj;
+    }
+
+    public static ScriptField_Divergent create1D(RenderScript rs, int dimX) {
+        return create1D(rs, dimX, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_Divergent create2D(RenderScript rs, int dimX, int dimY) {
+        return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_Divergent create2D(RenderScript rs, int dimX, int dimY, int usages) {
+        ScriptField_Divergent obj = new ScriptField_Divergent(rs);
+        Type.Builder b = new Type.Builder(rs, obj.mElement);
+        b.setX(dimX);
+        b.setY(dimY);
+        Type t = b.create();
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    public static Type.Builder createTypeBuilder(RenderScript rs) {
+        Element e = createElement(rs);
+        return new Type.Builder(rs, e);
+    }
+
+    public static ScriptField_Divergent createCustom(RenderScript rs, Type.Builder tb, int usages) {
+        ScriptField_Divergent obj = new ScriptField_Divergent(rs);
+        Type t = tb.create();
+        if (t.getElement() != obj.mElement) {
+            throw new RSIllegalArgumentException("Type.Builder did not match expected element type.");
+        }
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    private void copyToArrayLocal(Item i, FieldPacker fp) {
+        fp.addI32(i.i);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        fp.addObj(i.a);
+        fp.addI32(i.j);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+    }
+
+    private void copyToArray(Item i, int index) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        mIOBuffer.reset(index * mElement.getBytesSize());
+        copyToArrayLocal(i, mIOBuffer);
+    }
+
+    public synchronized void set(Item i, int index, boolean copyNow) {
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        mItemArray[index] = i;
+        if (copyNow)  {
+            copyToArray(i, index);
+            FieldPacker fp = new FieldPacker(mElement.getBytesSize());
+            copyToArrayLocal(i, fp);
+            mAllocation.setFromFieldPacker(index, fp);
+        }
+
+    }
+
+    public synchronized Item get(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index];
+    }
+
+    public synchronized void set_i(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].i = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize());
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, 0, fp);
+        }
+
+    }
+
+    public synchronized void set_a(int index, Allocation v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].a = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + ((RenderScript.getPointerSize() == 8) ? 8 : 4));
+            mIOBuffer.addObj(v);
+            FieldPacker fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 32 : 4);
+            fp.addObj(v);
+            mAllocation.setFromFieldPacker(index, (RenderScript.getPointerSize() == 8) ? 2 : 1, fp);
+        }
+
+    }
+
+    public synchronized void set_j(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].j = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + ((RenderScript.getPointerSize() == 8) ? 40 : 8));
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, (RenderScript.getPointerSize() == 8) ? 3 : 2, fp);
+        }
+
+    }
+
+    public synchronized int get_i(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].i;
+    }
+
+    public synchronized Allocation get_a(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index].a;
+    }
+
+    public synchronized int get_j(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].j;
+    }
+
+    public synchronized void copyAll() {
+        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
+        mAllocation.setFromFieldPacker(0, mIOBuffer);
+    }
+
+}
+
diff --git a/tests/P_reflection3264_divergent_support/ScriptField_DivergentNest.java.expect b/tests/P_reflection3264_divergent_support/ScriptField_DivergentNest.java.expect
new file mode 100644
index 0000000..80df1cd
--- /dev/null
+++ b/tests/P_reflection3264_divergent_support/ScriptField_DivergentNest.java.expect
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_divergent.rs
+ */
+
+package foo;
+
+import android.support.v8.renderscript.*;
+import foo.reflection3264_divergentBitCode;
+
+/**
+ * @hide
+ */
+public class ScriptField_DivergentNest extends android.support.v8.renderscript.Script.FieldBase {
+    static public class Item {
+
+        int x;
+        ScriptField_Divergent.Item d;
+        int y;
+
+        Item() {
+            d = new ScriptField_Divergent.Item();
+        }
+
+    }
+
+    private Item mItemArray[];
+    private FieldPacker mIOBuffer;
+    private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null);
+    public static Element createElement(RenderScript rs) {
+        Element.Builder eb = new Element.Builder(rs);
+        eb.add(Element.I32(rs), "x");
+        if (RenderScript.getPointerSize() == 8) {
+            eb.add(Element.U32(rs), "#rs_padding_1");
+        }
+
+        eb.add(ScriptField_Divergent.createElement(rs), "d");
+        eb.add(Element.I32(rs), "y");
+        if (RenderScript.getPointerSize() == 8) {
+            eb.add(Element.U32(rs), "#rs_padding_2");
+        }
+
+        return eb.create();
+    }
+
+    private  ScriptField_DivergentNest(RenderScript rs) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+    }
+
+    public  ScriptField_DivergentNest(RenderScript rs, int count) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count);
+    }
+
+    public  ScriptField_DivergentNest(RenderScript rs, int count, int usages) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count, usages);
+    }
+
+    public static ScriptField_DivergentNest create1D(RenderScript rs, int dimX, int usages) {
+        ScriptField_DivergentNest obj = new ScriptField_DivergentNest(rs);
+        obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages);
+        return obj;
+    }
+
+    public static ScriptField_DivergentNest create1D(RenderScript rs, int dimX) {
+        return create1D(rs, dimX, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_DivergentNest create2D(RenderScript rs, int dimX, int dimY) {
+        return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_DivergentNest create2D(RenderScript rs, int dimX, int dimY, int usages) {
+        ScriptField_DivergentNest obj = new ScriptField_DivergentNest(rs);
+        Type.Builder b = new Type.Builder(rs, obj.mElement);
+        b.setX(dimX);
+        b.setY(dimY);
+        Type t = b.create();
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    public static Type.Builder createTypeBuilder(RenderScript rs) {
+        Element e = createElement(rs);
+        return new Type.Builder(rs, e);
+    }
+
+    public static ScriptField_DivergentNest createCustom(RenderScript rs, Type.Builder tb, int usages) {
+        ScriptField_DivergentNest obj = new ScriptField_DivergentNest(rs);
+        Type t = tb.create();
+        if (t.getElement() != obj.mElement) {
+            throw new RSIllegalArgumentException("Type.Builder did not match expected element type.");
+        }
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    private void copyToArrayLocal(Item i, FieldPacker fp) {
+        fp.addI32(i.x);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        fp.addI32(i.d.i);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        fp.addObj(i.d.a);
+        fp.addI32(i.d.j);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+        fp.addI32(i.y);
+        fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+    }
+
+    private void copyToArray(Item i, int index) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        mIOBuffer.reset(index * mElement.getBytesSize());
+        copyToArrayLocal(i, mIOBuffer);
+    }
+
+    public synchronized void set(Item i, int index, boolean copyNow) {
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        mItemArray[index] = i;
+        if (copyNow)  {
+            copyToArray(i, index);
+            FieldPacker fp = new FieldPacker(mElement.getBytesSize());
+            copyToArrayLocal(i, fp);
+            mAllocation.setFromFieldPacker(index, fp);
+        }
+
+    }
+
+    public synchronized Item get(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index];
+    }
+
+    public synchronized void set_x(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].x = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize());
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, 0, fp);
+        }
+
+    }
+
+    public synchronized void set_d(int index, ScriptField_Divergent.Item v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].d = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + ((RenderScript.getPointerSize() == 8) ? 8 : 4));
+            mIOBuffer.addI32(v.i);
+            mIOBuffer.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+            mIOBuffer.addObj(v.a);
+            mIOBuffer.addI32(v.j);
+            mIOBuffer.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+            FieldPacker fp = new FieldPacker((RenderScript.getPointerSize() == 8) ? 48 : 12);
+            fp.addI32(v.i);
+            fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+            fp.addObj(v.a);
+            fp.addI32(v.j);
+            fp.skip((RenderScript.getPointerSize() == 8) ? 4 : 0);
+            mAllocation.setFromFieldPacker(index, (RenderScript.getPointerSize() == 8) ? 2 : 1, fp);
+        }
+
+    }
+
+    public synchronized void set_y(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].y = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + ((RenderScript.getPointerSize() == 8) ? 56 : 16));
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, (RenderScript.getPointerSize() == 8) ? 3 : 2, fp);
+        }
+
+    }
+
+    public synchronized int get_x(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].x;
+    }
+
+    public synchronized ScriptField_Divergent.Item get_d(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index].d;
+    }
+
+    public synchronized int get_y(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].y;
+    }
+
+    public synchronized void copyAll() {
+        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
+        mAllocation.setFromFieldPacker(0, mIOBuffer);
+    }
+
+}
+
diff --git a/tests/P_reflection3264_divergent_support/ScriptField_NonDivergent.java.expect b/tests/P_reflection3264_divergent_support/ScriptField_NonDivergent.java.expect
new file mode 100644
index 0000000..64559c3
--- /dev/null
+++ b/tests/P_reflection3264_divergent_support/ScriptField_NonDivergent.java.expect
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_divergent.rs
+ */
+
+package foo;
+
+import android.support.v8.renderscript.*;
+import foo.reflection3264_divergentBitCode;
+
+/**
+ * @hide
+ */
+public class ScriptField_NonDivergent extends android.support.v8.renderscript.Script.FieldBase {
+    static public class Item {
+
+        int i;
+        int j;
+
+        Item() {
+        }
+
+    }
+
+    private Item mItemArray[];
+    private FieldPacker mIOBuffer;
+    private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null);
+    public static Element createElement(RenderScript rs) {
+        Element.Builder eb = new Element.Builder(rs);
+        eb.add(Element.I32(rs), "i");
+        eb.add(Element.I32(rs), "j");
+        return eb.create();
+    }
+
+    private  ScriptField_NonDivergent(RenderScript rs) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+    }
+
+    public  ScriptField_NonDivergent(RenderScript rs, int count) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count);
+    }
+
+    public  ScriptField_NonDivergent(RenderScript rs, int count, int usages) {
+        mItemArray = null;
+        mIOBuffer = null;
+        mElement = createElement(rs);
+        init(rs, count, usages);
+    }
+
+    public static ScriptField_NonDivergent create1D(RenderScript rs, int dimX, int usages) {
+        ScriptField_NonDivergent obj = new ScriptField_NonDivergent(rs);
+        obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages);
+        return obj;
+    }
+
+    public static ScriptField_NonDivergent create1D(RenderScript rs, int dimX) {
+        return create1D(rs, dimX, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_NonDivergent create2D(RenderScript rs, int dimX, int dimY) {
+        return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT);
+    }
+
+    public static ScriptField_NonDivergent create2D(RenderScript rs, int dimX, int dimY, int usages) {
+        ScriptField_NonDivergent obj = new ScriptField_NonDivergent(rs);
+        Type.Builder b = new Type.Builder(rs, obj.mElement);
+        b.setX(dimX);
+        b.setY(dimY);
+        Type t = b.create();
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    public static Type.Builder createTypeBuilder(RenderScript rs) {
+        Element e = createElement(rs);
+        return new Type.Builder(rs, e);
+    }
+
+    public static ScriptField_NonDivergent createCustom(RenderScript rs, Type.Builder tb, int usages) {
+        ScriptField_NonDivergent obj = new ScriptField_NonDivergent(rs);
+        Type t = tb.create();
+        if (t.getElement() != obj.mElement) {
+            throw new RSIllegalArgumentException("Type.Builder did not match expected element type.");
+        }
+        obj.mAllocation = Allocation.createTyped(rs, t, usages);
+        return obj;
+    }
+
+    private void copyToArrayLocal(Item i, FieldPacker fp) {
+        fp.addI32(i.i);
+        fp.addI32(i.j);
+    }
+
+    private void copyToArray(Item i, int index) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        mIOBuffer.reset(index * mElement.getBytesSize());
+        copyToArrayLocal(i, mIOBuffer);
+    }
+
+    public synchronized void set(Item i, int index, boolean copyNow) {
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        mItemArray[index] = i;
+        if (copyNow)  {
+            copyToArray(i, index);
+            FieldPacker fp = new FieldPacker(mElement.getBytesSize());
+            copyToArrayLocal(i, fp);
+            mAllocation.setFromFieldPacker(index, fp);
+        }
+
+    }
+
+    public synchronized Item get(int index) {
+        if (mItemArray == null) return null;
+        return mItemArray[index];
+    }
+
+    public synchronized void set_i(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].i = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize());
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, 0, fp);
+        }
+
+    }
+
+    public synchronized void set_j(int index, int v, boolean copyNow) {
+        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
+        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+        if (mItemArray[index] == null) mItemArray[index] = new Item();
+        mItemArray[index].j = v;
+        if (copyNow)  {
+            mIOBuffer.reset(index * mElement.getBytesSize() + 4);
+            mIOBuffer.addI32(v);
+            FieldPacker fp = new FieldPacker(4);
+            fp.addI32(v);
+            mAllocation.setFromFieldPacker(index, 1, fp);
+        }
+
+    }
+
+    public synchronized int get_i(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].i;
+    }
+
+    public synchronized int get_j(int index) {
+        if (mItemArray == null) return 0;
+        return mItemArray[index].j;
+    }
+
+    public synchronized void copyAll() {
+        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
+        mAllocation.setFromFieldPacker(0, mIOBuffer);
+    }
+
+}
+
diff --git a/tests/P_reflection3264_divergent_support/reflection3264_divergent.rs b/tests/P_reflection3264_divergent_support/reflection3264_divergent.rs
new file mode 100644
index 0000000..4dff5df
--- /dev/null
+++ b/tests/P_reflection3264_divergent_support/reflection3264_divergent.rs
@@ -0,0 +1,77 @@
+// -rs-package-name android.support.v8.renderscript
+
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+// "Divergent" = reflected code must have a runtime check for 32-bit
+// versus 64-bit target.
+
+// non-divergent
+int intVar;
+
+// non-divergent
+int intArray[10];
+
+// non-divergent
+rs_matrix2x2 matVar;
+
+// non-divergent
+rs_matrix2x2 matArray[10];
+
+// divergent
+rs_allocation allocVar;
+
+// divergent
+rs_allocation allocArray[10];
+
+struct NonDivergent {
+  int i;
+  int j;
+};
+
+struct NonDivergent ndVar;
+
+struct NonDivergent ndArray[10];
+
+// 32-bit: 12 bytes; 64-bit: 48 bytes
+struct Divergent {
+  int i;
+  rs_allocation a;
+  int j;
+};
+
+struct Divergent dVar;
+
+struct Divergent dArray[10];
+
+// 32-bit: 20 bytes; 64-bit: 64 bytes
+struct DivergentNest {
+  int x;
+  struct Divergent d;
+  int y;
+};
+
+struct DivergentNest dnVar;
+
+struct DivergentNest dnArray[10];
+
+void intFe(const int *in, int *out, const int *data) { }
+
+void matFe(const int *in, int *out, const rs_matrix2x2 *data) { }
+
+void allocFe(const int *in, int *out, const rs_allocation *data) { }
+
+void ndFe(const int *in, int *out, const struct NonDivergent *data) { }
+
+void dFe(const int *in, int *out, const struct Divergent *data) { }
+
+void dnFe(const int *in, int *out, const struct DivergentNest *data) { }
+
+// for arguments, should get a helper struct that looks like struct NonDivergent
+void ndInv(int i, int j) { }
+
+// for arguments, should get a helper struct that looks like struct Divergent
+void dInv(int i, rs_allocation a, int j) { }
+
+// for arguments, should get a helper struct that looks like struct DivergentNest
+void dnInv(int x, struct Divergent d, int y) { }
diff --git a/tests/P_reflection3264_divergent_support/stderr.txt.expect b/tests/P_reflection3264_divergent_support/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_reflection3264_divergent_support/stderr.txt.expect
diff --git a/tests/P_reflection3264_divergent_support/stdout.txt.expect b/tests/P_reflection3264_divergent_support/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_reflection3264_divergent_support/stdout.txt.expect
diff --git a/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_1.java.expect b/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_1.java.expect
new file mode 100644
index 0000000..9637753
--- /dev/null
+++ b/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_1.java.expect
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_multifile_1.rs
+ */
+
+package foo;
+
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
+import android.renderscript.*;
+import foo.reflection3264_multifile_1BitCode;
+
+/**
+ * @hide
+ */
+public class ScriptC_reflection3264_multifile_1 extends ScriptC {
+    private static final String __rs_resource_name = "reflection3264_multifile_1";
+    // Constructor
+    public  ScriptC_reflection3264_multifile_1(RenderScript rs) {
+        super(rs,
+              __rs_resource_name,
+              reflection3264_multifile_1BitCode.getBitCode32(),
+              reflection3264_multifile_1BitCode.getBitCode64());
+        __I32 = Element.I32(rs);
+        __ALLOCATION = Element.ALLOCATION(rs);
+    }
+
+    private Element __ALLOCATION;
+    private Element __I32;
+    private FieldPacker __rs_fp_ALLOCATION;
+    private FieldPacker __rs_fp_I32;
+    private final static int mExportVarIdx_a = 0;
+    private int[] mExportVar_a;
+    public synchronized void set_a(int[] v) {
+        mExportVar_a = v;
+        FieldPacker fp = new FieldPacker(40);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_a, fp, __I32, __dimArr);
+    }
+
+    public int[] get_a() {
+        return mExportVar_a;
+    }
+
+    public Script.FieldID getFieldID_a() {
+        return createFieldID(mExportVarIdx_a, null);
+    }
+
+    private final static int mExportVarIdx_b = 1;
+    private Allocation[] mExportVar_b;
+    public synchronized void set_b(Allocation[] v) {
+        mExportVar_b = v;
+        FieldPacker fp = new FieldPacker(sIs64Bit ? 320 : 40);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addObj(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_b, fp, __ALLOCATION, __dimArr);
+    }
+
+    public Allocation[] get_b() {
+        return mExportVar_b;
+    }
+
+    public Script.FieldID getFieldID_b() {
+        return createFieldID(mExportVarIdx_b, null);
+    }
+
+    private final static int mExportFuncIdx_f = 0;
+    public Script.InvokeID getInvokeID_f() {
+        return createInvokeID(mExportFuncIdx_f);
+    }
+
+    public void invoke_f(int c, Allocation d, int e) {
+        FieldPacker f_fp = new FieldPacker(sIs64Bit ? 48 : 12);
+        f_fp.addI32(c);
+        f_fp.skip(sIs64Bit ? 4 : 0);
+        f_fp.addObj(d);
+        f_fp.addI32(e);
+        f_fp.skip(sIs64Bit ? 4 : 0);
+        invoke(mExportFuncIdx_f, f_fp);
+    }
+
+    private static boolean sIs64Bit;
+
+    static {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            sIs64Bit = Process.is64Bit();
+        }
+
+        else {
+            try {
+                Field f = RenderScript.class.getDeclaredField("sPointerSize");
+                f.setAccessible(true);
+                sIs64Bit = (f.getInt(null) == 8);
+            }
+
+            catch (Throwable e) {
+                sIs64Bit = false;
+            }
+
+        }
+
+    }
+
+}
+
diff --git a/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_2.java.expect b/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_2.java.expect
new file mode 100644
index 0000000..4464559
--- /dev/null
+++ b/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_2.java.expect
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_multifile_2.rs
+ */
+
+package foo;
+
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
+import android.renderscript.*;
+import foo.reflection3264_multifile_2BitCode;
+
+/**
+ * @hide
+ */
+public class ScriptC_reflection3264_multifile_2 extends ScriptC {
+    private static final String __rs_resource_name = "reflection3264_multifile_2";
+    // Constructor
+    public  ScriptC_reflection3264_multifile_2(RenderScript rs) {
+        super(rs,
+              __rs_resource_name,
+              reflection3264_multifile_2BitCode.getBitCode32(),
+              reflection3264_multifile_2BitCode.getBitCode64());
+        __I16 = Element.I16(rs);
+        __I64 = Element.I64(rs);
+    }
+
+    private Element __I16;
+    private Element __I64;
+    private FieldPacker __rs_fp_I16;
+    private FieldPacker __rs_fp_I64;
+    private final static int mExportVarIdx_a = 0;
+    private short[] mExportVar_a;
+    public synchronized void set_a(short[] v) {
+        mExportVar_a = v;
+        FieldPacker fp = new FieldPacker(20);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI16(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_a, fp, __I16, __dimArr);
+    }
+
+    public short[] get_a() {
+        return mExportVar_a;
+    }
+
+    public Script.FieldID getFieldID_a() {
+        return createFieldID(mExportVarIdx_a, null);
+    }
+
+    private final static int mExportVarIdx_b = 1;
+    private long[] mExportVar_b;
+    public synchronized void set_b(long[] v) {
+        mExportVar_b = v;
+        FieldPacker fp = new FieldPacker(80);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI64(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_b, fp, __I64, __dimArr);
+    }
+
+    public long[] get_b() {
+        return mExportVar_b;
+    }
+
+    public Script.FieldID getFieldID_b() {
+        return createFieldID(mExportVarIdx_b, null);
+    }
+
+    private final static int mExportFuncIdx_g = 0;
+    public Script.InvokeID getInvokeID_g() {
+        return createInvokeID(mExportFuncIdx_g);
+    }
+
+    public void invoke_g(int c) {
+        FieldPacker g_fp = new FieldPacker(4);
+        g_fp.addI32(c);
+        invoke(mExportFuncIdx_g, g_fp);
+    }
+
+}
+
diff --git a/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_3.java.expect b/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_3.java.expect
new file mode 100644
index 0000000..7740bb5
--- /dev/null
+++ b/tests/P_reflection3264_multifile/ScriptC_reflection3264_multifile_3.java.expect
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2011-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file is auto-generated. DO NOT MODIFY!
+ * The source Renderscript file: reflection3264_multifile_3.rs
+ */
+
+package foo;
+
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
+import android.renderscript.*;
+import foo.reflection3264_multifile_3BitCode;
+
+/**
+ * @hide
+ */
+public class ScriptC_reflection3264_multifile_3 extends ScriptC {
+    private static final String __rs_resource_name = "reflection3264_multifile_3";
+    // Constructor
+    public  ScriptC_reflection3264_multifile_3(RenderScript rs) {
+        super(rs,
+              __rs_resource_name,
+              reflection3264_multifile_3BitCode.getBitCode32(),
+              reflection3264_multifile_3BitCode.getBitCode64());
+        __ALLOCATION = Element.ALLOCATION(rs);
+        __I32 = Element.I32(rs);
+    }
+
+    private Element __ALLOCATION;
+    private Element __I32;
+    private FieldPacker __rs_fp_ALLOCATION;
+    private FieldPacker __rs_fp_I32;
+    private final static int mExportVarIdx_a = 0;
+    private Allocation[] mExportVar_a;
+    public synchronized void set_a(Allocation[] v) {
+        mExportVar_a = v;
+        FieldPacker fp = new FieldPacker(sIs64Bit ? 320 : 40);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addObj(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_a, fp, __ALLOCATION, __dimArr);
+    }
+
+    public Allocation[] get_a() {
+        return mExportVar_a;
+    }
+
+    public Script.FieldID getFieldID_a() {
+        return createFieldID(mExportVarIdx_a, null);
+    }
+
+    private final static int mExportVarIdx_b = 1;
+    private int[] mExportVar_b;
+    public synchronized void set_b(int[] v) {
+        mExportVar_b = v;
+        FieldPacker fp = new FieldPacker(40);
+        for (int ct1 = 0; ct1 < 10; ct1++) {
+            fp.addI32(v[ct1]);
+        }
+
+        int []__dimArr = new int[1];
+        __dimArr[0] = 10;
+        setVar(mExportVarIdx_b, fp, __I32, __dimArr);
+    }
+
+    public int[] get_b() {
+        return mExportVar_b;
+    }
+
+    public Script.FieldID getFieldID_b() {
+        return createFieldID(mExportVarIdx_b, null);
+    }
+
+    private final static int mExportFuncIdx_h = 0;
+    public Script.InvokeID getInvokeID_h() {
+        return createInvokeID(mExportFuncIdx_h);
+    }
+
+    public void invoke_h(Allocation c, int d, Allocation e) {
+        FieldPacker h_fp = new FieldPacker(sIs64Bit ? 72 : 12);
+        h_fp.addObj(c);
+        h_fp.addI32(d);
+        h_fp.skip(sIs64Bit ? 4 : 0);
+        h_fp.addObj(e);
+        invoke(mExportFuncIdx_h, h_fp);
+    }
+
+    private static boolean sIs64Bit;
+
+    static {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            sIs64Bit = Process.is64Bit();
+        }
+
+        else {
+            try {
+                Field f = RenderScript.class.getDeclaredField("sPointerSize");
+                f.setAccessible(true);
+                sIs64Bit = (f.getInt(null) == 8);
+            }
+
+            catch (Throwable e) {
+                sIs64Bit = false;
+            }
+
+        }
+
+    }
+
+}
+
diff --git a/tests/P_reflection3264_multifile/reflection3264_multifile_1.rs b/tests/P_reflection3264_multifile/reflection3264_multifile_1.rs
new file mode 100644
index 0000000..c8bcd16
--- /dev/null
+++ b/tests/P_reflection3264_multifile/reflection3264_multifile_1.rs
@@ -0,0 +1,7 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+int a[10];
+rs_allocation b[10];
+
+void f(int c, rs_allocation d, int e) { }
diff --git a/tests/P_reflection3264_multifile/reflection3264_multifile_2.rs b/tests/P_reflection3264_multifile/reflection3264_multifile_2.rs
new file mode 100644
index 0000000..2b54e08
--- /dev/null
+++ b/tests/P_reflection3264_multifile/reflection3264_multifile_2.rs
@@ -0,0 +1,10 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+// no 32-bit versus 64-bit differences
+
+short a[10];
+long b[10];
+
+void g(int c) { }
+
diff --git a/tests/P_reflection3264_multifile/reflection3264_multifile_3.rs b/tests/P_reflection3264_multifile/reflection3264_multifile_3.rs
new file mode 100644
index 0000000..2a9785b
--- /dev/null
+++ b/tests/P_reflection3264_multifile/reflection3264_multifile_3.rs
@@ -0,0 +1,7 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+rs_allocation a[10];
+int b[10];
+
+void h(rs_allocation c, int d, rs_allocation e) { }
diff --git a/tests/P_reflection3264_multifile/stderr.txt.expect b/tests/P_reflection3264_multifile/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_reflection3264_multifile/stderr.txt.expect
diff --git a/tests/P_reflection3264_multifile/stdout.txt.expect b/tests/P_reflection3264_multifile/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_reflection3264_multifile/stdout.txt.expect
diff --git a/tests/P_struct_field/ScriptC_struct_field.java.expect b/tests/P_struct_field/ScriptC_struct_field.java.expect
index 2134315..9729da8 100644
--- a/tests/P_struct_field/ScriptC_struct_field.java.expect
+++ b/tests/P_struct_field/ScriptC_struct_field.java.expect
@@ -21,6 +21,9 @@
 
 package struct_field;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import struct_field.struct_fieldBitCode;
 
diff --git a/tests/P_struct_field/ScriptField_InnerOne.java.expect b/tests/P_struct_field/ScriptField_InnerOne.java.expect
index 54bcafe..8ceea0a 100644
--- a/tests/P_struct_field/ScriptField_InnerOne.java.expect
+++ b/tests/P_struct_field/ScriptField_InnerOne.java.expect
@@ -21,6 +21,9 @@
 
 package struct_field;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import struct_field.struct_fieldBitCode;
 
diff --git a/tests/P_struct_field/ScriptField_InnerTwo.java.expect b/tests/P_struct_field/ScriptField_InnerTwo.java.expect
index da7c768..f28d9cd 100644
--- a/tests/P_struct_field/ScriptField_InnerTwo.java.expect
+++ b/tests/P_struct_field/ScriptField_InnerTwo.java.expect
@@ -21,6 +21,9 @@
 
 package struct_field;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import struct_field.struct_fieldBitCode;
 
diff --git a/tests/P_struct_field/ScriptField_Outer.java.expect b/tests/P_struct_field/ScriptField_Outer.java.expect
index 6ee82e8..7d9b5c7 100644
--- a/tests/P_struct_field/ScriptField_Outer.java.expect
+++ b/tests/P_struct_field/ScriptField_Outer.java.expect
@@ -21,6 +21,9 @@
 
 package struct_field;
 
+import android.os.Build;
+import android.os.Process;
+import java.lang.reflect.Field;
 import android.renderscript.*;
 import struct_field.struct_fieldBitCode;