Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 2440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2451 func->shared()->set_name(*Utils::OpenHandle(*name)); | 2451 func->shared()->set_name(*Utils::OpenHandle(*name)); |
| 2452 } | 2452 } |
| 2453 | 2453 |
| 2454 | 2454 |
| 2455 Handle<Value> Function::GetName() const { | 2455 Handle<Value> Function::GetName() const { |
| 2456 i::Handle<i::JSFunction> func = Utils::OpenHandle(this); | 2456 i::Handle<i::JSFunction> func = Utils::OpenHandle(this); |
| 2457 return Utils::ToLocal(i::Handle<i::Object>(func->shared()->name())); | 2457 return Utils::ToLocal(i::Handle<i::Object>(func->shared()->name())); |
| 2458 } | 2458 } |
| 2459 | 2459 |
| 2460 | 2460 |
| 2461 namespace { | |
| 2462 | |
| 2463 // Tracks string usage to help make better decisions when | |
| 2464 // externalizing strings. | |
| 2465 class StringTracker { | |
| 2466 public: | |
| 2467 // Records that the given string's characters were copied to some | |
|
Mads Ager (chromium)
2010/02/16 08:16:19
Could you update the comments in this class to mak
Vitaly Repeshko
2010/02/16 18:56:42
Done.
| |
| 2468 // external buffer. If this happens often we should honor | |
| 2469 // externalization requests for the string. | |
| 2470 static void RecordWrite(i::Handle<i::String> string) { | |
| 2471 i::Address address = reinterpret_cast<i::Address>(*string); | |
| 2472 i::Address top = i::Heap::NewSpaceTop(); | |
| 2473 if (IsFreshString(address, top)) { | |
| 2474 IncrementUseCount(top); | |
| 2475 } | |
| 2476 } | |
| 2477 | |
| 2478 // Estimates freshness and use frequency of the given string based | |
| 2479 // on how close it is to the new space top and its recorded usage | |
| 2480 // history. | |
| 2481 static inline bool IsFreshUnusedString(i::Handle<i::String> string) { | |
| 2482 i::Address address = reinterpret_cast<i::Address>(*string); | |
| 2483 i::Address top = i::Heap::NewSpaceTop(); | |
| 2484 return IsFreshString(address, top) && IsUseCountLow(top); | |
| 2485 } | |
| 2486 | |
| 2487 private: | |
| 2488 static inline bool IsFreshString(i::Address string, i::Address top) { | |
| 2489 return top - kFreshnessLimit <= string && string <= top; | |
| 2490 } | |
| 2491 | |
| 2492 static inline bool IsUseCountLow(i::Address top) { | |
| 2493 if (last_top_ != top) return true; | |
| 2494 return use_count_ < kUseLimit; | |
| 2495 } | |
| 2496 | |
| 2497 static inline void IncrementUseCount(i::Address top) { | |
| 2498 if (last_top_ != top) { | |
| 2499 use_count_ = 0; | |
| 2500 last_top_ = top; | |
| 2501 } | |
| 2502 ++use_count_; | |
| 2503 } | |
| 2504 | |
| 2505 // How close to the new space top a fresh string has to be. | |
| 2506 static const int kFreshnessLimit = 1024; | |
| 2507 | |
| 2508 // The number of uses required to consider a string useful. | |
| 2509 static const int kUseLimit = 32; | |
| 2510 | |
| 2511 // Single use counter shared by all fresh strings. | |
| 2512 static int use_count_; | |
| 2513 | |
| 2514 // Last new space top when the use count above was valid. | |
| 2515 static i::Address last_top_; | |
| 2516 }; | |
| 2517 | |
| 2518 int StringTracker::use_count_ = 0; | |
| 2519 i::Address StringTracker::last_top_ = NULL; | |
| 2520 | |
| 2521 } // namespace | |
| 2522 | |
| 2523 | |
| 2461 int String::Length() const { | 2524 int String::Length() const { |
| 2462 if (IsDeadCheck("v8::String::Length()")) return 0; | 2525 if (IsDeadCheck("v8::String::Length()")) return 0; |
| 2463 return Utils::OpenHandle(this)->length(); | 2526 return Utils::OpenHandle(this)->length(); |
| 2464 } | 2527 } |
| 2465 | 2528 |
| 2466 | 2529 |
| 2467 int String::Utf8Length() const { | 2530 int String::Utf8Length() const { |
| 2468 if (IsDeadCheck("v8::String::Utf8Length()")) return 0; | 2531 if (IsDeadCheck("v8::String::Utf8Length()")) return 0; |
| 2469 return Utils::OpenHandle(this)->Utf8Length(); | 2532 return Utils::OpenHandle(this)->Utf8Length(); |
| 2470 } | 2533 } |
| 2471 | 2534 |
| 2472 | 2535 |
| 2473 int String::WriteUtf8(char* buffer, int capacity) const { | 2536 int String::WriteUtf8(char* buffer, int capacity) const { |
| 2474 if (IsDeadCheck("v8::String::WriteUtf8()")) return 0; | 2537 if (IsDeadCheck("v8::String::WriteUtf8()")) return 0; |
| 2475 LOG_API("String::WriteUtf8"); | 2538 LOG_API("String::WriteUtf8"); |
| 2476 ENTER_V8; | 2539 ENTER_V8; |
| 2477 i::Handle<i::String> str = Utils::OpenHandle(this); | 2540 i::Handle<i::String> str = Utils::OpenHandle(this); |
| 2541 StringTracker::RecordWrite(str); | |
| 2478 write_input_buffer.Reset(0, *str); | 2542 write_input_buffer.Reset(0, *str); |
| 2479 int len = str->length(); | 2543 int len = str->length(); |
| 2480 // Encode the first K - 3 bytes directly into the buffer since we | 2544 // Encode the first K - 3 bytes directly into the buffer since we |
| 2481 // know there's room for them. If no capacity is given we copy all | 2545 // know there's room for them. If no capacity is given we copy all |
| 2482 // of them here. | 2546 // of them here. |
| 2483 int fast_end = capacity - (unibrow::Utf8::kMaxEncodedSize - 1); | 2547 int fast_end = capacity - (unibrow::Utf8::kMaxEncodedSize - 1); |
| 2484 int i; | 2548 int i; |
| 2485 int pos = 0; | 2549 int pos = 0; |
| 2486 for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) { | 2550 for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) { |
| 2487 i::uc32 c = write_input_buffer.GetNext(); | 2551 i::uc32 c = write_input_buffer.GetNext(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 2511 return pos; | 2575 return pos; |
| 2512 } | 2576 } |
| 2513 | 2577 |
| 2514 | 2578 |
| 2515 int String::WriteAscii(char* buffer, int start, int length) const { | 2579 int String::WriteAscii(char* buffer, int start, int length) const { |
| 2516 if (IsDeadCheck("v8::String::WriteAscii()")) return 0; | 2580 if (IsDeadCheck("v8::String::WriteAscii()")) return 0; |
| 2517 LOG_API("String::WriteAscii"); | 2581 LOG_API("String::WriteAscii"); |
| 2518 ENTER_V8; | 2582 ENTER_V8; |
| 2519 ASSERT(start >= 0 && length >= -1); | 2583 ASSERT(start >= 0 && length >= -1); |
| 2520 i::Handle<i::String> str = Utils::OpenHandle(this); | 2584 i::Handle<i::String> str = Utils::OpenHandle(this); |
| 2585 StringTracker::RecordWrite(str); | |
| 2521 // Flatten the string for efficiency. This applies whether we are | 2586 // Flatten the string for efficiency. This applies whether we are |
| 2522 // using StringInputBuffer or Get(i) to access the characters. | 2587 // using StringInputBuffer or Get(i) to access the characters. |
| 2523 str->TryFlattenIfNotFlat(); | 2588 str->TryFlattenIfNotFlat(); |
| 2524 int end = length; | 2589 int end = length; |
| 2525 if ( (length == -1) || (length > str->length() - start) ) | 2590 if ( (length == -1) || (length > str->length() - start) ) |
| 2526 end = str->length() - start; | 2591 end = str->length() - start; |
| 2527 if (end < 0) return 0; | 2592 if (end < 0) return 0; |
| 2528 write_input_buffer.Reset(start, *str); | 2593 write_input_buffer.Reset(start, *str); |
| 2529 int i; | 2594 int i; |
| 2530 for (i = 0; i < end; i++) { | 2595 for (i = 0; i < end; i++) { |
| 2531 char c = static_cast<char>(write_input_buffer.GetNext()); | 2596 char c = static_cast<char>(write_input_buffer.GetNext()); |
| 2532 if (c == '\0') c = ' '; | 2597 if (c == '\0') c = ' '; |
| 2533 buffer[i] = c; | 2598 buffer[i] = c; |
| 2534 } | 2599 } |
| 2535 if (length == -1 || i < length) | 2600 if (length == -1 || i < length) |
| 2536 buffer[i] = '\0'; | 2601 buffer[i] = '\0'; |
| 2537 return i; | 2602 return i; |
| 2538 } | 2603 } |
| 2539 | 2604 |
| 2540 | 2605 |
| 2541 int String::Write(uint16_t* buffer, int start, int length) const { | 2606 int String::Write(uint16_t* buffer, int start, int length) const { |
| 2542 if (IsDeadCheck("v8::String::Write()")) return 0; | 2607 if (IsDeadCheck("v8::String::Write()")) return 0; |
| 2543 LOG_API("String::Write"); | 2608 LOG_API("String::Write"); |
| 2544 ENTER_V8; | 2609 ENTER_V8; |
| 2545 ASSERT(start >= 0 && length >= -1); | 2610 ASSERT(start >= 0 && length >= -1); |
| 2546 i::Handle<i::String> str = Utils::OpenHandle(this); | 2611 i::Handle<i::String> str = Utils::OpenHandle(this); |
| 2612 StringTracker::RecordWrite(str); | |
| 2547 int end = length; | 2613 int end = length; |
| 2548 if ( (length == -1) || (length > str->length() - start) ) | 2614 if ( (length == -1) || (length > str->length() - start) ) |
| 2549 end = str->length() - start; | 2615 end = str->length() - start; |
| 2550 if (end < 0) return 0; | 2616 if (end < 0) return 0; |
| 2551 i::String::WriteToFlat(*str, buffer, start, end); | 2617 i::String::WriteToFlat(*str, buffer, start, end); |
| 2552 if (length == -1 || end < length) | 2618 if (length == -1 || end < length) |
| 2553 buffer[end] = '\0'; | 2619 buffer[end] = '\0'; |
| 2554 return end; | 2620 return end; |
| 2555 } | 2621 } |
| 2556 | 2622 |
| (...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3104 i::ExternalStringTable::AddString(*result); | 3170 i::ExternalStringTable::AddString(*result); |
| 3105 return Utils::ToLocal(result); | 3171 return Utils::ToLocal(result); |
| 3106 } | 3172 } |
| 3107 | 3173 |
| 3108 | 3174 |
| 3109 bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { | 3175 bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { |
| 3110 if (IsDeadCheck("v8::String::MakeExternal()")) return false; | 3176 if (IsDeadCheck("v8::String::MakeExternal()")) return false; |
| 3111 if (this->IsExternal()) return false; // Already an external string. | 3177 if (this->IsExternal()) return false; // Already an external string. |
| 3112 ENTER_V8; | 3178 ENTER_V8; |
| 3113 i::Handle<i::String> obj = Utils::OpenHandle(this); | 3179 i::Handle<i::String> obj = Utils::OpenHandle(this); |
| 3180 if (StringTracker::IsFreshUnusedString(obj)) return false; | |
| 3114 bool result = obj->MakeExternal(resource); | 3181 bool result = obj->MakeExternal(resource); |
| 3115 if (result && !obj->IsSymbol()) { | 3182 if (result && !obj->IsSymbol()) { |
| 3116 i::ExternalStringTable::AddString(*obj); | 3183 i::ExternalStringTable::AddString(*obj); |
| 3117 } | 3184 } |
| 3118 return result; | 3185 return result; |
| 3119 } | 3186 } |
| 3120 | 3187 |
| 3121 | 3188 |
| 3122 Local<String> v8::String::NewExternal( | 3189 Local<String> v8::String::NewExternal( |
| 3123 v8::String::ExternalAsciiStringResource* resource) { | 3190 v8::String::ExternalAsciiStringResource* resource) { |
| 3124 EnsureInitialized("v8::String::NewExternal()"); | 3191 EnsureInitialized("v8::String::NewExternal()"); |
| 3125 LOG_API("String::NewExternal"); | 3192 LOG_API("String::NewExternal"); |
| 3126 ENTER_V8; | 3193 ENTER_V8; |
| 3127 i::Handle<i::String> result = NewExternalAsciiStringHandle(resource); | 3194 i::Handle<i::String> result = NewExternalAsciiStringHandle(resource); |
| 3128 i::ExternalStringTable::AddString(*result); | 3195 i::ExternalStringTable::AddString(*result); |
| 3129 return Utils::ToLocal(result); | 3196 return Utils::ToLocal(result); |
| 3130 } | 3197 } |
| 3131 | 3198 |
| 3132 | 3199 |
| 3133 bool v8::String::MakeExternal( | 3200 bool v8::String::MakeExternal( |
| 3134 v8::String::ExternalAsciiStringResource* resource) { | 3201 v8::String::ExternalAsciiStringResource* resource) { |
| 3135 if (IsDeadCheck("v8::String::MakeExternal()")) return false; | 3202 if (IsDeadCheck("v8::String::MakeExternal()")) return false; |
| 3136 if (this->IsExternal()) return false; // Already an external string. | 3203 if (this->IsExternal()) return false; // Already an external string. |
| 3137 ENTER_V8; | 3204 ENTER_V8; |
| 3138 i::Handle<i::String> obj = Utils::OpenHandle(this); | 3205 i::Handle<i::String> obj = Utils::OpenHandle(this); |
| 3206 if (StringTracker::IsFreshUnusedString(obj)) return false; | |
| 3139 bool result = obj->MakeExternal(resource); | 3207 bool result = obj->MakeExternal(resource); |
| 3140 if (result && !obj->IsSymbol()) { | 3208 if (result && !obj->IsSymbol()) { |
| 3141 i::ExternalStringTable::AddString(*obj); | 3209 i::ExternalStringTable::AddString(*obj); |
| 3142 } | 3210 } |
| 3143 return result; | 3211 return result; |
| 3144 } | 3212 } |
| 3145 | 3213 |
| 3146 | 3214 |
| 3147 bool v8::String::CanMakeExternal() { | 3215 bool v8::String::CanMakeExternal() { |
| 3148 if (IsDeadCheck("v8::String::CanMakeExternal()")) return false; | 3216 if (IsDeadCheck("v8::String::CanMakeExternal()")) return false; |
| 3149 i::Handle<i::String> obj = Utils::OpenHandle(this); | 3217 i::Handle<i::String> obj = Utils::OpenHandle(this); |
| 3218 if (StringTracker::IsFreshUnusedString(obj)) return false; | |
| 3150 int size = obj->Size(); // Byte size of the original string. | 3219 int size = obj->Size(); // Byte size of the original string. |
| 3151 if (size < i::ExternalString::kSize) | 3220 if (size < i::ExternalString::kSize) |
| 3152 return false; | 3221 return false; |
| 3153 i::StringShape shape(*obj); | 3222 i::StringShape shape(*obj); |
| 3154 return !shape.IsExternal(); | 3223 return !shape.IsExternal(); |
| 3155 } | 3224 } |
| 3156 | 3225 |
| 3157 | 3226 |
| 3158 Local<v8::Object> v8::Object::New() { | 3227 Local<v8::Object> v8::Object::New() { |
| 3159 EnsureInitialized("v8::Object::New()"); | 3228 EnsureInitialized("v8::Object::New()"); |
| (...skipping 679 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3839 | 3908 |
| 3840 | 3909 |
| 3841 char* HandleScopeImplementer::Iterate(ObjectVisitor* v, char* storage) { | 3910 char* HandleScopeImplementer::Iterate(ObjectVisitor* v, char* storage) { |
| 3842 HandleScopeImplementer* thread_local = | 3911 HandleScopeImplementer* thread_local = |
| 3843 reinterpret_cast<HandleScopeImplementer*>(storage); | 3912 reinterpret_cast<HandleScopeImplementer*>(storage); |
| 3844 thread_local->IterateThis(v); | 3913 thread_local->IterateThis(v); |
| 3845 return storage + ArchiveSpacePerThread(); | 3914 return storage + ArchiveSpacePerThread(); |
| 3846 } | 3915 } |
| 3847 | 3916 |
| 3848 } } // namespace v8::internal | 3917 } } // namespace v8::internal |
| OLD | NEW |