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 |