OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #include <iomanip> | 5 #include <iomanip> |
6 #include <sstream> | 6 #include <sstream> |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
(...skipping 8883 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8894 } | 8894 } |
8895 | 8895 |
8896 | 8896 |
8897 | 8897 |
8898 template <typename SourceChar> | 8898 template <typename SourceChar> |
8899 static void CalculateLineEndsImpl(Isolate* isolate, | 8899 static void CalculateLineEndsImpl(Isolate* isolate, |
8900 List<int>* line_ends, | 8900 List<int>* line_ends, |
8901 Vector<const SourceChar> src, | 8901 Vector<const SourceChar> src, |
8902 bool include_ending_line) { | 8902 bool include_ending_line) { |
8903 const int src_len = src.length(); | 8903 const int src_len = src.length(); |
8904 bool exotic_newlines = false; | |
8905 if (include_ending_line) { | |
8906 // Initally assume reduction is 1, ie all line endings are in the array. | |
8907 DCHECK_EQ(line_ends->length(), Script::kReductionIndex); | |
8908 line_ends->Add(1); | |
8909 // Write a placeholder for the number-of-lines indicator. | |
8910 DCHECK_EQ(line_ends->length(), Script::kNumberOfLinesIndex); | |
8911 line_ends->Add(0); | |
8912 DCHECK_EQ(line_ends->length(), Script::kFirstLineEndIndex); | |
8913 // There's a fictional newline just before the first character. This | |
8914 // simplifies a lot of things. | |
8915 line_ends->Add(-1); | |
8916 } | |
8917 UnicodeCache* cache = isolate->unicode_cache(); | 8904 UnicodeCache* cache = isolate->unicode_cache(); |
8918 for (int i = 0; i < src_len - 1; i++) { | 8905 for (int i = 0; i < src_len - 1; i++) { |
8919 SourceChar current = src[i]; | 8906 SourceChar current = src[i]; |
8920 SourceChar next = src[i + 1]; | 8907 SourceChar next = src[i + 1]; |
8921 if (cache->IsLineTerminatorSequence(current, next)) { | 8908 if (cache->IsLineTerminatorSequence(current, next)) line_ends->Add(i); |
8922 if (current != '\n' && current != '\r') exotic_newlines = true; | |
8923 line_ends->Add(i); | |
8924 } | |
8925 } | 8909 } |
8926 | 8910 |
8927 int last_posn = src_len - 1; | 8911 if (src_len > 0 && cache->IsLineTerminatorSequence(src[src_len - 1], 0)) { |
8928 if (last_posn >= 0 && cache->IsLineTerminatorSequence(src[last_posn], 0)) { | 8912 line_ends->Add(src_len - 1); |
8929 if (src[last_posn] != '\n' && src[last_posn] != '\r') | |
8930 exotic_newlines = true; | |
8931 line_ends->Add(last_posn); | |
8932 } else if (include_ending_line) { | 8913 } else if (include_ending_line) { |
8933 // Even if the last line misses a line end, it is counted. Because we | 8914 // Even if the last line misses a line end, it is counted. |
8934 // sometimes use character positions that are one beyond the end of the | 8915 line_ends->Add(src_len); |
8935 // source (see Rewriter::Rewrite) we set the newline one beyond that. | |
8936 // This is used for substr calculations, which trims to string length, | |
8937 // so it's harmless. | |
8938 line_ends->Add(last_posn + 1); | |
8939 } | |
8940 if (include_ending_line) { | |
8941 // Update number of lines in script. | |
8942 int lines = line_ends->length() - (Script::kFirstLineEndIndex + 1); | |
8943 line_ends->Set(Script::kNumberOfLinesIndex, lines); | |
8944 // Abuse some flags. The bots will run with a good variety of these flags, | |
8945 // giving better coverage for the reduction code. | |
8946 bool always_reduce = FLAG_always_opt; | |
8947 bool never_reduce = !FLAG_crankshaft; | |
8948 if (!never_reduce && !exotic_newlines && | |
8949 (always_reduce || | |
8950 (line_ends->length() > 5 && line_ends->length() * 8 > src_len / 12))) { | |
8951 // If the line-ends array (8 bytes per entry) is larger than about 8% | |
8952 // of the source length, then we reduce it to save memory. This won't | |
8953 // trigger if lines are > 100 characters on average. If it triggers, then | |
8954 // the goal is for it to take only 3% of the source size. | |
8955 int reduction = | |
8956 always_reduce ? 2 : (line_ends->length() * 8 * 33 / src_len); | |
8957 DCHECK(reduction > 1); | |
8958 line_ends->Set(Script::kReductionIndex, reduction); | |
8959 } | |
8960 } | 8916 } |
8961 } | 8917 } |
8962 | 8918 |
8963 | 8919 |
8964 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src, | 8920 Handle<FixedArray> String::CalculateLineEnds(Handle<String> src, |
8965 bool include_ending_line) { | 8921 bool include_ending_line) { |
8966 src = Flatten(src); | 8922 src = Flatten(src); |
8967 // Rough estimate of line count based on a roughly estimated average | 8923 // Rough estimate of line count based on a roughly estimated average |
8968 // length of (unpacked) code. | 8924 // length of (unpacked) code. |
8969 int line_count_estimate = src->length() >> 4; | 8925 int line_count_estimate = src->length() >> 4; |
8970 List<int> line_ends(line_count_estimate); | 8926 List<int> line_ends(line_count_estimate); |
8971 Isolate* isolate = src->GetIsolate(); | 8927 Isolate* isolate = src->GetIsolate(); |
8972 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid. | 8928 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid. |
8973 // Dispatch on type of strings. | 8929 // Dispatch on type of strings. |
8974 String::FlatContent content = src->GetFlatContent(); | 8930 String::FlatContent content = src->GetFlatContent(); |
8975 DCHECK(content.IsFlat()); | 8931 DCHECK(content.IsFlat()); |
8976 if (content.IsOneByte()) { | 8932 if (content.IsOneByte()) { |
8977 CalculateLineEndsImpl(isolate, | 8933 CalculateLineEndsImpl(isolate, |
8978 &line_ends, | 8934 &line_ends, |
8979 content.ToOneByteVector(), | 8935 content.ToOneByteVector(), |
8980 include_ending_line); | 8936 include_ending_line); |
8981 } else { | 8937 } else { |
8982 CalculateLineEndsImpl(isolate, | 8938 CalculateLineEndsImpl(isolate, |
8983 &line_ends, | 8939 &line_ends, |
8984 content.ToUC16Vector(), | 8940 content.ToUC16Vector(), |
8985 include_ending_line); | 8941 include_ending_line); |
8986 } | 8942 } |
8987 } | 8943 } |
8988 if (include_ending_line) { | 8944 int line_count = line_ends.length(); |
8989 const int kReductionIndex = Script::kReductionIndex; | 8945 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count); |
8990 const int kFirstLineEndIndex = Script::kFirstLineEndIndex; | 8946 for (int i = 0; i < line_count; i++) { |
8991 int line_count = line_ends.length() - kFirstLineEndIndex; | 8947 array->set(i, Smi::FromInt(line_ends[i])); |
8992 int reduction = line_ends[kReductionIndex]; | |
8993 int reduced_lines = (line_count + reduction - 1) / reduction; | |
8994 Handle<FixedArray> array = | |
8995 isolate->factory()->NewFixedArray(kFirstLineEndIndex + reduced_lines); | |
8996 for (int i = 0; i < kFirstLineEndIndex; i++) { | |
8997 array->set(i, Smi::FromInt(line_ends[i])); | |
8998 } | |
8999 int j = kFirstLineEndIndex; | |
9000 for (int i = 0; i < line_count; i += reduction, ++j) { | |
9001 array->set(j, Smi::FromInt(line_ends[i + kFirstLineEndIndex])); | |
9002 } | |
9003 return array; | |
9004 } else { | |
9005 Handle<FixedArray> array = | |
9006 isolate->factory()->NewFixedArray(line_ends.length()); | |
9007 for (int i = 0; i < line_ends.length(); i++) { | |
9008 array->set(i, Smi::FromInt(line_ends[i])); | |
9009 } | |
9010 return array; | |
9011 } | 8948 } |
| 8949 return array; |
9012 } | 8950 } |
9013 | 8951 |
9014 | 8952 |
9015 // Compares the contents of two strings by reading and comparing | 8953 // Compares the contents of two strings by reading and comparing |
9016 // int-sized blocks of characters. | 8954 // int-sized blocks of characters. |
9017 template <typename Char> | 8955 template <typename Char> |
9018 static inline bool CompareRawStringContents(const Char* const a, | 8956 static inline bool CompareRawStringContents(const Char* const a, |
9019 const Char* const b, | 8957 const Char* const b, |
9020 int length) { | 8958 int length) { |
9021 return CompareChars(a, b, length) == 0; | 8959 return CompareChars(a, b, length) == 0; |
(...skipping 1337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10359 | 10297 |
10360 if (*array != isolate->heap()->empty_fixed_array()) { | 10298 if (*array != isolate->heap()->empty_fixed_array()) { |
10361 array->set_map(isolate->heap()->fixed_cow_array_map()); | 10299 array->set_map(isolate->heap()->fixed_cow_array_map()); |
10362 } | 10300 } |
10363 | 10301 |
10364 script->set_line_ends(*array); | 10302 script->set_line_ends(*array); |
10365 DCHECK(script->line_ends()->IsFixedArray()); | 10303 DCHECK(script->line_ends()->IsFixedArray()); |
10366 } | 10304 } |
10367 | 10305 |
10368 | 10306 |
10369 static int CountForwardNNewlines(Handle<Script> script, int block_position, | |
10370 int n) { | |
10371 int position = block_position; | |
10372 Handle<Object> source_object(script->source(), script->GetIsolate()); | |
10373 if (!source_object->IsString() || n == 0) return position; | |
10374 Handle<String> source(Handle<String>::cast(source_object)); | |
10375 int length = source->length(); | |
10376 for (int i = position; i < length; i++) { | |
10377 uc16 current = source->Get(i); | |
10378 if (current == '\r') { | |
10379 n--; | |
10380 if (i + 1 < length && source->Get(i + 1) == '\n') i++; | |
10381 } else if (current == '\n') { | |
10382 n--; | |
10383 } | |
10384 if (n == 0) return i + 1; | |
10385 } | |
10386 if (n == 1 && length > 0) { | |
10387 uc16 last = source->Get(length - 1); | |
10388 if (last != '\n' && last != '\r') return length; | |
10389 } | |
10390 return -1; | |
10391 } | |
10392 | |
10393 | |
10394 int Script::GetColumnNumber(Handle<Script> script, int code_pos) { | 10307 int Script::GetColumnNumber(Handle<Script> script, int code_pos) { |
10395 // Get zero-based line number. | |
10396 int line_number = GetLineNumber(script, code_pos); | 10308 int line_number = GetLineNumber(script, code_pos); |
10397 if (line_number == -1) return -1; | 10309 if (line_number == -1) return -1; |
10398 | 10310 |
10399 DisallowHeapAllocation no_allocation; | 10311 DisallowHeapAllocation no_allocation; |
10400 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); | 10312 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); |
10401 line_number = line_number - script->line_offset()->value(); | 10313 line_number = line_number - script->line_offset()->value(); |
10402 int reduction = Smi::cast(line_ends_array->get(kReductionIndex))->value(); | 10314 if (line_number == 0) return code_pos + script->column_offset()->value(); |
10403 | 10315 int prev_line_end_pos = |
10404 int line_block_position = | 10316 Smi::cast(line_ends_array->get(line_number - 1))->value(); |
10405 Smi::cast(line_ends_array->get(line_number / reduction + | 10317 return code_pos - (prev_line_end_pos + 1); |
10406 kFirstLineEndIndex))->value() + | |
10407 1; | |
10408 | |
10409 int line_position = CountForwardNNewlines(script, line_block_position, | |
10410 line_number % reduction); | |
10411 if (line_number == 0) line_position = -script->column_offset()->value(); | |
10412 return code_pos - line_position; | |
10413 } | 10318 } |
10414 | 10319 |
10415 | 10320 |
10416 // Zero-based line number, calculated from UTF16 character position. | |
10417 int Script::GetLineNumberWithArray(int code_pos) { | 10321 int Script::GetLineNumberWithArray(int code_pos) { |
10418 DisallowHeapAllocation no_allocation; | 10322 DisallowHeapAllocation no_allocation; |
10419 DCHECK(line_ends()->IsFixedArray()); | 10323 DCHECK(line_ends()->IsFixedArray()); |
10420 FixedArray* line_ends_array = FixedArray::cast(line_ends()); | 10324 FixedArray* line_ends_array = FixedArray::cast(line_ends()); |
10421 int line_ends_len = line_ends_array->length(); | 10325 int line_ends_len = line_ends_array->length(); |
10422 if (line_ends_len == 0) return -1; // This happens if there is no source. | 10326 if (line_ends_len == 0) return -1; |
10423 // There's always at least one line ending: A fictional newline just before | |
10424 // the start. | |
10425 DCHECK_GE(line_ends_len, kFirstLineEndIndex + 1); | |
10426 int lower = kFirstLineEndIndex; | |
10427 int upper = line_ends_len - 1; | |
10428 | 10327 |
10429 if (code_pos < 0) return -1; | 10328 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) { |
10430 int index = 0; | 10329 return line_offset()->value(); |
10431 | |
10432 if (code_pos > Smi::cast(line_ends_array->get(upper))->value()) { | |
10433 index = upper; | |
10434 } else { | |
10435 while (lower + 1 < upper) { | |
10436 DCHECK_LE(Smi::cast(line_ends_array->get(lower))->value(), code_pos); | |
10437 DCHECK_LE(code_pos, Smi::cast(line_ends_array->get(upper))->value()); | |
10438 int i = (lower + upper) >> 1; | |
10439 DCHECK(lower != i && upper != i); | |
10440 if ((Smi::cast(line_ends_array->get(i)))->value() >= code_pos) { | |
10441 upper = i; | |
10442 } else { | |
10443 lower = i; | |
10444 } | |
10445 } | |
10446 index = lower; | |
10447 } | 10330 } |
10448 | 10331 |
10449 int reduction = Smi::cast(line_ends_array->get(kReductionIndex))->value(); | 10332 int left = 0; |
10450 int line_number = (index - kFirstLineEndIndex) * reduction; | 10333 int right = line_ends_len; |
10451 | 10334 while (int half = (right - left) / 2) { |
10452 // We only saved an nth of the line ends in the array, because there were so | 10335 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) { |
10453 // many. | 10336 right -= half; |
10454 int start_of_earlier_line = | 10337 } else { |
10455 Smi::cast(line_ends_array->get(index))->value() + 1; | 10338 left += half; |
10456 | |
10457 if (reduction == 1 || !source()->IsString()) { | |
10458 return line_number + line_offset()->value(); | |
10459 } | |
10460 String* src = String::cast(source()); | |
10461 // This '>' would normally be a '>=', but due to {}-less 'with' statements in | |
10462 // top-level code we sometimes encounter code positions that are one character | |
10463 // after the end of the source. See comment in Rewriter::Rewrite. | |
10464 if (code_pos > src->length()) return -1; | |
10465 for (int i = start_of_earlier_line; i < src->length() && i < code_pos; i++) { | |
10466 uc16 current = src->Get(i); | |
10467 if (current == '\r') { | |
10468 if (i < code_pos - 1 && i < src->length() - 1 && src->Get(i + 1) == '\n') | |
10469 i++; | |
10470 line_number++; | |
10471 } else if (current == '\n') { | |
10472 line_number++; | |
10473 } | 10339 } |
10474 } | 10340 } |
10475 return line_number + line_offset()->value(); | 10341 return right + line_offset()->value(); |
10476 } | 10342 } |
10477 | 10343 |
10478 | 10344 |
10479 int Script::GetLineNumber(Handle<Script> script, int code_pos) { | 10345 int Script::GetLineNumber(Handle<Script> script, int code_pos) { |
10480 InitLineEnds(script); | 10346 InitLineEnds(script); |
10481 return script->GetLineNumberWithArray(code_pos); | 10347 return script->GetLineNumberWithArray(code_pos); |
10482 } | 10348 } |
10483 | 10349 |
10484 | 10350 |
10485 int Script::GetLineNumber(int code_pos) { | 10351 int Script::GetLineNumber(int code_pos) { |
(...skipping 6616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17102 Handle<Object> new_value) { | 16968 Handle<Object> new_value) { |
17103 if (cell->value() != *new_value) { | 16969 if (cell->value() != *new_value) { |
17104 cell->set_value(*new_value); | 16970 cell->set_value(*new_value); |
17105 Isolate* isolate = cell->GetIsolate(); | 16971 Isolate* isolate = cell->GetIsolate(); |
17106 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16972 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
17107 isolate, DependentCode::kPropertyCellChangedGroup); | 16973 isolate, DependentCode::kPropertyCellChangedGroup); |
17108 } | 16974 } |
17109 } | 16975 } |
17110 } // namespace internal | 16976 } // namespace internal |
17111 } // namespace v8 | 16977 } // namespace v8 |
OLD | NEW |