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 |