summaryrefslogtreecommitdiff
path: root/deps/v8/src/liveedit-debugger.js
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2010-05-06 09:59:35 -0700
committerRyan Dahl <ry@tinyclouds.org>2010-05-06 09:59:35 -0700
commit6aab6ebe6168464de8e7b0c7254fad4771f281c1 (patch)
treeb0c6b91086cbf16147ba247ac6283652bfece086 /deps/v8/src/liveedit-debugger.js
parent4ce1e1fca59bc6ad6e2d19643db2ed3159ccb7dc (diff)
downloadnode-6aab6ebe6168464de8e7b0c7254fad4771f281c1.tar.gz
Upgrade V8 to 2.2.8
Diffstat (limited to 'deps/v8/src/liveedit-debugger.js')
-rw-r--r--deps/v8/src/liveedit-debugger.js640
1 files changed, 369 insertions, 271 deletions
diff --git a/deps/v8/src/liveedit-debugger.js b/deps/v8/src/liveedit-debugger.js
index 8fbff41b4..34d5c0da8 100644
--- a/deps/v8/src/liveedit-debugger.js
+++ b/deps/v8/src/liveedit-debugger.js
@@ -44,205 +44,47 @@
// LiveEdit namespace is declared inside a single function constructor.
Debug.LiveEdit = new function() {
- // Applies the change to the script.
- // The change is always a substring (change_pos, change_pos + change_len)
- // being replaced with a completely different string new_str.
- // This API is a legacy and is obsolete.
- //
- // @param {Script} script that is being changed
- // @param {Array} change_log a list that collects engineer-readable
- // description of what happened.
- function ApplyPatch(script, change_pos, change_len, new_str,
- change_log) {
- var old_source = script.source;
-
- // Prepare new source string.
- var new_source = old_source.substring(0, change_pos) +
- new_str + old_source.substring(change_pos + change_len);
-
- return ApplyPatchMultiChunk(script,
- [ change_pos, change_pos + change_len, change_pos + new_str.length],
- new_source, change_log);
- }
- // Function is public.
- this.ApplyPatch = ApplyPatch;
-
// Forward declaration for minifier.
var FunctionStatus;
+
// Applies the change to the script.
// The change is in form of list of chunks encoded in a single array as
// a series of triplets (pos1_start, pos1_end, pos2_end)
function ApplyPatchMultiChunk(script, diff_array, new_source, change_log) {
- // Fully compiles source string as a script. Returns Array of
- // FunctionCompileInfo -- a descriptions of all functions of the script.
- // Elements of array are ordered by start positions of functions (from top
- // to bottom) in the source. Fields outer_index and next_sibling_index help
- // to navigate the nesting structure of functions.
- //
- // The script is used for compilation, because it produces code that
- // needs to be linked with some particular script (for nested functions).
- function DebugGatherCompileInfo(source) {
- // Get function info, elements are partially sorted (it is a tree of
- // nested functions serialized as parent followed by serialized children.
- var raw_compile_info = %LiveEditGatherCompileInfo(script, source);
-
- // Sort function infos by start position field.
- var compile_info = new Array();
- var old_index_map = new Array();
- for (var i = 0; i < raw_compile_info.length; i++) {
- compile_info.push(new FunctionCompileInfo(raw_compile_info[i]));
- old_index_map.push(i);
- }
-
- for (var i = 0; i < compile_info.length; i++) {
- var k = i;
- for (var j = i + 1; j < compile_info.length; j++) {
- if (compile_info[k].start_position > compile_info[j].start_position) {
- k = j;
- }
- }
- if (k != i) {
- var temp_info = compile_info[k];
- var temp_index = old_index_map[k];
- compile_info[k] = compile_info[i];
- old_index_map[k] = old_index_map[i];
- compile_info[i] = temp_info;
- old_index_map[i] = temp_index;
- }
- }
-
- // After sorting update outer_inder field using old_index_map. Also
- // set next_sibling_index field.
- var current_index = 0;
-
- // The recursive function, that goes over all children of a particular
- // node (i.e. function info).
- function ResetIndexes(new_parent_index, old_parent_index) {
- var previous_sibling = -1;
- while (current_index < compile_info.length &&
- compile_info[current_index].outer_index == old_parent_index) {
- var saved_index = current_index;
- compile_info[saved_index].outer_index = new_parent_index;
- if (previous_sibling != -1) {
- compile_info[previous_sibling].next_sibling_index = saved_index;
- }
- previous_sibling = saved_index;
- current_index++;
- ResetIndexes(saved_index, old_index_map[saved_index]);
- }
- if (previous_sibling != -1) {
- compile_info[previous_sibling].next_sibling_index = -1;
- }
- }
-
- ResetIndexes(-1, -1);
- Assert(current_index == compile_info.length);
-
- return compile_info;
- }
-
- // Variable forward declarations. Preprocessor "Minifier" needs them.
- var old_compile_info;
- var shared_infos;
- // Finds SharedFunctionInfo that corresponds compile info with index
- // in old version of the script.
- function FindFunctionInfo(index) {
- var old_info = old_compile_info[index];
- for (var i = 0; i < shared_infos.length; i++) {
- var info = shared_infos[i];
- if (info.start_position == old_info.start_position &&
- info.end_position == old_info.end_position) {
- return info;
- }
- }
- }
-
- // Replaces function's Code.
- function PatchCode(new_info, shared_info) {
- if (shared_info) {
- %LiveEditReplaceFunctionCode(new_info.raw_array, shared_info.raw_array);
- change_log.push( {function_patched: new_info.function_name} );
- } else {
- change_log.push( {function_patched: new_info.function_name,
- function_info_not_found: true} );
- }
-
- }
-
-
- var position_patch_report;
- function PatchPositions(old_info, shared_info) {
- if (!shared_info) {
- // TODO(LiveEdit): function is not compiled yet or is already collected.
- position_patch_report.push(
- { name: old_info.function_name, info_not_found: true } );
- return;
- }
- var breakpoint_position_update = %LiveEditPatchFunctionPositions(
- shared_info.raw_array, diff_array);
- for (var i = 0; i < breakpoint_position_update.length; i += 2) {
- var new_pos = breakpoint_position_update[i];
- var break_point_object = breakpoint_position_update[i + 1];
- change_log.push( { breakpoint_position_update:
- { from: break_point_object.source_position(), to: new_pos } } );
- break_point_object.updateSourcePosition(new_pos, script);
- }
- position_patch_report.push( { name: old_info.function_name } );
- }
-
- var link_to_old_script_report;
- var old_script;
- // Makes a function associated with another instance of a script (the
- // one representing its old version). This way the function still
- // may access its own text.
- function LinkToOldScript(shared_info, old_info_node) {
- if (shared_info) {
- %LiveEditRelinkFunctionToScript(shared_info.raw_array, old_script);
- link_to_old_script_report.push( { name: shared_info.function_name } );
- } else {
- link_to_old_script_report.push(
- { name: old_info_node.info.function_name, not_found: true } );
- }
- }
-
-
var old_source = script.source;
-
- // Find all SharedFunctionInfo's that are compiled from this script.
- var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script);
-
- var shared_infos = new Array();
-
- for (var i = 0; i < shared_raw_list.length; i++) {
- shared_infos.push(new SharedInfoWrapper(shared_raw_list[i]));
- }
-
+
// Gather compile information about old version of script.
- var old_compile_info = DebugGatherCompileInfo(old_source);
+ var old_compile_info = GatherCompileInfo(old_source, script);
+ // Build tree structures for old and new versions of the script.
+ var root_old_node = BuildCodeInfoTree(old_compile_info);
+
+ var pos_translator = new PosTranslator(diff_array);
+
+ // Analyze changes.
+ MarkChangedFunctions(root_old_node, pos_translator.GetChunks());
+
+ // Find all SharedFunctionInfo's that were compiled from this script.
+ FindLiveSharedInfos(root_old_node, script);
+
// Gather compile information about new version of script.
var new_compile_info;
try {
- new_compile_info = DebugGatherCompileInfo(new_source);
+ new_compile_info = GatherCompileInfo(new_source, script);
} catch (e) {
throw new Failure("Failed to compile new version of script: " + e);
}
-
- var pos_translator = new PosTranslator(diff_array);
-
- // Build tree structures for old and new versions of the script.
- var root_old_node = BuildCodeInfoTree(old_compile_info);
var root_new_node = BuildCodeInfoTree(new_compile_info);
- // Analyze changes.
- MarkChangedFunctions(root_old_node, pos_translator.GetChunks());
+ // Link recompiled script data with other data.
FindCorrespondingFunctions(root_old_node, root_new_node);
// Prepare to-do lists.
var replace_code_list = new Array();
var link_to_old_script_list = new Array();
+ var link_to_original_script_list = new Array();
var update_positions_list = new Array();
function HarvestTodo(old_node) {
@@ -252,6 +94,15 @@ Debug.LiveEdit = new function() {
CollectDamaged(node.children[i]);
}
}
+
+ // Recursively collects all newly compiled functions that are going into
+ // business and should be have link to the actual script updated.
+ function CollectNew(node_list) {
+ for (var i = 0; i < node_list.length; i++) {
+ link_to_original_script_list.push(node_list[i]);
+ CollectNew(node_list[i].children);
+ }
+ }
if (old_node.status == FunctionStatus.DAMAGED) {
CollectDamaged(old_node);
@@ -263,6 +114,7 @@ Debug.LiveEdit = new function() {
update_positions_list.push(old_node);
} else if (old_node.status == FunctionStatus.CHANGED) {
replace_code_list.push(old_node);
+ CollectNew(old_node.unmatched_new_nodes);
}
for (var i = 0; i < old_node.children.length; i++) {
HarvestTodo(old_node.children[i]);
@@ -274,9 +126,9 @@ Debug.LiveEdit = new function() {
// Collect shared infos for functions whose code need to be patched.
var replaced_function_infos = new Array();
for (var i = 0; i < replace_code_list.length; i++) {
- var info = FindFunctionInfo(replace_code_list[i].array_index);
- if (info) {
- replaced_function_infos.push(info);
+ var info_wrapper = replace_code_list[i].live_shared_info_wrapper;
+ if (info_wrapper) {
+ replaced_function_infos.push(info_wrapper);
}
}
@@ -286,14 +138,24 @@ Debug.LiveEdit = new function() {
// We haven't changed anything before this line yet.
// Committing all changes.
+
+ // Start with breakpoints. Convert their line/column positions and
+ // temporary remove.
+ var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log);
+
+ var old_script;
- // Create old script if there are function linked to old version.
- if (link_to_old_script_list.length > 0) {
+ // Create an old script only if there are function that should be linked
+ // to old version.
+ if (link_to_old_script_list.length == 0) {
+ %LiveEditReplaceScript(script, new_source, null);
+ old_script = void 0;
+ } else {
var old_script_name = CreateNameForOldScript(script);
// Update the script text and create a new script representing an old
// version of the script.
- var old_script = %LiveEditReplaceScript(script, new_source,
+ old_script = %LiveEditReplaceScript(script, new_source,
old_script_name);
var link_to_old_script_report = new Array();
@@ -301,16 +163,19 @@ Debug.LiveEdit = new function() {
// We need to link to old script all former nested functions.
for (var i = 0; i < link_to_old_script_list.length; i++) {
- LinkToOldScript(
- FindFunctionInfo(link_to_old_script_list[i].array_index),
- link_to_old_script_list[i]);
+ LinkToOldScript(link_to_old_script_list[i], old_script,
+ link_to_old_script_report);
}
}
+ // Link to an actual script all the functions that we are going to use.
+ for (var i = 0; i < link_to_original_script_list.length; i++) {
+ %LiveEditFunctionSetScript(
+ link_to_original_script_list[i].info.shared_function_info, script);
+ }
for (var i = 0; i < replace_code_list.length; i++) {
- PatchCode(replace_code_list[i].corresponding_node.info,
- FindFunctionInfo(replace_code_list[i].array_index));
+ PatchFunctionCode(replace_code_list[i], change_log);
}
var position_patch_report = new Array();
@@ -319,14 +184,214 @@ Debug.LiveEdit = new function() {
for (var i = 0; i < update_positions_list.length; i++) {
// TODO(LiveEdit): take into account wether it's source_changed or
// unchanged and whether positions changed at all.
- PatchPositions(update_positions_list[i].info,
- FindFunctionInfo(update_positions_list[i].array_index));
+ PatchPositions(update_positions_list[i], diff_array,
+ position_patch_report);
}
+
+ break_points_restorer(pos_translator, old_script);
}
// Function is public.
this.ApplyPatchMultiChunk = ApplyPatchMultiChunk;
+ // Fully compiles source string as a script. Returns Array of
+ // FunctionCompileInfo -- a descriptions of all functions of the script.
+ // Elements of array are ordered by start positions of functions (from top
+ // to bottom) in the source. Fields outer_index and next_sibling_index help
+ // to navigate the nesting structure of functions.
+ //
+ // All functions get compiled linked to script provided as parameter script.
+ // TODO(LiveEdit): consider not using actual scripts as script, because
+ // we have to manually erase all links right after compile.
+ function GatherCompileInfo(source, script) {
+ // Get function info, elements are partially sorted (it is a tree of
+ // nested functions serialized as parent followed by serialized children.
+ var raw_compile_info = %LiveEditGatherCompileInfo(script, source);
+
+ // Sort function infos by start position field.
+ var compile_info = new Array();
+ var old_index_map = new Array();
+ for (var i = 0; i < raw_compile_info.length; i++) {
+ var info = new FunctionCompileInfo(raw_compile_info[i]);
+ // Remove all links to the actual script. Breakpoints system and
+ // LiveEdit itself believe that any function in heap that points to a
+ // particular script is a regular function.
+ // For some functions we will restore this link later.
+ %LiveEditFunctionSetScript(info.shared_function_info, void 0);
+ compile_info.push(info);
+ old_index_map.push(i);
+ }
+
+ for (var i = 0; i < compile_info.length; i++) {
+ var k = i;
+ for (var j = i + 1; j < compile_info.length; j++) {
+ if (compile_info[k].start_position > compile_info[j].start_position) {
+ k = j;
+ }
+ }
+ if (k != i) {
+ var temp_info = compile_info[k];
+ var temp_index = old_index_map[k];
+ compile_info[k] = compile_info[i];
+ old_index_map[k] = old_index_map[i];
+ compile_info[i] = temp_info;
+ old_index_map[i] = temp_index;
+ }
+ }
+
+ // After sorting update outer_inder field using old_index_map. Also
+ // set next_sibling_index field.
+ var current_index = 0;
+
+ // The recursive function, that goes over all children of a particular
+ // node (i.e. function info).
+ function ResetIndexes(new_parent_index, old_parent_index) {
+ var previous_sibling = -1;
+ while (current_index < compile_info.length &&
+ compile_info[current_index].outer_index == old_parent_index) {
+ var saved_index = current_index;
+ compile_info[saved_index].outer_index = new_parent_index;
+ if (previous_sibling != -1) {
+ compile_info[previous_sibling].next_sibling_index = saved_index;
+ }
+ previous_sibling = saved_index;
+ current_index++;
+ ResetIndexes(saved_index, old_index_map[saved_index]);
+ }
+ if (previous_sibling != -1) {
+ compile_info[previous_sibling].next_sibling_index = -1;
+ }
+ }
+
+ ResetIndexes(-1, -1);
+ Assert(current_index == compile_info.length);
+
+ return compile_info;
+ }
+
+
+ // Replaces function's Code.
+ function PatchFunctionCode(old_node, change_log) {
+ var new_info = old_node.corresponding_node.info;
+ var shared_info_wrapper = old_node.live_shared_info_wrapper;
+ if (shared_info_wrapper) {
+ %LiveEditReplaceFunctionCode(new_info.raw_array,
+ shared_info_wrapper.raw_array);
+
+ // The function got a new code. However, this new code brings all new
+ // instances of SharedFunctionInfo for nested functions. However,
+ // we want the original instances to be used wherever possible.
+ // (This is because old instances and new instances will be both
+ // linked to a script and breakpoints subsystem does not really
+ // expects this; neither does LiveEdit subsystem on next call).
+ for (var i = 0; i < old_node.children.length; i++) {
+ if (old_node.children[i].corresponding_node) {
+ var corresponding_child = old_node.children[i].corresponding_node;
+ var child_shared_info_wrapper =
+ old_node.children[i].live_shared_info_wrapper;
+ if (child_shared_info_wrapper) {
+ %LiveEditReplaceRefToNestedFunction(shared_info_wrapper.info,
+ corresponding_child.info.shared_function_info,
+ child_shared_info_wrapper.info);
+ }
+ }
+ }
+
+ change_log.push( {function_patched: new_info.function_name} );
+ } else {
+ change_log.push( {function_patched: new_info.function_name,
+ function_info_not_found: true} );
+ }
+ }
+
+
+ // Makes a function associated with another instance of a script (the
+ // one representing its old version). This way the function still
+ // may access its own text.
+ function LinkToOldScript(old_info_node, old_script, report_array) {
+ var shared_info = old_info_node.live_shared_info_wrapper;
+ if (shared_info) {
+ %LiveEditFunctionSetScript(shared_info.info, old_script);
+ report_array.push( { name: shared_info.function_name } );
+ } else {
+ report_array.push(
+ { name: old_info_node.info.function_name, not_found: true } );
+ }
+ }
+
+
+ // Returns function that restores breakpoints.
+ function TemporaryRemoveBreakPoints(original_script, change_log) {
+ var script_break_points = GetScriptBreakPoints(original_script);
+
+ var break_points_update_report = [];
+ change_log.push( { break_points_update: break_points_update_report } );
+
+ var break_point_old_positions = [];
+ for (var i = 0; i < script_break_points.length; i++) {
+ var break_point = script_break_points[i];
+
+ break_point.clear();
+
+ // TODO(LiveEdit): be careful with resource offset here.
+ var break_point_position = Debug.findScriptSourcePosition(original_script,
+ break_point.line(), break_point.column());
+
+ var old_position_description = {
+ position: break_point_position,
+ line: break_point.line(),
+ column: break_point.column()
+ }
+ break_point_old_positions.push(old_position_description);
+ }
+
+
+ // Restores breakpoints and creates their copies in the "old" copy of
+ // the script.
+ return function (pos_translator, old_script_copy_opt) {
+ // Update breakpoints (change positions and restore them in old version
+ // of script.
+ for (var i = 0; i < script_break_points.length; i++) {
+ var break_point = script_break_points[i];
+ if (old_script_copy_opt) {
+ var clone = break_point.cloneForOtherScript(old_script_copy_opt);
+ clone.set(old_script_copy_opt);
+
+ break_points_update_report.push( {
+ type: "copied_to_old",
+ id: break_point.number(),
+ new_id: clone.number(),
+ positions: break_point_old_positions[i]
+ } );
+ }
+
+ var updated_position = pos_translator.Translate(
+ break_point_old_positions[i].position,
+ PosTranslator.ShiftWithTopInsideChunkHandler);
+
+ var new_location =
+ original_script.locationFromPosition(updated_position, false);
+
+ break_point.update_positions(new_location.line, new_location.column);
+
+ var new_position_description = {
+ position: updated_position,
+ line: new_location.line,
+ column: new_location.column
+ }
+
+ break_point.set(original_script);
+
+ break_points_update_report.push( { type: "position_changed",
+ id: break_point.number(),
+ old_positions: break_point_old_positions[i],
+ new_positions: new_position_description
+ } );
+ }
+ }
+ }
+
+
function Assert(condition, message) {
if (!condition) {
if (message) {
@@ -346,15 +411,15 @@ Debug.LiveEdit = new function() {
function PosTranslator(diff_array) {
var chunks = new Array();
- var pos1 = 0;
- var pos2 = 0;
+ var current_diff = 0;
for (var i = 0; i < diff_array.length; i += 3) {
- pos2 += diff_array[i] - pos1 + pos2;
- pos1 = diff_array[i];
- chunks.push(new DiffChunk(pos1, pos2, diff_array[i + 1] - pos1,
- diff_array[i + 2] - pos2));
- pos1 = diff_array[i + 1];
- pos2 = diff_array[i + 2];
+ var pos1_begin = diff_array[i];
+ var pos2_begin = pos1_begin + current_diff;
+ var pos1_end = diff_array[i + 1];
+ var pos2_end = diff_array[i + 2];
+ chunks.push(new DiffChunk(pos1_begin, pos2_begin, pos1_end - pos1_begin,
+ pos2_end - pos2_begin));
+ current_diff = pos2_end - pos1_end;
}
this.chunks = chunks;
}
@@ -364,14 +429,14 @@ Debug.LiveEdit = new function() {
PosTranslator.prototype.Translate = function(pos, inside_chunk_handler) {
var array = this.chunks;
- if (array.length == 0 || pos < array[0]) {
+ if (array.length == 0 || pos < array[0].pos1) {
return pos;
}
var chunk_index1 = 0;
var chunk_index2 = array.length - 1;
while (chunk_index1 < chunk_index2) {
- var middle_index = (chunk_index1 + chunk_index2) / 2;
+ var middle_index = Math.floor((chunk_index1 + chunk_index2) / 2);
if (pos < array[middle_index + 1].pos1) {
chunk_index2 = middle_index;
} else {
@@ -380,17 +445,24 @@ Debug.LiveEdit = new function() {
}
var chunk = array[chunk_index1];
if (pos >= chunk.pos1 + chunk.len1) {
- return pos += chunk.pos2 + chunk.len2 - chunk.pos1 - chunk.len1;
+ return pos + chunk.pos2 + chunk.len2 - chunk.pos1 - chunk.len1;
}
if (!inside_chunk_handler) {
- inside_chunk_handler = PosTranslator.default_inside_chunk_handler;
+ inside_chunk_handler = PosTranslator.DefaultInsideChunkHandler;
}
- inside_chunk_handler(pos, chunk);
+ return inside_chunk_handler(pos, chunk);
}
- PosTranslator.default_inside_chunk_handler = function() {
- Assert(false, "Cannot translate position in chaged area");
+ PosTranslator.DefaultInsideChunkHandler = function(pos, diff_chunk) {
+ Assert(false, "Cannot translate position in changed area");
+ }
+
+ PosTranslator.ShiftWithTopInsideChunkHandler =
+ function(pos, diff_chunk) {
+ // We carelessly do not check whether we stay inside the chunk after
+ // translation.
+ return pos - diff_chunk.pos1 + diff_chunk.pos2;
}
var FunctionStatus = {
@@ -412,15 +484,17 @@ Debug.LiveEdit = new function() {
this.children = children;
// an index in array of compile_info
this.array_index = array_index;
- this.parent = void(0);
+ this.parent = void 0;
this.status = FunctionStatus.UNCHANGED;
// Status explanation is used for debugging purposes and will be shown
// in user UI if some explanations are needed.
- this.status_explanation = void(0);
- this.new_start_pos = void(0);
- this.new_end_pos = void(0);
- this.corresponding_node = void(0);
+ this.status_explanation = void 0;
+ this.new_start_pos = void 0;
+ this.new_end_pos = void 0;
+ this.corresponding_node = void 0;
+ this.unmatched_new_nodes = void 0;
+ this.live_shared_info_wrapper = void 0;
}
// From array of function infos that is implicitly a tree creates
@@ -564,6 +638,8 @@ Debug.LiveEdit = new function() {
function ProcessChildren(old_node, new_node) {
var old_children = old_node.children;
var new_children = new_node.children;
+
+ var unmatched_new_nodes_list = [];
var old_index = 0;
var new_index = 0;
@@ -573,6 +649,7 @@ Debug.LiveEdit = new function() {
} else if (new_index < new_children.length) {
if (new_children[new_index].info.start_position <
old_children[old_index].new_start_pos) {
+ unmatched_new_nodes_list.push(new_children[new_index]);
new_index++;
} else if (new_children[new_index].info.start_position ==
old_children[old_index].new_start_pos) {
@@ -584,6 +661,9 @@ Debug.LiveEdit = new function() {
ProcessChildren(old_children[old_index],
new_children[new_index]);
if (old_children[old_index].status == FunctionStatus.DAMAGED) {
+ unmatched_new_nodes_list.push(
+ old_children[old_index].corresponding_node);
+ old_children[old_index].corresponding_node = void 0;
old_node.status = FunctionStatus.CHANGED;
}
}
@@ -592,6 +672,7 @@ Debug.LiveEdit = new function() {
old_children[old_index].status_explanation =
"No corresponding function in new script found";
old_node.status = FunctionStatus.CHANGED;
+ unmatched_new_nodes_list.push(new_children[new_index]);
}
new_index++;
old_index++;
@@ -611,12 +692,18 @@ Debug.LiveEdit = new function() {
}
}
+ while (new_index < new_children.length) {
+ unmatched_new_nodes_list.push(new_children[new_index]);
+ new_index++;
+ }
+
if (old_node.status == FunctionStatus.CHANGED) {
if (!CompareFunctionExpectations(old_node.info, new_node.info)) {
old_node.status = FunctionStatus.DAMAGED;
old_node.status_explanation = "Changed code expectations";
}
}
+ old_node.unmatched_new_nodes = unmatched_new_nodes_list;
}
ProcessChildren(old_code_tree, new_code_tree);
@@ -625,6 +712,40 @@ Debug.LiveEdit = new function() {
Assert(old_code_tree.status != FunctionStatus.DAMAGED,
"Script became damaged");
}
+
+ function FindLiveSharedInfos(old_code_tree, script) {
+ var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script);
+
+ var shared_infos = new Array();
+
+ for (var i = 0; i < shared_raw_list.length; i++) {
+ shared_infos.push(new SharedInfoWrapper(shared_raw_list[i]));
+ }
+
+ // Finds SharedFunctionInfo that corresponds compile info with index
+ // in old version of the script.
+ function FindFunctionInfo(compile_info) {
+ for (var i = 0; i < shared_infos.length; i++) {
+ var wrapper = shared_infos[i];
+ if (wrapper.start_position == compile_info.start_position &&
+ wrapper.end_position == compile_info.end_position) {
+ return wrapper;
+ }
+ }
+ }
+
+ function TraverseTree(node) {
+ var info_wrapper = FindFunctionInfo(node.info);
+ if (info_wrapper) {
+ node.live_shared_info_wrapper = info_wrapper;
+ }
+ for (var i = 0; i < node.children.length; i++) {
+ TraverseTree(node.children[i]);
+ }
+ }
+
+ TraverseTree(old_code_tree);
+ }
// An object describing function compilation details. Its index fields
@@ -637,6 +758,7 @@ Debug.LiveEdit = new function() {
this.code = raw_array[4];
this.scope_info = raw_array[5];
this.outer_index = raw_array[6];
+ this.shared_function_info = raw_array[7];
this.next_sibling_index = null;
this.raw_array = raw_array;
}
@@ -648,7 +770,21 @@ Debug.LiveEdit = new function() {
this.info = raw_array[3];
this.raw_array = raw_array;
}
-
+
+ // Changes positions (including all statments) in function.
+ function PatchPositions(old_info_node, diff_array, report_array) {
+ var shared_info_wrapper = old_info_node.live_shared_info_wrapper;
+ if (!shared_info_wrapper) {
+ // TODO(LiveEdit): function is not compiled yet or is already collected.
+ report_array.push(
+ { name: old_info_node.info.function_name, info_not_found: true } );
+ return;
+ }
+ %LiveEditPatchFunctionPositions(shared_info_wrapper.raw_array,
+ diff_array);
+ report_array.push( { name: old_info_node.info.function_name } );
+ }
+
// Adds a suffix to script name to mark that it is old version.
function CreateNameForOldScript(script) {
// TODO(635): try better than this; support several changes.
@@ -776,71 +912,33 @@ Debug.LiveEdit = new function() {
function CompareStringsLinewise(s1, s2) {
return %LiveEditCompareStringsLinewise(s1, s2);
}
- // Function is public (for tests).
- this.CompareStringsLinewise = CompareStringsLinewise;
+ // Applies the change to the script.
+ // The change is always a substring (change_pos, change_pos + change_len)
+ // being replaced with a completely different string new_str.
+ // This API is a legacy and is obsolete.
+ //
+ // @param {Script} script that is being changed
+ // @param {Array} change_log a list that collects engineer-readable
+ // description of what happened.
+ function ApplySingleChunkPatch(script, change_pos, change_len, new_str,
+ change_log) {
+ var old_source = script.source;
- // Finds a difference between 2 strings in form of a single chunk.
- // This is a temporary solution. We should calculate a read diff instead.
- function FindSimpleDiff(old_source, new_source) {
- var change_pos;
- var old_len;
- var new_len;
+ // Prepare new source string.
+ var new_source = old_source.substring(0, change_pos) +
+ new_str + old_source.substring(change_pos + change_len);
- // A find range block. Whenever control leaves it, it should set 3 local
- // variables declared above.
- find_range:
- {
- // First look from the beginning of strings.
- var pos1;
- {
- var next_pos;
- for (pos1 = 0; true; pos1 = next_pos) {
- if (pos1 >= old_source.length) {
- change_pos = pos1;
- old_len = 0;
- new_len = new_source.length - pos1;
- break find_range;
- }
- if (pos1 >= new_source.length) {
- change_pos = pos1;
- old_len = old_source.length - pos1;
- new_len = 0;
- break find_range;
- }
- if (old_source[pos1] != new_source[pos1]) {
- break;
- }
- next_pos = pos1 + 1;
- }
- }
- // Now compare strings from the ends.
- change_pos = pos1;
- var pos_old;
- var pos_new;
- {
- for (pos_old = old_source.length - 1, pos_new = new_source.length - 1;
- true;
- pos_old--, pos_new--) {
- if (pos_old - change_pos + 1 < 0 || pos_new - change_pos + 1 < 0) {
- old_len = pos_old - change_pos + 2;
- new_len = pos_new - change_pos + 2;
- break find_range;
- }
- if (old_source[pos_old] != new_source[pos_new]) {
- old_len = pos_old - change_pos + 1;
- new_len = pos_new - change_pos + 1;
- break find_range;
- }
- }
- }
- }
+ return ApplyPatchMultiChunk(script,
+ [ change_pos, change_pos + change_len, change_pos + new_str.length],
+ new_source, change_log);
+ }
- if (old_len == 0 && new_len == 0) {
- // no change
- return;
- }
-
- return { "change_pos": change_pos, "old_len": old_len, "new_len": new_len };
+
+ // Functions are public for tests.
+ this.TestApi = {
+ PosTranslator: PosTranslator,
+ CompareStringsLinewise: CompareStringsLinewise,
+ ApplySingleChunkPatch: ApplySingleChunkPatch
}
}