Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1463)

Side by Side Diff: src/liveedit-debugger.js

Issue 2883020: Describe LiveEdit changes and support preview mode (Closed)
Patch Set: follow codereview Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/debug-debugger.js ('k') | test/mjsunit/debug-liveedit-3.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/debug-debugger.js ('k') | test/mjsunit/debug-liveedit-3.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698