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