123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865 |
- /*
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
- #ifndef HERMES_SYNTHTRACE_H
- #define HERMES_SYNTHTRACE_H
- #ifdef HERMESVM_API_TRACE
- #include "hermes/Public/RuntimeConfig.h"
- #include "hermes/Support/JSONEmitter.h"
- #include "hermes/Support/StringSetVector.h"
- #include "hermes/VM/HermesValue.h"
- #include "hermes/VM/MockedEnvironment.h"
- #include "hermes/VM/Operations.h"
- #include <chrono>
- #include <cstdlib>
- #include <memory>
- #include <string>
- #include <vector>
- namespace llvm {
- // Forward declaration to avoid including llvm headers.
- class raw_ostream;
- } // namespace llvm
- namespace facebook {
- namespace hermes {
- namespace tracing {
- /// A SynthTrace is a list of events that occur in a run of a JS file by a
- /// runtime that uses JSI.
- /// It can be serialized into JSON and written to a llvm::raw_ostream.
- class SynthTrace {
- public:
- using ObjectID = uint64_t;
- /// A tagged union representing different types available in the trace.
- /// HermesValue doesn't have to be used, but it is an efficient way
- /// of encoding a type tag and a value. std::variant is another option.
- /// NOTE: Since HermesValue can only store 64-bit values, strings need to be
- /// changed into a table index.
- using TraceValue = ::hermes::vm::HermesValue;
- /// A TimePoint is a time when some event occurred.
- using TimePoint = std::chrono::steady_clock::time_point;
- using TimeSinceStart = std::chrono::milliseconds;
- static constexpr size_t kHashNumBytes = 20;
- /// RecordType is a tag used to differentiate which type of record it is.
- /// There should be a unique tag for each record type.
- enum class RecordType {
- BeginExecJS,
- EndExecJS,
- Marker,
- CreateObject,
- CreateHostObject,
- CreateHostFunction,
- GetProperty,
- SetProperty,
- HasProperty,
- GetPropertyNames,
- CreateArray,
- ArrayRead,
- ArrayWrite,
- CallFromNative,
- ConstructFromNative,
- ReturnFromNative,
- ReturnToNative,
- CallToNative,
- GetPropertyNative,
- GetPropertyNativeReturn,
- SetPropertyNative,
- SetPropertyNativeReturn,
- GetNativePropertyNames,
- GetNativePropertyNamesReturn,
- };
- /// A Record is one element of a trace.
- struct Record {
- /// The time at which this event occurred with respect to the start of
- /// execution.
- /// NOTE: This is not compared in the \c operator= in order for tests to
- /// pass.
- const TimeSinceStart time_;
- explicit Record() = delete;
- explicit Record(TimeSinceStart time) : time_(time) {}
- virtual ~Record() = default;
- /// Write out a serialization of this Record.
- /// \param json An emitter connected to an ostream which will write out
- /// JSON.
- void toJSON(::hermes::JSONEmitter &json, const SynthTrace &trace) const;
- virtual RecordType getType() const = 0;
- /// \return A list of object ids that are defined by this record.
- /// Defined means that the record would produce that object as a locally
- /// accessible value if it were executed.
- virtual std::vector<ObjectID> defs() const {
- return {};
- }
- /// \return A list of object ids that are used by this record.
- /// Used means that the record would use that object as a value if it were
- /// executed.
- /// If a record uses an object, then some preceding record (either in the
- /// same function invocation, or somewhere globally) must provide a
- /// definition.
- virtual std::vector<ObjectID> uses() const {
- return {};
- }
- protected:
- /// Compare records for equality. Derived classes should override this, call
- /// their parent, and mark any public versions as "final".
- virtual bool operator==(const Record &that) const {
- return getType() == that.getType();
- }
- /// Emit JSON fields into \p os, excluding the closing curly brace.
- /// NOTE: This is overridable, and non-abstract children should call the
- /// parent.
- virtual void toJSONInternal(
- ::hermes::JSONEmitter &json,
- const SynthTrace &trace) const;
- };
- /// If \p traceStream is non-null, the trace will be written to that
- /// stream. Otherwise, no trace is written.
- explicit SynthTrace(
- ObjectID globalObjID,
- const ::hermes::vm::RuntimeConfig &conf,
- std::unique_ptr<llvm::raw_ostream> traceStream = nullptr);
- template <typename T, typename... Args>
- void emplace_back(Args &&... args) {
- records_.emplace_back(new T(std::forward<Args>(args)...));
- flushRecordsIfNecessary();
- }
- const std::vector<std::unique_ptr<Record>> &records() const {
- return records_;
- }
- ObjectID globalObjID() const {
- return globalObjID_;
- }
- /// Given a trace value, turn it into its typed string.
- std::string encode(TraceValue value) const;
- /// Encode an undefined JS value for the trace.
- static TraceValue encodeUndefined();
- /// Encode a null JS value for the trace.
- static TraceValue encodeNull();
- /// Encode a boolean JS value for the trace.
- static TraceValue encodeBool(bool value);
- /// Encodes a numeric value for the trace.
- static TraceValue encodeNumber(double value);
- /// Encodes an object for the trace as a unique id.
- static TraceValue encodeObject(ObjectID objID);
- /// Encodes a string for the trace. Adds it to the string table if it hasn't
- /// been seen before.
- TraceValue encodeString(const std::string &value);
- /// Decodes a string into a trace value. It can add to the string table.
- TraceValue decode(const std::string &);
- /// Extracts an object ID from a trace value.
- /// \pre The value must be an object.
- static ObjectID decodeObject(TraceValue value);
- /// Extracts a string from a trace value.
- /// \pre The value must be a string.
- const std::string &decodeString(TraceValue value) const;
- static bool equal(TraceValue x, TraceValue y) {
- // We are encoding random numbers into strings, and can't use the library
- // functions.
- // For now, ignore differences that result from NaN, +0/-0.
- return x.getRaw() == y.getRaw();
- }
- /// The version of the Synth Benchmark
- constexpr static uint32_t synthVersion() {
- return 2;
- }
- static const char *nameFromReleaseUnused(::hermes::vm::ReleaseUnused ru);
- static ::hermes::vm::ReleaseUnused releaseUnusedFromName(const char *name);
- private:
- llvm::raw_ostream &os() const {
- return (*traceStream_);
- }
- /// If we're tracing to a file, and the number of accumulated
- /// records has reached the limit kTraceRecordsToFlush, below,
- /// flush the records to the file, and reset the accumulated records
- /// to be empty.
- void flushRecordsIfNecessary();
- /// Assumes we're tracing to a file; flush accumulated records to
- /// the file, and reset the accumulated records to be empty.
- void flushRecords();
- static constexpr unsigned kTraceRecordsToFlush = 100;
- /// If we're tracing to a file, pointer to a stream onto
- /// traceFilename_. Null otherwise.
- std::unique_ptr<llvm::raw_ostream> traceStream_;
- /// If we're tracing to a file, pointer to a JSONEmitter writting
- /// into *traceStream_. Null otherwise.
- std::unique_ptr<::hermes::JSONEmitter> json_;
- /// The records currently being accumulated in the trace. If we are
- /// tracing to a file, these will be only the records not yet
- /// written to the file.
- std::vector<std::unique_ptr<Record>> records_;
- /// The id of the global object.
- const ObjectID globalObjID_;
- /// A table of strings to avoid repeated strings taking up memory. Similar to
- /// the IdentifierTable, except it doesn't need to be collected (it stores
- /// strings forever).
- /// Strings are stored in the trace objects as an index into this table.
- ::hermes::StringSetVector stringTable_;
- public:
- /// @name Record classes
- /// @{
- /// A MarkerRecord is an event that simply records an interesting event that
- /// is not necessarily meaningful to the interpreter. It comes with a tag that
- /// says what type of marker it was.
- struct MarkerRecord : public Record {
- static constexpr RecordType type{RecordType::Marker};
- const std::string tag_;
- explicit MarkerRecord(TimeSinceStart time, const std::string &tag)
- : Record(time), tag_(tag) {}
- RecordType getType() const override {
- return type;
- }
- protected:
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- bool operator==(const Record &that) const override;
- };
- /// A BeginExecJSRecord is an event where execution begins of JS source
- /// code. This is not necessarily the first record, since native code can
- /// inject values into the VM before any source code is run.
- struct BeginExecJSRecord final : public Record {
- static constexpr RecordType type{RecordType::BeginExecJS};
- explicit BeginExecJSRecord(
- TimeSinceStart time,
- std::string sourceURL,
- ::hermes::SHA1 sourceHash)
- : Record(time),
- sourceURL_(std::move(sourceURL)),
- sourceHash_(std::move(sourceHash)) {}
- RecordType getType() const override {
- return type;
- }
- const std::string &sourceURL() const {
- return sourceURL_;
- }
- const ::hermes::SHA1 &sourceHash() const {
- return sourceHash_;
- }
- private:
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- /// The URL providing the source file mapping for the file being executed.
- /// Can be empty.
- std::string sourceURL_;
- /// A hash of the source that was executed. The source hash must match up
- /// when the file is replayed.
- /// The hash is optional, and will be all zeros if not provided.
- ::hermes::SHA1 sourceHash_;
- };
- struct ReturnMixin {
- const TraceValue retVal_;
- explicit ReturnMixin(TraceValue value) : retVal_(value) {}
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const;
- bool operator==(const ReturnMixin &that) const;
- };
- /// A EndExecJSRecord is an event where execution of JS source code stops.
- /// This does not mean that the source code will never be entered again, just
- /// that it has an entered a phase where it is waiting for native code to call
- /// into the JS. This event is not guaranteed to be the last event, for the
- /// aforementioned reason. The logged retVal is the result of the evaluation
- /// ("undefined" in the majority of cases).
- struct EndExecJSRecord final : public MarkerRecord, public ReturnMixin {
- static constexpr RecordType type{RecordType::EndExecJS};
- EndExecJSRecord(TimeSinceStart time, TraceValue retVal)
- : MarkerRecord(time, "end_global_code"), ReturnMixin(retVal) {}
- RecordType getType() const override {
- return type;
- }
- bool operator==(const Record &that) const final;
- virtual void toJSONInternal(
- ::hermes::JSONEmitter &json,
- const SynthTrace &trace) const final;
- std::vector<ObjectID> defs() const override {
- auto defs = MarkerRecord::defs();
- if (retVal_.isObject()) {
- defs.push_back(decodeObject(retVal_));
- }
- return defs;
- }
- };
- /// A CreateObjectRecord is an event where an empty object is created by the
- /// native code.
- struct CreateObjectRecord : public Record {
- static constexpr RecordType type{RecordType::CreateObject};
- const ObjectID objID_;
- explicit CreateObjectRecord(TimeSinceStart time, ObjectID objID)
- : Record(time), objID_(objID) {}
- bool operator==(const Record &that) const override;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> defs() const override {
- return {objID_};
- }
- std::vector<ObjectID> uses() const override {
- return {};
- }
- };
- struct CreateHostObjectRecord final : public CreateObjectRecord {
- static constexpr RecordType type{RecordType::CreateHostObject};
- using CreateObjectRecord::CreateObjectRecord;
- RecordType getType() const override {
- return type;
- }
- };
- struct CreateHostFunctionRecord final : public CreateObjectRecord {
- static constexpr RecordType type{RecordType::CreateHostFunction};
- const std::string functionName_;
- const unsigned paramCount_;
- CreateHostFunctionRecord(
- TimeSinceStart time,
- ObjectID objID,
- std::string functionName,
- unsigned paramCount)
- : CreateObjectRecord(time, objID),
- functionName_(std::move(functionName)),
- paramCount_(paramCount) {}
- bool operator==(const Record &that) const override;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- RecordType getType() const override {
- return type;
- }
- };
- struct GetOrSetPropertyRecord : public Record {
- const ObjectID objID_;
- const std::string propName_;
- const TraceValue value_;
- explicit GetOrSetPropertyRecord(
- TimeSinceStart time,
- ObjectID objID,
- const std::string &propName,
- TraceValue value)
- : Record(time), objID_(objID), propName_(propName), value_(value) {}
- bool operator==(const Record &that) const final;
- std::vector<ObjectID> uses() const override {
- return {objID_};
- }
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- };
- /// A GetPropertyRecord is an event where native code accesses the property
- /// of a JS object.
- struct GetPropertyRecord : public GetOrSetPropertyRecord {
- static constexpr RecordType type{RecordType::GetProperty};
- using GetOrSetPropertyRecord::GetOrSetPropertyRecord;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> defs() const override {
- auto defs = GetOrSetPropertyRecord::defs();
- if (value_.isObject()) {
- defs.push_back(decodeObject(value_));
- }
- return defs;
- }
- };
- /// A SetPropertyRecord is an event where native code writes to the property
- /// of a JS object.
- struct SetPropertyRecord : public GetOrSetPropertyRecord {
- static constexpr RecordType type{RecordType::SetProperty};
- using GetOrSetPropertyRecord::GetOrSetPropertyRecord;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> uses() const override {
- auto uses = GetOrSetPropertyRecord::uses();
- if (value_.isObject()) {
- uses.push_back(decodeObject(value_));
- }
- return uses;
- }
- };
- /// A HasPropertyRecord is an event where native code queries whether a
- /// property exists on an object. (We don't care about the result because
- /// it cannot influence the trace.)
- struct HasPropertyRecord final : public Record {
- static constexpr RecordType type{RecordType::HasProperty};
- const ObjectID objID_;
- const std::string propName_;
- explicit HasPropertyRecord(
- TimeSinceStart time,
- ObjectID objID,
- const std::string &propName)
- : Record(time), objID_(objID), propName_(propName) {}
- bool operator==(const Record &that) const final;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> uses() const override {
- return {objID_};
- }
- };
- struct GetPropertyNamesRecord final : public Record {
- static constexpr RecordType type{RecordType::GetPropertyNames};
- const ObjectID objID_;
- // Since getPropertyNames always returns an array, this can be an object id
- // rather than a TraceValue.
- const ObjectID propNamesID_;
- explicit GetPropertyNamesRecord(
- TimeSinceStart time,
- ObjectID objID,
- ObjectID propNamesID)
- : Record(time), objID_(objID), propNamesID_(propNamesID) {}
- bool operator==(const Record &that) const final;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> defs() const override {
- return {propNamesID_};
- }
- std::vector<ObjectID> uses() const override {
- return {objID_};
- }
- };
- /// A CreateArrayRecord is an event where a new array is created of a specific
- /// length.
- struct CreateArrayRecord final : public Record {
- static constexpr RecordType type{RecordType::CreateArray};
- const ObjectID objID_;
- const size_t length_;
- explicit CreateArrayRecord(
- TimeSinceStart time,
- ObjectID objID,
- size_t length)
- : Record(time), objID_(objID), length_(length) {}
- bool operator==(const Record &that) const final;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> defs() const override {
- return {objID_};
- }
- };
- struct ArrayReadOrWriteRecord : public Record {
- const ObjectID objID_;
- const size_t index_;
- const TraceValue value_;
- explicit ArrayReadOrWriteRecord(
- TimeSinceStart time,
- ObjectID objID,
- size_t index,
- TraceValue value)
- : Record(time), objID_(objID), index_(index), value_(value) {}
- bool operator==(const Record &that) const final;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- std::vector<ObjectID> uses() const override {
- return {objID_};
- }
- };
- /// An ArrayReadRecord is an event where a value was read from an index
- /// of an array.
- /// It is modeled separately from GetProperty because it is more efficient to
- /// read from a numeric index on an array than a string.
- struct ArrayReadRecord final : public ArrayReadOrWriteRecord {
- static constexpr RecordType type{RecordType::ArrayRead};
- using ArrayReadOrWriteRecord::ArrayReadOrWriteRecord;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> defs() const override {
- auto defs = ArrayReadOrWriteRecord::defs();
- if (value_.isObject()) {
- defs.push_back(decodeObject(value_));
- }
- return defs;
- }
- };
- /// An ArrayWriteRecord is an event where a value was written into an index
- /// of an array.
- struct ArrayWriteRecord final : public ArrayReadOrWriteRecord {
- static constexpr RecordType type{RecordType::ArrayWrite};
- using ArrayReadOrWriteRecord::ArrayReadOrWriteRecord;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> uses() const override {
- auto uses = ArrayReadOrWriteRecord::uses();
- if (value_.isObject()) {
- uses.push_back(decodeObject(value_));
- }
- return uses;
- }
- };
- struct CallRecord : public Record {
- /// The functionID_ is the id of the function JS object that is called from
- /// JS.
- const ObjectID functionID_;
- const TraceValue thisArg_;
- /// The arguments given to a call (excluding the this parameter),
- /// already JSON stringified.
- const std::vector<TraceValue> args_;
- explicit CallRecord(
- TimeSinceStart time,
- ObjectID functionID,
- TraceValue thisArg,
- const std::vector<TraceValue> &args)
- : Record(time),
- functionID_(functionID),
- thisArg_(thisArg),
- args_(args) {}
- bool operator==(const Record &that) const final;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- std::vector<ObjectID> uses() const override {
- // The function is used regardless of direction.
- return {functionID_};
- }
- protected:
- std::vector<ObjectID> getArgObjects() const {
- std::vector<ObjectID> objs;
- if (thisArg_.isObject()) {
- objs.push_back(decodeObject(thisArg_));
- }
- for (const auto &arg : args_) {
- if (arg.isObject()) {
- objs.push_back(decodeObject(arg));
- }
- }
- return objs;
- }
- };
- /// A CallFromNativeRecord is an event where native code calls into a JS
- /// function.
- struct CallFromNativeRecord : public CallRecord {
- static constexpr RecordType type{RecordType::CallFromNative};
- using CallRecord::CallRecord;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> uses() const override {
- auto uses = CallRecord::uses();
- auto objs = CallRecord::getArgObjects();
- uses.insert(uses.end(), objs.begin(), objs.end());
- return uses;
- }
- };
- /// A ConstructFromNativeRecord is the same as \c CallFromNativeRecord, except
- /// the function is called with the new operator.
- struct ConstructFromNativeRecord final : public CallFromNativeRecord {
- static constexpr RecordType type{RecordType::ConstructFromNative};
- using CallFromNativeRecord::CallFromNativeRecord;
- RecordType getType() const override {
- return type;
- }
- };
- /// A ReturnFromNativeRecord is an event where a native function returns to a
- /// JS caller.
- /// It pairs with \c CallToNativeRecord.
- struct ReturnFromNativeRecord final : public Record, public ReturnMixin {
- static constexpr RecordType type{RecordType::ReturnFromNative};
- ReturnFromNativeRecord(TimeSinceStart time, TraceValue retVal)
- : Record(time), ReturnMixin(retVal) {}
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> uses() const override {
- auto uses = Record::uses();
- if (retVal_.isObject()) {
- uses.push_back(decodeObject(retVal_));
- }
- return uses;
- }
- bool operator==(const Record &that) const final;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- };
- /// A ReturnToNativeRecord is an event where a JS function returns to a native
- /// caller.
- /// It pairs with \c CallFromNativeRecord.
- struct ReturnToNativeRecord final : public Record, public ReturnMixin {
- static constexpr RecordType type{RecordType::ReturnToNative};
- ReturnToNativeRecord(TimeSinceStart time, TraceValue retVal)
- : Record(time), ReturnMixin(retVal) {}
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> defs() const override {
- auto defs = Record::defs();
- if (retVal_.isObject()) {
- defs.push_back(decodeObject(retVal_));
- }
- return defs;
- }
- bool operator==(const Record &that) const final;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- };
- /// A CallToNativeRecord is an event where JS code calls into a natively
- /// defined function.
- struct CallToNativeRecord final : public CallRecord {
- static constexpr RecordType type{RecordType::CallToNative};
- using CallRecord::CallRecord;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> defs() const override {
- auto defs = CallRecord::defs();
- auto objs = CallRecord::getArgObjects();
- defs.insert(defs.end(), objs.begin(), objs.end());
- return defs;
- }
- };
- struct GetOrSetPropertyNativeRecord : public Record {
- const ObjectID hostObjectID_;
- const std::string propName_;
- explicit GetOrSetPropertyNativeRecord(
- TimeSinceStart time,
- ObjectID hostObjectID,
- std::string propName)
- : Record(time), hostObjectID_(hostObjectID), propName_(propName) {}
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- std::vector<ObjectID> uses() const override {
- return {hostObjectID_};
- }
- protected:
- bool operator==(const Record &that) const override;
- };
- /// A GetPropertyNativeRecord is an event where JS tries to access a property
- /// on a native object.
- /// This needs to be modeled as a call with no arguments, since native code
- /// can arbitrarily affect the JS heap during the accessor.
- struct GetPropertyNativeRecord final : public GetOrSetPropertyNativeRecord {
- static constexpr RecordType type{RecordType::GetPropertyNative};
- using GetOrSetPropertyNativeRecord::GetOrSetPropertyNativeRecord;
- RecordType getType() const override {
- return type;
- }
- bool operator==(const Record &that) const final;
- };
- struct GetPropertyNativeReturnRecord final : public Record,
- public ReturnMixin {
- static constexpr RecordType type{RecordType::GetPropertyNativeReturn};
- GetPropertyNativeReturnRecord(TimeSinceStart time, TraceValue retVal)
- : Record(time), ReturnMixin(retVal) {}
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> uses() const override {
- auto uses = Record::uses();
- if (retVal_.isObject()) {
- uses.push_back(decodeObject(retVal_));
- }
- return uses;
- }
- bool operator==(const Record &that) const final;
- protected:
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- };
- /// A SetPropertyNativeRecord is an event where JS code writes to the property
- /// of a Native object.
- /// This needs to be modeled as a call with one argument, since native code
- /// can arbitrarily affect the JS heap during the accessor.
- struct SetPropertyNativeRecord final : public GetOrSetPropertyNativeRecord {
- static constexpr RecordType type{RecordType::SetPropertyNative};
- TraceValue value_;
- explicit SetPropertyNativeRecord(
- TimeSinceStart time,
- ObjectID hostObjectID,
- std::string propName,
- TraceValue value)
- : GetOrSetPropertyNativeRecord(time, hostObjectID, propName),
- value_(value) {}
- bool operator==(const Record &that) const final;
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- RecordType getType() const override {
- return type;
- }
- std::vector<ObjectID> defs() const override {
- auto defs = GetOrSetPropertyNativeRecord::defs();
- if (value_.isObject()) {
- defs.push_back(decodeObject(value_));
- }
- return defs;
- }
- };
- /// A SetPropertyNativeReturnRecord needs to record no extra information
- struct SetPropertyNativeReturnRecord final : public Record {
- static constexpr RecordType type{RecordType::SetPropertyNativeReturn};
- using Record::Record;
- RecordType getType() const override {
- return type;
- }
- bool operator==(const Record &that) const final {
- // Since there are no fields to compare, any two will always be the same.
- return Record::operator==(that);
- }
- };
- /// A GetNativePropertyNamesRecord records an event where JS asked for a list
- /// of property names available on a host object. It records the object, and
- /// the returned list of property names.
- struct GetNativePropertyNamesRecord : public Record {
- static constexpr RecordType type{RecordType::GetNativePropertyNames};
- const ObjectID hostObjectID_;
- explicit GetNativePropertyNamesRecord(
- TimeSinceStart time,
- ObjectID hostObjectID)
- : Record(time), hostObjectID_(hostObjectID) {}
- RecordType getType() const override {
- return type;
- }
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- std::vector<ObjectID> uses() const override {
- return {hostObjectID_};
- }
- bool operator==(const Record &that) const override;
- };
- /// A GetNativePropertyNamesReturnRecord records what property names were
- /// returned by the GetNativePropertyNames query.
- struct GetNativePropertyNamesReturnRecord final : public Record {
- static constexpr RecordType type{RecordType::GetNativePropertyNamesReturn};
- const std::vector<std::string> propNames_;
- explicit GetNativePropertyNamesReturnRecord(
- TimeSinceStart time,
- const std::vector<std::string> &propNames)
- : Record(time), propNames_(propNames) {}
- RecordType getType() const override {
- return type;
- }
- void toJSONInternal(::hermes::JSONEmitter &json, const SynthTrace &trace)
- const override;
- bool operator==(const Record &that) const override;
- };
- /// Completes writing of the trace to the trace stream. If writing
- /// to a file, disables further writing to the file, or accumulation
- /// of data.
- void flushAndDisable(const ::hermes::vm::MockedEnvironment &env);
- };
- llvm::raw_ostream &operator<<(
- llvm::raw_ostream &os,
- SynthTrace::RecordType type);
- std::istream &operator>>(std::istream &is, SynthTrace::RecordType &type);
- } // namespace tracing
- } // namespace hermes
- } // namespace facebook
- #endif // HERMESVM_API_TRACE
- #endif // HERMES_SYNTHTRACE_H
|