OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 10636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10647 ASSERT(args.length() == 2); | 10647 ASSERT(args.length() == 2); |
10648 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) + | 10648 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) + |
10649 Smi::cast(args[1])->value()); | 10649 Smi::cast(args[1])->value()); |
10650 Top::PrintStack(); | 10650 Top::PrintStack(); |
10651 OS::Abort(); | 10651 OS::Abort(); |
10652 UNREACHABLE(); | 10652 UNREACHABLE(); |
10653 return NULL; | 10653 return NULL; |
10654 } | 10654 } |
10655 | 10655 |
10656 | 10656 |
10657 MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj, | |
10658 int index, | |
10659 Object* key_obj) { | |
10660 ASSERT(index % 2 == 0); // index of the key | |
10661 ASSERT(index >= JSFunctionResultCache::kEntriesIndex); | |
10662 ASSERT(index < cache_obj->length()); | |
10663 | |
10664 HandleScope scope; | |
10665 | |
10666 Handle<FixedArray> cache(cache_obj); | |
10667 Handle<Object> key(key_obj); | |
10668 Handle<JSFunction> factory(JSFunction::cast( | |
10669 cache->get(JSFunctionResultCache::kFactoryIndex))); | |
10670 // TODO(antonm): consider passing a receiver when constructing a cache. | |
10671 Handle<Object> receiver(Top::global_context()->global()); | |
10672 | |
10673 Handle<Object> value; | |
10674 { | |
10675 // This handle is nor shared, nor used later, so it's safe. | |
10676 Object** argv[] = { key.location() }; | |
10677 bool pending_exception = false; | |
10678 value = Execution::Call(factory, | |
10679 receiver, | |
10680 1, | |
10681 argv, | |
10682 &pending_exception); | |
10683 if (pending_exception) return Failure::Exception(); | |
10684 } | |
10685 | |
10686 cache->set(index, *key); | |
10687 cache->set(index + 1, *value); | |
10688 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index)); | |
10689 | |
10690 return *value; | |
10691 } | |
10692 | |
10693 | |
10694 static MaybeObject* Runtime_GetFromCache(Arguments args) { | 10657 static MaybeObject* Runtime_GetFromCache(Arguments args) { |
10695 // This is only called from codegen, so checks might be more lax. | 10658 // This is only called from codegen, so checks might be more lax. |
10696 CONVERT_CHECKED(FixedArray, cache, args[0]); | 10659 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]); |
10697 Object* key = args[1]; | 10660 Object* key = args[1]; |
10698 | 10661 |
10699 const int finger_index = | 10662 int finger_index = cache->finger_index(); |
10700 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value(); | |
10701 | |
10702 Object* o = cache->get(finger_index); | 10663 Object* o = cache->get(finger_index); |
10703 if (o == key) { | 10664 if (o == key) { |
10704 // The fastest case: hit the same place again. | 10665 // The fastest case: hit the same place again. |
10705 return cache->get(finger_index + 1); | 10666 return cache->get(finger_index + 1); |
10706 } | 10667 } |
10707 | 10668 |
10708 for (int i = finger_index - 2; | 10669 for (int i = finger_index - 2; |
10709 i >= JSFunctionResultCache::kEntriesIndex; | 10670 i >= JSFunctionResultCache::kEntriesIndex; |
10710 i -= 2) { | 10671 i -= 2) { |
10711 o = cache->get(i); | 10672 o = cache->get(i); |
10712 if (o == key) { | 10673 if (o == key) { |
10713 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i)); | 10674 cache->set_finger_index(i); |
10714 return cache->get(i + 1); | 10675 return cache->get(i + 1); |
10715 } | 10676 } |
10716 } | 10677 } |
10717 | 10678 |
10718 const int size = | 10679 int size = cache->size(); |
10719 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value(); | |
10720 ASSERT(size <= cache->length()); | 10680 ASSERT(size <= cache->length()); |
10721 | 10681 |
10722 for (int i = size - 2; i > finger_index; i -= 2) { | 10682 for (int i = size - 2; i > finger_index; i -= 2) { |
10723 o = cache->get(i); | 10683 o = cache->get(i); |
10724 if (o == key) { | 10684 if (o == key) { |
10725 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i)); | 10685 cache->set_finger_index(i); |
10726 return cache->get(i + 1); | 10686 return cache->get(i + 1); |
10727 } | 10687 } |
10728 } | 10688 } |
10729 | 10689 |
10730 // Cache miss. If we have spare room, put new data into it, otherwise | 10690 // There is no value in the cache. Invoke the function and cache result. |
10731 // evict post finger entry which must be least recently used. | 10691 HandleScope scope; |
10732 if (size < cache->length()) { | 10692 |
10733 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2)); | 10693 Handle<JSFunctionResultCache> cache_handle(cache); |
10734 return CacheMiss(cache, size, key); | 10694 Handle<Object> key_handle(key); |
| 10695 Handle<Object> value; |
| 10696 { |
| 10697 Handle<JSFunction> factory(JSFunction::cast( |
| 10698 cache_handle->get(JSFunctionResultCache::kFactoryIndex))); |
| 10699 // TODO(antonm): consider passing a receiver when constructing a cache. |
| 10700 Handle<Object> receiver(Top::global_context()->global()); |
| 10701 // This handle is nor shared, nor used later, so it's safe. |
| 10702 Object** argv[] = { key_handle.location() }; |
| 10703 bool pending_exception = false; |
| 10704 value = Execution::Call(factory, |
| 10705 receiver, |
| 10706 1, |
| 10707 argv, |
| 10708 &pending_exception); |
| 10709 if (pending_exception) return Failure::Exception(); |
| 10710 } |
| 10711 |
| 10712 #ifdef DEBUG |
| 10713 cache_handle->JSFunctionResultCacheVerify(); |
| 10714 #endif |
| 10715 |
| 10716 // Function invocation may have cleared the cache. Reread all the data. |
| 10717 finger_index = cache_handle->finger_index(); |
| 10718 size = cache_handle->size(); |
| 10719 |
| 10720 // If we have spare room, put new data into it, otherwise evict post finger |
| 10721 // entry which is likely to be the least recently used. |
| 10722 int index = -1; |
| 10723 if (size < cache_handle->length()) { |
| 10724 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize); |
| 10725 index = size; |
10735 } else { | 10726 } else { |
10736 int target_index = finger_index + JSFunctionResultCache::kEntrySize; | 10727 index = finger_index + JSFunctionResultCache::kEntrySize; |
10737 if (target_index == cache->length()) { | 10728 if (index == cache_handle->length()) { |
10738 target_index = JSFunctionResultCache::kEntriesIndex; | 10729 index = JSFunctionResultCache::kEntriesIndex; |
10739 } | 10730 } |
10740 return CacheMiss(cache, target_index, key); | |
10741 } | 10731 } |
| 10732 |
| 10733 ASSERT(index % 2 == 0); |
| 10734 ASSERT(index >= JSFunctionResultCache::kEntriesIndex); |
| 10735 ASSERT(index < cache_handle->length()); |
| 10736 |
| 10737 cache_handle->set(index, *key_handle); |
| 10738 cache_handle->set(index + 1, *value); |
| 10739 cache_handle->set_finger_index(index); |
| 10740 |
| 10741 #ifdef DEBUG |
| 10742 cache_handle->JSFunctionResultCacheVerify(); |
| 10743 #endif |
| 10744 |
| 10745 return *value; |
10742 } | 10746 } |
10743 | 10747 |
10744 #ifdef DEBUG | 10748 #ifdef DEBUG |
10745 // ListNatives is ONLY used by the fuzz-natives.js in debug mode | 10749 // ListNatives is ONLY used by the fuzz-natives.js in debug mode |
10746 // Exclude the code in release mode. | 10750 // Exclude the code in release mode. |
10747 static MaybeObject* Runtime_ListNatives(Arguments args) { | 10751 static MaybeObject* Runtime_ListNatives(Arguments args) { |
10748 ASSERT(args.length() == 0); | 10752 ASSERT(args.length() == 0); |
10749 HandleScope scope; | 10753 HandleScope scope; |
10750 Handle<JSArray> result = Factory::NewJSArray(0); | 10754 Handle<JSArray> result = Factory::NewJSArray(0); |
10751 int index = 0; | 10755 int index = 0; |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10863 } else { | 10867 } else { |
10864 // Handle last resort GC and make sure to allow future allocations | 10868 // Handle last resort GC and make sure to allow future allocations |
10865 // to grow the heap without causing GCs (if possible). | 10869 // to grow the heap without causing GCs (if possible). |
10866 Counters::gc_last_resort_from_js.Increment(); | 10870 Counters::gc_last_resort_from_js.Increment(); |
10867 Heap::CollectAllGarbage(false); | 10871 Heap::CollectAllGarbage(false); |
10868 } | 10872 } |
10869 } | 10873 } |
10870 | 10874 |
10871 | 10875 |
10872 } } // namespace v8::internal | 10876 } } // namespace v8::internal |
OLD | NEW |