Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: runtime/vm/object.cc

Issue 542363003: Don't double-escape in strings in the VM Service, and don't use \u0000 to determine the string lengt (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698