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

Side by Side Diff: chrome/browser/nacl_host/pnacl_translation_cache.cc

Issue 15647018: Add read support to PNaClTranslationCache (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: use smaller 'large' file Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/nacl_host/pnacl_translation_cache.h" 5 #include "chrome/browser/nacl_host/pnacl_translation_cache.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 15 matching lines...) Expand all
26 26
27 } // namespace 27 } // namespace
28 28
29 namespace pnacl_cache { 29 namespace pnacl_cache {
30 // These are in pnacl_cache namespace instead of static so they can be used 30 // These are in pnacl_cache namespace instead of static so they can be used
31 // by the unit test. 31 // by the unit test.
32 const int kMaxDiskCacheSize = 1000 * 1024 * 1024; 32 const int kMaxDiskCacheSize = 1000 * 1024 * 1024;
33 const int kMaxMemCacheSize = 100 * 1024 * 1024; 33 const int kMaxMemCacheSize = 100 * 1024 * 1024;
34 34
35 ////////////////////////////////////////////////////////////////////// 35 //////////////////////////////////////////////////////////////////////
36 // Handle Storing to Cache. 36 // Handle Reading/Writing to Cache.
37 37
38 // PNaClTranslationCacheWriteEntry is a shim that provides storage for the 38 // PNaClTranslationCacheEntry is a shim that provides storage for the
39 // 'key' and 'data' strings as the disk_cache is performing various async 39 // 'key' and 'data' strings as the disk_cache is performing various async
40 // operations. It also tracks the open disk_cache::Entry 40 // operations. It also tracks the open disk_cache::Entry
41 // and ensures that the entry is closed. 41 // and ensures that the entry is closed.
42 class PNaClTranslationCacheWriteEntry 42 class PNaClTranslationCacheEntry
43 : public base::RefCounted<PNaClTranslationCacheWriteEntry> { 43 : public base::RefCounted<PNaClTranslationCacheEntry> {
44 public: 44 public:
45 PNaClTranslationCacheWriteEntry(base::WeakPtr<PNaClTranslationCache> cache, 45 PNaClTranslationCacheEntry(base::WeakPtr<PNaClTranslationCache> cache,
46 const std::string& key, 46 const std::string& key,
47 const std::string& nexe, 47 std::string* read_nexe,
48 const net::CompletionCallback& callback); 48 const std::string& write_nexe,
49 const CompletionCallback& callback,
50 bool is_read);
51 void Start();
49 52
50 void Cache(); 53 // Writes: ---
51
52 // ---
53 // v | 54 // v |
54 // Cache -> Open Existing --------------> Write ---> Close 55 // Start -> Open Existing --------------> Write ---> Close
55 // \ ^ 56 // \ ^
56 // \ / 57 // \ /
57 // --> Create -- 58 // --> Create --
59 // Reads:
60 // Start -> Open --------Read ----> Close
61 // | ^
62 // |__|
58 enum CacheStep { 63 enum CacheStep {
59 UNINITIALIZED, 64 UNINITIALIZED,
60 OPEN_ENTRY, 65 OPEN_ENTRY,
61 CREATE_ENTRY, 66 CREATE_ENTRY,
62 WRITE_ENTRY, 67 TRANSFER_ENTRY,
63 CLOSE_ENTRY 68 CLOSE_ENTRY
64 }; 69 };
65 70
66 private: 71 private:
67 friend class base::RefCounted<PNaClTranslationCacheWriteEntry>; 72 friend class base::RefCounted<PNaClTranslationCacheEntry>;
68 ~PNaClTranslationCacheWriteEntry(); 73 ~PNaClTranslationCacheEntry();
69 74
75 // Try to open an existing entry in the backend
76 void OpenEntry();
77 // Create a new entry in the backend (for writes)
70 void CreateEntry(); 78 void CreateEntry();
71 79 // Write |len| bytes to the backend, starting at |offset|
72 void OpenEntry(); 80 void WriteEntry(int offset, int len);
73 81 // Read |len| bytes from the backend, starting at |offset|
74 void WriteEntry(int bytes_to_skip); 82 void ReadEntry(int offset, int len);
75 83 // If there was an error, doom the entry. Then post a task to the IO
84 // thread to close (and delete) it.
76 void CloseEntry(int rv); 85 void CloseEntry(int rv);
77 86 // Call the user callback, and signal to the cache to delete this.
87 void Finish(int rv);
88 // Used as the callback for all operations to the backend. Handle state
89 // transitions, track bytes transferred, and call the other helper methods.
78 void DispatchNext(int rv); 90 void DispatchNext(int rv);
91 // Get the total transfer size. For reads, must be called after the backend
92 // entry has been opened.
93 int GetTransferSize();
79 94
80 base::WeakPtr<PNaClTranslationCache> cache_; 95 base::WeakPtr<PNaClTranslationCache> cache_;
81 96
82 std::string key_; 97 std::string key_;
83 std::string nexe_; 98 std::string* read_nexe_;
99 std::string write_nexe_;
84 disk_cache::Entry* entry_; 100 disk_cache::Entry* entry_;
85 CacheStep step_; 101 CacheStep step_;
102 bool is_read_;
103 int bytes_transferred_;
104 int bytes_to_transfer_;
105 scoped_refptr<net::IOBufferWithSize> read_buf_;
86 CompletionCallback finish_callback_; 106 CompletionCallback finish_callback_;
87 base::ThreadChecker thread_checker_; 107 base::ThreadChecker thread_checker_;
88 DISALLOW_COPY_AND_ASSIGN(PNaClTranslationCacheWriteEntry); 108 DISALLOW_COPY_AND_ASSIGN(PNaClTranslationCacheEntry);
89 }; 109 };
90 110
91 PNaClTranslationCacheWriteEntry::PNaClTranslationCacheWriteEntry( 111 PNaClTranslationCacheEntry::PNaClTranslationCacheEntry(
92 base::WeakPtr<PNaClTranslationCache> cache, 112 base::WeakPtr<PNaClTranslationCache> cache,
93 const std::string& key, 113 const std::string& key,
94 const std::string& nexe, 114 std::string* read_nexe,
95 const net::CompletionCallback& callback) 115 const std::string& write_nexe,
116 const CompletionCallback& callback,
117 bool is_read)
96 : cache_(cache), 118 : cache_(cache),
97 key_(key), 119 key_(key),
98 nexe_(nexe), 120 read_nexe_(read_nexe),
121 write_nexe_(write_nexe),
99 entry_(NULL), 122 entry_(NULL),
100 step_(UNINITIALIZED), 123 step_(UNINITIALIZED),
124 is_read_(is_read),
125 bytes_transferred_(0),
126 bytes_to_transfer_(-1),
101 finish_callback_(callback) {} 127 finish_callback_(callback) {}
102 128
103 PNaClTranslationCacheWriteEntry::~PNaClTranslationCacheWriteEntry() { 129 PNaClTranslationCacheEntry::~PNaClTranslationCacheEntry() {
104 if (entry_) 130 // Ensure we have called the user's callback
105 BrowserThread::PostTask( 131 DCHECK(finish_callback_.is_null());
106 BrowserThread::IO, FROM_HERE, base::Bind(&CloseDiskCacheEntry, entry_));
107 } 132 }
108 133
109 void PNaClTranslationCacheWriteEntry::Cache() { 134 void PNaClTranslationCacheEntry::Start() {
110 DCHECK(thread_checker_.CalledOnValidThread()); 135 DCHECK(thread_checker_.CalledOnValidThread());
111 step_ = OPEN_ENTRY; 136 step_ = OPEN_ENTRY;
112 OpenEntry(); 137 OpenEntry();
113 } 138 }
114 139
115 // OpenEntry, CreateEntry, WriteEntry, and CloseEntry are only called from 140 // OpenEntry, CreateEntry, WriteEntry, ReadEntry and CloseEntry are only called
116 // DispatchNext, so they know that cache_ is still valid. 141 // from DispatchNext, so they know that cache_ is still valid.
117 void PNaClTranslationCacheWriteEntry::OpenEntry() { 142 void PNaClTranslationCacheEntry::OpenEntry() {
118 int rv = cache_->backend()->OpenEntry( 143 int rv = cache_->backend()
119 key_, 144 ->OpenEntry(key_,
120 &entry_, 145 &entry_,
121 base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this)); 146 base::Bind(&PNaClTranslationCacheEntry::DispatchNext, this));
122 if (rv != net::ERR_IO_PENDING) 147 if (rv != net::ERR_IO_PENDING)
123 DispatchNext(rv); 148 DispatchNext(rv);
124 } 149 }
125 150
126 void PNaClTranslationCacheWriteEntry::CreateEntry() { 151 void PNaClTranslationCacheEntry::CreateEntry() {
127 int rv = cache_->backend()->CreateEntry( 152 int rv = cache_->backend()->CreateEntry(
128 key_, 153 key_,
129 &entry_, 154 &entry_,
130 base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this)); 155 base::Bind(&PNaClTranslationCacheEntry::DispatchNext, this));
131 if (rv != net::ERR_IO_PENDING) 156 if (rv != net::ERR_IO_PENDING)
132 DispatchNext(rv); 157 DispatchNext(rv);
133 } 158 }
134 159
135 void PNaClTranslationCacheWriteEntry::WriteEntry(int bytes_to_skip) { 160 void PNaClTranslationCacheEntry::WriteEntry(int offset, int len) {
136 nexe_ = nexe_.substr(bytes_to_skip); 161 scoped_refptr<net::StringIOBuffer> io_buf =
137 scoped_refptr<net::StringIOBuffer> io_buf = new net::StringIOBuffer(nexe_); 162 new net::StringIOBuffer(write_nexe_.substr(offset, len));
138 int rv = entry_->WriteData( 163 int rv = entry_->WriteData(
139 1, 164 1,
140 0, 165 offset,
141 io_buf, 166 io_buf,
142 nexe_.length(), 167 len,
143 base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this), 168 base::Bind(&PNaClTranslationCacheEntry::DispatchNext, this),
144 false); 169 false);
145 if (rv != net::ERR_IO_PENDING) 170 if (rv != net::ERR_IO_PENDING)
146 DispatchNext(rv); 171 DispatchNext(rv);
147 } 172 }
148 173
149 void PNaClTranslationCacheWriteEntry::CloseEntry(int rv) { 174 void PNaClTranslationCacheEntry::ReadEntry(int offset, int len) {
175 read_buf_ = new net::IOBufferWithSize(len);
176 int rv = entry_->ReadData(
177 1,
178 offset,
179 read_buf_,
180 len,
181 base::Bind(&PNaClTranslationCacheEntry::DispatchNext, this));
182 if (rv != net::ERR_IO_PENDING)
183 DispatchNext(rv);
184 }
185
186 int PNaClTranslationCacheEntry::GetTransferSize() {
187 if (is_read_) {
188 DCHECK(entry_);
189 return entry_->GetDataSize(1);
190 }
191 return write_nexe_.size();
192 }
193
194 void PNaClTranslationCacheEntry::CloseEntry(int rv) {
195 DCHECK(entry_);
150 if (rv < 0) 196 if (rv < 0)
151 entry_->Doom(); 197 entry_->Doom();
198 BrowserThread::PostTask(
199 BrowserThread::IO, FROM_HERE, base::Bind(&CloseDiskCacheEntry, entry_));
200 Finish(rv);
201 }
202
203 void PNaClTranslationCacheEntry::Finish(int rv) {
152 if (!finish_callback_.is_null()) { 204 if (!finish_callback_.is_null()) {
153 finish_callback_.Run(rv); 205 finish_callback_.Run(rv);
154 finish_callback_.Reset(); 206 finish_callback_.Reset();
155 } 207 }
156 cache_->WriteComplete(this); 208 cache_->OpComplete(this);
157 } 209 }
158 210
159 void PNaClTranslationCacheWriteEntry::DispatchNext(int rv) { 211 void PNaClTranslationCacheEntry::DispatchNext(int rv) {
160 DCHECK(thread_checker_.CalledOnValidThread()); 212 DCHECK(thread_checker_.CalledOnValidThread());
161 if (!cache_) 213 if (!cache_)
162 return; 214 return;
163 215
164 switch (step_) { 216 switch (step_) {
165 case UNINITIALIZED: 217 case UNINITIALIZED:
166 LOG(ERROR) << "Unexpected step in DispatchNext"; 218 LOG(ERROR) << "Unexpected step in DispatchNext";
167 break; 219 break;
168 220
169 case OPEN_ENTRY: 221 case OPEN_ENTRY:
170 if (rv == net::OK) { 222 if (rv == net::OK) {
171 step_ = WRITE_ENTRY; 223 step_ = TRANSFER_ENTRY;
172 WriteEntry(0); 224 bytes_to_transfer_ = GetTransferSize();
225 is_read_ ? ReadEntry(0, bytes_to_transfer_)
226 : WriteEntry(0, bytes_to_transfer_);
173 } else { 227 } else {
228 if (is_read_) {
229 // Just a cache miss, not necessarily an error.
230 entry_ = NULL;
231 Finish(rv);
232 break;
233 }
174 step_ = CREATE_ENTRY; 234 step_ = CREATE_ENTRY;
175 CreateEntry(); 235 CreateEntry();
176 } 236 }
177 break; 237 break;
178 238
179 case CREATE_ENTRY: 239 case CREATE_ENTRY:
180 if (rv == net::OK) { 240 if (rv == net::OK) {
181 step_ = WRITE_ENTRY; 241 step_ = TRANSFER_ENTRY;
182 WriteEntry(0); 242 bytes_to_transfer_ = GetTransferSize();
243 WriteEntry(bytes_transferred_, bytes_to_transfer_ - bytes_transferred_);
183 } else { 244 } else {
184 LOG(ERROR) << "Failed to Open/Create a PNaCl Translation Cache Entry"; 245 LOG(ERROR) << "Failed to Create a PNaCl Translation Cache Entry";
185 CloseEntry(rv); 246 Finish(rv);
186 } 247 }
187 break; 248 break;
188 249
189 case WRITE_ENTRY: 250 case TRANSFER_ENTRY:
190 if (rv < 0) { 251 if (rv < 0) {
191 // We do not call DispatchNext directly if WriteEntry returns 252 // We do not call DispatchNext directly if WriteEntry/ReadEntry returns
192 // ERR_IO_PENDING, and the callback should not return that value either. 253 // ERR_IO_PENDING, and the callback should not return that value either.
193 LOG(ERROR) 254 LOG(ERROR)
194 << "Failed to complete write to PNaCl Translation Cache Entry: " 255 << "Failed to complete write to PNaCl Translation Cache Entry: "
195 << rv; 256 << rv;
196 step_ = CLOSE_ENTRY; 257 step_ = CLOSE_ENTRY;
197 CloseEntry(rv); 258 CloseEntry(rv);
198 break; 259 break;
260 } else if (rv > 0) {
261 // For reads, copy the data that was just returned
262 if (is_read_)
263 read_nexe_->append(read_buf_->data(), rv);
264 bytes_transferred_ += rv;
265 if (bytes_transferred_ < bytes_to_transfer_) {
266 int len = bytes_to_transfer_ - bytes_transferred_;
267 is_read_ ? ReadEntry(bytes_transferred_, len)
268 : WriteEntry(bytes_transferred_, len);
269 break;
270 }
199 } 271 }
200 if (rv == 0) { 272 // rv == 0 or we fell through (i.e. we have transferred all the bytes)
201 step_ = CLOSE_ENTRY; 273 step_ = CLOSE_ENTRY;
202 CloseEntry(rv); 274 CloseEntry(0);
203 break;
204 }
205 // rv bytes were written; call WriteEntry again to skip them and try to
206 // write the rest.
207 WriteEntry(rv);
208 break; 275 break;
209 276
210 case CLOSE_ENTRY: 277 case CLOSE_ENTRY:
211 step_ = UNINITIALIZED; 278 step_ = UNINITIALIZED;
212 break; 279 break;
213 } 280 }
214 } 281 }
215 282
216 ////////////////////////////////////////////////////////////////////// 283 //////////////////////////////////////////////////////////////////////
217 void PNaClTranslationCache::WriteComplete( 284 void PNaClTranslationCache::OpComplete(PNaClTranslationCacheEntry* entry) {
218 PNaClTranslationCacheWriteEntry* entry) { 285 open_entries_.erase(entry);
219 write_entries_.erase(entry);
220 } 286 }
221 287
222 ////////////////////////////////////////////////////////////////////// 288 //////////////////////////////////////////////////////////////////////
223 // Construction and cache backend initialization 289 // Construction and cache backend initialization
224 PNaClTranslationCache::PNaClTranslationCache() 290 PNaClTranslationCache::PNaClTranslationCache()
225 : disk_cache_(NULL), in_memory_(false) {} 291 : disk_cache_(NULL), in_memory_(false) {}
226 292
227 PNaClTranslationCache::~PNaClTranslationCache() { 293 PNaClTranslationCache::~PNaClTranslationCache() { delete disk_cache_; }
228 delete disk_cache_;
229 }
230 294
231 int PNaClTranslationCache::InitWithDiskBackend( 295 int PNaClTranslationCache::InitWithDiskBackend(
232 const base::FilePath& cache_dir, 296 const base::FilePath& cache_dir,
233 int cache_size, 297 int cache_size,
234 const net::CompletionCallback& callback) { 298 const CompletionCallback& callback) {
235 return Init(net::DISK_CACHE, cache_dir, cache_size, callback); 299 return Init(net::DISK_CACHE, cache_dir, cache_size, callback);
236 } 300 }
237 301
238 int PNaClTranslationCache::InitWithMemBackend( 302 int PNaClTranslationCache::InitWithMemBackend(
239 int cache_size, 303 int cache_size,
240 const net::CompletionCallback& callback) { 304 const CompletionCallback& callback) {
241 return Init(net::MEMORY_CACHE, base::FilePath(), cache_size, callback); 305 return Init(net::MEMORY_CACHE, base::FilePath(), cache_size, callback);
242 } 306 }
243 307
244 int PNaClTranslationCache::Init(net::CacheType cache_type, 308 int PNaClTranslationCache::Init(net::CacheType cache_type,
245 const base::FilePath& cache_dir, 309 const base::FilePath& cache_dir,
246 int cache_size, 310 int cache_size,
247 const net::CompletionCallback& callback) { 311 const CompletionCallback& callback) {
248 int rv = disk_cache::CreateCacheBackend( 312 int rv = disk_cache::CreateCacheBackend(
249 cache_type, 313 cache_type,
250 net::CACHE_BACKEND_DEFAULT, 314 net::CACHE_BACKEND_DEFAULT,
251 cache_dir, 315 cache_dir,
252 cache_size, 316 cache_size,
253 true /* force_initialize */, 317 true /* force_initialize */,
254 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE), 318 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE),
255 NULL, /* dummy net log */ 319 NULL, /* dummy net log */
256 &disk_cache_, 320 &disk_cache_,
257 base::Bind(&PNaClTranslationCache::OnCreateBackendComplete, AsWeakPtr())); 321 base::Bind(&PNaClTranslationCache::OnCreateBackendComplete, AsWeakPtr()));
258 init_callback_ = callback; 322 init_callback_ = callback;
259 if (rv != net::ERR_IO_PENDING) { 323 if (rv != net::ERR_IO_PENDING) {
260 OnCreateBackendComplete(rv); 324 OnCreateBackendComplete(rv);
261 } 325 }
262 return rv; 326 return rv;
263 } 327 }
264 328
265 void PNaClTranslationCache::OnCreateBackendComplete(int rv) { 329 void PNaClTranslationCache::OnCreateBackendComplete(int rv) {
266 // Invoke our client's callback function. 330 // Invoke our client's callback function.
267 if (!init_callback_.is_null()) { 331 if (!init_callback_.is_null()) {
268 init_callback_.Run(rv); 332 init_callback_.Run(rv);
269 init_callback_.Reset(); 333 init_callback_.Reset();
270 } 334 }
271 } 335 }
272 336
273 ////////////////////////////////////////////////////////////////////// 337 //////////////////////////////////////////////////////////////////////
274 // High-level API 338 // High-level API
275 339
276 // TODO(dschuff): Surely there must be a way to just create a null callback?
277 static void NullCallback(int ignored) {}
278
279 void PNaClTranslationCache::StoreNexe(const std::string& key, 340 void PNaClTranslationCache::StoreNexe(const std::string& key,
280 const std::string& nexe) { 341 const std::string& nexe) {
281 StoreNexe(key, nexe, base::Bind(NullCallback)); 342 StoreNexe(key, nexe, CompletionCallback());
282 } 343 }
283 344
284 void PNaClTranslationCache::StoreNexe(const std::string& key, 345 void PNaClTranslationCache::StoreNexe(const std::string& key,
285 const std::string& nexe, 346 const std::string& nexe,
286 const net::CompletionCallback& callback) { 347 const CompletionCallback& callback) {
287 PNaClTranslationCacheWriteEntry* entry = 348 PNaClTranslationCacheEntry* entry = new PNaClTranslationCacheEntry(
288 new PNaClTranslationCacheWriteEntry(AsWeakPtr(), key, nexe, callback); 349 AsWeakPtr(), key, NULL, nexe, callback, false);
289 write_entries_[entry] = entry; 350 open_entries_[entry] = entry;
290 entry->Cache(); 351 entry->Start();
291 } 352 }
292 353
293 int PNaClTranslationCache::GetNexe(const std::string& key, 354 void PNaClTranslationCache::GetNexe(const std::string& key,
294 std::string* nexe, 355 std::string* nexe,
295 const net::CompletionCallback& callback) { 356 const CompletionCallback& callback) {
296 // TODO(dschuff): Actually find the entry, and do the right thing. 357 PNaClTranslationCacheEntry* entry = new PNaClTranslationCacheEntry(
297 // Shader cache ended up making a separate ReadHelper, analogous 358 AsWeakPtr(), key, nexe, std::string(), callback, true);
298 // to the PNaClTranslationCacheWriteEntry. 359 open_entries_[entry] = entry;
299 return net::OK; 360 entry->Start();
300 } 361 }
301 362
302 int PNaClTranslationCache::InitCache(const base::FilePath& cache_directory, 363 int PNaClTranslationCache::InitCache(const base::FilePath& cache_directory,
303 bool in_memory, 364 bool in_memory,
304 const net::CompletionCallback& callback) { 365 const CompletionCallback& callback) {
305 int rv; 366 int rv;
306 in_memory_ = in_memory; 367 in_memory_ = in_memory;
307 if (in_memory_) { 368 if (in_memory_) {
308 rv = InitWithMemBackend(kMaxMemCacheSize, callback); 369 rv = InitWithMemBackend(kMaxMemCacheSize, callback);
309 } else { 370 } else {
310 rv = InitWithDiskBackend(cache_directory.Append(kDiskCacheDirectoryName), 371 rv = InitWithDiskBackend(cache_directory.Append(kDiskCacheDirectoryName),
311 kMaxDiskCacheSize, 372 kMaxDiskCacheSize,
312 callback); 373 callback);
313 } 374 }
314 375
315 return rv; 376 return rv;
316 } 377 }
317 378
318 int PNaClTranslationCache::Size() { 379 int PNaClTranslationCache::Size() {
319 if (!disk_cache_) 380 if (!disk_cache_)
320 return -1; 381 return -1;
321 return disk_cache_->GetEntryCount(); 382 return disk_cache_->GetEntryCount();
322 } 383 }
323 384
324 } // namespace nacl_cache 385 } // namespace pnacl_cache
OLDNEW
« no previous file with comments | « chrome/browser/nacl_host/pnacl_translation_cache.h ('k') | chrome/browser/nacl_host/pnacl_translation_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698