Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/api.cc

Issue 608006: Don't externalize fresh strings. (Closed)
Patch Set: Tracking of string usage. Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | test/cctest/test-api.cc » ('j') | test/cctest/test-api.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | test/cctest/test-api.cc » ('j') | test/cctest/test-api.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698