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

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

Issue 1158005: Remove the last of the obsolete *-delay.js files. This one... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 // LiveEdit feature implementation. The script should be executed after
29 // debug-delay.js.
30
31
32 // Changes script text and recompiles all relevant functions if possible.
33 // The change is always a substring (change_pos, change_pos + change_len)
34 // being replaced with a completely different string new_str.
35 //
36 // Only one function will have its Code changed in result of this function.
37 // All nested functions (should they have any instances at the moment) are left
38 // unchanged and re-linked to a newly created script instance representing old
39 // version of the source. (Generally speaking,
40 // during the change all nested functions are erased and completely different
41 // set of nested functions are introduced.) All other functions just have
42 // their positions updated.
43 //
44 // @param {Script} script that is being changed
45 // @param {Array} change_log a list that collects engineer-readable description
46 // of what happened.
47 Debug.LiveEditChangeScript = function(script, change_pos, change_len, new_str,
48 change_log) {
49
50 // So far the function works as namespace.
51 var liveedit = Debug.LiveEditChangeScript;
52 var Assert = liveedit.Assert;
53
54 // Fully compiles source string as a script. Returns Array of
55 // FunctionCompileInfo -- a descriptions of all functions of the script.
56 // Elements of array are ordered by start positions of functions (from top
57 // to bottom) in the source. Fields outer_index and next_sibling_index help
58 // to navigate the nesting structure of functions.
59 //
60 // The script is used for compilation, because it produces code that
61 // needs to be linked with some particular script (for nested functions).
62 function DebugGatherCompileInfo(source) {
63 // Get function info, elements are partially sorted (it is a tree
64 // of nested functions serialized as parent followed by serialized children.
65 var raw_compile_info = %LiveEditGatherCompileInfo(script, source);
66
67 // Sort function infos by start position field.
68 var compile_info = new Array();
69 var old_index_map = new Array();
70 for (var i = 0; i < raw_compile_info.length; i++) {
71 compile_info.push(new liveedit.FunctionCompileInfo(raw_compile_info[i])) ;
72 old_index_map.push(i);
73 }
74
75 for (var i = 0; i < compile_info.length; i++) {
76 var k = i;
77 for (var j = i + 1; j < compile_info.length; j++) {
78 if (compile_info[k].start_position > compile_info[j].start_position) {
79 k = j;
80 }
81 }
82 if (k != i) {
83 var temp_info = compile_info[k];
84 var temp_index = old_index_map[k];
85 compile_info[k] = compile_info[i];
86 old_index_map[k] = old_index_map[i];
87 compile_info[i] = temp_info;
88 old_index_map[i] = temp_index;
89 }
90 }
91
92 // After sorting update outer_inder field using old_index_map. Also
93 // set next_sibling_index field.
94 var current_index = 0;
95
96 // The recursive function, that goes over all children of a particular
97 // node (i.e. function info).
98 function ResetIndexes(new_parent_index, old_parent_index) {
99 var previous_sibling = -1;
100 while (current_index < compile_info.length &&
101 compile_info[current_index].outer_index == old_parent_index) {
102 var saved_index = current_index;
103 compile_info[saved_index].outer_index = new_parent_index;
104 if (previous_sibling != -1) {
105 compile_info[previous_sibling].next_sibling_index = saved_index;
106 }
107 previous_sibling = saved_index;
108 current_index++;
109 ResetIndexes(saved_index, old_index_map[saved_index]);
110 }
111 if (previous_sibling != -1) {
112 compile_info[previous_sibling].next_sibling_index = -1;
113 }
114 }
115
116 ResetIndexes(-1, -1);
117 Assert(current_index == compile_info.length);
118
119 return compile_info;
120 }
121
122 // Given a positions, finds a function that fully includes the entire change.
123 function FindChangedFunction(compile_info, offset, len) {
124 // First condition: function should start before the change region.
125 // Function #0 (whole-script function) always does, but we want
126 // one, that is later in this list.
127 var index = 0;
128 while (index + 1 < compile_info.length &&
129 compile_info[index + 1].start_position <= offset) {
130 index++;
131 }
132 // Now we are at the last function that begins before the change
133 // region. The function that covers entire change region is either
134 // this function or the enclosing one.
135 for (; compile_info[index].end_position < offset + len;
136 index = compile_info[index].outer_index) {
137 Assert(index != -1);
138 }
139 return index;
140 }
141
142 // Variable forward declarations. Preprocessor "Minifier" needs them.
143 var old_compile_info;
144 var shared_infos;
145 // Finds SharedFunctionInfo that corresponds compile info with index
146 // in old version of the script.
147 function FindFunctionInfo(index) {
148 var old_info = old_compile_info[index];
149 for (var i = 0; i < shared_infos.length; i++) {
150 var info = shared_infos[i];
151 if (info.start_position == old_info.start_position &&
152 info.end_position == old_info.end_position) {
153 return info;
154 }
155 }
156 }
157
158 // Replaces function's Code.
159 function PatchCode(new_info, shared_info) {
160 %LiveEditReplaceFunctionCode(new_info.raw_array, shared_info.raw_array);
161
162 change_log.push( {function_patched: new_info.function_name} );
163 }
164
165 var change_len_old;
166 var change_len_new;
167 // Translate position in old version of script into position in new
168 // version of script.
169 function PosTranslator(old_pos) {
170 if (old_pos <= change_pos) {
171 return old_pos;
172 }
173 if (old_pos >= change_pos + change_len_old) {
174 return old_pos + change_len_new - change_len_old;
175 }
176 return -1;
177 }
178
179 var position_change_array;
180 var position_patch_report;
181 function PatchPositions(new_info, shared_info) {
182 if (!shared_info) {
183 // TODO: explain what is happening.
184 return;
185 }
186 %LiveEditPatchFunctionPositions(shared_info.raw_array,
187 position_change_array);
188 position_patch_report.push( { name: new_info.function_name } );
189 }
190
191 var link_to_old_script_report;
192 var old_script;
193 // Makes a function associated with another instance of a script (the
194 // one representing its old version). This way the function still
195 // may access its own text.
196 function LinkToOldScript(shared_info) {
197 %LiveEditRelinkFunctionToScript(shared_info.raw_array, old_script);
198
199 link_to_old_script_report.push( { name: shared_info.function_name } );
200 }
201
202
203
204 var old_source = script.source;
205 var change_len_old = change_len;
206 var change_len_new = new_str.length;
207
208 // Prepare new source string.
209 var new_source = old_source.substring(0, change_pos) +
210 new_str + old_source.substring(change_pos + change_len);
211
212 // Find all SharedFunctionInfo's that are compiled from this 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 }
220
221 // Gather compile information about old version of script.
222 var old_compile_info = DebugGatherCompileInfo(old_source);
223
224 // Gather compile information about new version of script.
225 var new_compile_info;
226 try {
227 new_compile_info = DebugGatherCompileInfo(new_source);
228 } catch (e) {
229 throw new liveedit.Failure("Failed to compile new version of script: " + e);
230 }
231
232 // An index of a single function, that is going to have its code replaced.
233 var function_being_patched =
234 FindChangedFunction(old_compile_info, change_pos, change_len_old);
235
236 // In old and new script versions function with a change should have the
237 // same indexes.
238 var function_being_patched2 =
239 FindChangedFunction(new_compile_info, change_pos, change_len_new);
240 Assert(function_being_patched == function_being_patched2,
241 "inconsistent old/new compile info");
242
243 // Check that function being patched has the same expectations in a new
244 // version. Otherwise we cannot safely patch its behavior and should
245 // choose the outer function instead.
246 while (!liveedit.CompareFunctionExpectations(
247 old_compile_info[function_being_patched],
248 new_compile_info[function_being_patched])) {
249
250 Assert(old_compile_info[function_being_patched].outer_index ==
251 new_compile_info[function_being_patched].outer_index);
252 function_being_patched =
253 old_compile_info[function_being_patched].outer_index;
254 Assert(function_being_patched != -1);
255 }
256
257 // Check that function being patched is not currently on stack.
258 liveedit.CheckStackActivations(
259 [ FindFunctionInfo(function_being_patched) ], change_log );
260
261
262 // Committing all changes.
263 var old_script_name = liveedit.CreateNameForOldScript(script);
264
265 // Update the script text and create a new script representing an old
266 // version of the script.
267 var old_script = %LiveEditReplaceScript(script, new_source, old_script_name);
268
269 PatchCode(new_compile_info[function_being_patched],
270 FindFunctionInfo(function_being_patched));
271
272 var position_patch_report = new Array();
273 change_log.push( {position_patched: position_patch_report} );
274
275 var position_change_array = [ change_pos,
276 change_pos + change_len_old,
277 change_pos + change_len_new ];
278
279 // Update positions of all outer functions (i.e. all functions, that
280 // are partially below the function being patched).
281 for (var i = new_compile_info[function_being_patched].outer_index;
282 i != -1;
283 i = new_compile_info[i].outer_index) {
284 PatchPositions(new_compile_info[i], FindFunctionInfo(i));
285 }
286
287 // Update positions of all functions that are fully below the function
288 // being patched.
289 var old_next_sibling =
290 old_compile_info[function_being_patched].next_sibling_index;
291 var new_next_sibling =
292 new_compile_info[function_being_patched].next_sibling_index;
293
294 // We simply go over the tail of both old and new lists. Their tails should
295 // have an identical structure.
296 if (old_next_sibling == -1) {
297 Assert(new_next_sibling == -1);
298 } else {
299 Assert(old_compile_info.length - old_next_sibling ==
300 new_compile_info.length - new_next_sibling);
301
302 for (var i = old_next_sibling, j = new_next_sibling;
303 i < old_compile_info.length; i++, j++) {
304 PatchPositions(new_compile_info[j], FindFunctionInfo(i));
305 }
306 }
307
308 var link_to_old_script_report = new Array();
309 change_log.push( { linked_to_old_script: link_to_old_script_report } );
310
311 // We need to link to old script all former nested functions.
312 for (var i = function_being_patched + 1; i < old_next_sibling; i++) {
313 LinkToOldScript(FindFunctionInfo(i), old_script);
314 }
315 }
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 }
427
428 // A testing entry.
429 Debug.LiveEditChangeScript.GetPcFromSourcePos = function(func, source_pos) {
430 return %GetFunctionCodePositionFromSource(func, source_pos);
431 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698