Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 // LiveEdit namespace is declared inside a single function constructor. | 44 // LiveEdit namespace is declared inside a single function constructor. |
| 45 Debug.LiveEdit = new function() { | 45 Debug.LiveEdit = new function() { |
| 46 | 46 |
| 47 // Forward declaration for minifier. | 47 // Forward declaration for minifier. |
| 48 var FunctionStatus; | 48 var FunctionStatus; |
| 49 | 49 |
| 50 | 50 |
| 51 // Applies the change to the script. | 51 // Applies the change to the script. |
| 52 // The change is in form of list of chunks encoded in a single array as | 52 // The change is in form of list of chunks encoded in a single array as |
| 53 // a series of triplets (pos1_start, pos1_end, pos2_end) | 53 // a series of triplets (pos1_start, pos1_end, pos2_end) |
| 54 function ApplyPatchMultiChunk(script, diff_array, new_source, change_log) { | 54 function ApplyPatchMultiChunk(script, diff_array, new_source, preview_only, ch ange_log) { |
|
mnaganov (inactive)
2010/07/02 16:23:36
nit: >80 chars
Peter Rybin
2013/06/26 19:39:57
Done.
| |
| 55 | 55 |
| 56 var old_source = script.source; | 56 var old_source = script.source; |
| 57 | 57 |
| 58 // Gather compile information about old version of script. | 58 // Gather compile information about old version of script. |
| 59 var old_compile_info = GatherCompileInfo(old_source, script); | 59 var old_compile_info = GatherCompileInfo(old_source, script); |
| 60 | 60 |
| 61 // Build tree structures for old and new versions of the script. | 61 // Build tree structures for old and new versions of the script. |
| 62 var root_old_node = BuildCodeInfoTree(old_compile_info); | 62 var root_old_node = BuildCodeInfoTree(old_compile_info); |
| 63 | 63 |
| 64 var pos_translator = new PosTranslator(diff_array); | 64 var pos_translator = new PosTranslator(diff_array); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 89 | 89 |
| 90 function HarvestTodo(old_node) { | 90 function HarvestTodo(old_node) { |
| 91 function CollectDamaged(node) { | 91 function CollectDamaged(node) { |
| 92 link_to_old_script_list.push(node); | 92 link_to_old_script_list.push(node); |
| 93 for (var i = 0; i < node.children.length; i++) { | 93 for (var i = 0; i < node.children.length; i++) { |
| 94 CollectDamaged(node.children[i]); | 94 CollectDamaged(node.children[i]); |
| 95 } | 95 } |
| 96 } | 96 } |
| 97 | 97 |
| 98 // Recursively collects all newly compiled functions that are going into | 98 // Recursively collects all newly compiled functions that are going into |
| 99 // business and should be have link to the actual script updated. | 99 // business and should have link to the actual script updated. |
| 100 function CollectNew(node_list) { | 100 function CollectNew(node_list) { |
| 101 for (var i = 0; i < node_list.length; i++) { | 101 for (var i = 0; i < node_list.length; i++) { |
| 102 link_to_original_script_list.push(node_list[i]); | 102 link_to_original_script_list.push(node_list[i]); |
| 103 CollectNew(node_list[i].children); | 103 CollectNew(node_list[i].children); |
| 104 } | 104 } |
| 105 } | 105 } |
| 106 | 106 |
| 107 if (old_node.status == FunctionStatus.DAMAGED) { | 107 if (old_node.status == FunctionStatus.DAMAGED) { |
| 108 CollectDamaged(old_node); | 108 CollectDamaged(old_node); |
| 109 return; | 109 return; |
| 110 } | 110 } |
| 111 if (old_node.status == FunctionStatus.UNCHANGED) { | 111 if (old_node.status == FunctionStatus.UNCHANGED) { |
| 112 update_positions_list.push(old_node); | 112 update_positions_list.push(old_node); |
| 113 } else if (old_node.status == FunctionStatus.SOURCE_CHANGED) { | 113 } else if (old_node.status == FunctionStatus.SOURCE_CHANGED) { |
| 114 update_positions_list.push(old_node); | 114 update_positions_list.push(old_node); |
| 115 } else if (old_node.status == FunctionStatus.CHANGED) { | 115 } else if (old_node.status == FunctionStatus.CHANGED) { |
| 116 replace_code_list.push(old_node); | 116 replace_code_list.push(old_node); |
| 117 CollectNew(old_node.unmatched_new_nodes); | 117 CollectNew(old_node.unmatched_new_nodes); |
| 118 } | 118 } |
| 119 for (var i = 0; i < old_node.children.length; i++) { | 119 for (var i = 0; i < old_node.children.length; i++) { |
| 120 HarvestTodo(old_node.children[i]); | 120 HarvestTodo(old_node.children[i]); |
| 121 } | 121 } |
| 122 } | 122 } |
| 123 | 123 |
| 124 var preview_description = { | |
| 125 change_tree: DescribeChangeTree(root_old_node), | |
| 126 textual_diff: { | |
| 127 old_len: old_source.length, | |
| 128 new_len: new_source.length, | |
| 129 chunks: diff_array | |
| 130 }, | |
| 131 updated: false | |
| 132 }; | |
| 133 | |
| 134 if (preview_only) { | |
| 135 return preview_description; | |
| 136 } | |
| 137 | |
| 124 HarvestTodo(root_old_node); | 138 HarvestTodo(root_old_node); |
| 125 | 139 |
| 126 // Collect shared infos for functions whose code need to be patched. | 140 // Collect shared infos for functions whose code need to be patched. |
| 127 var replaced_function_infos = new Array(); | 141 var replaced_function_infos = new Array(); |
| 128 for (var i = 0; i < replace_code_list.length; i++) { | 142 for (var i = 0; i < replace_code_list.length; i++) { |
| 129 var info_wrapper = replace_code_list[i].live_shared_info_wrapper; | 143 var info_wrapper = replace_code_list[i].live_shared_info_wrapper; |
| 130 if (info_wrapper) { | 144 if (info_wrapper) { |
| 131 replaced_function_infos.push(info_wrapper); | 145 replaced_function_infos.push(info_wrapper); |
| 132 } | 146 } |
| 133 } | 147 } |
| 134 | 148 |
| 135 // Check that function being patched is not currently on stack. | |
| 136 CheckStackActivations(replaced_function_infos, change_log); | |
| 137 | |
| 138 | |
| 139 // We haven't changed anything before this line yet. | 149 // We haven't changed anything before this line yet. |
| 140 // Committing all changes. | 150 // Committing all changes. |
| 141 | 151 |
| 152 // Check that function being patched is not currently on stack or drop them. | |
| 153 var dropped_functions_number = | |
| 154 CheckStackActivations(replaced_function_infos, change_log); | |
| 155 | |
| 156 preview_description.stack_modified = dropped_functions_number != 0; | |
| 157 | |
| 142 // Start with breakpoints. Convert their line/column positions and | 158 // Start with breakpoints. Convert their line/column positions and |
| 143 // temporary remove. | 159 // temporary remove. |
| 144 var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log); | 160 var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log); |
| 145 | 161 |
| 146 var old_script; | 162 var old_script; |
| 147 | 163 |
| 148 // Create an old script only if there are function that should be linked | 164 // Create an old script only if there are function that should be linked |
| 149 // to old version. | 165 // to old version. |
| 150 if (link_to_old_script_list.length == 0) { | 166 if (link_to_old_script_list.length == 0) { |
| 151 %LiveEditReplaceScript(script, new_source, null); | 167 %LiveEditReplaceScript(script, new_source, null); |
| 152 old_script = void 0; | 168 old_script = void 0; |
| 153 } else { | 169 } else { |
| 154 var old_script_name = CreateNameForOldScript(script); | 170 var old_script_name = CreateNameForOldScript(script); |
| 155 | 171 |
| 156 // Update the script text and create a new script representing an old | 172 // Update the script text and create a new script representing an old |
| 157 // version of the script. | 173 // version of the script. |
| 158 old_script = %LiveEditReplaceScript(script, new_source, | 174 old_script = %LiveEditReplaceScript(script, new_source, |
| 159 old_script_name); | 175 old_script_name); |
| 160 | 176 |
| 161 var link_to_old_script_report = new Array(); | 177 var link_to_old_script_report = new Array(); |
| 162 change_log.push( { linked_to_old_script: link_to_old_script_report } ); | 178 change_log.push( { linked_to_old_script: link_to_old_script_report } ); |
| 163 | 179 |
| 164 // We need to link to old script all former nested functions. | 180 // We need to link to old script all former nested functions. |
| 165 for (var i = 0; i < link_to_old_script_list.length; i++) { | 181 for (var i = 0; i < link_to_old_script_list.length; i++) { |
| 166 LinkToOldScript(link_to_old_script_list[i], old_script, | 182 LinkToOldScript(link_to_old_script_list[i], old_script, |
| 167 link_to_old_script_report); | 183 link_to_old_script_report); |
| 168 } | 184 } |
| 185 | |
| 186 preview_description.created_script_name = old_script_name; | |
| 169 } | 187 } |
| 170 | 188 |
| 171 // Link to an actual script all the functions that we are going to use. | 189 // Link to an actual script all the functions that we are going to use. |
| 172 for (var i = 0; i < link_to_original_script_list.length; i++) { | 190 for (var i = 0; i < link_to_original_script_list.length; i++) { |
| 173 %LiveEditFunctionSetScript( | 191 %LiveEditFunctionSetScript( |
| 174 link_to_original_script_list[i].info.shared_function_info, script); | 192 link_to_original_script_list[i].info.shared_function_info, script); |
| 175 } | 193 } |
| 176 | 194 |
| 177 for (var i = 0; i < replace_code_list.length; i++) { | 195 for (var i = 0; i < replace_code_list.length; i++) { |
| 178 PatchFunctionCode(replace_code_list[i], change_log); | 196 PatchFunctionCode(replace_code_list[i], change_log); |
| 179 } | 197 } |
| 180 | 198 |
| 181 var position_patch_report = new Array(); | 199 var position_patch_report = new Array(); |
| 182 change_log.push( {position_patched: position_patch_report} ); | 200 change_log.push( {position_patched: position_patch_report} ); |
| 183 | 201 |
| 184 for (var i = 0; i < update_positions_list.length; i++) { | 202 for (var i = 0; i < update_positions_list.length; i++) { |
| 185 // TODO(LiveEdit): take into account wether it's source_changed or | 203 // TODO(LiveEdit): take into account wether it's source_changed or |
| 186 // unchanged and whether positions changed at all. | 204 // unchanged and whether positions changed at all. |
| 187 PatchPositions(update_positions_list[i], diff_array, | 205 PatchPositions(update_positions_list[i], diff_array, |
| 188 position_patch_report); | 206 position_patch_report); |
| 189 } | 207 } |
| 190 | 208 |
| 191 break_points_restorer(pos_translator, old_script); | 209 break_points_restorer(pos_translator, old_script); |
| 210 | |
| 211 preview_description.updated = true; | |
| 212 return preview_description; | |
| 192 } | 213 } |
| 193 // Function is public. | 214 // Function is public. |
| 194 this.ApplyPatchMultiChunk = ApplyPatchMultiChunk; | 215 this.ApplyPatchMultiChunk = ApplyPatchMultiChunk; |
| 195 | 216 |
| 196 | 217 |
| 197 // Fully compiles source string as a script. Returns Array of | 218 // Fully compiles source string as a script. Returns Array of |
| 198 // FunctionCompileInfo -- a descriptions of all functions of the script. | 219 // FunctionCompileInfo -- a descriptions of all functions of the script. |
| 199 // Elements of array are ordered by start positions of functions (from top | 220 // Elements of array are ordered by start positions of functions (from top |
| 200 // to bottom) in the source. Fields outer_index and next_sibling_index help | 221 // to bottom) in the source. Fields outer_index and next_sibling_index help |
| 201 // to navigate the nesting structure of functions. | 222 // to navigate the nesting structure of functions. |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 487 this.parent = void 0; | 508 this.parent = void 0; |
| 488 | 509 |
| 489 this.status = FunctionStatus.UNCHANGED; | 510 this.status = FunctionStatus.UNCHANGED; |
| 490 // Status explanation is used for debugging purposes and will be shown | 511 // Status explanation is used for debugging purposes and will be shown |
| 491 // in user UI if some explanations are needed. | 512 // in user UI if some explanations are needed. |
| 492 this.status_explanation = void 0; | 513 this.status_explanation = void 0; |
| 493 this.new_start_pos = void 0; | 514 this.new_start_pos = void 0; |
| 494 this.new_end_pos = void 0; | 515 this.new_end_pos = void 0; |
| 495 this.corresponding_node = void 0; | 516 this.corresponding_node = void 0; |
| 496 this.unmatched_new_nodes = void 0; | 517 this.unmatched_new_nodes = void 0; |
| 518 | |
| 519 // 'Textual' correspondence/matching is weaker than 'pure' | |
| 520 // correspondence/matching. We need 'textual' level for visual presentation | |
| 521 // in UI, we use 'pure' level for actual code manipulation. | |
| 522 // Sometimes only function body is changed (functions in old and new script | |
| 523 // textually correspond), but we cannot patch the code, so we see them | |
| 524 // as an old function deleted and new function created. | |
| 525 this.textual_corresponding_node = void 0; | |
| 526 this.textually_unmatched_new_nodes = void 0; | |
| 527 | |
| 497 this.live_shared_info_wrapper = void 0; | 528 this.live_shared_info_wrapper = void 0; |
| 498 } | 529 } |
| 499 | 530 |
| 500 // From array of function infos that is implicitly a tree creates | 531 // From array of function infos that is implicitly a tree creates |
| 501 // an actual tree of functions in script. | 532 // an actual tree of functions in script. |
| 502 function BuildCodeInfoTree(code_info_array) { | 533 function BuildCodeInfoTree(code_info_array) { |
| 503 // Throughtout all function we iterate over input array. | 534 // Throughtout all function we iterate over input array. |
| 504 var index = 0; | 535 var index = 0; |
| 505 | 536 |
| 506 // Recursive function that builds a branch of tree. | 537 // Recursive function that builds a branch of tree. |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 633 // splits a function into 2 functions. | 664 // splits a function into 2 functions. |
| 634 function FindCorrespondingFunctions(old_code_tree, new_code_tree) { | 665 function FindCorrespondingFunctions(old_code_tree, new_code_tree) { |
| 635 | 666 |
| 636 // A recursive function that tries to find a correspondence for all | 667 // A recursive function that tries to find a correspondence for all |
| 637 // child functions and for their inner functions. | 668 // child functions and for their inner functions. |
| 638 function ProcessChildren(old_node, new_node) { | 669 function ProcessChildren(old_node, new_node) { |
| 639 var old_children = old_node.children; | 670 var old_children = old_node.children; |
| 640 var new_children = new_node.children; | 671 var new_children = new_node.children; |
| 641 | 672 |
| 642 var unmatched_new_nodes_list = []; | 673 var unmatched_new_nodes_list = []; |
| 674 var textually_unmatched_new_nodes_list = []; | |
| 643 | 675 |
| 644 var old_index = 0; | 676 var old_index = 0; |
| 645 var new_index = 0; | 677 var new_index = 0; |
| 646 while (old_index < old_children.length) { | 678 while (old_index < old_children.length) { |
| 647 if (old_children[old_index].status == FunctionStatus.DAMAGED) { | 679 if (old_children[old_index].status == FunctionStatus.DAMAGED) { |
| 648 old_index++; | 680 old_index++; |
| 649 } else if (new_index < new_children.length) { | 681 } else if (new_index < new_children.length) { |
| 650 if (new_children[new_index].info.start_position < | 682 if (new_children[new_index].info.start_position < |
| 651 old_children[old_index].new_start_pos) { | 683 old_children[old_index].new_start_pos) { |
| 652 unmatched_new_nodes_list.push(new_children[new_index]); | 684 unmatched_new_nodes_list.push(new_children[new_index]); |
| 685 textually_unmatched_new_nodes_list.push(new_children[new_index]); | |
| 653 new_index++; | 686 new_index++; |
| 654 } else if (new_children[new_index].info.start_position == | 687 } else if (new_children[new_index].info.start_position == |
| 655 old_children[old_index].new_start_pos) { | 688 old_children[old_index].new_start_pos) { |
| 656 if (new_children[new_index].info.end_position == | 689 if (new_children[new_index].info.end_position == |
| 657 old_children[old_index].new_end_pos) { | 690 old_children[old_index].new_end_pos) { |
| 658 old_children[old_index].corresponding_node = | 691 old_children[old_index].corresponding_node = |
| 659 new_children[new_index]; | 692 new_children[new_index]; |
| 693 old_children[old_index].textual_corresponding_node = | |
| 694 new_children[new_index]; | |
| 660 if (old_children[old_index].status != FunctionStatus.UNCHANGED) { | 695 if (old_children[old_index].status != FunctionStatus.UNCHANGED) { |
| 661 ProcessChildren(old_children[old_index], | 696 ProcessChildren(old_children[old_index], |
| 662 new_children[new_index]); | 697 new_children[new_index]); |
| 663 if (old_children[old_index].status == FunctionStatus.DAMAGED) { | 698 if (old_children[old_index].status == FunctionStatus.DAMAGED) { |
| 664 unmatched_new_nodes_list.push( | 699 unmatched_new_nodes_list.push( |
| 665 old_children[old_index].corresponding_node); | 700 old_children[old_index].corresponding_node); |
| 666 old_children[old_index].corresponding_node = void 0; | 701 old_children[old_index].corresponding_node = void 0; |
| 667 old_node.status = FunctionStatus.CHANGED; | 702 old_node.status = FunctionStatus.CHANGED; |
| 668 } | 703 } |
| 669 } | 704 } |
| 670 } else { | 705 } else { |
| 671 old_children[old_index].status = FunctionStatus.DAMAGED; | 706 old_children[old_index].status = FunctionStatus.DAMAGED; |
| 672 old_children[old_index].status_explanation = | 707 old_children[old_index].status_explanation = |
| 673 "No corresponding function in new script found"; | 708 "No corresponding function in new script found"; |
| 674 old_node.status = FunctionStatus.CHANGED; | 709 old_node.status = FunctionStatus.CHANGED; |
| 675 unmatched_new_nodes_list.push(new_children[new_index]); | 710 unmatched_new_nodes_list.push(new_children[new_index]); |
| 711 textually_unmatched_new_nodes_list.push(new_children[new_index]); | |
| 676 } | 712 } |
| 677 new_index++; | 713 new_index++; |
| 678 old_index++; | 714 old_index++; |
| 679 } else { | 715 } else { |
| 680 old_children[old_index].status = FunctionStatus.DAMAGED; | 716 old_children[old_index].status = FunctionStatus.DAMAGED; |
| 681 old_children[old_index].status_explanation = | 717 old_children[old_index].status_explanation = |
| 682 "No corresponding function in new script found"; | 718 "No corresponding function in new script found"; |
| 683 old_node.status = FunctionStatus.CHANGED; | 719 old_node.status = FunctionStatus.CHANGED; |
| 684 old_index++; | 720 old_index++; |
| 685 } | 721 } |
| 686 } else { | 722 } else { |
| 687 old_children[old_index].status = FunctionStatus.DAMAGED; | 723 old_children[old_index].status = FunctionStatus.DAMAGED; |
| 688 old_children[old_index].status_explanation = | 724 old_children[old_index].status_explanation = |
| 689 "No corresponding function in new script found"; | 725 "No corresponding function in new script found"; |
| 690 old_node.status = FunctionStatus.CHANGED; | 726 old_node.status = FunctionStatus.CHANGED; |
| 691 old_index++; | 727 old_index++; |
| 692 } | 728 } |
| 693 } | 729 } |
| 694 | 730 |
| 695 while (new_index < new_children.length) { | 731 while (new_index < new_children.length) { |
| 696 unmatched_new_nodes_list.push(new_children[new_index]); | 732 unmatched_new_nodes_list.push(new_children[new_index]); |
| 733 textually_unmatched_new_nodes_list.push(new_children[new_index]); | |
| 697 new_index++; | 734 new_index++; |
| 698 } | 735 } |
| 699 | 736 |
| 700 if (old_node.status == FunctionStatus.CHANGED) { | 737 if (old_node.status == FunctionStatus.CHANGED) { |
| 701 if (!CompareFunctionExpectations(old_node.info, new_node.info)) { | 738 var why_wrong_expectations = |
| 739 WhyFunctionExpectationsDiffer(old_node.info, new_node.info); | |
| 740 if (why_wrong_expectations) { | |
| 702 old_node.status = FunctionStatus.DAMAGED; | 741 old_node.status = FunctionStatus.DAMAGED; |
| 703 old_node.status_explanation = "Changed code expectations"; | 742 old_node.status_explanation = why_wrong_expectations; |
| 704 } | 743 } |
| 705 } | 744 } |
| 706 old_node.unmatched_new_nodes = unmatched_new_nodes_list; | 745 old_node.unmatched_new_nodes = unmatched_new_nodes_list; |
| 746 old_node.textually_unmatched_new_nodes = | |
| 747 textually_unmatched_new_nodes_list; | |
| 707 } | 748 } |
| 708 | 749 |
| 709 ProcessChildren(old_code_tree, new_code_tree); | 750 ProcessChildren(old_code_tree, new_code_tree); |
| 710 | 751 |
| 711 old_code_tree.corresponding_node = new_code_tree; | 752 old_code_tree.corresponding_node = new_code_tree; |
| 753 old_code_tree.textual_corresponding_node = new_code_tree; | |
| 754 | |
| 712 Assert(old_code_tree.status != FunctionStatus.DAMAGED, | 755 Assert(old_code_tree.status != FunctionStatus.DAMAGED, |
| 713 "Script became damaged"); | 756 "Script became damaged"); |
| 714 } | 757 } |
| 715 | 758 |
| 716 function FindLiveSharedInfos(old_code_tree, script) { | 759 function FindLiveSharedInfos(old_code_tree, script) { |
| 717 var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script); | 760 var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script); |
| 718 | 761 |
| 719 var shared_infos = new Array(); | 762 var shared_infos = new Array(); |
| 720 | 763 |
| 721 for (var i = 0; i < shared_raw_list.length; i++) { | 764 for (var i = 0; i < shared_raw_list.length; i++) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 785 report_array.push( { name: old_info_node.info.function_name } ); | 828 report_array.push( { name: old_info_node.info.function_name } ); |
| 786 } | 829 } |
| 787 | 830 |
| 788 // Adds a suffix to script name to mark that it is old version. | 831 // Adds a suffix to script name to mark that it is old version. |
| 789 function CreateNameForOldScript(script) { | 832 function CreateNameForOldScript(script) { |
| 790 // TODO(635): try better than this; support several changes. | 833 // TODO(635): try better than this; support several changes. |
| 791 return script.name + " (old)"; | 834 return script.name + " (old)"; |
| 792 } | 835 } |
| 793 | 836 |
| 794 // Compares a function interface old and new version, whether it | 837 // Compares a function interface old and new version, whether it |
| 795 // changed or not. | 838 // changed or not. Returns explanation if they differ. |
| 796 function CompareFunctionExpectations(function_info1, function_info2) { | 839 function WhyFunctionExpectationsDiffer(function_info1, function_info2) { |
| 797 // Check that function has the same number of parameters (there may exist | 840 // Check that function has the same number of parameters (there may exist |
| 798 // an adapter, that won't survive function parameter number change). | 841 // an adapter, that won't survive function parameter number change). |
| 799 if (function_info1.param_num != function_info2.param_num) { | 842 if (function_info1.param_num != function_info2.param_num) { |
| 800 return false; | 843 return "Changed parameter number: " + function_info1.param_num + |
| 844 " and " + function_info2.param_num; | |
| 801 } | 845 } |
| 802 var scope_info1 = function_info1.scope_info; | 846 var scope_info1 = function_info1.scope_info; |
| 803 var scope_info2 = function_info2.scope_info; | 847 var scope_info2 = function_info2.scope_info; |
| 804 | 848 |
| 805 if (!scope_info1) { | 849 var scope_info1_text; |
| 806 return !scope_info2; | 850 var scope_info2_text; |
| 851 | |
| 852 if (scope_info1) { | |
| 853 scope_info1_text = scope_info1.toString(); | |
| 854 } else { | |
| 855 scope_info1_text = ""; | |
| 807 } | 856 } |
| 808 | 857 if (scope_info2) { |
| 809 if (scope_info1.length != scope_info2.length) { | 858 scope_info2_text = scope_info2.toString(); |
| 810 return false; | 859 } else { |
| 860 scope_info2_text = ""; | |
| 811 } | 861 } |
| 812 | 862 |
| 813 // Check that outer scope structure is not changed. Otherwise the function | 863 if (scope_info1_text != scope_info2_text) { |
| 814 // will not properly work with existing scopes. | 864 return "Incompatible variable maps: [" + scope_info1_text + |
| 815 return scope_info1.toString() == scope_info2.toString(); | 865 "] and [" + scope_info2_text + "]"; |
| 866 } | |
| 867 return; | |
|
mnaganov (inactive)
2010/07/02 16:23:36
I would expect a comment here.
Peter Rybin
2013/06/26 19:39:57
Done.
| |
| 816 } | 868 } |
| 817 | 869 |
| 818 // Minifier forward declaration. | 870 // Minifier forward declaration. |
| 819 var FunctionPatchabilityStatus; | 871 var FunctionPatchabilityStatus; |
| 820 | 872 |
| 821 // For array of wrapped shared function infos checks that none of them | 873 // For array of wrapped shared function infos checks that none of them |
| 822 // have activations on stack (of any thread). Throws a Failure exception | 874 // have activations on stack (of any thread). Throws a Failure exception |
| 823 // if this proves to be false. | 875 // if this proves to be false. |
| 824 function CheckStackActivations(shared_wrapper_list, change_log) { | 876 function CheckStackActivations(shared_wrapper_list, change_log) { |
| 825 var shared_list = new Array(); | 877 var shared_list = new Array(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 849 problems.push(description); | 901 problems.push(description); |
| 850 } | 902 } |
| 851 } | 903 } |
| 852 if (dropped.length > 0) { | 904 if (dropped.length > 0) { |
| 853 change_log.push({ dropped_from_stack: dropped }); | 905 change_log.push({ dropped_from_stack: dropped }); |
| 854 } | 906 } |
| 855 if (problems.length > 0) { | 907 if (problems.length > 0) { |
| 856 change_log.push( { functions_on_stack: problems } ); | 908 change_log.push( { functions_on_stack: problems } ); |
| 857 throw new Failure("Blocked by functions on stack"); | 909 throw new Failure("Blocked by functions on stack"); |
| 858 } | 910 } |
| 911 | |
| 912 return dropped.length; | |
| 859 } | 913 } |
| 860 | 914 |
| 861 // A copy of the FunctionPatchabilityStatus enum from liveedit.h | 915 // A copy of the FunctionPatchabilityStatus enum from liveedit.h |
| 862 var FunctionPatchabilityStatus = { | 916 var FunctionPatchabilityStatus = { |
| 863 AVAILABLE_FOR_PATCH: 1, | 917 AVAILABLE_FOR_PATCH: 1, |
| 864 BLOCKED_ON_ACTIVE_STACK: 2, | 918 BLOCKED_ON_ACTIVE_STACK: 2, |
| 865 BLOCKED_ON_OTHER_STACK: 3, | 919 BLOCKED_ON_OTHER_STACK: 3, |
| 866 BLOCKED_UNDER_NATIVE_CODE: 4, | 920 BLOCKED_UNDER_NATIVE_CODE: 4, |
| 867 REPLACED_ON_ACTIVE_STACK: 5 | 921 REPLACED_ON_ACTIVE_STACK: 5 |
| 868 } | 922 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 890 } | 944 } |
| 891 | 945 |
| 892 // A testing entry. | 946 // A testing entry. |
| 893 function GetPcFromSourcePos(func, source_pos) { | 947 function GetPcFromSourcePos(func, source_pos) { |
| 894 return %GetFunctionCodePositionFromSource(func, source_pos); | 948 return %GetFunctionCodePositionFromSource(func, source_pos); |
| 895 } | 949 } |
| 896 // Function is public. | 950 // Function is public. |
| 897 this.GetPcFromSourcePos = GetPcFromSourcePos; | 951 this.GetPcFromSourcePos = GetPcFromSourcePos; |
| 898 | 952 |
| 899 // LiveEdit main entry point: changes a script text to a new string. | 953 // LiveEdit main entry point: changes a script text to a new string. |
| 900 function SetScriptSource(script, new_source, change_log) { | 954 function SetScriptSource(script, new_source, preview_only, change_log) { |
| 901 var old_source = script.source; | 955 var old_source = script.source; |
| 902 var diff = CompareStringsLinewise(old_source, new_source); | 956 var diff = CompareStringsLinewise(old_source, new_source); |
| 903 if (diff.length == 0) { | 957 return ApplyPatchMultiChunk(script, diff, new_source, preview_only, |
| 904 change_log.push( { empty_diff: true } ); | 958 change_log); |
| 905 return; | |
| 906 } | |
| 907 ApplyPatchMultiChunk(script, diff, new_source, change_log); | |
| 908 } | 959 } |
| 909 // Function is public. | 960 // Function is public. |
| 910 this.SetScriptSource = SetScriptSource; | 961 this.SetScriptSource = SetScriptSource; |
| 911 | 962 |
| 912 function CompareStringsLinewise(s1, s2) { | 963 function CompareStringsLinewise(s1, s2) { |
| 913 return %LiveEditCompareStringsLinewise(s1, s2); | 964 return %LiveEditCompareStringsLinewise(s1, s2); |
| 914 } | 965 } |
| 915 | 966 |
| 916 // Applies the change to the script. | 967 // Applies the change to the script. |
| 917 // The change is always a substring (change_pos, change_pos + change_len) | 968 // The change is always a substring (change_pos, change_pos + change_len) |
| 918 // being replaced with a completely different string new_str. | 969 // being replaced with a completely different string new_str. |
| 919 // This API is a legacy and is obsolete. | 970 // This API is a legacy and is obsolete. |
| 920 // | 971 // |
| 921 // @param {Script} script that is being changed | 972 // @param {Script} script that is being changed |
| 922 // @param {Array} change_log a list that collects engineer-readable | 973 // @param {Array} change_log a list that collects engineer-readable |
| 923 // description of what happened. | 974 // description of what happened. |
| 924 function ApplySingleChunkPatch(script, change_pos, change_len, new_str, | 975 function ApplySingleChunkPatch(script, change_pos, change_len, new_str, |
| 925 change_log) { | 976 change_log) { |
| 926 var old_source = script.source; | 977 var old_source = script.source; |
| 927 | 978 |
| 928 // Prepare new source string. | 979 // Prepare new source string. |
| 929 var new_source = old_source.substring(0, change_pos) + | 980 var new_source = old_source.substring(0, change_pos) + |
| 930 new_str + old_source.substring(change_pos + change_len); | 981 new_str + old_source.substring(change_pos + change_len); |
| 931 | 982 |
| 932 return ApplyPatchMultiChunk(script, | 983 return ApplyPatchMultiChunk(script, |
| 933 [ change_pos, change_pos + change_len, change_pos + new_str.length], | 984 [ change_pos, change_pos + change_len, change_pos + new_str.length], |
| 934 new_source, change_log); | 985 new_source, false, change_log); |
| 986 } | |
| 987 | |
| 988 // Creates JSON description for a change tree. | |
| 989 function DescribeChangeTree(old_code_tree) { | |
| 990 | |
| 991 function ProcessOldNode(node) { | |
| 992 var child_infos = []; | |
| 993 for (var i = 0; i < node.children.length; i++) { | |
| 994 var child = node.children[i]; | |
| 995 if (child.status != FunctionStatus.UNCHANGED) { | |
| 996 child_infos.push(ProcessOldNode(child)); | |
| 997 } | |
| 998 } | |
| 999 var new_child_infos = []; | |
| 1000 if (node.textually_unmatched_new_nodes) { | |
| 1001 for (var i = 0; i < node.textually_unmatched_new_nodes.length; i++) { | |
| 1002 var child = node.textually_unmatched_new_nodes[i]; | |
| 1003 new_child_infos.push(ProcessNewNode(child)); | |
| 1004 } | |
| 1005 } | |
| 1006 var res = { | |
| 1007 name: node.info.function_name, | |
| 1008 positions: DescribePositions(node), | |
| 1009 status: node.status, | |
| 1010 children: child_infos, | |
| 1011 new_children: new_child_infos | |
| 1012 }; | |
| 1013 if (node.status_explanation) { | |
| 1014 res.status_explanation = node.status_explanation; | |
| 1015 } | |
| 1016 if (node.textual_corresponding_node) { | |
| 1017 res.new_positions = DescribePositions(node.textual_corresponding_node); | |
| 1018 } | |
| 1019 return res; | |
| 1020 } | |
| 1021 | |
| 1022 function ProcessNewNode(node) { | |
| 1023 var child_infos = []; | |
| 1024 // Do not list ancestors. | |
| 1025 if (false) { | |
| 1026 for (var i = 0; i < node.children.length; i++) { | |
| 1027 child_infos.push(ProcessNewNode(node.children[i])); | |
| 1028 } | |
| 1029 } | |
| 1030 var res = { | |
| 1031 name: node.info.function_name, | |
| 1032 positions: DescribePositions(node), | |
| 1033 children: child_infos, | |
| 1034 }; | |
| 1035 return res; | |
| 1036 } | |
| 1037 | |
| 1038 function DescribePositions(node) { | |
| 1039 return { | |
| 1040 start_position: node.info.start_position, | |
| 1041 end_position: node.info.end_position | |
| 1042 }; | |
| 1043 } | |
| 1044 | |
| 1045 return ProcessOldNode(old_code_tree); | |
| 935 } | 1046 } |
| 936 | 1047 |
| 937 | 1048 |
| 938 // Functions are public for tests. | 1049 // Functions are public for tests. |
| 939 this.TestApi = { | 1050 this.TestApi = { |
| 940 PosTranslator: PosTranslator, | 1051 PosTranslator: PosTranslator, |
| 941 CompareStringsLinewise: CompareStringsLinewise, | 1052 CompareStringsLinewise: CompareStringsLinewise, |
| 942 ApplySingleChunkPatch: ApplySingleChunkPatch | 1053 ApplySingleChunkPatch: ApplySingleChunkPatch |
| 943 } | 1054 } |
| 944 } | 1055 } |
| OLD | NEW |