LCOV - code coverage report
Current view: top level - src - string-stream.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 183 246 74.4 %
Date: 2019-02-19 Functions: 21 24 87.5 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/string-stream.h"
       6             : 
       7             : #include <memory>
       8             : 
       9             : #include "src/handles-inl.h"
      10             : #include "src/log.h"
      11             : #include "src/objects-inl.h"
      12             : #include "src/objects/js-array-inl.h"
      13             : #include "src/prototype.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : static const int kMentionedObjectCacheMaxSize = 256;
      19             : 
      20       83370 : char* HeapStringAllocator::allocate(unsigned bytes) {
      21       83370 :   space_ = NewArray<char>(bytes);
      22       83370 :   return space_;
      23             : }
      24             : 
      25             : 
      26          15 : char* FixedStringAllocator::allocate(unsigned bytes) {
      27          15 :   CHECK_LE(bytes, length_);
      28          15 :   return buffer_;
      29             : }
      30             : 
      31             : 
      32           0 : char* FixedStringAllocator::grow(unsigned* old) {
      33           0 :   *old = length_;
      34           0 :   return buffer_;
      35             : }
      36             : 
      37             : 
      38     5083157 : bool StringStream::Put(char c) {
      39     5083157 :   if (full()) return false;
      40             :   DCHECK(length_ < capacity_);
      41             :   // Since the trailing '\0' is not accounted for in length_ fullness is
      42             :   // indicated by a difference of 1 between length_ and capacity_. Thus when
      43             :   // reaching a difference of 2 we need to grow the buffer.
      44     5083157 :   if (length_ == capacity_ - 2) {
      45      198369 :     unsigned new_capacity = capacity_;
      46      198369 :     char* new_buffer = allocator_->grow(&new_capacity);
      47      198369 :     if (new_capacity > capacity_) {
      48      198369 :       capacity_ = new_capacity;
      49      198369 :       buffer_ = new_buffer;
      50             :     } else {
      51             :       // Reached the end of the available buffer.
      52             :       DCHECK_GE(capacity_, 5);
      53           0 :       length_ = capacity_ - 1;  // Indicate fullness of the stream.
      54           0 :       buffer_[length_ - 4] = '.';
      55           0 :       buffer_[length_ - 3] = '.';
      56           0 :       buffer_[length_ - 2] = '.';
      57           0 :       buffer_[length_ - 1] = '\n';
      58           0 :       buffer_[length_] = '\0';
      59           0 :       return false;
      60             :     }
      61             :   }
      62     5083157 :   buffer_[length_] = c;
      63     5083157 :   buffer_[length_ + 1] = '\0';
      64     5083157 :   length_++;
      65     5083157 :   return true;
      66             : }
      67             : 
      68             : 
      69             : // A control character is one that configures a format element.  For
      70             : // instance, in %.5s, .5 are control characters.
      71             : static bool IsControlChar(char c) {
      72             :   switch (c) {
      73             :   case '0': case '1': case '2': case '3': case '4': case '5':
      74             :   case '6': case '7': case '8': case '9': case '.': case '-':
      75             :     return true;
      76             :   default:
      77             :     return false;
      78             :   }
      79             : }
      80             : 
      81             : 
      82      871920 : void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) {
      83             :   // If we already ran out of space then return immediately.
      84      871920 :   if (full()) return;
      85             :   int offset = 0;
      86             :   int elm = 0;
      87     6121197 :   while (offset < format.length()) {
      88    11202501 :     if (format[offset] != '%' || elm == elms.length()) {
      89     4545338 :       Put(format[offset]);
      90     4545338 :       offset++;
      91     4545338 :       continue;
      92             :     }
      93             :     // Read this formatting directive into a temporary buffer
      94             :     EmbeddedVector<char, 24> temp;
      95             :     int format_length = 0;
      96             :     // Skip over the whole control character sequence until the
      97             :     // format element type
      98      703939 :     temp[format_length++] = format[offset++];
      99     3607583 :     while (offset < format.length() && IsControlChar(format[offset]))
     100     2243649 :       temp[format_length++] = format[offset++];
     101      703939 :     if (offset >= format.length())
     102           0 :       return;
     103     1407878 :     char type = format[offset];
     104     1407878 :     temp[format_length++] = type;
     105     1407878 :     temp[format_length] = '\0';
     106      703939 :     offset++;
     107     1407878 :     FmtElm current = elms[elm++];
     108      703939 :     switch (type) {
     109             :     case 's': {
     110             :       DCHECK_EQ(FmtElm::C_STR, current.type_);
     111      207339 :       const char* value = current.data_.u_c_str_;
     112      207339 :       Add(value);
     113      207339 :       break;
     114             :     }
     115             :     case 'w': {
     116             :       DCHECK_EQ(FmtElm::LC_STR, current.type_);
     117           0 :       Vector<const uc16> value = *current.data_.u_lc_str_;
     118           0 :       for (int i = 0; i < value.length(); i++)
     119           0 :         Put(static_cast<char>(value[i]));
     120             :       break;
     121             :     }
     122             :     case 'o': {
     123             :       DCHECK_EQ(FmtElm::OBJ, current.type_);
     124         549 :       Object obj(current.data_.u_obj_);
     125         549 :       PrintObject(obj);
     126             :       break;
     127             :     }
     128             :     case 'k': {
     129             :       DCHECK_EQ(FmtElm::INT, current.type_);
     130           0 :       int value = current.data_.u_int_;
     131           0 :       if (0x20 <= value && value <= 0x7F) {
     132           0 :         Put(value);
     133           0 :       } else if (value <= 0xFF) {
     134           0 :         Add("\\x%02x", value);
     135             :       } else {
     136           0 :         Add("\\u%04x", value);
     137             :       }
     138             :       break;
     139             :     }
     140             :     case 'i': case 'd': case 'u': case 'x': case 'c': case 'X': {
     141      465424 :       int value = current.data_.u_int_;
     142             :       EmbeddedVector<char, 24> formatted;
     143      465424 :       int length = SNPrintF(formatted, temp.start(), value);
     144      930848 :       Add(Vector<const char>(formatted.start(), length));
     145             :       break;
     146             :     }
     147             :     case 'f': case 'g': case 'G': case 'e': case 'E': {
     148           0 :       double value = current.data_.u_double_;
     149           0 :       int inf = std::isinf(value);
     150           0 :       if (inf == -1) {
     151           0 :         Add("-inf");
     152           0 :       } else if (inf == 1) {
     153           0 :         Add("inf");
     154           0 :       } else if (std::isnan(value)) {
     155           0 :         Add("nan");
     156             :       } else {
     157             :         EmbeddedVector<char, 28> formatted;
     158           0 :         SNPrintF(formatted, temp.start(), value);
     159           0 :         Add(formatted.start());
     160             :       }
     161             :       break;
     162             :     }
     163             :     case 'p': {
     164       30627 :       void* value = current.data_.u_pointer_;
     165             :       EmbeddedVector<char, 20> formatted;
     166       30627 :       SNPrintF(formatted, temp.start(), value);
     167       30627 :       Add(formatted.start());
     168             :       break;
     169             :     }
     170             :     default:
     171           0 :       UNREACHABLE();
     172             :       break;
     173             :     }
     174             :   }
     175             : 
     176             :   // Verify that the buffer is 0-terminated
     177             :   DCHECK_EQ(buffer_[length_], '\0');
     178             : }
     179             : 
     180         549 : void StringStream::PrintObject(Object o) {
     181         549 :   o->ShortPrint(this);
     182         549 :   if (o->IsString()) {
     183          49 :     if (String::cast(o)->length() <= String::kMaxShortPrintLength) {
     184             :       return;
     185             :     }
     186         872 :   } else if (o->IsNumber() || o->IsOddball()) {
     187             :     return;
     188             :   }
     189         337 :   if (o->IsHeapObject() && object_print_mode_ == kPrintObjectVerbose) {
     190             :     // TODO(delphick): Consider whether we can get the isolate without using
     191             :     // TLS.
     192        3893 :     DebugObjectCache* debug_object_cache =
     193         337 :         Isolate::Current()->string_stream_debug_object_cache();
     194        7786 :     for (size_t i = 0; i < debug_object_cache->size(); i++) {
     195        3647 :       if ((*debug_object_cache)[i] == o) {
     196          91 :         Add("#%d#", static_cast<int>(i));
     197          91 :         return;
     198             :       }
     199             :     }
     200         246 :     if (debug_object_cache->size() < kMentionedObjectCacheMaxSize) {
     201         246 :       Add("#%d#", static_cast<int>(debug_object_cache->size()));
     202         492 :       debug_object_cache->push_back(HeapObject::cast(o));
     203             :     } else {
     204           0 :       Add("@%p", o);
     205             :     }
     206             :   }
     207             : }
     208             : 
     209       83353 : std::unique_ptr<char[]> StringStream::ToCString() const {
     210       83353 :   char* str = NewArray<char>(length_ + 1);
     211       83353 :   MemCopy(str, buffer_, length_);
     212       83353 :   str[length_] = '\0';
     213       83353 :   return std::unique_ptr<char[]>(str);
     214             : }
     215             : 
     216             : 
     217          17 : void StringStream::Log(Isolate* isolate) {
     218          17 :   LOG(isolate, StringEvent("StackDump", buffer_));
     219          17 : }
     220             : 
     221             : 
     222          17 : void StringStream::OutputToFile(FILE* out) {
     223             :   // Dump the output to stdout, but make sure to break it up into
     224             :   // manageable chunks to avoid losing parts of the output in the OS
     225             :   // printing code. This is a problem on Windows in particular; see
     226             :   // the VPrint() function implementations in platform-win32.cc.
     227             :   unsigned position = 0;
     228          63 :   for (unsigned next; (next = position + 2048) < length_; position = next) {
     229          29 :     char save = buffer_[next];
     230          29 :     buffer_[next] = '\0';
     231          29 :     internal::PrintF(out, "%s", &buffer_[position]);
     232          29 :     buffer_[next] = save;
     233             :   }
     234          17 :   internal::PrintF(out, "%s", &buffer_[position]);
     235          17 : }
     236             : 
     237             : 
     238           0 : Handle<String> StringStream::ToString(Isolate* isolate) {
     239             :   return isolate->factory()->NewStringFromUtf8(
     240           0 :       Vector<const char>(buffer_, length_)).ToHandleChecked();
     241             : }
     242             : 
     243             : 
     244          69 : void StringStream::ClearMentionedObjectCache(Isolate* isolate) {
     245             :   isolate->set_string_stream_current_security_token(Object());
     246          23 :   if (isolate->string_stream_debug_object_cache() == nullptr) {
     247          15 :     isolate->set_string_stream_debug_object_cache(new DebugObjectCache());
     248             :   }
     249             :   isolate->string_stream_debug_object_cache()->clear();
     250          23 : }
     251             : 
     252             : 
     253             : #ifdef DEBUG
     254             : bool StringStream::IsMentionedObjectCacheClear(Isolate* isolate) {
     255             :   return object_print_mode_ == kPrintObjectConcise ||
     256             :          isolate->string_stream_debug_object_cache()->size() == 0;
     257             : }
     258             : #endif
     259             : 
     260       51355 : bool StringStream::Put(String str) { return Put(str, 0, str->length()); }
     261             : 
     262       25857 : bool StringStream::Put(String str, int start, int end) {
     263       25857 :   StringCharacterStream stream(str, start);
     264      191988 :   for (int i = start; i < end && stream.HasMore(); i++) {
     265      166131 :     uint16_t c = stream.GetNext();
     266      166131 :     if (c >= 127 || c < 32) {
     267             :       c = '?';
     268             :     }
     269      166131 :     if (!Put(static_cast<char>(c))) {
     270             :       return false;  // Output was truncated.
     271             :     }
     272             :   }
     273             :   return true;
     274             : }
     275             : 
     276         139 : void StringStream::PrintName(Object name) {
     277         139 :   if (name->IsString()) {
     278             :     String str = String::cast(name);
     279         139 :     if (str->length() > 0) {
     280             :       Put(str);
     281             :     } else {
     282          25 :       Add("/* anonymous */");
     283             :     }
     284             :   } else {
     285           0 :     Add("%o", name);
     286             :   }
     287         139 : }
     288             : 
     289         205 : void StringStream::PrintUsingMap(JSObject js_object) {
     290         205 :   Map map = js_object->map();
     291             :   int real_size = map->NumberOfOwnDescriptors();
     292         205 :   DescriptorArray descs = map->instance_descriptors();
     293         639 :   for (int i = 0; i < real_size; i++) {
     294         434 :     PropertyDetails details = descs->GetDetails(i);
     295         434 :     if (details.location() == kField) {
     296             :       DCHECK_EQ(kData, details.kind());
     297         245 :       Object key = descs->GetKey(i);
     298         245 :       if (key->IsString() || key->IsNumber()) {
     299             :         int len = 3;
     300         245 :         if (key->IsString()) {
     301             :           len = String::cast(key)->length();
     302             :         }
     303        2499 :         for (; len < 18; len++)
     304        2499 :           Put(' ');
     305         245 :         if (key->IsString()) {
     306             :           Put(String::cast(key));
     307             :         } else {
     308           0 :           key->ShortPrint();
     309             :         }
     310         245 :         Add(": ");
     311         245 :         FieldIndex index = FieldIndex::ForDescriptor(map, i);
     312         245 :         if (js_object->IsUnboxedDoubleField(index)) {
     313             :           double value = js_object->RawFastDoublePropertyAt(index);
     314           0 :           Add("<unboxed double> %.16g\n", FmtElm(value));
     315             :         } else {
     316         245 :           Object value = js_object->RawFastPropertyAt(index);
     317         245 :           Add("%o\n", value);
     318             :         }
     319             :       }
     320             :     }
     321             :   }
     322         205 : }
     323             : 
     324          42 : void StringStream::PrintFixedArray(FixedArray array, unsigned int limit) {
     325          42 :   ReadOnlyRoots roots = array->GetReadOnlyRoots();
     326         112 :   for (unsigned int i = 0; i < 10 && i < limit; i++) {
     327         140 :     Object element = array->get(i);
     328          70 :     if (element->IsTheHole(roots)) continue;
     329        1190 :     for (int len = 1; len < 18; len++) {
     330        1190 :       Put(' ');
     331             :     }
     332          70 :     Add("%d: %o\n", i, array->get(i));
     333             :   }
     334          42 :   if (limit >= 10) {
     335           0 :     Add("                  ...\n");
     336             :   }
     337          42 : }
     338             : 
     339           0 : void StringStream::PrintByteArray(ByteArray byte_array) {
     340           0 :   unsigned int limit = byte_array->length();
     341           0 :   for (unsigned int i = 0; i < 10 && i < limit; i++) {
     342           0 :     byte b = byte_array->get(i);
     343           0 :     Add("             %d: %3d 0x%02x", i, b, b);
     344           0 :     if (b >= ' ' && b <= '~') {
     345           0 :       Add(" '%c'", b);
     346           0 :     } else if (b == '\n') {
     347           0 :       Add(" '\n'");
     348           0 :     } else if (b == '\r') {
     349           0 :       Add(" '\r'");
     350           0 :     } else if (b >= 1 && b <= 26) {
     351           0 :       Add(" ^%c", b + 'A' - 1);
     352             :     }
     353           0 :     Add("\n");
     354             :   }
     355           0 :   if (limit >= 10) {
     356           0 :     Add("                  ...\n");
     357             :   }
     358           0 : }
     359             : 
     360          16 : void StringStream::PrintMentionedObjectCache(Isolate* isolate) {
     361          16 :   if (object_print_mode_ == kPrintObjectConcise) return;
     362         227 :   DebugObjectCache* debug_object_cache =
     363             :       isolate->string_stream_debug_object_cache();
     364           8 :   Add("==== Key         ============================================\n\n");
     365         454 :   for (size_t i = 0; i < debug_object_cache->size(); i++) {
     366         219 :     HeapObject printee = (*debug_object_cache)[i];
     367             :     Add(" #%d# %p: ", static_cast<int>(i),
     368         219 :         reinterpret_cast<void*>(printee->ptr()));
     369         219 :     printee->ShortPrint(this);
     370         219 :     Add("\n");
     371         219 :     if (printee->IsJSObject()) {
     372         205 :       if (printee->IsJSValue()) {
     373           0 :         Add("           value(): %o\n", JSValue::cast(printee)->value());
     374             :       }
     375         205 :       PrintUsingMap(JSObject::cast(printee));
     376         205 :       if (printee->IsJSArray()) {
     377         105 :         JSArray array = JSArray::cast(printee);
     378         105 :         if (array->HasObjectElements()) {
     379          56 :           unsigned int limit = FixedArray::cast(array->elements())->length();
     380             :           unsigned int length =
     381          28 :             static_cast<uint32_t>(JSArray::cast(array)->length()->Number());
     382          28 :           if (length < limit) limit = length;
     383          56 :           PrintFixedArray(FixedArray::cast(array->elements()), limit);
     384             :         }
     385             :       }
     386          14 :     } else if (printee->IsByteArray()) {
     387           0 :       PrintByteArray(ByteArray::cast(printee));
     388          14 :     } else if (printee->IsFixedArray()) {
     389          14 :       unsigned int limit = FixedArray::cast(printee)->length();
     390          14 :       PrintFixedArray(FixedArray::cast(printee), limit);
     391             :     }
     392             :   }
     393             : }
     394             : 
     395          66 : void StringStream::PrintSecurityTokenIfChanged(JSFunction fun) {
     396          66 :   Object token = fun->native_context()->security_token();
     397             :   Isolate* isolate = fun->GetIsolate();
     398          66 :   if (token != isolate->string_stream_current_security_token()) {
     399          17 :     Add("Security context: %o\n", token);
     400             :     isolate->set_string_stream_current_security_token(token);
     401             :   }
     402          66 : }
     403             : 
     404          66 : void StringStream::PrintFunction(JSFunction fun, Object receiver, Code* code) {
     405          66 :   PrintPrototype(fun, receiver);
     406          66 :   *code = fun->code();
     407          66 : }
     408             : 
     409          66 : void StringStream::PrintPrototype(JSFunction fun, Object receiver) {
     410          66 :   Object name = fun->shared()->Name();
     411             :   bool print_name = false;
     412             :   Isolate* isolate = fun->GetIsolate();
     413         198 :   if (receiver->IsNullOrUndefined(isolate) || receiver->IsTheHole(isolate) ||
     414             :       receiver->IsJSProxy()) {
     415             :     print_name = true;
     416          66 :   } else if (!isolate->context().is_null()) {
     417          66 :     if (!receiver->IsJSObject()) {
     418           0 :       receiver = receiver->GetPrototypeChainRootMap(isolate)->prototype();
     419             :     }
     420             : 
     421         360 :     for (PrototypeIterator iter(isolate, JSObject::cast(receiver),
     422             :                                 kStartAtReceiver);
     423         228 :          !iter.IsAtEnd(); iter.Advance()) {
     424         474 :       if (iter.GetCurrent()->IsJSProxy()) break;
     425         237 :       Object key = iter.GetCurrent<JSObject>()->SlowReverseLookup(fun);
     426         237 :       if (!key->IsUndefined(isolate)) {
     427          18 :         if (!name->IsString() ||
     428          18 :             !key->IsString() ||
     429          27 :             !String::cast(name)->Equals(String::cast(key))) {
     430             :           print_name = true;
     431             :         }
     432          18 :         if (name->IsString() && String::cast(name)->length() == 0) {
     433             :           print_name = false;
     434             :         }
     435           9 :         name = key;
     436           9 :         break;
     437             :       }
     438             :     }
     439             :   }
     440          66 :   PrintName(name);
     441             :   // Also known as - if the name in the function doesn't match the name under
     442             :   // which it was looked up.
     443          66 :   if (print_name) {
     444           0 :     Add("(aka ");
     445           0 :     PrintName(fun->shared()->Name());
     446           0 :     Put(')');
     447             :   }
     448          66 : }
     449             : 
     450       91539 : char* HeapStringAllocator::grow(unsigned* bytes) {
     451       91539 :   unsigned new_bytes = *bytes * 2;
     452             :   // Check for overflow.
     453       91539 :   if (new_bytes <= *bytes) {
     454           0 :     return space_;
     455             :   }
     456       91539 :   char* new_space = NewArray<char>(new_bytes);
     457       91539 :   if (new_space == nullptr) {
     458           0 :     return space_;
     459             :   }
     460       91539 :   MemCopy(new_space, space_, *bytes);
     461       91539 :   *bytes = new_bytes;
     462       91539 :   DeleteArray(space_);
     463       91539 :   space_ = new_space;
     464       91539 :   return new_space;
     465             : }
     466             : 
     467             : 
     468             : }  // namespace internal
     469      178779 : }  // namespace v8

Generated by: LCOV version 1.10