5 #include "src/string-stream.h" 9 #include "src/handles-inl.h" 11 #include "src/objects-inl.h" 12 #include "src/objects/js-array-inl.h" 13 #include "src/prototype.h" 18 static const int kMentionedObjectCacheMaxSize = 256;
20 char* HeapStringAllocator::allocate(
unsigned bytes) {
21 space_ = NewArray<char>(bytes);
26 char* FixedStringAllocator::allocate(
unsigned bytes) {
27 CHECK_LE(bytes, length_);
32 char* FixedStringAllocator::grow(
unsigned* old) {
38 bool StringStream::Put(
char c) {
39 if (full())
return false;
40 DCHECK(length_ < capacity_);
44 if (length_ == capacity_ - 2) {
45 unsigned new_capacity = capacity_;
46 char* new_buffer = allocator_->grow(&new_capacity);
47 if (new_capacity > capacity_) {
48 capacity_ = new_capacity;
52 DCHECK_GE(capacity_, 5);
53 length_ = capacity_ - 1;
54 buffer_[length_ - 4] =
'.';
55 buffer_[length_ - 3] =
'.';
56 buffer_[length_ - 2] =
'.';
57 buffer_[length_ - 1] =
'\n';
58 buffer_[length_] =
'\0';
63 buffer_[length_ + 1] =
'\0';
71 static bool IsControlChar(
char 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 '-':
82 void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) {
87 while (offset < format.length()) {
88 if (format[offset] !=
'%' || elm == elms.length()) {
94 EmbeddedVector<char, 24> temp;
95 int format_length = 0;
98 temp[format_length++] = format[offset++];
99 while (offset < format.length() && IsControlChar(format[offset]))
100 temp[format_length++] = format[offset++];
101 if (offset >= format.length())
103 char type = format[offset];
104 temp[format_length++] = type;
105 temp[format_length] =
'\0';
107 FmtElm current = elms[elm++];
110 DCHECK_EQ(FmtElm::C_STR, current.type_);
111 const char* value = current.data_.u_c_str_;
116 DCHECK_EQ(FmtElm::LC_STR, current.type_);
117 Vector<const uc16> value = *current.data_.u_lc_str_;
118 for (
int i = 0;
i < value.length();
i++)
119 Put(static_cast<char>(value[
i]));
123 DCHECK_EQ(FmtElm::OBJ, current.type_);
124 Object* obj = current.data_.u_obj_;
129 DCHECK_EQ(FmtElm::INT, current.type_);
130 int value = current.data_.u_int_;
131 if (0x20 <= value && value <= 0x7F) {
133 }
else if (value <= 0xFF) {
134 Add(
"\\x%02x", value);
136 Add(
"\\u%04x", value);
140 case 'i':
case 'd':
case 'u':
case 'x':
case 'c':
case 'X': {
141 int value = current.data_.u_int_;
142 EmbeddedVector<char, 24> formatted;
143 int length = SNPrintF(formatted, temp.start(), value);
144 Add(Vector<const char>(formatted.start(), length));
147 case 'f':
case 'g':
case 'G':
case 'e':
case 'E': {
148 double value = current.data_.u_double_;
149 int inf = std::isinf(value);
152 }
else if (inf == 1) {
154 }
else if (std::isnan(value)) {
157 EmbeddedVector<char, 28> formatted;
158 SNPrintF(formatted, temp.start(), value);
159 Add(formatted.start());
164 void* value = current.data_.u_pointer_;
165 EmbeddedVector<char, 20> formatted;
166 SNPrintF(formatted, temp.start(), value);
167 Add(formatted.start());
177 DCHECK_EQ(buffer_[length_],
'\0');
181 void StringStream::PrintObject(Object* o) {
184 if (String::cast(o)->length() <= String::kMaxShortPrintLength) {
187 }
else if (o->IsNumber() || o->IsOddball()) {
190 if (o->IsHeapObject() && object_print_mode_ == kPrintObjectVerbose) {
193 DebugObjectCache* debug_object_cache =
194 Isolate::Current()->string_stream_debug_object_cache();
195 for (
size_t i = 0;
i < debug_object_cache->size();
i++) {
196 if ((*debug_object_cache)[
i] == o) {
197 Add(
"#%d#", static_cast<int>(
i));
201 if (debug_object_cache->size() < kMentionedObjectCacheMaxSize) {
202 Add(
"#%d#", static_cast<int>(debug_object_cache->size()));
203 debug_object_cache->push_back(HeapObject::cast(o));
211 std::unique_ptr<char[]> StringStream::ToCString()
const {
212 char* str = NewArray<char>(length_ + 1);
213 MemCopy(str, buffer_, length_);
215 return std::unique_ptr<char[]>(str);
219 void StringStream::Log(Isolate* isolate) {
220 LOG(isolate, StringEvent(
"StackDump", buffer_));
224 void StringStream::OutputToFile(FILE* out) {
229 unsigned position = 0;
230 for (
unsigned next; (next = position + 2048) < length_; position = next) {
231 char save = buffer_[next];
232 buffer_[next] =
'\0';
233 internal::PrintF(out,
"%s", &buffer_[position]);
234 buffer_[next] = save;
236 internal::PrintF(out,
"%s", &buffer_[position]);
240 Handle<String> StringStream::ToString(Isolate* isolate) {
241 return isolate->factory()->NewStringFromUtf8(
242 Vector<const char>(buffer_, length_)).ToHandleChecked();
246 void StringStream::ClearMentionedObjectCache(Isolate* isolate) {
247 isolate->set_string_stream_current_security_token(
nullptr);
248 if (isolate->string_stream_debug_object_cache() ==
nullptr) {
249 isolate->set_string_stream_debug_object_cache(
new DebugObjectCache());
251 isolate->string_stream_debug_object_cache()->clear();
256 bool StringStream::IsMentionedObjectCacheClear(Isolate* isolate) {
257 return object_print_mode_ == kPrintObjectConcise ||
258 isolate->string_stream_debug_object_cache()->size() == 0;
262 bool StringStream::Put(String str) {
return Put(str, 0, str->length()); }
264 bool StringStream::Put(String str,
int start,
int end) {
265 StringCharacterStream stream(str, start);
266 for (
int i = start;
i < end && stream.HasMore();
i++) {
267 uint16_t c = stream.GetNext();
268 if (c >= 127 || c < 32) {
271 if (!Put(static_cast<char>(c))) {
278 void StringStream::PrintName(Object* name) {
279 if (name->IsString()) {
280 String str = String::cast(name);
281 if (str->length() > 0) {
284 Add(
"/* anonymous */");
292 void StringStream::PrintUsingMap(JSObject* js_object) {
293 Map map = js_object->map();
294 int real_size = map->NumberOfOwnDescriptors();
295 DescriptorArray* descs = map->instance_descriptors();
296 for (
int i = 0;
i < real_size;
i++) {
297 PropertyDetails details = descs->GetDetails(
i);
298 if (details.location() == kField) {
299 DCHECK_EQ(kData, details.kind());
300 Object* key = descs->GetKey(
i);
301 if (key->IsString() || key->IsNumber()) {
303 if (key->IsString()) {
304 len = String::cast(key)->length();
306 for (; len < 18; len++)
308 if (key->IsString()) {
309 Put(String::cast(key));
314 FieldIndex index = FieldIndex::ForDescriptor(map,
i);
315 if (js_object->IsUnboxedDoubleField(index)) {
316 double value = js_object->RawFastDoublePropertyAt(index);
317 Add(
"<unboxed double> %.16g\n", FmtElm(value));
319 Object* value = js_object->RawFastPropertyAt(index);
327 void StringStream::PrintFixedArray(FixedArray array,
unsigned int limit) {
328 ReadOnlyRoots roots = array->GetReadOnlyRoots();
329 for (
unsigned int i = 0;
i < 10 &&
i < limit;
i++) {
330 Object* element = array->get(
i);
331 if (element->IsTheHole(roots))
continue;
332 for (
int len = 1; len < 18; len++) {
335 Add(
"%d: %o\n",
i, array->get(
i));
342 void StringStream::PrintByteArray(ByteArray byte_array) {
343 unsigned int limit = byte_array->length();
344 for (
unsigned int i = 0;
i < 10 &&
i < limit;
i++) {
345 byte b = byte_array->get(
i);
346 Add(
" %d: %3d 0x%02x",
i, b, b);
347 if (b >=
' ' && b <=
'~') {
349 }
else if (b ==
'\n') {
351 }
else if (b ==
'\r') {
353 }
else if (b >= 1 && b <= 26) {
354 Add(
" ^%c", b +
'A' - 1);
363 void StringStream::PrintMentionedObjectCache(Isolate* isolate) {
364 if (object_print_mode_ == kPrintObjectConcise)
return;
365 DebugObjectCache* debug_object_cache =
366 isolate->string_stream_debug_object_cache();
367 Add(
"==== Key ============================================\n\n");
368 for (
size_t i = 0;
i < debug_object_cache->size();
i++) {
369 HeapObject* printee = (*debug_object_cache)[
i];
370 Add(
" #%d# %p: ", static_cast<int>(
i), printee);
371 printee->ShortPrint(
this);
373 if (printee->IsJSObject()) {
374 if (printee->IsJSValue()) {
375 Add(
" value(): %o\n", JSValue::cast(printee)->value());
377 PrintUsingMap(JSObject::cast(printee));
378 if (printee->IsJSArray()) {
379 JSArray* array = JSArray::cast(printee);
380 if (array->HasObjectElements()) {
381 unsigned int limit = FixedArray::cast(array->elements())->length();
382 unsigned int length =
383 static_cast<uint32_t>(JSArray::cast(array)->length()->Number());
384 if (length < limit) limit = length;
385 PrintFixedArray(FixedArray::cast(array->elements()), limit);
388 }
else if (printee->IsByteArray()) {
389 PrintByteArray(ByteArray::cast(printee));
390 }
else if (printee->IsFixedArray()) {
391 unsigned int limit = FixedArray::cast(printee)->length();
392 PrintFixedArray(FixedArray::cast(printee), limit);
397 void StringStream::PrintSecurityTokenIfChanged(JSFunction* fun) {
398 Object* token = fun->native_context()->security_token();
399 Isolate* isolate = fun->GetIsolate();
400 if (token != isolate->string_stream_current_security_token()) {
401 Add(
"Security context: %o\n", token);
402 isolate->set_string_stream_current_security_token(token);
406 void StringStream::PrintFunction(JSFunction* fun, Object* receiver,
408 PrintPrototype(fun, receiver);
413 void StringStream::PrintPrototype(JSFunction* fun, Object* receiver) {
414 Object* name = fun->shared()->Name();
415 bool print_name =
false;
416 Isolate* isolate = fun->GetIsolate();
417 if (receiver->IsNullOrUndefined(isolate) || receiver->IsTheHole(isolate) ||
418 receiver->IsJSProxy()) {
420 }
else if (!isolate->context().is_null()) {
421 if (!receiver->IsJSObject()) {
422 receiver = receiver->GetPrototypeChainRootMap(isolate)->prototype();
425 for (PrototypeIterator iter(isolate, JSObject::cast(receiver),
427 !iter.IsAtEnd(); iter.Advance()) {
428 if (iter.GetCurrent()->IsJSProxy())
break;
429 Object* key = iter.GetCurrent<JSObject>()->SlowReverseLookup(fun);
430 if (!key->IsUndefined(isolate)) {
431 if (!name->IsString() ||
433 !String::cast(name)->Equals(String::cast(key))) {
436 if (name->IsString() && String::cast(name)->length() == 0) {
449 PrintName(fun->shared()->Name());
455 char* HeapStringAllocator::grow(
unsigned* bytes) {
456 unsigned new_bytes = *bytes * 2;
458 if (new_bytes <= *bytes) {
461 char* new_space = NewArray<char>(new_bytes);
462 if (new_space ==
nullptr) {
465 MemCopy(new_space, space_, *bytes);