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;
}