11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciimport {LogReader, parseString, parseVarArgs} from '../logreader.mjs';
61cb0ef41Sopenharmony_ciimport {Profile} from '../profile.mjs';
71cb0ef41Sopenharmony_ciimport {RemoteLinuxCppEntriesProvider, RemoteMacOSCppEntriesProvider} from '../tickprocessor.mjs'
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciimport {CodeLogEntry, DeoptLogEntry, FeedbackVectorEntry, SharedLibLogEntry} from './log/code.mjs';
101cb0ef41Sopenharmony_ciimport {IcLogEntry} from './log/ic.mjs';
111cb0ef41Sopenharmony_ciimport {Edge, MapLogEntry} from './log/map.mjs';
121cb0ef41Sopenharmony_ciimport {TickLogEntry} from './log/tick.mjs';
131cb0ef41Sopenharmony_ciimport {TimerLogEntry} from './log/timer.mjs';
141cb0ef41Sopenharmony_ciimport {Timeline} from './timeline.mjs';
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci// ===========================================================================
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciclass AsyncConsumer {
191cb0ef41Sopenharmony_ci  constructor(consumer_fn) {
201cb0ef41Sopenharmony_ci    this._chunks = [];
211cb0ef41Sopenharmony_ci    this._consumer = consumer_fn;
221cb0ef41Sopenharmony_ci    this._pendingWork = Promise.resolve();
231cb0ef41Sopenharmony_ci    this._isConsuming = false;
241cb0ef41Sopenharmony_ci  }
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  get pendingWork() {
271cb0ef41Sopenharmony_ci    return this._pendingWork;
281cb0ef41Sopenharmony_ci  }
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci  push(chunk) {
311cb0ef41Sopenharmony_ci    this._chunks.push(chunk);
321cb0ef41Sopenharmony_ci    this.consumeAll();
331cb0ef41Sopenharmony_ci  }
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  async consumeAll() {
361cb0ef41Sopenharmony_ci    if (!this._isConsuming) this._pendingWork = this._consumeAll();
371cb0ef41Sopenharmony_ci    return await this._pendingWork;
381cb0ef41Sopenharmony_ci  }
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  async _consumeAll() {
411cb0ef41Sopenharmony_ci    this._isConsuming = true;
421cb0ef41Sopenharmony_ci    while (this._chunks.length > 0) {
431cb0ef41Sopenharmony_ci      await this._consumer(this._chunks.shift());
441cb0ef41Sopenharmony_ci    }
451cb0ef41Sopenharmony_ci    this._isConsuming = false;
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci}
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ciexport class Processor extends LogReader {
501cb0ef41Sopenharmony_ci  _profile = new Profile();
511cb0ef41Sopenharmony_ci  _codeTimeline = new Timeline();
521cb0ef41Sopenharmony_ci  _deoptTimeline = new Timeline();
531cb0ef41Sopenharmony_ci  _icTimeline = new Timeline();
541cb0ef41Sopenharmony_ci  _mapTimeline = new Timeline();
551cb0ef41Sopenharmony_ci  _tickTimeline = new Timeline();
561cb0ef41Sopenharmony_ci  _timerTimeline = new Timeline();
571cb0ef41Sopenharmony_ci  _formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
581cb0ef41Sopenharmony_ci  _lastTimestamp = 0;
591cb0ef41Sopenharmony_ci  _lastCodeLogEntry;
601cb0ef41Sopenharmony_ci  _lastTickLogEntry;
611cb0ef41Sopenharmony_ci  _chunkRemainder = '';
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  _totalInputBytes = 0;
641cb0ef41Sopenharmony_ci  _processedInputChars = 0;
651cb0ef41Sopenharmony_ci  _progressCallback;
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  MAJOR_VERSION = 7;
681cb0ef41Sopenharmony_ci  MINOR_VERSION = 6;
691cb0ef41Sopenharmony_ci  constructor() {
701cb0ef41Sopenharmony_ci    super();
711cb0ef41Sopenharmony_ci    this._chunkConsumer =
721cb0ef41Sopenharmony_ci        new AsyncConsumer((chunk) => this._processChunk(chunk));
731cb0ef41Sopenharmony_ci    const propertyICParser = [
741cb0ef41Sopenharmony_ci      parseInt, parseInt, parseInt, parseInt, parseString, parseString,
751cb0ef41Sopenharmony_ci      parseString, parseString, parseString, parseString
761cb0ef41Sopenharmony_ci    ];
771cb0ef41Sopenharmony_ci    this.setDispatchTable({
781cb0ef41Sopenharmony_ci      __proto__: null,
791cb0ef41Sopenharmony_ci      'v8-version': {
801cb0ef41Sopenharmony_ci        parsers: [
811cb0ef41Sopenharmony_ci          parseInt,
821cb0ef41Sopenharmony_ci          parseInt,
831cb0ef41Sopenharmony_ci        ],
841cb0ef41Sopenharmony_ci        processor: this.processV8Version,
851cb0ef41Sopenharmony_ci      },
861cb0ef41Sopenharmony_ci      'shared-library': {
871cb0ef41Sopenharmony_ci        parsers: [parseString, parseInt, parseInt, parseInt],
881cb0ef41Sopenharmony_ci        processor: this.processSharedLibrary.bind(this),
891cb0ef41Sopenharmony_ci        isAsync: true,
901cb0ef41Sopenharmony_ci      },
911cb0ef41Sopenharmony_ci      'code-creation': {
921cb0ef41Sopenharmony_ci        parsers: [
931cb0ef41Sopenharmony_ci          parseString, parseInt, parseInt, parseInt, parseInt, parseString,
941cb0ef41Sopenharmony_ci          parseVarArgs
951cb0ef41Sopenharmony_ci        ],
961cb0ef41Sopenharmony_ci        processor: this.processCodeCreation
971cb0ef41Sopenharmony_ci      },
981cb0ef41Sopenharmony_ci      'code-deopt': {
991cb0ef41Sopenharmony_ci        parsers: [
1001cb0ef41Sopenharmony_ci          parseInt, parseInt, parseInt, parseInt, parseInt, parseString,
1011cb0ef41Sopenharmony_ci          parseString, parseString
1021cb0ef41Sopenharmony_ci        ],
1031cb0ef41Sopenharmony_ci        processor: this.processCodeDeopt
1041cb0ef41Sopenharmony_ci      },
1051cb0ef41Sopenharmony_ci      'code-move':
1061cb0ef41Sopenharmony_ci          {parsers: [parseInt, parseInt], processor: this.processCodeMove},
1071cb0ef41Sopenharmony_ci      'code-delete': {parsers: [parseInt], processor: this.processCodeDelete},
1081cb0ef41Sopenharmony_ci      'code-source-info': {
1091cb0ef41Sopenharmony_ci        parsers: [
1101cb0ef41Sopenharmony_ci          parseInt, parseInt, parseInt, parseInt, parseString, parseString,
1111cb0ef41Sopenharmony_ci          parseString
1121cb0ef41Sopenharmony_ci        ],
1131cb0ef41Sopenharmony_ci        processor: this.processCodeSourceInfo
1141cb0ef41Sopenharmony_ci      },
1151cb0ef41Sopenharmony_ci      'code-disassemble': {
1161cb0ef41Sopenharmony_ci        parsers: [
1171cb0ef41Sopenharmony_ci          parseInt,
1181cb0ef41Sopenharmony_ci          parseString,
1191cb0ef41Sopenharmony_ci          parseString,
1201cb0ef41Sopenharmony_ci        ],
1211cb0ef41Sopenharmony_ci        processor: this.processCodeDisassemble
1221cb0ef41Sopenharmony_ci      },
1231cb0ef41Sopenharmony_ci      'feedback-vector': {
1241cb0ef41Sopenharmony_ci        parsers: [
1251cb0ef41Sopenharmony_ci          parseInt, parseString, parseInt, parseInt, parseString, parseString,
1261cb0ef41Sopenharmony_ci          parseInt, parseInt, parseString
1271cb0ef41Sopenharmony_ci        ],
1281cb0ef41Sopenharmony_ci        processor: this.processFeedbackVector
1291cb0ef41Sopenharmony_ci      },
1301cb0ef41Sopenharmony_ci      'script-source': {
1311cb0ef41Sopenharmony_ci        parsers: [parseInt, parseString, parseString],
1321cb0ef41Sopenharmony_ci        processor: this.processScriptSource
1331cb0ef41Sopenharmony_ci      },
1341cb0ef41Sopenharmony_ci      'sfi-move':
1351cb0ef41Sopenharmony_ci          {parsers: [parseInt, parseInt], processor: this.processFunctionMove},
1361cb0ef41Sopenharmony_ci      'tick': {
1371cb0ef41Sopenharmony_ci        parsers:
1381cb0ef41Sopenharmony_ci            [parseInt, parseInt, parseInt, parseInt, parseInt, parseVarArgs],
1391cb0ef41Sopenharmony_ci        processor: this.processTick
1401cb0ef41Sopenharmony_ci      },
1411cb0ef41Sopenharmony_ci      'active-runtime-timer': undefined,
1421cb0ef41Sopenharmony_ci      'heap-sample-begin': undefined,
1431cb0ef41Sopenharmony_ci      'heap-sample-end': undefined,
1441cb0ef41Sopenharmony_ci      'timer-event-start': {
1451cb0ef41Sopenharmony_ci        parsers: [parseString, parseInt],
1461cb0ef41Sopenharmony_ci        processor: this.processTimerEventStart
1471cb0ef41Sopenharmony_ci      },
1481cb0ef41Sopenharmony_ci      'timer-event-end': {
1491cb0ef41Sopenharmony_ci        parsers: [parseString, parseInt],
1501cb0ef41Sopenharmony_ci        processor: this.processTimerEventEnd
1511cb0ef41Sopenharmony_ci      },
1521cb0ef41Sopenharmony_ci      'map-create':
1531cb0ef41Sopenharmony_ci          {parsers: [parseInt, parseString], processor: this.processMapCreate},
1541cb0ef41Sopenharmony_ci      'map': {
1551cb0ef41Sopenharmony_ci        parsers: [
1561cb0ef41Sopenharmony_ci          parseString, parseInt, parseString, parseString, parseInt, parseInt,
1571cb0ef41Sopenharmony_ci          parseInt, parseString, parseString
1581cb0ef41Sopenharmony_ci        ],
1591cb0ef41Sopenharmony_ci        processor: this.processMap
1601cb0ef41Sopenharmony_ci      },
1611cb0ef41Sopenharmony_ci      'map-details': {
1621cb0ef41Sopenharmony_ci        parsers: [parseInt, parseString, parseString],
1631cb0ef41Sopenharmony_ci        processor: this.processMapDetails
1641cb0ef41Sopenharmony_ci      },
1651cb0ef41Sopenharmony_ci      'LoadGlobalIC': {
1661cb0ef41Sopenharmony_ci        parsers: propertyICParser,
1671cb0ef41Sopenharmony_ci        processor: this.processPropertyIC.bind(this, 'LoadGlobalIC')
1681cb0ef41Sopenharmony_ci      },
1691cb0ef41Sopenharmony_ci      'StoreGlobalIC': {
1701cb0ef41Sopenharmony_ci        parsers: propertyICParser,
1711cb0ef41Sopenharmony_ci        processor: this.processPropertyIC.bind(this, 'StoreGlobalIC')
1721cb0ef41Sopenharmony_ci      },
1731cb0ef41Sopenharmony_ci      'LoadIC': {
1741cb0ef41Sopenharmony_ci        parsers: propertyICParser,
1751cb0ef41Sopenharmony_ci        processor: this.processPropertyIC.bind(this, 'LoadIC')
1761cb0ef41Sopenharmony_ci      },
1771cb0ef41Sopenharmony_ci      'StoreIC': {
1781cb0ef41Sopenharmony_ci        parsers: propertyICParser,
1791cb0ef41Sopenharmony_ci        processor: this.processPropertyIC.bind(this, 'StoreIC')
1801cb0ef41Sopenharmony_ci      },
1811cb0ef41Sopenharmony_ci      'KeyedLoadIC': {
1821cb0ef41Sopenharmony_ci        parsers: propertyICParser,
1831cb0ef41Sopenharmony_ci        processor: this.processPropertyIC.bind(this, 'KeyedLoadIC')
1841cb0ef41Sopenharmony_ci      },
1851cb0ef41Sopenharmony_ci      'KeyedStoreIC': {
1861cb0ef41Sopenharmony_ci        parsers: propertyICParser,
1871cb0ef41Sopenharmony_ci        processor: this.processPropertyIC.bind(this, 'KeyedStoreIC')
1881cb0ef41Sopenharmony_ci      },
1891cb0ef41Sopenharmony_ci      'StoreInArrayLiteralIC': {
1901cb0ef41Sopenharmony_ci        parsers: propertyICParser,
1911cb0ef41Sopenharmony_ci        processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC')
1921cb0ef41Sopenharmony_ci      },
1931cb0ef41Sopenharmony_ci      'api': {
1941cb0ef41Sopenharmony_ci        parsers: [parseString, parseVarArgs],
1951cb0ef41Sopenharmony_ci        processor: this.processApiEvent
1961cb0ef41Sopenharmony_ci      },
1971cb0ef41Sopenharmony_ci    });
1981cb0ef41Sopenharmony_ci    // TODO(cbruni): Choose correct cpp entries provider
1991cb0ef41Sopenharmony_ci    this._cppEntriesProvider = new RemoteLinuxCppEntriesProvider();
2001cb0ef41Sopenharmony_ci  }
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  printError(str) {
2031cb0ef41Sopenharmony_ci    console.error(str);
2041cb0ef41Sopenharmony_ci    throw str
2051cb0ef41Sopenharmony_ci  }
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci  processChunk(chunk) {
2081cb0ef41Sopenharmony_ci    this._chunkConsumer.push(chunk)
2091cb0ef41Sopenharmony_ci  }
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  setProgressCallback(totalSize, callback) {
2121cb0ef41Sopenharmony_ci    this._totalInputBytes = totalSize;
2131cb0ef41Sopenharmony_ci    this._progressCallback = callback;
2141cb0ef41Sopenharmony_ci  }
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  async _updateProgress() {
2171cb0ef41Sopenharmony_ci    if (!this._progressCallback) return;
2181cb0ef41Sopenharmony_ci    // We use chars and bytes interchangeably for simplicity. This causes us to
2191cb0ef41Sopenharmony_ci    // slightly underestimate progress.
2201cb0ef41Sopenharmony_ci    this._progressCallback(
2211cb0ef41Sopenharmony_ci        this._processedInputChars / this._totalInputBytes,
2221cb0ef41Sopenharmony_ci        this._processedInputChars);
2231cb0ef41Sopenharmony_ci  }
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci  async _processChunk(chunk) {
2261cb0ef41Sopenharmony_ci    const prevProcessedInputChars = this._processedInputChars;
2271cb0ef41Sopenharmony_ci    let end = chunk.length;
2281cb0ef41Sopenharmony_ci    let current = 0;
2291cb0ef41Sopenharmony_ci    let next = 0;
2301cb0ef41Sopenharmony_ci    let line;
2311cb0ef41Sopenharmony_ci    let lineNumber = 1;
2321cb0ef41Sopenharmony_ci    try {
2331cb0ef41Sopenharmony_ci      while (current < end) {
2341cb0ef41Sopenharmony_ci        next = chunk.indexOf('\n', current);
2351cb0ef41Sopenharmony_ci        if (next === -1) {
2361cb0ef41Sopenharmony_ci          this._chunkRemainder = chunk.substring(current);
2371cb0ef41Sopenharmony_ci          break;
2381cb0ef41Sopenharmony_ci        }
2391cb0ef41Sopenharmony_ci        line = chunk.substring(current, next);
2401cb0ef41Sopenharmony_ci        if (this._chunkRemainder) {
2411cb0ef41Sopenharmony_ci          line = this._chunkRemainder + line;
2421cb0ef41Sopenharmony_ci          this._chunkRemainder = '';
2431cb0ef41Sopenharmony_ci        }
2441cb0ef41Sopenharmony_ci        current = next + 1;
2451cb0ef41Sopenharmony_ci        lineNumber++;
2461cb0ef41Sopenharmony_ci        await this.processLogLine(line);
2471cb0ef41Sopenharmony_ci        this._processedInputChars = prevProcessedInputChars + current;
2481cb0ef41Sopenharmony_ci      }
2491cb0ef41Sopenharmony_ci      this._updateProgress();
2501cb0ef41Sopenharmony_ci    } catch (e) {
2511cb0ef41Sopenharmony_ci      console.error(
2521cb0ef41Sopenharmony_ci          `Could not parse log line ${lineNumber}, trying to continue: ${e}`);
2531cb0ef41Sopenharmony_ci    }
2541cb0ef41Sopenharmony_ci  }
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci  async processLogFile(fileName) {
2571cb0ef41Sopenharmony_ci    this.collectEntries = true;
2581cb0ef41Sopenharmony_ci    this.lastLogFileName_ = fileName;
2591cb0ef41Sopenharmony_ci    let i = 1;
2601cb0ef41Sopenharmony_ci    let line;
2611cb0ef41Sopenharmony_ci    try {
2621cb0ef41Sopenharmony_ci      while (line = readline()) {
2631cb0ef41Sopenharmony_ci        await this.processLogLine(line);
2641cb0ef41Sopenharmony_ci        i++;
2651cb0ef41Sopenharmony_ci      }
2661cb0ef41Sopenharmony_ci    } catch (e) {
2671cb0ef41Sopenharmony_ci      console.error(
2681cb0ef41Sopenharmony_ci          `Error occurred during parsing line ${i}` +
2691cb0ef41Sopenharmony_ci          ', trying to continue: ' + e);
2701cb0ef41Sopenharmony_ci    }
2711cb0ef41Sopenharmony_ci    this.finalize();
2721cb0ef41Sopenharmony_ci  }
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_ci  async finalize() {
2751cb0ef41Sopenharmony_ci    await this._chunkConsumer.consumeAll();
2761cb0ef41Sopenharmony_ci    if (this._profile.warnings.size > 0) {
2771cb0ef41Sopenharmony_ci      console.warn('Found profiler warnings:', this._profile.warnings);
2781cb0ef41Sopenharmony_ci    }
2791cb0ef41Sopenharmony_ci    // TODO(cbruni): print stats;
2801cb0ef41Sopenharmony_ci    this._mapTimeline.transitions = new Map();
2811cb0ef41Sopenharmony_ci    let id = 0;
2821cb0ef41Sopenharmony_ci    this._mapTimeline.forEach(map => {
2831cb0ef41Sopenharmony_ci      if (map.isRoot()) id = map.finalizeRootMap(id + 1);
2841cb0ef41Sopenharmony_ci      if (map.edge && map.edge.name) {
2851cb0ef41Sopenharmony_ci        const edge = map.edge;
2861cb0ef41Sopenharmony_ci        const list = this._mapTimeline.transitions.get(edge.name);
2871cb0ef41Sopenharmony_ci        if (list === undefined) {
2881cb0ef41Sopenharmony_ci          this._mapTimeline.transitions.set(edge.name, [edge]);
2891cb0ef41Sopenharmony_ci        } else {
2901cb0ef41Sopenharmony_ci          list.push(edge);
2911cb0ef41Sopenharmony_ci        }
2921cb0ef41Sopenharmony_ci      }
2931cb0ef41Sopenharmony_ci    });
2941cb0ef41Sopenharmony_ci  }
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_ci  processV8Version(majorVersion, minorVersion) {
2971cb0ef41Sopenharmony_ci    if ((majorVersion == this.MAJOR_VERSION &&
2981cb0ef41Sopenharmony_ci         minorVersion <= this.MINOR_VERSION) ||
2991cb0ef41Sopenharmony_ci        (majorVersion < this.MAJOR_VERSION)) {
3001cb0ef41Sopenharmony_ci      window.alert(
3011cb0ef41Sopenharmony_ci          `Unsupported version ${majorVersion}.${minorVersion}. \n` +
3021cb0ef41Sopenharmony_ci          `Please use the matching tool for given the V8 version.`);
3031cb0ef41Sopenharmony_ci    }
3041cb0ef41Sopenharmony_ci  }
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci  async processSharedLibrary(name, startAddr, endAddr, aslrSlide) {
3071cb0ef41Sopenharmony_ci    const entry = this._profile.addLibrary(name, startAddr, endAddr);
3081cb0ef41Sopenharmony_ci    entry.logEntry = new SharedLibLogEntry(entry);
3091cb0ef41Sopenharmony_ci    // Many events rely on having a script around, creating fake entries for
3101cb0ef41Sopenharmony_ci    // shared libraries.
3111cb0ef41Sopenharmony_ci    this._profile.addScriptSource(-1, name, '');
3121cb0ef41Sopenharmony_ci    await this._cppEntriesProvider.parseVmSymbols(
3131cb0ef41Sopenharmony_ci        name, startAddr, endAddr, aslrSlide, (fName, fStart, fEnd) => {
3141cb0ef41Sopenharmony_ci          this._profile.addStaticCode(fName, fStart, fEnd);
3151cb0ef41Sopenharmony_ci        });
3161cb0ef41Sopenharmony_ci  }
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci  processCodeCreation(type, kind, timestamp, start, size, name, maybe_func) {
3191cb0ef41Sopenharmony_ci    this._lastTimestamp = timestamp;
3201cb0ef41Sopenharmony_ci    let entry;
3211cb0ef41Sopenharmony_ci    let stateName = '';
3221cb0ef41Sopenharmony_ci    if (maybe_func.length) {
3231cb0ef41Sopenharmony_ci      const funcAddr = parseInt(maybe_func[0]);
3241cb0ef41Sopenharmony_ci      stateName = maybe_func[1] ?? '';
3251cb0ef41Sopenharmony_ci      const state = Profile.parseState(maybe_func[1]);
3261cb0ef41Sopenharmony_ci      entry = this._profile.addFuncCode(
3271cb0ef41Sopenharmony_ci          type, name, timestamp, start, size, funcAddr, state);
3281cb0ef41Sopenharmony_ci    } else {
3291cb0ef41Sopenharmony_ci      entry = this._profile.addCode(type, name, timestamp, start, size);
3301cb0ef41Sopenharmony_ci    }
3311cb0ef41Sopenharmony_ci    this._lastCodeLogEntry = new CodeLogEntry(
3321cb0ef41Sopenharmony_ci        type + stateName, timestamp,
3331cb0ef41Sopenharmony_ci        Profile.getKindFromState(Profile.parseState(stateName)), kind, entry);
3341cb0ef41Sopenharmony_ci    this._codeTimeline.push(this._lastCodeLogEntry);
3351cb0ef41Sopenharmony_ci  }
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  processCodeDeopt(
3381cb0ef41Sopenharmony_ci      timestamp, codeSize, instructionStart, inliningId, scriptOffset,
3391cb0ef41Sopenharmony_ci      deoptKind, deoptLocation, deoptReason) {
3401cb0ef41Sopenharmony_ci    this._lastTimestamp = timestamp;
3411cb0ef41Sopenharmony_ci    const profCodeEntry = this._profile.findEntry(instructionStart);
3421cb0ef41Sopenharmony_ci    const logEntry = new DeoptLogEntry(
3431cb0ef41Sopenharmony_ci        deoptKind, timestamp, profCodeEntry, deoptReason, deoptLocation,
3441cb0ef41Sopenharmony_ci        scriptOffset, instructionStart, codeSize, inliningId);
3451cb0ef41Sopenharmony_ci    profCodeEntry.logEntry.add(logEntry);
3461cb0ef41Sopenharmony_ci    this._deoptTimeline.push(logEntry);
3471cb0ef41Sopenharmony_ci    this.addSourcePosition(profCodeEntry, logEntry);
3481cb0ef41Sopenharmony_ci    logEntry.functionSourcePosition = logEntry.sourcePosition;
3491cb0ef41Sopenharmony_ci    // custom parse deopt location
3501cb0ef41Sopenharmony_ci    if (deoptLocation === '<unknown>') return;
3511cb0ef41Sopenharmony_ci    // Handle deopt location for inlined code: <location> inlined at <location>
3521cb0ef41Sopenharmony_ci    const inlinedPos = deoptLocation.indexOf(' inlined at ');
3531cb0ef41Sopenharmony_ci    if (inlinedPos > 0) {
3541cb0ef41Sopenharmony_ci      deoptLocation = deoptLocation.substring(0, inlinedPos)
3551cb0ef41Sopenharmony_ci    }
3561cb0ef41Sopenharmony_ci    const script = this.getProfileEntryScript(profCodeEntry);
3571cb0ef41Sopenharmony_ci    if (!script) return;
3581cb0ef41Sopenharmony_ci    const colSeparator = deoptLocation.lastIndexOf(':');
3591cb0ef41Sopenharmony_ci    const rowSeparator = deoptLocation.lastIndexOf(':', colSeparator - 1);
3601cb0ef41Sopenharmony_ci    const line =
3611cb0ef41Sopenharmony_ci        parseInt(deoptLocation.substring(rowSeparator + 1, colSeparator));
3621cb0ef41Sopenharmony_ci    const column = parseInt(
3631cb0ef41Sopenharmony_ci        deoptLocation.substring(colSeparator + 1, deoptLocation.length - 1));
3641cb0ef41Sopenharmony_ci    logEntry.sourcePosition = script.addSourcePosition(line, column, logEntry);
3651cb0ef41Sopenharmony_ci  }
3661cb0ef41Sopenharmony_ci
3671cb0ef41Sopenharmony_ci  processFeedbackVector(
3681cb0ef41Sopenharmony_ci      timestamp, fbv_address, fbv_length, instructionStart, optimization_marker,
3691cb0ef41Sopenharmony_ci      optimization_tier, invocation_count, profiler_ticks, fbv_string) {
3701cb0ef41Sopenharmony_ci    const profCodeEntry = this._profile.findEntry(instructionStart);
3711cb0ef41Sopenharmony_ci    if (!profCodeEntry) {
3721cb0ef41Sopenharmony_ci      console.warn('Didn\'t find code for FBV', {fbv, instructionStart});
3731cb0ef41Sopenharmony_ci      return;
3741cb0ef41Sopenharmony_ci    }
3751cb0ef41Sopenharmony_ci    const fbv = new FeedbackVectorEntry(
3761cb0ef41Sopenharmony_ci        timestamp, profCodeEntry.logEntry, fbv_address, fbv_length,
3771cb0ef41Sopenharmony_ci        optimization_marker, optimization_tier, invocation_count,
3781cb0ef41Sopenharmony_ci        profiler_ticks, fbv_string);
3791cb0ef41Sopenharmony_ci    profCodeEntry.logEntry.setFeedbackVector(fbv);
3801cb0ef41Sopenharmony_ci  }
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_ci  processScriptSource(scriptId, url, source) {
3831cb0ef41Sopenharmony_ci    this._profile.addScriptSource(scriptId, url, source);
3841cb0ef41Sopenharmony_ci  }
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci  processCodeMove(from, to) {
3871cb0ef41Sopenharmony_ci    this._profile.moveCode(from, to);
3881cb0ef41Sopenharmony_ci  }
3891cb0ef41Sopenharmony_ci
3901cb0ef41Sopenharmony_ci  processCodeDelete(start) {
3911cb0ef41Sopenharmony_ci    this._profile.deleteCode(start);
3921cb0ef41Sopenharmony_ci  }
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci  processFunctionMove(from, to) {
3951cb0ef41Sopenharmony_ci    this._profile.moveFunc(from, to);
3961cb0ef41Sopenharmony_ci  }
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  processTick(
3991cb0ef41Sopenharmony_ci      pc, time_ns, is_external_callback, tos_or_external_callback, vmState,
4001cb0ef41Sopenharmony_ci      stack) {
4011cb0ef41Sopenharmony_ci    if (is_external_callback) {
4021cb0ef41Sopenharmony_ci      // Don't use PC when in external callback code, as it can point
4031cb0ef41Sopenharmony_ci      // inside callback's code, and we will erroneously report
4041cb0ef41Sopenharmony_ci      // that a callback calls itself. Instead we use tos_or_external_callback,
4051cb0ef41Sopenharmony_ci      // as simply resetting PC will produce unaccounted ticks.
4061cb0ef41Sopenharmony_ci      pc = tos_or_external_callback;
4071cb0ef41Sopenharmony_ci      tos_or_external_callback = 0;
4081cb0ef41Sopenharmony_ci    } else if (tos_or_external_callback) {
4091cb0ef41Sopenharmony_ci      // Find out, if top of stack was pointing inside a JS function
4101cb0ef41Sopenharmony_ci      // meaning that we have encountered a frameless invocation.
4111cb0ef41Sopenharmony_ci      const funcEntry = this._profile.findEntry(tos_or_external_callback);
4121cb0ef41Sopenharmony_ci      if (!funcEntry?.isJSFunction?.()) {
4131cb0ef41Sopenharmony_ci        tos_or_external_callback = 0;
4141cb0ef41Sopenharmony_ci      }
4151cb0ef41Sopenharmony_ci    }
4161cb0ef41Sopenharmony_ci    const entryStack = this._profile.recordTick(
4171cb0ef41Sopenharmony_ci        time_ns, vmState,
4181cb0ef41Sopenharmony_ci        this.processStack(pc, tos_or_external_callback, stack));
4191cb0ef41Sopenharmony_ci    const newEntry = new TickLogEntry(time_ns, vmState, entryStack);
4201cb0ef41Sopenharmony_ci    this._tickTimeline.push(newEntry);
4211cb0ef41Sopenharmony_ci    if (this._lastTickLogEntry !== undefined) {
4221cb0ef41Sopenharmony_ci      this._lastTickLogEntry.end(time_ns);
4231cb0ef41Sopenharmony_ci    }
4241cb0ef41Sopenharmony_ci    this._lastTickLogEntry = newEntry;
4251cb0ef41Sopenharmony_ci  }
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ci  processCodeSourceInfo(
4281cb0ef41Sopenharmony_ci      start, scriptId, startPos, endPos, sourcePositions, inliningPositions,
4291cb0ef41Sopenharmony_ci      inlinedFunctions) {
4301cb0ef41Sopenharmony_ci    this._profile.addSourcePositions(
4311cb0ef41Sopenharmony_ci        start, scriptId, startPos, endPos, sourcePositions, inliningPositions,
4321cb0ef41Sopenharmony_ci        inlinedFunctions);
4331cb0ef41Sopenharmony_ci    if (this._lastCodeLogEntry === undefined) return;
4341cb0ef41Sopenharmony_ci    let profileEntry = this._profile.findEntry(start);
4351cb0ef41Sopenharmony_ci    if (profileEntry !== this._lastCodeLogEntry._entry) return;
4361cb0ef41Sopenharmony_ci    this.addSourcePosition(profileEntry, this._lastCodeLogEntry);
4371cb0ef41Sopenharmony_ci    this._lastCodeLogEntry = undefined;
4381cb0ef41Sopenharmony_ci  }
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  addSourcePosition(profileEntry, logEntry) {
4411cb0ef41Sopenharmony_ci    let script = this.getProfileEntryScript(profileEntry);
4421cb0ef41Sopenharmony_ci    const parts = profileEntry.getRawName().split(':');
4431cb0ef41Sopenharmony_ci    if (parts.length < 3) return;
4441cb0ef41Sopenharmony_ci    const line = parseInt(parts[parts.length - 2]);
4451cb0ef41Sopenharmony_ci    const column = parseInt(parts[parts.length - 1]);
4461cb0ef41Sopenharmony_ci    logEntry.sourcePosition = script.addSourcePosition(line, column, logEntry);
4471cb0ef41Sopenharmony_ci  }
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  processCodeDisassemble(start, kind, disassemble) {
4501cb0ef41Sopenharmony_ci    this._profile.addDisassemble(start, kind, disassemble);
4511cb0ef41Sopenharmony_ci  }
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci  processPropertyIC(
4541cb0ef41Sopenharmony_ci      type, pc, time, line, column, old_state, new_state, mapId, key, modifier,
4551cb0ef41Sopenharmony_ci      slow_reason) {
4561cb0ef41Sopenharmony_ci    this._lastTimestamp = time;
4571cb0ef41Sopenharmony_ci    const codeEntry = this._profile.findEntry(pc);
4581cb0ef41Sopenharmony_ci    const fnName = this.formatProfileEntry(codeEntry);
4591cb0ef41Sopenharmony_ci    const script = this.getProfileEntryScript(codeEntry);
4601cb0ef41Sopenharmony_ci    const map = this.getOrCreateMapEntry(mapId, time);
4611cb0ef41Sopenharmony_ci    // TODO: Use SourcePosition here directly
4621cb0ef41Sopenharmony_ci    let entry = new IcLogEntry(
4631cb0ef41Sopenharmony_ci        type, fnName, time, line, column, key, old_state, new_state, map,
4641cb0ef41Sopenharmony_ci        slow_reason, modifier, codeEntry);
4651cb0ef41Sopenharmony_ci    if (script) {
4661cb0ef41Sopenharmony_ci      entry.sourcePosition = script.addSourcePosition(line, column, entry);
4671cb0ef41Sopenharmony_ci    }
4681cb0ef41Sopenharmony_ci    this._icTimeline.push(entry);
4691cb0ef41Sopenharmony_ci  }
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci  formatProfileEntry(profileEntry, line, column) {
4721cb0ef41Sopenharmony_ci    if (!profileEntry) return '<unknown>';
4731cb0ef41Sopenharmony_ci    if (profileEntry.type === 'Builtin') return profileEntry.name;
4741cb0ef41Sopenharmony_ci    const name = profileEntry.func.getName();
4751cb0ef41Sopenharmony_ci    const array = this._formatPCRegexp.exec(name);
4761cb0ef41Sopenharmony_ci    const formatted =
4771cb0ef41Sopenharmony_ci        (array === null) ? name : profileEntry.getState() + array[1];
4781cb0ef41Sopenharmony_ci    if (line === undefined || column === undefined) return formatted;
4791cb0ef41Sopenharmony_ci    return `${formatted}:${line}:${column}`;
4801cb0ef41Sopenharmony_ci  }
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci  getProfileEntryScript(profileEntry) {
4831cb0ef41Sopenharmony_ci    if (!profileEntry) return undefined;
4841cb0ef41Sopenharmony_ci    if (profileEntry.type === 'Builtin') return undefined;
4851cb0ef41Sopenharmony_ci    const script = profileEntry.source?.script;
4861cb0ef41Sopenharmony_ci    if (script !== undefined) return script;
4871cb0ef41Sopenharmony_ci    let fileName;
4881cb0ef41Sopenharmony_ci    if (profileEntry.type === 'SHARED_LIB') {
4891cb0ef41Sopenharmony_ci      fileName = profileEntry.name;
4901cb0ef41Sopenharmony_ci    } else {
4911cb0ef41Sopenharmony_ci      // Slow path, try to get the script from the url:
4921cb0ef41Sopenharmony_ci      const fnName = this.formatProfileEntry(profileEntry);
4931cb0ef41Sopenharmony_ci      let parts = fnName.split(' ');
4941cb0ef41Sopenharmony_ci      fileName = parts[parts.length - 1];
4951cb0ef41Sopenharmony_ci    }
4961cb0ef41Sopenharmony_ci    return this.getScript(fileName);
4971cb0ef41Sopenharmony_ci  }
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ci  processMap(type, time, from, to, pc, line, column, reason, name) {
5001cb0ef41Sopenharmony_ci    this._lastTimestamp = time;
5011cb0ef41Sopenharmony_ci    const time_ = parseInt(time);
5021cb0ef41Sopenharmony_ci    if (type === 'Deprecate') return this.deprecateMap(type, time_, from);
5031cb0ef41Sopenharmony_ci    // Skip normalized maps that were cached so we don't introduce multiple
5041cb0ef41Sopenharmony_ci    // edges with the same source and target map.
5051cb0ef41Sopenharmony_ci    if (type === 'NormalizeCached') return;
5061cb0ef41Sopenharmony_ci    const from_ = this.getOrCreateMapEntry(from, time_);
5071cb0ef41Sopenharmony_ci    const to_ = this.getOrCreateMapEntry(to, time_);
5081cb0ef41Sopenharmony_ci    if (type === 'Normalize') {
5091cb0ef41Sopenharmony_ci      // Fix a bug where we log "Normalize" transitions for maps created from
5101cb0ef41Sopenharmony_ci      // the NormalizedMapCache.
5111cb0ef41Sopenharmony_ci      if (to_.parent?.id === from || to_.time < from_.time || to_.depth > 0) {
5121cb0ef41Sopenharmony_ci        console.log(`Skipping transition to cached normalized map`);
5131cb0ef41Sopenharmony_ci        return;
5141cb0ef41Sopenharmony_ci      }
5151cb0ef41Sopenharmony_ci    }
5161cb0ef41Sopenharmony_ci    if (pc) {
5171cb0ef41Sopenharmony_ci      const profCodeEntry = this._profile.findEntry(pc);
5181cb0ef41Sopenharmony_ci      if (profCodeEntry) {
5191cb0ef41Sopenharmony_ci        to_.entry = profCodeEntry;
5201cb0ef41Sopenharmony_ci        profCodeEntry.logEntry.add(to_);
5211cb0ef41Sopenharmony_ci        let script = this.getProfileEntryScript(profCodeEntry);
5221cb0ef41Sopenharmony_ci        if (script) {
5231cb0ef41Sopenharmony_ci          to_.sourcePosition = script.addSourcePosition(line, column, to_);
5241cb0ef41Sopenharmony_ci        }
5251cb0ef41Sopenharmony_ci      }
5261cb0ef41Sopenharmony_ci    }
5271cb0ef41Sopenharmony_ci    let edge = new Edge(type, name, reason, time, from_, to_);
5281cb0ef41Sopenharmony_ci    if (to_.parent !== undefined && to_.parent === from_) {
5291cb0ef41Sopenharmony_ci      // Fix bug where we double log transitions.
5301cb0ef41Sopenharmony_ci      console.warn('Fixing up double transition');
5311cb0ef41Sopenharmony_ci      to_.edge.updateFrom(edge);
5321cb0ef41Sopenharmony_ci    } else {
5331cb0ef41Sopenharmony_ci      edge.finishSetup();
5341cb0ef41Sopenharmony_ci    }
5351cb0ef41Sopenharmony_ci  }
5361cb0ef41Sopenharmony_ci
5371cb0ef41Sopenharmony_ci  deprecateMap(type, time, id) {
5381cb0ef41Sopenharmony_ci    this._lastTimestamp = time;
5391cb0ef41Sopenharmony_ci    this.getOrCreateMapEntry(id, time).deprecate();
5401cb0ef41Sopenharmony_ci  }
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_ci  processMapCreate(time, id) {
5431cb0ef41Sopenharmony_ci    // map-create events might override existing maps if the addresses get
5441cb0ef41Sopenharmony_ci    // recycled. Hence we do not check for existing maps.
5451cb0ef41Sopenharmony_ci    this._lastTimestamp = time;
5461cb0ef41Sopenharmony_ci    this.createMapEntry(id, time);
5471cb0ef41Sopenharmony_ci  }
5481cb0ef41Sopenharmony_ci
5491cb0ef41Sopenharmony_ci  processMapDetails(time, id, string) {
5501cb0ef41Sopenharmony_ci    // TODO(cbruni): fix initial map logging.
5511cb0ef41Sopenharmony_ci    const map = this.getOrCreateMapEntry(id, time);
5521cb0ef41Sopenharmony_ci    map.description = string;
5531cb0ef41Sopenharmony_ci  }
5541cb0ef41Sopenharmony_ci
5551cb0ef41Sopenharmony_ci  createMapEntry(id, time) {
5561cb0ef41Sopenharmony_ci    this._lastTimestamp = time;
5571cb0ef41Sopenharmony_ci    const map = new MapLogEntry(id, time);
5581cb0ef41Sopenharmony_ci    this._mapTimeline.push(map);
5591cb0ef41Sopenharmony_ci    return map;
5601cb0ef41Sopenharmony_ci  }
5611cb0ef41Sopenharmony_ci
5621cb0ef41Sopenharmony_ci  getOrCreateMapEntry(id, time) {
5631cb0ef41Sopenharmony_ci    if (id === '0x000000000000') return undefined;
5641cb0ef41Sopenharmony_ci    const map = MapLogEntry.get(id, time);
5651cb0ef41Sopenharmony_ci    if (map !== undefined) return map;
5661cb0ef41Sopenharmony_ci    console.warn(`No map details provided: id=${id}`);
5671cb0ef41Sopenharmony_ci    // Manually patch in a map to continue running.
5681cb0ef41Sopenharmony_ci    return this.createMapEntry(id, time);
5691cb0ef41Sopenharmony_ci  }
5701cb0ef41Sopenharmony_ci
5711cb0ef41Sopenharmony_ci  getScript(url) {
5721cb0ef41Sopenharmony_ci    const script = this._profile.getScript(url);
5731cb0ef41Sopenharmony_ci    // TODO create placeholder script for empty urls.
5741cb0ef41Sopenharmony_ci    if (script === undefined) {
5751cb0ef41Sopenharmony_ci      console.error(`Could not find script for url: '${url}'`)
5761cb0ef41Sopenharmony_ci    }
5771cb0ef41Sopenharmony_ci    return script;
5781cb0ef41Sopenharmony_ci  }
5791cb0ef41Sopenharmony_ci
5801cb0ef41Sopenharmony_ci  processApiEvent(type, varArgs) {
5811cb0ef41Sopenharmony_ci    // legacy events that are no longer supported
5821cb0ef41Sopenharmony_ci  }
5831cb0ef41Sopenharmony_ci
5841cb0ef41Sopenharmony_ci  processTimerEventStart(type, time) {
5851cb0ef41Sopenharmony_ci    const entry = new TimerLogEntry(type, time);
5861cb0ef41Sopenharmony_ci    this._timerTimeline.push(entry);
5871cb0ef41Sopenharmony_ci  }
5881cb0ef41Sopenharmony_ci
5891cb0ef41Sopenharmony_ci  processTimerEventEnd(type, time) {
5901cb0ef41Sopenharmony_ci    // Timer-events are infrequent, and not deeply nested, doing a linear walk
5911cb0ef41Sopenharmony_ci    // is usually good enough.
5921cb0ef41Sopenharmony_ci    for (let i = this._timerTimeline.length - 1; i >= 0; i--) {
5931cb0ef41Sopenharmony_ci      const timer = this._timerTimeline.at(i);
5941cb0ef41Sopenharmony_ci      if (timer.type == type && !timer.isInitialized) {
5951cb0ef41Sopenharmony_ci        timer.end(time);
5961cb0ef41Sopenharmony_ci        return;
5971cb0ef41Sopenharmony_ci      }
5981cb0ef41Sopenharmony_ci    }
5991cb0ef41Sopenharmony_ci    console.error('Couldn\'t find matching timer event start', {type, time});
6001cb0ef41Sopenharmony_ci  }
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci  get icTimeline() {
6031cb0ef41Sopenharmony_ci    return this._icTimeline;
6041cb0ef41Sopenharmony_ci  }
6051cb0ef41Sopenharmony_ci
6061cb0ef41Sopenharmony_ci  get mapTimeline() {
6071cb0ef41Sopenharmony_ci    return this._mapTimeline;
6081cb0ef41Sopenharmony_ci  }
6091cb0ef41Sopenharmony_ci
6101cb0ef41Sopenharmony_ci  get deoptTimeline() {
6111cb0ef41Sopenharmony_ci    return this._deoptTimeline;
6121cb0ef41Sopenharmony_ci  }
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ci  get codeTimeline() {
6151cb0ef41Sopenharmony_ci    return this._codeTimeline;
6161cb0ef41Sopenharmony_ci  }
6171cb0ef41Sopenharmony_ci
6181cb0ef41Sopenharmony_ci  get tickTimeline() {
6191cb0ef41Sopenharmony_ci    return this._tickTimeline;
6201cb0ef41Sopenharmony_ci  }
6211cb0ef41Sopenharmony_ci
6221cb0ef41Sopenharmony_ci  get timerTimeline() {
6231cb0ef41Sopenharmony_ci    return this._timerTimeline;
6241cb0ef41Sopenharmony_ci  }
6251cb0ef41Sopenharmony_ci
6261cb0ef41Sopenharmony_ci  get scripts() {
6271cb0ef41Sopenharmony_ci    return this._profile.scripts_.filter(script => script !== undefined);
6281cb0ef41Sopenharmony_ci  }
6291cb0ef41Sopenharmony_ci
6301cb0ef41Sopenharmony_ci  get profile() {
6311cb0ef41Sopenharmony_ci    return this._profile;
6321cb0ef41Sopenharmony_ci  }
6331cb0ef41Sopenharmony_ci}
634