00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "v8.h"
00029
00030 #include "factory.h"
00031 #include "string-stream.h"
00032
00033 namespace v8 { namespace internal {
00034
00035 static const int kMentionedObjectCacheMaxSize = 256;
00036 static List<HeapObject*, PreallocatedStorage>* debug_object_cache = NULL;
00037 static Object* current_security_token = NULL;
00038
00039
00040 char* HeapStringAllocator::allocate(unsigned bytes) {
00041 space_ = NewArray<char>(bytes);
00042 return space_;
00043 }
00044
00045
00046 NoAllocationStringAllocator::NoAllocationStringAllocator(unsigned bytes) {
00047 size_ = bytes;
00048 space_ = NewArray<char>(bytes);
00049 }
00050
00051
00052 NoAllocationStringAllocator::NoAllocationStringAllocator(char* memory,
00053 unsigned size) {
00054 size_ = size;
00055 space_ = memory;
00056 }
00057
00058
00059 bool StringStream::Put(char c) {
00060 if (space() == 0) return false;
00061 if (length_ >= capacity_ - 1) {
00062 unsigned new_capacity = capacity_;
00063 char* new_buffer = allocator_->grow(&new_capacity);
00064 if (new_capacity > capacity_) {
00065 capacity_ = new_capacity;
00066 buffer_ = new_buffer;
00067 } else {
00068
00069 memset(cursor(), '.', space());
00070 length_ = capacity_;
00071 buffer_[length_ - 2] = '\n';
00072 buffer_[length_ - 1] = '\0';
00073 return false;
00074 }
00075 }
00076 buffer_[length_] = c;
00077 buffer_[length_ + 1] = '\0';
00078 length_++;
00079 return true;
00080 }
00081
00082
00083
00084
00085 static bool IsControlChar(char c) {
00086 switch (c) {
00087 case '0': case '1': case '2': case '3': case '4': case '5':
00088 case '6': case '7': case '8': case '9': case '.': case '-':
00089 return true;
00090 default:
00091 return false;
00092 }
00093 }
00094
00095
00096 void StringStream::Add(const char* format, Vector<FmtElm> elms) {
00097
00098 if (space() == 0)
00099 return;
00100 int offset = 0;
00101 int elm = 0;
00102 while (format[offset] != '\0') {
00103 if (format[offset] != '%' || elm == elms.length()) {
00104 Put(format[offset]);
00105 offset++;
00106 continue;
00107 }
00108
00109 EmbeddedVector<char, 24> temp;
00110 int format_length = 0;
00111
00112
00113 temp[format_length++] = format[offset++];
00114
00115
00116 while (IsControlChar(format[offset]))
00117 temp[format_length++] = format[offset++];
00118 char type = format[offset];
00119 if (type == '\0') return;
00120 temp[format_length++] = type;
00121 temp[format_length] = '\0';
00122 offset++;
00123 FmtElm current = elms[elm++];
00124 switch (type) {
00125 case 's': {
00126 ASSERT_EQ(FmtElm::C_STR, current.type_);
00127 const char* value = current.data_.u_c_str_;
00128 Add(value);
00129 break;
00130 }
00131 case 'o': {
00132 ASSERT_EQ(FmtElm::OBJ, current.type_);
00133 Object* obj = current.data_.u_obj_;
00134 PrintObject(obj);
00135 break;
00136 }
00137 case 'i': case 'd': case 'u': case 'x': case 'c': case 'p': {
00138 int value = current.data_.u_int_;
00139 EmbeddedVector<char, 24> formatted;
00140 OS::SNPrintF(formatted, temp.start(), value);
00141 Add(formatted.start());
00142 break;
00143 }
00144 default:
00145 UNREACHABLE();
00146 break;
00147 }
00148 }
00149
00150
00151
00152 ASSERT(buffer_[length_] == '\0');
00153 ASSERT(strlen(buffer_) == length_);
00154 }
00155
00156
00157 void StringStream::PrintObject(Object* o) {
00158 o->ShortPrint(this);
00159 if (o->IsString()) {
00160 if (String::cast(o)->length() <= String::kMaxMediumStringSize) {
00161 return;
00162 }
00163 } else if (o->IsNumber() || o->IsOddball()) {
00164 return;
00165 }
00166 if (o->IsHeapObject()) {
00167 for (int i = 0; i < debug_object_cache->length(); i++) {
00168 if ((*debug_object_cache)[i] == o) {
00169 Add("#%d#", i);
00170 return;
00171 }
00172 }
00173 if (debug_object_cache->length() < kMentionedObjectCacheMaxSize) {
00174 Add("#%d#", debug_object_cache->length());
00175 debug_object_cache->Add(HeapObject::cast(o));
00176 } else {
00177 Add("@%p", o);
00178 }
00179 }
00180 }
00181
00182
00183 void StringStream::Add(const char* format) {
00184 Add(format, Vector<FmtElm>::empty());
00185 }
00186
00187
00188 void StringStream::Add(const char* format, FmtElm arg0) {
00189 const char argc = 1;
00190 FmtElm argv[argc] = { arg0 };
00191 Add(format, Vector<FmtElm>(argv, argc));
00192 }
00193
00194
00195 void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1) {
00196 const char argc = 2;
00197 FmtElm argv[argc] = { arg0, arg1 };
00198 Add(format, Vector<FmtElm>(argv, argc));
00199 }
00200
00201
00202 void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
00203 FmtElm arg2) {
00204 const char argc = 3;
00205 FmtElm argv[argc] = { arg0, arg1, arg2 };
00206 Add(format, Vector<FmtElm>(argv, argc));
00207 }
00208
00209
00210 SmartPointer<char> StringStream::ToCString() {
00211 char* str = NewArray<char>(length_ + 1);
00212 memcpy(str, buffer_, length_);
00213 str[length_] = '\0';
00214 return SmartPointer<char>(str);
00215 }
00216
00217
00218 void StringStream::Log() {
00219 LOG(StringEvent("StackDump", buffer_));
00220 }
00221
00222
00223 void StringStream::OutputToStdOut() {
00224
00225
00226
00227
00228 unsigned position = 0;
00229 for (unsigned next; (next = position + 2048) < length_; position = next) {
00230 char save = buffer_[next];
00231 buffer_[next] = '\0';
00232 internal::PrintF("%s", &buffer_[position]);
00233 buffer_[next] = save;
00234 }
00235 internal::PrintF("%s", &buffer_[position]);
00236 }
00237
00238
00239 Handle<String> StringStream::ToString() {
00240 return Factory::NewStringFromUtf8(Vector<const char>(buffer_, length_));
00241 }
00242
00243
00244 void StringStream::ClearMentionedObjectCache() {
00245 current_security_token = NULL;
00246 if (debug_object_cache == NULL) {
00247 debug_object_cache = new List<HeapObject*, PreallocatedStorage>(0);
00248 }
00249 debug_object_cache->Clear();
00250 }
00251
00252
00253 #ifdef DEBUG
00254 bool StringStream::IsMentionedObjectCacheClear() {
00255 return (debug_object_cache->length() == 0);
00256 }
00257 #endif
00258
00259
00260 bool StringStream::Put(String* str) {
00261 return Put(str, 0, str->length());
00262 }
00263
00264
00265 bool StringStream::Put(String* str, int start, int end) {
00266 StringInputBuffer name_buffer(str);
00267 name_buffer.Seek(start);
00268 for (int i = start; i < end && name_buffer.has_more(); i++) {
00269 int c = name_buffer.GetNext();
00270 if (c >= 127 || c < 32) {
00271 c = '?';
00272 }
00273 if (!Put(c)) {
00274 return false;
00275 }
00276 }
00277 return true;
00278 }
00279
00280
00281 void StringStream::PrintName(Object* name) {
00282 if (name->IsString()) {
00283 String* str = String::cast(name);
00284 if (str->length() > 0) {
00285 Put(str);
00286 } else {
00287 Add("/* anonymous */");
00288 }
00289 } else {
00290 Add("%o", name);
00291 }
00292 }
00293
00294
00295 void StringStream::PrintUsingMap(JSObject* js_object) {
00296 Map* map = js_object->map();
00297 if (!Heap::Contains(map) ||
00298 !map->IsHeapObject() ||
00299 !map->IsMap()) {
00300 Add("<Invalid map>\n");
00301 return;
00302 }
00303 for (DescriptorReader r(map->instance_descriptors()); !r.eos(); r.advance()) {
00304 switch (r.type()) {
00305 case FIELD: {
00306 Object* key = r.GetKey();
00307 if (key->IsString() || key->IsNumber()) {
00308 int len = 3;
00309 if (key->IsString()) {
00310 len = String::cast(key)->length();
00311 }
00312 for (; len < 18; len++)
00313 Put(' ');
00314 if (key->IsString()) {
00315 Put(String::cast(key));
00316 } else {
00317 key->ShortPrint();
00318 }
00319 Add(": ");
00320 Object* value = js_object->FastPropertyAt(r.GetFieldIndex());
00321 Add("%o\n", value);
00322 }
00323 }
00324 break;
00325 default:
00326 break;
00327 }
00328 }
00329 }
00330
00331
00332 void StringStream::PrintFixedArray(FixedArray* array, unsigned int limit) {
00333 for (unsigned int i = 0; i < 10 && i < limit; i++) {
00334 Object* element = array->get(i);
00335 if (element != Heap::the_hole_value()) {
00336 for (int len = 1; len < 18; len++)
00337 Put(' ');
00338 Add("%d: %o\n", i, array->get(i));
00339 }
00340 }
00341 if (limit >= 10) {
00342 Add(" ...\n");
00343 }
00344 }
00345
00346
00347 void StringStream::PrintByteArray(ByteArray* byte_array) {
00348 unsigned int limit = byte_array->length();
00349 for (unsigned int i = 0; i < 10 && i < limit; i++) {
00350 byte b = byte_array->get(i);
00351 Add(" %d: %3d 0x%02x", i, b, b);
00352 if (b >= ' ' && b <= '~') {
00353 Add(" '%c'", b);
00354 } else if (b == '\n') {
00355 Add(" '\n'");
00356 } else if (b == '\r') {
00357 Add(" '\r'");
00358 } else if (b >= 1 && b <= 26) {
00359 Add(" ^%c", b + 'A' - 1);
00360 }
00361 Add("\n");
00362 }
00363 if (limit >= 10) {
00364 Add(" ...\n");
00365 }
00366 }
00367
00368
00369 void StringStream::PrintMentionedObjectCache() {
00370 Add("==== Key ============================================\n\n");
00371 for (int i = 0; i < debug_object_cache->length(); i++) {
00372 HeapObject* printee = (*debug_object_cache)[i];
00373 Add(" #%d# %p: ", i, printee);
00374 printee->ShortPrint(this);
00375 Add("\n");
00376 if (printee->IsJSObject()) {
00377 if (printee->IsJSValue()) {
00378 Add(" value(): %o\n", JSValue::cast(printee)->value());
00379 }
00380 PrintUsingMap(JSObject::cast(printee));
00381 if (printee->IsJSArray()) {
00382 JSArray* array = JSArray::cast(printee);
00383 if (array->HasFastElements()) {
00384 unsigned int limit = FixedArray::cast(array->elements())->length();
00385 unsigned int length =
00386 static_cast<uint32_t>(JSArray::cast(array)->length()->Number());
00387 if (length < limit) limit = length;
00388 PrintFixedArray(FixedArray::cast(array->elements()), limit);
00389 }
00390 }
00391 } else if (printee->IsByteArray()) {
00392 PrintByteArray(ByteArray::cast(printee));
00393 } else if (printee->IsFixedArray()) {
00394 unsigned int limit = FixedArray::cast(printee)->length();
00395 PrintFixedArray(FixedArray::cast(printee), limit);
00396 }
00397 }
00398 }
00399
00400
00401 void StringStream::PrintSecurityTokenIfChanged(Object* f) {
00402 if (!f->IsHeapObject() || !Heap::Contains(HeapObject::cast(f))) {
00403 return;
00404 }
00405 Map* map = HeapObject::cast(f)->map();
00406 if (!map->IsHeapObject() ||
00407 !Heap::Contains(map) ||
00408 !map->IsMap() ||
00409 !f->IsJSFunction()) {
00410 return;
00411 }
00412
00413 JSFunction* fun = JSFunction::cast(f);
00414 Object* perhaps_context = fun->unchecked_context();
00415 if (perhaps_context->IsHeapObject() &&
00416 Heap::Contains(HeapObject::cast(perhaps_context)) &&
00417 perhaps_context->IsContext()) {
00418 Context* context = fun->context();
00419 if (!Heap::Contains(context)) {
00420 Add("(Function context is outside heap)\n");
00421 return;
00422 }
00423 Object* token = context->global_context()->security_token();
00424 if (token != current_security_token) {
00425 Add("Security context: %o\n", token);
00426 current_security_token = token;
00427 }
00428 } else {
00429 Add("(Function context is corrupt)\n");
00430 }
00431 }
00432
00433
00434 void StringStream::PrintFunction(Object* f, Object* receiver, Code** code) {
00435 if (f->IsHeapObject() &&
00436 Heap::Contains(HeapObject::cast(f)) &&
00437 Heap::Contains(HeapObject::cast(f)->map()) &&
00438 HeapObject::cast(f)->map()->IsMap()) {
00439 if (f->IsJSFunction()) {
00440 JSFunction* fun = JSFunction::cast(f);
00441
00442 PrintPrototype(fun, receiver);
00443 *code = fun->code();
00444 } else if (f->IsSymbol()) {
00445
00446
00447 PrintName(f);
00448 Add("/* unresolved */ ");
00449 } else {
00450
00451
00452
00453 Add("%o", f);
00454 Add("/* warning: no JSFunction object or function name found */ ");
00455 }
00456
00457
00458
00459 } else {
00460 if (!f->IsHeapObject()) {
00461 Add("/* warning: 'function' was not a heap object */ ");
00462 return;
00463 }
00464 if (!Heap::Contains(HeapObject::cast(f))) {
00465 Add("/* warning: 'function' was not on the heap */ ");
00466 return;
00467 }
00468 if (!Heap::Contains(HeapObject::cast(f)->map())) {
00469 Add("/* warning: function's map was not on the heap */ ");
00470 return;
00471 }
00472 if (!HeapObject::cast(f)->map()->IsMap()) {
00473 Add("/* warning: function's map was not a valid map */ ");
00474 return;
00475 }
00476 Add("/* warning: Invalid JSFunction object found */ ");
00477 }
00478 }
00479
00480
00481 void StringStream::PrintPrototype(JSFunction* fun, Object* receiver) {
00482 Object* name = fun->shared()->name();
00483 bool print_name = false;
00484 for (Object* p = receiver; p != Heap::null_value(); p = p->GetPrototype()) {
00485 if (p->IsJSObject()) {
00486 Object* key = JSObject::cast(p)->SlowReverseLookup(fun);
00487 if (key != Heap::undefined_value()) {
00488 if (!name->IsString() ||
00489 !key->IsString() ||
00490 !String::cast(name)->Equals(String::cast(key))) {
00491 print_name = true;
00492 }
00493 if (name->IsString() && String::cast(name)->length() == 0) {
00494 print_name = false;
00495 }
00496 name = key;
00497 }
00498 } else {
00499 print_name = true;
00500 }
00501 }
00502 PrintName(name);
00503
00504
00505 if (print_name) {
00506 Add("(aka ");
00507 PrintName(fun->shared()->name());
00508 Put(')');
00509 }
00510 }
00511
00512
00513 char* HeapStringAllocator::grow(unsigned* bytes) {
00514 unsigned new_bytes = *bytes * 2;
00515
00516 if (new_bytes <= *bytes) {
00517 return space_;
00518 }
00519 char* new_space = NewArray<char>(new_bytes);
00520 if (new_space == NULL) {
00521 return space_;
00522 }
00523 memcpy(new_space, space_, *bytes);
00524 *bytes = new_bytes;
00525 DeleteArray(space_);
00526 space_ = new_space;
00527 return new_space;
00528 }
00529
00530
00531 char* NoAllocationStringAllocator::grow(unsigned* bytes) {
00532 unsigned new_bytes = *bytes * 2;
00533 if (new_bytes > size_) {
00534 new_bytes = size_;
00535 }
00536 *bytes = new_bytes;
00537 return space_;
00538 }
00539
00540
00541 } }