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

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

Issue 2943002: Reimplement stack manipulations for LiveEdit (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/liveedit.cc ('k') | src/mips/debug-mips.cc » ('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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 }, 131 },
132 updated: false 132 updated: false
133 }; 133 };
134 134
135 if (preview_only) { 135 if (preview_only) {
136 return preview_description; 136 return preview_description;
137 } 137 }
138 138
139 HarvestTodo(root_old_node); 139 HarvestTodo(root_old_node);
140 140
141 // Collect shared infos for functions whose code need to be patched. 141 // Check whether the functions being patched are currently on stack.
142 var replaced_function_infos = new Array(); 142 var stack_info_wrapper =
143 for (var i = 0; i < replace_code_list.length; i++) { 143 CheckStackActivations(replace_code_list, change_log);
144 var info_wrapper = replace_code_list[i].live_shared_info_wrapper; 144 preview_description.stack_modified = !!stack_info_wrapper;
145 if (info_wrapper) { 145
146 replaced_function_infos.push(info_wrapper);
147 }
148 }
149
150 // We haven't changed anything before this line yet. 146 // We haven't changed anything before this line yet.
151 // Committing all changes. 147 // Committing all changes.
152 148
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
159 // Start with breakpoints. Convert their line/column positions and 149 // Start with breakpoints. Convert their line/column positions and
160 // temporary remove. 150 // temporary remove.
161 var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log); 151 var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log);
162 152
163 var old_script; 153 try {
164 154 var old_script;
165 // Create an old script only if there are function that should be linked 155
166 // to old version. 156 // Create an old script only if there are function that should be linked
167 if (link_to_old_script_list.length == 0) { 157 // to old version.
168 %LiveEditReplaceScript(script, new_source, null); 158 if (link_to_old_script_list.length == 0) {
169 old_script = void 0; 159 %LiveEditReplaceScript(script, new_source, null);
170 } else { 160 old_script = void 0;
171 var old_script_name = CreateNameForOldScript(script); 161 } else {
162 var old_script_name = CreateNameForOldScript(script);
163
164 // Update the script text and create a new script representing an old
165 // version of the script.
166 old_script = %LiveEditReplaceScript(script, new_source,
167 old_script_name);
168
169 var link_to_old_script_report = new Array();
170 change_log.push( { linked_to_old_script: link_to_old_script_report } );
172 171
173 // Update the script text and create a new script representing an old 172 // We need to link to old script all former nested functions.
174 // version of the script. 173 for (var i = 0; i < link_to_old_script_list.length; i++) {
175 old_script = %LiveEditReplaceScript(script, new_source, 174 LinkToOldScript(link_to_old_script_list[i], old_script,
176 old_script_name); 175 link_to_old_script_report);
177 176 }
178 var link_to_old_script_report = new Array(); 177
179 change_log.push( { linked_to_old_script: link_to_old_script_report } ); 178 preview_description.created_script_name = old_script_name;
180
181 // We need to link to old script all former nested functions.
182 for (var i = 0; i < link_to_old_script_list.length; i++) {
183 LinkToOldScript(link_to_old_script_list[i], old_script,
184 link_to_old_script_report);
185 } 179 }
186 180
187 preview_description.created_script_name = old_script_name; 181 // Link to an actual script all the functions that we are going to use.
182 for (var i = 0; i < link_to_original_script_list.length; i++) {
183 %LiveEditFunctionSetScript(
184 link_to_original_script_list[i].info.shared_function_info, script);
185 }
186
187 // In the general case there are several functions to be patched
188 // and some of them are activated on the stack.
189 // We drop n topmost frames from the stack, while restaring the
190 // bottom frame. The bottom frame function always is in the patch
191 // list (otherwise there was no reason to touch it). We have to
192 // reset the stack and patch the function in one transaction.
193 // All other functions are patched later.
194 var bottom_function_index;
195 if (stack_info_wrapper) {
196 bottom_function_index = stack_info_wrapper.bottom_function_index;
197 // First we must patch the function that is being reset
198 // to start on stack.
199 PatchFunctionCode(replace_code_list[bottom_function_index],
200 stack_info_wrapper.drop_data, change_log);
201 } else {
202 bottom_function_index = -1;
203 }
204
205
206 for (var i = 0; i < replace_code_list.length; i++) {
207 if (i == bottom_function_index) {
208 // Skip the function that has already been patched.
209 continue;
210 }
211 PatchFunctionCode(replace_code_list[i], void 0, change_log);
212 }
213
214 var position_patch_report = new Array();
215 change_log.push( {position_patched: position_patch_report} );
216
217 for (var i = 0; i < update_positions_list.length; i++) {
218 // TODO(LiveEdit): take into account wether it's source_changed or
219 // unchanged and whether positions changed at all.
220 PatchPositions(update_positions_list[i], diff_array,
221 position_patch_report);
222 }
223 } finally {
224 break_points_restorer(pos_translator, old_script);
188 } 225 }
189 226
190 // Link to an actual script all the functions that we are going to use.
191 for (var i = 0; i < link_to_original_script_list.length; i++) {
192 %LiveEditFunctionSetScript(
193 link_to_original_script_list[i].info.shared_function_info, script);
194 }
195
196 for (var i = 0; i < replace_code_list.length; i++) {
197 PatchFunctionCode(replace_code_list[i], change_log);
198 }
199
200 var position_patch_report = new Array();
201 change_log.push( {position_patched: position_patch_report} );
202
203 for (var i = 0; i < update_positions_list.length; i++) {
204 // TODO(LiveEdit): take into account wether it's source_changed or
205 // unchanged and whether positions changed at all.
206 PatchPositions(update_positions_list[i], diff_array,
207 position_patch_report);
208 }
209
210 break_points_restorer(pos_translator, old_script);
211
212 preview_description.updated = true; 227 preview_description.updated = true;
213 return preview_description; 228 return preview_description;
214 } 229 }
215 // Function is public. 230 // Function is public.
216 this.ApplyPatchMultiChunk = ApplyPatchMultiChunk; 231 this.ApplyPatchMultiChunk = ApplyPatchMultiChunk;
217 232
218 233
219 // Fully compiles source string as a script. Returns Array of 234 // Fully compiles source string as a script. Returns Array of
220 // FunctionCompileInfo -- a descriptions of all functions of the script. 235 // FunctionCompileInfo -- a descriptions of all functions of the script.
221 // Elements of array are ordered by start positions of functions (from top 236 // Elements of array are ordered by start positions of functions (from top
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 } 300 }
286 } 301 }
287 302
288 ResetIndexes(-1, -1); 303 ResetIndexes(-1, -1);
289 Assert(current_index == compile_info.length); 304 Assert(current_index == compile_info.length);
290 305
291 return compile_info; 306 return compile_info;
292 } 307 }
293 308
294 309
295 // Replaces function's Code. 310 // Replaces function's Code and optionally resets the stack.
296 function PatchFunctionCode(old_node, change_log) { 311 function PatchFunctionCode(old_node, stack_drop_data, change_log) {
297 var new_info = old_node.corresponding_node.info; 312 var new_info = old_node.corresponding_node.info;
298 var shared_info_wrapper = old_node.live_shared_info_wrapper; 313 var shared_info_wrapper = old_node.live_shared_info_wrapper;
299 if (shared_info_wrapper) { 314 if (shared_info_wrapper) {
300 %LiveEditReplaceFunctionCode(new_info.raw_array, 315 %LiveEditReplaceFunctionCode(new_info.raw_array,
301 shared_info_wrapper.raw_array); 316 shared_info_wrapper.raw_array, stack_drop_data);
302 317
303 // The function got a new code. However, this new code brings all new 318 // The function got a new code. However, this new code brings all new
304 // instances of SharedFunctionInfo for nested functions. However, 319 // instances of SharedFunctionInfo for nested functions. However,
305 // we want the original instances to be used wherever possible. 320 // we want the original instances to be used wherever possible.
306 // (This is because old instances and new instances will be both 321 // (This is because old instances and new instances will be both
307 // linked to a script and breakpoints subsystem does not really 322 // linked to a script and breakpoints subsystem does not really
308 // expects this; neither does LiveEdit subsystem on next call). 323 // expects this; neither does LiveEdit subsystem on next call).
309 for (var i = 0; i < old_node.children.length; i++) { 324 for (var i = 0; i < old_node.children.length; i++) {
310 if (old_node.children[i].corresponding_node) { 325 if (old_node.children[i].corresponding_node) {
311 var corresponding_child = old_node.children[i].corresponding_node; 326 var corresponding_child = old_node.children[i].corresponding_node;
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after
807 this.raw_array = raw_array; 822 this.raw_array = raw_array;
808 } 823 }
809 824
810 function SharedInfoWrapper(raw_array) { 825 function SharedInfoWrapper(raw_array) {
811 this.function_name = raw_array[0]; 826 this.function_name = raw_array[0];
812 this.start_position = raw_array[1]; 827 this.start_position = raw_array[1];
813 this.end_position = raw_array[2]; 828 this.end_position = raw_array[2];
814 this.info = raw_array[3]; 829 this.info = raw_array[3];
815 this.raw_array = raw_array; 830 this.raw_array = raw_array;
816 } 831 }
832
833 // Information about possible stack manipulations. Either
834 // success (drop_data is defined), failure (error_message is defined)
835 // or empty otherwise.
836 function StackInfoWrapper(raw_array) {
837 this.error_message = raw_array[0];
838 this.bottom_function_index = raw_array[1];
839 this.drop_data = raw_array[2];
840 }
817 841
818 // Changes positions (including all statments) in function. 842 // Changes positions (including all statments) in function.
819 function PatchPositions(old_info_node, diff_array, report_array) { 843 function PatchPositions(old_info_node, diff_array, report_array) {
820 var shared_info_wrapper = old_info_node.live_shared_info_wrapper; 844 var shared_info_wrapper = old_info_node.live_shared_info_wrapper;
821 if (!shared_info_wrapper) { 845 if (!shared_info_wrapper) {
822 // TODO(LiveEdit): function is not compiled yet or is already collected. 846 // TODO(LiveEdit): function is not compiled yet or is already collected.
823 report_array.push( 847 report_array.push(
824 { name: old_info_node.info.function_name, info_not_found: true } ); 848 { name: old_info_node.info.function_name, info_not_found: true } );
825 return; 849 return;
826 } 850 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 } 886 }
863 887
864 if (scope_info1_text != scope_info2_text) { 888 if (scope_info1_text != scope_info2_text) {
865 return "Incompatible variable maps: [" + scope_info1_text + 889 return "Incompatible variable maps: [" + scope_info1_text +
866 "] and [" + scope_info2_text + "]"; 890 "] and [" + scope_info2_text + "]";
867 } 891 }
868 // No differences. Return undefined. 892 // No differences. Return undefined.
869 return; 893 return;
870 } 894 }
871 895
872 // Minifier forward declaration. 896 // For an array of function nodes checks that none of them
873 var FunctionPatchabilityStatus;
874
875 // For array of wrapped shared function infos checks that none of them
876 // have activations on stack (of any thread). Throws a Failure exception 897 // have activations on stack (of any thread). Throws a Failure exception
877 // if this proves to be false. 898 // if this proves to be false.
878 function CheckStackActivations(shared_wrapper_list, change_log) { 899 // Returns StackInfoWrapper for future stack manipulations or
900 // nothing if there is nothing to do with stack.
901 function CheckStackActivations(function_node_list, change_log) {
879 var shared_list = new Array(); 902 var shared_list = new Array();
880 for (var i = 0; i < shared_wrapper_list.length; i++) { 903 for (var i = 0; i < function_node_list.length; i++) {
881 shared_list[i] = shared_wrapper_list[i].info; 904 var info_wrapper = function_node_list[i].live_shared_info_wrapper;
882 } 905 if (info_wrapper) {
883 var result = %LiveEditCheckAndDropActivations(shared_list, true); 906 shared_list[i] = info_wrapper.info;
884 if (result[shared_list.length]) {
885 // Extra array element may contain error message.
886 throw new Failure(result[shared_list.length]);
887 }
888
889 var problems = new Array();
890 var dropped = new Array();
891 for (var i = 0; i < shared_list.length; i++) {
892 var shared = shared_wrapper_list[i];
893 if (result[i] == FunctionPatchabilityStatus.REPLACED_ON_ACTIVE_STACK) {
894 dropped.push({ name: shared.function_name } );
895 } else if (result[i] != FunctionPatchabilityStatus.AVAILABLE_FOR_PATCH) {
896 var description = {
897 name: shared.function_name,
898 start_pos: shared.start_position,
899 end_pos: shared.end_position,
900 replace_problem:
901 FunctionPatchabilityStatus.SymbolName(result[i])
902 };
903 problems.push(description);
904 } 907 }
905 } 908 }
906 if (dropped.length > 0) { 909 var raw_data_array = %LiveEditCheckActivations(shared_list);
907 change_log.push({ dropped_from_stack: dropped }); 910 var stack_info_wrapper = new StackInfoWrapper(raw_data_array);
911 var bottom_function_index = stack_info_wrapper.bottom_function_index;
912 if (stack_info_wrapper.error_message) {
913 if (IS_NUMBER(bottom_function_index)) {
914 throw new Failure(stack_info_wrapper.error_message +
915 "; function=" + shared_list[bottom_function_index].function_name);
916 } else {
917 throw new Failure(stack_info_wrapper.error_message + ".");
918 }
908 } 919 }
909 if (problems.length > 0) { 920 if (IS_NUMBER(bottom_function_index)) {
910 change_log.push( { functions_on_stack: problems } ); 921 return stack_info_wrapper;
911 throw new Failure("Blocked by functions on stack"); 922 } else {
923 return;
912 } 924 }
913
914 return dropped.length;
915 }
916
917 // A copy of the FunctionPatchabilityStatus enum from liveedit.h
918 var FunctionPatchabilityStatus = {
919 AVAILABLE_FOR_PATCH: 1,
920 BLOCKED_ON_ACTIVE_STACK: 2,
921 BLOCKED_ON_OTHER_STACK: 3,
922 BLOCKED_UNDER_NATIVE_CODE: 4,
923 REPLACED_ON_ACTIVE_STACK: 5
924 }
925
926 FunctionPatchabilityStatus.SymbolName = function(code) {
927 var enum = FunctionPatchabilityStatus;
928 for (name in enum) {
929 if (enum[name] == code) {
930 return name;
931 }
932 }
933 } 925 }
934 926
935 927
936 // A logical failure in liveedit process. This means that change_log 928 // A logical failure in liveedit process. This means that change_log
937 // is valid and consistent description of what happened. 929 // is valid and consistent description of what happened.
938 function Failure(message) { 930 function Failure(message) {
939 this.message = message; 931 this.message = message;
940 } 932 }
941 // Function (constructor) is public. 933 // Function (constructor) is public.
942 this.Failure = Failure; 934 this.Failure = Failure;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1048 } 1040 }
1049 1041
1050 1042
1051 // Functions are public for tests. 1043 // Functions are public for tests.
1052 this.TestApi = { 1044 this.TestApi = {
1053 PosTranslator: PosTranslator, 1045 PosTranslator: PosTranslator,
1054 CompareStringsLinewise: CompareStringsLinewise, 1046 CompareStringsLinewise: CompareStringsLinewise,
1055 ApplySingleChunkPatch: ApplySingleChunkPatch 1047 ApplySingleChunkPatch: ApplySingleChunkPatch
1056 } 1048 }
1057 } 1049 }
OLDNEW
« no previous file with comments | « src/liveedit.cc ('k') | src/mips/debug-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698