| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // LiveEdit feature implementation. The script should be executed after | 5 // LiveEdit feature implementation. The script should be executed after |
| 6 // debug.js. | 6 // debug.js. |
| 7 | 7 |
| 8 // A LiveEdit namespace. It contains functions that modifies JavaScript code | 8 // A LiveEdit namespace. It contains functions that modifies JavaScript code |
| 9 // according to changes of script source (if possible). | 9 // according to changes of script source (if possible). |
| 10 // | 10 // |
| 11 // When new script source is put in, the difference is calculated textually, | 11 // When new script source is put in, the difference is calculated textually, |
| 12 // in form of list of delete/add/change chunks. The functions that include | 12 // in form of list of delete/add/change chunks. The functions that include |
| 13 // change chunk(s) get recompiled, or their enclosing functions are | 13 // change chunk(s) get recompiled, or their enclosing functions are |
| 14 // recompiled instead. | 14 // recompiled instead. |
| 15 // If the function may not be recompiled (e.g. it was completely erased in new | 15 // If the function may not be recompiled (e.g. it was completely erased in new |
| 16 // version of the script) it remains unchanged, but the code that could | 16 // version of the script) it remains unchanged, but the code that could |
| 17 // create a new instance of this function goes away. An old version of script | 17 // create a new instance of this function goes away. An old version of script |
| 18 // is created to back up this obsolete function. | 18 // is created to back up this obsolete function. |
| 19 // All unchanged functions have their positions updated accordingly. | 19 // All unchanged functions have their positions updated accordingly. |
| 20 // | 20 // |
| 21 // LiveEdit namespace is declared inside a single function constructor. | 21 // LiveEdit namespace is declared inside a single function constructor. |
| 22 | 22 |
| 23 (function(global, utils) { | 23 (function(global, utils) { |
| 24 "use strict"; | 24 "use strict"; |
| 25 | 25 |
| 26 // ------------------------------------------------------------------- | 26 // ------------------------------------------------------------------- |
| 27 // Imports | 27 // Imports |
| 28 | 28 |
| 29 var FindScriptSourcePosition = global.Debug.findScriptSourcePosition; | 29 var FindScriptSourcePosition = global.Debug.findScriptSourcePosition; |
| 30 var GetScriptBreakPoints; | |
| 31 var GlobalArray = global.Array; | 30 var GlobalArray = global.Array; |
| 32 var MathFloor = global.Math.floor; | 31 var MathFloor = global.Math.floor; |
| 33 var SyntaxError = global.SyntaxError; | 32 var SyntaxError = global.SyntaxError; |
| 34 | 33 |
| 35 utils.Import(function(from) { | |
| 36 GetScriptBreakPoints = from.GetScriptBreakPoints; | |
| 37 }); | |
| 38 | |
| 39 // ------------------------------------------------------------------- | 34 // ------------------------------------------------------------------- |
| 40 | 35 |
| 41 // Forward declaration for minifier. | 36 // Forward declaration for minifier. |
| 42 var FunctionStatus; | 37 var FunctionStatus; |
| 43 | 38 |
| 44 // Applies the change to the script. | 39 // Applies the change to the script. |
| 45 // The change is in form of list of chunks encoded in a single array as | 40 // The change is in form of list of chunks encoded in a single array as |
| 46 // a series of triplets (pos1_start, pos1_end, pos2_end) | 41 // a series of triplets (pos1_start, pos1_end, pos2_end) |
| 47 function ApplyPatchMultiChunk(script, diff_array, new_source, preview_only, | 42 function ApplyPatchMultiChunk(script, diff_array, new_source, preview_only, |
| 48 change_log) { | 43 change_log) { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 // Check that function being patched is not currently on stack or drop them. | 158 // Check that function being patched is not currently on stack or drop them. |
| 164 var dropped_functions_number = | 159 var dropped_functions_number = |
| 165 CheckStackActivations(replaced_function_old_infos, | 160 CheckStackActivations(replaced_function_old_infos, |
| 166 replaced_function_new_infos, | 161 replaced_function_new_infos, |
| 167 change_log); | 162 change_log); |
| 168 | 163 |
| 169 // Our current implementation requires client to manually issue "step in" | 164 // Our current implementation requires client to manually issue "step in" |
| 170 // command for correct stack state if the stack was modified. | 165 // command for correct stack state if the stack was modified. |
| 171 preview_description.stack_modified = dropped_functions_number != 0; | 166 preview_description.stack_modified = dropped_functions_number != 0; |
| 172 | 167 |
| 173 // Start with breakpoints. Convert their line/column positions and | |
| 174 // temporary remove. | |
| 175 var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log); | |
| 176 | |
| 177 var old_script; | 168 var old_script; |
| 178 | 169 |
| 179 // Create an old script only if there are function that should be linked | 170 // Create an old script only if there are function that should be linked |
| 180 // to old version. | 171 // to old version. |
| 181 if (link_to_old_script_list.length == 0) { | 172 if (link_to_old_script_list.length == 0) { |
| 182 %LiveEditReplaceScript(script, new_source, null); | 173 %LiveEditReplaceScript(script, new_source, null); |
| 183 old_script = UNDEFINED; | 174 old_script = UNDEFINED; |
| 184 } else { | 175 } else { |
| 185 var old_script_name = CreateNameForOldScript(script); | 176 var old_script_name = CreateNameForOldScript(script); |
| 186 | 177 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 position_patch_report); | 212 position_patch_report); |
| 222 | 213 |
| 223 if (update_positions_list[i].live_shared_function_infos) { | 214 if (update_positions_list[i].live_shared_function_infos) { |
| 224 update_positions_list[i].live_shared_function_infos. | 215 update_positions_list[i].live_shared_function_infos. |
| 225 forEach(function (info) { | 216 forEach(function (info) { |
| 226 %LiveEditFunctionSourceUpdated(info.raw_array); | 217 %LiveEditFunctionSourceUpdated(info.raw_array); |
| 227 }); | 218 }); |
| 228 } | 219 } |
| 229 } | 220 } |
| 230 | 221 |
| 231 break_points_restorer(pos_translator, old_script); | |
| 232 | |
| 233 preview_description.updated = true; | 222 preview_description.updated = true; |
| 234 return preview_description; | 223 return preview_description; |
| 235 } | 224 } |
| 236 | 225 |
| 237 // Fully compiles source string as a script. Returns Array of | 226 // Fully compiles source string as a script. Returns Array of |
| 238 // FunctionCompileInfo -- a descriptions of all functions of the script. | 227 // FunctionCompileInfo -- a descriptions of all functions of the script. |
| 239 // Elements of array are ordered by start positions of functions (from top | 228 // Elements of array are ordered by start positions of functions (from top |
| 240 // to bottom) in the source. Fields outer_index and next_sibling_index help | 229 // to bottom) in the source. Fields outer_index and next_sibling_index help |
| 241 // to navigate the nesting structure of functions. | 230 // to navigate the nesting structure of functions. |
| 242 // | 231 // |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 %LiveEditFunctionSetScript(info.info, old_script); | 350 %LiveEditFunctionSetScript(info.info, old_script); |
| 362 }); | 351 }); |
| 363 | 352 |
| 364 report_array.push( { name: old_info_node.info.function_name } ); | 353 report_array.push( { name: old_info_node.info.function_name } ); |
| 365 } else { | 354 } else { |
| 366 report_array.push( | 355 report_array.push( |
| 367 { name: old_info_node.info.function_name, not_found: true } ); | 356 { name: old_info_node.info.function_name, not_found: true } ); |
| 368 } | 357 } |
| 369 } | 358 } |
| 370 | 359 |
| 371 | |
| 372 // Returns function that restores breakpoints. | |
| 373 function TemporaryRemoveBreakPoints(original_script, change_log) { | |
| 374 var script_break_points = GetScriptBreakPoints(original_script); | |
| 375 | |
| 376 var break_points_update_report = []; | |
| 377 change_log.push( { break_points_update: break_points_update_report } ); | |
| 378 | |
| 379 var break_point_old_positions = []; | |
| 380 for (var i = 0; i < script_break_points.length; i++) { | |
| 381 var break_point = script_break_points[i]; | |
| 382 | |
| 383 break_point.clear(); | |
| 384 | |
| 385 // TODO(LiveEdit): be careful with resource offset here. | |
| 386 var break_point_position = FindScriptSourcePosition(original_script, | |
| 387 break_point.line(), break_point.column()); | |
| 388 | |
| 389 var old_position_description = { | |
| 390 position: break_point_position, | |
| 391 line: break_point.line(), | |
| 392 column: break_point.column() | |
| 393 }; | |
| 394 break_point_old_positions.push(old_position_description); | |
| 395 } | |
| 396 | |
| 397 | |
| 398 // Restores breakpoints and creates their copies in the "old" copy of | |
| 399 // the script. | |
| 400 return function (pos_translator, old_script_copy_opt) { | |
| 401 // Update breakpoints (change positions and restore them in old version | |
| 402 // of script. | |
| 403 for (var i = 0; i < script_break_points.length; i++) { | |
| 404 var break_point = script_break_points[i]; | |
| 405 if (old_script_copy_opt) { | |
| 406 var clone = break_point.cloneForOtherScript(old_script_copy_opt); | |
| 407 clone.set(old_script_copy_opt); | |
| 408 | |
| 409 break_points_update_report.push( { | |
| 410 type: "copied_to_old", | |
| 411 id: break_point.number(), | |
| 412 new_id: clone.number(), | |
| 413 positions: break_point_old_positions[i] | |
| 414 } ); | |
| 415 } | |
| 416 | |
| 417 var updated_position = pos_translator.Translate( | |
| 418 break_point_old_positions[i].position, | |
| 419 PosTranslator.ShiftWithTopInsideChunkHandler); | |
| 420 | |
| 421 var new_location = | |
| 422 original_script.locationFromPosition(updated_position, false); | |
| 423 | |
| 424 break_point.update_positions(new_location.line, new_location.column); | |
| 425 | |
| 426 var new_position_description = { | |
| 427 position: updated_position, | |
| 428 line: new_location.line, | |
| 429 column: new_location.column | |
| 430 }; | |
| 431 | |
| 432 break_point.set(original_script); | |
| 433 | |
| 434 break_points_update_report.push( { type: "position_changed", | |
| 435 id: break_point.number(), | |
| 436 old_positions: break_point_old_positions[i], | |
| 437 new_positions: new_position_description | |
| 438 } ); | |
| 439 } | |
| 440 }; | |
| 441 } | |
| 442 | |
| 443 | |
| 444 function Assert(condition, message) { | 360 function Assert(condition, message) { |
| 445 if (!condition) { | 361 if (!condition) { |
| 446 if (message) { | 362 if (message) { |
| 447 throw "Assert " + message; | 363 throw "Assert " + message; |
| 448 } else { | 364 } else { |
| 449 throw "Assert"; | 365 throw "Assert"; |
| 450 } | 366 } |
| 451 } | 367 } |
| 452 } | 368 } |
| 453 | 369 |
| (...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1115 | 1031 |
| 1116 LiveEdit.TestApi = { | 1032 LiveEdit.TestApi = { |
| 1117 PosTranslator: PosTranslator, | 1033 PosTranslator: PosTranslator, |
| 1118 CompareStrings: CompareStrings, | 1034 CompareStrings: CompareStrings, |
| 1119 ApplySingleChunkPatch: ApplySingleChunkPatch | 1035 ApplySingleChunkPatch: ApplySingleChunkPatch |
| 1120 }; | 1036 }; |
| 1121 | 1037 |
| 1122 global.Debug.LiveEdit = LiveEdit; | 1038 global.Debug.LiveEdit = LiveEdit; |
| 1123 | 1039 |
| 1124 }) | 1040 }) |
| OLD | NEW |