| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "factory.h" | 30 #include "factory.h" |
| 31 #include "string-stream.h" | 31 #include "string-stream.h" |
| 32 | 32 |
| 33 namespace v8 { | 33 namespace v8 { |
| 34 namespace internal { | 34 namespace internal { |
| 35 | 35 |
| 36 static const int kMentionedObjectCacheMaxSize = 256; | 36 static const int kMentionedObjectCacheMaxSize = 256; |
| 37 static List<HeapObject*, PreallocatedStorage>* debug_object_cache = NULL; | |
| 38 static Object* current_security_token = NULL; | |
| 39 | |
| 40 | 37 |
| 41 char* HeapStringAllocator::allocate(unsigned bytes) { | 38 char* HeapStringAllocator::allocate(unsigned bytes) { |
| 42 space_ = NewArray<char>(bytes); | 39 space_ = NewArray<char>(bytes); |
| 43 return space_; | 40 return space_; |
| 44 } | 41 } |
| 45 | 42 |
| 46 | 43 |
| 47 NoAllocationStringAllocator::NoAllocationStringAllocator(char* memory, | 44 NoAllocationStringAllocator::NoAllocationStringAllocator(char* memory, |
| 48 unsigned size) { | 45 unsigned size) { |
| 49 size_ = size; | 46 size_ = size; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 void StringStream::PrintObject(Object* o) { | 185 void StringStream::PrintObject(Object* o) { |
| 189 o->ShortPrint(this); | 186 o->ShortPrint(this); |
| 190 if (o->IsString()) { | 187 if (o->IsString()) { |
| 191 if (String::cast(o)->length() <= String::kMaxShortPrintLength) { | 188 if (String::cast(o)->length() <= String::kMaxShortPrintLength) { |
| 192 return; | 189 return; |
| 193 } | 190 } |
| 194 } else if (o->IsNumber() || o->IsOddball()) { | 191 } else if (o->IsNumber() || o->IsOddball()) { |
| 195 return; | 192 return; |
| 196 } | 193 } |
| 197 if (o->IsHeapObject()) { | 194 if (o->IsHeapObject()) { |
| 195 DebugObjectCache* debug_object_cache = Isolate::Current()-> |
| 196 string_stream_debug_object_cache(); |
| 198 for (int i = 0; i < debug_object_cache->length(); i++) { | 197 for (int i = 0; i < debug_object_cache->length(); i++) { |
| 199 if ((*debug_object_cache)[i] == o) { | 198 if ((*debug_object_cache)[i] == o) { |
| 200 Add("#%d#", i); | 199 Add("#%d#", i); |
| 201 return; | 200 return; |
| 202 } | 201 } |
| 203 } | 202 } |
| 204 if (debug_object_cache->length() < kMentionedObjectCacheMaxSize) { | 203 if (debug_object_cache->length() < kMentionedObjectCacheMaxSize) { |
| 205 Add("#%d#", debug_object_cache->length()); | 204 Add("#%d#", debug_object_cache->length()); |
| 206 debug_object_cache->Add(HeapObject::cast(o)); | 205 debug_object_cache->Add(HeapObject::cast(o)); |
| 207 } else { | 206 } else { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 | 252 |
| 254 SmartPointer<const char> StringStream::ToCString() const { | 253 SmartPointer<const char> StringStream::ToCString() const { |
| 255 char* str = NewArray<char>(length_ + 1); | 254 char* str = NewArray<char>(length_ + 1); |
| 256 memcpy(str, buffer_, length_); | 255 memcpy(str, buffer_, length_); |
| 257 str[length_] = '\0'; | 256 str[length_] = '\0'; |
| 258 return SmartPointer<const char>(str); | 257 return SmartPointer<const char>(str); |
| 259 } | 258 } |
| 260 | 259 |
| 261 | 260 |
| 262 void StringStream::Log() { | 261 void StringStream::Log() { |
| 263 LOG(StringEvent("StackDump", buffer_)); | 262 LOG(ISOLATE, StringEvent("StackDump", buffer_)); |
| 264 } | 263 } |
| 265 | 264 |
| 266 | 265 |
| 267 void StringStream::OutputToFile(FILE* out) { | 266 void StringStream::OutputToFile(FILE* out) { |
| 268 // Dump the output to stdout, but make sure to break it up into | 267 // Dump the output to stdout, but make sure to break it up into |
| 269 // manageable chunks to avoid losing parts of the output in the OS | 268 // manageable chunks to avoid losing parts of the output in the OS |
| 270 // printing code. This is a problem on Windows in particular; see | 269 // printing code. This is a problem on Windows in particular; see |
| 271 // the VPrint() function implementations in platform-win32.cc. | 270 // the VPrint() function implementations in platform-win32.cc. |
| 272 unsigned position = 0; | 271 unsigned position = 0; |
| 273 for (unsigned next; (next = position + 2048) < length_; position = next) { | 272 for (unsigned next; (next = position + 2048) < length_; position = next) { |
| 274 char save = buffer_[next]; | 273 char save = buffer_[next]; |
| 275 buffer_[next] = '\0'; | 274 buffer_[next] = '\0'; |
| 276 internal::PrintF(out, "%s", &buffer_[position]); | 275 internal::PrintF(out, "%s", &buffer_[position]); |
| 277 buffer_[next] = save; | 276 buffer_[next] = save; |
| 278 } | 277 } |
| 279 internal::PrintF(out, "%s", &buffer_[position]); | 278 internal::PrintF(out, "%s", &buffer_[position]); |
| 280 } | 279 } |
| 281 | 280 |
| 282 | 281 |
| 283 Handle<String> StringStream::ToString() { | 282 Handle<String> StringStream::ToString() { |
| 284 return Factory::NewStringFromUtf8(Vector<const char>(buffer_, length_)); | 283 return FACTORY->NewStringFromUtf8(Vector<const char>(buffer_, length_)); |
| 285 } | 284 } |
| 286 | 285 |
| 287 | 286 |
| 288 void StringStream::ClearMentionedObjectCache() { | 287 void StringStream::ClearMentionedObjectCache() { |
| 289 current_security_token = NULL; | 288 Isolate* isolate = Isolate::Current(); |
| 290 if (debug_object_cache == NULL) { | 289 isolate->set_string_stream_current_security_token(NULL); |
| 291 debug_object_cache = new List<HeapObject*, PreallocatedStorage>(0); | 290 if (isolate->string_stream_debug_object_cache() == NULL) { |
| 291 isolate->set_string_stream_debug_object_cache( |
| 292 new List<HeapObject*, PreallocatedStorage>(0)); |
| 292 } | 293 } |
| 293 debug_object_cache->Clear(); | 294 isolate->string_stream_debug_object_cache()->Clear(); |
| 294 } | 295 } |
| 295 | 296 |
| 296 | 297 |
| 297 #ifdef DEBUG | 298 #ifdef DEBUG |
| 298 bool StringStream::IsMentionedObjectCacheClear() { | 299 bool StringStream::IsMentionedObjectCacheClear() { |
| 299 return (debug_object_cache->length() == 0); | 300 return ( |
| 301 Isolate::Current()->string_stream_debug_object_cache()->length() == 0); |
| 300 } | 302 } |
| 301 #endif | 303 #endif |
| 302 | 304 |
| 303 | 305 |
| 304 bool StringStream::Put(String* str) { | 306 bool StringStream::Put(String* str) { |
| 305 return Put(str, 0, str->length()); | 307 return Put(str, 0, str->length()); |
| 306 } | 308 } |
| 307 | 309 |
| 308 | 310 |
| 309 bool StringStream::Put(String* str, int start, int end) { | 311 bool StringStream::Put(String* str, int start, int end) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 331 Add("/* anonymous */"); | 333 Add("/* anonymous */"); |
| 332 } | 334 } |
| 333 } else { | 335 } else { |
| 334 Add("%o", name); | 336 Add("%o", name); |
| 335 } | 337 } |
| 336 } | 338 } |
| 337 | 339 |
| 338 | 340 |
| 339 void StringStream::PrintUsingMap(JSObject* js_object) { | 341 void StringStream::PrintUsingMap(JSObject* js_object) { |
| 340 Map* map = js_object->map(); | 342 Map* map = js_object->map(); |
| 341 if (!Heap::Contains(map) || | 343 if (!HEAP->Contains(map) || |
| 342 !map->IsHeapObject() || | 344 !map->IsHeapObject() || |
| 343 !map->IsMap()) { | 345 !map->IsMap()) { |
| 344 Add("<Invalid map>\n"); | 346 Add("<Invalid map>\n"); |
| 345 return; | 347 return; |
| 346 } | 348 } |
| 347 DescriptorArray* descs = map->instance_descriptors(); | 349 DescriptorArray* descs = map->instance_descriptors(); |
| 348 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 350 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 349 switch (descs->GetType(i)) { | 351 switch (descs->GetType(i)) { |
| 350 case FIELD: { | 352 case FIELD: { |
| 351 Object* key = descs->GetKey(i); | 353 Object* key = descs->GetKey(i); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 368 } | 370 } |
| 369 break; | 371 break; |
| 370 default: | 372 default: |
| 371 break; | 373 break; |
| 372 } | 374 } |
| 373 } | 375 } |
| 374 } | 376 } |
| 375 | 377 |
| 376 | 378 |
| 377 void StringStream::PrintFixedArray(FixedArray* array, unsigned int limit) { | 379 void StringStream::PrintFixedArray(FixedArray* array, unsigned int limit) { |
| 380 Heap* heap = HEAP; |
| 378 for (unsigned int i = 0; i < 10 && i < limit; i++) { | 381 for (unsigned int i = 0; i < 10 && i < limit; i++) { |
| 379 Object* element = array->get(i); | 382 Object* element = array->get(i); |
| 380 if (element != Heap::the_hole_value()) { | 383 if (element != heap->the_hole_value()) { |
| 381 for (int len = 1; len < 18; len++) | 384 for (int len = 1; len < 18; len++) |
| 382 Put(' '); | 385 Put(' '); |
| 383 Add("%d: %o\n", i, array->get(i)); | 386 Add("%d: %o\n", i, array->get(i)); |
| 384 } | 387 } |
| 385 } | 388 } |
| 386 if (limit >= 10) { | 389 if (limit >= 10) { |
| 387 Add(" ...\n"); | 390 Add(" ...\n"); |
| 388 } | 391 } |
| 389 } | 392 } |
| 390 | 393 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 405 } | 408 } |
| 406 Add("\n"); | 409 Add("\n"); |
| 407 } | 410 } |
| 408 if (limit >= 10) { | 411 if (limit >= 10) { |
| 409 Add(" ...\n"); | 412 Add(" ...\n"); |
| 410 } | 413 } |
| 411 } | 414 } |
| 412 | 415 |
| 413 | 416 |
| 414 void StringStream::PrintMentionedObjectCache() { | 417 void StringStream::PrintMentionedObjectCache() { |
| 418 DebugObjectCache* debug_object_cache = |
| 419 Isolate::Current()->string_stream_debug_object_cache(); |
| 415 Add("==== Key ============================================\n\n"); | 420 Add("==== Key ============================================\n\n"); |
| 416 for (int i = 0; i < debug_object_cache->length(); i++) { | 421 for (int i = 0; i < debug_object_cache->length(); i++) { |
| 417 HeapObject* printee = (*debug_object_cache)[i]; | 422 HeapObject* printee = (*debug_object_cache)[i]; |
| 418 Add(" #%d# %p: ", i, printee); | 423 Add(" #%d# %p: ", i, printee); |
| 419 printee->ShortPrint(this); | 424 printee->ShortPrint(this); |
| 420 Add("\n"); | 425 Add("\n"); |
| 421 if (printee->IsJSObject()) { | 426 if (printee->IsJSObject()) { |
| 422 if (printee->IsJSValue()) { | 427 if (printee->IsJSValue()) { |
| 423 Add(" value(): %o\n", JSValue::cast(printee)->value()); | 428 Add(" value(): %o\n", JSValue::cast(printee)->value()); |
| 424 } | 429 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 437 PrintByteArray(ByteArray::cast(printee)); | 442 PrintByteArray(ByteArray::cast(printee)); |
| 438 } else if (printee->IsFixedArray()) { | 443 } else if (printee->IsFixedArray()) { |
| 439 unsigned int limit = FixedArray::cast(printee)->length(); | 444 unsigned int limit = FixedArray::cast(printee)->length(); |
| 440 PrintFixedArray(FixedArray::cast(printee), limit); | 445 PrintFixedArray(FixedArray::cast(printee), limit); |
| 441 } | 446 } |
| 442 } | 447 } |
| 443 } | 448 } |
| 444 | 449 |
| 445 | 450 |
| 446 void StringStream::PrintSecurityTokenIfChanged(Object* f) { | 451 void StringStream::PrintSecurityTokenIfChanged(Object* f) { |
| 447 if (!f->IsHeapObject() || !Heap::Contains(HeapObject::cast(f))) { | 452 Isolate* isolate = Isolate::Current(); |
| 453 Heap* heap = isolate->heap(); |
| 454 if (!f->IsHeapObject() || !heap->Contains(HeapObject::cast(f))) { |
| 448 return; | 455 return; |
| 449 } | 456 } |
| 450 Map* map = HeapObject::cast(f)->map(); | 457 Map* map = HeapObject::cast(f)->map(); |
| 451 if (!map->IsHeapObject() || | 458 if (!map->IsHeapObject() || |
| 452 !Heap::Contains(map) || | 459 !heap->Contains(map) || |
| 453 !map->IsMap() || | 460 !map->IsMap() || |
| 454 !f->IsJSFunction()) { | 461 !f->IsJSFunction()) { |
| 455 return; | 462 return; |
| 456 } | 463 } |
| 457 | 464 |
| 458 JSFunction* fun = JSFunction::cast(f); | 465 JSFunction* fun = JSFunction::cast(f); |
| 459 Object* perhaps_context = fun->unchecked_context(); | 466 Object* perhaps_context = fun->unchecked_context(); |
| 460 if (perhaps_context->IsHeapObject() && | 467 if (perhaps_context->IsHeapObject() && |
| 461 Heap::Contains(HeapObject::cast(perhaps_context)) && | 468 heap->Contains(HeapObject::cast(perhaps_context)) && |
| 462 perhaps_context->IsContext()) { | 469 perhaps_context->IsContext()) { |
| 463 Context* context = fun->context(); | 470 Context* context = fun->context(); |
| 464 if (!Heap::Contains(context)) { | 471 if (!heap->Contains(context)) { |
| 465 Add("(Function context is outside heap)\n"); | 472 Add("(Function context is outside heap)\n"); |
| 466 return; | 473 return; |
| 467 } | 474 } |
| 468 Object* token = context->global_context()->security_token(); | 475 Object* token = context->global_context()->security_token(); |
| 469 if (token != current_security_token) { | 476 if (token != isolate->string_stream_current_security_token()) { |
| 470 Add("Security context: %o\n", token); | 477 Add("Security context: %o\n", token); |
| 471 current_security_token = token; | 478 isolate->set_string_stream_current_security_token(token); |
| 472 } | 479 } |
| 473 } else { | 480 } else { |
| 474 Add("(Function context is corrupt)\n"); | 481 Add("(Function context is corrupt)\n"); |
| 475 } | 482 } |
| 476 } | 483 } |
| 477 | 484 |
| 478 | 485 |
| 479 void StringStream::PrintFunction(Object* f, Object* receiver, Code** code) { | 486 void StringStream::PrintFunction(Object* f, Object* receiver, Code** code) { |
| 480 if (f->IsHeapObject() && | 487 if (f->IsHeapObject() && |
| 481 Heap::Contains(HeapObject::cast(f)) && | 488 HEAP->Contains(HeapObject::cast(f)) && |
| 482 Heap::Contains(HeapObject::cast(f)->map()) && | 489 HEAP->Contains(HeapObject::cast(f)->map()) && |
| 483 HeapObject::cast(f)->map()->IsMap()) { | 490 HeapObject::cast(f)->map()->IsMap()) { |
| 484 if (f->IsJSFunction()) { | 491 if (f->IsJSFunction()) { |
| 485 JSFunction* fun = JSFunction::cast(f); | 492 JSFunction* fun = JSFunction::cast(f); |
| 486 // Common case: on-stack function present and resolved. | 493 // Common case: on-stack function present and resolved. |
| 487 PrintPrototype(fun, receiver); | 494 PrintPrototype(fun, receiver); |
| 488 *code = fun->code(); | 495 *code = fun->code(); |
| 489 } else if (f->IsSymbol()) { | 496 } else if (f->IsSymbol()) { |
| 490 // Unresolved and megamorphic calls: Instead of the function | 497 // Unresolved and megamorphic calls: Instead of the function |
| 491 // we have the function name on the stack. | 498 // we have the function name on the stack. |
| 492 PrintName(f); | 499 PrintName(f); |
| 493 Add("/* unresolved */ "); | 500 Add("/* unresolved */ "); |
| 494 } else { | 501 } else { |
| 495 // Unless this is the frame of a built-in function, we should always have | 502 // Unless this is the frame of a built-in function, we should always have |
| 496 // the callee function or name on the stack. If we don't, we have a | 503 // the callee function or name on the stack. If we don't, we have a |
| 497 // problem or a change of the stack frame layout. | 504 // problem or a change of the stack frame layout. |
| 498 Add("%o", f); | 505 Add("%o", f); |
| 499 Add("/* warning: no JSFunction object or function name found */ "); | 506 Add("/* warning: no JSFunction object or function name found */ "); |
| 500 } | 507 } |
| 501 /* } else if (is_trampoline()) { | 508 /* } else if (is_trampoline()) { |
| 502 Print("trampoline "); | 509 Print("trampoline "); |
| 503 */ | 510 */ |
| 504 } else { | 511 } else { |
| 505 if (!f->IsHeapObject()) { | 512 if (!f->IsHeapObject()) { |
| 506 Add("/* warning: 'function' was not a heap object */ "); | 513 Add("/* warning: 'function' was not a heap object */ "); |
| 507 return; | 514 return; |
| 508 } | 515 } |
| 509 if (!Heap::Contains(HeapObject::cast(f))) { | 516 if (!HEAP->Contains(HeapObject::cast(f))) { |
| 510 Add("/* warning: 'function' was not on the heap */ "); | 517 Add("/* warning: 'function' was not on the heap */ "); |
| 511 return; | 518 return; |
| 512 } | 519 } |
| 513 if (!Heap::Contains(HeapObject::cast(f)->map())) { | 520 if (!HEAP->Contains(HeapObject::cast(f)->map())) { |
| 514 Add("/* warning: function's map was not on the heap */ "); | 521 Add("/* warning: function's map was not on the heap */ "); |
| 515 return; | 522 return; |
| 516 } | 523 } |
| 517 if (!HeapObject::cast(f)->map()->IsMap()) { | 524 if (!HeapObject::cast(f)->map()->IsMap()) { |
| 518 Add("/* warning: function's map was not a valid map */ "); | 525 Add("/* warning: function's map was not a valid map */ "); |
| 519 return; | 526 return; |
| 520 } | 527 } |
| 521 Add("/* warning: Invalid JSFunction object found */ "); | 528 Add("/* warning: Invalid JSFunction object found */ "); |
| 522 } | 529 } |
| 523 } | 530 } |
| 524 | 531 |
| 525 | 532 |
| 526 void StringStream::PrintPrototype(JSFunction* fun, Object* receiver) { | 533 void StringStream::PrintPrototype(JSFunction* fun, Object* receiver) { |
| 527 Object* name = fun->shared()->name(); | 534 Object* name = fun->shared()->name(); |
| 528 bool print_name = false; | 535 bool print_name = false; |
| 529 for (Object* p = receiver; p != Heap::null_value(); p = p->GetPrototype()) { | 536 Heap* heap = HEAP; |
| 537 for (Object* p = receiver; p != heap->null_value(); p = p->GetPrototype()) { |
| 530 if (p->IsJSObject()) { | 538 if (p->IsJSObject()) { |
| 531 Object* key = JSObject::cast(p)->SlowReverseLookup(fun); | 539 Object* key = JSObject::cast(p)->SlowReverseLookup(fun); |
| 532 if (key != Heap::undefined_value()) { | 540 if (key != heap->undefined_value()) { |
| 533 if (!name->IsString() || | 541 if (!name->IsString() || |
| 534 !key->IsString() || | 542 !key->IsString() || |
| 535 !String::cast(name)->Equals(String::cast(key))) { | 543 !String::cast(name)->Equals(String::cast(key))) { |
| 536 print_name = true; | 544 print_name = true; |
| 537 } | 545 } |
| 538 if (name->IsString() && String::cast(name)->length() == 0) { | 546 if (name->IsString() && String::cast(name)->length() == 0) { |
| 539 print_name = false; | 547 print_name = false; |
| 540 } | 548 } |
| 541 name = key; | 549 name = key; |
| 542 } | 550 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 | 583 |
| 576 // Only grow once to the maximum allowable size. | 584 // Only grow once to the maximum allowable size. |
| 577 char* NoAllocationStringAllocator::grow(unsigned* bytes) { | 585 char* NoAllocationStringAllocator::grow(unsigned* bytes) { |
| 578 ASSERT(size_ >= *bytes); | 586 ASSERT(size_ >= *bytes); |
| 579 *bytes = size_; | 587 *bytes = size_; |
| 580 return space_; | 588 return space_; |
| 581 } | 589 } |
| 582 | 590 |
| 583 | 591 |
| 584 } } // namespace v8::internal | 592 } } // namespace v8::internal |
| OLD | NEW |