Chromium Code Reviews| Index: components/nacl/renderer/ppb_nacl_private_impl.cc |
| diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc |
| index 79cbf9cea22c5519366c090d2d446de799d2d3af..cc21e71461e1a84b7117fc95dc24441e36f27c4f 100644 |
| --- a/components/nacl/renderer/ppb_nacl_private_impl.cc |
| +++ b/components/nacl/renderer/ppb_nacl_private_impl.cc |
| @@ -17,6 +17,8 @@ |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/rand_util.h" |
| +#include "base/strings/string_split.h" |
| +#include "base/strings/string_util.h" |
| #include "components/nacl/common/nacl_host_messages.h" |
| #include "components/nacl/common/nacl_messages.h" |
| #include "components/nacl/common/nacl_nonsfi_util.h" |
| @@ -52,6 +54,7 @@ |
| #include "ppapi/shared_impl/var_tracker.h" |
| #include "ppapi/thunk/enter.h" |
| #include "third_party/WebKit/public/platform/WebURLLoader.h" |
| +#include "third_party/WebKit/public/platform/WebURLResponse.h" |
| #include "third_party/WebKit/public/web/WebDocument.h" |
| #include "third_party/WebKit/public/web/WebElement.h" |
| #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| @@ -587,80 +590,82 @@ PP_Bool PPIsNonSFIModeEnabled() { |
| return PP_FromBool(IsNonSFIModeEnabled()); |
| } |
| -void GetNexeFdContinuation(scoped_refptr<ppapi::TrackedCallback> callback, |
| - PP_Bool* out_is_hit, |
| - PP_FileHandle* out_handle, |
| - int32_t pp_error, |
| - bool is_hit, |
| - PP_FileHandle handle) { |
| - if (pp_error == PP_OK) { |
| - *out_is_hit = PP_FromBool(is_hit); |
| - *out_handle = handle; |
| - } |
| - callback->PostRun(pp_error); |
| +std::string GetCpuFeatureAttrs() { |
|
dmichael (off chromium)
2014/07/17 16:13:21
Maybe it would make sense to combine this with the
teravest
2014/07/21 18:33:21
Done (in a separate change).
|
| + // PNaCl's translator from pexe to nexe can be told exactly what |
| + // capabilities the user's machine has because the pexe to nexe |
| + // translation is specific to the machine, and CPU information goes |
| + // into the translation cache. This allows the translator to generate |
| + // faster code. |
| + // |
| + // Care must be taken to avoid instructions which aren't supported by |
| + // the NaCl sandbox. Ideally the translator would do this, but there's |
| + // no point in not doing the whitelist here. |
| + // |
| + // TODO(jfb) Some features are missing, either because the NaCl |
| + // sandbox doesn't support them, because base::CPU doesn't |
| + // detect them, or because they don't help vector shuffles |
| + // (and we omit them because it simplifies testing). Add the |
| + // other features. |
| + // |
| + // TODO(jfb) The following is x86-specific. The base::CPU class |
| + // doesn't handle other architectures very well, and we |
| + // should at least detect the presence of ARM's integer |
| + // divide. |
| + std::vector<std::string> attrs; |
| + base::CPU cpu; |
| + |
| + // On x86, SSE features are ordered: the most recent one implies the |
| + // others. Care is taken here to only specify the latest SSE version, |
| + // whereas non-SSE features don't follow this model: POPCNT is |
| + // effectively always implied by SSE4.2 but has to be specified |
| + // separately. |
| + // |
| + // TODO: AVX2, AVX, SSE 4.2. |
| + if (cpu.has_sse41()) attrs.push_back("+sse4.1"); |
| + // TODO: SSE 4A, SSE 4. |
| + else if (cpu.has_ssse3()) attrs.push_back("+ssse3"); |
| + // TODO: SSE 3 |
| + else if (cpu.has_sse2()) attrs.push_back("+sse2"); |
| + |
| + // TODO: AES, POPCNT, LZCNT, ... |
| + |
| + return JoinString(attrs, ","); |
| } |
| -int32_t GetNexeFd(PP_Instance instance, |
| - const char* pexe_url, |
| - uint32_t abi_version, |
| - uint32_t opt_level, |
| - const char* http_headers_param, |
| - const char* extra_flags, |
| - PP_Bool* is_hit, |
| - PP_FileHandle* handle, |
| - struct PP_CompletionCallback callback) { |
| - ppapi::thunk::EnterInstance enter(instance, callback); |
| - if (enter.failed()) |
| - return enter.retval(); |
| - if (!pexe_url || !is_hit || !handle) |
| - return enter.SetResult(PP_ERROR_BADARGUMENT); |
| - if (!InitializePnaclResourceHost()) |
| - return enter.SetResult(PP_ERROR_FAILED); |
| - |
| - std::string http_headers(http_headers_param); |
| - net::HttpUtil::HeadersIterator iter( |
| - http_headers.begin(), http_headers.end(), "\r\n"); |
| - |
| - std::string last_modified; |
| - std::string etag; |
| - bool has_no_store_header = false; |
| - while (iter.GetNext()) { |
| - if (StringToLowerASCII(iter.name()) == "last-modified") |
| - last_modified = iter.values(); |
| - if (StringToLowerASCII(iter.name()) == "etag") |
| - etag = iter.values(); |
| - if (StringToLowerASCII(iter.name()) == "cache-control") { |
| - net::HttpUtil::ValuesIterator values_iter( |
| - iter.values_begin(), iter.values_end(), ','); |
| - while (values_iter.GetNext()) { |
| - if (StringToLowerASCII(values_iter.value()) == "no-store") |
| - has_no_store_header = true; |
| - } |
| - } |
| +void GetNexeFd(PP_Instance instance, |
| + const std::string& pexe_url, |
| + uint32_t opt_level, |
| + const base::Time& last_modified_time, |
| + const std::string& etag, |
| + bool has_no_store_header, |
| + base::Callback<void(int32_t, bool, PP_FileHandle)> callback) { |
| + if (!InitializePnaclResourceHost()) { |
| + ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask( |
| + FROM_HERE, |
| + base::Bind(callback, |
| + static_cast<int32_t>(PP_ERROR_FAILED), |
| + false, |
| + PP_kInvalidFileHandle)); |
| + return; |
| } |
| - base::Time last_modified_time; |
| - // If FromString fails, it doesn't touch last_modified_time and we just send |
| - // the default-constructed null value. |
| - base::Time::FromString(last_modified.c_str(), &last_modified_time); |
| - |
| PnaclCacheInfo cache_info; |
| cache_info.pexe_url = GURL(pexe_url); |
| - cache_info.abi_version = abi_version; |
| + // TODO(dschuff): Get this value from the pnacl json file after it |
| + // rolls in from NaCl. |
| + cache_info.abi_version = 1; |
| cache_info.opt_level = opt_level; |
| cache_info.last_modified = last_modified_time; |
| cache_info.etag = etag; |
| cache_info.has_no_store_header = has_no_store_header; |
| cache_info.sandbox_isa = GetSandboxArch(); |
| - cache_info.extra_flags = std::string(extra_flags); |
| + cache_info.extra_flags = GetCpuFeatureAttrs(); |
| g_pnacl_resource_host.Get()->RequestNexeFd( |
| GetRoutingID(instance), |
| instance, |
| cache_info, |
| - base::Bind(&GetNexeFdContinuation, enter.callback(), is_hit, handle)); |
| - |
| - return enter.SetResult(PP_OK_COMPLETIONPENDING); |
| + callback); |
| } |
| void ReportTranslationFinished(PP_Instance instance, |
| @@ -1219,54 +1224,8 @@ PP_Bool GetPNaClResourceInfo(PP_Instance instance, |
| return PP_TRUE; |
| } |
| -// Helper to std::accumulate that creates a comma-separated list from the input. |
| -std::string CommaAccumulator(const std::string &lhs, const std::string &rhs) { |
| - if (lhs.empty()) |
| - return rhs; |
| - return lhs + "," + rhs; |
| -} |
| - |
| -PP_Var GetCpuFeatureAttrs() { |
| - // PNaCl's translator from pexe to nexe can be told exactly what |
| - // capabilities the user's machine has because the pexe to nexe |
| - // translation is specific to the machine, and CPU information goes |
| - // into the translation cache. This allows the translator to generate |
| - // faster code. |
| - // |
| - // Care must be taken to avoid instructions which aren't supported by |
| - // the NaCl sandbox. Ideally the translator would do this, but there's |
| - // no point in not doing the whitelist here. |
| - // |
| - // TODO(jfb) Some features are missing, either because the NaCl |
| - // sandbox doesn't support them, because base::CPU doesn't |
| - // detect them, or because they don't help vector shuffles |
| - // (and we omit them because it simplifies testing). Add the |
| - // other features. |
| - // |
| - // TODO(jfb) The following is x86-specific. The base::CPU class |
| - // doesn't handle other architectures very well, and we |
| - // should at least detect the presence of ARM's integer |
| - // divide. |
| - std::vector<std::string> attrs; |
| - base::CPU cpu; |
| - |
| - // On x86, SSE features are ordered: the most recent one implies the |
| - // others. Care is taken here to only specify the latest SSE version, |
| - // whereas non-SSE features don't follow this model: POPCNT is |
| - // effectively always implied by SSE4.2 but has to be specified |
| - // separately. |
| - // |
| - // TODO: AVX2, AVX, SSE 4.2. |
| - if (cpu.has_sse41()) attrs.push_back("+sse4.1"); |
| - // TODO: SSE 4A, SSE 4. |
| - else if (cpu.has_ssse3()) attrs.push_back("+ssse3"); |
| - // TODO: SSE 3 |
| - else if (cpu.has_sse2()) attrs.push_back("+sse2"); |
| - |
| - // TODO: AES, POPCNT, LZCNT, ... |
| - |
| - return ppapi::StringVar::StringToPPVar(std::accumulate( |
| - attrs.begin(), attrs.end(), std::string(), CommaAccumulator)); |
| +PP_Var ExternalGetCpuFeatureAttrs() { |
| + return ppapi::StringVar::StringToPPVar(GetCpuFeatureAttrs()); |
| } |
| void PostMessageToJavaScriptMainThread(PP_Instance instance, |
| @@ -1609,6 +1568,160 @@ void SetPNaClStartTime(PP_Instance instance) { |
| load_manager->set_pnacl_start_time(base::Time::Now()); |
| } |
| +class PexeDownloader : public blink::WebURLLoaderClient { |
| + public: |
| + PexeDownloader(PP_Instance instance, |
| + scoped_ptr<blink::WebURLLoader> url_loader, |
| + const std::string& pexe_url, |
| + int32_t pexe_opt_level, |
| + const PPP_PexeStreamHandler* stream_handler, |
| + void* stream_handler_user_data) |
| + : instance_(instance), |
| + url_loader_(url_loader.Pass()), |
| + pexe_url_(pexe_url), |
| + pexe_opt_level_(pexe_opt_level), |
| + stream_handler_(stream_handler), |
| + stream_handler_user_data_(stream_handler_user_data), |
| + success_(false), |
| + expected_content_length_(-1), |
| + weak_factory_(this) { } |
| + |
| + void Load(const blink::WebURLRequest& request) { |
| + url_loader_->loadAsynchronously(request, this); |
| + } |
| + |
| + private: |
| + virtual void didReceiveResponse(blink::WebURLLoader* loader, |
| + const blink::WebURLResponse& response) { |
| + success_ = (response.httpStatusCode() == 200); |
| + if (!success_) |
| + return; |
| + |
| + expected_content_length_ = response.expectedContentLength(); |
| + |
| + // Defer loading after receiving headers. This is because we may already |
| + // have a cached translated nexe, so check for that now. |
| + url_loader_->setDefersLoading(true); |
| + |
| + std::string etag = response.httpHeaderField("etag").utf8(); |
| + std::string last_modified = |
| + response.httpHeaderField("last-modified").utf8(); |
| + base::Time last_modified_time; |
| + base::Time::FromString(last_modified.c_str(), &last_modified_time); |
| + |
| + bool has_no_store_header = false; |
| + std::string cache_control = |
| + response.httpHeaderField("cache-control").utf8(); |
| + |
| + std::vector<std::string> values; |
| + base::SplitString(cache_control, ',', &values); |
| + for (std::vector<std::string>::const_iterator it = values.begin(); |
| + it != values.end(); |
| + ++it) { |
| + if (StringToLowerASCII(*it) == "no-store") |
| + has_no_store_header = true; |
| + } |
| + |
| + GetNexeFd(instance_, |
| + pexe_url_, |
| + pexe_opt_level_, |
| + last_modified_time, |
| + etag, |
| + has_no_store_header, |
| + base::Bind(&PexeDownloader::didGetNexeFd, |
| + weak_factory_.GetWeakPtr())); |
| + } |
| + |
| + virtual void didGetNexeFd(int32_t pp_error, |
| + bool cache_hit, |
| + PP_FileHandle file_handle) { |
| + if (cache_hit) { |
| + stream_handler_->DidCacheHit(stream_handler_user_data_, file_handle); |
| + |
| + // We delete the PexeDownloader at this point since we successfully got a |
| + // cached, translated nexe. |
| + delete this; |
| + return; |
| + } |
| + stream_handler_->DidCacheMiss(stream_handler_user_data_, |
| + expected_content_length_); |
| + |
| + // No translated nexe was found in the cache, so we should download the |
| + // file to start streaming it. |
| + url_loader_->setDefersLoading(false); |
| + } |
| + |
| + virtual void didReceiveData(blink::WebURLLoader* loader, |
| + const char* data, |
| + int data_length, |
| + int encoded_data_length) { |
| + // Stream the data we received to the stream callback. |
| + stream_handler_->DidStreamData(stream_handler_user_data_, |
| + data, |
| + data_length); |
| + } |
| + |
| + virtual void didFinishLoading(blink::WebURLLoader* loader, |
| + double finish_time, |
| + int64_t total_encoded_data_length) { |
| + int32_t result = success_ ? PP_OK : PP_ERROR_FAILED; |
| + stream_handler_->DidFinishStream(stream_handler_user_data_, result); |
| + delete this; |
| + } |
| + |
| + virtual void didFail(blink::WebURLLoader* loader, |
| + const blink::WebURLError& error) { |
| + success_ = false; |
| + } |
| + |
| + PP_Instance instance_; |
| + scoped_ptr<blink::WebURLLoader> url_loader_; |
| + std::string pexe_url_; |
| + int32_t pexe_opt_level_; |
| + const PPP_PexeStreamHandler* stream_handler_; |
| + void* stream_handler_user_data_; |
| + bool success_; |
| + int64_t expected_content_length_; |
| + base::WeakPtrFactory<PexeDownloader> weak_factory_; |
| +}; |
| + |
| +void StreamPexe(PP_Instance instance, |
| + const char* pexe_url, |
| + int32_t opt_level, |
| + const PPP_PexeStreamHandler* handler, |
| + void* handler_user_data) { |
| + content::PepperPluginInstance* plugin_instance = |
| + content::PepperPluginInstance::Get(instance); |
| + if (!plugin_instance) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(handler->DidFinishStream, |
| + handler_user_data, |
| + static_cast<int32_t>(PP_ERROR_FAILED))); |
| + return; |
| + } |
| + |
| + GURL gurl(pexe_url); |
| + const blink::WebDocument& document = |
| + plugin_instance->GetContainer()->element().document(); |
| + scoped_ptr<blink::WebURLLoader> url_loader( |
| + CreateWebURLLoader(document, gurl)); |
| + PexeDownloader* downloader = new PexeDownloader(instance, |
| + url_loader.Pass(), |
| + pexe_url, |
| + opt_level, |
| + handler, |
| + handler_user_data); |
| + |
| + blink::WebURLRequest url_request = CreateWebURLRequest(document, gurl); |
| + // Mark the request as requesting a PNaCl bitcode file, |
| + // so that component updater can detect this user action. |
| + url_request.addHTTPHeaderField( |
| + blink::WebString::fromUTF8("Accept"), |
| + blink::WebString::fromUTF8("application/x-pnacl, */*")); |
| + downloader->Load(url_request); |
| +} |
| + |
| const PPB_NaCl_Private nacl_interface = { |
| &LaunchSelLdr, |
| &StartPpapiProxy, |
| @@ -1619,7 +1732,6 @@ const PPB_NaCl_Private nacl_interface = { |
| &CreateTemporaryFile, |
| &GetNumberOfProcessors, |
| &PPIsNonSFIModeEnabled, |
| - &GetNexeFd, |
| &ReportTranslationFinished, |
| &DispatchEvent, |
| &ReportLoadSuccess, |
| @@ -1643,13 +1755,14 @@ const PPB_NaCl_Private nacl_interface = { |
| &DevInterfacesEnabled, |
| &ManifestGetProgramURL, |
| &GetPNaClResourceInfo, |
| - &GetCpuFeatureAttrs, |
| + &ExternalGetCpuFeatureAttrs, |
| &PostMessageToJavaScript, |
| &DownloadNexe, |
| &ReportSelLdrStatus, |
| &LogTranslateTime, |
| &OpenManifestEntry, |
| - &SetPNaClStartTime |
| + &SetPNaClStartTime, |
| + &StreamPexe |
| }; |
| } // namespace |