Пример #1
0
SSATmp* IRBuilder::preOptimizeLdLocAddr(IRInstruction* inst) {
  auto const locId = inst->extra<LdLocAddr>()->locId;
  auto const type = localType(locId, DataTypeGeneric);
  assert(inst->typeParam().deref() >= type);
  inst->setTypeParam(Type::mostRefined(type.ptr(), inst->typeParam()));
  return nullptr;
}
Пример #2
0
SSATmp* TraceBuilder::preOptimizeCheckLoc(IRInstruction* inst) {
  auto const locId = inst->extra<CheckLoc>()->locId;
  Type typeParam = inst->typeParam();

  if (auto const prevValue = localValue(locId, DataTypeGeneric)) {
    return gen(CheckType, typeParam, inst->taken(), prevValue);
  }

  auto const prevType = localType(locId, DataTypeSpecific);

  if (prevType <= typeParam) {
    return inst->src(0);
  } else {
    //
    // Normally, it doesn't make sense to be checking something that's
    // deemed to fail.  Incompatible boxed types are ok though, since
    // we don't track them precisely, but instead check them at every
    // use.
    //
    // However, in JitPGO mode right now, this pathological case can
    // happen, because profile counters are not accurate and we
    // currently don't analyze Block post-conditions when picking its
    // successors during region selection.  This can lead to
    // incompatible types in blocks selected for the same region.
    //
    if (!typeParam.isBoxed() || !prevType.isBoxed()) {
      if ((typeParam & prevType) == Type::Bottom) {
        assert(RuntimeOption::EvalJitPGO);
        return gen(Jmp, inst->taken());
      }
    }
  }

  return nullptr;
}
Пример #3
0
SSATmp* TraceBuilder::preOptimizeAssertLoc(IRInstruction* inst) {
  auto const locId = inst->extra<AssertLoc>()->locId;

  auto const prevType = localType(locId, DataTypeGeneric);
  auto const typeParam = inst->typeParam();

  if (prevType.not(typeParam)) {
    /* Task #2553746
     * This is triggering for a case where the tracked state says the local is
     * InitNull but the AssertLoc says it's Str. */
    static auto const error =
      makeStaticString("Internal error: static analysis was "
                       "wrong about a local variable's type.");
    auto* errorInst = m_unit.gen(RaiseError, inst->marker(), cns(error));
    inst->become(m_unit, errorInst);

    // It's not a disaster to generate this in unreachable code for
    // now. t2590033.
    if (false) {
      assert_log(false,  [&]{
          return folly::format("\npreOptimizeAssertLoc: prevType: {} "
                               "typeParam: {}\nin instr: {}\nin trace: {}\n",
                               prevType.toString(),
                               typeParam.toString(),
                               inst->toString(),
                               m_unit.main()->toString()).str();
        });
    }
  } else if (shouldElideAssertType(prevType, typeParam, nullptr)) {
    // The type we're asserting is worse than the last known type.
    return inst->src(0);
  }
  return nullptr;
}
Пример #4
0
SSATmp* IRBuilder::preOptimizeCheckLoc(IRInstruction* inst) {
  auto const locId = inst->extra<CheckLoc>()->locId;
  Type typeParam   = inst->typeParam();
  SSATmp* src      = inst->src(0);

  if (auto const prevValue = localValue(locId, DataTypeGeneric)) {
    return gen(CheckType, typeParam, inst->taken(), prevValue);
  }

  auto const prevType = localType(locId, DataTypeGeneric);

  if (prevType <= typeParam) {
    return src;
  }

  if (prevType.not(typeParam)) {
    if (typeParam.isBoxed() && prevType.isBoxed()) {
      /* When both types are non-intersecting boxed types, we're just
       * updating the inner type hint. This requires no runtime work. */
      constrainLocal(locId, DataTypeCountness, "preOptimizeCheckLoc");
      return gen(AssertLoc, LocalId(locId), typeParam, src);
    }
    /* This check will always fail. It's probably due to an incorrect
     * prediction. Generate a Jmp, and return the source because
     * following instructions may depend on the output of CheckLoc
     * (they'll be DCEd later).  Note that we can't use convertToJmp
     * because the return value isn't nullptr, so the original
     * instruction won't be inserted into the stream. */
    gen(Jmp, inst->taken());
    return src;
  }

  return nullptr;
}
Пример #5
0
SSATmp* IRBuilder::preOptimizeDecRefLoc(IRInstruction* inst) {
  auto const locId = inst->extra<DecRefLoc>()->locId;

  /*
   * Refine the type if we can.
   *
   * We can't really rely on the types held in the boxed values since aliasing
   * stores may change them, and we only guard during LdRef.  So we have to
   * change any boxed type to BoxedCell.
   *
   * DataTypeGeneric is used because we don't want a DecRef to be the only
   * thing keeping a guard around. This code is designed to tolerate the
   * incoming type being relaxed.
   */
  auto knownType = localType(locId, DataTypeGeneric);
  if (knownType.isBoxed()) {
    knownType = Type::BoxedCell;
  }

  /*
   * If we have the local value in flight, use a DecRef on it instead of doing
   * it in memory.
   */
  if (auto tmp = localValue(locId, DataTypeGeneric)) {
    gen(DecRef, tmp);
    inst->convertToNop();
    return nullptr;
  }

  if (!typeMightRelax()) {
    inst->setTypeParam(std::min(knownType, inst->typeParam()));
  }

  return nullptr;
}
Пример #6
0
SSATmp* TraceBuilder::preOptimizeStLoc(IRInstruction* inst) {
  auto locId = inst->extra<StLoc>()->locId;
  auto const curType = localType(locId, DataTypeGeneric);
  auto const newType = inst->src(1)->type();

  assert(inst->typeParam().equals(Type::None));

  // There's no need to store the type if it's going to be the same
  // KindOfFoo. We still have to store string types because we don't
  // guard on KindOfStaticString vs. KindOfString.
  auto const bothBoxed = curType.isBoxed() && newType.isBoxed();
  auto const sameUnboxed = curType != Type::None && // TODO(#2135185)
    curType.isSameKindOf(newType) &&
    !curType.isString();
  if (bothBoxed || sameUnboxed) {
    // TODO(t2598894) once relaxGuards supports proper type reflowing, we
    // should be able to relax the constraint here and degrade StLocNT to
    // StLoc if we relax its input.
    if (sameUnboxed) constrainLocal(locId, DataTypeSpecific,
                                    "StLoc -> StLocNT");
    inst->setOpcode(StLocNT);
  }

  return nullptr;
}
Пример #7
0
SSATmp* TraceBuilder::preOptimizeDecRefLoc(IRInstruction* inst) {
  auto const locId = inst->extra<DecRefLoc>()->locId;

  /*
   * Refine the type if we can.
   *
   * We can't really rely on the types held in the boxed values since
   * aliasing stores may change them, and we only guard during LdRef.
   * So we have to change any boxed type to BoxedCell.
   */
  auto knownType = localType(locId, DataTypeCountness);
  if (knownType.isBoxed()) {
    knownType = Type::BoxedCell;
  }
  if (knownType != Type::None) { // TODO(#2135185)
    inst->setTypeParam(
      Type::mostRefined(knownType, inst->typeParam())
    );
  }

  /*
   * If we have the local value in flight, use a DecRef on it instead
   * of doing it in memory.
   */
  if (auto tmp = localValue(locId, DataTypeCountness)) {
    gen(DecRef, tmp);
    inst->convertToNop();
  }

  return nullptr;
}
Пример #8
0
SSATmp* TraceBuilder::preOptimizeAssertLoc(IRInstruction* inst) {
  auto const locId = inst->extra<AssertLoc>()->locId;
  auto const prevType = localType(locId, DataTypeGeneric);
  auto const typeParam = inst->typeParam();

  if (!prevType.equals(Type::None) && !typeParam.strictSubtypeOf(prevType)) {
    if (!prevType.subtypeOf(typeParam)) {
      /* Task #2553746
       * This is triggering for a case where the tracked state says the local is
       * InitNull but the AssertLoc says it's Str. */
      static auto const error =
        StringData::GetStaticString("Internal error: static analysis was "
                                    "wrong about a local variable's type.");
      auto* errorInst = m_irFactory.gen(RaiseError, inst->marker(), cns(error));
      inst->become(&m_irFactory, errorInst);

      // It's not a disaster to generate this in unreachable code for
      // now. t2590033.
      if (false) {
        assert_log(false,  [&]{
            IRTrace& mainTrace = trace()->isMain() ? *trace()
                                                   : *(trace()->main());
            return folly::format("\npreOptimizeAssertLoc: prevType: {} "
                                 "typeParam: {}\nin instr: {}\nin trace: {}\n",
                                 prevType.toString(), typeParam.toString(),
                                 inst->toString(), mainTrace.toString()).str();
          });
      }
    } else {
      inst->convertToNop();
    }
  }
  return nullptr;
}
Пример #9
0
SSATmp* TraceBuilder::preOptimizeLdLocAddr(IRInstruction* inst) {
  auto const locId = inst->extra<LdLocAddr>()->locId;
  auto const type = localType(locId, DataTypeGeneric);
  if (!type.equals(Type::None)) { // TODO(#2135185)
    inst->setTypeParam(Type::mostRefined(type.ptr(), inst->typeParam()));
  }
  return nullptr;
}
Пример #10
0
SSATmp* IRBuilder::preOptimizeLdLoc(IRInstruction* inst) {
  auto const locId = inst->extra<LdLoc>()->locId;
  if (auto tmp = localValue(locId, DataTypeGeneric)) {
    return tmp;
  }

  auto const type = localType(locId, DataTypeGeneric);
  // If FrameState's type isn't as good as the type param, we're missing
  // information in the IR.
  assert(inst->typeParam() >= type);
  inst->setTypeParam(Type::mostRefined(type, inst->typeParam()));
  return nullptr;
}
Пример #11
0
SSATmp* IRBuilder::preOptimizeAssertLoc(IRInstruction* inst) {
  auto const locId = inst->extra<AssertLoc>()->locId;

  if (auto const prevValue = localValue(locId, DataTypeGeneric)) {
    return gen(AssertType, inst->typeParam(), prevValue);
  }

  return m_simplifier.simplifyAssertTypeOp(
    inst, localType(locId, DataTypeGeneric), [&](TypeConstraint tc) {
      constrainLocal(locId, tc, "preOptimizeAssertLoc");
    }
  );
}
Пример #12
0
SSATmp* TraceBuilder::preOptimizeAssertLoc(IRInstruction* inst) {
  auto const locId = inst->extra<AssertLoc>()->locId;

  auto const prevType = localType(locId, DataTypeGeneric);
  auto const typeParam = inst->typeParam();

  if (prevType.not(typeParam)) {
    TRACE_PUNT("Invalid AssertLoc");
  }

  if (shouldElideAssertType(prevType, typeParam, nullptr)) {
    return inst->src(0);
  }

  if (filterAssertType(inst, prevType)) {
    constrainLocal(locId, categoryForType(prevType), "AssertLoc");
  }

  return nullptr;
}
Пример #13
0
SSATmp* IRBuilder::preOptimizeStLoc(IRInstruction* inst) {
  // Guard relaxation might change the current local type, so don't try to
  // change to StLocNT until after relaxation happens.
  if (typeMightRelax()) return nullptr;

  auto locId = inst->extra<StLoc>()->locId;
  auto const curType = localType(locId, DataTypeGeneric);
  auto const newType = inst->src(1)->type();

  assert(!inst->hasTypeParam());

  /*
   * There's no need to store the type if it's going to be the same
   * KindOfFoo.  We'll still have to store string types because we
   * aren't specific about storing KindOfStaticString
   * vs. KindOfString, and a Type::Null might mean KindOfUninit or
   * KindOfNull.
   */
  auto const bothBoxed = curType.isBoxed() && newType.isBoxed();
  auto const sameUnboxed = [&] {
    auto avoidable = { Type::Uninit,
                       Type::InitNull,
                       Type::Bool,
                       Type::Int,
                       Type::Dbl,
                       // No strings.
                       Type::Arr,
                       Type::Obj,
                       Type::Res };
    for (auto t : avoidable) {
      if (curType <= t && newType <= t) return true;
    }
    return false;
  };
  if (bothBoxed || sameUnboxed()) {
    inst->setOpcode(StLocNT);
  }

  return nullptr;
}
Пример #14
0
SSATmp* TraceBuilder::preOptimizeStLoc(IRInstruction* inst) {
  // Guard relaxation might change the current local type, so don't try to
  // change to StLocNT until after relaxation happens.
  if (!inReoptimize()) return nullptr;

  auto locId = inst->extra<StLoc>()->locId;
  auto const curType = localType(locId, DataTypeGeneric);
  auto const newType = inst->src(1)->type();

  assert(inst->typeParam() == Type::None);

  // There's no need to store the type if it's going to be the same
  // KindOfFoo. We still have to store string types because we don't
  // guard on KindOfStaticString vs. KindOfString.
  auto const bothBoxed = curType.isBoxed() && newType.isBoxed();
  auto const sameUnboxed =
    curType.isSameKindOf(newType) && !curType.isString();
  if (bothBoxed || sameUnboxed) {
    inst->setOpcode(StLocNT);
  }

  return nullptr;
}
Пример #15
0
void CodeGenPB::go() {

    // first analyse the objects if they are embedded objects
    // for all objects that could accept such an object
    for(int i=0; i < m_objects.size(); i++) {
        // for all objects
        XSDObject *obj1 = m_objects.at(i);

        // find if there is another object that refers to the obj
        for(int h=0; h < m_objects.size(); h++) {

            XSDObject *obj2 = m_objects.at(h);

            // refers means obj2 has an attribute of type obj1
            for(int j=0; j < obj2->attributes().size(); j++) {
                XSDAttribute *attr = obj2->attributes().at(j);
                QString objType = attr->type();

                if (objType == obj1->name()) {
                    obj1->setEmbedded();    // obj1 is embedded in obj2
                }
            }
        }
    }

    // open the proto filea
    QString baseName;
    if (m_prefix != "") {
        baseName = m_outDir + "/" + m_prefix + ".proto";
    } else {
        baseName = m_outDir + "/interface.proto"; // must have prefix
    }
    QFile protoFile(baseName);
    if (!protoFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        std::cerr << QString("cannot create file: %1").arg(baseName).toLatin1().data() << std::endl;
        std::exit(-1);
    }
    QTextStream protoFileOut(&protoFile);

    // GPL header
    protoFileOut << writeHeader( baseName );

    for(int i=0; i < m_objects.size(); i++) {
        // get a class
        XSDObject *obj = m_objects.at(i);

        // get some vars we frequently use
        QString name = obj->name();
        QString upperName = name.toUpper();
        QVector<XSDAttribute*>attributes = obj->attributes();
        QMap<QString, QString>fixedValues = obj->fixedValues();

        // report
        std::cout << QString("creating class: %1").arg(className(name)).toLatin1().data() << std::endl;

        //-----------------------------------------------------------------------------------------------
        // generate the header
        //-----------------------------------------------------------------------------------------------

        // define the class
        protoFileOut << "\nmessage " << className(name) << " { \n";
        if (obj->hasBaseClass()) {
            protoFileOut << "\nextend " << className(obj->baseClass()) << " { \n";
        }

        // the tag counter
        int tag = 1;

        // variables  section
        for(int j=0; j < attributes.size(); j++) {
            XSDAttribute *attr = attributes.at(j);
            QString type = localType(attr->type()); // convert to cpp types
            // definition
            if (attr->isScalar()) { // there more then one
                protoFileOut << "    repeated " << type << " " << variableName(attr->name()) << " = " << tag++ << ";\n";
            } else if (!attr->required() || obj->isMerged()) {
                protoFileOut << "    optional " << type << " " << variableName(attr->name()) <<  " = " << tag++ << ";\n";
            } else {
                protoFileOut << "    required " << type << " " << variableName(attr->name()) << " = " << tag++ << ";\n";
            }
        }

        // and fixed values
        for(int j=0; j < fixedValues.size(); j++) {
            QString attrName = fixedValues.keys().at(j);
            protoFileOut << "    required string " << variableName(attrName) << " = " << tag++ << ";\n";
        }
        protoFileOut << "}\n";
        if (obj->hasBaseClass()) {
            protoFileOut << "}\n";
        }
    }

    // close and flush
    protoFileOut.flush();
    protoFile.close();
}