Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/object.h" | 5 #include "vm/object.h" |
| 6 | 6 |
| 7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
| 9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 357 (value == '\f') || | 357 (value == '\f') || |
| 358 (value == '\b') || | 358 (value == '\b') || |
| 359 (value == '\t') || | 359 (value == '\t') || |
| 360 (value == '\v') || | 360 (value == '\v') || |
| 361 (value == '\r') || | 361 (value == '\r') || |
| 362 (value == '\\') || | 362 (value == '\\') || |
| 363 (value == '$')); | 363 (value == '$')); |
| 364 } | 364 } |
| 365 | 365 |
| 366 | 366 |
| 367 static bool IsAsciiPrintChar(int32_t code_point) { | |
| 368 return (code_point >= ' ') && (code_point <= '~'); | |
| 369 } | |
| 370 | |
| 371 | |
| 372 static inline bool IsAsciiNonprintable(int32_t c) { | 367 static inline bool IsAsciiNonprintable(int32_t c) { |
| 373 return ((0 <= c) && (c < 32)) || (c == 127); | 368 return ((0 <= c) && (c < 32)) || (c == 127); |
| 374 } | 369 } |
| 375 | 370 |
| 376 | 371 |
| 377 static inline bool NeedsEscapeSequence(int32_t c) { | 372 static inline bool NeedsEscapeSequence(int32_t c) { |
| 378 return (c == '"') || | 373 return (c == '"') || |
| 379 (c == '\\') || | 374 (c == '\\') || |
| 380 (c == '$') || | 375 (c == '$') || |
| 381 IsAsciiNonprintable(c); | 376 IsAsciiNonprintable(c); |
| (...skipping 16660 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 17042 result = OneByteString::New(length, space); | 17037 result = OneByteString::New(length, space); |
| 17043 } else { | 17038 } else { |
| 17044 result = TwoByteString::New(length, space); | 17039 result = TwoByteString::New(length, space); |
| 17045 } | 17040 } |
| 17046 String::Copy(result, 0, str, begin_index, length); | 17041 String::Copy(result, 0, str, begin_index, length); |
| 17047 return result.raw(); | 17042 return result.raw(); |
| 17048 } | 17043 } |
| 17049 | 17044 |
| 17050 | 17045 |
| 17051 const char* String::ToCString() const { | 17046 const char* String::ToCString() const { |
| 17047 intptr_t length; | |
| 17048 return ToCString(&length); | |
| 17049 } | |
| 17050 | |
| 17051 | |
| 17052 const char* String::ToCString(intptr_t* length) const { | |
| 17052 if (IsOneByteString()) { | 17053 if (IsOneByteString()) { |
| 17053 // Quick conversion if OneByteString contains only ASCII characters. | 17054 // Quick conversion if OneByteString contains only ASCII characters. |
| 17054 intptr_t len = Length(); | 17055 intptr_t len = Length(); |
| 17055 if (len == 0) { | 17056 if (len == 0) { |
| 17057 *length = 0; | |
| 17056 return ""; | 17058 return ""; |
| 17057 } | 17059 } |
| 17058 Zone* zone = Isolate::Current()->current_zone(); | 17060 Zone* zone = Isolate::Current()->current_zone(); |
| 17059 uint8_t* result = zone->Alloc<uint8_t>(len + 1); | 17061 uint8_t* result = zone->Alloc<uint8_t>(len + 1); |
| 17060 NoGCScope no_gc; | 17062 NoGCScope no_gc; |
| 17061 const uint8_t* original_str = OneByteString::CharAddr(*this, 0); | 17063 const uint8_t* original_str = OneByteString::CharAddr(*this, 0); |
| 17062 for (intptr_t i = 0; i < len; i++) { | 17064 for (intptr_t i = 0; i < len; i++) { |
| 17063 if (original_str[i] <= Utf8::kMaxOneByteChar) { | 17065 if (original_str[i] <= Utf8::kMaxOneByteChar) { |
| 17064 result[i] = original_str[i]; | 17066 result[i] = original_str[i]; |
| 17065 } else { | 17067 } else { |
| 17066 len = -1; | 17068 len = -1; |
| 17067 break; | 17069 break; |
| 17068 } | 17070 } |
| 17069 } | 17071 } |
| 17070 if (len > 0) { | 17072 if (len > 0) { |
| 17071 result[len] = 0; | 17073 result[len] = 0; |
| 17074 *length = len; | |
| 17072 return reinterpret_cast<const char*>(result); | 17075 return reinterpret_cast<const char*>(result); |
| 17073 } | 17076 } |
| 17074 } | 17077 } |
| 17075 const intptr_t len = Utf8::Length(*this); | 17078 const intptr_t len = Utf8::Length(*this); |
| 17076 Zone* zone = Isolate::Current()->current_zone(); | 17079 Zone* zone = Isolate::Current()->current_zone(); |
| 17077 uint8_t* result = zone->Alloc<uint8_t>(len + 1); | 17080 uint8_t* result = zone->Alloc<uint8_t>(len + 1); |
| 17078 ToUTF8(result, len); | 17081 ToUTF8(result, len); |
| 17079 result[len] = 0; | 17082 result[len] = 0; |
| 17083 *length = len; | |
| 17080 return reinterpret_cast<const char*>(result); | 17084 return reinterpret_cast<const char*>(result); |
| 17081 } | 17085 } |
| 17082 | 17086 |
| 17083 | 17087 |
| 17084 // Does not null-terminate. | 17088 const char* String::ToCStringTruncated(intptr_t max_len, |
| 17085 intptr_t String::EscapedString(char* buffer, int max_len) const { | 17089 bool* did_truncate, |
| 17086 int pos = 0; | 17090 intptr_t* length) const { |
| 17091 if (Length() <= max_len) { | |
| 17092 *did_truncate = false; | |
| 17093 return ToCString(length); | |
| 17094 } | |
| 17087 | 17095 |
| 17088 CodePointIterator cpi(*this); | 17096 intptr_t aligned_limit = max_len; |
| 17089 while (cpi.Next()) { | 17097 if (Utf16::IsLeadSurrogate(CharAt(max_len - 1))) { |
| 17090 int32_t code_point = cpi.Current(); | 17098 // Don't let truncation split a surrogate pair. |
| 17091 if (IsSpecialCharacter(code_point)) { | 17099 aligned_limit--; |
| 17092 if (pos + 2 > max_len) { | |
| 17093 return pos; | |
| 17094 } | |
| 17095 buffer[pos++] = '\\'; | |
| 17096 buffer[pos++] = SpecialCharacter(code_point); | |
| 17097 } else if (IsAsciiPrintChar(code_point)) { | |
| 17098 buffer[pos++] = code_point; | |
| 17099 } else { | |
| 17100 if (pos + 6 > max_len) { | |
| 17101 return pos; | |
| 17102 } | |
| 17103 pos += OS::SNPrint((buffer + pos), (max_len - pos), | |
| 17104 "\\u%04x", code_point); | |
| 17105 } | |
| 17106 if (pos == max_len) { | |
| 17107 return pos; | |
| 17108 } | |
| 17109 } | 17100 } |
| 17110 return pos; | 17101 ASSERT(!Utf16::IsLeadSurrogate(CharAt(aligned_limit - 1))); |
| 17102 | |
| 17103 *did_truncate = true; | |
| 17104 const String& truncated = | |
| 17105 String::Handle(String::SubString(*this, 0, aligned_limit)); | |
| 17106 return truncated.ToCString(length); | |
| 17111 } | 17107 } |
| 17112 | 17108 |
| 17113 | 17109 |
| 17114 intptr_t String::EscapedStringLen(intptr_t too_long) const { | |
| 17115 intptr_t len = 0; | |
| 17116 | |
| 17117 CodePointIterator cpi(*this); | |
| 17118 while (cpi.Next()) { | |
| 17119 int32_t code_point = cpi.Current(); | |
| 17120 if (IsSpecialCharacter(code_point)) { | |
| 17121 len += 2; // e.g. "\n" | |
| 17122 } else if (IsAsciiPrintChar(code_point)) { | |
| 17123 len += 1; | |
| 17124 } else { | |
| 17125 len += 6; // e.g. "\u0000". | |
| 17126 } | |
| 17127 if (len > too_long) { | |
| 17128 // No point going further. | |
| 17129 break; | |
| 17130 } | |
| 17131 } | |
| 17132 return len; | |
| 17133 } | |
| 17134 | |
| 17135 | |
| 17136 const char* String::ToUserCString(intptr_t max_len) const { | |
| 17137 // Compute the needed length for the buffer. | |
| 17138 const intptr_t escaped_len = EscapedStringLen(max_len); | |
| 17139 intptr_t print_len = escaped_len; | |
| 17140 intptr_t buffer_len = escaped_len + 2; // +2 for quotes. | |
| 17141 if (buffer_len > max_len) { | |
| 17142 buffer_len = max_len; // Truncate. | |
| 17143 print_len = max_len - 5; // -2 for quotes, -3 for elipsis. | |
| 17144 } | |
| 17145 | |
| 17146 // Allocate the buffer. | |
| 17147 Zone* zone = Isolate::Current()->current_zone(); | |
| 17148 char* buffer = zone->Alloc<char>(buffer_len + 1); | |
| 17149 | |
| 17150 // Leading quote. | |
| 17151 intptr_t pos = 0; | |
| 17152 buffer[pos++] = '\"'; | |
| 17153 | |
| 17154 // Print escaped string. | |
| 17155 pos += EscapedString((buffer + pos), print_len); | |
| 17156 | |
| 17157 // Trailing quote. | |
| 17158 buffer[pos++] = '\"'; | |
| 17159 | |
| 17160 if (print_len < escaped_len) { | |
| 17161 buffer[pos++] = '.'; | |
| 17162 buffer[pos++] = '.'; | |
| 17163 buffer[pos++] = '.'; | |
| 17164 } | |
| 17165 ASSERT(pos <= buffer_len); | |
| 17166 buffer[pos++] = '\0'; | |
| 17167 | |
| 17168 return buffer; | |
| 17169 } | |
| 17170 | |
| 17171 | |
| 17172 void String::PrintJSONImpl(JSONStream* stream, bool ref) const { | 17110 void String::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| 17173 JSONObject jsobj(stream); | 17111 JSONObject jsobj(stream); |
| 17174 if (raw() == Symbols::OptimizedOut().raw()) { | 17112 if (raw() == Symbols::OptimizedOut().raw()) { |
| 17175 // TODO(turnidge): This is a hack. The user could have this | 17113 // TODO(turnidge): This is a hack. The user could have this |
| 17176 // special string in their program. Fixing this involves updating | 17114 // special string in their program. Fixing this involves updating |
| 17177 // the debugging api a bit. | 17115 // the debugging api a bit. |
| 17178 jsobj.AddProperty("type", "Sentinel"); | 17116 jsobj.AddProperty("type", "Sentinel"); |
| 17179 jsobj.AddProperty("id", "objects/optimized-out"); | 17117 jsobj.AddProperty("id", "objects/optimized-out"); |
| 17180 jsobj.AddProperty("valueAsString", "<optimized out>"); | 17118 jsobj.AddProperty("valueAsString", "<optimized out>"); |
| 17181 return; | 17119 return; |
| 17182 } | 17120 } |
| 17183 PrintSharedInstanceJSON(&jsobj, ref); | 17121 PrintSharedInstanceJSON(&jsobj, ref); |
| 17184 ObjectIdRing* ring = Isolate::Current()->object_id_ring(); | 17122 ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
| 17185 const intptr_t id = ring->GetIdForObject(raw()); | 17123 const intptr_t id = ring->GetIdForObject(raw()); |
| 17186 jsobj.AddPropertyF("id", "objects/%" Pd "", id); | 17124 jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
| 17187 jsobj.AddProperty("valueAsString", ToUserCString(1024)); | 17125 if (ref) { |
| 17126 bool did_truncate = false; | |
| 17127 intptr_t length = 0; | |
|
turnidge
2014/09/09 16:12:31
Do you like these names? I've always felt 'valueA
rmacnak
2014/09/09 21:00:23
I'm not fond of them. Perhaps just 'toString'?
| |
| 17128 const char* cstr = ToCStringTruncated(128, &did_truncate, &length); | |
| 17129 jsobj.AddProperty("valueAsString", cstr, length); | |
| 17130 jsobj.AddProperty("valueAsStringIsTruncated", did_truncate); | |
|
turnidge
2014/09/09 16:12:31
I think we should have a convention that if "value
rmacnak
2014/09/09 21:00:23
I like that.
| |
| 17131 } else { | |
| 17132 intptr_t length = 0; | |
| 17133 const char* cstr = ToCString(&length); | |
| 17134 jsobj.AddProperty("valueAsString", cstr, length); | |
| 17135 jsobj.AddProperty("valueAsStringIsTruncated", false); | |
| 17136 } | |
| 17188 } | 17137 } |
| 17189 | 17138 |
| 17190 | 17139 |
| 17191 void String::ToUTF8(uint8_t* utf8_array, intptr_t array_len) const { | 17140 void String::ToUTF8(uint8_t* utf8_array, intptr_t array_len) const { |
| 17192 ASSERT(array_len >= Utf8::Length(*this)); | 17141 ASSERT(array_len >= Utf8::Length(*this)); |
| 17193 Utf8::Encode(*this, reinterpret_cast<char*>(utf8_array), array_len); | 17142 Utf8::Encode(*this, reinterpret_cast<char*>(utf8_array), array_len); |
| 17194 } | 17143 } |
| 17195 | 17144 |
| 17196 | 17145 |
| 17197 static FinalizablePersistentHandle* AddFinalizer( | 17146 static FinalizablePersistentHandle* AddFinalizer( |
| (...skipping 2490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 19688 return tag_label.ToCString(); | 19637 return tag_label.ToCString(); |
| 19689 } | 19638 } |
| 19690 | 19639 |
| 19691 | 19640 |
| 19692 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 19641 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| 19693 Instance::PrintJSONImpl(stream, ref); | 19642 Instance::PrintJSONImpl(stream, ref); |
| 19694 } | 19643 } |
| 19695 | 19644 |
| 19696 | 19645 |
| 19697 } // namespace dart | 19646 } // namespace dart |
| OLD | NEW |