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

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

Issue 668246: Check that function being patched has no activations on any thread stack (Closed)
Patch Set: format Created 10 years, 9 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/runtime.h » ('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 29 matching lines...) Expand all
40 // during the change all nested functions are erased and completely different 40 // during the change all nested functions are erased and completely different
41 // set of nested functions are introduced.) All other functions just have 41 // set of nested functions are introduced.) All other functions just have
42 // their positions updated. 42 // their positions updated.
43 // 43 //
44 // @param {Script} script that is being changed 44 // @param {Script} script that is being changed
45 // @param {Array} change_log a list that collects engineer-readable description 45 // @param {Array} change_log a list that collects engineer-readable description
46 // of what happened. 46 // of what happened.
47 Debug.LiveEditChangeScript = function(script, change_pos, change_len, new_str, 47 Debug.LiveEditChangeScript = function(script, change_pos, change_len, new_str,
48 change_log) { 48 change_log) {
49 49
50 function Assert(condition, message) { 50 // So far the function works as namespace.
51 if (!condition) { 51 var liveedit = Debug.LiveEditChangeScript;
52 if (message) { 52 var Assert = liveedit.Assert;
53 throw "Assert " + message;
54 } else {
55 throw "Assert";
56 }
57 }
58 }
59
60 // An object describing function compilation details. Its index fields
61 // apply to indexes inside array that stores these objects.
62 function FunctionCompileInfo(raw_array) {
63 this.function_name = raw_array[0];
64 this.start_position = raw_array[1];
65 this.end_position = raw_array[2];
66 this.param_num = raw_array[3];
67 this.code = raw_array[4];
68 this.scope_info = raw_array[5];
69 this.outer_index = raw_array[6];
70 this.next_sibling_index = null;
71 this.raw_array = raw_array;
72 }
73
74 // A structure describing SharedFunctionInfo.
75 function SharedInfoWrapper(raw_array) {
76 this.function_name = raw_array[0];
77 this.start_position = raw_array[1];
78 this.end_position = raw_array[2];
79 this.info = raw_array[3];
80 this.raw_array = raw_array;
81 }
82
83 53
84 // Fully compiles source string as a script. Returns Array of 54 // Fully compiles source string as a script. Returns Array of
85 // FunctionCompileInfo -- a descriptions of all functions of the script. 55 // FunctionCompileInfo -- a descriptions of all functions of the script.
86 // Elements of array are ordered by start positions of functions (from top 56 // Elements of array are ordered by start positions of functions (from top
87 // to bottom) in the source. Fields outer_index and next_sibling_index help 57 // to bottom) in the source. Fields outer_index and next_sibling_index help
88 // to navigate the nesting structure of functions. 58 // to navigate the nesting structure of functions.
89 // 59 //
90 // The script is used for compilation, because it produces code that 60 // The script is used for compilation, because it produces code that
91 // needs to be linked with some particular script (for nested functions). 61 // needs to be linked with some particular script (for nested functions).
92 function DebugGatherCompileInfo(source) { 62 function DebugGatherCompileInfo(source) {
93 // Get function info, elements are partially sorted (it is a tree 63 // Get function info, elements are partially sorted (it is a tree
94 // of nested functions serialized as parent followed by serialized children. 64 // of nested functions serialized as parent followed by serialized children.
95 var raw_compile_info = %LiveEditGatherCompileInfo(script, source); 65 var raw_compile_info = %LiveEditGatherCompileInfo(script, source);
96 66
97 // Sort function infos by start position field. 67 // Sort function infos by start position field.
98 var compile_info = new Array(); 68 var compile_info = new Array();
99 var old_index_map = new Array(); 69 var old_index_map = new Array();
100 for (var i = 0; i < raw_compile_info.length; i++) { 70 for (var i = 0; i < raw_compile_info.length; i++) {
101 compile_info.push(new FunctionCompileInfo(raw_compile_info[i])); 71 compile_info.push(new liveedit.FunctionCompileInfo(raw_compile_info[i])) ;
102 old_index_map.push(i); 72 old_index_map.push(i);
103 } 73 }
104 74
105 for (var i = 0; i < compile_info.length; i++) { 75 for (var i = 0; i < compile_info.length; i++) {
106 var k = i; 76 var k = i;
107 for (var j = i + 1; j < compile_info.length; j++) { 77 for (var j = i + 1; j < compile_info.length; j++) {
108 if (compile_info[k].start_position > compile_info[j].start_position) { 78 if (compile_info[k].start_position > compile_info[j].start_position) {
109 k = j; 79 k = j;
110 } 80 }
111 } 81 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 // Now we are at the last function that begins before the change 132 // Now we are at the last function that begins before the change
163 // region. The function that covers entire change region is either 133 // region. The function that covers entire change region is either
164 // this function or the enclosing one. 134 // this function or the enclosing one.
165 for (; compile_info[index].end_position < offset + len; 135 for (; compile_info[index].end_position < offset + len;
166 index = compile_info[index].outer_index) { 136 index = compile_info[index].outer_index) {
167 Assert(index != -1); 137 Assert(index != -1);
168 } 138 }
169 return index; 139 return index;
170 } 140 }
171 141
172 // Compares a function interface old and new version, whether it
173 // changed or not.
174 function CompareFunctionExpectations(function_info1, function_info2) {
175 // Check that function has the same number of parameters (there may exist
176 // an adapter, that won't survive function parameter number change).
177 if (function_info1.param_num != function_info2.param_num) {
178 return false;
179 }
180 var scope_info1 = function_info1.scope_info;
181 var scope_info2 = function_info2.scope_info;
182
183 if (!scope_info1) {
184 return !scope_info2;
185 }
186
187 if (scope_info1.length != scope_info2.length) {
188 return false;
189 }
190
191 // Check that outer scope structure is not changed. Otherwise the function
192 // will not properly work with existing scopes.
193 return scope_info1.toString() == scope_info2.toString();
194 }
195
196 // Variable forward declarations. Preprocessor "Minifier" needs them. 142 // Variable forward declarations. Preprocessor "Minifier" needs them.
197 var old_compile_info; 143 var old_compile_info;
198 var shared_infos; 144 var shared_infos;
199 // Finds SharedFunctionInfo that corresponds compile info with index 145 // Finds SharedFunctionInfo that corresponds compile info with index
200 // in old version of the script. 146 // in old version of the script.
201 function FindFunctionInfo(index) { 147 function FindFunctionInfo(index) {
202 var old_info = old_compile_info[index]; 148 var old_info = old_compile_info[index];
203 for (var i = 0; i < shared_infos.length; i++) { 149 for (var i = 0; i < shared_infos.length; i++) {
204 var info = shared_infos[i]; 150 var info = shared_infos[i];
205 if (info.start_position == old_info.start_position && 151 if (info.start_position == old_info.start_position &&
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 var old_source = script.source; 204 var old_source = script.source;
259 var change_len_old = change_len; 205 var change_len_old = change_len;
260 var change_len_new = new_str.length; 206 var change_len_new = new_str.length;
261 207
262 // Prepare new source string. 208 // Prepare new source string.
263 var new_source = old_source.substring(0, change_pos) + 209 var new_source = old_source.substring(0, change_pos) +
264 new_str + old_source.substring(change_pos + change_len); 210 new_str + old_source.substring(change_pos + change_len);
265 211
266 // Find all SharedFunctionInfo's that are compiled from this script. 212 // Find all SharedFunctionInfo's that are compiled from this script.
267 var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script); 213 var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script);
214
215 var shared_infos = new Array();
216
217 for (var i = 0; i < shared_raw_list.length; i++) {
218 shared_infos.push(new liveedit.SharedInfoWrapper(shared_raw_list[i]));
219 }
268 220
269 // Gather compile information about old version of script. 221 // Gather compile information about old version of script.
270 var old_compile_info = DebugGatherCompileInfo(old_source); 222 var old_compile_info = DebugGatherCompileInfo(old_source);
271 223
272 // Gather compile information about new version of script. 224 // Gather compile information about new version of script.
273 var new_compile_info; 225 var new_compile_info;
274 try { 226 try {
275 new_compile_info = DebugGatherCompileInfo(new_source); 227 new_compile_info = DebugGatherCompileInfo(new_source);
276 } catch (e) { 228 } catch (e) {
277 throw "Failed to compile new version of script: " + e; 229 throw new liveedit.Failure("Failed to compile new version of script: " + e);
278 } 230 }
279 231
280 // An index of a single function, that is going to have its code replaced. 232 // An index of a single function, that is going to have its code replaced.
281 var function_being_patched = 233 var function_being_patched =
282 FindChangedFunction(old_compile_info, change_pos, change_len_old); 234 FindChangedFunction(old_compile_info, change_pos, change_len_old);
235
283 // In old and new script versions function with a change should have the 236 // In old and new script versions function with a change should have the
284 // same indexes. 237 // same indexes.
285 var function_being_patched2 = 238 var function_being_patched2 =
286 FindChangedFunction(new_compile_info, change_pos, change_len_new); 239 FindChangedFunction(new_compile_info, change_pos, change_len_new);
287 Assert(function_being_patched == function_being_patched2, 240 Assert(function_being_patched == function_being_patched2,
288 "inconsistent old/new compile info"); 241 "inconsistent old/new compile info");
289 242
290 // Check that function being patched has the same expectations in a new 243 // Check that function being patched has the same expectations in a new
291 // version. Otherwise we cannot safely patch its behavior and should 244 // version. Otherwise we cannot safely patch its behavior and should
292 // choose the outer function instead. 245 // choose the outer function instead.
293 while (!CompareFunctionExpectations(old_compile_info[function_being_patched], 246 while (!liveedit.CompareFunctionExpectations(
247 old_compile_info[function_being_patched],
294 new_compile_info[function_being_patched])) { 248 new_compile_info[function_being_patched])) {
295 249
296 Assert(old_compile_info[function_being_patched].outer_index == 250 Assert(old_compile_info[function_being_patched].outer_index ==
297 new_compile_info[function_being_patched].outer_index); 251 new_compile_info[function_being_patched].outer_index);
298 function_being_patched = 252 function_being_patched =
299 old_compile_info[function_being_patched].outer_index; 253 old_compile_info[function_being_patched].outer_index;
300 Assert(function_being_patched != -1); 254 Assert(function_being_patched != -1);
301 } 255 }
302 256
303 // TODO: Need to check here that there are no activations of the function 257 // Check that function being patched is not currently on stack.
304 // being patched on stack. 258 liveedit.CheckStackActivations(
259 [ FindFunctionInfo(function_being_patched) ], change_log );
260
305 261
306 // Committing all changes. 262 // Committing all changes.
307 var old_script_name = script.name + " (old)"; 263 var old_script_name = liveedit.CreateNameForOldScript(script);
308 264
309 // Update the script text and create a new script representing an old 265 // Update the script text and create a new script representing an old
310 // version of the script. 266 // version of the script.
311 var old_script = %LiveEditReplaceScript(script, new_source, old_script_name); 267 var old_script = %LiveEditReplaceScript(script, new_source, old_script_name);
312 268
313 var shared_infos = new Array();
314
315 for (var i = 0; i < shared_raw_list.length; i++) {
316 shared_infos.push(new SharedInfoWrapper(shared_raw_list[i]));
317 }
318
319 PatchCode(new_compile_info[function_being_patched], 269 PatchCode(new_compile_info[function_being_patched],
320 FindFunctionInfo(function_being_patched)); 270 FindFunctionInfo(function_being_patched));
321 271
322 var position_patch_report = new Array(); 272 var position_patch_report = new Array();
323 change_log.push( {position_patched: position_patch_report} ); 273 change_log.push( {position_patched: position_patch_report} );
324 274
325 var position_change_array = [ change_pos, 275 var position_change_array = [ change_pos,
326 change_pos + change_len_old, 276 change_pos + change_len_old,
327 change_pos + change_len_new ]; 277 change_pos + change_len_new ];
328 278
(...skipping 28 matching lines...) Expand all
357 307
358 var link_to_old_script_report = new Array(); 308 var link_to_old_script_report = new Array();
359 change_log.push( { linked_to_old_script: link_to_old_script_report } ); 309 change_log.push( { linked_to_old_script: link_to_old_script_report } );
360 310
361 // We need to link to old script all former nested functions. 311 // We need to link to old script all former nested functions.
362 for (var i = function_being_patched + 1; i < old_next_sibling; i++) { 312 for (var i = function_being_patched + 1; i < old_next_sibling; i++) {
363 LinkToOldScript(FindFunctionInfo(i), old_script); 313 LinkToOldScript(FindFunctionInfo(i), old_script);
364 } 314 }
365 } 315 }
366 316
317 Debug.LiveEditChangeScript.Assert = function(condition, message) {
318 if (!condition) {
319 if (message) {
320 throw "Assert " + message;
321 } else {
322 throw "Assert";
323 }
324 }
325 }
326
327 // An object describing function compilation details. Its index fields
328 // apply to indexes inside array that stores these objects.
329 Debug.LiveEditChangeScript.FunctionCompileInfo = function(raw_array) {
330 this.function_name = raw_array[0];
331 this.start_position = raw_array[1];
332 this.end_position = raw_array[2];
333 this.param_num = raw_array[3];
334 this.code = raw_array[4];
335 this.scope_info = raw_array[5];
336 this.outer_index = raw_array[6];
337 this.next_sibling_index = null;
338 this.raw_array = raw_array;
339 }
340
341 // A structure describing SharedFunctionInfo.
342 Debug.LiveEditChangeScript.SharedInfoWrapper = function(raw_array) {
343 this.function_name = raw_array[0];
344 this.start_position = raw_array[1];
345 this.end_position = raw_array[2];
346 this.info = raw_array[3];
347 this.raw_array = raw_array;
348 }
349
350 // Adds a suffix to script name to mark that it is old version.
351 Debug.LiveEditChangeScript.CreateNameForOldScript = function(script) {
352 // TODO(635): try better than this; support several changes.
353 return script.name + " (old)";
354 }
355
356 // Compares a function interface old and new version, whether it
357 // changed or not.
358 Debug.LiveEditChangeScript.CompareFunctionExpectations =
359 function(function_info1, function_info2) {
360 // Check that function has the same number of parameters (there may exist
361 // an adapter, that won't survive function parameter number change).
362 if (function_info1.param_num != function_info2.param_num) {
363 return false;
364 }
365 var scope_info1 = function_info1.scope_info;
366 var scope_info2 = function_info2.scope_info;
367
368 if (!scope_info1) {
369 return !scope_info2;
370 }
371
372 if (scope_info1.length != scope_info2.length) {
373 return false;
374 }
375
376 // Check that outer scope structure is not changed. Otherwise the function
377 // will not properly work with existing scopes.
378 return scope_info1.toString() == scope_info2.toString();
379 }
380
381 // For array of wrapped shared function infos checks that none of them
382 // have activations on stack (of any thread). Throws a Failure exception
383 // if this proves to be false.
384 Debug.LiveEditChangeScript.CheckStackActivations = function(shared_wrapper_list,
385 change_log) {
386 var liveedit = Debug.LiveEditChangeScript;
387
388 var shared_list = new Array();
389 for (var i = 0; i < shared_wrapper_list.length; i++) {
390 shared_list[i] = shared_wrapper_list[i].info;
391 }
392 var result = %LiveEditCheckStackActivations(shared_list);
393 var problems = new Array();
394 for (var i = 0; i < shared_list.length; i++) {
395 if (result[i] == liveedit.FunctionPatchabilityStatus.FUNCTION_BLOCKED_ON_STA CK) {
396 var shared = shared_list[i];
397 var description = {
398 name: shared.function_name,
399 start_pos: shared.start_position,
400 end_pos: shared.end_position
401 };
402 problems.push(description);
403 }
404 }
405 if (problems.length > 0) {
406 change_log.push( { functions_on_stack: problems } );
407 throw new liveedit.Failure("Blocked by functions on stack");
408 }
409 }
410
411 // A copy of the FunctionPatchabilityStatus enum from liveedit.h
412 Debug.LiveEditChangeScript.FunctionPatchabilityStatus = {
413 FUNCTION_AVAILABLE_FOR_PATCH: 0,
414 FUNCTION_BLOCKED_ON_STACK: 1
415 }
416
417
418 // A logical failure in liveedit process. This means that change_log
419 // is valid and consistent description of what happened.
420 Debug.LiveEditChangeScript.Failure = function(message) {
421 this.message = message;
422 }
423
424 Debug.LiveEditChangeScript.Failure.prototype.toString = function() {
425 return "LiveEdit Failure: " + this.message;
426 }
OLDNEW
« no previous file with comments | « src/liveedit.cc ('k') | src/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698