1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_OBJECTS_OSR_OPTIMIZED_CODE_CACHE_H_
6#define V8_OBJECTS_OSR_OPTIMIZED_CODE_CACHE_H_
7
8#include "src/objects/fixed-array.h"
9
10// Has to be the last include (doesn't have include guards):
11#include "src/objects/object-macros.h"
12
13namespace v8 {
14namespace internal {
15
16// This enum is a performance optimization for accessing the OSR code cache -
17// we can skip cache iteration in many cases unless there are multiple entries
18// for a particular SharedFunctionInfo.
19enum OSRCodeCacheStateOfSFI : uint8_t {
20  kNotCached,       // Likely state.
21  kCachedOnce,      // Unlikely state, one entry.
22  kCachedMultiple,  // Very unlikely state, multiple entries.
23};
24
25// TODO(jgruber): There are a few issues with the current implementation:
26//
27// - The cache is a flat list, thus any search operation is O(N). This resulted
28//   in optimization attempts, see OSRCodeCacheStateOfSFI.
29// - We always iterate up to `length` (== capacity).
30// - We essentially reimplement WeakArrayList, i.e. growth and shrink logic.
31// - On overflow, new entries always pick slot 0.
32//
33// There are a few alternatives:
34//
35// 1) we could reuse WeakArrayList logic (but then we'd still have to
36//    implement custom compaction due to our entry tuple structure).
37// 2) we could reuse CompilationCacheTable (but then we lose weakness and have
38//    to deal with aging).
39// 3) we could try to base on a weak HashTable variant (EphemeronHashTable?).
40class V8_EXPORT OSROptimizedCodeCache : public WeakFixedArray {
41 public:
42  DECL_CAST(OSROptimizedCodeCache)
43
44  static Handle<OSROptimizedCodeCache> Empty(Isolate* isolate);
45
46  // Caches the optimized code |code| corresponding to the shared function
47  // |shared| and bailout id |osr_offset| in the OSROptimized code cache.
48  // If the OSR code cache wasn't created before it creates a code cache with
49  // kOSRCodeCacheInitialLength entries.
50  static void Insert(Isolate* isolate, Handle<NativeContext> context,
51                     Handle<SharedFunctionInfo> shared, Handle<CodeT> code,
52                     BytecodeOffset osr_offset);
53
54  // Returns the code corresponding to the shared function |shared| and
55  // BytecodeOffset |offset| if an entry exists in the cache. Returns an empty
56  // object otherwise.
57  CodeT TryGet(SharedFunctionInfo shared, BytecodeOffset osr_offset,
58               Isolate* isolate);
59
60  std::vector<BytecodeOffset> OsrOffsetsFor(SharedFunctionInfo shared);
61  base::Optional<BytecodeOffset> FirstOsrOffsetFor(SharedFunctionInfo shared);
62
63  // Remove all code objects marked for deoptimization from OSR code cache.
64  void EvictDeoptimizedCode(Isolate* isolate);
65
66  // Reduces the size of the OSR code cache if the number of valid entries are
67  // less than the current capacity of the cache.
68  static void Compact(Isolate* isolate, Handle<NativeContext> context);
69
70  // Sets the OSR optimized code cache to an empty array.
71  static void Clear(Isolate* isolate, NativeContext context);
72
73  enum OSRCodeCacheConstants {
74    kSharedOffset,
75    kCachedCodeOffset,
76    kOsrIdOffset,
77    kEntryLength
78  };
79
80  static constexpr int kInitialLength = OSRCodeCacheConstants::kEntryLength * 4;
81  static constexpr int kMaxLength = OSRCodeCacheConstants::kEntryLength * 1024;
82
83  // For osr-code-cache-unittest.cc.
84  MaybeObject RawGetForTesting(int index) const;
85  void RawSetForTesting(int index, MaybeObject value);
86
87 private:
88  // Hide raw accessors to avoid terminology confusion.
89  using WeakFixedArray::Get;
90  using WeakFixedArray::Set;
91
92  // Functions that implement heuristics on when to grow / shrink the cache.
93  static int CapacityForLength(int curr_capacity);
94  static bool NeedsTrimming(int num_valid_entries, int curr_capacity);
95  static int GrowOSRCache(Isolate* isolate,
96                          Handle<NativeContext> native_context,
97                          Handle<OSROptimizedCodeCache>* osr_cache);
98
99  // Helper functions to get individual items from an entry in the cache.
100  CodeT GetCodeFromEntry(int index);
101  SharedFunctionInfo GetSFIFromEntry(int index);
102  BytecodeOffset GetBytecodeOffsetFromEntry(int index);
103
104  inline int FindEntry(SharedFunctionInfo shared, BytecodeOffset osr_offset);
105  inline void ClearEntry(int src, Isolate* isolate);
106  inline void InitializeEntry(int entry, SharedFunctionInfo shared, CodeT code,
107                              BytecodeOffset osr_offset);
108  inline void MoveEntry(int src, int dst, Isolate* isolate);
109
110  OBJECT_CONSTRUCTORS(OSROptimizedCodeCache, WeakFixedArray);
111};
112
113}  // namespace internal
114}  // namespace v8
115
116#include "src/objects/object-macros-undef.h"
117
118#endif  // V8_OBJECTS_OSR_OPTIMIZED_CODE_CACHE_H_
119