Home | History | Annotate | Download | only in slang
      1 /*
      2  * Copyright 2017, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <algorithm>
     18 #include <iostream>
     19 #include <string>
     20 
     21 #include "clang/AST/APValue.h"
     22 
     23 #include "slang_assert.h"
     24 #include "slang_rs_export_foreach.h"
     25 #include "slang_rs_export_func.h"
     26 #include "slang_rs_export_reduce.h"
     27 #include "slang_rs_export_type.h"
     28 #include "slang_rs_export_var.h"
     29 #include "slang_rs_reflection.h"
     30 #include "slang_rs_reflection_state.h"
     31 
     32 #include "bcinfo/MetadataExtractor.h"
     33 
     34 namespace slang {
     35 
     36 static bool equal(const clang::APValue &a, const clang::APValue &b) {
     37   if (a.getKind() != b.getKind())
     38     return false;
     39   switch (a.getKind()) {
     40     case clang::APValue::Float:
     41       return a.getFloat().bitwiseIsEqual(b.getFloat());
     42     case clang::APValue::Int:
     43       return a.getInt() == b.getInt();
     44     case clang::APValue::Vector: {
     45       unsigned NumElements = a.getVectorLength();
     46       if (NumElements != b.getVectorLength())
     47         return false;
     48       for (unsigned i = 0; i < NumElements; ++i) {
     49         if (!equal(a.getVectorElt(i), b.getVectorElt(i)))
     50           return false;
     51       }
     52       return true;
     53     }
     54     default:
     55       slangAssert(false && "unexpected APValue kind");
     56       return false;
     57   }
     58 }
     59 
     60 ReflectionState::~ReflectionState() {
     61   slangAssert(mState==S_Initial || mState==S_ClosedJava64 || mState==S_Bad);
     62   delete mStringSet;
     63 }
     64 
     65 void ReflectionState::openJava32(size_t NumFiles) {
     66   if (kDisabled)
     67     return;
     68   slangAssert(mState==S_Initial);
     69   mState = S_OpenJava32;
     70   mStringSet = new llvm::StringSet<>;
     71   mFiles.BeginCollecting(NumFiles);
     72 }
     73 
     74 void ReflectionState::closeJava32() {
     75   if (kDisabled)
     76     return;
     77   slangAssert(mState==S_OpenJava32 && (mForEachOpen < 0) && !mOutputClassOpen && (mRecordsState != RS_Open));
     78   mState = S_ClosedJava32;
     79   mRSC = nullptr;
     80 }
     81 
     82 void ReflectionState::openJava64() {
     83   if (kDisabled)
     84     return;
     85   slangAssert(mState==S_ClosedJava32);
     86   mState = S_OpenJava64;
     87   mFiles.BeginUsing();
     88 }
     89 
     90 void ReflectionState::closeJava64() {
     91   if (kDisabled)
     92     return;
     93   slangAssert(mState==S_OpenJava64 && (mForEachOpen < 0) && !mOutputClassOpen && (mRecordsState != RS_Open));
     94   mState = S_ClosedJava64;
     95   mRSC = nullptr;
     96 }
     97 
     98 llvm::StringRef ReflectionState::canon(const std::string &String) {
     99   slangAssert(isCollecting());
    100   return mStringSet->insert(String).first->getKey();
    101 }
    102 
    103 std::string ReflectionState::getUniqueTypeName(const RSExportType *T) {
    104   return RSReflectionJava::GetTypeName(T, RSReflectionJava::TypeNamePseudoC);
    105 }
    106 
    107 void ReflectionState::nextFile(const RSContext *RSC,
    108                                const std::string &PackageName,
    109                                const std::string &RSSourceFileName) {
    110   slangAssert(!isClosed());
    111   if (!isActive())
    112     return;
    113 
    114   mRSC = RSC;
    115 
    116   slangAssert(mRecordsState != RS_Open);
    117   mRecordsState = RS_Initial;
    118 
    119   if (isCollecting()) {
    120     File &file = mFiles.CollectNext();
    121     file.mPackageName = PackageName;
    122     file.mRSSourceFileName = RSSourceFileName;
    123   }
    124   if (isUsing()) {
    125     File &file = mFiles.UseNext();
    126     slangAssert(file.mRSSourceFileName == RSSourceFileName);
    127     if (file.mPackageName != PackageName)
    128       mRSC->ReportError("in file '%0' Java package name is '%1' for 32-bit targets "
    129                         "but '%2' for 64-bit targets")
    130           << RSSourceFileName << file.mPackageName << PackageName;
    131   }
    132 }
    133 
    134 void ReflectionState::dump() {
    135   const size_t NumFiles = mFiles.Size();
    136   for (int i = 0; i < NumFiles; ++i) {
    137     const File &file = mFiles[i];
    138     std::cout << "file = \"" << file.mRSSourceFileName << "\", "
    139               << "package = \"" << file.mPackageName << "\"" << std::endl;
    140 
    141     // NOTE: "StringMap iteration order, however, is not guaranteed to
    142     // be deterministic".  So sort before dumping.
    143     typedef const llvm::StringMap<File::Record>::MapEntryTy *RecordsEntryTy;
    144     std::vector<RecordsEntryTy> Records;
    145     Records.reserve(file.mRecords.size());
    146     for (auto I = file.mRecords.begin(), E = file.mRecords.end(); I != E; I++)
    147       Records.push_back(&(*I));
    148     std::sort(Records.begin(), Records.end(),
    149               [](RecordsEntryTy a, RecordsEntryTy b) { return a->getKey().compare(b->getKey())==-1; });
    150     for (auto Record : Records) {
    151       const auto &Val = Record->getValue();
    152       std::cout << "  (Record) name=\"" << Record->getKey().str() << "\""
    153                 << " allocSize=" << Val.mAllocSize
    154                 << " postPadding=" << Val.mPostPadding
    155                 << " ordinary=" << Val.mOrdinary
    156                 << " matchedByName=" << Val.mMatchedByName
    157                 << std::endl;
    158       const size_t NumFields = Val.mFieldCount;
    159       for (int fieldIdx = 0; fieldIdx < NumFields; ++fieldIdx) {
    160         const auto &field = Val.mFields[fieldIdx];
    161         std::cout << "    (Field) name=\"" << field.mName << "\" ("
    162                   << field.mPrePadding << ", \"" << field.mType.str()
    163                   << "\"(" << field.mStoreSize << ")@" << field.mOffset
    164                   << ", " << field.mPostPadding << ")" << std::endl;
    165       }
    166     }
    167 
    168     const size_t NumVars = file.mVariables.Size();
    169     for (int varIdx = 0; varIdx < NumVars; ++varIdx) {
    170       const auto &var = file.mVariables[varIdx];
    171       std::cout << "  (Var) name=\"" << var.mName << "\" type=\"" << var.mType.str()
    172                 << "\" const=" << var.mIsConst << " initialized=" << (var.mInitializerCount != 0)
    173                 << " allocSize=" << var.mAllocSize << std::endl;
    174     }
    175 
    176     for (int feIdx = 0; feIdx < file.mForEachCount; ++feIdx) {
    177       const auto &fe = file.mForEaches[feIdx];
    178       std::cout << "  (ForEach) ordinal=" << feIdx << " state=";
    179       switch (fe.mState) {
    180         case File::ForEach::S_Initial:
    181           std::cout << "initial" << std::endl;
    182           continue;
    183         case File::ForEach::S_Collected:
    184           std::cout << "collected";
    185           break;
    186         case File::ForEach::S_UseMatched:
    187           std::cout << "usematched";
    188           break;
    189         default:
    190           std::cout << fe.mState;
    191           break;
    192       }
    193       std::cout << " name=\"" << fe.mName << "\" kernel=" << fe.mIsKernel
    194                 << " hasOut=" << fe.mHasOut << " out=\"" << fe.mOut.str()
    195                 << "\" metadata=0x" << std::hex << fe.mSignatureMetadata << std::dec
    196                 << std::endl;
    197       const size_t NumIns = fe.mIns.Size();
    198       for (int insIdx = 0; insIdx < NumIns; ++insIdx)
    199         std::cout << "    (In) " << fe.mIns[insIdx].str() << std::endl;
    200       const size_t NumParams = fe.mParams.Size();
    201       for (int paramsIdx = 0; paramsIdx < NumParams; ++paramsIdx)
    202         std::cout << "    (Param) " << fe.mParams[paramsIdx].str() << std::endl;
    203     }
    204 
    205     for (auto feBad : mForEachesBad) {
    206       std::cout << "  (ForEachBad) ordinal=" << feBad->getOrdinal()
    207                 << " name=\"" << feBad->getName() << "\""
    208                 << std::endl;
    209     }
    210 
    211     const size_t NumInvokables = file.mInvokables.Size();
    212     for (int invIdx = 0; invIdx < NumInvokables; ++invIdx) {
    213       const auto &inv = file.mInvokables[invIdx];
    214       std::cout << "  (Invokable) name=\"" << inv.mName << "\"" << std::endl;
    215       const size_t NumParams = inv.mParamCount;
    216       for (int paramsIdx = 0; paramsIdx < NumParams; ++paramsIdx)
    217         std::cout << "    (Param) " << inv.mParams[paramsIdx].str() << std::endl;
    218     }
    219 
    220     const size_t NumReduces = file.mReduces.Size();
    221     for (int redIdx = 0; redIdx < NumReduces; ++redIdx) {
    222       const auto &red = file.mReduces[redIdx];
    223       std::cout << "  (Reduce) name=\"" << red.mName
    224                 << "\" result=\"" << red.mResult.str()
    225                 << "\" exportable=" << red.mIsExportable
    226                 << std::endl;
    227       const size_t NumIns = red.mAccumInCount;
    228       for (int insIdx = 0; insIdx < NumIns; ++insIdx)
    229         std::cout << "    (In) " << red.mAccumIns[insIdx].str() << std::endl;
    230     }
    231   }
    232 }
    233 
    234 // ForEach /////////////////////////////////////////////////////////////////////////////////////
    235 
    236 void ReflectionState::beginForEaches(size_t Count) {
    237   slangAssert(!isClosed());
    238   if (!isActive())
    239     return;
    240 
    241   if (isCollecting()) {
    242     auto &file = mFiles.Current();
    243     file.mForEaches = new File::ForEach[Count];
    244     file.mForEachCount = Count;
    245   }
    246   if (isUsing()) {
    247     slangAssert(mForEachesBad.empty());
    248     mNumForEachesMatchedByOrdinal = 0;
    249   }
    250 }
    251 
    252 // Keep this in sync with RSReflectionJava::genExportForEach().
    253 void ReflectionState::beginForEach(const RSExportForEach *EF) {
    254   slangAssert(!isClosed() && (mForEachOpen < 0));
    255   if (!isActive())
    256     return;
    257 
    258   const bool IsKernel = EF->isKernelStyle();
    259   const std::string Name = EF->getName();
    260   const unsigned Ordinal = EF->getOrdinal();
    261   const size_t InCount = EF->getInTypes().size();
    262   const size_t ParamCount = EF->params_count();
    263 
    264   const RSExportType *OET = EF->getOutType();
    265   if (OET && !IsKernel) {
    266     slangAssert(OET->getClass() == RSExportType::ExportClassPointer);
    267     OET = static_cast<const RSExportPointerType *>(OET)->getPointeeType();
    268   }
    269   const std::string OutType = (OET ? getUniqueTypeName(OET) : "");
    270   const bool HasOut = (EF->hasOut() || EF->hasReturn());
    271 
    272   mForEachOpen = Ordinal;
    273   mForEachFatal = true;  // we'll set this to false if everything looks ok
    274 
    275   auto &file = mFiles.Current();
    276   auto &foreaches = file.mForEaches;
    277   if (isCollecting()) {
    278     slangAssert(Ordinal < file.mForEachCount);
    279     auto &foreach = foreaches[Ordinal];
    280     slangAssert(foreach.mState == File::ForEach::S_Initial);
    281     foreach.mState = File::ForEach::S_Collected;
    282     foreach.mName = Name;
    283     foreach.mIns.BeginCollecting(InCount);
    284     foreach.mParams.BeginCollecting(ParamCount);
    285     foreach.mOut = canon(OutType);
    286     foreach.mHasOut = HasOut;
    287     foreach.mSignatureMetadata = 0;
    288     foreach.mIsKernel = IsKernel;
    289   }
    290   if (isUsing()) {
    291     if (Ordinal >= file.mForEachCount) {
    292       mForEachesBad.push_back(EF);
    293       return;
    294     }
    295 
    296     auto &foreach = foreaches[Ordinal];
    297     slangAssert(foreach.mState == File::ForEach::S_Collected);
    298     foreach.mState = File::ForEach::S_UseMatched;
    299     ++mNumForEachesMatchedByOrdinal;
    300 
    301     if (foreach.mName != Name) {
    302       // Order matters because it determines slot number
    303       mForEachesBad.push_back(EF);
    304       return;
    305     }
    306 
    307     // At this point, we have matching ordinal and matching name.
    308 
    309     if (foreach.mIsKernel != IsKernel) {
    310       mRSC->ReportError(EF->getLocation(),
    311                         "foreach kernel '%0' has __attribute__((kernel)) for %select{32|64}1-bit targets "
    312                         "but not for %select{64|32}1-bit targets")
    313           << Name << IsKernel;
    314       return;
    315     }
    316 
    317     if ((foreach.mHasOut != HasOut) || !foreach.mOut.equals(OutType)) {
    318       // There are several different patterns we need to handle:
    319       // (1) Two different non-void* output types
    320       // (2) One non-void* output type, one void* output type
    321       // (3) One non-void* output type, one no-output
    322       // (4) One void* output type, one no-output
    323       if (foreach.mHasOut && HasOut) {
    324         if (foreach.mOut.size() && OutType.size()) {
    325           // (1) Two different non-void* output types
    326           mRSC->ReportError(EF->getLocation(),
    327                             "foreach kernel '%0' has output type '%1' for 32-bit targets "
    328                             "but output type '%2' for 64-bit targets")
    329               << Name << foreach.mOut.str() << OutType;
    330         } else {
    331           // (2) One non-void* return type, one void* output type
    332           const bool hasTyped64 = OutType.size();
    333           mRSC->ReportError(EF->getLocation(),
    334                             "foreach kernel '%0' has output type '%1' for %select{32|64}2-bit targets "
    335                             "but has untyped output for %select{64|32}2-bit targets")
    336               << Name << (foreach.mOut.str() + OutType) << hasTyped64;
    337         }
    338       } else {
    339         const std::string CombinedOutType = (foreach.mOut.str() + OutType);
    340         if (CombinedOutType.size()) {
    341           // (3) One non-void* output type, one no-output
    342           mRSC->ReportError(EF->getLocation(),
    343                             "foreach kernel '%0' has output type '%1' for %select{32|64}2-bit targets "
    344                             "but no output for %select{64|32}2-bit targets")
    345               << Name << CombinedOutType << HasOut;
    346         } else {
    347           // (4) One void* output type, one no-output
    348           mRSC->ReportError(EF->getLocation(),
    349                             "foreach kernel '%0' has untyped output for %select{32|64}1-bit targets "
    350                             "but no output for %select{64|32}1-bit targets")
    351               << Name << HasOut;
    352         }
    353       }
    354     }
    355 
    356     bool BadCount = false;
    357     if (foreach.mIns.Size() != InCount) {
    358       mRSC->ReportError(EF->getLocation(),
    359                         "foreach kernel '%0' has %1 input%s1 for 32-bit targets "
    360                         "but %2 input%s2 for 64-bit targets")
    361           << Name << unsigned(foreach.mIns.Size()) << unsigned(InCount);
    362       BadCount = true;
    363     }
    364     if (foreach.mParams.Size() != ParamCount) {
    365       mRSC->ReportError(EF->getLocation(),
    366                         "foreach kernel '%0' has %1 usrData parameter%s1 for 32-bit targets "
    367                         "but %2 usrData parameter%s2 for 64-bit targets")
    368           << Name << unsigned(foreach.mParams.Size()) << unsigned(ParamCount);
    369       BadCount = true;
    370     }
    371 
    372     if (BadCount)
    373       return;
    374 
    375     foreach.mIns.BeginUsing();
    376     foreach.mParams.BeginUsing();
    377   }
    378 
    379   mForEachFatal = false;
    380 }
    381 
    382 void ReflectionState::addForEachIn(const RSExportForEach *EF, const RSExportType *Type) {
    383   slangAssert(!isClosed());
    384   if (!isActive())
    385     return;
    386 
    387   slangAssert(mForEachOpen == EF->getOrdinal());
    388 
    389   // Type may be nullptr in the case of void*.  See RSExportForEach::Create().
    390   if (Type && !EF->isKernelStyle()) {
    391     slangAssert(Type->getClass() == RSExportType::ExportClassPointer);
    392     Type = static_cast<const RSExportPointerType *>(Type)->getPointeeType();
    393   }
    394   const std::string TypeName = (Type ? getUniqueTypeName(Type) : std::string());
    395 
    396   auto &ins = mFiles.Current().mForEaches[EF->getOrdinal()].mIns;
    397   if (isCollecting()) {
    398     ins.CollectNext() = canon(TypeName);
    399   }
    400   if (isUsing()) {
    401     if (mForEachFatal)
    402       return;
    403 
    404     if (!ins.UseNext().equals(TypeName)) {
    405       if (ins.Current().size() && TypeName.size()) {
    406         mRSC->ReportError(EF->getLocation(),
    407                           "%ordinal0 input of foreach kernel '%1' "
    408                           "has type '%2' for 32-bit targets "
    409                           "but type '%3' for 64-bit targets")
    410             << unsigned(ins.CurrentIdx() + 1)
    411             << EF->getName()
    412             << ins.Current().str()
    413             << TypeName;
    414       } else {
    415         const bool hasType64 = TypeName.size();
    416         mRSC->ReportError(EF->getLocation(),
    417                           "%ordinal0 input of foreach kernel '%1' "
    418                           "has type '%2' for %select{32|64}3-bit targets "
    419                           "but is untyped for %select{64|32}3-bit targets")
    420             << unsigned(ins.CurrentIdx() + 1)
    421             << EF->getName()
    422             << (ins.Current().str() + TypeName)
    423             << hasType64;
    424       }
    425     }
    426   }
    427 }
    428 
    429 void ReflectionState::addForEachParam(const RSExportForEach *EF, const RSExportType *Type) {
    430   slangAssert(!isClosed());
    431   if (!isActive())
    432     return;
    433 
    434   slangAssert(mForEachOpen == EF->getOrdinal());
    435 
    436   const std::string TypeName = getUniqueTypeName(Type);
    437 
    438   auto &params = mFiles.Current().mForEaches[EF->getOrdinal()].mParams;
    439   if (isCollecting()) {
    440     params.CollectNext() = canon(TypeName);
    441   }
    442   if (isUsing()) {
    443     if (mForEachFatal)
    444       return;
    445 
    446     if (!params.UseNext().equals(TypeName)) {
    447       mRSC->ReportError(EF->getLocation(),
    448                         "%ordinal0 usrData parameter of foreach kernel '%1' "
    449                         "has type '%2' for 32-bit targets "
    450                         "but type '%3' for 64-bit targets")
    451           << unsigned(params.CurrentIdx() + 1)
    452           << EF->getName()
    453           << params.Current().str()
    454           << TypeName;
    455     }
    456   }
    457 }
    458 
    459 void ReflectionState::addForEachSignatureMetadata(const RSExportForEach *EF, unsigned Metadata) {
    460   slangAssert(!isClosed());
    461   if (!isActive())
    462     return;
    463 
    464   slangAssert(mForEachOpen == EF->getOrdinal());
    465 
    466   // These are properties in the metadata that we need to check.
    467   const unsigned SpecialParameterBits = bcinfo::MD_SIG_X|bcinfo::MD_SIG_Y|bcinfo::MD_SIG_Z|bcinfo::MD_SIG_Ctxt;
    468 
    469 #ifndef __DISABLE_ASSERTS
    470   {
    471     // These are properties in the metadata that we already check in
    472     // some other way.
    473     const unsigned BoringBits = bcinfo::MD_SIG_In|bcinfo::MD_SIG_Out|bcinfo::MD_SIG_Usr|bcinfo::MD_SIG_Kernel;
    474 
    475     slangAssert((Metadata & ~(SpecialParameterBits | BoringBits)) == 0);
    476   }
    477 #endif
    478 
    479   auto &mSignatureMetadata = mFiles.Current().mForEaches[EF->getOrdinal()].mSignatureMetadata;
    480   if (isCollecting()) {
    481     mSignatureMetadata = Metadata;
    482   }
    483   if (isUsing()) {
    484     if (mForEachFatal)
    485       return;
    486 
    487     if ((mSignatureMetadata & SpecialParameterBits) != (Metadata & SpecialParameterBits)) {
    488       mRSC->ReportError(EF->getLocation(),
    489                         "foreach kernel '%0' has different special parameters "
    490                         "for 32-bit targets than for 64-bit targets")
    491           << EF->getName();
    492     }
    493   }
    494 }
    495 
    496 void ReflectionState::endForEach() {
    497   slangAssert(!isClosed());
    498   if (!isActive())
    499     return;
    500 
    501   slangAssert(mForEachOpen >= 0);
    502   if (isUsing() && !mForEachFatal) {
    503     slangAssert(mFiles.Current().mForEaches[mForEachOpen].mIns.isFinished());
    504     slangAssert(mFiles.Current().mForEaches[mForEachOpen].mParams.isFinished());
    505   }
    506 
    507   mForEachOpen = -1;
    508 }
    509 
    510 void ReflectionState::endForEaches() {
    511   slangAssert(mForEachOpen < 0);
    512   if (!isUsing())
    513     return;
    514 
    515   const auto &file = mFiles.Current();
    516 
    517   if (!mForEachesBad.empty()) {
    518     std::sort(mForEachesBad.begin(), mForEachesBad.end(),
    519          [](const RSExportForEach *a, const RSExportForEach *b) { return a->getOrdinal() < b->getOrdinal(); });
    520     // Note that after the sort, all kernels that are bad because of
    521     // name mismatch precede all kernels that are bad because of
    522     // too-high ordinal.
    523 
    524     // 32-bit and 64-bit compiles need to see foreach kernels in the
    525     // same order, because of slot number assignment.  Once we see the
    526     // first name mismatch in the sequence of foreach kernels, it
    527     // doesn't make sense to issue further diagnostics regarding
    528     // foreach kernels except those that still happen to match by name
    529     // and ordinal (we already handled those diagnostics between
    530     // beginForEach() and endForEach()).
    531     bool ForEachesOrderFatal = false;
    532 
    533     for (const RSExportForEach *EF : mForEachesBad) {
    534       if (EF->getOrdinal() >= file.mForEachCount) {
    535         mRSC->ReportError(EF->getLocation(),
    536                           "foreach kernel '%0' is only present for 64-bit targets")
    537             << EF->getName();
    538       } else {
    539         mRSC->ReportError(EF->getLocation(),
    540                           "%ordinal0 foreach kernel is '%1' for 32-bit targets "
    541                           "but '%2' for 64-bit targets")
    542             << (EF->getOrdinal() + 1)
    543             << mFiles.Current().mForEaches[EF->getOrdinal()].mName
    544             << EF->getName();
    545         ForEachesOrderFatal = true;
    546         break;
    547       }
    548     }
    549 
    550     mForEachesBad.clear();
    551 
    552     if (ForEachesOrderFatal)
    553       return;
    554   }
    555 
    556   if (mNumForEachesMatchedByOrdinal == file.mForEachCount)
    557     return;
    558   for (unsigned ord = 0; ord < file.mForEachCount; ord++) {
    559     const auto &fe = file.mForEaches[ord];
    560     if (fe.mState == File::ForEach::S_Collected) {
    561       mRSC->ReportError("in file '%0' foreach kernel '%1' is only present for 32-bit targets")
    562           << file.mRSSourceFileName << fe.mName;
    563     }
    564   }
    565 }
    566 
    567 // Invokable ///////////////////////////////////////////////////////////////////////////////////
    568 
    569 // Keep this in sync with RSReflectionJava::genExportFunction().
    570 void ReflectionState::declareInvokable(const RSExportFunc *EF) {
    571   slangAssert(!isClosed());
    572   if (!isActive())
    573     return;
    574 
    575   const std::string Name = EF->getName(/*Mangle=*/false);
    576   const size_t ParamCount = EF->getNumParameters();
    577 
    578   auto &invokables = mFiles.Current().mInvokables;
    579   if (isCollecting()) {
    580     auto &invokable = invokables.CollectNext();
    581     invokable.mName = Name;
    582     invokable.mParamCount = ParamCount;
    583     if (EF->hasParam()) {
    584       unsigned FieldIdx = 0;
    585       invokable.mParams = new llvm::StringRef[ParamCount];
    586       for (RSExportFunc::const_param_iterator I = EF->params_begin(),
    587                                               E = EF->params_end();
    588            I != E; I++, FieldIdx++) {
    589         invokable.mParams[FieldIdx] = canon(getUniqueTypeName((*I)->getType()));
    590       }
    591     }
    592   }
    593   if (isUsing()) {
    594     if (mInvokablesOrderFatal)
    595       return;
    596 
    597     if (invokables.isFinished()) {
    598       // This doesn't actually break reflection, but that's a
    599       // coincidence of the fact that we reflect during the 64-bit
    600       // compilation pass rather than the 32-bit compilation pass, and
    601       // of the fact that the "extra" invokable(s) are at the end.
    602       mRSC->ReportError(EF->getLocation(),
    603                         "invokable function '%0' is only present for 64-bit targets")
    604           << Name;
    605       return;
    606     }
    607 
    608     auto &invokable = invokables.UseNext();
    609 
    610     if (invokable.mName != Name) {
    611       // Order matters because it determines slot number
    612       mRSC->ReportError(EF->getLocation(),
    613                         "%ordinal0 invokable function is '%1' for 32-bit targets "
    614                         "but '%2' for 64-bit targets")
    615           << unsigned(invokables.CurrentIdx() + 1)
    616           << invokable.mName
    617           << Name;
    618       mInvokablesOrderFatal = true;
    619       return;
    620     }
    621 
    622     if (invokable.mParamCount != ParamCount) {
    623       mRSC->ReportError(EF->getLocation(),
    624                         "invokable function '%0' has %1 parameter%s1 for 32-bit targets "
    625                         "but %2 parameter%s2 for 64-bit targets")
    626           << Name << unsigned(invokable.mParamCount) << unsigned(ParamCount);
    627       return;
    628     }
    629     if (EF->hasParam()) {
    630       unsigned FieldIdx = 0;
    631       for (RSExportFunc::const_param_iterator I = EF->params_begin(),
    632                                               E = EF->params_end();
    633            I != E; I++, FieldIdx++) {
    634         const std::string Type = getUniqueTypeName((*I)->getType());
    635         if (!invokable.mParams[FieldIdx].equals(Type)) {
    636           mRSC->ReportError(EF->getLocation(),
    637                             "%ordinal0 parameter of invokable function '%1' "
    638                             "has type '%2' for 32-bit targets "
    639                             "but type '%3' for 64-bit targets")
    640               << (FieldIdx + 1)
    641               << Name
    642               << invokable.mParams[FieldIdx].str()
    643               << Type;
    644         }
    645       }
    646     }
    647   }
    648 }
    649 
    650 void ReflectionState::endInvokables() {
    651   if (!isUsing() || mInvokablesOrderFatal)
    652     return;
    653 
    654   auto &invokables = mFiles.Current().mInvokables;
    655   while (!invokables.isFinished()) {
    656     const auto &invokable = invokables.UseNext();
    657     mRSC->ReportError("in file '%0' invokable function '%1' is only present for 32-bit targets")
    658         << mFiles.Current().mRSSourceFileName << invokable.mName;
    659   }
    660 }
    661 
    662 // Record //////////////////////////////////////////////////////////////////////////////////////
    663 
    664 void ReflectionState::beginRecords() {
    665   slangAssert(!isClosed());
    666   if (!isActive())
    667     return;
    668 
    669   slangAssert(mRecordsState != RS_Open);
    670   mRecordsState = RS_Open;
    671   mNumRecordsMatchedByName = 0;
    672 }
    673 
    674 void ReflectionState::endRecords() {
    675   slangAssert(!isClosed());
    676   if (!isActive())
    677     return;
    678 
    679   slangAssert(mRecordsState == RS_Open);
    680   mRecordsState = RS_Closed;
    681 
    682   if (isUsing()) {
    683     const File &file = mFiles.Current();
    684     if (mNumRecordsMatchedByName == file.mRecords.size())
    685       return;
    686     // NOTE: "StringMap iteration order, however, is not guaranteed to
    687     // be deterministic".  So sort by name before reporting.
    688     // Alternatively, if we record additional information, we could
    689     // sort by source location or by order in which we discovered the
    690     // need to export.
    691     std::vector<llvm::StringRef> Non64RecordNames;
    692     for (auto I = file.mRecords.begin(), E = file.mRecords.end(); I != E; I++)
    693       if (!I->getValue().mMatchedByName && I->getValue().mOrdinary)
    694         Non64RecordNames.push_back(I->getKey());
    695     std::sort(Non64RecordNames.begin(), Non64RecordNames.end(),
    696               [](llvm::StringRef a, llvm::StringRef b) { return a.compare(b)==-1; });
    697     for (auto N : Non64RecordNames)
    698       mRSC->ReportError("in file '%0' structure '%1' is exported only for 32-bit targets")
    699           << file.mRSSourceFileName << N.str();
    700   }
    701 }
    702 
    703 void ReflectionState::declareRecord(const RSExportRecordType *ERT, bool Ordinary) {
    704   slangAssert(!isClosed());
    705   if (!isActive())
    706     return;
    707 
    708   slangAssert(mRecordsState == RS_Open);
    709 
    710   auto &records = mFiles.Current().mRecords;
    711   if (isCollecting()) {
    712     // Keep struct/field layout in sync with
    713     // RSReflectionJava::genPackVarOfType() and
    714     // RSReflectionJavaElementBuilder::genAddElement()
    715 
    716     // Save properties of record
    717 
    718     const size_t FieldCount = ERT->fields_size();
    719     File::Record::Field *Fields = new File::Record::Field[FieldCount];
    720 
    721     size_t Pos = 0;  // Relative position of field within record
    722     unsigned FieldIdx = 0;
    723     for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), E = ERT->fields_end();
    724          I != E; I++, FieldIdx++) {
    725       const RSExportRecordType::Field *FieldExport = *I;
    726       size_t FieldOffset = FieldExport->getOffsetInParent();
    727       const RSExportType *T = FieldExport->getType();
    728       size_t FieldStoreSize = T->getStoreSize();
    729       size_t FieldAllocSize = T->getAllocSize();
    730 
    731       slangAssert(FieldOffset >= Pos);
    732       slangAssert(FieldAllocSize >= FieldStoreSize);
    733 
    734       auto &FieldState = Fields[FieldIdx];
    735       FieldState.mName = FieldExport->getName();
    736       FieldState.mType = canon(getUniqueTypeName(T));
    737       FieldState.mPrePadding = FieldOffset - Pos;
    738       FieldState.mPostPadding = FieldAllocSize - FieldStoreSize;
    739       FieldState.mOffset = FieldOffset;
    740       FieldState.mStoreSize = FieldStoreSize;
    741 
    742       Pos = FieldOffset + FieldAllocSize;
    743     }
    744 
    745     slangAssert(ERT->getAllocSize() >= Pos);
    746 
    747     // Insert record into map
    748 
    749     slangAssert(records.find(ERT->getName()) == records.end());
    750     File::Record &record = records[ERT->getName()];
    751     record.mFields = Fields;
    752     record.mFieldCount = FieldCount;
    753     record.mPostPadding = ERT->getAllocSize() - Pos;
    754     record.mAllocSize = ERT->getAllocSize();
    755     record.mOrdinary = Ordinary;
    756     record.mMatchedByName = false;
    757   }
    758   if (isUsing()) {
    759     if (!Ordinary)
    760       return;
    761 
    762     const auto RIT = records.find(ERT->getName());
    763     if (RIT == records.end()) {
    764       // This doesn't actually break reflection, but that's a
    765       // coincidence of the fact that we reflect during the 64-bit
    766       // compilation pass rather than the 32-bit compilation pass, so
    767       // a record that's only classified as exported during the 64-bit
    768       // compilation pass doesn't cause any problems.
    769       mRSC->ReportError(ERT->getLocation(), "structure '%0' is exported only for 64-bit targets")
    770           << ERT->getName();
    771       return;
    772     }
    773     File::Record &record = RIT->getValue();
    774     record.mMatchedByName = true;
    775     ++mNumRecordsMatchedByName;
    776     slangAssert(record.mOrdinary);
    777 
    778     if (ERT->fields_size() != record.mFieldCount) {
    779       mRSC->ReportError(ERT->getLocation(),
    780                         "exported structure '%0' has %1 field%s1 for 32-bit targets "
    781                         "but %2 field%s2 for 64-bit targets")
    782           << ERT->getName() << unsigned(record.mFieldCount) << unsigned(ERT->fields_size());
    783       return;
    784     }
    785 
    786     // Note that we are deliberately NOT comparing layout properties
    787     // (such as Field offsets and sizes, or Record allocation size);
    788     // we need to tolerate layout differences between 32-bit
    789     // compilation and 64-bit compilation.
    790 
    791     unsigned FieldIdx = 0;
    792     for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), E = ERT->fields_end();
    793          I != E; I++, FieldIdx++) {
    794       const RSExportRecordType::Field &FieldExport = **I;
    795       const File::Record::Field &FieldState = record.mFields[FieldIdx];
    796       if (FieldState.mName != FieldExport.getName()) {
    797         mRSC->ReportError(ERT->getLocation(),
    798                           "%ordinal0 field of exported structure '%1' "
    799                           "is '%2' for 32-bit targets "
    800                           "but '%3' for 64-bit targets")
    801             << (FieldIdx + 1) << ERT->getName() << FieldState.mName << FieldExport.getName();
    802         return;
    803       }
    804       const std::string FieldExportType = getUniqueTypeName(FieldExport.getType());
    805       if (!FieldState.mType.equals(FieldExportType)) {
    806         mRSC->ReportError(ERT->getLocation(),
    807                           "field '%0' of exported structure '%1' "
    808                           "has type '%2' for 32-bit targets "
    809                           "but type '%3' for 64-bit targets")
    810             << FieldState.mName << ERT->getName() << FieldState.mType.str() << FieldExportType;
    811       }
    812     }
    813   }
    814 }
    815 
    816 ReflectionState::Record32
    817 ReflectionState::getRecord32(const RSExportRecordType *ERT) {
    818   if (isUsing()) {
    819     const auto &Records = mFiles.Current().mRecords;
    820     const auto RIT = Records.find(ERT->getName());
    821     if (RIT != Records.end())
    822       return Record32(&RIT->getValue());
    823   }
    824   return Record32();
    825 }
    826 
    827 // Reduce //////////////////////////////////////////////////////////////////////////////////////
    828 
    829 void ReflectionState::declareReduce(const RSExportReduce *ER, bool IsExportable) {
    830   slangAssert(!isClosed());
    831   if (!isActive())
    832     return;
    833 
    834   auto &reduces = mFiles.Current().mReduces;
    835   if (isCollecting()) {
    836     auto &reduce = reduces.CollectNext();
    837     reduce.mName = ER->getNameReduce();
    838 
    839     const auto &InTypes = ER->getAccumulatorInTypes();
    840     const size_t InTypesSize = InTypes.size();
    841     reduce.mAccumInCount = InTypesSize;
    842     reduce.mAccumIns = new llvm::StringRef[InTypesSize];
    843     unsigned InTypesIdx = 0;
    844     for (const auto &InType : InTypes)
    845       reduce.mAccumIns[InTypesIdx++] = canon(getUniqueTypeName(InType));
    846 
    847     reduce.mResult = canon(getUniqueTypeName(ER->getResultType()));
    848     reduce.mIsExportable = IsExportable;
    849   }
    850   if (isUsing()) {
    851     if (mReducesOrderFatal)
    852       return;
    853 
    854     const std::string Name = ER->getNameReduce();
    855 
    856     if (reduces.isFinished()) {
    857       // This doesn't actually break reflection, but that's a
    858       // coincidence of the fact that we reflect during the 64-bit
    859       // compilation pass rather than the 32-bit compilation pass, and
    860       // of the fact that the "extra" reduction kernel(s) are at the
    861       // end.
    862       mRSC->ReportError(ER->getLocation(),
    863                         "reduction kernel '%0' is only present for 64-bit targets")
    864           << Name;
    865       return;
    866     }
    867 
    868     auto &reduce = reduces.UseNext();
    869 
    870     if (reduce.mName != Name) {
    871       // Order matters because it determines slot number.  We might be
    872       // able to tolerate certain cases if we ignore non-exportable
    873       // kernels in the two sequences (32-bit and 64-bit) -- non-exportable
    874       // kernels do not take up slot numbers.
    875       mRSC->ReportError(ER->getLocation(),
    876                         "%ordinal0 reduction kernel is '%1' for 32-bit targets "
    877                         "but '%2' for 64-bit targets")
    878           << unsigned(reduces.CurrentIdx() + 1)
    879           << reduce.mName
    880           << Name;
    881       mReducesOrderFatal = true;
    882       return;
    883     }
    884 
    885     // If at least one of the two kernels (32-bit or 64-bit) is not
    886     // exporable, then there will be no reflection for that kernel,
    887     // and so any mismatch in result type or in inputs is irrelevant.
    888     // However, we may make more kernels exportable in the future.
    889     // Therefore, we'll forbid mismatches anyway.
    890 
    891     if (reduce.mIsExportable != IsExportable) {
    892       mRSC->ReportError(ER->getLocation(),
    893                         "reduction kernel '%0' is reflected in Java only for %select{32|64}1-bit targets")
    894           << reduce.mName
    895           << IsExportable;
    896     }
    897 
    898     const std::string ResultType = getUniqueTypeName(ER->getResultType());
    899     if (!reduce.mResult.equals(ResultType)) {
    900       mRSC->ReportError(ER->getLocation(),
    901                         "reduction kernel '%0' has result type '%1' for 32-bit targets "
    902                         "but result type '%2' for 64-bit targets")
    903           << reduce.mName << reduce.mResult.str() << ResultType;
    904     }
    905 
    906     const auto &InTypes = ER->getAccumulatorInTypes();
    907     if (reduce.mAccumInCount != InTypes.size()) {
    908       mRSC->ReportError(ER->getLocation(),
    909                         "reduction kernel '%0' has %1 input%s1 for 32-bit targets "
    910                         "but %2 input%s2 for 64-bit targets")
    911           << Name << unsigned(reduce.mAccumInCount) << unsigned(InTypes.size());
    912       return;
    913     }
    914     unsigned FieldIdx = 0;
    915     for (const auto &InType : InTypes) {
    916       const std::string InTypeName = getUniqueTypeName(InType);
    917       const llvm::StringRef StateInTypeName = reduce.mAccumIns[FieldIdx++];
    918       if (!StateInTypeName.equals(InTypeName)) {
    919         mRSC->ReportError(ER->getLocation(),
    920                           "%ordinal0 input of reduction kernel '%1' "
    921                           "has type '%2' for 32-bit targets "
    922                           "but type '%3' for 64-bit targets")
    923             << FieldIdx
    924             << Name
    925             << StateInTypeName.str()
    926             << InTypeName;
    927       }
    928     }
    929   }
    930 }
    931 
    932 void ReflectionState::endReduces() {
    933   if (!isUsing() || mReducesOrderFatal)
    934     return;
    935 
    936   auto &reduces = mFiles.Current().mReduces;
    937   while (!reduces.isFinished()) {
    938     const auto &reduce = reduces.UseNext();
    939     mRSC->ReportError("in file '%0' reduction kernel '%1' is only present for 32-bit targets")
    940         << mFiles.Current().mRSSourceFileName << reduce.mName;
    941   }
    942 }
    943 
    944 // Variable ////////////////////////////////////////////////////////////////////////////////////
    945 
    946 // Keep this in sync with initialization handling in
    947 // RSReflectionJava::genScriptClassConstructor().
    948 ReflectionState::Val32 ReflectionState::declareVariable(const RSExportVar *EV) {
    949   slangAssert(!isClosed());
    950   if (!isActive())
    951     return NoVal32();
    952 
    953   auto &variables = mFiles.Current().mVariables;
    954   if (isCollecting()) {
    955     auto &variable = variables.CollectNext();
    956     variable.mName = EV->getName();
    957     variable.mType = canon(getUniqueTypeName(EV->getType()));
    958     variable.mAllocSize = EV->getType()->getAllocSize();
    959     variable.mIsConst = EV->isConst();
    960     if (!EV->getInit().isUninit()) {
    961       variable.mInitializerCount = 1;
    962       variable.mInitializers = new clang::APValue[1];
    963       variable.mInitializers[0] = EV->getInit();
    964     } else if (EV->getArraySize()) {
    965       variable.mInitializerCount = EV->getNumInits();
    966       variable.mInitializers = new clang::APValue[variable.mInitializerCount];
    967       for (size_t i = 0; i < variable.mInitializerCount; ++i)
    968         variable.mInitializers[i] = EV->getInitArray(i);
    969     } else {
    970       variable.mInitializerCount = 0;
    971     }
    972     return NoVal32();
    973   }
    974 
    975   /*-- isUsing() -----------------------------------------------------------*/
    976 
    977   slangAssert(isUsing());
    978 
    979   if (mVariablesOrderFatal)
    980     return NoVal32();
    981 
    982   if (variables.isFinished()) {
    983     // This doesn't actually break reflection, but that's a
    984     // coincidence of the fact that we reflect during the 64-bit
    985     // compilation pass rather than the 32-bit compilation pass, and
    986     // of the fact that the "extra" variable(s) are at the end.
    987     mRSC->ReportError(EV->getLocation(), "global variable '%0' is only present for 64-bit targets")
    988         << EV->getName();
    989     return NoVal32();
    990   }
    991 
    992   const auto &variable = variables.UseNext();
    993 
    994   if (variable.mName != EV->getName()) {
    995     // Order matters because it determines slot number
    996     mRSC->ReportError(EV->getLocation(),
    997                       "%ordinal0 global variable is '%1' for 32-bit targets "
    998                       "but '%2' for 64-bit targets")
    999         << unsigned(variables.CurrentIdx() + 1)
   1000         << variable.mName
   1001         << EV->getName();
   1002     mVariablesOrderFatal = true;
   1003     return NoVal32();
   1004   }
   1005 
   1006   const std::string TypeName = getUniqueTypeName(EV->getType());
   1007 
   1008   if (!variable.mType.equals(TypeName)) {
   1009     mRSC->ReportError(EV->getLocation(),
   1010                       "global variable '%0' has type '%1' for 32-bit targets "
   1011                       "but type '%2' for 64-bit targets")
   1012         << EV->getName()
   1013         << variable.mType.str()
   1014         << TypeName;
   1015     return NoVal32();
   1016   }
   1017 
   1018   if (variable.mIsConst != EV->isConst()) {
   1019     mRSC->ReportError(EV->getLocation(),
   1020                       "global variable '%0' has inconsistent 'const' qualification "
   1021                       "between 32-bit targets and 64-bit targets")
   1022         << EV->getName();
   1023     return NoVal32();
   1024   }
   1025 
   1026   // NOTE: Certain syntactically different but semantically
   1027   // equivalent initialization patterns are unnecessarily rejected
   1028   // as errors.
   1029   //
   1030   // Background:
   1031   //
   1032   // . A vector initialized with a scalar value is treated
   1033   //   by reflection as if all elements of the vector are
   1034   //   initialized with the scalar value.
   1035   // . A vector may be initialized with a vector of greater
   1036   //   length; reflection ignores the extra initializers.
   1037   // . If only the beginning of a vector is explicitly
   1038   //   initialized, reflection treats it as if trailing elements are
   1039   //   initialized to zero (by issuing explicit assignments to those
   1040   //   trailing elements).
   1041   // . If only the beginning of an array is explicitly initialized,
   1042   //   reflection treats it as if trailing elements are initialized
   1043   //   to zero (by Java rules for newly-created arrays).
   1044   //
   1045   // Unnecessarily rejected as errors:
   1046   //
   1047   // . One compile initializes a vector with a scalar, and
   1048   //   another initializes it with a vector whose elements
   1049   //   are the scalar, as in
   1050   //
   1051   //     int2 x =
   1052   //     #ifdef __LP64__
   1053   //       1
   1054   //     #else
   1055   //       { 1, 1 }
   1056   //     #endif
   1057   //
   1058   // . Compiles initialize a vector with vectors of different
   1059   //   lengths, but the initializers agree up to the length
   1060   //   of the variable being initialized, as in
   1061   //
   1062   //     int2 x = { 1, 2
   1063   //     #ifdef __LP64__
   1064   //       3
   1065   //     #else
   1066   //       4
   1067   //     #endif
   1068   //     };
   1069   //
   1070   // . Two compiles agree with the initializer for a vector or
   1071   //   array, except that one has some number of explicit trailing
   1072   //   zeroes, as in
   1073   //
   1074   //     int x[4] = { 3, 2, 1
   1075   //     #ifdef __LP64__
   1076   //       , 0
   1077   //     #endif
   1078   //     };
   1079 
   1080   bool MismatchedInitializers = false;
   1081   if (!EV->getInit().isUninit()) {
   1082     // Use phase has a scalar initializer.
   1083     // Make sure that Collect phase had a matching scalar initializer.
   1084     if ((variable.mInitializerCount != 1) ||
   1085         !equal(variable.mInitializers[0], EV->getInit()))
   1086       MismatchedInitializers = true;
   1087   } else if (EV->getArraySize()) {
   1088     const size_t UseSize = EV->getNumInits();
   1089     if (variable.mInitializerCount != UseSize)
   1090       MismatchedInitializers = true;
   1091     else {
   1092       for (int i = 0; i < UseSize; ++i)
   1093         if (!equal(variable.mInitializers[i], EV->getInitArray(i))) {
   1094           MismatchedInitializers = true;
   1095           break;
   1096         }
   1097     }
   1098   } else if (variable.mInitializerCount != 0) {
   1099     // Use phase does not have a scalar initializer, variable is not
   1100     // an array, and Collect phase has an initializer.  This is an error.
   1101     MismatchedInitializers = true;
   1102   }
   1103 
   1104   if (MismatchedInitializers) {
   1105     mRSC->ReportError(EV->getLocation(),
   1106                       "global variable '%0' is initialized differently for 32-bit targets "
   1107                       "than for 64-bit targets")
   1108         << EV->getName();
   1109     return NoVal32();
   1110   }
   1111 
   1112   return Val32(true, variable.mAllocSize);
   1113 }
   1114 
   1115 void ReflectionState::endVariables() {
   1116   if (!isUsing() || mVariablesOrderFatal)
   1117     return;
   1118 
   1119   auto &variables = mFiles.Current().mVariables;
   1120   while (!variables.isFinished()) {
   1121     const auto &variable = variables.UseNext();
   1122     mRSC->ReportError("in file '%0' global variable '%1' is only present for 32-bit targets")
   1123         << mFiles.Current().mRSSourceFileName << variable.mName;
   1124   }
   1125 }
   1126 
   1127 }  // namespace slang
   1128