| 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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |