| 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 16760 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 17142 result = OneByteString::New(length, space); | 17137 result = OneByteString::New(length, space); |
| 17143 } else { | 17138 } else { |
| 17144 result = TwoByteString::New(length, space); | 17139 result = TwoByteString::New(length, space); |
| 17145 } | 17140 } |
| 17146 String::Copy(result, 0, str, begin_index, length); | 17141 String::Copy(result, 0, str, begin_index, length); |
| 17147 return result.raw(); | 17142 return result.raw(); |
| 17148 } | 17143 } |
| 17149 | 17144 |
| 17150 | 17145 |
| 17151 const char* String::ToCString() const { | 17146 const char* String::ToCString() const { |
| 17147 intptr_t length; |
| 17148 return ToCString(&length); |
| 17149 } |
| 17150 |
| 17151 |
| 17152 const char* String::ToCString(intptr_t* length) const { |
| 17152 if (IsOneByteString()) { | 17153 if (IsOneByteString()) { |
| 17153 // Quick conversion if OneByteString contains only ASCII characters. | 17154 // Quick conversion if OneByteString contains only ASCII characters. |
| 17154 intptr_t len = Length(); | 17155 intptr_t len = Length(); |
| 17155 if (len == 0) { | 17156 if (len == 0) { |
| 17157 *length = 0; |
| 17156 return ""; | 17158 return ""; |
| 17157 } | 17159 } |
| 17158 Zone* zone = Isolate::Current()->current_zone(); | 17160 Zone* zone = Isolate::Current()->current_zone(); |
| 17159 uint8_t* result = zone->Alloc<uint8_t>(len + 1); | 17161 uint8_t* result = zone->Alloc<uint8_t>(len + 1); |
| 17160 NoGCScope no_gc; | 17162 NoGCScope no_gc; |
| 17161 const uint8_t* original_str = OneByteString::CharAddr(*this, 0); | 17163 const uint8_t* original_str = OneByteString::CharAddr(*this, 0); |
| 17162 for (intptr_t i = 0; i < len; i++) { | 17164 for (intptr_t i = 0; i < len; i++) { |
| 17163 if (original_str[i] <= Utf8::kMaxOneByteChar) { | 17165 if (original_str[i] <= Utf8::kMaxOneByteChar) { |
| 17164 result[i] = original_str[i]; | 17166 result[i] = original_str[i]; |
| 17165 } else { | 17167 } else { |
| 17166 len = -1; | 17168 len = -1; |
| 17167 break; | 17169 break; |
| 17168 } | 17170 } |
| 17169 } | 17171 } |
| 17170 if (len > 0) { | 17172 if (len > 0) { |
| 17171 result[len] = 0; | 17173 result[len] = 0; |
| 17174 *length = len; |
| 17172 return reinterpret_cast<const char*>(result); | 17175 return reinterpret_cast<const char*>(result); |
| 17173 } | 17176 } |
| 17174 } | 17177 } |
| 17175 const intptr_t len = Utf8::Length(*this); | 17178 const intptr_t len = Utf8::Length(*this); |
| 17176 Zone* zone = Isolate::Current()->current_zone(); | 17179 Zone* zone = Isolate::Current()->current_zone(); |
| 17177 uint8_t* result = zone->Alloc<uint8_t>(len + 1); | 17180 uint8_t* result = zone->Alloc<uint8_t>(len + 1); |
| 17178 ToUTF8(result, len); | 17181 ToUTF8(result, len); |
| 17179 result[len] = 0; | 17182 result[len] = 0; |
| 17183 *length = len; |
| 17180 return reinterpret_cast<const char*>(result); | 17184 return reinterpret_cast<const char*>(result); |
| 17181 } | 17185 } |
| 17182 | 17186 |
| 17183 | 17187 |
| 17184 // Does not null-terminate. | 17188 const char* String::ToCStringTruncated(intptr_t max_len, |
| 17185 intptr_t String::EscapedString(char* buffer, int max_len) const { | 17189 bool* did_truncate, |
| 17186 int pos = 0; | 17190 intptr_t* length) const { |
| 17191 if (Length() <= max_len) { |
| 17192 *did_truncate = false; |
| 17193 return ToCString(length); |
| 17194 } |
| 17187 | 17195 |
| 17188 CodePointIterator cpi(*this); | 17196 intptr_t aligned_limit = max_len; |
| 17189 while (cpi.Next()) { | 17197 if (Utf16::IsLeadSurrogate(CharAt(max_len - 1))) { |
| 17190 int32_t code_point = cpi.Current(); | 17198 // Don't let truncation split a surrogate pair. |
| 17191 if (IsSpecialCharacter(code_point)) { | 17199 aligned_limit--; |
| 17192 if (pos + 2 > max_len) { | |
| 17193 return pos; | |
| 17194 } | |
| 17195 buffer[pos++] = '\\'; | |
| 17196 buffer[pos++] = SpecialCharacter(code_point); | |
| 17197 } else if (IsAsciiPrintChar(code_point)) { | |
| 17198 buffer[pos++] = code_point; | |
| 17199 } else { | |
| 17200 if (pos + 6 > max_len) { | |
| 17201 return pos; | |
| 17202 } | |
| 17203 pos += OS::SNPrint((buffer + pos), (max_len - pos), | |
| 17204 "\\u%04x", code_point); | |
| 17205 } | |
| 17206 if (pos == max_len) { | |
| 17207 return pos; | |
| 17208 } | |
| 17209 } | 17200 } |
| 17210 return pos; | 17201 ASSERT(!Utf16::IsLeadSurrogate(CharAt(aligned_limit - 1))); |
| 17202 |
| 17203 *did_truncate = true; |
| 17204 const String& truncated = |
| 17205 String::Handle(String::SubString(*this, 0, aligned_limit)); |
| 17206 return truncated.ToCString(length); |
| 17211 } | 17207 } |
| 17212 | 17208 |
| 17213 | 17209 |
| 17214 intptr_t String::EscapedStringLen(intptr_t too_long) const { | |
| 17215 intptr_t len = 0; | |
| 17216 | |
| 17217 CodePointIterator cpi(*this); | |
| 17218 while (cpi.Next()) { | |
| 17219 int32_t code_point = cpi.Current(); | |
| 17220 if (IsSpecialCharacter(code_point)) { | |
| 17221 len += 2; // e.g. "\n" | |
| 17222 } else if (IsAsciiPrintChar(code_point)) { | |
| 17223 len += 1; | |
| 17224 } else { | |
| 17225 len += 6; // e.g. "\u0000". | |
| 17226 } | |
| 17227 if (len > too_long) { | |
| 17228 // No point going further. | |
| 17229 break; | |
| 17230 } | |
| 17231 } | |
| 17232 return len; | |
| 17233 } | |
| 17234 | |
| 17235 | |
| 17236 const char* String::ToUserCString(intptr_t max_len) const { | |
| 17237 // Compute the needed length for the buffer. | |
| 17238 const intptr_t escaped_len = EscapedStringLen(max_len); | |
| 17239 intptr_t print_len = escaped_len; | |
| 17240 intptr_t buffer_len = escaped_len + 2; // +2 for quotes. | |
| 17241 if (buffer_len > max_len) { | |
| 17242 buffer_len = max_len; // Truncate. | |
| 17243 print_len = max_len - 5; // -2 for quotes, -3 for elipsis. | |
| 17244 } | |
| 17245 | |
| 17246 // Allocate the buffer. | |
| 17247 Zone* zone = Isolate::Current()->current_zone(); | |
| 17248 char* buffer = zone->Alloc<char>(buffer_len + 1); | |
| 17249 | |
| 17250 // Leading quote. | |
| 17251 intptr_t pos = 0; | |
| 17252 buffer[pos++] = '\"'; | |
| 17253 | |
| 17254 // Print escaped string. | |
| 17255 pos += EscapedString((buffer + pos), print_len); | |
| 17256 | |
| 17257 // Trailing quote. | |
| 17258 buffer[pos++] = '\"'; | |
| 17259 | |
| 17260 if (print_len < escaped_len) { | |
| 17261 buffer[pos++] = '.'; | |
| 17262 buffer[pos++] = '.'; | |
| 17263 buffer[pos++] = '.'; | |
| 17264 } | |
| 17265 ASSERT(pos <= buffer_len); | |
| 17266 buffer[pos++] = '\0'; | |
| 17267 | |
| 17268 return buffer; | |
| 17269 } | |
| 17270 | |
| 17271 | |
| 17272 void String::PrintJSONImpl(JSONStream* stream, bool ref) const { | 17210 void String::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| 17273 JSONObject jsobj(stream); | 17211 JSONObject jsobj(stream); |
| 17274 if (raw() == Symbols::OptimizedOut().raw()) { | 17212 if (raw() == Symbols::OptimizedOut().raw()) { |
| 17275 // TODO(turnidge): This is a hack. The user could have this | 17213 // TODO(turnidge): This is a hack. The user could have this |
| 17276 // special string in their program. Fixing this involves updating | 17214 // special string in their program. Fixing this involves updating |
| 17277 // the debugging api a bit. | 17215 // the debugging api a bit. |
| 17278 jsobj.AddProperty("type", "Sentinel"); | 17216 jsobj.AddProperty("type", "Sentinel"); |
| 17279 jsobj.AddProperty("id", "objects/optimized-out"); | 17217 jsobj.AddProperty("id", "objects/optimized-out"); |
| 17280 jsobj.AddProperty("valueAsString", "<optimized out>"); | 17218 jsobj.AddProperty("valueAsString", "<optimized out>"); |
| 17281 return; | 17219 return; |
| 17282 } | 17220 } |
| 17283 AddTypeProperties(&jsobj, "String", JSONType(), ref); | 17221 AddTypeProperties(&jsobj, "String", JSONType(), ref); |
| 17284 PrintSharedInstanceJSON(&jsobj, ref); | 17222 PrintSharedInstanceJSON(&jsobj, ref); |
| 17285 ObjectIdRing* ring = Isolate::Current()->object_id_ring(); | 17223 ObjectIdRing* ring = Isolate::Current()->object_id_ring(); |
| 17286 const intptr_t id = ring->GetIdForObject(raw()); | 17224 const intptr_t id = ring->GetIdForObject(raw()); |
| 17287 jsobj.AddPropertyF("id", "objects/%" Pd "", id); | 17225 jsobj.AddPropertyF("id", "objects/%" Pd "", id); |
| 17288 jsobj.AddProperty("valueAsString", ToUserCString(1024)); | 17226 if (ref) { |
| 17227 bool did_truncate = false; |
| 17228 intptr_t length = 0; |
| 17229 const char* cstr = ToCStringTruncated(128, &did_truncate, &length); |
| 17230 jsobj.AddProperty("valueAsString", cstr, length); |
| 17231 if (did_truncate) { |
| 17232 jsobj.AddProperty("valueAsStringIsTruncated", did_truncate); |
| 17233 } |
| 17234 } else { |
| 17235 intptr_t length = 0; |
| 17236 const char* cstr = ToCString(&length); |
| 17237 jsobj.AddProperty("valueAsString", cstr, length); |
| 17238 } |
| 17289 } | 17239 } |
| 17290 | 17240 |
| 17291 | 17241 |
| 17292 void String::ToUTF8(uint8_t* utf8_array, intptr_t array_len) const { | 17242 void String::ToUTF8(uint8_t* utf8_array, intptr_t array_len) const { |
| 17293 ASSERT(array_len >= Utf8::Length(*this)); | 17243 ASSERT(array_len >= Utf8::Length(*this)); |
| 17294 Utf8::Encode(*this, reinterpret_cast<char*>(utf8_array), array_len); | 17244 Utf8::Encode(*this, reinterpret_cast<char*>(utf8_array), array_len); |
| 17295 } | 17245 } |
| 17296 | 17246 |
| 17297 | 17247 |
| 17298 static FinalizablePersistentHandle* AddFinalizer( | 17248 static FinalizablePersistentHandle* AddFinalizer( |
| (...skipping 2495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 19794 return tag_label.ToCString(); | 19744 return tag_label.ToCString(); |
| 19795 } | 19745 } |
| 19796 | 19746 |
| 19797 | 19747 |
| 19798 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | 19748 void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { |
| 19799 Instance::PrintJSONImpl(stream, ref); | 19749 Instance::PrintJSONImpl(stream, ref); |
| 19800 } | 19750 } |
| 19801 | 19751 |
| 19802 | 19752 |
| 19803 } // namespace dart | 19753 } // namespace dart |
| OLD | NEW |