• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium 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 #include "ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h"
6 
7 #include <utility>
8 #include <vector>
9 
10 #include "native_client/src/include/checked_cast.h"
11 #include "native_client/src/include/portability_io.h"
12 #include "native_client/src/shared/platform/nacl_check.h"
13 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
14 
15 #include "ppapi/c/pp_bool.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/c/private/ppb_uma_private.h"
18 
19 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
20 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
21 #include "ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h"
22 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
23 #include "ppapi/native_client/src/trusted/plugin/temporary_file.h"
24 
25 namespace plugin {
26 
27 namespace {
28 
29 const int32_t kSizeKBMin = 1;
30 const int32_t kSizeKBMax = 512*1024;       // very large .pexe / .nexe.
31 const uint32_t kSizeKBBuckets = 100;
32 
33 const int32_t kRatioMin = 10;
34 const int32_t kRatioMax = 10*100;          // max of 10x difference.
35 const uint32_t kRatioBuckets = 100;
36 
HistogramSizeKB(pp::UMAPrivate & uma,const nacl::string & name,int32_t kb)37 void HistogramSizeKB(pp::UMAPrivate& uma,
38                      const nacl::string& name, int32_t kb) {
39   if (kb < 0) return;
40   uma.HistogramCustomCounts(name,
41                             kb,
42                             kSizeKBMin, kSizeKBMax,
43                             kSizeKBBuckets);
44 }
45 
HistogramRatio(pp::UMAPrivate & uma,const nacl::string & name,int64_t a,int64_t b)46 void HistogramRatio(pp::UMAPrivate& uma,
47                     const nacl::string& name, int64_t a, int64_t b) {
48   if (a < 0 || b <= 0) return;
49   uma.HistogramCustomCounts(name,
50                             100 * a / b,
51                             kRatioMin, kRatioMax,
52                             kRatioBuckets);
53 }
54 
HistogramEnumerateTranslationCache(pp::UMAPrivate & uma,bool hit)55 void HistogramEnumerateTranslationCache(pp::UMAPrivate& uma, bool hit) {
56   uma.HistogramEnumeration("NaCl.Perf.PNaClCache.IsHit",
57                            hit, 2);
58 }
59 
GetArchitectureAttributes(Plugin * plugin)60 nacl::string GetArchitectureAttributes(Plugin* plugin) {
61   pp::Var attrs_var(pp::PASS_REF,
62                     plugin->nacl_interface()->GetCpuFeatureAttrs());
63   return attrs_var.AsString();
64 }
65 
66 }  // namespace
67 
68 // Out-of-line destructor to keep it from getting put in every .o where
69 // callback_source.h is included
70 template<>
~CallbackSource()71 CallbackSource<FileStreamData>::~CallbackSource() {}
72 
BitcodeToNative(Plugin * plugin,const nacl::string & pexe_url,const PP_PNaClOptions & pnacl_options,const pp::CompletionCallback & translate_notify_callback)73 PnaclCoordinator* PnaclCoordinator::BitcodeToNative(
74     Plugin* plugin,
75     const nacl::string& pexe_url,
76     const PP_PNaClOptions& pnacl_options,
77     const pp::CompletionCallback& translate_notify_callback) {
78   PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (plugin=%p, pexe=%s)\n",
79                  static_cast<void*>(plugin), pexe_url.c_str()));
80   PnaclCoordinator* coordinator =
81       new PnaclCoordinator(plugin, pexe_url,
82                            pnacl_options,
83                            translate_notify_callback);
84 
85   coordinator->pnacl_init_time_ = NaClGetTimeOfDayMicroseconds();
86   int cpus = plugin->nacl_interface()->GetNumberOfProcessors();
87   coordinator->split_module_count_ = std::min(4, std::max(1, cpus));
88 
89   // First start a network request for the pexe, to tickle the component
90   // updater's On-Demand resource throttler, and to get Last-Modified/ETag
91   // cache information. We can cancel the request later if there's
92   // a bitcode->nexe cache hit.
93   coordinator->OpenBitcodeStream();
94   return coordinator;
95 }
96 
PnaclCoordinator(Plugin * plugin,const nacl::string & pexe_url,const PP_PNaClOptions & pnacl_options,const pp::CompletionCallback & translate_notify_callback)97 PnaclCoordinator::PnaclCoordinator(
98     Plugin* plugin,
99     const nacl::string& pexe_url,
100     const PP_PNaClOptions& pnacl_options,
101     const pp::CompletionCallback& translate_notify_callback)
102   : translate_finish_error_(PP_OK),
103     plugin_(plugin),
104     translate_notify_callback_(translate_notify_callback),
105     translation_finished_reported_(false),
106     pexe_url_(pexe_url),
107     pnacl_options_(pnacl_options),
108     architecture_attributes_(GetArchitectureAttributes(plugin)),
109     split_module_count_(1),
110     is_cache_hit_(PP_FALSE),
111     error_already_reported_(false),
112     pnacl_init_time_(0),
113     pexe_size_(0),
114     pexe_bytes_compiled_(0),
115     expected_pexe_size_(-1) {
116   PLUGIN_PRINTF(("PnaclCoordinator::PnaclCoordinator (this=%p, plugin=%p)\n",
117                  static_cast<void*>(this), static_cast<void*>(plugin)));
118   callback_factory_.Initialize(this);
119 }
120 
~PnaclCoordinator()121 PnaclCoordinator::~PnaclCoordinator() {
122   PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p, "
123                  "translate_thread=%p\n",
124                  static_cast<void*>(this), translate_thread_.get()));
125   // Stopping the translate thread will cause the translate thread to try to
126   // run translation_complete_callback_ on the main thread.  This destructor is
127   // running from the main thread, and by the time it exits, callback_factory_
128   // will have been destroyed.  This will result in the cancellation of
129   // translation_complete_callback_, so no notification will be delivered.
130   if (translate_thread_.get() != NULL)
131     translate_thread_->AbortSubprocesses();
132   if (!translation_finished_reported_) {
133     plugin_->nacl_interface()->ReportTranslationFinished(
134         plugin_->pp_instance(),
135         PP_FALSE, 0, 0, 0, 0);
136   }
137   // Force deleting the translate_thread now. It must be deleted
138   // before any scoped_* fields hanging off of PnaclCoordinator
139   // since the thread may be accessing those fields.
140   // It will also be accessing obj_files_.
141   translate_thread_.reset(NULL);
142   for (size_t i = 0; i < obj_files_.size(); i++)
143     delete obj_files_[i];
144 }
145 
TakeTranslatedFileHandle()146 PP_FileHandle PnaclCoordinator::TakeTranslatedFileHandle() {
147   DCHECK(temp_nexe_file_ != NULL);
148   return temp_nexe_file_->TakeFileHandle();
149 }
150 
ReportNonPpapiError(PP_NaClError err_code,const nacl::string & message)151 void PnaclCoordinator::ReportNonPpapiError(PP_NaClError err_code,
152                                            const nacl::string& message) {
153   ErrorInfo error_info;
154   error_info.SetReport(err_code, message);
155   plugin_->ReportLoadError(error_info);
156   ExitWithError();
157 }
158 
ReportPpapiError(PP_NaClError err_code,int32_t pp_error,const nacl::string & message)159 void PnaclCoordinator::ReportPpapiError(PP_NaClError err_code,
160                                         int32_t pp_error,
161                                         const nacl::string& message) {
162   nacl::stringstream ss;
163   ss << "PnaclCoordinator: " << message << " (pp_error=" << pp_error << ").";
164   ErrorInfo error_info;
165   error_info.SetReport(err_code, ss.str());
166   plugin_->ReportLoadError(error_info);
167   ExitWithError();
168 }
169 
ExitWithError()170 void PnaclCoordinator::ExitWithError() {
171   PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError\n"));
172   // Free all the intermediate callbacks we ever created.
173   // Note: this doesn't *cancel* the callbacks from the factories attached
174   // to the various helper classes (e.g., pnacl_resources). Thus, those
175   // callbacks may still run asynchronously.  We let those run but ignore
176   // any other errors they may generate so that they do not end up running
177   // translate_notify_callback_, which has already been freed.
178   callback_factory_.CancelAll();
179   if (!error_already_reported_) {
180     error_already_reported_ = true;
181     translation_finished_reported_ = true;
182     plugin_->nacl_interface()->ReportTranslationFinished(
183         plugin_->pp_instance(),
184         PP_FALSE, 0, 0, 0, 0);
185     translate_notify_callback_.Run(PP_ERROR_FAILED);
186   } else {
187     PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError an earlier error was "
188                    "already reported -- Skipping.\n"));
189   }
190 }
191 
192 // Signal that Pnacl translation completed normally.
TranslateFinished(int32_t pp_error)193 void PnaclCoordinator::TranslateFinished(int32_t pp_error) {
194   PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%"
195                  NACL_PRId32 ")\n", pp_error));
196   // Bail out if there was an earlier error (e.g., pexe load failure),
197   // or if there is an error from the translation thread.
198   if (translate_finish_error_ != PP_OK || pp_error != PP_OK) {
199     plugin_->ReportLoadError(error_info_);
200     ExitWithError();
201     return;
202   }
203 
204   // Send out one last progress event, to finish up the progress events
205   // that were delayed (see the delay inserted in BitcodeGotCompiled).
206   if (expected_pexe_size_ != -1) {
207     pexe_bytes_compiled_ = expected_pexe_size_;
208     GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
209                                       PP_NACL_EVENT_PROGRESS,
210                                       pexe_url_.c_str(),
211                                       PP_TRUE,
212                                       pexe_bytes_compiled_,
213                                       expected_pexe_size_);
214   }
215   struct nacl_abi_stat stbuf;
216   struct NaClDesc* desc = temp_nexe_file_->read_wrapper()->desc();
217   int stat_ret;
218   if (0 != (stat_ret = (*((struct NaClDescVtbl const *) desc->base.vtbl)->
219                         Fstat)(desc, &stbuf))) {
220     PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished can't stat nexe.\n"));
221   } else {
222     size_t nexe_size = stbuf.nacl_abi_st_size;
223     HistogramSizeKB(plugin_->uma_interface(),
224                     "NaCl.Perf.Size.PNaClTranslatedNexe",
225                     static_cast<int64_t>(nexe_size / 1024));
226     HistogramRatio(plugin_->uma_interface(),
227                    "NaCl.Perf.Size.PexeNexeSizePct", pexe_size_, nexe_size);
228   }
229   // The nexe is written to the temp_nexe_file_.  We must Reset() the file
230   // pointer to be able to read it again from the beginning.
231   temp_nexe_file_->Reset();
232 
233   int64_t total_time = NaClGetTimeOfDayMicroseconds() - pnacl_init_time_;
234   // Report to the browser that translation finished. The browser will take
235   // care of storing the nexe in the cache.
236   translation_finished_reported_ = true;
237   plugin_->nacl_interface()->ReportTranslationFinished(
238       plugin_->pp_instance(), PP_TRUE, pnacl_options_.opt_level,
239       pexe_size_, translate_thread_->GetCompileTime(), total_time);
240 
241   NexeReadDidOpen(PP_OK);
242 }
243 
NexeReadDidOpen(int32_t pp_error)244 void PnaclCoordinator::NexeReadDidOpen(int32_t pp_error) {
245   PLUGIN_PRINTF(("PnaclCoordinator::NexeReadDidOpen (pp_error=%"
246                  NACL_PRId32 ")\n", pp_error));
247   if (pp_error != PP_OK) {
248     if (pp_error == PP_ERROR_FILENOTFOUND) {
249       ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_NOTFOUND,
250                        pp_error,
251                        "Failed to open translated nexe (not found).");
252       return;
253     }
254     if (pp_error == PP_ERROR_NOACCESS) {
255       ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_NOACCESS,
256                        pp_error,
257                        "Failed to open translated nexe (no access).");
258       return;
259     }
260     ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_OTHER,
261                      pp_error,
262                      "Failed to open translated nexe.");
263     return;
264   }
265 
266   translate_notify_callback_.Run(pp_error);
267 }
268 
OpenBitcodeStream()269 void PnaclCoordinator::OpenBitcodeStream() {
270   // Now open the pexe stream.
271   streaming_downloader_.reset(new FileDownloader(plugin_));
272   // Mark the request as requesting a PNaCl bitcode file,
273   // so that component updater can detect this user action.
274   streaming_downloader_->set_request_headers(
275       "Accept: application/x-pnacl, */*");
276 
277   // Even though we haven't started downloading, create the translation
278   // thread object immediately. This ensures that any pieces of the file
279   // that get downloaded before the compilation thread is accepting
280   // SRPCs won't get dropped.
281   translate_thread_.reset(new PnaclTranslateThread());
282   if (translate_thread_ == NULL) {
283     ReportNonPpapiError(
284         PP_NACL_ERROR_PNACL_THREAD_CREATE,
285         "PnaclCoordinator: could not allocate translation thread.");
286     return;
287   }
288 
289   pp::CompletionCallback cb =
290       callback_factory_.NewCallback(&PnaclCoordinator::BitcodeStreamDidOpen);
291   if (!streaming_downloader_->OpenStream(pexe_url_, cb, this)) {
292     ReportNonPpapiError(
293         PP_NACL_ERROR_PNACL_PEXE_FETCH_OTHER,
294         nacl::string("PnaclCoordinator: failed to open stream ") + pexe_url_);
295     return;
296   }
297 }
298 
BitcodeStreamDidOpen(int32_t pp_error)299 void PnaclCoordinator::BitcodeStreamDidOpen(int32_t pp_error) {
300   if (pp_error != PP_OK) {
301     BitcodeStreamDidFinish(pp_error);
302     // We have not spun up the translation process yet, so we need to call
303     // TranslateFinished here.
304     TranslateFinished(pp_error);
305     return;
306   }
307 
308   // The component updater's resource throttles + OnDemand update/install
309   // should block the URL request until the compiler is present. Now we
310   // can load the resources (e.g. llc and ld nexes).
311   resources_.reset(new PnaclResources(plugin_));
312   CHECK(resources_ != NULL);
313 
314   // The first step of loading resources: read the resource info file.
315   pp::CompletionCallback resource_info_read_cb =
316       callback_factory_.NewCallback(&PnaclCoordinator::ResourceInfoWasRead);
317   resources_->ReadResourceInfo(resource_info_read_cb);
318 }
319 
ResourceInfoWasRead(int32_t pp_error)320 void PnaclCoordinator::ResourceInfoWasRead(int32_t pp_error) {
321   PLUGIN_PRINTF(("PluginCoordinator::ResourceInfoWasRead (pp_error=%"
322                 NACL_PRId32 ")\n", pp_error));
323   if (pp_error != PP_OK) {
324     ExitWithError();
325     return;
326   }
327   // Second step of loading resources: call StartLoad to load pnacl-llc
328   // and pnacl-ld, based on the filenames found in the resource info file.
329   pp::CompletionCallback resources_cb =
330       callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad);
331   resources_->StartLoad(resources_cb);
332 }
333 
ResourcesDidLoad(int32_t pp_error)334 void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) {
335   PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%"
336                  NACL_PRId32 ")\n", pp_error));
337   if (pp_error != PP_OK) {
338     ReportNonPpapiError(
339         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
340         nacl::string("The Portable Native Client (pnacl) component is not "
341                      "installed. Please consult chrome://components for more "
342                       "information."));
343     return;
344   }
345 
346   // Okay, now that we've started the HTTP request for the pexe
347   // and we've ensured that the PNaCl compiler + metadata is installed,
348   // get the cache key from the response headers and from the
349   // compiler's version metadata.
350   nacl::string headers = streaming_downloader_->GetResponseHeaders();
351 
352   temp_nexe_file_.reset(new TempFile(plugin_));
353   pp::CompletionCallback cb =
354       callback_factory_.NewCallback(&PnaclCoordinator::NexeFdDidOpen);
355   int32_t nexe_fd_err =
356       plugin_->nacl_interface()->GetNexeFd(
357           plugin_->pp_instance(),
358           streaming_downloader_->full_url().c_str(),
359           // TODO(dschuff): Get this value from the pnacl json file after it
360           // rolls in from NaCl.
361           1,
362           pnacl_options_.opt_level,
363           headers.c_str(),
364           architecture_attributes_.c_str(), // Extra compile flags.
365           &is_cache_hit_,
366           temp_nexe_file_->internal_handle(),
367           cb.pp_completion_callback());
368   if (nexe_fd_err < PP_OK_COMPLETIONPENDING) {
369     ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP, nexe_fd_err,
370                      nacl::string("Call to GetNexeFd failed"));
371   }
372 }
373 
NexeFdDidOpen(int32_t pp_error)374 void PnaclCoordinator::NexeFdDidOpen(int32_t pp_error) {
375   PLUGIN_PRINTF(("PnaclCoordinator::NexeFdDidOpen (pp_error=%"
376                  NACL_PRId32 ", hit=%d)\n", pp_error,
377                  is_cache_hit_ == PP_TRUE));
378   if (pp_error < PP_OK) {
379     ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP, pp_error,
380                      nacl::string("GetNexeFd failed"));
381     return;
382   }
383 
384   if (*temp_nexe_file_->internal_handle() == PP_kInvalidFileHandle) {
385     ReportNonPpapiError(
386         PP_NACL_ERROR_PNACL_CREATE_TEMP,
387         nacl::string(
388             "PnaclCoordinator: Got bad temp file handle from GetNexeFd"));
389     return;
390   }
391   HistogramEnumerateTranslationCache(plugin_->uma_interface(), is_cache_hit_);
392 
393   if (is_cache_hit_ == PP_TRUE) {
394     // Cache hit -- no need to stream the rest of the file.
395     streaming_downloader_.reset(NULL);
396     // Open it for reading as the cached nexe file.
397     NexeReadDidOpen(temp_nexe_file_->Open(false));
398   } else {
399     // Open an object file first so the translator can start writing to it
400     // during streaming translation.
401     for (int i = 0; i < split_module_count_; i++) {
402       nacl::scoped_ptr<TempFile> temp_file(new TempFile(plugin_));
403       int32_t pp_error = temp_file->Open(true);
404       if (pp_error != PP_OK) {
405         ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP,
406                          pp_error,
407                          "Failed to open scratch object file.");
408         return;
409       } else {
410         obj_files_.push_back(temp_file.release());
411       }
412     }
413     invalid_desc_wrapper_.reset(plugin_->wrapper_factory()->MakeInvalid());
414 
415     // Meanwhile, a miss means we know we need to stream the bitcode, so stream
416     // the rest of it now. (Calling BeginStreaming means that the downloader
417     // will begin handing data to the coordinator, which is safe any time after
418     // the translate_thread_ object has been initialized).
419     pp::CompletionCallback finish_cb = callback_factory_.NewCallback(
420         &PnaclCoordinator::BitcodeStreamDidFinish);
421     streaming_downloader_->BeginStreaming(finish_cb);
422 
423     // Open the nexe file for connecting ld and sel_ldr.
424     // Start translation when done with this last step of setup!
425     RunTranslate(temp_nexe_file_->Open(true));
426   }
427 }
428 
BitcodeStreamDidFinish(int32_t pp_error)429 void PnaclCoordinator::BitcodeStreamDidFinish(int32_t pp_error) {
430   PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamDidFinish (pp_error=%"
431                  NACL_PRId32 ")\n", pp_error));
432   if (pp_error != PP_OK) {
433     // Defer reporting the error and cleanup until after the translation
434     // thread returns, because it may be accessing the coordinator's
435     // objects or writing to the files.
436     translate_finish_error_ = pp_error;
437     if (pp_error == PP_ERROR_ABORTED) {
438       error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_ABORTED,
439                             "PnaclCoordinator: pexe load failed (aborted).");
440     }
441     if (pp_error == PP_ERROR_NOACCESS) {
442       error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_NOACCESS,
443                             "PnaclCoordinator: pexe load failed (no access).");
444     } else {
445       nacl::stringstream ss;
446       ss << "PnaclCoordinator: pexe load failed (pp_error=" << pp_error << ").";
447       error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_OTHER, ss.str());
448     }
449     translate_thread_->AbortSubprocesses();
450   } else {
451     // Compare download completion pct (100% now), to compile completion pct.
452     HistogramRatio(plugin_->uma_interface(),
453                    "NaCl.Perf.PNaClLoadTime.PctCompiledWhenFullyDownloaded",
454                    pexe_bytes_compiled_, pexe_size_);
455   }
456 }
457 
BitcodeStreamGotData(int32_t pp_error,FileStreamData data)458 void PnaclCoordinator::BitcodeStreamGotData(int32_t pp_error,
459                                             FileStreamData data) {
460   PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamGotData (pp_error=%"
461                  NACL_PRId32 ", data=%p)\n", pp_error, data ? &(*data)[0] : 0));
462   DCHECK(translate_thread_.get());
463 
464   translate_thread_->PutBytes(data, pp_error);
465   // If pp_error > 0, then it represents the number of bytes received.
466   if (data && pp_error > 0)
467     pexe_size_ += pp_error;
468 }
469 
GetCallback()470 StreamCallback PnaclCoordinator::GetCallback() {
471   return callback_factory_.NewCallbackWithOutput(
472       &PnaclCoordinator::BitcodeStreamGotData);
473 }
474 
BitcodeGotCompiled(int32_t pp_error,int64_t bytes_compiled)475 void PnaclCoordinator::BitcodeGotCompiled(int32_t pp_error,
476                                           int64_t bytes_compiled) {
477   DCHECK(pp_error == PP_OK);
478   pexe_bytes_compiled_ += bytes_compiled;
479   // If we don't know the expected total yet, ask.
480   if (expected_pexe_size_ == -1) {
481     int64_t amount_downloaded;  // dummy variable.
482     streaming_downloader_->GetDownloadProgress(&amount_downloaded,
483                                                &expected_pexe_size_);
484   }
485   // Hold off reporting the last few bytes of progress, since we don't know
486   // when they are actually completely compiled.  "bytes_compiled" only means
487   // that bytes were sent to the compiler.
488   if (expected_pexe_size_ != -1) {
489     if (!ShouldDelayProgressEvent()) {
490       GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
491                                         PP_NACL_EVENT_PROGRESS,
492                                         pexe_url_.c_str(),
493                                         PP_TRUE,
494                                         pexe_bytes_compiled_,
495                                         expected_pexe_size_);
496     }
497   } else {
498     GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
499                                       PP_NACL_EVENT_PROGRESS,
500                                       pexe_url_.c_str(),
501                                       PP_FALSE,
502                                       pexe_bytes_compiled_,
503                                       expected_pexe_size_);
504   }
505 }
506 
GetCompileProgressCallback(int64_t bytes_compiled)507 pp::CompletionCallback PnaclCoordinator::GetCompileProgressCallback(
508     int64_t bytes_compiled) {
509   return callback_factory_.NewCallback(&PnaclCoordinator::BitcodeGotCompiled,
510                                        bytes_compiled);
511 }
512 
GetCurrentProgress(int64_t * bytes_loaded,int64_t * bytes_total)513 void PnaclCoordinator::GetCurrentProgress(int64_t* bytes_loaded,
514                                           int64_t* bytes_total) {
515   *bytes_loaded = pexe_bytes_compiled_;
516   *bytes_total = expected_pexe_size_;
517 }
518 
RunTranslate(int32_t pp_error)519 void PnaclCoordinator::RunTranslate(int32_t pp_error) {
520   PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%"
521                  NACL_PRId32 ")\n", pp_error));
522   // Invoke llc followed by ld off the main thread.  This allows use of
523   // blocking RPCs that would otherwise block the JavaScript main thread.
524   pp::CompletionCallback report_translate_finished =
525       callback_factory_.NewCallback(&PnaclCoordinator::TranslateFinished);
526 
527   CHECK(translate_thread_ != NULL);
528   translate_thread_->RunTranslate(report_translate_finished,
529                                   &obj_files_,
530                                   temp_nexe_file_.get(),
531                                   invalid_desc_wrapper_.get(),
532                                   &error_info_,
533                                   resources_.get(),
534                                   &pnacl_options_,
535                                   architecture_attributes_,
536                                   this,
537                                   plugin_);
538 }
539 
540 }  // namespace plugin
541