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