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

Side by Side Diff: src/liveedit.cc

Issue 1652008: LiveEdit: calculate a real script difference (Closed)
Patch Set: static assert Created 10 years, 8 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.h ('k') | src/liveedit-debugger.js » ('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 24 matching lines...) Expand all
35 #include "global-handles.h" 35 #include "global-handles.h"
36 #include "debug.h" 36 #include "debug.h"
37 #include "memory.h" 37 #include "memory.h"
38 38
39 namespace v8 { 39 namespace v8 {
40 namespace internal { 40 namespace internal {
41 41
42 42
43 #ifdef ENABLE_DEBUGGER_SUPPORT 43 #ifdef ENABLE_DEBUGGER_SUPPORT
44 44
45
46 // A simple implementation of dynamic programming algorithm. It solves
47 // the problem of finding the difference of 2 arrays. It uses a table of results
48 // of subproblems. Each cell contains a number together with 2-bit flag
49 // that helps building the chunk list.
50 class Differencer {
51 public:
52 explicit Differencer(Compare::Input* input)
53 : input_(input), len1_(input->getLength1()), len2_(input->getLength2()) {
54 buffer_ = NewArray<int>(len1_ * len2_);
55 }
56 ~Differencer() {
57 DeleteArray(buffer_);
58 }
59
60 void Initialize() {
61 int array_size = len1_ * len2_;
62 for (int i = 0; i < array_size; i++) {
63 buffer_[i] = kEmptyCellValue;
64 }
65 }
66
67 // Makes sure that result for the full problem is calculated and stored
68 // in the table together with flags showing a path through subproblems.
69 void FillTable() {
70 CompareUpToTail(0, 0);
71 }
72
73 void SaveResult(Compare::Output* chunk_writer) {
74 ResultWriter writer(chunk_writer);
75
76 int pos1 = 0;
77 int pos2 = 0;
78 while (true) {
79 if (pos1 < len1_) {
80 if (pos2 < len2_) {
81 Direction dir = get_direction(pos1, pos2);
82 switch (dir) {
83 case EQ:
84 writer.eq();
85 pos1++;
86 pos2++;
87 break;
88 case SKIP1:
89 writer.skip1(1);
90 pos1++;
91 break;
92 case SKIP2:
93 case SKIP_ANY:
94 writer.skip2(1);
95 pos2++;
96 break;
97 default:
98 UNREACHABLE();
99 }
100 } else {
101 writer.skip1(len1_ - pos1);
102 break;
103 }
104 } else {
105 if (len2_ != pos2) {
106 writer.skip2(len2_ - pos2);
107 }
108 break;
109 }
110 }
111 writer.close();
112 }
113
114 private:
115 Compare::Input* input_;
116 int* buffer_;
117 int len1_;
118 int len2_;
119
120 enum Direction {
121 EQ = 0,
122 SKIP1,
123 SKIP2,
124 SKIP_ANY,
125
126 MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
127 };
128
129 // Computes result for a subtask and optionally caches it in the buffer table.
130 // All results values are shifted to make space for flags in the lower bits.
131 int CompareUpToTail(int pos1, int pos2) {
132 if (pos1 < len1_) {
133 if (pos2 < len2_) {
134 int cached_res = get_value4(pos1, pos2);
135 if (cached_res == kEmptyCellValue) {
136 Direction dir;
137 int res;
138 if (input_->equals(pos1, pos2)) {
139 res = CompareUpToTail(pos1 + 1, pos2 + 1);
140 dir = EQ;
141 } else {
142 int res1 = CompareUpToTail(pos1 + 1, pos2) +
143 (1 << kDirectionSizeBits);
144 int res2 = CompareUpToTail(pos1, pos2 + 1) +
145 (1 << kDirectionSizeBits);
146 if (res1 == res2) {
147 res = res1;
148 dir = SKIP_ANY;
149 } else if (res1 < res2) {
150 res = res1;
151 dir = SKIP1;
152 } else {
153 res = res2;
154 dir = SKIP2;
155 }
156 }
157 set_value4_and_dir(pos1, pos2, res, dir);
158 cached_res = res;
159 }
160 return cached_res;
161 } else {
162 return (len1_ - pos1) << kDirectionSizeBits;
163 }
164 } else {
165 return (len2_ - pos2) << kDirectionSizeBits;
166 }
167 }
168
169 inline int& get_cell(int i1, int i2) {
170 return buffer_[i1 + i2 * len1_];
171 }
172
173 // Each cell keeps a value plus direction. Value is multiplied by 4.
174 void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
175 ASSERT((value4 & kDirectionMask) == 0);
176 get_cell(i1, i2) = value4 | dir;
177 }
178
179 int get_value4(int i1, int i2) {
180 return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
181 }
182 Direction get_direction(int i1, int i2) {
183 return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
184 }
185
186 static const int kDirectionSizeBits = 2;
187 static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
188 static const int kEmptyCellValue = -1 << kDirectionSizeBits;
189
190 // This method only holds static assert statement (unfortunately you cannot
191 // place one in class scope).
192 void StaticAssertHolder() {
193 STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
194 }
195
196 class ResultWriter {
197 public:
198 explicit ResultWriter(Compare::Output* chunk_writer)
199 : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
200 pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
201 }
202 void eq() {
203 FlushChunk();
204 pos1_++;
205 pos2_++;
206 }
207 void skip1(int len1) {
208 StartChunk();
209 pos1_ += len1;
210 }
211 void skip2(int len2) {
212 StartChunk();
213 pos2_ += len2;
214 }
215 void close() {
216 FlushChunk();
217 }
218
219 private:
220 Compare::Output* chunk_writer_;
221 int pos1_;
222 int pos2_;
223 int pos1_begin_;
224 int pos2_begin_;
225 bool has_open_chunk_;
226
227 void StartChunk() {
228 if (!has_open_chunk_) {
229 pos1_begin_ = pos1_;
230 pos2_begin_ = pos2_;
231 has_open_chunk_ = true;
232 }
233 }
234
235 void FlushChunk() {
236 if (has_open_chunk_) {
237 chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
238 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
239 has_open_chunk_ = false;
240 }
241 }
242 };
243 };
244
245
246 void Compare::CalculateDifference(Compare::Input* input,
247 Compare::Output* result_writer) {
248 Differencer differencer(input);
249 differencer.Initialize();
250 differencer.FillTable();
251 differencer.SaveResult(result_writer);
252 }
253
254
255 static bool CompareSubstrings(Handle<String> s1, int pos1,
256 Handle<String> s2, int pos2, int len) {
257 static StringInputBuffer buf1;
258 static StringInputBuffer buf2;
259 buf1.Reset(*s1);
260 buf1.Seek(pos1);
261 buf2.Reset(*s2);
262 buf2.Seek(pos2);
263 for (int i = 0; i < len; i++) {
264 ASSERT(buf1.has_more() && buf2.has_more());
265 if (buf1.GetNext() != buf2.GetNext()) {
266 return false;
267 }
268 }
269 return true;
270 }
271
272
273 // Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
274 // never has terminating new line character.
275 class LineEndsWrapper {
276 public:
277 explicit LineEndsWrapper(Handle<String> string)
278 : ends_array_(CalculateLineEnds(string, false)),
279 string_len_(string->length()) {
280 }
281 int length() {
282 return ends_array_->length() + 1;
283 }
284 // Returns start for any line including start of the imaginary line after
285 // the last line.
286 int GetLineStart(int index) {
287 if (index == 0) {
288 return 0;
289 } else {
290 return GetLineEnd(index - 1);
291 }
292 }
293 int GetLineEnd(int index) {
294 if (index == ends_array_->length()) {
295 // End of the last line is always an end of the whole string.
296 // If the string ends with a new line character, the last line is an
297 // empty string after this character.
298 return string_len_;
299 } else {
300 return GetPosAfterNewLine(index);
301 }
302 }
303
304 private:
305 Handle<FixedArray> ends_array_;
306 int string_len_;
307
308 int GetPosAfterNewLine(int index) {
309 return Smi::cast(ends_array_->get(index))->value() + 1;
310 }
311 };
312
313
314 // Represents 2 strings as 2 arrays of lines.
315 class LineArrayCompareInput : public Compare::Input {
316 public:
317 LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
318 LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
319 : s1_(s1), s2_(s2), line_ends1_(line_ends1), line_ends2_(line_ends2) {
320 }
321 int getLength1() {
322 return line_ends1_.length();
323 }
324 int getLength2() {
325 return line_ends2_.length();
326 }
327 bool equals(int index1, int index2) {
328 int line_start1 = line_ends1_.GetLineStart(index1);
329 int line_start2 = line_ends2_.GetLineStart(index2);
330 int line_end1 = line_ends1_.GetLineEnd(index1);
331 int line_end2 = line_ends2_.GetLineEnd(index2);
332 int len1 = line_end1 - line_start1;
333 int len2 = line_end2 - line_start2;
334 if (len1 != len2) {
335 return false;
336 }
337 return CompareSubstrings(s1_, line_start1, s2_, line_start2, len1);
338 }
339
340 private:
341 Handle<String> s1_;
342 Handle<String> s2_;
343 LineEndsWrapper line_ends1_;
344 LineEndsWrapper line_ends2_;
345 };
346
347
348 // Stores compare result in JSArray. Each chunk is stored as 3 array elements:
349 // (pos1, len1, len2).
350 class LineArrayCompareOutput : public Compare::Output {
351 public:
352 LineArrayCompareOutput(LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
353 : array_(Factory::NewJSArray(10)), current_size_(0),
354 line_ends1_(line_ends1), line_ends2_(line_ends2) {
355 }
356
357 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
358 int char_pos1 = line_ends1_.GetLineStart(line_pos1);
359 int char_pos2 = line_ends2_.GetLineStart(line_pos2);
360 int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
361 int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
362
363 SetElement(array_, current_size_, Handle<Object>(Smi::FromInt(char_pos1)));
364 SetElement(array_, current_size_ + 1,
365 Handle<Object>(Smi::FromInt(char_len1)));
366 SetElement(array_, current_size_ + 2,
367 Handle<Object>(Smi::FromInt(char_len2)));
368 current_size_ += 3;
369 }
370
371 Handle<JSArray> GetResult() {
372 return array_;
373 }
374
375 private:
376 Handle<JSArray> array_;
377 int current_size_;
378 LineEndsWrapper line_ends1_;
379 LineEndsWrapper line_ends2_;
380 };
381
382
383 Handle<JSArray> LiveEdit::CompareStringsLinewise(Handle<String> s1,
384 Handle<String> s2) {
385 LineEndsWrapper line_ends1(s1);
386 LineEndsWrapper line_ends2(s2);
387
388 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
389 LineArrayCompareOutput output(line_ends1, line_ends2);
390
391 Compare::CalculateDifference(&input, &output);
392
393 return output.GetResult();
394 }
395
396
45 static void CompileScriptForTracker(Handle<Script> script) { 397 static void CompileScriptForTracker(Handle<Script> script) {
46 const bool is_eval = false; 398 const bool is_eval = false;
47 const bool is_global = true; 399 const bool is_global = true;
48 // TODO(635): support extensions. 400 // TODO(635): support extensions.
49 Extension* extension = NULL; 401 Extension* extension = NULL;
50 402
51 PostponeInterruptsScope postpone; 403 PostponeInterruptsScope postpone;
52 404
53 // Only allow non-global compiles for eval. 405 // Only allow non-global compiles for eval.
54 ASSERT(is_eval || is_global); 406 ASSERT(is_eval || is_global);
(...skipping 996 matching lines...) Expand 10 before | Expand all | Expand 10 after
1051 1403
1052 bool LiveEditFunctionTracker::IsActive() { 1404 bool LiveEditFunctionTracker::IsActive() {
1053 return false; 1405 return false;
1054 } 1406 }
1055 1407
1056 #endif // ENABLE_DEBUGGER_SUPPORT 1408 #endif // ENABLE_DEBUGGER_SUPPORT
1057 1409
1058 1410
1059 1411
1060 } } // namespace v8::internal 1412 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/liveedit.h ('k') | src/liveedit-debugger.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698