11cb0ef41Sopenharmony_ci// Copyright 2012 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_ci#include "src/debug/liveedit.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/api/api-inl.h"
81cb0ef41Sopenharmony_ci#include "src/ast/ast-traversal-visitor.h"
91cb0ef41Sopenharmony_ci#include "src/ast/ast.h"
101cb0ef41Sopenharmony_ci#include "src/ast/scopes.h"
111cb0ef41Sopenharmony_ci#include "src/codegen/compilation-cache.h"
121cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h"
131cb0ef41Sopenharmony_ci#include "src/codegen/source-position-table.h"
141cb0ef41Sopenharmony_ci#include "src/common/globals.h"
151cb0ef41Sopenharmony_ci#include "src/debug/debug-interface.h"
161cb0ef41Sopenharmony_ci#include "src/debug/debug.h"
171cb0ef41Sopenharmony_ci#include "src/execution/frames-inl.h"
181cb0ef41Sopenharmony_ci#include "src/execution/isolate-inl.h"
191cb0ef41Sopenharmony_ci#include "src/execution/v8threads.h"
201cb0ef41Sopenharmony_ci#include "src/init/v8.h"
211cb0ef41Sopenharmony_ci#include "src/logging/log.h"
221cb0ef41Sopenharmony_ci#include "src/objects/hash-table-inl.h"
231cb0ef41Sopenharmony_ci#include "src/objects/js-generator-inl.h"
241cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
251cb0ef41Sopenharmony_ci#include "src/parsing/parse-info.h"
261cb0ef41Sopenharmony_ci#include "src/parsing/parsing.h"
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_cinamespace v8 {
291cb0ef41Sopenharmony_cinamespace internal {
301cb0ef41Sopenharmony_cinamespace {
311cb0ef41Sopenharmony_ci// A general-purpose comparator between 2 arrays.
321cb0ef41Sopenharmony_ciclass Comparator {
331cb0ef41Sopenharmony_ci public:
341cb0ef41Sopenharmony_ci  // Holds 2 arrays of some elements allowing to compare any pair of
351cb0ef41Sopenharmony_ci  // element from the first array and element from the second array.
361cb0ef41Sopenharmony_ci  class Input {
371cb0ef41Sopenharmony_ci   public:
381cb0ef41Sopenharmony_ci    virtual int GetLength1() = 0;
391cb0ef41Sopenharmony_ci    virtual int GetLength2() = 0;
401cb0ef41Sopenharmony_ci    virtual bool Equals(int index1, int index2) = 0;
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci   protected:
431cb0ef41Sopenharmony_ci    virtual ~Input() = default;
441cb0ef41Sopenharmony_ci  };
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  // Receives compare result as a series of chunks.
471cb0ef41Sopenharmony_ci  class Output {
481cb0ef41Sopenharmony_ci   public:
491cb0ef41Sopenharmony_ci    // Puts another chunk in result list. Note that technically speaking
501cb0ef41Sopenharmony_ci    // only 3 arguments actually needed with 4th being derivable.
511cb0ef41Sopenharmony_ci    virtual void AddChunk(int pos1, int pos2, int len1, int len2) = 0;
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci   protected:
541cb0ef41Sopenharmony_ci    virtual ~Output() = default;
551cb0ef41Sopenharmony_ci  };
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  // Finds the difference between 2 arrays of elements.
581cb0ef41Sopenharmony_ci  static void CalculateDifference(Input* input, Output* result_writer);
591cb0ef41Sopenharmony_ci};
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci// A simple implementation of dynamic programming algorithm. It solves
621cb0ef41Sopenharmony_ci// the problem of finding the difference of 2 arrays. It uses a table of results
631cb0ef41Sopenharmony_ci// of subproblems. Each cell contains a number together with 2-bit flag
641cb0ef41Sopenharmony_ci// that helps building the chunk list.
651cb0ef41Sopenharmony_ciclass Differencer {
661cb0ef41Sopenharmony_ci public:
671cb0ef41Sopenharmony_ci  explicit Differencer(Comparator::Input* input)
681cb0ef41Sopenharmony_ci      : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  void Initialize() {
721cb0ef41Sopenharmony_ci  }
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  // Makes sure that result for the full problem is calculated and stored
751cb0ef41Sopenharmony_ci  // in the table together with flags showing a path through subproblems.
761cb0ef41Sopenharmony_ci  void FillTable() {
771cb0ef41Sopenharmony_ci    // Determine common prefix to skip.
781cb0ef41Sopenharmony_ci    int minLen = std::min(len1_, len2_);
791cb0ef41Sopenharmony_ci    while (prefixLen_ < minLen && input_->Equals(prefixLen_, prefixLen_)) {
801cb0ef41Sopenharmony_ci      ++prefixLen_;
811cb0ef41Sopenharmony_ci    }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci    // Pre-fill common suffix in the table.
841cb0ef41Sopenharmony_ci    for (int pos1 = len1_, pos2 = len2_; pos1 > prefixLen_ &&
851cb0ef41Sopenharmony_ci                                         pos2 > prefixLen_ &&
861cb0ef41Sopenharmony_ci                                         input_->Equals(--pos1, --pos2);) {
871cb0ef41Sopenharmony_ci      set_value4_and_dir(pos1, pos2, 0, EQ);
881cb0ef41Sopenharmony_ci    }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci    CompareUpToTail(prefixLen_, prefixLen_);
911cb0ef41Sopenharmony_ci  }
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  void SaveResult(Comparator::Output* chunk_writer) {
941cb0ef41Sopenharmony_ci    ResultWriter writer(chunk_writer);
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci    if (prefixLen_) writer.eq(prefixLen_);
971cb0ef41Sopenharmony_ci    for (int pos1 = prefixLen_, pos2 = prefixLen_; true;) {
981cb0ef41Sopenharmony_ci      if (pos1 < len1_) {
991cb0ef41Sopenharmony_ci        if (pos2 < len2_) {
1001cb0ef41Sopenharmony_ci          Direction dir = get_direction(pos1, pos2);
1011cb0ef41Sopenharmony_ci          switch (dir) {
1021cb0ef41Sopenharmony_ci            case EQ:
1031cb0ef41Sopenharmony_ci              writer.eq();
1041cb0ef41Sopenharmony_ci              pos1++;
1051cb0ef41Sopenharmony_ci              pos2++;
1061cb0ef41Sopenharmony_ci              break;
1071cb0ef41Sopenharmony_ci            case SKIP1:
1081cb0ef41Sopenharmony_ci              writer.skip1(1);
1091cb0ef41Sopenharmony_ci              pos1++;
1101cb0ef41Sopenharmony_ci              break;
1111cb0ef41Sopenharmony_ci            case SKIP2:
1121cb0ef41Sopenharmony_ci            case SKIP_ANY:
1131cb0ef41Sopenharmony_ci              writer.skip2(1);
1141cb0ef41Sopenharmony_ci              pos2++;
1151cb0ef41Sopenharmony_ci              break;
1161cb0ef41Sopenharmony_ci            default:
1171cb0ef41Sopenharmony_ci              UNREACHABLE();
1181cb0ef41Sopenharmony_ci          }
1191cb0ef41Sopenharmony_ci        } else {
1201cb0ef41Sopenharmony_ci          writer.skip1(len1_ - pos1);
1211cb0ef41Sopenharmony_ci          break;
1221cb0ef41Sopenharmony_ci        }
1231cb0ef41Sopenharmony_ci      } else {
1241cb0ef41Sopenharmony_ci        if (len2_ != pos2) {
1251cb0ef41Sopenharmony_ci          writer.skip2(len2_ - pos2);
1261cb0ef41Sopenharmony_ci        }
1271cb0ef41Sopenharmony_ci        break;
1281cb0ef41Sopenharmony_ci      }
1291cb0ef41Sopenharmony_ci    }
1301cb0ef41Sopenharmony_ci    writer.close();
1311cb0ef41Sopenharmony_ci  }
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci private:
1341cb0ef41Sopenharmony_ci  Comparator::Input* input_;
1351cb0ef41Sopenharmony_ci  std::map<std::pair<int, int>, int> buffer_;
1361cb0ef41Sopenharmony_ci  int len1_;
1371cb0ef41Sopenharmony_ci  int len2_;
1381cb0ef41Sopenharmony_ci  int prefixLen_ = 0;
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  enum Direction {
1411cb0ef41Sopenharmony_ci    EQ = 0,
1421cb0ef41Sopenharmony_ci    SKIP1,
1431cb0ef41Sopenharmony_ci    SKIP2,
1441cb0ef41Sopenharmony_ci    SKIP_ANY,
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci    MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
1471cb0ef41Sopenharmony_ci  };
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  // Computes result for a subtask and optionally caches it in the buffer table.
1501cb0ef41Sopenharmony_ci  // All results values are shifted to make space for flags in the lower bits.
1511cb0ef41Sopenharmony_ci  int CompareUpToTail(int pos1, int pos2) {
1521cb0ef41Sopenharmony_ci    if (pos1 == len1_) {
1531cb0ef41Sopenharmony_ci      return (len2_ - pos2) << kDirectionSizeBits;
1541cb0ef41Sopenharmony_ci    }
1551cb0ef41Sopenharmony_ci    if (pos2 == len2_) {
1561cb0ef41Sopenharmony_ci      return (len1_ - pos1) << kDirectionSizeBits;
1571cb0ef41Sopenharmony_ci    }
1581cb0ef41Sopenharmony_ci    int res = get_value4(pos1, pos2);
1591cb0ef41Sopenharmony_ci    if (res != kEmptyCellValue) {
1601cb0ef41Sopenharmony_ci      return res;
1611cb0ef41Sopenharmony_ci    }
1621cb0ef41Sopenharmony_ci    Direction dir;
1631cb0ef41Sopenharmony_ci    if (input_->Equals(pos1, pos2)) {
1641cb0ef41Sopenharmony_ci      res = CompareUpToTail(pos1 + 1, pos2 + 1);
1651cb0ef41Sopenharmony_ci      dir = EQ;
1661cb0ef41Sopenharmony_ci    } else {
1671cb0ef41Sopenharmony_ci      int res1 = CompareUpToTail(pos1 + 1, pos2) + (1 << kDirectionSizeBits);
1681cb0ef41Sopenharmony_ci      int res2 = CompareUpToTail(pos1, pos2 + 1) + (1 << kDirectionSizeBits);
1691cb0ef41Sopenharmony_ci      if (res1 == res2) {
1701cb0ef41Sopenharmony_ci        res = res1;
1711cb0ef41Sopenharmony_ci        dir = SKIP_ANY;
1721cb0ef41Sopenharmony_ci      } else if (res1 < res2) {
1731cb0ef41Sopenharmony_ci        res = res1;
1741cb0ef41Sopenharmony_ci        dir = SKIP1;
1751cb0ef41Sopenharmony_ci      } else {
1761cb0ef41Sopenharmony_ci        res = res2;
1771cb0ef41Sopenharmony_ci        dir = SKIP2;
1781cb0ef41Sopenharmony_ci      }
1791cb0ef41Sopenharmony_ci    }
1801cb0ef41Sopenharmony_ci    set_value4_and_dir(pos1, pos2, res, dir);
1811cb0ef41Sopenharmony_ci    return res;
1821cb0ef41Sopenharmony_ci  }
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci  inline int get_cell(int i1, int i2) {
1851cb0ef41Sopenharmony_ci    auto it = buffer_.find(std::make_pair(i1, i2));
1861cb0ef41Sopenharmony_ci    return it == buffer_.end() ? kEmptyCellValue : it->second;
1871cb0ef41Sopenharmony_ci  }
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  inline void set_cell(int i1, int i2, int value) {
1901cb0ef41Sopenharmony_ci    buffer_.insert(std::make_pair(std::make_pair(i1, i2), value));
1911cb0ef41Sopenharmony_ci  }
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci  // Each cell keeps a value plus direction. Value is multiplied by 4.
1941cb0ef41Sopenharmony_ci  void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
1951cb0ef41Sopenharmony_ci    DCHECK_EQ(0, value4 & kDirectionMask);
1961cb0ef41Sopenharmony_ci    set_cell(i1, i2, value4 | dir);
1971cb0ef41Sopenharmony_ci  }
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci  int get_value4(int i1, int i2) {
2001cb0ef41Sopenharmony_ci    return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
2011cb0ef41Sopenharmony_ci  }
2021cb0ef41Sopenharmony_ci  Direction get_direction(int i1, int i2) {
2031cb0ef41Sopenharmony_ci    return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
2041cb0ef41Sopenharmony_ci  }
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci  static const int kDirectionSizeBits = 2;
2071cb0ef41Sopenharmony_ci  static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
2081cb0ef41Sopenharmony_ci  static const int kEmptyCellValue = ~0u << kDirectionSizeBits;
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci  // This method only holds static assert statement (unfortunately you cannot
2111cb0ef41Sopenharmony_ci  // place one in class scope).
2121cb0ef41Sopenharmony_ci  void StaticAssertHolder() {
2131cb0ef41Sopenharmony_ci    STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
2141cb0ef41Sopenharmony_ci  }
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  class ResultWriter {
2171cb0ef41Sopenharmony_ci   public:
2181cb0ef41Sopenharmony_ci    explicit ResultWriter(Comparator::Output* chunk_writer)
2191cb0ef41Sopenharmony_ci        : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
2201cb0ef41Sopenharmony_ci          pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
2211cb0ef41Sopenharmony_ci    }
2221cb0ef41Sopenharmony_ci    void eq(int len = 1) {
2231cb0ef41Sopenharmony_ci      FlushChunk();
2241cb0ef41Sopenharmony_ci      pos1_ += len;
2251cb0ef41Sopenharmony_ci      pos2_ += len;
2261cb0ef41Sopenharmony_ci    }
2271cb0ef41Sopenharmony_ci    void skip1(int len1) {
2281cb0ef41Sopenharmony_ci      StartChunk();
2291cb0ef41Sopenharmony_ci      pos1_ += len1;
2301cb0ef41Sopenharmony_ci    }
2311cb0ef41Sopenharmony_ci    void skip2(int len2) {
2321cb0ef41Sopenharmony_ci      StartChunk();
2331cb0ef41Sopenharmony_ci      pos2_ += len2;
2341cb0ef41Sopenharmony_ci    }
2351cb0ef41Sopenharmony_ci    void close() {
2361cb0ef41Sopenharmony_ci      FlushChunk();
2371cb0ef41Sopenharmony_ci    }
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci   private:
2401cb0ef41Sopenharmony_ci    Comparator::Output* chunk_writer_;
2411cb0ef41Sopenharmony_ci    int pos1_;
2421cb0ef41Sopenharmony_ci    int pos2_;
2431cb0ef41Sopenharmony_ci    int pos1_begin_;
2441cb0ef41Sopenharmony_ci    int pos2_begin_;
2451cb0ef41Sopenharmony_ci    bool has_open_chunk_;
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci    void StartChunk() {
2481cb0ef41Sopenharmony_ci      if (!has_open_chunk_) {
2491cb0ef41Sopenharmony_ci        pos1_begin_ = pos1_;
2501cb0ef41Sopenharmony_ci        pos2_begin_ = pos2_;
2511cb0ef41Sopenharmony_ci        has_open_chunk_ = true;
2521cb0ef41Sopenharmony_ci      }
2531cb0ef41Sopenharmony_ci    }
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci    void FlushChunk() {
2561cb0ef41Sopenharmony_ci      if (has_open_chunk_) {
2571cb0ef41Sopenharmony_ci        chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
2581cb0ef41Sopenharmony_ci                                pos1_ - pos1_begin_, pos2_ - pos2_begin_);
2591cb0ef41Sopenharmony_ci        has_open_chunk_ = false;
2601cb0ef41Sopenharmony_ci      }
2611cb0ef41Sopenharmony_ci    }
2621cb0ef41Sopenharmony_ci  };
2631cb0ef41Sopenharmony_ci};
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_civoid Comparator::CalculateDifference(Comparator::Input* input,
2661cb0ef41Sopenharmony_ci                                     Comparator::Output* result_writer) {
2671cb0ef41Sopenharmony_ci  Differencer differencer(input);
2681cb0ef41Sopenharmony_ci  differencer.Initialize();
2691cb0ef41Sopenharmony_ci  differencer.FillTable();
2701cb0ef41Sopenharmony_ci  differencer.SaveResult(result_writer);
2711cb0ef41Sopenharmony_ci}
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_cibool CompareSubstrings(Handle<String> s1, int pos1, Handle<String> s2, int pos2,
2741cb0ef41Sopenharmony_ci                       int len) {
2751cb0ef41Sopenharmony_ci  for (int i = 0; i < len; i++) {
2761cb0ef41Sopenharmony_ci    if (s1->Get(i + pos1) != s2->Get(i + pos2)) return false;
2771cb0ef41Sopenharmony_ci  }
2781cb0ef41Sopenharmony_ci  return true;
2791cb0ef41Sopenharmony_ci}
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci// Additional to Input interface. Lets switch Input range to subrange.
2821cb0ef41Sopenharmony_ci// More elegant way would be to wrap one Input as another Input object
2831cb0ef41Sopenharmony_ci// and translate positions there, but that would cost us additional virtual
2841cb0ef41Sopenharmony_ci// call per comparison.
2851cb0ef41Sopenharmony_ciclass SubrangableInput : public Comparator::Input {
2861cb0ef41Sopenharmony_ci public:
2871cb0ef41Sopenharmony_ci  virtual void SetSubrange1(int offset, int len) = 0;
2881cb0ef41Sopenharmony_ci  virtual void SetSubrange2(int offset, int len) = 0;
2891cb0ef41Sopenharmony_ci};
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ciclass SubrangableOutput : public Comparator::Output {
2931cb0ef41Sopenharmony_ci public:
2941cb0ef41Sopenharmony_ci  virtual void SetSubrange1(int offset, int len) = 0;
2951cb0ef41Sopenharmony_ci  virtual void SetSubrange2(int offset, int len) = 0;
2961cb0ef41Sopenharmony_ci};
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci// Finds common prefix and suffix in input. This parts shouldn't take space in
2991cb0ef41Sopenharmony_ci// linear programming table. Enable subranging in input and output.
3001cb0ef41Sopenharmony_civoid NarrowDownInput(SubrangableInput* input, SubrangableOutput* output) {
3011cb0ef41Sopenharmony_ci  const int len1 = input->GetLength1();
3021cb0ef41Sopenharmony_ci  const int len2 = input->GetLength2();
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ci  int common_prefix_len;
3051cb0ef41Sopenharmony_ci  int common_suffix_len;
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci  {
3081cb0ef41Sopenharmony_ci    common_prefix_len = 0;
3091cb0ef41Sopenharmony_ci    int prefix_limit = std::min(len1, len2);
3101cb0ef41Sopenharmony_ci    while (common_prefix_len < prefix_limit &&
3111cb0ef41Sopenharmony_ci        input->Equals(common_prefix_len, common_prefix_len)) {
3121cb0ef41Sopenharmony_ci      common_prefix_len++;
3131cb0ef41Sopenharmony_ci    }
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ci    common_suffix_len = 0;
3161cb0ef41Sopenharmony_ci    int suffix_limit =
3171cb0ef41Sopenharmony_ci        std::min(len1 - common_prefix_len, len2 - common_prefix_len);
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci    while (common_suffix_len < suffix_limit &&
3201cb0ef41Sopenharmony_ci        input->Equals(len1 - common_suffix_len - 1,
3211cb0ef41Sopenharmony_ci        len2 - common_suffix_len - 1)) {
3221cb0ef41Sopenharmony_ci      common_suffix_len++;
3231cb0ef41Sopenharmony_ci    }
3241cb0ef41Sopenharmony_ci  }
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci  if (common_prefix_len > 0 || common_suffix_len > 0) {
3271cb0ef41Sopenharmony_ci    int new_len1 = len1 - common_suffix_len - common_prefix_len;
3281cb0ef41Sopenharmony_ci    int new_len2 = len2 - common_suffix_len - common_prefix_len;
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_ci    input->SetSubrange1(common_prefix_len, new_len1);
3311cb0ef41Sopenharmony_ci    input->SetSubrange2(common_prefix_len, new_len2);
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci    output->SetSubrange1(common_prefix_len, new_len1);
3341cb0ef41Sopenharmony_ci    output->SetSubrange2(common_prefix_len, new_len2);
3351cb0ef41Sopenharmony_ci  }
3361cb0ef41Sopenharmony_ci}
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci// Represents 2 strings as 2 arrays of tokens.
3391cb0ef41Sopenharmony_ci// TODO(LiveEdit): Currently it's actually an array of charactres.
3401cb0ef41Sopenharmony_ci//     Make array of tokens instead.
3411cb0ef41Sopenharmony_ciclass TokensCompareInput : public Comparator::Input {
3421cb0ef41Sopenharmony_ci public:
3431cb0ef41Sopenharmony_ci  TokensCompareInput(Handle<String> s1, int offset1, int len1,
3441cb0ef41Sopenharmony_ci                       Handle<String> s2, int offset2, int len2)
3451cb0ef41Sopenharmony_ci      : s1_(s1), offset1_(offset1), len1_(len1),
3461cb0ef41Sopenharmony_ci        s2_(s2), offset2_(offset2), len2_(len2) {
3471cb0ef41Sopenharmony_ci  }
3481cb0ef41Sopenharmony_ci  int GetLength1() override { return len1_; }
3491cb0ef41Sopenharmony_ci  int GetLength2() override { return len2_; }
3501cb0ef41Sopenharmony_ci  bool Equals(int index1, int index2) override {
3511cb0ef41Sopenharmony_ci    return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
3521cb0ef41Sopenharmony_ci  }
3531cb0ef41Sopenharmony_ci
3541cb0ef41Sopenharmony_ci private:
3551cb0ef41Sopenharmony_ci  Handle<String> s1_;
3561cb0ef41Sopenharmony_ci  int offset1_;
3571cb0ef41Sopenharmony_ci  int len1_;
3581cb0ef41Sopenharmony_ci  Handle<String> s2_;
3591cb0ef41Sopenharmony_ci  int offset2_;
3601cb0ef41Sopenharmony_ci  int len2_;
3611cb0ef41Sopenharmony_ci};
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_ci// Stores compare result in std::vector. Converts substring positions
3641cb0ef41Sopenharmony_ci// to absolute positions.
3651cb0ef41Sopenharmony_ciclass TokensCompareOutput : public Comparator::Output {
3661cb0ef41Sopenharmony_ci public:
3671cb0ef41Sopenharmony_ci  TokensCompareOutput(int offset1, int offset2,
3681cb0ef41Sopenharmony_ci                      std::vector<SourceChangeRange>* output)
3691cb0ef41Sopenharmony_ci      : output_(output), offset1_(offset1), offset2_(offset2) {}
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci  void AddChunk(int pos1, int pos2, int len1, int len2) override {
3721cb0ef41Sopenharmony_ci    output_->emplace_back(
3731cb0ef41Sopenharmony_ci        SourceChangeRange{pos1 + offset1_, pos1 + len1 + offset1_,
3741cb0ef41Sopenharmony_ci                          pos2 + offset2_, pos2 + offset2_ + len2});
3751cb0ef41Sopenharmony_ci  }
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci private:
3781cb0ef41Sopenharmony_ci  std::vector<SourceChangeRange>* output_;
3791cb0ef41Sopenharmony_ci  int offset1_;
3801cb0ef41Sopenharmony_ci  int offset2_;
3811cb0ef41Sopenharmony_ci};
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci// Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
3841cb0ef41Sopenharmony_ci// never has terminating new line character.
3851cb0ef41Sopenharmony_ciclass LineEndsWrapper {
3861cb0ef41Sopenharmony_ci public:
3871cb0ef41Sopenharmony_ci  explicit LineEndsWrapper(Isolate* isolate, Handle<String> string)
3881cb0ef41Sopenharmony_ci      : ends_array_(String::CalculateLineEnds(isolate, string, false)),
3891cb0ef41Sopenharmony_ci        string_len_(string->length()) {}
3901cb0ef41Sopenharmony_ci  int length() {
3911cb0ef41Sopenharmony_ci    return ends_array_->length() + 1;
3921cb0ef41Sopenharmony_ci  }
3931cb0ef41Sopenharmony_ci  // Returns start for any line including start of the imaginary line after
3941cb0ef41Sopenharmony_ci  // the last line.
3951cb0ef41Sopenharmony_ci  int GetLineStart(int index) { return index == 0 ? 0 : GetLineEnd(index - 1); }
3961cb0ef41Sopenharmony_ci  int GetLineEnd(int index) {
3971cb0ef41Sopenharmony_ci    if (index == ends_array_->length()) {
3981cb0ef41Sopenharmony_ci      // End of the last line is always an end of the whole string.
3991cb0ef41Sopenharmony_ci      // If the string ends with a new line character, the last line is an
4001cb0ef41Sopenharmony_ci      // empty string after this character.
4011cb0ef41Sopenharmony_ci      return string_len_;
4021cb0ef41Sopenharmony_ci    } else {
4031cb0ef41Sopenharmony_ci      return GetPosAfterNewLine(index);
4041cb0ef41Sopenharmony_ci    }
4051cb0ef41Sopenharmony_ci  }
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci private:
4081cb0ef41Sopenharmony_ci  Handle<FixedArray> ends_array_;
4091cb0ef41Sopenharmony_ci  int string_len_;
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  int GetPosAfterNewLine(int index) {
4121cb0ef41Sopenharmony_ci    return Smi::ToInt(ends_array_->get(index)) + 1;
4131cb0ef41Sopenharmony_ci  }
4141cb0ef41Sopenharmony_ci};
4151cb0ef41Sopenharmony_ci
4161cb0ef41Sopenharmony_ci// Represents 2 strings as 2 arrays of lines.
4171cb0ef41Sopenharmony_ciclass LineArrayCompareInput : public SubrangableInput {
4181cb0ef41Sopenharmony_ci public:
4191cb0ef41Sopenharmony_ci  LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
4201cb0ef41Sopenharmony_ci                        LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
4211cb0ef41Sopenharmony_ci      : s1_(s1), s2_(s2), line_ends1_(line_ends1),
4221cb0ef41Sopenharmony_ci        line_ends2_(line_ends2),
4231cb0ef41Sopenharmony_ci        subrange_offset1_(0), subrange_offset2_(0),
4241cb0ef41Sopenharmony_ci        subrange_len1_(line_ends1_.length()),
4251cb0ef41Sopenharmony_ci        subrange_len2_(line_ends2_.length()) {
4261cb0ef41Sopenharmony_ci  }
4271cb0ef41Sopenharmony_ci  int GetLength1() override { return subrange_len1_; }
4281cb0ef41Sopenharmony_ci  int GetLength2() override { return subrange_len2_; }
4291cb0ef41Sopenharmony_ci  bool Equals(int index1, int index2) override {
4301cb0ef41Sopenharmony_ci    index1 += subrange_offset1_;
4311cb0ef41Sopenharmony_ci    index2 += subrange_offset2_;
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_ci    int line_start1 = line_ends1_.GetLineStart(index1);
4341cb0ef41Sopenharmony_ci    int line_start2 = line_ends2_.GetLineStart(index2);
4351cb0ef41Sopenharmony_ci    int line_end1 = line_ends1_.GetLineEnd(index1);
4361cb0ef41Sopenharmony_ci    int line_end2 = line_ends2_.GetLineEnd(index2);
4371cb0ef41Sopenharmony_ci    int len1 = line_end1 - line_start1;
4381cb0ef41Sopenharmony_ci    int len2 = line_end2 - line_start2;
4391cb0ef41Sopenharmony_ci    if (len1 != len2) {
4401cb0ef41Sopenharmony_ci      return false;
4411cb0ef41Sopenharmony_ci    }
4421cb0ef41Sopenharmony_ci    return CompareSubstrings(s1_, line_start1, s2_, line_start2,
4431cb0ef41Sopenharmony_ci                             len1);
4441cb0ef41Sopenharmony_ci  }
4451cb0ef41Sopenharmony_ci  void SetSubrange1(int offset, int len) override {
4461cb0ef41Sopenharmony_ci    subrange_offset1_ = offset;
4471cb0ef41Sopenharmony_ci    subrange_len1_ = len;
4481cb0ef41Sopenharmony_ci  }
4491cb0ef41Sopenharmony_ci  void SetSubrange2(int offset, int len) override {
4501cb0ef41Sopenharmony_ci    subrange_offset2_ = offset;
4511cb0ef41Sopenharmony_ci    subrange_len2_ = len;
4521cb0ef41Sopenharmony_ci  }
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci private:
4551cb0ef41Sopenharmony_ci  Handle<String> s1_;
4561cb0ef41Sopenharmony_ci  Handle<String> s2_;
4571cb0ef41Sopenharmony_ci  LineEndsWrapper line_ends1_;
4581cb0ef41Sopenharmony_ci  LineEndsWrapper line_ends2_;
4591cb0ef41Sopenharmony_ci  int subrange_offset1_;
4601cb0ef41Sopenharmony_ci  int subrange_offset2_;
4611cb0ef41Sopenharmony_ci  int subrange_len1_;
4621cb0ef41Sopenharmony_ci  int subrange_len2_;
4631cb0ef41Sopenharmony_ci};
4641cb0ef41Sopenharmony_ci
4651cb0ef41Sopenharmony_ci// Stores compare result in std::vector. For each chunk tries to conduct
4661cb0ef41Sopenharmony_ci// a fine-grained nested diff token-wise.
4671cb0ef41Sopenharmony_ciclass TokenizingLineArrayCompareOutput : public SubrangableOutput {
4681cb0ef41Sopenharmony_ci public:
4691cb0ef41Sopenharmony_ci  TokenizingLineArrayCompareOutput(Isolate* isolate, LineEndsWrapper line_ends1,
4701cb0ef41Sopenharmony_ci                                   LineEndsWrapper line_ends2,
4711cb0ef41Sopenharmony_ci                                   Handle<String> s1, Handle<String> s2,
4721cb0ef41Sopenharmony_ci                                   std::vector<SourceChangeRange>* output)
4731cb0ef41Sopenharmony_ci      : isolate_(isolate),
4741cb0ef41Sopenharmony_ci        line_ends1_(line_ends1),
4751cb0ef41Sopenharmony_ci        line_ends2_(line_ends2),
4761cb0ef41Sopenharmony_ci        s1_(s1),
4771cb0ef41Sopenharmony_ci        s2_(s2),
4781cb0ef41Sopenharmony_ci        subrange_offset1_(0),
4791cb0ef41Sopenharmony_ci        subrange_offset2_(0),
4801cb0ef41Sopenharmony_ci        output_(output) {}
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci  void AddChunk(int line_pos1, int line_pos2, int line_len1,
4831cb0ef41Sopenharmony_ci                int line_len2) override {
4841cb0ef41Sopenharmony_ci    line_pos1 += subrange_offset1_;
4851cb0ef41Sopenharmony_ci    line_pos2 += subrange_offset2_;
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_ci    int char_pos1 = line_ends1_.GetLineStart(line_pos1);
4881cb0ef41Sopenharmony_ci    int char_pos2 = line_ends2_.GetLineStart(line_pos2);
4891cb0ef41Sopenharmony_ci    int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
4901cb0ef41Sopenharmony_ci    int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci    if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
4931cb0ef41Sopenharmony_ci      // Chunk is small enough to conduct a nested token-level diff.
4941cb0ef41Sopenharmony_ci      HandleScope subTaskScope(isolate_);
4951cb0ef41Sopenharmony_ci
4961cb0ef41Sopenharmony_ci      TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
4971cb0ef41Sopenharmony_ci                                      s2_, char_pos2, char_len2);
4981cb0ef41Sopenharmony_ci      TokensCompareOutput tokens_output(char_pos1, char_pos2, output_);
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci      Comparator::CalculateDifference(&tokens_input, &tokens_output);
5011cb0ef41Sopenharmony_ci    } else {
5021cb0ef41Sopenharmony_ci      output_->emplace_back(SourceChangeRange{
5031cb0ef41Sopenharmony_ci          char_pos1, char_pos1 + char_len1, char_pos2, char_pos2 + char_len2});
5041cb0ef41Sopenharmony_ci    }
5051cb0ef41Sopenharmony_ci  }
5061cb0ef41Sopenharmony_ci  void SetSubrange1(int offset, int len) override {
5071cb0ef41Sopenharmony_ci    subrange_offset1_ = offset;
5081cb0ef41Sopenharmony_ci  }
5091cb0ef41Sopenharmony_ci  void SetSubrange2(int offset, int len) override {
5101cb0ef41Sopenharmony_ci    subrange_offset2_ = offset;
5111cb0ef41Sopenharmony_ci  }
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_ci private:
5141cb0ef41Sopenharmony_ci  static const int CHUNK_LEN_LIMIT = 800;
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci  Isolate* isolate_;
5171cb0ef41Sopenharmony_ci  LineEndsWrapper line_ends1_;
5181cb0ef41Sopenharmony_ci  LineEndsWrapper line_ends2_;
5191cb0ef41Sopenharmony_ci  Handle<String> s1_;
5201cb0ef41Sopenharmony_ci  Handle<String> s2_;
5211cb0ef41Sopenharmony_ci  int subrange_offset1_;
5221cb0ef41Sopenharmony_ci  int subrange_offset2_;
5231cb0ef41Sopenharmony_ci  std::vector<SourceChangeRange>* output_;
5241cb0ef41Sopenharmony_ci};
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_cistruct SourcePositionEvent {
5271cb0ef41Sopenharmony_ci  enum Type { LITERAL_STARTS, LITERAL_ENDS, DIFF_STARTS, DIFF_ENDS };
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ci  int position;
5301cb0ef41Sopenharmony_ci  Type type;
5311cb0ef41Sopenharmony_ci
5321cb0ef41Sopenharmony_ci  union {
5331cb0ef41Sopenharmony_ci    FunctionLiteral* literal;
5341cb0ef41Sopenharmony_ci    int pos_diff;
5351cb0ef41Sopenharmony_ci  };
5361cb0ef41Sopenharmony_ci
5371cb0ef41Sopenharmony_ci  SourcePositionEvent(FunctionLiteral* literal, bool is_start)
5381cb0ef41Sopenharmony_ci      : position(is_start ? literal->start_position()
5391cb0ef41Sopenharmony_ci                          : literal->end_position()),
5401cb0ef41Sopenharmony_ci        type(is_start ? LITERAL_STARTS : LITERAL_ENDS),
5411cb0ef41Sopenharmony_ci        literal(literal) {}
5421cb0ef41Sopenharmony_ci  SourcePositionEvent(const SourceChangeRange& change, bool is_start)
5431cb0ef41Sopenharmony_ci      : position(is_start ? change.start_position : change.end_position),
5441cb0ef41Sopenharmony_ci        type(is_start ? DIFF_STARTS : DIFF_ENDS),
5451cb0ef41Sopenharmony_ci        pos_diff((change.new_end_position - change.new_start_position) -
5461cb0ef41Sopenharmony_ci                 (change.end_position - change.start_position)) {}
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_ci  static bool LessThan(const SourcePositionEvent& a,
5491cb0ef41Sopenharmony_ci                       const SourcePositionEvent& b) {
5501cb0ef41Sopenharmony_ci    if (a.position != b.position) return a.position < b.position;
5511cb0ef41Sopenharmony_ci    if (a.type != b.type) return a.type < b.type;
5521cb0ef41Sopenharmony_ci    if (a.type == LITERAL_STARTS && b.type == LITERAL_STARTS) {
5531cb0ef41Sopenharmony_ci      // If the literals start in the same position, we want the one with the
5541cb0ef41Sopenharmony_ci      // furthest (i.e. largest) end position to be first.
5551cb0ef41Sopenharmony_ci      if (a.literal->end_position() != b.literal->end_position()) {
5561cb0ef41Sopenharmony_ci        return a.literal->end_position() > b.literal->end_position();
5571cb0ef41Sopenharmony_ci      }
5581cb0ef41Sopenharmony_ci      // If they also end in the same position, we want the first in order of
5591cb0ef41Sopenharmony_ci      // literal ids to be first.
5601cb0ef41Sopenharmony_ci      return a.literal->function_literal_id() <
5611cb0ef41Sopenharmony_ci             b.literal->function_literal_id();
5621cb0ef41Sopenharmony_ci    } else if (a.type == LITERAL_ENDS && b.type == LITERAL_ENDS) {
5631cb0ef41Sopenharmony_ci      // If the literals end in the same position, we want the one with the
5641cb0ef41Sopenharmony_ci      // nearest (i.e. largest) start position to be first.
5651cb0ef41Sopenharmony_ci      if (a.literal->start_position() != b.literal->start_position()) {
5661cb0ef41Sopenharmony_ci        return a.literal->start_position() > b.literal->start_position();
5671cb0ef41Sopenharmony_ci      }
5681cb0ef41Sopenharmony_ci      // If they also end in the same position, we want the last in order of
5691cb0ef41Sopenharmony_ci      // literal ids to be first.
5701cb0ef41Sopenharmony_ci      return a.literal->function_literal_id() >
5711cb0ef41Sopenharmony_ci             b.literal->function_literal_id();
5721cb0ef41Sopenharmony_ci    } else {
5731cb0ef41Sopenharmony_ci      return a.pos_diff < b.pos_diff;
5741cb0ef41Sopenharmony_ci    }
5751cb0ef41Sopenharmony_ci  }
5761cb0ef41Sopenharmony_ci};
5771cb0ef41Sopenharmony_ci
5781cb0ef41Sopenharmony_cistruct FunctionLiteralChange {
5791cb0ef41Sopenharmony_ci  // If any of start/end position is kNoSourcePosition, this literal is
5801cb0ef41Sopenharmony_ci  // considered damaged and will not be mapped and edited at all.
5811cb0ef41Sopenharmony_ci  int new_start_position;
5821cb0ef41Sopenharmony_ci  int new_end_position;
5831cb0ef41Sopenharmony_ci  bool has_changes;
5841cb0ef41Sopenharmony_ci  FunctionLiteral* outer_literal;
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci  explicit FunctionLiteralChange(int new_start_position, FunctionLiteral* outer)
5871cb0ef41Sopenharmony_ci      : new_start_position(new_start_position),
5881cb0ef41Sopenharmony_ci        new_end_position(kNoSourcePosition),
5891cb0ef41Sopenharmony_ci        has_changes(false),
5901cb0ef41Sopenharmony_ci        outer_literal(outer) {}
5911cb0ef41Sopenharmony_ci};
5921cb0ef41Sopenharmony_ci
5931cb0ef41Sopenharmony_ciusing FunctionLiteralChanges =
5941cb0ef41Sopenharmony_ci    std::unordered_map<FunctionLiteral*, FunctionLiteralChange>;
5951cb0ef41Sopenharmony_civoid CalculateFunctionLiteralChanges(
5961cb0ef41Sopenharmony_ci    const std::vector<FunctionLiteral*>& literals,
5971cb0ef41Sopenharmony_ci    const std::vector<SourceChangeRange>& diffs,
5981cb0ef41Sopenharmony_ci    FunctionLiteralChanges* result) {
5991cb0ef41Sopenharmony_ci  std::vector<SourcePositionEvent> events;
6001cb0ef41Sopenharmony_ci  events.reserve(literals.size() * 2 + diffs.size() * 2);
6011cb0ef41Sopenharmony_ci  for (FunctionLiteral* literal : literals) {
6021cb0ef41Sopenharmony_ci    events.emplace_back(literal, true);
6031cb0ef41Sopenharmony_ci    events.emplace_back(literal, false);
6041cb0ef41Sopenharmony_ci  }
6051cb0ef41Sopenharmony_ci  for (const SourceChangeRange& diff : diffs) {
6061cb0ef41Sopenharmony_ci    events.emplace_back(diff, true);
6071cb0ef41Sopenharmony_ci    events.emplace_back(diff, false);
6081cb0ef41Sopenharmony_ci  }
6091cb0ef41Sopenharmony_ci  std::sort(events.begin(), events.end(), SourcePositionEvent::LessThan);
6101cb0ef41Sopenharmony_ci  bool inside_diff = false;
6111cb0ef41Sopenharmony_ci  int delta = 0;
6121cb0ef41Sopenharmony_ci  std::stack<std::pair<FunctionLiteral*, FunctionLiteralChange>> literal_stack;
6131cb0ef41Sopenharmony_ci  for (const SourcePositionEvent& event : events) {
6141cb0ef41Sopenharmony_ci    switch (event.type) {
6151cb0ef41Sopenharmony_ci      case SourcePositionEvent::DIFF_ENDS:
6161cb0ef41Sopenharmony_ci        DCHECK(inside_diff);
6171cb0ef41Sopenharmony_ci        inside_diff = false;
6181cb0ef41Sopenharmony_ci        delta += event.pos_diff;
6191cb0ef41Sopenharmony_ci        break;
6201cb0ef41Sopenharmony_ci      case SourcePositionEvent::LITERAL_ENDS: {
6211cb0ef41Sopenharmony_ci        DCHECK_EQ(literal_stack.top().first, event.literal);
6221cb0ef41Sopenharmony_ci        FunctionLiteralChange& change = literal_stack.top().second;
6231cb0ef41Sopenharmony_ci        change.new_end_position = inside_diff
6241cb0ef41Sopenharmony_ci                                      ? kNoSourcePosition
6251cb0ef41Sopenharmony_ci                                      : event.literal->end_position() + delta;
6261cb0ef41Sopenharmony_ci        result->insert(literal_stack.top());
6271cb0ef41Sopenharmony_ci        literal_stack.pop();
6281cb0ef41Sopenharmony_ci        break;
6291cb0ef41Sopenharmony_ci      }
6301cb0ef41Sopenharmony_ci      case SourcePositionEvent::LITERAL_STARTS:
6311cb0ef41Sopenharmony_ci        literal_stack.push(std::make_pair(
6321cb0ef41Sopenharmony_ci            event.literal,
6331cb0ef41Sopenharmony_ci            FunctionLiteralChange(
6341cb0ef41Sopenharmony_ci                inside_diff ? kNoSourcePosition
6351cb0ef41Sopenharmony_ci                            : event.literal->start_position() + delta,
6361cb0ef41Sopenharmony_ci                literal_stack.empty() ? nullptr : literal_stack.top().first)));
6371cb0ef41Sopenharmony_ci        break;
6381cb0ef41Sopenharmony_ci      case SourcePositionEvent::DIFF_STARTS:
6391cb0ef41Sopenharmony_ci        DCHECK(!inside_diff);
6401cb0ef41Sopenharmony_ci        inside_diff = true;
6411cb0ef41Sopenharmony_ci        if (!literal_stack.empty()) {
6421cb0ef41Sopenharmony_ci          // Note that outer literal has not necessarily changed, unless the
6431cb0ef41Sopenharmony_ci          // diff goes past the end of this literal. In this case, we'll mark
6441cb0ef41Sopenharmony_ci          // this function as damaged and parent as changed later in
6451cb0ef41Sopenharmony_ci          // MapLiterals.
6461cb0ef41Sopenharmony_ci          literal_stack.top().second.has_changes = true;
6471cb0ef41Sopenharmony_ci        }
6481cb0ef41Sopenharmony_ci        break;
6491cb0ef41Sopenharmony_ci    }
6501cb0ef41Sopenharmony_ci  }
6511cb0ef41Sopenharmony_ci}
6521cb0ef41Sopenharmony_ci
6531cb0ef41Sopenharmony_ci// Function which has not changed itself, but if any variable in its
6541cb0ef41Sopenharmony_ci// outer context has been added/removed, we must consider this function
6551cb0ef41Sopenharmony_ci// as damaged and not update references to it.
6561cb0ef41Sopenharmony_ci// This is because old compiled function has hardcoded references to
6571cb0ef41Sopenharmony_ci// it's outer context.
6581cb0ef41Sopenharmony_cibool HasChangedScope(FunctionLiteral* a, FunctionLiteral* b) {
6591cb0ef41Sopenharmony_ci  Scope* scope_a = a->scope()->outer_scope();
6601cb0ef41Sopenharmony_ci  Scope* scope_b = b->scope()->outer_scope();
6611cb0ef41Sopenharmony_ci  while (scope_a && scope_b) {
6621cb0ef41Sopenharmony_ci    std::unordered_map<int, Handle<String>> vars;
6631cb0ef41Sopenharmony_ci    for (Variable* var : *scope_a->locals()) {
6641cb0ef41Sopenharmony_ci      if (!var->IsContextSlot()) continue;
6651cb0ef41Sopenharmony_ci      vars[var->index()] = var->name();
6661cb0ef41Sopenharmony_ci    }
6671cb0ef41Sopenharmony_ci    for (Variable* var : *scope_b->locals()) {
6681cb0ef41Sopenharmony_ci      if (!var->IsContextSlot()) continue;
6691cb0ef41Sopenharmony_ci      auto it = vars.find(var->index());
6701cb0ef41Sopenharmony_ci      if (it == vars.end()) return true;
6711cb0ef41Sopenharmony_ci      if (*it->second != *var->name()) return true;
6721cb0ef41Sopenharmony_ci    }
6731cb0ef41Sopenharmony_ci    scope_a = scope_a->outer_scope();
6741cb0ef41Sopenharmony_ci    scope_b = scope_b->outer_scope();
6751cb0ef41Sopenharmony_ci  }
6761cb0ef41Sopenharmony_ci  return scope_a != scope_b;
6771cb0ef41Sopenharmony_ci}
6781cb0ef41Sopenharmony_ci
6791cb0ef41Sopenharmony_cienum ChangeState { UNCHANGED, CHANGED, DAMAGED };
6801cb0ef41Sopenharmony_ci
6811cb0ef41Sopenharmony_ciusing LiteralMap = std::unordered_map<FunctionLiteral*, FunctionLiteral*>;
6821cb0ef41Sopenharmony_civoid MapLiterals(const FunctionLiteralChanges& changes,
6831cb0ef41Sopenharmony_ci                 const std::vector<FunctionLiteral*>& new_literals,
6841cb0ef41Sopenharmony_ci                 LiteralMap* unchanged, LiteralMap* changed) {
6851cb0ef41Sopenharmony_ci  // Track the top-level script function separately as it can overlap fully with
6861cb0ef41Sopenharmony_ci  // another function, e.g. the script "()=>42".
6871cb0ef41Sopenharmony_ci  const std::pair<int, int> kTopLevelMarker = std::make_pair(-1, -1);
6881cb0ef41Sopenharmony_ci  std::map<std::pair<int, int>, FunctionLiteral*> position_to_new_literal;
6891cb0ef41Sopenharmony_ci  for (FunctionLiteral* literal : new_literals) {
6901cb0ef41Sopenharmony_ci    DCHECK(literal->start_position() != kNoSourcePosition);
6911cb0ef41Sopenharmony_ci    DCHECK(literal->end_position() != kNoSourcePosition);
6921cb0ef41Sopenharmony_ci    std::pair<int, int> key =
6931cb0ef41Sopenharmony_ci        literal->function_literal_id() == kFunctionLiteralIdTopLevel
6941cb0ef41Sopenharmony_ci            ? kTopLevelMarker
6951cb0ef41Sopenharmony_ci            : std::make_pair(literal->start_position(),
6961cb0ef41Sopenharmony_ci                             literal->end_position());
6971cb0ef41Sopenharmony_ci    // Make sure there are no duplicate keys.
6981cb0ef41Sopenharmony_ci    DCHECK_EQ(position_to_new_literal.find(key), position_to_new_literal.end());
6991cb0ef41Sopenharmony_ci    position_to_new_literal[key] = literal;
7001cb0ef41Sopenharmony_ci  }
7011cb0ef41Sopenharmony_ci  LiteralMap mappings;
7021cb0ef41Sopenharmony_ci  std::unordered_map<FunctionLiteral*, ChangeState> change_state;
7031cb0ef41Sopenharmony_ci  for (const auto& change_pair : changes) {
7041cb0ef41Sopenharmony_ci    FunctionLiteral* literal = change_pair.first;
7051cb0ef41Sopenharmony_ci    const FunctionLiteralChange& change = change_pair.second;
7061cb0ef41Sopenharmony_ci    std::pair<int, int> key =
7071cb0ef41Sopenharmony_ci        literal->function_literal_id() == kFunctionLiteralIdTopLevel
7081cb0ef41Sopenharmony_ci            ? kTopLevelMarker
7091cb0ef41Sopenharmony_ci            : std::make_pair(change.new_start_position,
7101cb0ef41Sopenharmony_ci                             change.new_end_position);
7111cb0ef41Sopenharmony_ci    auto it = position_to_new_literal.find(key);
7121cb0ef41Sopenharmony_ci    if (it == position_to_new_literal.end() ||
7131cb0ef41Sopenharmony_ci        HasChangedScope(literal, it->second)) {
7141cb0ef41Sopenharmony_ci      change_state[literal] = ChangeState::DAMAGED;
7151cb0ef41Sopenharmony_ci      if (!change.outer_literal) continue;
7161cb0ef41Sopenharmony_ci      if (change_state[change.outer_literal] != ChangeState::DAMAGED) {
7171cb0ef41Sopenharmony_ci        change_state[change.outer_literal] = ChangeState::CHANGED;
7181cb0ef41Sopenharmony_ci      }
7191cb0ef41Sopenharmony_ci    } else {
7201cb0ef41Sopenharmony_ci      mappings[literal] = it->second;
7211cb0ef41Sopenharmony_ci      if (change_state.find(literal) == change_state.end()) {
7221cb0ef41Sopenharmony_ci        change_state[literal] =
7231cb0ef41Sopenharmony_ci            change.has_changes ? ChangeState::CHANGED : ChangeState::UNCHANGED;
7241cb0ef41Sopenharmony_ci      }
7251cb0ef41Sopenharmony_ci    }
7261cb0ef41Sopenharmony_ci  }
7271cb0ef41Sopenharmony_ci  for (const auto& mapping : mappings) {
7281cb0ef41Sopenharmony_ci    if (change_state[mapping.first] == ChangeState::UNCHANGED) {
7291cb0ef41Sopenharmony_ci      (*unchanged)[mapping.first] = mapping.second;
7301cb0ef41Sopenharmony_ci    } else if (change_state[mapping.first] == ChangeState::CHANGED) {
7311cb0ef41Sopenharmony_ci      (*changed)[mapping.first] = mapping.second;
7321cb0ef41Sopenharmony_ci    }
7331cb0ef41Sopenharmony_ci  }
7341cb0ef41Sopenharmony_ci}
7351cb0ef41Sopenharmony_ci
7361cb0ef41Sopenharmony_ciclass CollectFunctionLiterals final
7371cb0ef41Sopenharmony_ci    : public AstTraversalVisitor<CollectFunctionLiterals> {
7381cb0ef41Sopenharmony_ci public:
7391cb0ef41Sopenharmony_ci  CollectFunctionLiterals(Isolate* isolate, AstNode* root)
7401cb0ef41Sopenharmony_ci      : AstTraversalVisitor<CollectFunctionLiterals>(isolate, root) {}
7411cb0ef41Sopenharmony_ci  void VisitFunctionLiteral(FunctionLiteral* lit) {
7421cb0ef41Sopenharmony_ci    AstTraversalVisitor::VisitFunctionLiteral(lit);
7431cb0ef41Sopenharmony_ci    literals_->push_back(lit);
7441cb0ef41Sopenharmony_ci  }
7451cb0ef41Sopenharmony_ci  void Run(std::vector<FunctionLiteral*>* literals) {
7461cb0ef41Sopenharmony_ci    literals_ = literals;
7471cb0ef41Sopenharmony_ci    AstTraversalVisitor::Run();
7481cb0ef41Sopenharmony_ci    literals_ = nullptr;
7491cb0ef41Sopenharmony_ci  }
7501cb0ef41Sopenharmony_ci
7511cb0ef41Sopenharmony_ci private:
7521cb0ef41Sopenharmony_ci  std::vector<FunctionLiteral*>* literals_;
7531cb0ef41Sopenharmony_ci};
7541cb0ef41Sopenharmony_ci
7551cb0ef41Sopenharmony_cibool ParseScript(Isolate* isolate, Handle<Script> script, ParseInfo* parse_info,
7561cb0ef41Sopenharmony_ci                 bool compile_as_well, std::vector<FunctionLiteral*>* literals,
7571cb0ef41Sopenharmony_ci                 debug::LiveEditResult* result) {
7581cb0ef41Sopenharmony_ci  v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
7591cb0ef41Sopenharmony_ci  Handle<SharedFunctionInfo> shared;
7601cb0ef41Sopenharmony_ci  bool success = false;
7611cb0ef41Sopenharmony_ci  if (compile_as_well) {
7621cb0ef41Sopenharmony_ci    success = Compiler::CompileForLiveEdit(parse_info, script, isolate)
7631cb0ef41Sopenharmony_ci                  .ToHandle(&shared);
7641cb0ef41Sopenharmony_ci  } else {
7651cb0ef41Sopenharmony_ci    success = parsing::ParseProgram(parse_info, script, isolate,
7661cb0ef41Sopenharmony_ci                                    parsing::ReportStatisticsMode::kYes);
7671cb0ef41Sopenharmony_ci    if (!success) {
7681cb0ef41Sopenharmony_ci      // Throw the parser error.
7691cb0ef41Sopenharmony_ci      parse_info->pending_error_handler()->PrepareErrors(
7701cb0ef41Sopenharmony_ci          isolate, parse_info->ast_value_factory());
7711cb0ef41Sopenharmony_ci      parse_info->pending_error_handler()->ReportErrors(isolate, script);
7721cb0ef41Sopenharmony_ci    }
7731cb0ef41Sopenharmony_ci  }
7741cb0ef41Sopenharmony_ci  if (!success) {
7751cb0ef41Sopenharmony_ci    isolate->OptionalRescheduleException(false);
7761cb0ef41Sopenharmony_ci    DCHECK(try_catch.HasCaught());
7771cb0ef41Sopenharmony_ci    result->message = try_catch.Message()->Get();
7781cb0ef41Sopenharmony_ci    auto self = Utils::OpenHandle(*try_catch.Message());
7791cb0ef41Sopenharmony_ci    auto msg = i::Handle<i::JSMessageObject>::cast(self);
7801cb0ef41Sopenharmony_ci    result->line_number = msg->GetLineNumber();
7811cb0ef41Sopenharmony_ci    result->column_number = msg->GetColumnNumber();
7821cb0ef41Sopenharmony_ci    result->status = debug::LiveEditResult::COMPILE_ERROR;
7831cb0ef41Sopenharmony_ci    return false;
7841cb0ef41Sopenharmony_ci  }
7851cb0ef41Sopenharmony_ci  CollectFunctionLiterals(isolate, parse_info->literal()).Run(literals);
7861cb0ef41Sopenharmony_ci  return true;
7871cb0ef41Sopenharmony_ci}
7881cb0ef41Sopenharmony_ci
7891cb0ef41Sopenharmony_cistruct FunctionData {
7901cb0ef41Sopenharmony_ci  explicit FunctionData(FunctionLiteral* literal)
7911cb0ef41Sopenharmony_ci      : literal(literal), stack_position(NOT_ON_STACK) {}
7921cb0ef41Sopenharmony_ci
7931cb0ef41Sopenharmony_ci  FunctionLiteral* literal;
7941cb0ef41Sopenharmony_ci  MaybeHandle<SharedFunctionInfo> shared;
7951cb0ef41Sopenharmony_ci  std::vector<Handle<JSFunction>> js_functions;
7961cb0ef41Sopenharmony_ci  std::vector<Handle<JSGeneratorObject>> running_generators;
7971cb0ef41Sopenharmony_ci  // In case of multiple functions with different stack position, the latest
7981cb0ef41Sopenharmony_ci  // one (in the order below) is used, since it is the most restrictive.
7991cb0ef41Sopenharmony_ci  // This is important only for functions to be restarted.
8001cb0ef41Sopenharmony_ci  enum StackPosition { NOT_ON_STACK, ON_STACK };
8011cb0ef41Sopenharmony_ci  StackPosition stack_position;
8021cb0ef41Sopenharmony_ci};
8031cb0ef41Sopenharmony_ci
8041cb0ef41Sopenharmony_ciclass FunctionDataMap : public ThreadVisitor {
8051cb0ef41Sopenharmony_ci public:
8061cb0ef41Sopenharmony_ci  void AddInterestingLiteral(int script_id, FunctionLiteral* literal) {
8071cb0ef41Sopenharmony_ci    map_.emplace(GetFuncId(script_id, literal), FunctionData{literal});
8081cb0ef41Sopenharmony_ci  }
8091cb0ef41Sopenharmony_ci
8101cb0ef41Sopenharmony_ci  bool Lookup(SharedFunctionInfo sfi, FunctionData** data) {
8111cb0ef41Sopenharmony_ci    int start_position = sfi.StartPosition();
8121cb0ef41Sopenharmony_ci    if (!sfi.script().IsScript() || start_position == -1) {
8131cb0ef41Sopenharmony_ci      return false;
8141cb0ef41Sopenharmony_ci    }
8151cb0ef41Sopenharmony_ci    Script script = Script::cast(sfi.script());
8161cb0ef41Sopenharmony_ci    return Lookup(GetFuncId(script.id(), sfi), data);
8171cb0ef41Sopenharmony_ci  }
8181cb0ef41Sopenharmony_ci
8191cb0ef41Sopenharmony_ci  bool Lookup(Handle<Script> script, FunctionLiteral* literal,
8201cb0ef41Sopenharmony_ci              FunctionData** data) {
8211cb0ef41Sopenharmony_ci    return Lookup(GetFuncId(script->id(), literal), data);
8221cb0ef41Sopenharmony_ci  }
8231cb0ef41Sopenharmony_ci
8241cb0ef41Sopenharmony_ci  void Fill(Isolate* isolate) {
8251cb0ef41Sopenharmony_ci    {
8261cb0ef41Sopenharmony_ci      HeapObjectIterator iterator(isolate->heap(),
8271cb0ef41Sopenharmony_ci                                  HeapObjectIterator::kFilterUnreachable);
8281cb0ef41Sopenharmony_ci      for (HeapObject obj = iterator.Next(); !obj.is_null();
8291cb0ef41Sopenharmony_ci           obj = iterator.Next()) {
8301cb0ef41Sopenharmony_ci        if (obj.IsSharedFunctionInfo()) {
8311cb0ef41Sopenharmony_ci          SharedFunctionInfo sfi = SharedFunctionInfo::cast(obj);
8321cb0ef41Sopenharmony_ci          FunctionData* data = nullptr;
8331cb0ef41Sopenharmony_ci          if (!Lookup(sfi, &data)) continue;
8341cb0ef41Sopenharmony_ci          data->shared = handle(sfi, isolate);
8351cb0ef41Sopenharmony_ci        } else if (obj.IsJSFunction()) {
8361cb0ef41Sopenharmony_ci          JSFunction js_function = JSFunction::cast(obj);
8371cb0ef41Sopenharmony_ci          SharedFunctionInfo sfi = js_function.shared();
8381cb0ef41Sopenharmony_ci          FunctionData* data = nullptr;
8391cb0ef41Sopenharmony_ci          if (!Lookup(sfi, &data)) continue;
8401cb0ef41Sopenharmony_ci          data->js_functions.emplace_back(js_function, isolate);
8411cb0ef41Sopenharmony_ci        } else if (obj.IsJSGeneratorObject()) {
8421cb0ef41Sopenharmony_ci          JSGeneratorObject gen = JSGeneratorObject::cast(obj);
8431cb0ef41Sopenharmony_ci          if (gen.is_closed()) continue;
8441cb0ef41Sopenharmony_ci          SharedFunctionInfo sfi = gen.function().shared();
8451cb0ef41Sopenharmony_ci          FunctionData* data = nullptr;
8461cb0ef41Sopenharmony_ci          if (!Lookup(sfi, &data)) continue;
8471cb0ef41Sopenharmony_ci          data->running_generators.emplace_back(gen, isolate);
8481cb0ef41Sopenharmony_ci        }
8491cb0ef41Sopenharmony_ci      }
8501cb0ef41Sopenharmony_ci    }
8511cb0ef41Sopenharmony_ci
8521cb0ef41Sopenharmony_ci    // Visit the current thread stack.
8531cb0ef41Sopenharmony_ci    VisitThread(isolate, isolate->thread_local_top());
8541cb0ef41Sopenharmony_ci
8551cb0ef41Sopenharmony_ci    // Visit the stacks of all archived threads.
8561cb0ef41Sopenharmony_ci    isolate->thread_manager()->IterateArchivedThreads(this);
8571cb0ef41Sopenharmony_ci  }
8581cb0ef41Sopenharmony_ci
8591cb0ef41Sopenharmony_ci private:
8601cb0ef41Sopenharmony_ci  // Unique id for a function: script_id + start_position, where start_position
8611cb0ef41Sopenharmony_ci  // is special cased to -1 for top-level so that it does not overlap with a
8621cb0ef41Sopenharmony_ci  // function whose start position is 0.
8631cb0ef41Sopenharmony_ci  using FuncId = std::pair<int, int>;
8641cb0ef41Sopenharmony_ci
8651cb0ef41Sopenharmony_ci  FuncId GetFuncId(int script_id, FunctionLiteral* literal) {
8661cb0ef41Sopenharmony_ci    int start_position = literal->start_position();
8671cb0ef41Sopenharmony_ci    if (literal->function_literal_id() == 0) {
8681cb0ef41Sopenharmony_ci      // This is the top-level script function literal, so special case its
8691cb0ef41Sopenharmony_ci      // start position
8701cb0ef41Sopenharmony_ci      DCHECK_EQ(start_position, 0);
8711cb0ef41Sopenharmony_ci      start_position = -1;
8721cb0ef41Sopenharmony_ci    }
8731cb0ef41Sopenharmony_ci    return FuncId(script_id, start_position);
8741cb0ef41Sopenharmony_ci  }
8751cb0ef41Sopenharmony_ci
8761cb0ef41Sopenharmony_ci  FuncId GetFuncId(int script_id, SharedFunctionInfo sfi) {
8771cb0ef41Sopenharmony_ci    DCHECK_EQ(script_id, Script::cast(sfi.script()).id());
8781cb0ef41Sopenharmony_ci    int start_position = sfi.StartPosition();
8791cb0ef41Sopenharmony_ci    DCHECK_NE(start_position, -1);
8801cb0ef41Sopenharmony_ci    if (sfi.is_toplevel()) {
8811cb0ef41Sopenharmony_ci      // This is the top-level function, so special case its start position
8821cb0ef41Sopenharmony_ci      DCHECK_EQ(start_position, 0);
8831cb0ef41Sopenharmony_ci      start_position = -1;
8841cb0ef41Sopenharmony_ci    }
8851cb0ef41Sopenharmony_ci    return FuncId(script_id, start_position);
8861cb0ef41Sopenharmony_ci  }
8871cb0ef41Sopenharmony_ci
8881cb0ef41Sopenharmony_ci  bool Lookup(FuncId id, FunctionData** data) {
8891cb0ef41Sopenharmony_ci    auto it = map_.find(id);
8901cb0ef41Sopenharmony_ci    if (it == map_.end()) return false;
8911cb0ef41Sopenharmony_ci    *data = &it->second;
8921cb0ef41Sopenharmony_ci    return true;
8931cb0ef41Sopenharmony_ci  }
8941cb0ef41Sopenharmony_ci
8951cb0ef41Sopenharmony_ci  void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
8961cb0ef41Sopenharmony_ci    for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8971cb0ef41Sopenharmony_ci      std::vector<Handle<SharedFunctionInfo>> sfis;
8981cb0ef41Sopenharmony_ci      it.frame()->GetFunctions(&sfis);
8991cb0ef41Sopenharmony_ci      for (auto& sfi : sfis) {
9001cb0ef41Sopenharmony_ci        FunctionData* data = nullptr;
9011cb0ef41Sopenharmony_ci        if (!Lookup(*sfi, &data)) continue;
9021cb0ef41Sopenharmony_ci        data->stack_position = FunctionData::ON_STACK;
9031cb0ef41Sopenharmony_ci      }
9041cb0ef41Sopenharmony_ci    }
9051cb0ef41Sopenharmony_ci  }
9061cb0ef41Sopenharmony_ci
9071cb0ef41Sopenharmony_ci  std::map<FuncId, FunctionData> map_;
9081cb0ef41Sopenharmony_ci};
9091cb0ef41Sopenharmony_ci
9101cb0ef41Sopenharmony_cibool CanPatchScript(const LiteralMap& changed, Handle<Script> script,
9111cb0ef41Sopenharmony_ci                    Handle<Script> new_script,
9121cb0ef41Sopenharmony_ci                    FunctionDataMap& function_data_map,
9131cb0ef41Sopenharmony_ci                    debug::LiveEditResult* result) {
9141cb0ef41Sopenharmony_ci  for (const auto& mapping : changed) {
9151cb0ef41Sopenharmony_ci    FunctionData* data = nullptr;
9161cb0ef41Sopenharmony_ci    function_data_map.Lookup(script, mapping.first, &data);
9171cb0ef41Sopenharmony_ci    FunctionData* new_data = nullptr;
9181cb0ef41Sopenharmony_ci    function_data_map.Lookup(new_script, mapping.second, &new_data);
9191cb0ef41Sopenharmony_ci    Handle<SharedFunctionInfo> sfi;
9201cb0ef41Sopenharmony_ci    if (!data->shared.ToHandle(&sfi)) {
9211cb0ef41Sopenharmony_ci      continue;
9221cb0ef41Sopenharmony_ci    } else if (data->stack_position == FunctionData::ON_STACK) {
9231cb0ef41Sopenharmony_ci      result->status = debug::LiveEditResult::BLOCKED_BY_ACTIVE_FUNCTION;
9241cb0ef41Sopenharmony_ci      return false;
9251cb0ef41Sopenharmony_ci    } else if (!data->running_generators.empty()) {
9261cb0ef41Sopenharmony_ci      result->status = debug::LiveEditResult::BLOCKED_BY_RUNNING_GENERATOR;
9271cb0ef41Sopenharmony_ci      return false;
9281cb0ef41Sopenharmony_ci    }
9291cb0ef41Sopenharmony_ci  }
9301cb0ef41Sopenharmony_ci  return true;
9311cb0ef41Sopenharmony_ci}
9321cb0ef41Sopenharmony_ci
9331cb0ef41Sopenharmony_civoid TranslateSourcePositionTable(Isolate* isolate, Handle<BytecodeArray> code,
9341cb0ef41Sopenharmony_ci                                  const std::vector<SourceChangeRange>& diffs) {
9351cb0ef41Sopenharmony_ci  Zone zone(isolate->allocator(), ZONE_NAME);
9361cb0ef41Sopenharmony_ci  SourcePositionTableBuilder builder(&zone);
9371cb0ef41Sopenharmony_ci
9381cb0ef41Sopenharmony_ci  Handle<ByteArray> source_position_table(code->SourcePositionTable(), isolate);
9391cb0ef41Sopenharmony_ci  for (SourcePositionTableIterator iterator(*source_position_table);
9401cb0ef41Sopenharmony_ci       !iterator.done(); iterator.Advance()) {
9411cb0ef41Sopenharmony_ci    SourcePosition position = iterator.source_position();
9421cb0ef41Sopenharmony_ci    position.SetScriptOffset(
9431cb0ef41Sopenharmony_ci        LiveEdit::TranslatePosition(diffs, position.ScriptOffset()));
9441cb0ef41Sopenharmony_ci    builder.AddPosition(iterator.code_offset(), position,
9451cb0ef41Sopenharmony_ci                        iterator.is_statement());
9461cb0ef41Sopenharmony_ci  }
9471cb0ef41Sopenharmony_ci
9481cb0ef41Sopenharmony_ci  Handle<ByteArray> new_source_position_table(
9491cb0ef41Sopenharmony_ci      builder.ToSourcePositionTable(isolate));
9501cb0ef41Sopenharmony_ci  code->set_source_position_table(*new_source_position_table, kReleaseStore);
9511cb0ef41Sopenharmony_ci  LOG_CODE_EVENT(isolate,
9521cb0ef41Sopenharmony_ci                 CodeLinePosInfoRecordEvent(code->GetFirstBytecodeAddress(),
9531cb0ef41Sopenharmony_ci                                            *new_source_position_table,
9541cb0ef41Sopenharmony_ci                                            JitCodeEvent::BYTE_CODE));
9551cb0ef41Sopenharmony_ci}
9561cb0ef41Sopenharmony_ci
9571cb0ef41Sopenharmony_civoid UpdatePositions(Isolate* isolate, Handle<SharedFunctionInfo> sfi,
9581cb0ef41Sopenharmony_ci                     const std::vector<SourceChangeRange>& diffs) {
9591cb0ef41Sopenharmony_ci  int old_start_position = sfi->StartPosition();
9601cb0ef41Sopenharmony_ci  int new_start_position =
9611cb0ef41Sopenharmony_ci      LiveEdit::TranslatePosition(diffs, old_start_position);
9621cb0ef41Sopenharmony_ci  int new_end_position = LiveEdit::TranslatePosition(diffs, sfi->EndPosition());
9631cb0ef41Sopenharmony_ci  int new_function_token_position =
9641cb0ef41Sopenharmony_ci      LiveEdit::TranslatePosition(diffs, sfi->function_token_position());
9651cb0ef41Sopenharmony_ci  sfi->SetPosition(new_start_position, new_end_position);
9661cb0ef41Sopenharmony_ci  sfi->SetFunctionTokenPosition(new_function_token_position,
9671cb0ef41Sopenharmony_ci                                new_start_position);
9681cb0ef41Sopenharmony_ci  if (sfi->HasBytecodeArray()) {
9691cb0ef41Sopenharmony_ci    TranslateSourcePositionTable(
9701cb0ef41Sopenharmony_ci        isolate, handle(sfi->GetBytecodeArray(isolate), isolate), diffs);
9711cb0ef41Sopenharmony_ci  }
9721cb0ef41Sopenharmony_ci}
9731cb0ef41Sopenharmony_ci}  // anonymous namespace
9741cb0ef41Sopenharmony_ci
9751cb0ef41Sopenharmony_civoid LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
9761cb0ef41Sopenharmony_ci                           Handle<String> new_source, bool preview,
9771cb0ef41Sopenharmony_ci                           debug::LiveEditResult* result) {
9781cb0ef41Sopenharmony_ci  std::vector<SourceChangeRange> diffs;
9791cb0ef41Sopenharmony_ci  LiveEdit::CompareStrings(isolate,
9801cb0ef41Sopenharmony_ci                           handle(String::cast(script->source()), isolate),
9811cb0ef41Sopenharmony_ci                           new_source, &diffs);
9821cb0ef41Sopenharmony_ci  if (diffs.empty()) {
9831cb0ef41Sopenharmony_ci    result->status = debug::LiveEditResult::OK;
9841cb0ef41Sopenharmony_ci    return;
9851cb0ef41Sopenharmony_ci  }
9861cb0ef41Sopenharmony_ci
9871cb0ef41Sopenharmony_ci  ReusableUnoptimizedCompileState reusable_state(isolate);
9881cb0ef41Sopenharmony_ci
9891cb0ef41Sopenharmony_ci  UnoptimizedCompileState compile_state;
9901cb0ef41Sopenharmony_ci  UnoptimizedCompileFlags flags =
9911cb0ef41Sopenharmony_ci      UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
9921cb0ef41Sopenharmony_ci  flags.set_is_eager(true);
9931cb0ef41Sopenharmony_ci  ParseInfo parse_info(isolate, flags, &compile_state, &reusable_state);
9941cb0ef41Sopenharmony_ci  std::vector<FunctionLiteral*> literals;
9951cb0ef41Sopenharmony_ci  if (!ParseScript(isolate, script, &parse_info, false, &literals, result))
9961cb0ef41Sopenharmony_ci    return;
9971cb0ef41Sopenharmony_ci
9981cb0ef41Sopenharmony_ci  Handle<Script> new_script = isolate->factory()->CloneScript(script);
9991cb0ef41Sopenharmony_ci  new_script->set_source(*new_source);
10001cb0ef41Sopenharmony_ci  UnoptimizedCompileState new_compile_state;
10011cb0ef41Sopenharmony_ci  UnoptimizedCompileFlags new_flags =
10021cb0ef41Sopenharmony_ci      UnoptimizedCompileFlags::ForScriptCompile(isolate, *new_script);
10031cb0ef41Sopenharmony_ci  new_flags.set_is_eager(true);
10041cb0ef41Sopenharmony_ci  ParseInfo new_parse_info(isolate, new_flags, &new_compile_state,
10051cb0ef41Sopenharmony_ci                           &reusable_state);
10061cb0ef41Sopenharmony_ci  std::vector<FunctionLiteral*> new_literals;
10071cb0ef41Sopenharmony_ci  if (!ParseScript(isolate, new_script, &new_parse_info, true, &new_literals,
10081cb0ef41Sopenharmony_ci                   result)) {
10091cb0ef41Sopenharmony_ci    return;
10101cb0ef41Sopenharmony_ci  }
10111cb0ef41Sopenharmony_ci
10121cb0ef41Sopenharmony_ci  FunctionLiteralChanges literal_changes;
10131cb0ef41Sopenharmony_ci  CalculateFunctionLiteralChanges(literals, diffs, &literal_changes);
10141cb0ef41Sopenharmony_ci
10151cb0ef41Sopenharmony_ci  LiteralMap changed;
10161cb0ef41Sopenharmony_ci  LiteralMap unchanged;
10171cb0ef41Sopenharmony_ci  MapLiterals(literal_changes, new_literals, &unchanged, &changed);
10181cb0ef41Sopenharmony_ci
10191cb0ef41Sopenharmony_ci  FunctionDataMap function_data_map;
10201cb0ef41Sopenharmony_ci  for (const auto& mapping : changed) {
10211cb0ef41Sopenharmony_ci    function_data_map.AddInterestingLiteral(script->id(), mapping.first);
10221cb0ef41Sopenharmony_ci    function_data_map.AddInterestingLiteral(new_script->id(), mapping.second);
10231cb0ef41Sopenharmony_ci  }
10241cb0ef41Sopenharmony_ci  for (const auto& mapping : unchanged) {
10251cb0ef41Sopenharmony_ci    function_data_map.AddInterestingLiteral(script->id(), mapping.first);
10261cb0ef41Sopenharmony_ci  }
10271cb0ef41Sopenharmony_ci  function_data_map.Fill(isolate);
10281cb0ef41Sopenharmony_ci
10291cb0ef41Sopenharmony_ci  if (!CanPatchScript(changed, script, new_script, function_data_map, result)) {
10301cb0ef41Sopenharmony_ci    return;
10311cb0ef41Sopenharmony_ci  }
10321cb0ef41Sopenharmony_ci
10331cb0ef41Sopenharmony_ci  if (preview) {
10341cb0ef41Sopenharmony_ci    result->status = debug::LiveEditResult::OK;
10351cb0ef41Sopenharmony_ci    return;
10361cb0ef41Sopenharmony_ci  }
10371cb0ef41Sopenharmony_ci
10381cb0ef41Sopenharmony_ci  // Patching a script means that the bytecode on the stack may no longer
10391cb0ef41Sopenharmony_ci  // correspond to the bytecode of the JSFunction for that frame. As a result
10401cb0ef41Sopenharmony_ci  // it is no longer safe to flush bytecode since we might flush the new
10411cb0ef41Sopenharmony_ci  // bytecode for a JSFunction that is on the stack with an old bytecode, which
10421cb0ef41Sopenharmony_ci  // breaks the invariant that any JSFunction active on the stack is compiled.
10431cb0ef41Sopenharmony_ci  isolate->set_disable_bytecode_flushing(true);
10441cb0ef41Sopenharmony_ci
10451cb0ef41Sopenharmony_ci  std::map<int, int> start_position_to_unchanged_id;
10461cb0ef41Sopenharmony_ci  for (const auto& mapping : unchanged) {
10471cb0ef41Sopenharmony_ci    FunctionData* data = nullptr;
10481cb0ef41Sopenharmony_ci    if (!function_data_map.Lookup(script, mapping.first, &data)) continue;
10491cb0ef41Sopenharmony_ci    Handle<SharedFunctionInfo> sfi;
10501cb0ef41Sopenharmony_ci    if (!data->shared.ToHandle(&sfi)) continue;
10511cb0ef41Sopenharmony_ci    DCHECK_EQ(sfi->script(), *script);
10521cb0ef41Sopenharmony_ci
10531cb0ef41Sopenharmony_ci    isolate->compilation_cache()->Remove(sfi);
10541cb0ef41Sopenharmony_ci    isolate->debug()->DeoptimizeFunction(sfi);
10551cb0ef41Sopenharmony_ci    if (sfi->HasDebugInfo()) {
10561cb0ef41Sopenharmony_ci      Handle<DebugInfo> debug_info(sfi->GetDebugInfo(), isolate);
10571cb0ef41Sopenharmony_ci      isolate->debug()->RemoveBreakInfoAndMaybeFree(debug_info);
10581cb0ef41Sopenharmony_ci    }
10591cb0ef41Sopenharmony_ci    SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, sfi);
10601cb0ef41Sopenharmony_ci    UpdatePositions(isolate, sfi, diffs);
10611cb0ef41Sopenharmony_ci
10621cb0ef41Sopenharmony_ci    sfi->set_script(*new_script);
10631cb0ef41Sopenharmony_ci    sfi->set_function_literal_id(mapping.second->function_literal_id());
10641cb0ef41Sopenharmony_ci    new_script->shared_function_infos().Set(
10651cb0ef41Sopenharmony_ci        mapping.second->function_literal_id(), HeapObjectReference::Weak(*sfi));
10661cb0ef41Sopenharmony_ci    DCHECK_EQ(sfi->function_literal_id(),
10671cb0ef41Sopenharmony_ci              mapping.second->function_literal_id());
10681cb0ef41Sopenharmony_ci
10691cb0ef41Sopenharmony_ci    // Save the new start_position -> id mapping, so that we can recover it when
10701cb0ef41Sopenharmony_ci    // iterating over changed functions' constant pools.
10711cb0ef41Sopenharmony_ci    start_position_to_unchanged_id[mapping.second->start_position()] =
10721cb0ef41Sopenharmony_ci        mapping.second->function_literal_id();
10731cb0ef41Sopenharmony_ci
10741cb0ef41Sopenharmony_ci    if (sfi->HasUncompiledDataWithPreparseData()) {
10751cb0ef41Sopenharmony_ci      sfi->ClearPreparseData();
10761cb0ef41Sopenharmony_ci    }
10771cb0ef41Sopenharmony_ci
10781cb0ef41Sopenharmony_ci    for (auto& js_function : data->js_functions) {
10791cb0ef41Sopenharmony_ci      js_function->set_raw_feedback_cell(
10801cb0ef41Sopenharmony_ci          *isolate->factory()->many_closures_cell());
10811cb0ef41Sopenharmony_ci      if (!js_function->is_compiled()) continue;
10821cb0ef41Sopenharmony_ci      IsCompiledScope is_compiled_scope(
10831cb0ef41Sopenharmony_ci          js_function->shared().is_compiled_scope(isolate));
10841cb0ef41Sopenharmony_ci      JSFunction::EnsureFeedbackVector(isolate, js_function,
10851cb0ef41Sopenharmony_ci                                       &is_compiled_scope);
10861cb0ef41Sopenharmony_ci    }
10871cb0ef41Sopenharmony_ci
10881cb0ef41Sopenharmony_ci    if (!sfi->HasBytecodeArray()) continue;
10891cb0ef41Sopenharmony_ci    FixedArray constants = sfi->GetBytecodeArray(isolate).constant_pool();
10901cb0ef41Sopenharmony_ci    for (int i = 0; i < constants.length(); ++i) {
10911cb0ef41Sopenharmony_ci      if (!constants.get(i).IsSharedFunctionInfo()) continue;
10921cb0ef41Sopenharmony_ci      data = nullptr;
10931cb0ef41Sopenharmony_ci      if (!function_data_map.Lookup(SharedFunctionInfo::cast(constants.get(i)),
10941cb0ef41Sopenharmony_ci                                    &data)) {
10951cb0ef41Sopenharmony_ci        continue;
10961cb0ef41Sopenharmony_ci      }
10971cb0ef41Sopenharmony_ci      auto change_it = changed.find(data->literal);
10981cb0ef41Sopenharmony_ci      if (change_it == changed.end()) continue;
10991cb0ef41Sopenharmony_ci      if (!function_data_map.Lookup(new_script, change_it->second, &data)) {
11001cb0ef41Sopenharmony_ci        continue;
11011cb0ef41Sopenharmony_ci      }
11021cb0ef41Sopenharmony_ci      Handle<SharedFunctionInfo> new_sfi;
11031cb0ef41Sopenharmony_ci      if (!data->shared.ToHandle(&new_sfi)) continue;
11041cb0ef41Sopenharmony_ci      constants.set(i, *new_sfi);
11051cb0ef41Sopenharmony_ci    }
11061cb0ef41Sopenharmony_ci  }
11071cb0ef41Sopenharmony_ci  for (const auto& mapping : changed) {
11081cb0ef41Sopenharmony_ci    FunctionData* data = nullptr;
11091cb0ef41Sopenharmony_ci    if (!function_data_map.Lookup(new_script, mapping.second, &data)) continue;
11101cb0ef41Sopenharmony_ci    Handle<SharedFunctionInfo> new_sfi = data->shared.ToHandleChecked();
11111cb0ef41Sopenharmony_ci    DCHECK_EQ(new_sfi->script(), *new_script);
11121cb0ef41Sopenharmony_ci
11131cb0ef41Sopenharmony_ci    if (!function_data_map.Lookup(script, mapping.first, &data)) continue;
11141cb0ef41Sopenharmony_ci    Handle<SharedFunctionInfo> sfi;
11151cb0ef41Sopenharmony_ci    if (!data->shared.ToHandle(&sfi)) continue;
11161cb0ef41Sopenharmony_ci
11171cb0ef41Sopenharmony_ci    isolate->debug()->DeoptimizeFunction(sfi);
11181cb0ef41Sopenharmony_ci    isolate->compilation_cache()->Remove(sfi);
11191cb0ef41Sopenharmony_ci    for (auto& js_function : data->js_functions) {
11201cb0ef41Sopenharmony_ci      js_function->set_shared(*new_sfi);
11211cb0ef41Sopenharmony_ci      js_function->set_code(js_function->shared().GetCode(), kReleaseStore);
11221cb0ef41Sopenharmony_ci
11231cb0ef41Sopenharmony_ci      js_function->set_raw_feedback_cell(
11241cb0ef41Sopenharmony_ci          *isolate->factory()->many_closures_cell());
11251cb0ef41Sopenharmony_ci      if (!js_function->is_compiled()) continue;
11261cb0ef41Sopenharmony_ci      IsCompiledScope is_compiled_scope(
11271cb0ef41Sopenharmony_ci          js_function->shared().is_compiled_scope(isolate));
11281cb0ef41Sopenharmony_ci      JSFunction::EnsureFeedbackVector(isolate, js_function,
11291cb0ef41Sopenharmony_ci                                       &is_compiled_scope);
11301cb0ef41Sopenharmony_ci    }
11311cb0ef41Sopenharmony_ci  }
11321cb0ef41Sopenharmony_ci  SharedFunctionInfo::ScriptIterator it(isolate, *new_script);
11331cb0ef41Sopenharmony_ci  for (SharedFunctionInfo sfi = it.Next(); !sfi.is_null(); sfi = it.Next()) {
11341cb0ef41Sopenharmony_ci    if (!sfi.HasBytecodeArray()) continue;
11351cb0ef41Sopenharmony_ci    FixedArray constants = sfi.GetBytecodeArray(isolate).constant_pool();
11361cb0ef41Sopenharmony_ci    for (int i = 0; i < constants.length(); ++i) {
11371cb0ef41Sopenharmony_ci      if (!constants.get(i).IsSharedFunctionInfo()) continue;
11381cb0ef41Sopenharmony_ci      SharedFunctionInfo inner_sfi = SharedFunctionInfo::cast(constants.get(i));
11391cb0ef41Sopenharmony_ci      // See if there is a mapping from this function's start position to a
11401cb0ef41Sopenharmony_ci      // unchanged function's id.
11411cb0ef41Sopenharmony_ci      auto unchanged_it =
11421cb0ef41Sopenharmony_ci          start_position_to_unchanged_id.find(inner_sfi.StartPosition());
11431cb0ef41Sopenharmony_ci      if (unchanged_it == start_position_to_unchanged_id.end()) continue;
11441cb0ef41Sopenharmony_ci
11451cb0ef41Sopenharmony_ci      // Grab that function id from the new script's SFI list, which should have
11461cb0ef41Sopenharmony_ci      // already been updated in in the unchanged pass.
11471cb0ef41Sopenharmony_ci      SharedFunctionInfo old_unchanged_inner_sfi =
11481cb0ef41Sopenharmony_ci          SharedFunctionInfo::cast(new_script->shared_function_infos()
11491cb0ef41Sopenharmony_ci                                       .Get(unchanged_it->second)
11501cb0ef41Sopenharmony_ci                                       ->GetHeapObject());
11511cb0ef41Sopenharmony_ci      if (old_unchanged_inner_sfi == inner_sfi) continue;
11521cb0ef41Sopenharmony_ci      DCHECK_NE(old_unchanged_inner_sfi, inner_sfi);
11531cb0ef41Sopenharmony_ci      // Now some sanity checks. Make sure that the unchanged SFI has already
11541cb0ef41Sopenharmony_ci      // been processed and patched to be on the new script ...
11551cb0ef41Sopenharmony_ci      DCHECK_EQ(old_unchanged_inner_sfi.script(), *new_script);
11561cb0ef41Sopenharmony_ci      constants.set(i, old_unchanged_inner_sfi);
11571cb0ef41Sopenharmony_ci    }
11581cb0ef41Sopenharmony_ci  }
11591cb0ef41Sopenharmony_ci#ifdef DEBUG
11601cb0ef41Sopenharmony_ci  {
11611cb0ef41Sopenharmony_ci    // Check that all the functions in the new script are valid, that their
11621cb0ef41Sopenharmony_ci    // function literals match what is expected, and that start positions are
11631cb0ef41Sopenharmony_ci    // unique.
11641cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
11651cb0ef41Sopenharmony_ci
11661cb0ef41Sopenharmony_ci    SharedFunctionInfo::ScriptIterator script_it(isolate, *new_script);
11671cb0ef41Sopenharmony_ci    std::set<int> start_positions;
11681cb0ef41Sopenharmony_ci    for (SharedFunctionInfo sfi = script_it.Next(); !sfi.is_null();
11691cb0ef41Sopenharmony_ci         sfi = script_it.Next()) {
11701cb0ef41Sopenharmony_ci      DCHECK_EQ(sfi.script(), *new_script);
11711cb0ef41Sopenharmony_ci      DCHECK_EQ(sfi.function_literal_id(), script_it.CurrentIndex());
11721cb0ef41Sopenharmony_ci      // Don't check the start position of the top-level function, as it can
11731cb0ef41Sopenharmony_ci      // overlap with a function in the script.
11741cb0ef41Sopenharmony_ci      if (sfi.is_toplevel()) {
11751cb0ef41Sopenharmony_ci        DCHECK_EQ(start_positions.find(sfi.StartPosition()),
11761cb0ef41Sopenharmony_ci                  start_positions.end());
11771cb0ef41Sopenharmony_ci        start_positions.insert(sfi.StartPosition());
11781cb0ef41Sopenharmony_ci      }
11791cb0ef41Sopenharmony_ci
11801cb0ef41Sopenharmony_ci      if (!sfi.HasBytecodeArray()) continue;
11811cb0ef41Sopenharmony_ci      // Check that all the functions in this function's constant pool are also
11821cb0ef41Sopenharmony_ci      // on the new script, and that their id matches their index in the new
11831cb0ef41Sopenharmony_ci      // scripts function list.
11841cb0ef41Sopenharmony_ci      FixedArray constants = sfi.GetBytecodeArray(isolate).constant_pool();
11851cb0ef41Sopenharmony_ci      for (int i = 0; i < constants.length(); ++i) {
11861cb0ef41Sopenharmony_ci        if (!constants.get(i).IsSharedFunctionInfo()) continue;
11871cb0ef41Sopenharmony_ci        SharedFunctionInfo inner_sfi =
11881cb0ef41Sopenharmony_ci            SharedFunctionInfo::cast(constants.get(i));
11891cb0ef41Sopenharmony_ci        DCHECK_EQ(inner_sfi.script(), *new_script);
11901cb0ef41Sopenharmony_ci        DCHECK_EQ(inner_sfi, new_script->shared_function_infos()
11911cb0ef41Sopenharmony_ci                                 .Get(inner_sfi.function_literal_id())
11921cb0ef41Sopenharmony_ci                                 ->GetHeapObject());
11931cb0ef41Sopenharmony_ci      }
11941cb0ef41Sopenharmony_ci    }
11951cb0ef41Sopenharmony_ci  }
11961cb0ef41Sopenharmony_ci#endif
11971cb0ef41Sopenharmony_ci
11981cb0ef41Sopenharmony_ci  int script_id = script->id();
11991cb0ef41Sopenharmony_ci  script->set_id(new_script->id());
12001cb0ef41Sopenharmony_ci  new_script->set_id(script_id);
12011cb0ef41Sopenharmony_ci  result->status = debug::LiveEditResult::OK;
12021cb0ef41Sopenharmony_ci  result->script = ToApiHandle<v8::debug::Script>(new_script);
12031cb0ef41Sopenharmony_ci}
12041cb0ef41Sopenharmony_ci
12051cb0ef41Sopenharmony_civoid LiveEdit::CompareStrings(Isolate* isolate, Handle<String> s1,
12061cb0ef41Sopenharmony_ci                              Handle<String> s2,
12071cb0ef41Sopenharmony_ci                              std::vector<SourceChangeRange>* diffs) {
12081cb0ef41Sopenharmony_ci  s1 = String::Flatten(isolate, s1);
12091cb0ef41Sopenharmony_ci  s2 = String::Flatten(isolate, s2);
12101cb0ef41Sopenharmony_ci
12111cb0ef41Sopenharmony_ci  LineEndsWrapper line_ends1(isolate, s1);
12121cb0ef41Sopenharmony_ci  LineEndsWrapper line_ends2(isolate, s2);
12131cb0ef41Sopenharmony_ci
12141cb0ef41Sopenharmony_ci  LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
12151cb0ef41Sopenharmony_ci  TokenizingLineArrayCompareOutput output(isolate, line_ends1, line_ends2, s1,
12161cb0ef41Sopenharmony_ci                                          s2, diffs);
12171cb0ef41Sopenharmony_ci
12181cb0ef41Sopenharmony_ci  NarrowDownInput(&input, &output);
12191cb0ef41Sopenharmony_ci
12201cb0ef41Sopenharmony_ci  Comparator::CalculateDifference(&input, &output);
12211cb0ef41Sopenharmony_ci}
12221cb0ef41Sopenharmony_ci
12231cb0ef41Sopenharmony_ciint LiveEdit::TranslatePosition(const std::vector<SourceChangeRange>& diffs,
12241cb0ef41Sopenharmony_ci                                int position) {
12251cb0ef41Sopenharmony_ci  auto it = std::lower_bound(diffs.begin(), diffs.end(), position,
12261cb0ef41Sopenharmony_ci                             [](const SourceChangeRange& change, int position) {
12271cb0ef41Sopenharmony_ci                               return change.end_position < position;
12281cb0ef41Sopenharmony_ci                             });
12291cb0ef41Sopenharmony_ci  if (it != diffs.end() && position == it->end_position) {
12301cb0ef41Sopenharmony_ci    return it->new_end_position;
12311cb0ef41Sopenharmony_ci  }
12321cb0ef41Sopenharmony_ci  if (it == diffs.begin()) return position;
12331cb0ef41Sopenharmony_ci  DCHECK(it == diffs.end() || position <= it->start_position);
12341cb0ef41Sopenharmony_ci  it = std::prev(it);
12351cb0ef41Sopenharmony_ci  return position + (it->new_end_position - it->end_position);
12361cb0ef41Sopenharmony_ci}
12371cb0ef41Sopenharmony_ci}  // namespace internal
12381cb0ef41Sopenharmony_ci}  // namespace v8
1239