Commit e8c5a51c authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[liveedit] Fix patching functions with start position zero

For a script '()=>42', the anonymous arrow function has both start and
end position the same as the script function itself. This causes issues
when sorting the SourcePositionEvents of the function, in two ways:

  * If the start positions are the same, we should order by *furthest*
    end position to ensure the stack is in the right order
  * If both start and end are the same, we need to order by function
    literal id to make sure that start order and end order are inversed.

Also, MapLiterals assumes that start+end position uniquely identifies a
function, which is false in this case, so we process the top-level
script function separately in MapLiterals.

Change-Id: I2b2185dc2825018b7ea44c7d0918238e9b1dd972
Reviewed-on: https://chromium-review.googlesource.com/1141741
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarAleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54525}
parent 0c540335
......@@ -542,9 +542,25 @@ struct SourcePositionEvent {
if (a.position != b.position) return a.position < b.position;
if (a.type != b.type) return a.type < b.type;
if (a.type == LITERAL_STARTS && b.type == LITERAL_STARTS) {
return a.literal->end_position() < b.literal->end_position();
// If the literals start in the same position, we want the one with the
// furthest (i.e. largest) end position to be first.
if (a.literal->end_position() != b.literal->end_position()) {
return a.literal->end_position() > b.literal->end_position();
}
// If they also end in the same position, we want the first in order of
// literal ids to be first.
return a.literal->function_literal_id() <
b.literal->function_literal_id();
} else if (a.type == LITERAL_ENDS && b.type == LITERAL_ENDS) {
return a.literal->start_position() > b.literal->start_position();
// If the literals end in the same position, we want the one with the
// nearest (i.e. largest) start position to be first.
if (a.literal->start_position() != b.literal->start_position()) {
return a.literal->start_position() > b.literal->start_position();
}
// If they also end in the same position, we want the last in order of
// literal ids to be first.
return a.literal->function_literal_id() >
b.literal->function_literal_id();
} else {
return a.pos_diff < b.pos_diff;
}
......@@ -658,20 +674,33 @@ using LiteralMap = std::unordered_map<FunctionLiteral*, FunctionLiteral*>;
void MapLiterals(const FunctionLiteralChanges& changes,
const std::vector<FunctionLiteral*>& new_literals,
LiteralMap* unchanged, LiteralMap* changed) {
// Track the top-level script function separately as it can overlap fully with
// another function, e.g. the script "()=>42".
const std::pair<int, int> kTopLevelMarker = std::make_pair(-1, -1);
std::map<std::pair<int, int>, FunctionLiteral*> position_to_new_literal;
for (FunctionLiteral* literal : new_literals) {
DCHECK(literal->start_position() != kNoSourcePosition);
DCHECK(literal->end_position() != kNoSourcePosition);
position_to_new_literal[std::make_pair(literal->start_position(),
literal->end_position())] = literal;
std::pair<int, int> key =
literal->function_literal_id() == FunctionLiteral::kIdTypeTopLevel
? kTopLevelMarker
: std::make_pair(literal->start_position(),
literal->end_position());
// Make sure there are no duplicate keys.
DCHECK_EQ(position_to_new_literal.find(key), position_to_new_literal.end());
position_to_new_literal[key] = literal;
}
LiteralMap mappings;
std::unordered_map<FunctionLiteral*, ChangeState> change_state;
for (const auto& change_pair : changes) {
FunctionLiteral* literal = change_pair.first;
const FunctionLiteralChange& change = change_pair.second;
auto it = position_to_new_literal.find(
std::make_pair(change.new_start_position, change.new_end_position));
std::pair<int, int> key =
literal->function_literal_id() == FunctionLiteral::kIdTypeTopLevel
? kTopLevelMarker
: std::make_pair(change.new_start_position,
change.new_end_position);
auto it = position_to_new_literal.find(key);
if (it == position_to_new_literal.end() ||
HasChangedScope(literal, it->second)) {
change_state[literal] = ChangeState::DAMAGED;
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
// ()=>42 will have the same start and end position as the top-level script.
var foo = eval("()=>{ return 42 }");
assertEquals(42, foo());
%LiveEditPatchScript(foo, "()=>{ return 13 }");
assertEquals(13, foo());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment