| 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 |