SynthTrace getTrace()

in API/hermes/SynthTraceParser.cpp [248:536]


SynthTrace getTrace(JSONArray *array, SynthTrace::ObjectID globalObjID) {
  using RecordType = SynthTrace::RecordType;
  SynthTrace trace(globalObjID, ::hermes::vm::RuntimeConfig());
  auto getListOfTraceValues =
      [](JSONArray *array,
         SynthTrace &trace) -> std::vector<SynthTrace::TraceValue> {
    std::vector<SynthTrace::TraceValue> values;
    std::transform(
        array->begin(),
        array->end(),
        std::back_inserter(values),
        [&trace](const JSONValue *value) -> SynthTrace::TraceValue {
          if (value->getKind() != JSONKind::String) {
            throw std::invalid_argument("Array should contain only strings");
          }
          return trace.decode(llvh::cast<JSONString>(value)->c_str());
        });
    return values;
  };
  for (auto *val : *array) {
    auto *obj = llvh::cast<JSONObject>(val);
    auto timeFromStart =
        std::chrono::milliseconds(getNumberAs<uint64_t>(obj->get("time"), 0));
    std::stringstream ss;
    RecordType kind;
    ss << llvh::cast<JSONString>(obj->get("type"))->c_str();
    ss >> kind;
    // Common properties, they may not exist on all objects so use a
    // dynamic cast.
    auto *objID = llvh::dyn_cast_or_null<JSONNumber>(obj->get("objID"));
    auto *hostObjID =
        llvh::dyn_cast_or_null<JSONNumber>(obj->get("hostObjectID"));
    auto *funcID = llvh::dyn_cast_or_null<JSONNumber>(obj->get("functionID"));
    auto *propID = llvh::dyn_cast_or_null<JSONNumber>(obj->get("propID"));
    auto *propNameID =
        llvh::dyn_cast_or_null<JSONNumber>(obj->get("propNameID"));
    auto *propName = llvh::dyn_cast_or_null<JSONString>(obj->get("propName"));
    auto *propValue = llvh::dyn_cast_or_null<JSONString>(obj->get("value"));
    auto *arrayIndex = llvh::dyn_cast_or_null<JSONNumber>(obj->get("index"));
    auto *callArgs = llvh::dyn_cast_or_null<JSONArray>(obj->get("args"));
    auto *thisArg = llvh::dyn_cast_or_null<JSONString>(obj->get("thisArg"));
    auto *retval = llvh::dyn_cast_or_null<JSONString>(obj->get("retval"));
    switch (kind) {
      case RecordType::BeginExecJS: {
        std::string sourceURL;
        ::hermes::SHA1 hash{};
        bool sourceIsBytecode{false};
        if (JSONString *sourceURLJSON =
                llvh::dyn_cast_or_null<JSONString>(obj->get("sourceURL"))) {
          sourceURL = sourceURLJSON->str();
        }
        if (JSONString *sourceHash =
                llvh::dyn_cast_or_null<JSONString>(obj->get("sourceHash"))) {
          hash = parseHashStrAsNumber(sourceHash->str());
        }
        if (JSONBoolean *sourceIsBytecodeJson =
                llvh::dyn_cast_or_null<JSONBoolean>(
                    obj->get("sourceIsBytecode"))) {
          sourceIsBytecode = sourceIsBytecodeJson->getValue();
        }
        trace.emplace_back<SynthTrace::BeginExecJSRecord>(
            timeFromStart,
            std::move(sourceURL),
            std::move(hash),
            sourceIsBytecode);
        break;
      }
      case RecordType::EndExecJS:
        trace.emplace_back<SynthTrace::EndExecJSRecord>(
            timeFromStart, trace.decode(retval->c_str()));
        break;
      case RecordType::Marker:
        trace.emplace_back<SynthTrace::MarkerRecord>(
            timeFromStart, llvh::cast<JSONString>(obj->get("tag"))->c_str());
        break;
      case RecordType::CreateObject:
        trace.emplace_back<SynthTrace::CreateObjectRecord>(
            timeFromStart, objID->getValue());
        break;
      case RecordType::DrainMicrotasks: {
        int maxMicrotasksHint = getNumberAs<int>(obj->get("maxMicrotasksHint"));
        trace.emplace_back<SynthTrace::DrainMicrotasksRecord>(
            timeFromStart, maxMicrotasksHint);
        break;
      }
      case RecordType::CreateString: {
        auto encoding =
            llvh::dyn_cast_or_null<JSONString>(obj->get("encoding"));
        bool isAscii = false;
        if (encoding->str() == "ASCII") {
          isAscii = true;
        } else {
          assert(encoding->str() == "UTF-8");
        }
        auto str = llvh::dyn_cast_or_null<JSONString>(obj->get("chars"));
        if (isAscii) {
          trace.emplace_back<SynthTrace::CreateStringRecord>(
              timeFromStart,
              objID->getValue(),
              str->str().data(),
              str->str().size());
        } else {
          trace.emplace_back<SynthTrace::CreateStringRecord>(
              timeFromStart,
              objID->getValue(),
              reinterpret_cast<const uint8_t *>(str->str().data()),
              str->str().size());
        }
        break;
      }
      case RecordType::CreatePropNameID: {
        auto id = llvh::dyn_cast_or_null<JSONNumber>(obj->get("objID"));
        if (propValue) {
          trace.emplace_back<SynthTrace::CreatePropNameIDRecord>(
              timeFromStart, id->getValue(), trace.decode(propValue->c_str()));
        } else {
          auto encoding =
              llvh::dyn_cast_or_null<JSONString>(obj->get("encoding"));
          bool isAscii = false;
          if (encoding->str() == "ASCII") {
            isAscii = true;
          } else {
            assert(encoding->str() == "UTF-8");
          }
          auto str = llvh::dyn_cast_or_null<JSONString>(obj->get("chars"));
          if (isAscii) {
            trace.emplace_back<SynthTrace::CreatePropNameIDRecord>(
                timeFromStart,
                id->getValue(),
                str->str().data(),
                str->str().size());
          } else {
            trace.emplace_back<SynthTrace::CreatePropNameIDRecord>(
                timeFromStart,
                id->getValue(),
                reinterpret_cast<const uint8_t *>(str->str().data()),
                str->str().size());
          }
        }
        break;
      }
      case RecordType::CreateHostObject:
        trace.emplace_back<SynthTrace::CreateHostObjectRecord>(
            timeFromStart, objID->getValue());
        break;
      case RecordType::CreateHostFunction: {
        unsigned paramCount = 0;
        if (JSONNumber *jsonParamCount = llvh::dyn_cast_or_null<JSONNumber>(
                obj->get("parameterCount"))) {
          paramCount = jsonParamCount->getValue();
        }
        std::string functionName;
        if (JSONString *jsonFunctionName =
                llvh::dyn_cast_or_null<JSONString>(obj->get("functionName"))) {
          functionName = jsonFunctionName->str();
        }
        trace.emplace_back<SynthTrace::CreateHostFunctionRecord>(
            timeFromStart,
            objID->getValue(),
            propNameID->getValue(),
#ifdef HERMESVM_API_TRACE_DEBUG
            functionName,
#endif
            paramCount);
        break;
      }
      case RecordType::GetProperty:
        trace.emplace_back<SynthTrace::GetPropertyRecord>(
            timeFromStart,
            objID->getValue(),
            propID->getValue(),
#ifdef HERMESVM_API_TRACE_DEBUG
            std::string(propName->c_str()),
#endif
            trace.decode(propValue->c_str()));
        break;
      case RecordType::SetProperty:
        trace.emplace_back<SynthTrace::SetPropertyRecord>(
            timeFromStart,
            objID->getValue(),
            propID->getValue(),
#ifdef HERMESVM_API_TRACE_DEBUG
            std::string(propName->c_str()),
#endif
            trace.decode(propValue->c_str()));
        break;
      case RecordType::HasProperty:
        trace.emplace_back<SynthTrace::HasPropertyRecord>(
            timeFromStart,
            objID->getValue(),
            propID->getValue()
#ifdef HERMESVM_API_TRACE_DEBUG
                ,
            std::string(propName->c_str())
#endif
        );
        break;
      case RecordType::GetPropertyNames:
        trace.emplace_back<SynthTrace::GetPropertyNamesRecord>(
            timeFromStart,
            objID->getValue(),
            getNumberAs<SynthTrace::ObjectID>(obj->get("propNamesID")));
        break;
      case RecordType::CreateArray:
        trace.emplace_back<SynthTrace::CreateArrayRecord>(
            timeFromStart,
            objID->getValue(),
            getNumberAs<uint64_t>(obj->get("length")));
        break;
      case RecordType::ArrayRead:
        trace.emplace_back<SynthTrace::ArrayReadRecord>(
            timeFromStart,
            objID->getValue(),
            arrayIndex->getValue(),
            trace.decode(propValue->c_str()));
        break;
      case RecordType::ArrayWrite:
        trace.emplace_back<SynthTrace::ArrayWriteRecord>(
            timeFromStart,
            objID->getValue(),
            arrayIndex->getValue(),
            trace.decode(propValue->c_str()));
        break;
      case RecordType::CallFromNative:
        trace.emplace_back<SynthTrace::CallFromNativeRecord>(
            timeFromStart,
            funcID->getValue(),
            trace.decode(thisArg->c_str()),
            getListOfTraceValues(callArgs, trace));
        break;
      case RecordType::ConstructFromNative:
        trace.emplace_back<SynthTrace::ConstructFromNativeRecord>(
            timeFromStart,
            funcID->getValue(),
            trace.decode(thisArg->c_str()),
            getListOfTraceValues(callArgs, trace));
        break;
      case RecordType::ReturnFromNative:
        trace.emplace_back<SynthTrace::ReturnFromNativeRecord>(
            timeFromStart, trace.decode(retval->c_str()));
        break;
      case RecordType::ReturnToNative:
        trace.emplace_back<SynthTrace::ReturnToNativeRecord>(
            timeFromStart, trace.decode(retval->c_str()));
        break;
      case RecordType::CallToNative:
        trace.emplace_back<SynthTrace::CallToNativeRecord>(
            timeFromStart,
            funcID->getValue(),
            trace.decode(thisArg->c_str()),
            getListOfTraceValues(callArgs, trace));
        break;
      case RecordType::GetPropertyNative:
        trace.emplace_back<SynthTrace::GetPropertyNativeRecord>(
            timeFromStart,
            hostObjID->getValue(),
            propNameID->getValue(),
            propName->c_str());
        break;
      case RecordType::GetPropertyNativeReturn:
        trace.emplace_back<SynthTrace::GetPropertyNativeReturnRecord>(
            timeFromStart, trace.decode(retval->c_str()));
        break;
      case RecordType::SetPropertyNative:
        trace.emplace_back<SynthTrace::SetPropertyNativeRecord>(
            timeFromStart,
            hostObjID->getValue(),
            propNameID->getValue(),
            propName->c_str(),
            trace.decode(propValue->c_str()));
        break;
      case RecordType::SetPropertyNativeReturn:
        trace.emplace_back<SynthTrace::SetPropertyNativeReturnRecord>(
            timeFromStart);
        break;
      case RecordType::GetNativePropertyNames:
        trace.emplace_back<SynthTrace::GetNativePropertyNamesRecord>(
            timeFromStart, hostObjID->getValue());
        break;
      case RecordType::GetNativePropertyNamesReturn:
        trace.emplace_back<SynthTrace::GetNativePropertyNamesReturnRecord>(
            timeFromStart,
            getListOfStrings<std::vector>(
                llvh::cast<JSONArray>(obj->get("properties"))));
        break;
    }
  }
  return trace;
}