Beispiel #1
0
static void
genClassIDs(Vec<TypeSymbol*> & typeSymbols) {
  genComment("Class Type Identification Numbers");

  int count=0;
  forv_Vec(TypeSymbol, ts, typeSymbols) {
    if (AggregateType* ct = toAggregateType(ts->type)) {
      if (!isReferenceType(ct) && isClass(ct)) {
        genGlobalDefClassId(ts->cname, count);
        count++;
      }
    }
  }
}
Beispiel #2
0
static QualifiedType
returnInfoAsRef(CallExpr* call) {
  Type* t = call->get(1)->typeInfo();
  if (isReferenceType(t)) {
    return QualifiedType(t, QUAL_REF);
  }
  else if (t->symbol->hasFlag(FLAG_WIDE_REF)) {
    return QualifiedType(t, QUAL_WIDE_REF);
  }
  else {
    if (!t->refType)
      INT_FATAL(call, "invalid attempt to get reference type");
    return QualifiedType(t->refType, QUAL_REF);
  }
}
Beispiel #3
0
void cgCallBuiltin(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<CallBuiltin>();
  auto const callee = extra->callee;
  auto const returnType = inst->typeParam();
  auto const funcReturnType = callee->returnType();
  auto const returnByValue = callee->isReturnByValue();

  auto const dstData = dstLoc(env, inst, 0).reg(0);
  auto const dstType = dstLoc(env, inst, 0).reg(1);

  auto& v = vmain(env);

  // Whether `t' is passed in/out of C++ as String&/Array&/Object&.
  auto const isReqPtrRef = [] (MaybeDataType t) {
    return isStringType(t) || isArrayLikeType(t) ||
           t == KindOfObject || t == KindOfResource;
  };

  if (FixupMap::eagerRecord(callee)) {
    auto const sp = srcLoc(env, inst, 1).reg();
    auto const spOffset = cellsToBytes(extra->spOffset.offset);
    auto const& marker = inst->marker();
    auto const pc = marker.fixupSk().unit()->entry() + marker.fixupBcOff();

    auto const synced_sp = v.makeReg();
    v << lea{sp[spOffset], synced_sp};
    emitEagerSyncPoint(v, pc, rvmtl(), srcLoc(env, inst, 0).reg(), synced_sp);
  }

  int returnOffset = rds::kVmMInstrStateOff +
                     offsetof(MInstrState, tvBuiltinReturn);
  auto args = argGroup(env, inst);

  if (!returnByValue) {
    if (isBuiltinByRef(funcReturnType)) {
      if (isReqPtrRef(funcReturnType)) {
        returnOffset += TVOFF(m_data);
      }
      // Pass the address of tvBuiltinReturn to the native function as the
      // location where it can construct the return Array, String, Object, or
      // Variant.
      args.addr(rvmtl(), returnOffset);
      args.indirect();
    }
  }

  // The srcs past the first two (sp and fp) are the arguments to the callee.
  auto srcNum = uint32_t{2};

  // Add the this_ or self_ argument for HNI builtins.
  if (callee->isMethod()) {
    if (callee->isStatic()) {
      args.ssa(srcNum);
      ++srcNum;
    } else {
      // Note that we don't support objects with vtables here (if they may need
      // a $this pointer adjustment).  This should be filtered out during irgen
      // or before.
      args.ssa(srcNum);
      ++srcNum;
    }
  }

  // Add the func_num_args() value if needed.
  if (callee->attrs() & AttrNumArgs) {
    // If `numNonDefault' is negative, this is passed as an src.
    if (extra->numNonDefault >= 0) {
      args.imm((int64_t)extra->numNonDefault);
    } else {
      args.ssa(srcNum);
      ++srcNum;
    }
  }

  // Add the positional arguments.
  for (uint32_t i = 0; i < callee->numParams(); ++i, ++srcNum) {
    auto const& pi = callee->params()[i];

    // Non-pointer and NativeArg args are passed by value.  String, Array,
    // Object, and Variant are passed by const&, i.e. a pointer to stack memory
    // holding the value, so we expect PtrToT types for these.  Pointers to
    // req::ptr types (String, Array, Object) need adjusting to point to
    // &ptr->m_data.
    if (TVOFF(m_data) && !pi.nativeArg && isReqPtrRef(pi.builtinType)) {
      assertx(inst->src(srcNum)->type() <= TPtrToGen);
      args.addr(srcLoc(env, inst, srcNum).reg(), TVOFF(m_data));
    } else if (pi.nativeArg && !pi.builtinType && !callee->byRef(i)) {
      // This condition indicates a MixedTV (i.e., TypedValue-by-value) arg.
      args.typedValue(srcNum);
    } else {
      args.ssa(srcNum, pi.builtinType == KindOfDouble);
    }
  }

  auto dest = [&] () -> CallDest {
    if (isBuiltinByRef(funcReturnType)) {
      if (!returnByValue) return kVoidDest; // indirect return
      return funcReturnType
        ? callDest(dstData) // String, Array, or Object
        : callDest(dstData, dstType); // Variant
    }
    return funcReturnType == KindOfDouble
      ? callDestDbl(env, inst)
      : callDest(env, inst);
  }();

  cgCallHelper(v, env, CallSpec::direct(callee->nativeFuncPtr()),
               dest, SyncOptions::Sync, args);

  // For primitive return types (int, bool, double) and returnByValue, the
  // return value is already in dstData/dstType.
  if (returnType.isSimpleType() || returnByValue) return;

  // For return by reference (String, Object, Array, Variant), the builtin
  // writes the return value into MInstrState::tvBuiltinReturn, from where it
  // has to be tested and copied.

  if (returnType.isReferenceType()) {
    // The return type is String, Array, or Object; fold nullptr to KindOfNull.
    assertx(isBuiltinByRef(funcReturnType) && isReqPtrRef(funcReturnType));

    v << load{rvmtl()[returnOffset], dstData};

    if (dstType.isValid()) {
      auto const sf = v.makeReg();
      auto const rtype = v.cns(returnType.toDataType());
      auto const nulltype = v.cns(KindOfNull);
      v << testq{dstData, dstData, sf};
      v << cmovb{CC_Z, sf, rtype, nulltype, dstType};
    }
    return;
  }

  if (returnType <= TCell || returnType <= TBoxedCell) {
    // The return type is Variant; fold KindOfUninit to KindOfNull.
    assertx(isBuiltinByRef(funcReturnType) && !isReqPtrRef(funcReturnType));
    static_assert(KindOfUninit == 0, "KindOfUninit must be 0 for test");

    v << load{rvmtl()[returnOffset + TVOFF(m_data)], dstData};

    if (dstType.isValid()) {
      auto const rtype = v.makeReg();
      v << loadb{rvmtl()[returnOffset + TVOFF(m_type)], rtype};

      auto const sf = v.makeReg();
      auto const nulltype = v.cns(KindOfNull);
      v << testb{rtype, rtype, sf};
      v << cmovb{CC_Z, sf, rtype, nulltype, dstType};
    }
    return;
  }

  not_reached();
}
/**
 * \a obj is an expression to a type of an QObject (or pointer to) that is the sender or the receiver
 * \a method is an expression like SIGNAL(....)  or SLOT(....)
 *
 * This function try to find the matching signal or slot declaration, and register its use.
 */
void QtSupport::handleSignalOrSlot(clang::Expr* obj, clang::Expr* method)
{
    if (!obj || !method) return;
    obj = obj->IgnoreImpCasts();
    method = method->IgnoreImpCasts();
    auto objType = obj->getType().getTypePtrOrNull();
    if (!objType) return;

    const clang::CXXRecordDecl* objClass = objType->getPointeeCXXRecordDecl();
    if (!objClass) {
        // It can be a non-pointer if called like:  foo.connect(....);
        objClass = objType->getAsCXXRecordDecl();
        if (!objClass) return;
    }

    const clang::StringLiteral *methodLiteral = clang::dyn_cast<clang::StringLiteral>(method);
    if (!methodLiteral) {
        // try qFlagLocation
        clang::CallExpr *flagLoc = clang::dyn_cast<clang::CallExpr>(method);

        if (!flagLoc || flagLoc->getNumArgs() != 1 || !flagLoc->getDirectCallee()
            || flagLoc->getDirectCallee()->getName() != "qFlagLocation") return;


        methodLiteral = clang::dyn_cast<clang::StringLiteral>(flagLoc->getArg(0)->IgnoreImpCasts());
        if (!methodLiteral) return;
    }
    if (methodLiteral->getCharByteWidth() != 1) return;


    auto signature = methodLiteral->getString().trim();
    if (signature.size() < 4)
        return;

    if (signature.find('\0') != signature.npos) {
        signature = signature.substr(0, signature.find('\0')).trim();
    }

    auto lParenPos = signature.find('(');
    auto rParenPos = signature.find(')');
    if (rParenPos == std::string::npos || rParenPos < lParenPos || lParenPos < 2)
        return;

    llvm::StringRef methodName = signature.slice(1 , lParenPos).trim();

    // Try to find the method which match this name in the given class or bases.
    auto candidates = lookUpCandidates(objClass, methodName);

    clang::LangOptions lo;
    lo.CPlusPlus = true;
    lo.Bool = true;
    clang::PrintingPolicy policy(lo);
    policy.SuppressScope = true;

    auto argPos = lParenPos + 1;
    unsigned int arg = 0;
    while (argPos < signature.size() && !candidates.empty()) {

        // Find next comma to extract the next argument
        auto searchPos = argPos;
        while (searchPos < signature.size() && signature[searchPos] != ','
                && signature[searchPos] != ')') {
            if (signature[searchPos] == '<') {
                int depth = 0;
                int templDepth = 0;
                searchPos++;
                while(searchPos < signature.size() && depth >= 0 && templDepth >= 0) {
                    switch (signature[searchPos]) {
                        case '(': case '[': case '{': depth++; break;
                        case ')': case ']': case '}': depth--; break;
                        case '>': if (depth == 0) templDepth--; break;
                        case '<': if (depth == 0) templDepth++; break;
                    }
                    ++searchPos;
                }
                continue;
            }
            ++searchPos;
        }

        if (searchPos == signature.size())
            return;

        llvm::StringRef argument = signature.substr(argPos, searchPos - argPos).trim();
        // Skip the const at the beginning

        if (argument.startswith("const ") && argument.endswith("&"))
            argument = argument.slice(6, argument.size()-1).trim();

        argPos = searchPos + 1;

        if (argument.empty() && signature[searchPos] == ')' && arg == 0)
            break; //No arguments


        //Now go over the candidates and prune the impossible ones.
        auto it = candidates.begin();
        while (it != candidates.end()) {
            if ((*it)->getNumParams() < arg + 1) {
                // Not enough argument
                it = candidates.erase(it);
                continue;
            }

            auto type = (*it)->getParamDecl(arg)->getType();

            // remove const or const &
            if (type->isReferenceType() && type.getNonReferenceType().isConstQualified())
                type = type.getNonReferenceType();
            type.removeLocalConst();

            auto typeString_ = type.getAsString(policy);

            auto typeString = llvm::StringRef(typeString_).trim();

            // Now compare the two string without mathcin spaces,
            auto sigIt = argument.begin();
            auto parIt = typeString.begin();
            while (sigIt != argument.end() && parIt != typeString.end()) {
                if (*sigIt == *parIt) {
                    ++sigIt;
                    ++parIt;
                } else if (*sigIt == ' ') {
                    ++sigIt;
                } else if (*parIt == ' ') {
                    ++parIt;
                } else if (*sigIt == 'n' && llvm::StringRef(sigIt, 9).startswith("nsigned ")) {
                    // skip unsigned
                    sigIt += 8;
                } else if (*parIt == 'n' && llvm::StringRef(parIt, 9).startswith("nsigned ")) {
                    // skip unsigned
                    parIt += 8;
                } else {
                    break;
                }
            }

            if (sigIt != argument.end() || parIt != typeString.end()) {
                // Did not match.
                it = candidates.erase(it);
                continue;
            }

            ++it;
        }

        arg++;
        if (signature[searchPos] == ')')
            break;
    }

    if (argPos != signature.size())
        return;


    // Remove candidates that needs more argument
    candidates.erase(std::remove_if(candidates.begin(), candidates.end(), [=](clang::CXXMethodDecl *it) {
            return it->getMinRequiredArguments() > arg &&
                !(it->getNumParams() == arg+1 && it->getParamDecl(arg)->getType().getAsString(policy) == "QPrivateSignal");
        }), candidates.end());

    if (candidates.empty())
        return;

    auto used = candidates.front();



    clang::SourceRange range = methodLiteral->getSourceRange();
    if (methodLiteral->getNumConcatenated() >= 2) {
        auto &sm = annotator.getSourceMgr();
        // Goes two level up in the macro expension:  First level is the # expansion,  Second level is SIGNAL macro
        auto r = sm.getImmediateExpansionRange(methodLiteral->getStrTokenLoc(1));
#if CLANG_VERSION_MAJOR < 7
        range = { sm.getImmediateExpansionRange(r.first).first, sm.getImmediateExpansionRange(r.second).second };
#else
        range = { sm.getImmediateExpansionRange(r.getBegin()).getBegin(), sm.getImmediateExpansionRange(r.getEnd()).getEnd() };
#endif

        // now remove the SIGNAL or SLOT macro from the range.
        auto skip = clang::Lexer::MeasureTokenLength(range.getBegin(), sm, annotator.getLangOpts());
        range.setBegin(range.getBegin().getLocWithOffset(skip+1));
        // remove the ')' while we are on it
        range.setEnd(range.getEnd().getLocWithOffset(-1));

    }

    annotator.registerUse(used, range, Annotator::Call, currentContext, Annotator::Use_Address);
}