diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2010-05-06 09:59:35 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2010-05-06 09:59:35 -0700 |
commit | 6aab6ebe6168464de8e7b0c7254fad4771f281c1 (patch) | |
tree | b0c6b91086cbf16147ba247ac6283652bfece086 /deps/v8/src/liveedit-debugger.js | |
parent | 4ce1e1fca59bc6ad6e2d19643db2ed3159ccb7dc (diff) | |
download | node-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.js | 640 |
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 } } |