Import Cobalt 4.12959
diff --git a/src/base/circular_buffer_shell.cc b/src/base/circular_buffer_shell.cc index ae58e4b..ce64f42 100644 --- a/src/base/circular_buffer_shell.cc +++ b/src/base/circular_buffer_shell.cc
@@ -15,7 +15,7 @@ #include "starboard/memory.h" #define malloc SbMemoryAllocate #define realloc SbMemoryReallocate -#define free SbMemoryFree +#define free SbMemoryDeallocate #endif static inline void* add_to_pointer(void* pointer, size_t amount) {
diff --git a/src/base/logging.cc b/src/base/logging.cc index 6a135ea..d3a97e5 100644 --- a/src/base/logging.cc +++ b/src/base/logging.cc
@@ -406,6 +406,25 @@ return true; } +#if defined(OS_STARBOARD) +SbLogPriority LogLevelToStarboardLogPriority(int level) { + switch (level) { + case LOG_INFO: + return kSbLogPriorityInfo; + case LOG_WARNING: + return kSbLogPriorityWarning; + case LOG_ERROR: + case LOG_ERROR_REPORT: + return kSbLogPriorityError; + case LOG_FATAL: + return kSbLogPriorityFatal; + default: + NOTREACHED() << "Unrecognized log level."; + return kSbLogPriorityInfo; + } +} +#endif // defined(OS_STARBOARD) + } // namespace @@ -467,6 +486,11 @@ void SetMinLogLevel(int level) { min_log_level = std::min(LOG_ERROR_REPORT, level); + +#if defined(OS_STARBOARD) + starboard::logging::SetMinLogLevel( + LogLevelToStarboardLogPriority(std::min(LOG_FATAL, level))); +#endif } int GetMinLogLevel() { @@ -650,23 +674,7 @@ if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG || logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) { #if defined(OS_STARBOARD) - SbLogPriority priority = kSbLogPriorityUnknown; - switch (severity_) { - case LOG_INFO: - priority = kSbLogPriorityInfo; - break; - case LOG_WARNING: - priority = kSbLogPriorityWarning; - break; - case LOG_ERROR: - case LOG_ERROR_REPORT: - priority = kSbLogPriorityError; - break; - case LOG_FATAL: - priority = kSbLogPriorityFatal; - break; - } - SbLog(priority, str_newline.c_str()); + SbLog(LogLevelToStarboardLogPriority(severity_), str_newline.c_str()); #elif defined(OS_WIN) || defined(COBALT_WIN) OutputDebugStringA(str_newline.c_str()); #elif defined(OS_ANDROID) || defined(__LB_ANDROID__)
diff --git a/src/base/memory/aligned_memory.h b/src/base/memory/aligned_memory.h index 040b56d..8ea96b7 100644 --- a/src/base/memory/aligned_memory.h +++ b/src/base/memory/aligned_memory.h
@@ -99,7 +99,7 @@ #if defined(COMPILER_MSVC) _aligned_free(ptr); #elif defined(OS_STARBOARD) - SbMemoryFreeAligned(ptr); + SbMemoryDeallocateAligned(ptr); #else free(ptr); #endif
diff --git a/src/base/memory/scoped_ptr.h b/src/base/memory/scoped_ptr.h index 9ee780e..7f2d7dc 100644 --- a/src/base/memory/scoped_ptr.h +++ b/src/base/memory/scoped_ptr.h
@@ -395,7 +395,7 @@ public: inline void operator()(void* x) const { #if defined(OS_STARBOARD) - SbMemoryFree(x); + SbMemoryDeallocate(x); #else free(x); #endif
diff --git a/src/base/pickle.cc b/src/base/pickle.cc index 43121c9..e5050b9 100644 --- a/src/base/pickle.cc +++ b/src/base/pickle.cc
@@ -10,7 +10,7 @@ #if defined(OS_STARBOARD) #include "starboard/memory.h" #define realloc SbMemoryReallocate -#define free SbMemoryFree +#define free SbMemoryDeallocate #define memcpy SbMemoryCopy #else #include <stdlib.h>
diff --git a/src/base/shared_memory.h b/src/base/shared_memory.h index bf77788..8589779 100644 --- a/src/base/shared_memory.h +++ b/src/base/shared_memory.h
@@ -67,7 +67,7 @@ } ~RefCountedMem() { #if defined(OS_STARBOARD) - SbMemoryFree(memory_); + SbMemoryDeallocate(memory_); #else free(memory_); #endif
diff --git a/src/base/third_party/dmg_fp/dtoa.cc b/src/base/third_party/dmg_fp/dtoa.cc index 1339d3f..3c5d5a5 100644 --- a/src/base/third_party/dmg_fp/dtoa.cc +++ b/src/base/third_party/dmg_fp/dtoa.cc
@@ -205,7 +205,7 @@ #if defined(STARBOARD) #include "starboard/memory.h" #define MALLOC SbMemoryAllocate -#define FREE SbMemoryFree +#define FREE SbMemoryDeallocate #else #include "stdlib.h" #include "string.h"
diff --git a/src/base/tools_sanity_unittest.cc b/src/base/tools_sanity_unittest.cc index a901f59..074a13e 100644 --- a/src/base/tools_sanity_unittest.cc +++ b/src/base/tools_sanity_unittest.cc
@@ -15,7 +15,7 @@ #if defined(OS_STARBOARD) #include "starboard/memory.h" -#define free SbMemoryFree +#define free SbMemoryDeallocate #define malloc SbMemoryAllocate #endif
diff --git a/src/cobalt/base/console_commands.cc b/src/cobalt/base/console_commands.cc index eecf31a..73e4f1b 100644 --- a/src/cobalt/base/console_commands.cc +++ b/src/cobalt/base/console_commands.cc
@@ -50,10 +50,15 @@ const std::string& message) const { DCHECK_GT(channel.length(), size_t(0)); base::AutoLock auto_lock(lock_); - CommandHandlerMap::const_iterator iter = command_channel_map_.find(channel); - if (iter != command_channel_map_.end()) { + CommandHandlerMap::const_iterator iter = + command_channel_map_.lower_bound(channel); + bool handler_found = false; + while (iter != command_channel_map_.end() && iter->first == channel) { + handler_found = true; iter->second->callback().Run(message); - } else { + ++iter; + } + if (!handler_found) { DLOG(WARNING) << "No command handler registered for channel: " << channel; } } @@ -71,8 +76,9 @@ std::string ConsoleCommandManager::GetShortHelp( const std::string& channel) const { base::AutoLock auto_lock(lock_); - CommandHandlerMap::const_iterator iter = command_channel_map_.find(channel); - if (iter != command_channel_map_.end()) { + for (CommandHandlerMap::const_iterator iter = + command_channel_map_.lower_bound(channel); + iter != command_channel_map_.end() && iter->first == channel; ++iter) { return iter->second->short_help(); } return "No help available for unregistered channel: " + channel; @@ -81,8 +87,9 @@ std::string ConsoleCommandManager::GetLongHelp( const std::string& channel) const { base::AutoLock auto_lock(lock_); - CommandHandlerMap::const_iterator iter = command_channel_map_.find(channel); - if (iter != command_channel_map_.end()) { + for (CommandHandlerMap::const_iterator iter = + command_channel_map_.lower_bound(channel); + iter != command_channel_map_.end() && iter->first == channel; ++iter) { return iter->second->long_help(); } return "No help available for unregistered channel: " + channel; @@ -92,14 +99,22 @@ const CommandHandler* handler) { DCHECK_GT(handler->channel().length(), size_t(0)); base::AutoLock auto_lock(lock_); - command_channel_map_[handler->channel()] = handler; + command_channel_map_.insert(std::make_pair(handler->channel(), handler)); } void ConsoleCommandManager::UnregisterCommandHandler( const CommandHandler* handler) { - DCHECK_GT(handler->channel().length(), size_t(0)); + const std::string& channel = handler->channel(); + DCHECK_GT(channel.length(), size_t(0)); base::AutoLock auto_lock(lock_); - command_channel_map_.erase(handler->channel()); + for (CommandHandlerMap::iterator iter = + command_channel_map_.lower_bound(channel); + iter != command_channel_map_.end() && iter->first == channel; ++iter) { + if (iter->second == handler) { + command_channel_map_.erase(iter); + break; + } + } } #else // ENABLE_DEBUG_CONSOLE
diff --git a/src/cobalt/base/console_commands.h b/src/cobalt/base/console_commands.h index 47144d6..f12113e 100644 --- a/src/cobalt/base/console_commands.h +++ b/src/cobalt/base/console_commands.h
@@ -89,7 +89,7 @@ #if defined(ENABLE_DEBUG_CONSOLE) // Command handler map type. - typedef std::map<std::string, const CommandHandler*> CommandHandlerMap; + typedef std::multimap<std::string, const CommandHandler*> CommandHandlerMap; // Methods to register/unregister command handlers. // These are intended only to be called from the command handler objects.
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc index fe26699..438692d 100644 --- a/src/cobalt/browser/application.cc +++ b/src/cobalt/browser/application.cc
@@ -50,6 +50,10 @@ #endif // defined(__LB_SHELL__FOR_RELEASE__) #include "lbshell/src/lb_memory_pages.h" #endif // defined(__LB_SHELL__) +#if defined(OS_STARBOARD) +#include "starboard/configuration.h" +#include "starboard/log.h" +#endif // defined(OS_STARBOARD) namespace cobalt { namespace browser { @@ -61,7 +65,12 @@ #if defined(ENABLE_REMOTE_DEBUGGING) int GetRemoteDebuggingPort() { +#if defined(SB_OVERRIDE_DEFAULT_REMOTE_DEBUGGING_PORT) + const int kDefaultRemoteDebuggingPort = + SB_OVERRIDE_DEFAULT_REMOTE_DEBUGGING_PORT; +#else const int kDefaultRemoteDebuggingPort = 9222; +#endif // defined(SB_OVERRIDE_DEFAULT_REMOTE_DEBUGGING_PORT) int remote_debugging_port = kDefaultRemoteDebuggingPort; #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) CommandLine* command_line = CommandLine::ForCurrentProcess(); @@ -164,6 +173,31 @@ } #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES +std::string GetMinLogLevelString() { +#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kMinLogLevel)) { + return command_line->GetSwitchValueASCII(switches::kMinLogLevel); + } +#endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES + return "info"; +} + +int StringToLogLevel(const std::string& log_level) { + if (log_level == "info") { + return logging::LOG_INFO; + } else if (log_level == "warning") { + return logging::LOG_WARNING; + } else if (log_level == "error") { + return logging::LOG_ERROR; + } else if (log_level == "fatal") { + return logging::LOG_FATAL; + } else { + NOTREACHED() << "Unrecognized logging level: " << log_level; + return logging::LOG_INFO; + } +} + void SetIntegerIfSwitchIsSet(const char* switch_name, int* output) { if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) { int32 out; @@ -267,6 +301,9 @@ RegisterUserLogs(); + // Set the minimum logging level, if specified on the command line. + logging::SetMinLogLevel(StringToLogLevel(GetMinLogLevelString())); + stats_update_timer_.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(kStatUpdatePeriodMs), base::Bind(&Application::UpdatePeriodicStats, base::Unretained(this)));
diff --git a/src/cobalt/browser/browser_bindings.gyp b/src/cobalt/browser/browser_bindings.gyp index cb9d50b..329d8e2 100644 --- a/src/cobalt/browser/browser_bindings.gyp +++ b/src/cobalt/browser/browser_bindings.gyp
@@ -116,6 +116,7 @@ '../dom/MediaKeyNeededEvent.idl', '../dom/MediaQueryList.idl', '../dom/MediaSource.idl', + '../dom/MemoryInfo.idl', '../dom/MimeTypeArray.idl', '../dom/NamedNodeMap.idl', '../dom/Navigator.idl',
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc index 1532cca..58405df 100644 --- a/src/cobalt/browser/browser_module.cc +++ b/src/cobalt/browser/browser_module.cc
@@ -179,6 +179,8 @@ h5vcc_settings.account_manager = account_manager; h5vcc_settings.event_dispatcher = system_window->event_dispatcher(); h5vcc_settings.initial_deep_link = options.initial_deep_link; + h5vcc_settings.on_set_record_stats = base::Bind( + &BrowserModule::OnSetRecordStats, base::Unretained(this)); web_module_options_.injected_window_attributes["h5vcc"] = base::Bind(&CreateH5VCC, h5vcc_settings); @@ -219,6 +221,8 @@ } void BrowserModule::Navigate(const GURL& url) { + web_module_loaded_.Reset(); + // Always post this as a task in case this is being called from the WebModule. self_message_loop_->PostTask( FROM_HERE, base::Bind(&BrowserModule::NavigateInternal, weak_this_, url)); @@ -235,8 +239,6 @@ void BrowserModule::NavigateInternal(const GURL& url) { DCHECK_EQ(MessageLoop::current(), self_message_loop_); - web_module_loaded_.Reset(); - // First try the registered handlers (e.g. for h5vcc://). If one of these // handles the URL, we don't use the web module. if (TryURLHandlers(url)) { @@ -431,6 +433,11 @@ "BrowserModule::OnDebugConsoleRenderTreeProduced()"); DCHECK_EQ(MessageLoop::current(), self_message_loop_); + if (debug_console_->GetMode() == debug::DebugHub::kDebugConsoleOff) { + render_tree_combiner_.UpdateDebugConsoleRenderTree(base::nullopt); + return; + } + render_tree_combiner_.UpdateDebugConsoleRenderTree(renderer::Submission( layout_results.render_tree, layout_results.layout_time)); } @@ -653,6 +660,8 @@ // render tree resources either. render_tree_combiner_.Reset(); + media_module_->Suspend(); + // Place the renderer module into a suspended state where it releases all its // graphical resources. renderer_module_.Suspend(); @@ -666,6 +675,8 @@ renderer_module_.Resume(); + media_module_->Resume(); + // Note that at this point, it is probable that this resource provider is // different than the one that was managed in the associated call to // Suspend(). @@ -697,5 +708,11 @@ } #endif // OS_STARBOARD +void BrowserModule::OnSetRecordStats(bool set) { + if (web_module_) { + web_module_->OnSetRecordStats(set); + } +} + } // namespace browser } // namespace cobalt
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h index 82322b3..677aa32 100644 --- a/src/cobalt/browser/browser_module.h +++ b/src/cobalt/browser/browser_module.h
@@ -210,6 +210,9 @@ // Process all messages queued into the |render_tree_submission_queue_|. void ProcessRenderTreeSubmissionQueue(); + // Called when h5vcc.system.record_stats is set + void OnSetRecordStats(bool set); + // TODO: // WeakPtr usage here can be avoided if BrowserModule has a thread to // own where it can ensure that its tasks are all resolved when it is
diff --git a/src/cobalt/browser/debug_console/debug_console.css b/src/cobalt/browser/debug_console/debug_console.css index afac884..3df005f 100644 --- a/src/cobalt/browser/debug_console/debug_console.css +++ b/src/cobalt/browser/debug_console/debug_console.css
@@ -10,6 +10,7 @@ right: 0; background-color: rgba(128, 128, 128, 0.6); color: #FFFFFF; + display: none; } #hud { @@ -35,6 +36,7 @@ background-color: rgba(128, 128, 128, 0.6); color: #FFFFFF; overflow: hidden; + display: none; } #messageContainerFrame {
diff --git a/src/cobalt/browser/render_tree_combiner.cc b/src/cobalt/browser/render_tree_combiner.cc index 364158b..6a076e1 100644 --- a/src/cobalt/browser/render_tree_combiner.cc +++ b/src/cobalt/browser/render_tree_combiner.cc
@@ -45,7 +45,7 @@ } void RenderTreeCombiner::UpdateDebugConsoleRenderTree( - const renderer::Submission& render_tree_submission) { + const base::optional<renderer::Submission>& render_tree_submission) { debug_console_render_tree_ = render_tree_submission; SubmitToRenderer(); } @@ -105,7 +105,7 @@ } void RenderTreeCombiner::UpdateDebugConsoleRenderTree( - const renderer::Submission& render_tree_submission) { + const base::optional<renderer::Submission>& render_tree_submission) { UNREFERENCED_PARAMETER(render_tree_submission); } #endif // ENABLE_DEBUG_CONSOLE
diff --git a/src/cobalt/browser/render_tree_combiner.h b/src/cobalt/browser/render_tree_combiner.h index 44f38d6..75bca9b 100644 --- a/src/cobalt/browser/render_tree_combiner.h +++ b/src/cobalt/browser/render_tree_combiner.h
@@ -40,7 +40,7 @@ // Update the debug console render tree. void UpdateDebugConsoleRenderTree( - const renderer::Submission& render_tree_submission); + const base::optional<renderer::Submission>& render_tree_submission); #if defined(ENABLE_DEBUG_CONSOLE) bool render_debug_console() const { return render_debug_console_; }
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc index a402253..73b734a 100644 --- a/src/cobalt/browser/switches.cc +++ b/src/cobalt/browser/switches.cc
@@ -52,6 +52,9 @@ // taken from an external input device (like a controller). const char kInputFuzzer[] = "input_fuzzer"; +// Set the minimum logging level: info|warning|error|fatal. +const char kMinLogLevel[] = "min_log_level"; + // Use the NullAudioStreamer. Audio will be decoded but will not play back. No // audio output library will be initialized or used. const char kNullAudioStreamer[] = "null_audio_streamer";
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h index 7d463d0..fe02027 100644 --- a/src/cobalt/browser/switches.h +++ b/src/cobalt/browser/switches.h
@@ -31,6 +31,7 @@ extern const char kExtraWebFileDir[]; extern const char kIgnoreCertificateErrors[]; extern const char kInputFuzzer[]; +extern const char kMinLogLevel[]; extern const char kNullAudioStreamer[]; extern const char kNullSavegame[]; extern const char kPartialLayout[];
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc index 775f7e6..5ee42a0 100644 --- a/src/cobalt/browser/web_module.cc +++ b/src/cobalt/browser/web_module.cc
@@ -23,6 +23,8 @@ #include "base/message_loop_proxy.h" #include "base/optional.h" #include "base/stringprintf.h" +#include "cobalt/base/c_val.h" +#include "cobalt/base/poller.h" #include "cobalt/base/tokens.h" #include "cobalt/browser/switches.h" #include "cobalt/browser/web_module_stat_tracker.h" @@ -37,6 +39,12 @@ namespace { +#if defined(COBALT_RELEASE) +const int kPollerPeriodMs = 2000; +#else // #if defined(COBALT_RELEASE) +const int kPollerPeriodMs = 20; +#endif // #if defined(COBALT_RELEASE) + // The maximum number of element depth in the DOM tree. Elements at a level // deeper than this could be discarded, and will not be rendered. const int kDOMMaxElementDepth = 32; @@ -62,6 +70,29 @@ "To wipe the box tree and turn partial layout off."; #endif // defined(ENABLE_PARTIAL_LAYOUT_CONTROL) +class JSEngineStats { + public: + JSEngineStats() + : js_reserved_memory_("Memory.JS", 0, + "The total memory that is reserved by the engine, " + "including the part that is actually occupied by " + "JS objects, and the part that is not yet.") {} + + static JSEngineStats* GetInstance() { + return Singleton<JSEngineStats, + StaticMemorySingletonTraits<JSEngineStats> >::get(); + } + + void SetReservedMemory(size_t js_reserved_memory) { + js_reserved_memory_ = static_cast<uint64>(js_reserved_memory); + } + + private: + // The total memory that is reserved by the engine, including the part that is + // actually occupied by JS objects, and the part that is not yet. + base::CVal<base::cval::SizeInBytes, base::CValPublic> js_reserved_memory_; +}; + } // namespace // Private WebModule implementation. Each WebModule owns a single instance of @@ -80,7 +111,9 @@ #endif // ENABLE_DEBUG_CONSOLE // Called to inject a keyboard event into the web module. - void InjectKeyboardEvent(const dom::KeyboardEvent::Data& event); + void InjectKeyboardEvent( + scoped_refptr<dom::Element> element, + const dom::KeyboardEvent::Data& event); // Called to execute JavaScript in this WebModule. Sets the |result| // output parameter and signals |got_result|. @@ -111,6 +144,10 @@ void Suspend(); void Resume(render_tree::ResourceProvider* resource_provider); + void OnSetRecordStats(bool set) { + web_module_stat_tracker_->OnSetRecordStats(set); + } + private: class DocumentLoadedObserver; @@ -135,6 +172,13 @@ error_callback_.Run(window_->location()->url(), error); } + void UpdateJavaScriptEngineStats() { + if (javascript_engine_) { + JSEngineStats::GetInstance()->SetReservedMemory( + javascript_engine_->UpdateMemoryStatsAndReturnReserved()); + } + } + // Thread checker ensures all calls to the WebModule are made from the same // thread that it is created in. base::ThreadChecker thread_checker_; @@ -183,6 +227,9 @@ // JavaScript engine for the browser. scoped_ptr<script::JavaScriptEngine> javascript_engine_; + // Poller that updates javascript engine stats. + scoped_ptr<base::PollerWithThread> javascript_engine_poller_; + // JavaScript Global Object for the browser. There should be one per window, // but since there is only one window, we can have one per browser. scoped_refptr<script::GlobalEnvironment> global_environment_; @@ -305,6 +352,11 @@ javascript_engine_ = script::JavaScriptEngine::CreateEngine(); DCHECK(javascript_engine_); + javascript_engine_poller_.reset(new base::PollerWithThread( + base::Bind(&WebModule::Impl::UpdateJavaScriptEngineStats, + base::Unretained(this)), + base::TimeDelta::FromMilliseconds(kPollerPeriodMs))); + global_environment_ = javascript_engine_->CreateGlobalEnvironment(); DCHECK(global_environment_); @@ -413,6 +465,7 @@ script_runner_.reset(); execution_state_.reset(); global_environment_ = NULL; + javascript_engine_poller_.reset(); javascript_engine_.reset(); web_module_stat_tracker_.reset(); local_storage_database_.reset(); @@ -424,6 +477,7 @@ } void WebModule::Impl::InjectKeyboardEvent( + scoped_refptr<dom::Element> element, const dom::KeyboardEvent::Data& event) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(is_running_); @@ -438,7 +492,11 @@ // injected. web_module_stat_tracker_->OnInjectEvent(keyboard_event); - window_->InjectEvent(keyboard_event); + if (element) { + element->DispatchEvent(keyboard_event); + } else { + window_->InjectEvent(keyboard_event); + } } void WebModule::Impl::ExecuteJavascript( @@ -515,6 +573,7 @@ window_driver_out->reset(new webdriver::WindowDriver( window_id, window_weak_, base::Bind(&WebModule::Impl::global_environment, base::Unretained(this)), + base::Bind(&WebModule::Impl::InjectKeyboardEvent, base::Unretained(this)), base::MessageLoopProxy::current())); } #endif // defined(ENABLE_WEBDRIVER) @@ -694,15 +753,27 @@ impl_.reset(new Impl(data)); } -void WebModule::InjectKeyboardEvent(const dom::KeyboardEvent::Data& event) { +void WebModule::InjectKeyboardEvent( + const dom::KeyboardEvent::Data& event) { + DCHECK(message_loop()); + DCHECK(impl_); + message_loop()->PostTask(FROM_HERE, + base::Bind(&WebModule::Impl::InjectKeyboardEvent, + base::Unretained(impl_.get()), + scoped_refptr<dom::Element>(), + event)); +} + +void WebModule::InjectKeyboardEvent( + scoped_refptr<dom::Element> element, + const dom::KeyboardEvent::Data& event) { TRACE_EVENT1("cobalt::browser", "WebModule::InjectKeyboardEvent()", "type", event.type); DCHECK(message_loop()); DCHECK(impl_); + DCHECK_EQ(MessageLoop::current(), message_loop()); - message_loop()->PostTask(FROM_HERE, - base::Bind(&WebModule::Impl::InjectKeyboardEvent, - base::Unretained(impl_.get()), event)); + impl_->InjectKeyboardEvent(element, event); } std::string WebModule::ExecuteJavascript( @@ -808,5 +879,12 @@ base::Unretained(impl_.get()), resource_provider)); } +void WebModule::OnSetRecordStats(bool set) { + DCHECK(message_loop()); + DCHECK(impl_); + DCHECK_EQ(MessageLoop::current(), message_loop()); + impl_->OnSetRecordStats(set); +} + } // namespace browser } // namespace cobalt
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h index 4987ebe..5b6c8c2 100644 --- a/src/cobalt/browser/web_module.h +++ b/src/cobalt/browser/web_module.h
@@ -160,7 +160,16 @@ ~WebModule(); // Call this to inject a keyboard event into the web module. - void InjectKeyboardEvent(const dom::KeyboardEvent::Data& event); + // Event is directed at a specific element if the element is non-null. + // Otherwise, the currently focused element receives the event. + // If element is specified, we must be on the WebModule's message loop + void InjectKeyboardEvent( + scoped_refptr<dom::Element> element, + const dom::KeyboardEvent::Data& event); + + // Call this to inject a keyboard event into the web module. + void InjectKeyboardEvent( + const dom::KeyboardEvent::Data& event); // Call this to execute Javascript code in this web module. The calling // thread will block until the JavaScript has executed and the output results @@ -190,6 +199,9 @@ // can only be called if we have previously suspended the WebModule. void Resume(render_tree::ResourceProvider* resource_provider); + // Called when h5vcc.system.recordStats is set. + void OnSetRecordStats(bool set); + #if defined(COBALT_BUILD_TYPE_DEBUG) // Non-optimized builds require a bigger stack size. static const size_t kBaseStackSize = 2 * 1024 * 1024;
diff --git a/src/cobalt/browser/web_module_stat_tracker.cc b/src/cobalt/browser/web_module_stat_tracker.cc index 10bdf94..dc94278 100644 --- a/src/cobalt/browser/web_module_stat_tracker.cc +++ b/src/cobalt/browser/web_module_stat_tracker.cc
@@ -20,6 +20,9 @@ #include "cobalt/base/tokens.h" #include "cobalt/dom/event.h" +// The maximum allowed string size of any recorded stat +const std::string::size_type kMaxRecordedStatsBytes = 64 * 1024; + namespace cobalt { namespace browser { @@ -28,7 +31,10 @@ : dom_stat_tracker_(new dom::DomStatTracker(name)), layout_stat_tracker_(new layout::LayoutStatTracker(name)), should_track_event_stats_(should_track_event_stats), - current_event_type_(kEventTypeInvalid) { + current_event_type_(kEventTypeInvalid), + name_(name), + event_is_processing_(StringPrintf("Event.%s.IsProcessing", name.c_str()), + 0, "Nonzero when an event is being processed.") { if (should_track_event_stats_) { event_stats_.reserve(kNumEventTypes); for (int i = 0; i < kNumEventTypes; ++i) { @@ -56,6 +62,8 @@ EndCurrentEvent(false); + event_is_processing_ = 1; + if (event->type() == base::Tokens::keydown()) { current_event_type_ = kEventTypeKeyDown; } else if (event->type() == base::Tokens::keyup()) { @@ -82,6 +90,17 @@ layout_stat_tracker_->FlushPeriodicTracking(); } +void WebModuleStatTracker::OnSetRecordStats(bool set) { + record_stats_ = set; + + // Every time this variable is set, we clear out our stats + for (ScopedVector<EventStats>::iterator it = event_stats_.begin(); + it != event_stats_.end(); + ++it) { + (*it)->event_durations = "[]"; + } +} + WebModuleStatTracker::EventStats::EventStats(const std::string& name) : count_dom_html_elements_created( StringPrintf("Event.Count.%s.DOM.HtmlElement.Created", name.c_str()), @@ -138,7 +157,11 @@ StringPrintf("Event.Duration.%s.Layout.RenderAndAnimate", name.c_str()), base::TimeDelta(), - "RenderAndAnimate duration for event (in microseconds).") {} + "RenderAndAnimate duration for event (in microseconds)."), + event_durations(StringPrintf("Event.Durations.%s", name.c_str()), + "[]", + "JSON array of all event durations (in microseconds) " + "since reset.") {} bool WebModuleStatTracker::IsStopWatchEnabled(int /*id*/) const { return true; } @@ -152,6 +175,8 @@ return; } + event_is_processing_ = 0; + stop_watch_durations_[kStopWatchTypeEvent] = base::TimeDelta(); stop_watches_[kStopWatchTypeEvent].Stop(); dom_stat_tracker_->DisableStopWatches(); @@ -184,9 +209,25 @@ // misleading as it merely indicates how long the user waited to initiate the // next event. When this occurs, the injection duration provides a much more // accurate picture of how long the event takes. - event_stats->duration_total = was_render_tree_produced + base::TimeDelta duration_total = was_render_tree_produced ? stop_watch_durations_[kStopWatchTypeEvent] : event_injection_duration; + event_stats->duration_total = duration_total; + + if (record_stats_) { + std::string prev_durations = event_stats->event_durations.value(); + if (prev_durations.size() <= 2) { + event_stats->event_durations = + StringPrintf("[%ld]", duration_total.InMicroseconds()); + } else if (prev_durations.size() < kMaxRecordedStatsBytes) { + event_stats->event_durations + = StringPrintf("%s,%ld]", + prev_durations.substr( + 0, prev_durations.size() - 1).c_str(), + duration_total.InMicroseconds()); + } + } + event_stats->duration_dom_inject_event = event_injection_duration; event_stats->duration_dom_update_computed_style = dom_stat_tracker_->GetStopWatchTypeDuration(
diff --git a/src/cobalt/browser/web_module_stat_tracker.h b/src/cobalt/browser/web_module_stat_tracker.h index 8e9dbd3..8ebf73d 100644 --- a/src/cobalt/browser/web_module_stat_tracker.h +++ b/src/cobalt/browser/web_module_stat_tracker.h
@@ -54,6 +54,9 @@ // triggers flushing of periodic counts within the stat trackers. void OnRenderTreeProduced(); + // Called when h5vcc.system.record_stats is set + void OnSetRecordStats(bool set); + private: enum EventType { kEventTypeInvalid = -1, @@ -90,6 +93,9 @@ duration_layout_update_used_sizes; base::CVal<base::TimeDelta, base::CValPublic> duration_layout_render_and_animate; + + // Time series-related + base::CVal<std::string, base::CValPublic> event_durations; }; // From base::StopWatchOwner @@ -115,6 +121,13 @@ // Stop watch-related std::vector<base::StopWatch> stop_watches_; std::vector<base::TimeDelta> stop_watch_durations_; + + // Time series-related + bool record_stats_; + + std::string name_; + + base::CVal<int, base::CValPublic> event_is_processing_; }; } // namespace browser
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id index 66974b8..4860db9 100644 --- a/src/cobalt/build/build.id +++ b/src/cobalt/build/build.id
@@ -1 +1 @@ -12347 \ No newline at end of file +12959 \ No newline at end of file
diff --git a/src/cobalt/content/fonts/10megabytes/fonts.xml b/src/cobalt/content/fonts/10megabytes/fonts.xml index c0ffb0a..d066d4a 100644 --- a/src/cobalt/content/fonts/10megabytes/fonts.xml +++ b/src/cobalt/content/fonts/10megabytes/fonts.xml
@@ -1,4 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> +<familyset version="1"> <!-- NOTE: Families with a "fallback" value of "true" are added to the fallback list, regardless of whether or not they are named. Fallback fonts are chosen @@ -13,10 +14,9 @@ indexed, and each page contains 256 characters, so character 1000 would be contained within page 3. --> -<familyset version="1"> <!-- first font is default --> <family name="sans-serif"> - <font weight="400" style="normal">Roboto-Regular.ttf</font> + <font font_name="Roboto Regular" postscript_name="Roboto-Regular" style="normal" weight="400">Roboto-Regular.ttf</font> </family> <!-- Note that aliases must come after the fonts they reference. --> <alias name="arial" to="sans-serif" /> @@ -27,187 +27,187 @@ <alias name="courier" to="serif-monospace" /> <alias name="courier new" to="serif-monospace" /> <family name="sans-serif-smallcaps"> - <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font> + <font font_name="Carrois Gothic SC" postscript_name="CarroisGothicSC-Regular" style="normal" weight="400">CarroisGothicSC-Regular.ttf</font> </family> <!-- fallback fonts --> - <family name="Noto Naskh Arabic UI" fallback="true" pages="0,6-8,32,37,46,251-254"> - <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font> + <family fallback="true" name="Noto Naskh Arabic UI" pages="0,6-8,32,37,46,251-254"> + <font font_name="Noto Naskh Arabic UI" postscript_name="NotoNaskhArabicUI" style="normal" weight="400">NotoNaskhArabicUI-Regular.ttf</font> </family> <family fallback="true" pages="0,18-19,45,171,254"> - <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font> + <font font_name="Noto Sans Ethiopic" postscript_name="NotoSansEthiopic" style="normal" weight="400">NotoSansEthiopic-Regular.ttf</font> </family> <family fallback="true" pages="0,5,32,37,251,254"> - <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font> + <font font_name="Noto Sans Hebrew" postscript_name="NotoSansHebrew" style="normal" weight="400">NotoSansHebrew-Regular.ttf</font> </family> <family fallback="true" pages="0,2-3,14,32,37,254"> - <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font> + <font font_name="Noto Sans Thai UI" postscript_name="NotoSansThaiUI" style="normal" weight="400">NotoSansThaiUI-Regular.ttf</font> </family> <family fallback="true" pages="0,5,251,254"> - <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font> + <font font_name="Noto Sans Armenian" postscript_name="NotoSansArmenian" style="normal" weight="400">NotoSansArmenian-Regular.ttf</font> </family> <family fallback="true" pages="0,5,16,45,254"> - <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font> + <font font_name="Noto Sans Georgian" postscript_name="NotoSansGeorgian" style="normal" weight="400">NotoSansGeorgian-Regular.ttf</font> </family> <family fallback="true" pages="0,2,9,28,32,34,37,168,254"> - <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font> + <font font_name="Noto Sans Devanagari UI" postscript_name="NotoSansDevanagariUI" style="normal" weight="400">NotoSansDevanagariUI-Regular.ttf</font> </family> <!-- Gujarati should come after Devanagari --> <family fallback="true" pages="0,9-10,32,34,37,168,254"> - <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font> + <font font_name="Noto Sans Gujarati UI" postscript_name="NotoSansGujaratiUI" style="normal" weight="400">NotoSansGujaratiUI-Regular.ttf</font> </family> <!-- Gurmukhi should come after Devanagari --> <family fallback="true" pages="0,9-10,32,34,37-38,168,254"> - <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font> + <font font_name="Noto Sans Gurmukhi UI" postscript_name="NotoSansGurmukhiUI" style="normal" weight="400">NotoSansGurmukhiUI-Regular.ttf</font> </family> <family fallback="true" pages="0,9,11,32,34,37,254"> - <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font> + <font font_name="Noto Sans Tamil UI" postscript_name="NotoSansTamilUI" style="normal" weight="400">NotoSansTamilUI-Regular.ttf</font> </family> <family fallback="true" pages="0,3,9,13,32,34,37,254"> - <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font> + <font font_name="Noto Sans Malayalam UI" postscript_name="NotoSansMalayalamUI" style="normal" weight="400">NotoSansMalayalamUI-Regular.ttf</font> </family> <family fallback="true" pages="0,9,32,34,37,254"> - <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font> + <font font_name="Noto Sans Bengali UI" postscript_name="NotoSansBengaliUI" style="normal" weight="400">NotoSansBengaliUI-Regular.ttf</font> </family> <family fallback="true" pages="0,9,12,32,34,37,254"> - <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font> + <font font_name="Noto Sans Telugu UI" postscript_name="NotoSansTeluguUI" style="normal" weight="400">NotoSansTeluguUI-Regular.ttf</font> </family> <family fallback="true" pages="0,9,12,32,34,37,254"> - <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font> + <font font_name="Noto Sans Kannada UI" postscript_name="NotoSansKannadaUI" style="normal" weight="400">NotoSansKannadaUI-Regular.ttf</font> </family> <family fallback="true" pages="0,9,11,32,34,37,254"> - <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font> + <font font_name="Noto Sans Oriya UI" postscript_name="NotoSansOriyaUI" style="normal" weight="400">NotoSansOriyaUI-Regular.ttf</font> </family> <family fallback="true" pages="0,9,13,32,34,37,254"> - <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font> + <font font_name="Noto Sans Sinhala" postscript_name="NotoSansSinhala" style="normal" weight="400">NotoSansSinhala-Regular.ttf</font> </family> <family fallback="true" pages="0,23,25,32,37"> - <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font> + <font font_name="Noto Sans Khmer UI" postscript_name="NotoSansKhmerUI" style="normal" weight="400">NotoSansKhmerUI-Regular.ttf</font> </family> <family fallback="true" pages="0,3,14,32,37"> - <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font> + <font font_name="Noto Sans Lao UI" postscript_name="NotoSansLaoUI" style="normal" weight="400">NotoSansLaoUI-Regular.ttf</font> </family> <family fallback="true" pages="0,6-7,32,37,253-254"> - <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font> + <font font_name="Noto Sans Thaana" postscript_name="NotoSansThaana" style="normal" weight="400">NotoSansThaana-Regular.ttf</font> </family> <family fallback="true" pages="0,3,170"> - <font weight="400" style="normal">NotoSansCham-Regular.ttf</font> + <font font_name="Noto Sans Cham" postscript_name="NotoSansCham" style="normal" weight="400">NotoSansCham-Regular.ttf</font> </family> <family fallback="true" pages="0,27,32,37,254"> - <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font> + <font font_name="Noto Sans Balinese" postscript_name="NotoSansBalinese" style="normal" weight="400">NotoSansBalinese-Regular.ttf</font> </family> <family fallback="true" pages="0,166,254,360-362"> - <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font> + <font font_name="Noto Sans Bamum" postscript_name="NotoSansBamum" style="normal" weight="400">NotoSansBamum-Regular.ttf</font> </family> <family fallback="true" pages="0,27,254"> - <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font> + <font font_name="Noto Sans Batak" postscript_name="NotoSansBatak" style="normal" weight="400">NotoSansBatak-Regular.ttf</font> </family> <family fallback="true" pages="0,26,32,169,254"> - <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font> + <font font_name="Noto Sans Buginese" postscript_name="NotoSansBuginese" style="normal" weight="400">NotoSansBuginese-Regular.ttf</font> </family> <family fallback="true" pages="0,23,254"> - <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font> + <font font_name="Noto Sans Buhid" postscript_name="NotoSansBuhid" style="normal" weight="400">NotoSansBuhid-Regular.ttf</font> </family> <family fallback="true" pages="0-3,20-22,24,254"> - <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font> + <font font_name="Noto Sans Canadian Aboriginal" postscript_name="NotoSansCanadianAboriginal" style="normal" weight="400">NotoSansCanadianAboriginal-Regular.ttf</font> </family> <family fallback="true" pages="0,19,254"> - <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font> + <font font_name="Noto Sans Cherokee" postscript_name="NotoSansCherokee" style="normal" weight="400">NotoSansCherokee-Regular.ttf</font> </family> <family fallback="true" pages="0-3,29,44,254"> - <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font> + <font font_name="Noto Sans Coptic" postscript_name="NotoSansCoptic" style="normal" weight="400">NotoSansCoptic-Regular.ttf</font> </family> <family fallback="true" pages="0,44,254"> - <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font> + <font font_name="Noto Sans Glagolitic" postscript_name="NotoSansGlagolitic" style="normal" weight="400">NotoSansGlagolitic-Regular.ttf</font> </family> <family fallback="true" pages="0,23,254"> - <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font> + <font font_name="Noto Sans Hanunoo" postscript_name="NotoSansHanunoo" style="normal" weight="400">NotoSansHanunoo-Regular.ttf</font> </family> <family fallback="true" pages="0,32,37,169,254"> - <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font> + <font font_name="Noto Sans Javanese" postscript_name="NotoSansJavanese" style="normal" weight="400">NotoSansJavanese-Regular.ttf</font> </family> <family fallback="true" pages="0,169,254"> - <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font> + <font font_name="Noto Sans Kayah Li" postscript_name="NotoSansKayahLi" style="normal" weight="400">NotoSansKayahLi-Regular.ttf</font> </family> <family fallback="true" pages="0,28,37,254"> - <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font> + <font font_name="Noto Sans Lepcha" postscript_name="NotoSansLepcha" style="normal" weight="400">NotoSansLepcha-Regular.ttf</font> </family> <family fallback="true" pages="0,9,25,254"> - <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font> + <font font_name="Noto Sans Limbu" postscript_name="NotoSansLimbu" style="normal" weight="400">NotoSansLimbu-Regular.ttf</font> </family> <family fallback="true" pages="0,2,164,254"> - <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font> + <font font_name="Noto Sans Lisu" postscript_name="NotoSansLisu" style="normal" weight="400">NotoSansLisu-Regular.ttf</font> </family> <family fallback="true" pages="0,6,8,254"> - <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font> + <font font_name="Noto Sans Mandaic" postscript_name="NotoSansMandaic" style="normal" weight="400">NotoSansMandaic-Regular.ttf</font> </family> <family fallback="true" pages="0,170-171,254"> - <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font> + <font font_name="Noto Sans Meetei Mayek" postscript_name="NotoSansMeeteiMayek" style="normal" weight="400">NotoSansMeeteiMayek-Regular.ttf</font> </family> <family fallback="true" pages="0,25,254"> - <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font> + <font font_name="Noto Sans New Tai Lue" postscript_name="NotoSansNewTaiLue" style="normal" weight="400">NotoSansNewTaiLue-Regular.ttf</font> </family> <family fallback="true" pages="0,6-7,32,46,253-254"> - <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font> + <font font_name="Noto Sans NKo" postscript_name="NotoSansNKo" style="normal" weight="400">NotoSansNKo-Regular.ttf</font> </family> <family fallback="true" pages="0,28,254"> - <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font> + <font font_name="Noto Sans Ol Chiki" postscript_name="NotoSansOlChiki" style="normal" weight="400">NotoSansOlChiki-Regular.ttf</font> </family> <family fallback="true" pages="0,169,254"> - <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font> + <font font_name="Noto Sans Rejang" postscript_name="NotoSansRejang" style="normal" weight="400">NotoSansRejang-Regular.ttf</font> </family> <family fallback="true" pages="0,32,37,168,254"> - <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font> + <font font_name="Noto Sans Saurashtra" postscript_name="NotoSansSaurashtra" style="normal" weight="400">NotoSansSaurashtra-Regular.ttf</font> </family> <family fallback="true" pages="0,27-28,254"> - <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font> + <font font_name="Noto Sans Sundanese" postscript_name="NotoSansSundanese" style="normal" weight="400">NotoSansSundanese-Regular.ttf</font> </family> <family fallback="true" pages="0,9,32,37,168,254"> - <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font> + <font font_name="Noto Sans Syloti Nagri" postscript_name="NotoSansSylotiNagri" style="normal" weight="400">NotoSansSylotiNagri-Regular.ttf</font> </family> <family fallback="true" pages="0,3,6-7,32,34,37-38,254"> - <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font> + <font font_name="Noto Sans Syriac Estrangela" postscript_name="NotoSansSyriacEstrangela" style="normal" weight="400">NotoSansSyriacEstrangela-Regular.ttf</font> </family> <family fallback="true" pages="0,23,254"> - <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font> + <font font_name="Noto Sans Tagbanwa" postscript_name="NotoSansTagbanwa" style="normal" weight="400">NotoSansTagbanwa-Regular.ttf</font> </family> <family fallback="true" pages="0,26,32,34,37,254"> - <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font> + <font font_name="Noto Sans Tai Tham" postscript_name="NotoSansTaiTham" style="normal" weight="400">NotoSansTaiTham-Regular.ttf</font> </family> <family fallback="true" pages="0,32,37,167,170,254"> - <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font> + <font font_name="Noto Sans Tai Viet" postscript_name="NotoSansTaiViet" style="normal" weight="400">NotoSansTaiViet-Regular.ttf</font> </family> <family fallback="true" pages="0,15,32,37,254"> - <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font> + <font font_name="Noto Sans Tibetan" postscript_name="NotoSansTibetan" style="normal" weight="400">NotoSansTibetan-Regular.ttf</font> </family> <family fallback="true" pages="0,3,32,45,254"> - <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font> + <font font_name="Noto Sans Tifinagh" postscript_name="NotoSansTifinagh" style="normal" weight="400">NotoSansTifinagh-Regular.ttf</font> </family> <family fallback="true" pages="0,165-166,254"> - <font weight="400" style="normal">NotoSansVai-Regular.ttf</font> + <font font_name="Noto Sans Vai" postscript_name="NotoSansVai" style="normal" weight="400">NotoSansVai-Regular.ttf</font> </family> <family fallback="true" pages="0,160-164,254"> - <font weight="400" style="normal">NotoSansYi-Regular.ttf</font> + <font font_name="Noto Sans Yi" postscript_name="NotoSansYi" style="normal" weight="400">NotoSansYi-Regular.ttf</font> </family> <family fallback="true" pages="32-43"> - <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font> + <font font_name="Noto Sans Symbols" postscript_name="NotoSansSymbols" style="normal" weight="400">NotoSansSymbols-Regular-Subsetted.ttf</font> </family> <family fallback="true" lang="ja" pages="0,32,34-35,46-159,249-250,254-255,498,512-523,525-527,530-538,540-543,545-547,550,552,554-559,561,563-568,570,572-573,575-579,582-584,586-594,596-608,610-612,614-618,620,622-625,627-628,630-631,633-638,640,642-646,649-655,658,660-664,666,669-678,681,695-696,760-761"> - <font weight="400" style="normal">NotoSansJP-Regular.otf</font> + <font font_name="Noto Sans JP Regular" postscript_name="NotoSansJP-Regular" style="normal" weight="400">NotoSansJP-Regular.otf</font> </family> <family fallback="true" pages="0,32-33,35-39,41,43,48,50,224,254-255,496-502,4068"> - <font weight="400" style="normal">NotoEmoji-Regular.ttf</font> + <font font_name="Noto Emoji" postscript_name="NotoEmoji" style="normal" weight="400">NotoEmoji-Regular.ttf</font> </family> <family fallback="true" pages="0,14,17,32,48-51,77-159,172-215,249-250,254-255,260"> - <font weight="400" style="normal">DroidSansFallback.ttf</font> + <font font_name="Droid Sans Fallback" postscript_name="DroidSansFallback" style="normal" weight="400">DroidSansFallback.ttf</font> </family> <!-- Tai Le and Mongolian are intentionally kept last, to make sure they don't override the East Asian punctuation for Chinese. --> <family fallback="true" pages="0,16,25,48,254"> - <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font> + <font font_name="Noto Sans Tai Le" postscript_name="NotoSansTaiLe" style="normal" weight="400">NotoSansTaiLe-Regular.ttf</font> </family> <family fallback="true" pages="0,24,32,36-37,48,254"> - <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font> + <font font_name="Noto Sans Mongolian" postscript_name="NotoSansMongolian" style="normal" weight="400">NotoSansMongolian-Regular.ttf</font> </family> </familyset>
diff --git a/src/cobalt/content/fonts/minimal/fonts.xml b/src/cobalt/content/fonts/minimal/fonts.xml index 1381b81..bd40ee3 100644 --- a/src/cobalt/content/fonts/minimal/fonts.xml +++ b/src/cobalt/content/fonts/minimal/fonts.xml
@@ -1,11 +1,25 @@ <?xml version="1.0" encoding="utf-8"?> <familyset version="1"> +<!-- + NOTE: Families with a "fallback" value of "true" are added to the fallback + list, regardless of whether or not they are named. Fallback fonts are chosen + based on a match: full BCP-47 language tag including script, then just + language, and finally order (the first font containing the glyph). Order of + appearance is also the tiebreaker for weight matching. + + The pages attribute indicates which character pages are contained within + the font. It is used with character fallback to allow the system to quickly + determine that a character cannot appear in a font without requiring the + full character map to be loaded into memory. Character pages are zero + indexed, and each page contains 256 characters, so character 1000 would be + contained within page 3. +--> <!-- Ideally, this font should only be used if there are no other fonts in our final image. --> <family name="Minimal Roboto"> - <font weight="400" style="normal">MinimalRoboto.ttf</font> + <font font_name="Minimal Roboto" postscript_name="Minimal Roboto" style="normal" weight="400">MinimalRoboto.ttf</font> </family> <family name="sans-serif-smallcaps"> - <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font> + <font font_name="Carrois Gothic SC" postscript_name="CarroisGothicSC-Regular" style="normal" weight="400">CarroisGothicSC-Regular.ttf</font> </family> </familyset>
diff --git a/src/cobalt/content/fonts/unlimited/fonts.xml b/src/cobalt/content/fonts/unlimited/fonts.xml index 3e1ec53..25426c3 100644 --- a/src/cobalt/content/fonts/unlimited/fonts.xml +++ b/src/cobalt/content/fonts/unlimited/fonts.xml
@@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<familyset version="1"> <!-- NOTE: Families with a "fallback" value of "true" are added to the fallback list, regardless of whether or not they are named. Fallback fonts are chosen @@ -13,13 +13,12 @@ indexed, and each page contains 256 characters, so character 1000 would be contained within page 3. --> -<familyset version="1"> <!-- first font is default --> <family name="sans-serif"> - <font weight="400" style="normal">Roboto-Regular.ttf</font> - <font weight="400" style="italic">Roboto-Italic.ttf</font> - <font weight="700" style="normal">Roboto-Bold.ttf</font> - <font weight="700" style="italic">Roboto-BoldItalic.ttf</font> + <font font_name="Roboto Regular" postscript_name="Roboto-Regular" style="normal" weight="400">Roboto-Regular.ttf</font> + <font font_name="Roboto Italic" postscript_name="Roboto-Italic" style="italic" weight="400">Roboto-Italic.ttf</font> + <font font_name="Roboto Bold" postscript_name="Roboto-Bold" style="normal" weight="700">Roboto-Bold.ttf</font> + <font font_name="Roboto Bold Italic" postscript_name="Roboto-BoldItalic" style="italic" weight="700">Roboto-BoldItalic.ttf</font> </family> <!-- Note that aliases must come after the fonts they reference. --> <alias name="arial" to="sans-serif" /> @@ -30,13 +29,13 @@ <!-- Ideally, this font should only be used if there are no other fonts in our final image. --> <family name="Minimal Roboto"> - <font weight="400" style="normal">MinimalRoboto.ttf</font> + <font font_name="Minimal Roboto" postscript_name="Minimal Roboto" style="normal" weight="400">MinimalRoboto.ttf</font> </family> <family name="serif"> - <font weight="400" style="normal">NotoSerif-Regular.ttf</font> - <font weight="400" style="italic">NotoSerif-Italic.ttf</font> - <font weight="700" style="normal">NotoSerif-Bold.ttf</font> - <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font> + <font font_name="Noto Serif" postscript_name="NotoSerif" style="normal" weight="400">NotoSerif-Regular.ttf</font> + <font font_name="Noto Serif Italic" postscript_name="NotoSerif-Italic" style="italic" weight="400">NotoSerif-Italic.ttf</font> + <font font_name="Noto Serif Bold" postscript_name="NotoSerif-Bold" style="normal" weight="700">NotoSerif-Bold.ttf</font> + <font font_name="Noto Serif Bold Italic" postscript_name="NotoSerif-BoldItalic" style="italic" weight="700">NotoSerif-BoldItalic.ttf</font> </family> <alias name="times" to="serif" /> <alias name="times new roman" to="serif" /> @@ -47,243 +46,243 @@ <alias name="fantasy" to="serif" /> <alias name="ITC Stone Serif" to="serif" /> <family name="monospace"> - <font weight="400" style="normal">DroidSansMono.ttf</font> + <font font_name="Droid Sans Mono" postscript_name="DroidSansMono" style="normal" weight="400">DroidSansMono.ttf</font> </family> <alias name="sans-serif-monospace" to="monospace" /> <alias name="monaco" to="monospace" /> <family name="serif-monospace"> - <font weight="400" style="normal">CutiveMono.ttf</font> + <font font_name="Cutive Mono" postscript_name="CutiveMono-Regular" style="normal" weight="400">CutiveMono.ttf</font> </family> <alias name="courier" to="serif-monospace" /> <alias name="courier new" to="serif-monospace" /> <family name="casual"> - <font weight="400" style="normal">ComingSoon.ttf</font> + <font font_name="Coming Soon" postscript_name="ComingSoon" style="normal" weight="400">ComingSoon.ttf</font> </family> <family name="cursive"> - <font weight="400" style="normal">DancingScript-Regular.ttf</font> - <font weight="700" style="normal">DancingScript-Bold.ttf</font> + <font font_name="Dancing Script" postscript_name="DancingScript" style="normal" weight="400">DancingScript-Regular.ttf</font> + <font font_name="Dancing Script Bold" postscript_name="DancingScript-Bold" style="normal" weight="700">DancingScript-Bold.ttf</font> </family> <family name="sans-serif-smallcaps"> - <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font> + <font font_name="Carrois Gothic SC" postscript_name="CarroisGothicSC-Regular" style="normal" weight="400">CarroisGothicSC-Regular.ttf</font> </family> <!-- fallback fonts --> - <family name="Noto Naskh Arabic UI" fallback="true" pages="0,6-8,32,37,46,251-254"> - <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font> - <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font> + <family fallback="true" name="Noto Naskh Arabic UI" pages="0,6-8,32,37,46,251-254"> + <font font_name="Noto Naskh Arabic UI" postscript_name="NotoNaskhArabicUI" style="normal" weight="400">NotoNaskhArabicUI-Regular.ttf</font> + <font font_name="Noto Naskh Arabic UI Bold" postscript_name="NotoNaskhArabicUI-Bold" style="normal" weight="700">NotoNaskhArabicUI-Bold.ttf</font> </family> <family fallback="true" pages="0,18-19,45,171,254"> - <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font> - <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font> + <font font_name="Noto Sans Ethiopic" postscript_name="NotoSansEthiopic" style="normal" weight="400">NotoSansEthiopic-Regular.ttf</font> + <font font_name="Noto Sans Ethiopic Bold" postscript_name="NotoSansEthiopic-Bold" style="normal" weight="700">NotoSansEthiopic-Bold.ttf</font> </family> <family fallback="true" pages="0,5,32,37,251,254"> - <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font> - <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font> + <font font_name="Noto Sans Hebrew" postscript_name="NotoSansHebrew" style="normal" weight="400">NotoSansHebrew-Regular.ttf</font> + <font font_name="Noto Sans Hebrew Bold" postscript_name="NotoSansHebrew-Bold" style="normal" weight="700">NotoSansHebrew-Bold.ttf</font> </family> <family fallback="true" pages="0,2-3,14,32,37,254"> - <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font> + <font font_name="Noto Sans Thai UI" postscript_name="NotoSansThaiUI" style="normal" weight="400">NotoSansThaiUI-Regular.ttf</font> + <font font_name="Noto Sans Thai UI Bold" postscript_name="NotoSansThaiUI-Bold" style="normal" weight="700">NotoSansThaiUI-Bold.ttf</font> </family> <family fallback="true" pages="0,5,251,254"> - <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font> - <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font> + <font font_name="Noto Sans Armenian" postscript_name="NotoSansArmenian" style="normal" weight="400">NotoSansArmenian-Regular.ttf</font> + <font font_name="Noto Sans Armenian Bold" postscript_name="NotoSansArmenian-Bold" style="normal" weight="700">NotoSansArmenian-Bold.ttf</font> </family> <family fallback="true" pages="0,5,16,45,254"> - <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font> - <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font> + <font font_name="Noto Sans Georgian" postscript_name="NotoSansGeorgian" style="normal" weight="400">NotoSansGeorgian-Regular.ttf</font> + <font font_name="Noto Sans Georgian Bold" postscript_name="NotoSansGeorgian-Bold" style="normal" weight="700">NotoSansGeorgian-Bold.ttf</font> </family> <family fallback="true" pages="0,2,9,28,32,34,37,168,254"> - <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font> + <font font_name="Noto Sans Devanagari UI" postscript_name="NotoSansDevanagariUI" style="normal" weight="400">NotoSansDevanagariUI-Regular.ttf</font> + <font font_name="Noto Sans Devanagari UI Bold" postscript_name="NotoSansDevanagariUI-Bold" style="normal" weight="700">NotoSansDevanagariUI-Bold.ttf</font> </family> <!-- Gujarati should come after Devanagari --> <family fallback="true" pages="0,9-10,32,34,37,168,254"> - <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font> + <font font_name="Noto Sans Gujarati UI" postscript_name="NotoSansGujaratiUI" style="normal" weight="400">NotoSansGujaratiUI-Regular.ttf</font> + <font font_name="Noto Sans Gujarati UI Bold" postscript_name="NotoSansGujaratiUI-Bold" style="normal" weight="700">NotoSansGujaratiUI-Bold.ttf</font> </family> <!-- Gurmukhi should come after Devanagari --> <family fallback="true" pages="0,9-10,32,34,37-38,168,254"> - <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font> + <font font_name="Noto Sans Gurmukhi UI" postscript_name="NotoSansGurmukhiUI" style="normal" weight="400">NotoSansGurmukhiUI-Regular.ttf</font> + <font font_name="Noto Sans Gurmukhi UI Bold" postscript_name="NotoSansGurmukhiUI-Bold" style="normal" weight="700">NotoSansGurmukhiUI-Bold.ttf</font> </family> <family fallback="true" pages="0,9,11,32,34,37,254"> - <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font> + <font font_name="Noto Sans Tamil UI" postscript_name="NotoSansTamilUI" style="normal" weight="400">NotoSansTamilUI-Regular.ttf</font> + <font font_name="Noto Sans Tamil UI Bold" postscript_name="NotoSansTamilUI-Bold" style="normal" weight="700">NotoSansTamilUI-Bold.ttf</font> </family> <family fallback="true" pages="0,3,9,13,32,34,37,254"> - <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font> + <font font_name="Noto Sans Malayalam UI" postscript_name="NotoSansMalayalamUI" style="normal" weight="400">NotoSansMalayalamUI-Regular.ttf</font> + <font font_name="Noto Sans Malayalam UI Bold" postscript_name="NotoSansMalayalamUI-Bold" style="normal" weight="700">NotoSansMalayalamUI-Bold.ttf</font> </family> <family fallback="true" pages="0,9,32,34,37,254"> - <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font> + <font font_name="Noto Sans Bengali UI" postscript_name="NotoSansBengaliUI" style="normal" weight="400">NotoSansBengaliUI-Regular.ttf</font> + <font font_name="Noto Sans Bengali UI Bold" postscript_name="NotoSansBengaliUI-Bold" style="normal" weight="700">NotoSansBengaliUI-Bold.ttf</font> </family> <family fallback="true" pages="0,9,12,32,34,37,254"> - <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font> + <font font_name="Noto Sans Telugu UI" postscript_name="NotoSansTeluguUI" style="normal" weight="400">NotoSansTeluguUI-Regular.ttf</font> + <font font_name="Noto Sans Telugu UI Bold" postscript_name="NotoSansTeluguUI-Bold" style="normal" weight="700">NotoSansTeluguUI-Bold.ttf</font> </family> <family fallback="true" pages="0,9,12,32,34,37,254"> - <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font> + <font font_name="Noto Sans Kannada UI" postscript_name="NotoSansKannadaUI" style="normal" weight="400">NotoSansKannadaUI-Regular.ttf</font> + <font font_name="Noto Sans Kannada UI Bold" postscript_name="NotoSansKannadaUI-Bold" style="normal" weight="700">NotoSansKannadaUI-Bold.ttf</font> </family> <family fallback="true" pages="0,9,11,32,34,37,254"> - <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font> + <font font_name="Noto Sans Oriya UI" postscript_name="NotoSansOriyaUI" style="normal" weight="400">NotoSansOriyaUI-Regular.ttf</font> + <font font_name="Noto Sans Oriya UI Bold" postscript_name="NotoSansOriyaUI-Bold" style="normal" weight="700">NotoSansOriyaUI-Bold.ttf</font> </family> <family fallback="true" pages="0,9,13,32,34,37,254"> - <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font> - <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font> + <font font_name="Noto Sans Sinhala" postscript_name="NotoSansSinhala" style="normal" weight="400">NotoSansSinhala-Regular.ttf</font> + <font font_name="Noto Sans Sinhala Bold" postscript_name="NotoSansSinhala-Bold" style="normal" weight="700">NotoSansSinhala-Bold.ttf</font> </family> <family fallback="true" pages="0,23,25,32,37"> - <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font> + <font font_name="Noto Sans Khmer UI" postscript_name="NotoSansKhmerUI" style="normal" weight="400">NotoSansKhmerUI-Regular.ttf</font> + <font font_name="Noto Sans Khmer UI Bold" postscript_name="NotoSansKhmerUI-Bold" style="normal" weight="700">NotoSansKhmerUI-Bold.ttf</font> </family> <family fallback="true" pages="0,3,14,32,37"> - <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font> + <font font_name="Noto Sans Lao UI" postscript_name="NotoSansLaoUI" style="normal" weight="400">NotoSansLaoUI-Regular.ttf</font> + <font font_name="Noto Sans Lao UI Bold" postscript_name="NotoSansLaoUI-Bold" style="normal" weight="700">NotoSansLaoUI-Bold.ttf</font> </family> <family fallback="true" pages="0,16,32,37,169-170,254"> - <font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font> - <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font> + <font font_name="Noto Sans Myanmar UI" postscript_name="NotoSansMyanmarUI" style="normal" weight="400">NotoSansMyanmarUI-Regular.ttf</font> + <font font_name="Noto Sans Myanmar UI Bold" postscript_name="NotoSansMyanmarUI-Bold" style="normal" weight="700">NotoSansMyanmarUI-Bold.ttf</font> </family> <family fallback="true" pages="0,6-7,32,37,253-254"> - <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font> - <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font> + <font font_name="Noto Sans Thaana" postscript_name="NotoSansThaana" style="normal" weight="400">NotoSansThaana-Regular.ttf</font> + <font font_name="Noto Sans Thaana Bold" postscript_name="NotoSansThaana-Bold" style="normal" weight="700">NotoSansThaana-Bold.ttf</font> </family> <family fallback="true" pages="0,3,170"> - <font weight="400" style="normal">NotoSansCham-Regular.ttf</font> - <font weight="700" style="normal">NotoSansCham-Bold.ttf</font> + <font font_name="Noto Sans Cham" postscript_name="NotoSansCham" style="normal" weight="400">NotoSansCham-Regular.ttf</font> + <font font_name="Noto Sans Cham Bold" postscript_name="NotoSansCham-Bold" style="normal" weight="700">NotoSansCham-Bold.ttf</font> </family> <family fallback="true" pages="0,27,32,37,254"> - <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font> + <font font_name="Noto Sans Balinese" postscript_name="NotoSansBalinese" style="normal" weight="400">NotoSansBalinese-Regular.ttf</font> </family> <family fallback="true" pages="0,166,254,360-362"> - <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font> + <font font_name="Noto Sans Bamum" postscript_name="NotoSansBamum" style="normal" weight="400">NotoSansBamum-Regular.ttf</font> </family> <family fallback="true" pages="0,27,254"> - <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font> + <font font_name="Noto Sans Batak" postscript_name="NotoSansBatak" style="normal" weight="400">NotoSansBatak-Regular.ttf</font> </family> <family fallback="true" pages="0,26,32,169,254"> - <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font> + <font font_name="Noto Sans Buginese" postscript_name="NotoSansBuginese" style="normal" weight="400">NotoSansBuginese-Regular.ttf</font> </family> <family fallback="true" pages="0,23,254"> - <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font> + <font font_name="Noto Sans Buhid" postscript_name="NotoSansBuhid" style="normal" weight="400">NotoSansBuhid-Regular.ttf</font> </family> <family fallback="true" pages="0-3,20-22,24,254"> - <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font> + <font font_name="Noto Sans Canadian Aboriginal" postscript_name="NotoSansCanadianAboriginal" style="normal" weight="400">NotoSansCanadianAboriginal-Regular.ttf</font> </family> <family fallback="true" pages="0,19,254"> - <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font> + <font font_name="Noto Sans Cherokee" postscript_name="NotoSansCherokee" style="normal" weight="400">NotoSansCherokee-Regular.ttf</font> </family> <family fallback="true" pages="0-3,29,44,254"> - <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font> + <font font_name="Noto Sans Coptic" postscript_name="NotoSansCoptic" style="normal" weight="400">NotoSansCoptic-Regular.ttf</font> </family> <family fallback="true" pages="0,44,254"> - <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font> + <font font_name="Noto Sans Glagolitic" postscript_name="NotoSansGlagolitic" style="normal" weight="400">NotoSansGlagolitic-Regular.ttf</font> </family> <family fallback="true" pages="0,23,254"> - <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font> + <font font_name="Noto Sans Hanunoo" postscript_name="NotoSansHanunoo" style="normal" weight="400">NotoSansHanunoo-Regular.ttf</font> </family> <family fallback="true" pages="0,32,37,169,254"> - <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font> + <font font_name="Noto Sans Javanese" postscript_name="NotoSansJavanese" style="normal" weight="400">NotoSansJavanese-Regular.ttf</font> </family> <family fallback="true" pages="0,169,254"> - <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font> + <font font_name="Noto Sans Kayah Li" postscript_name="NotoSansKayahLi" style="normal" weight="400">NotoSansKayahLi-Regular.ttf</font> </family> <family fallback="true" pages="0,28,37,254"> - <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font> + <font font_name="Noto Sans Lepcha" postscript_name="NotoSansLepcha" style="normal" weight="400">NotoSansLepcha-Regular.ttf</font> </family> <family fallback="true" pages="0,9,25,254"> - <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font> + <font font_name="Noto Sans Limbu" postscript_name="NotoSansLimbu" style="normal" weight="400">NotoSansLimbu-Regular.ttf</font> </family> <family fallback="true" pages="0,2,164,254"> - <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font> + <font font_name="Noto Sans Lisu" postscript_name="NotoSansLisu" style="normal" weight="400">NotoSansLisu-Regular.ttf</font> </family> <family fallback="true" pages="0,6,8,254"> - <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font> + <font font_name="Noto Sans Mandaic" postscript_name="NotoSansMandaic" style="normal" weight="400">NotoSansMandaic-Regular.ttf</font> </family> <family fallback="true" pages="0,170-171,254"> - <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font> + <font font_name="Noto Sans Meetei Mayek" postscript_name="NotoSansMeeteiMayek" style="normal" weight="400">NotoSansMeeteiMayek-Regular.ttf</font> </family> <family fallback="true" pages="0,25,254"> - <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font> + <font font_name="Noto Sans New Tai Lue" postscript_name="NotoSansNewTaiLue" style="normal" weight="400">NotoSansNewTaiLue-Regular.ttf</font> </family> <family fallback="true" pages="0,6-7,32,46,253-254"> - <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font> + <font font_name="Noto Sans NKo" postscript_name="NotoSansNKo" style="normal" weight="400">NotoSansNKo-Regular.ttf</font> </family> <family fallback="true" pages="0,28,254"> - <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font> + <font font_name="Noto Sans Ol Chiki" postscript_name="NotoSansOlChiki" style="normal" weight="400">NotoSansOlChiki-Regular.ttf</font> </family> <family fallback="true" pages="0,169,254"> - <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font> + <font font_name="Noto Sans Rejang" postscript_name="NotoSansRejang" style="normal" weight="400">NotoSansRejang-Regular.ttf</font> </family> <family fallback="true" pages="0,32,37,168,254"> - <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font> + <font font_name="Noto Sans Saurashtra" postscript_name="NotoSansSaurashtra" style="normal" weight="400">NotoSansSaurashtra-Regular.ttf</font> </family> <family fallback="true" pages="0,27-28,254"> - <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font> + <font font_name="Noto Sans Sundanese" postscript_name="NotoSansSundanese" style="normal" weight="400">NotoSansSundanese-Regular.ttf</font> </family> <family fallback="true" pages="0,9,32,37,168,254"> - <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font> + <font font_name="Noto Sans Syloti Nagri" postscript_name="NotoSansSylotiNagri" style="normal" weight="400">NotoSansSylotiNagri-Regular.ttf</font> </family> <family fallback="true" pages="0,3,6-7,32,34,37-38,254"> - <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font> + <font font_name="Noto Sans Syriac Estrangela" postscript_name="NotoSansSyriacEstrangela" style="normal" weight="400">NotoSansSyriacEstrangela-Regular.ttf</font> </family> <family fallback="true" pages="0,23,254"> - <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font> + <font font_name="Noto Sans Tagbanwa" postscript_name="NotoSansTagbanwa" style="normal" weight="400">NotoSansTagbanwa-Regular.ttf</font> </family> <family fallback="true" pages="0,26,32,34,37,254"> - <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font> + <font font_name="Noto Sans Tai Tham" postscript_name="NotoSansTaiTham" style="normal" weight="400">NotoSansTaiTham-Regular.ttf</font> </family> <family fallback="true" pages="0,32,37,167,170,254"> - <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font> + <font font_name="Noto Sans Tai Viet" postscript_name="NotoSansTaiViet" style="normal" weight="400">NotoSansTaiViet-Regular.ttf</font> </family> <family fallback="true" pages="0,15,32,37,254"> - <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font> + <font font_name="Noto Sans Tibetan" postscript_name="NotoSansTibetan" style="normal" weight="400">NotoSansTibetan-Regular.ttf</font> </family> <family fallback="true" pages="0,3,32,45,254"> - <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font> + <font font_name="Noto Sans Tifinagh" postscript_name="NotoSansTifinagh" style="normal" weight="400">NotoSansTifinagh-Regular.ttf</font> </family> <family fallback="true" pages="0,165-166,254"> - <font weight="400" style="normal">NotoSansVai-Regular.ttf</font> + <font font_name="Noto Sans Vai" postscript_name="NotoSansVai" style="normal" weight="400">NotoSansVai-Regular.ttf</font> </family> <family fallback="true" pages="0,160-164,254"> - <font weight="400" style="normal">NotoSansYi-Regular.ttf</font> + <font font_name="Noto Sans Yi" postscript_name="NotoSansYi" style="normal" weight="400">NotoSansYi-Regular.ttf</font> </family> <family fallback="true" pages="32-43"> - <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font> + <font font_name="Noto Sans Symbols" postscript_name="NotoSansSymbols" style="normal" weight="400">NotoSansSymbols-Regular-Subsetted.ttf</font> </family> <family fallback="true" lang="zh-Hans" pages="0,2,32-39,41,43,46-159,249-250,254-255,497-498,512-513,518,524,531-533,553,565,572,574,577,584-586,597,602,606,610,612,614-615,617,619-620,632,639,644,646-647,651-652,654,662,664,671,679-682,687,689,691-696,698-702,704-718"> - <font weight="400" style="normal">NotoSansSC-Regular.otf</font> + <font font_name="Noto Sans SC Regular" postscript_name="NotoSansSC-Regular" style="normal" weight="400">NotoSansSC-Regular.otf</font> </family> <family fallback="true" lang="zh-Hant" pages="0,32,34,46-48,50,52-159,249-250,254-255,498,512-657,660-661,663-678,685,760-761"> - <font weight="400" style="normal">NotoSansTC-Regular.otf</font> + <font font_name="Noto Sans TC Regular" postscript_name="NotoSansTC-Regular" style="normal" weight="400">NotoSansTC-Regular.otf</font> </family> <family fallback="true" lang="ja" pages="0,32,34-35,46-159,249-250,254-255,498,512-523,525-527,530-538,540-543,545-547,550,552,554-559,561,563-568,570,572-573,575-579,582-584,586-594,596-608,610-612,614-618,620,622-625,627-628,630-631,633-638,640,642-646,649-655,658,660-664,666,669-678,681,695-696,760-761"> - <font weight="400" style="normal">NotoSansJP-Regular.otf</font> + <font font_name="Noto Sans JP Regular" postscript_name="NotoSansJP-Regular" style="normal" weight="400">NotoSansJP-Regular.otf</font> </family> <family fallback="true" lang="ko" pages="0,17,32,48-50,169,172-215,255"> - <font weight="400" style="normal">NotoSansKR-Regular.otf</font> + <font font_name="Noto Sans KR Regular" postscript_name="NotoSansKR-Regular" style="normal" weight="400">NotoSansKR-Regular.otf</font> </family> <family fallback="true" pages="0,17,32,49-50,172-215"> - <font weight="400" style="normal">NanumGothic.ttf</font> + <font font_name="NanumGothic" postscript_name="NanumGothic" style="normal" weight="400">NanumGothic.ttf</font> </family> <family fallback="true" pages="0,32-33,35-39,41,43,48,50,224,254-255,496-502,4068"> - <font weight="400" style="normal">NotoEmoji-Regular.ttf</font> + <font font_name="Noto Emoji" postscript_name="NotoEmoji" style="normal" weight="400">NotoEmoji-Regular.ttf</font> </family> <family fallback="true" pages="0,14,17,32,48-51,77-159,172-215,249-250,254-255,260"> - <font weight="400" style="normal">DroidSansFallback.ttf</font> + <font font_name="Droid Sans Fallback" postscript_name="DroidSansFallback" style="normal" weight="400">DroidSansFallback.ttf</font> </family> <family fallback="true" lang="ja" pages="0,2-4,32-38,48,50-51,78-159,249-250,255"> - <font weight="400" style="normal">MTLmr3m.ttf</font> + <font font_name="MotoyaLMaru W3 mono" postscript_name="MotoyaLMaru-W3-90ms-RKSJ-H" style="normal" weight="400">MTLmr3m.ttf</font> </family> <!-- Tai Le and Mongolian are intentionally kept last, to make sure they don't override the East Asian punctuation for Chinese. --> <family fallback="true" pages="0,16,25,48,254"> - <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font> + <font font_name="Noto Sans Tai Le" postscript_name="NotoSansTaiLe" style="normal" weight="400">NotoSansTaiLe-Regular.ttf</font> </family> <family fallback="true" pages="0,24,32,36-37,48,254"> - <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font> + <font font_name="Noto Sans Mongolian" postscript_name="NotoSansMongolian" style="normal" weight="400">NotoSansMongolian-Regular.ttf</font> </family> </familyset>
diff --git a/src/cobalt/css_parser/grammar.h b/src/cobalt/css_parser/grammar.h index 6842105..2e21c88 100644 --- a/src/cobalt/css_parser/grammar.h +++ b/src/cobalt/css_parser/grammar.h
@@ -105,7 +105,7 @@ #if defined(OS_STARBOARD) #include "starboard/memory.h" -#define YYFREE SbMemoryFree +#define YYFREE SbMemoryDeallocate #define YYMALLOC SbMemoryAllocate #endif
diff --git a/src/cobalt/css_parser/grammar.y b/src/cobalt/css_parser/grammar.y index a1b62f7..2b32f70 100644 --- a/src/cobalt/css_parser/grammar.y +++ b/src/cobalt/css_parser/grammar.y
@@ -3431,15 +3431,17 @@ comma_separated_box_shadow_list: validated_box_shadow_list { - if ($1) { + scoped_refptr<cssom::PropertyValue> shadow = MakeScopedRefPtrAndRelease($1); + if (shadow) { $$ = new cssom::PropertyListValue::Builder(); - $$->push_back(MakeScopedRefPtrAndRelease($1)); + $$->push_back(shadow); } } | comma_separated_box_shadow_list comma validated_box_shadow_list { $$ = $1; - if ($$ && $3) { - $$->push_back(MakeScopedRefPtrAndRelease($3)); + scoped_refptr<cssom::PropertyValue> shadow = MakeScopedRefPtrAndRelease($3); + if ($$ && shadow) { + $$->push_back(shadow); } } ;
diff --git a/src/cobalt/css_parser/parser_test.cc b/src/cobalt/css_parser/parser_test.cc index 85fe7c4..fe7b721 100644 --- a/src/cobalt/css_parser/parser_test.cc +++ b/src/cobalt/css_parser/parser_test.cc
@@ -7975,7 +7975,7 @@ TEST_F(ParserTest, ParsesFontFaceSrcLocalString) { scoped_refptr<cssom::CSSFontFaceDeclarationData> font_face = - parser_.ParseFontFaceDeclarationList("src: local('Roboto');", + parser_.ParseFontFaceDeclarationList("src: local('Roboto Regular');", source_location_); scoped_refptr<cssom::PropertyListValue> src_list = @@ -7987,12 +7987,12 @@ dynamic_cast<cssom::LocalSrcValue*>( src_list->get_item_modulo_size(0).get()); ASSERT_TRUE(local_src); - EXPECT_EQ("Roboto", local_src->value()); + EXPECT_EQ("Roboto Regular", local_src->value()); } TEST_F(ParserTest, ParsesFontFaceSrcLocalIdentifier) { scoped_refptr<cssom::CSSFontFaceDeclarationData> font_face = - parser_.ParseFontFaceDeclarationList("src: local(Roboto);", + parser_.ParseFontFaceDeclarationList("src: local(Roboto Regular);", source_location_); scoped_refptr<cssom::PropertyListValue> src_list = @@ -8004,7 +8004,7 @@ dynamic_cast<cssom::LocalSrcValue*>( src_list->get_item_modulo_size(0).get()); ASSERT_TRUE(local_src); - EXPECT_EQ("Roboto", local_src->value()); + EXPECT_EQ("Roboto Regular", local_src->value()); } TEST_F(ParserTest, ParsesFontFaceSrcUrlWithoutFormat) {
diff --git a/src/cobalt/dom/MemoryInfo.idl b/src/cobalt/dom/MemoryInfo.idl new file mode 100644 index 0000000..4cf1920 --- /dev/null +++ b/src/cobalt/dom/MemoryInfo.idl
@@ -0,0 +1,25 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This is a non-standard interface in Chromium. +// https://docs.webplatform.org/wiki/apis/timing/properties/memory + +[ + NoInterfaceObject, +] interface MemoryInfo { + [CallWith=EnvironmentSettings] readonly attribute unsigned long totalJSHeapSize; + [CallWith=EnvironmentSettings] readonly attribute unsigned long usedJSHeapSize; +};
diff --git a/src/cobalt/dom/Performance.idl b/src/cobalt/dom/Performance.idl index 891adc3..45a0e2f 100644 --- a/src/cobalt/dom/Performance.idl +++ b/src/cobalt/dom/Performance.idl
@@ -18,4 +18,7 @@ interface Performance { readonly attribute PerformanceTiming timing; + + // Chromium custom member. + readonly attribute MemoryInfo memory; };
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp index 5438684..6087406 100644 --- a/src/cobalt/dom/dom.gyp +++ b/src/cobalt/dom/dom.gyp
@@ -175,6 +175,8 @@ 'media_query_list.h', 'media_source.cc', 'media_source.h', + 'memory_info.cc', + 'memory_info.h', 'mime_type_array.cc', 'mime_type_array.h', 'named_node_map.cc',
diff --git a/src/cobalt/dom/dom_test.gyp b/src/cobalt/dom/dom_test.gyp index a399a4e..281ac59 100644 --- a/src/cobalt/dom/dom_test.gyp +++ b/src/cobalt/dom/dom_test.gyp
@@ -41,6 +41,7 @@ 'event_test.cc', 'float32_array_test.cc', 'float64_array_test.cc', + 'font_cache_test.cc', 'html_element_factory_test.cc', 'html_element_test.cc', 'keyboard_event_test.cc', @@ -70,6 +71,7 @@ '<(DEPTH)/cobalt/dom/dom.gyp:dom', '<(DEPTH)/cobalt/dom/dom.gyp:dom_testing', '<(DEPTH)/cobalt/dom_parser/dom_parser.gyp:dom_parser', + '<(DEPTH)/cobalt/renderer/rasterizer/skia/skia/skia.gyp:skia', '<(DEPTH)/testing/gmock.gyp:gmock', '<(DEPTH)/testing/gtest.gyp:gtest', ],
diff --git a/src/cobalt/dom/font_cache.cc b/src/cobalt/dom/font_cache.cc index 0ee045c..9c9750e 100644 --- a/src/cobalt/dom/font_cache.cc +++ b/src/cobalt/dom/font_cache.cc
@@ -155,7 +155,7 @@ return TryGetRemoteFont(source_iterator->GetUrl(), size, state); } else { scoped_refptr<render_tree::Font> font = - TryGetLocalFont(source_iterator->GetName(), style, size, state); + TryGetLocalFontByFaceName(source_iterator->GetName(), size, state); if (font != NULL) { return font; } @@ -283,6 +283,7 @@ const scoped_refptr<render_tree::Typeface>& FontCache::GetCachedLocalTypeface( const scoped_refptr<render_tree::Typeface>& typeface) { + DCHECK(typeface); // Check to see if a typeface with a matching id is already in the cache. If // it is not, then add the passed in typeface to the cache. scoped_refptr<render_tree::Typeface>& cached_typeface = @@ -308,6 +309,7 @@ // completed or the timer expires. if (requested_remote_typeface_iterator == requested_remote_typeface_cache_.end()) { + DLOG(INFO) << "Requested remote font from " << url; // Create the remote typeface load event's callback. This callback occurs on // successful loads, failed loads, and when the request's timer expires. base::Closure typeface_load_event_callback = base::Bind( @@ -317,7 +319,7 @@ // the iterator from the return value of the map insertion. requested_remote_typeface_iterator = requested_remote_typeface_cache_ - .insert(std::make_pair( + .insert(RequestedRemoteTypefaceMap::value_type( url, new RequestedRemoteTypefaceInfo( cached_remote_typeface, typeface_load_event_callback))) .first; @@ -346,6 +348,7 @@ const std::string& family, render_tree::FontStyle style, float size, FontListFont::State* state) { DCHECK(resource_provider()); + DCHECK(resource_provider() != NULL); // Only request the local font from the resource provider if the family is // empty or the resource provider actually has the family. The reason for this // is that the resource provider's |GetLocalTypeface()| is guaranteed to @@ -365,6 +368,28 @@ } } +scoped_refptr<render_tree::Font> FontCache::TryGetLocalFontByFaceName( + const std::string& font_face, float size, FontListFont::State* state) { + do { + if (font_face.empty()) { + break; + } + const scoped_refptr<render_tree::Typeface>& typeface( + resource_provider()->GetLocalTypefaceByFaceNameIfAvailable(font_face)); + if (!typeface) { + break; + } + const scoped_refptr<render_tree::Typeface>& typeface_cached( + GetCachedLocalTypeface(typeface)); + + *state = FontListFont::kLoadedState; + return GetFontFromTypefaceAndSize(typeface_cached, size); + } while (false); + + *state = FontListFont::kUnavailableState; + return NULL; +} + void FontCache::OnRemoteTypefaceLoadEvent(const GURL& url) { DCHECK(thread_checker_.CalledOnValidThread()); RequestedRemoteTypefaceMap::iterator requested_remote_typeface_iterator =
diff --git a/src/cobalt/dom/font_cache.h b/src/cobalt/dom/font_cache.h index e3a574a..8e5afc5 100644 --- a/src/cobalt/dom/font_cache.h +++ b/src/cobalt/dom/font_cache.h
@@ -254,19 +254,22 @@ // the constructor and an |OnRemoteFontLoadEvent| callback provided by the // font are registered with the remote typeface cache to be called when the // load finishes. - // If the font is loading but not currently available, |maybe_is_font_loading| - // will be set to true. scoped_refptr<render_tree::Font> TryGetRemoteFont(const GURL& url, float size, FontListFont::State* state); // Returns NULL if the requested family is not empty and is not available in // the resource provider. Otherwise, returns the best matching local font. - // |maybe_is_font_loading| is always set to false. scoped_refptr<render_tree::Font> TryGetLocalFont(const std::string& family, render_tree::FontStyle style, float size, FontListFont::State* state); + // Lookup by a typeface (aka font_face), typeface is defined as font family + + // style (weight, width, and style). + // Returns NULL if the requested font face is not found. + scoped_refptr<render_tree::Font> TryGetLocalFontByFaceName( + const std::string& font_face, float size, FontListFont::State* state); + // Called when a remote typeface either successfully loads or fails to load. // In either case, the event can impact the fonts contained within the font // lists. As a result, the font lists need to have their loading fonts reset
diff --git a/src/cobalt/dom/font_cache_test.cc b/src/cobalt/dom/font_cache_test.cc new file mode 100644 index 0000000..a46b631 --- /dev/null +++ b/src/cobalt/dom/font_cache_test.cc
@@ -0,0 +1,134 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cobalt/dom/font_cache.h" + +#include "base/bind.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "cobalt/csp/content_security_policy.h" +#include "cobalt/dom/font_face.h" +#include "cobalt/loader/font/remote_typeface_cache.h" +#include "cobalt/loader/font/typeface_decoder.h" +#include "cobalt/loader/loader.h" +#include "cobalt/loader/mock_loader_factory.h" +#include "cobalt/render_tree/mock_resource_provider.h" +#include "cobalt/render_tree/resource_provider.h" +#include "cobalt/render_tree/resource_provider_stub.h" +#include "googleurl/src/gurl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cobalt { +namespace dom { + +using ::testing::_; +using ::testing::Return; + +const render_tree::FontStyle kNormalUpright( + render_tree::FontStyle::kNormalWeight, + render_tree::FontStyle::kUprightSlant); + +scoped_ptr<FontCache::FontFaceMap> CreateFontFaceMapHelper( + const std::string& family_name, const base::StringPiece local_font_name) { + scoped_ptr<FontCache::FontFaceMap> ffm(new FontCache::FontFaceMap()); + dom::FontFaceStyleSet ffss; + dom::FontFaceStyleSet::Entry entry; + entry.sources.push_back( + FontFaceSource(local_font_name.as_string())); // local() + entry.sources.push_back(FontFaceSource( + GURL("https://example.com/Dancing-Regular.woff"))); // url() + ffss.AddEntry(entry); + ffm->insert(FontCache::FontFaceMap::value_type(family_name, ffss)); + return ffm.Pass(); +} + +class FontCacheTest : public ::testing::Test { + public: + FontCacheTest(); + ~FontCacheTest() OVERRIDE {} + + void DummyOnTypefaceLoadEvent() {} + + protected: + ::testing::StrictMock<loader::MockLoaderFactory> loader_factory_; + scoped_refptr<cobalt::render_tree::Typeface> sample_typeface_; + ::testing::StrictMock<cobalt::render_tree::MockResourceProvider> + mock_resource_provider_; + cobalt::render_tree::ResourceProvider* mrp; + scoped_ptr<loader::font::RemoteTypefaceCache> rtc; + scoped_ptr<dom::FontCache> font_cache_; + + MessageLoop message_loop_; +}; + +FontCacheTest::FontCacheTest() + : sample_typeface_(new render_tree::TypefaceStub(NULL)), + mrp(dynamic_cast<cobalt::render_tree::ResourceProvider*>( + &mock_resource_provider_)), + rtc(new loader::font::RemoteTypefaceCache( + "test_cache", 32 * 1024 /* 32 KB */, + base::Bind(&loader::MockLoaderFactory::CreateTypefaceLoader, + base::Unretained(&loader_factory_)))), + font_cache_( + new dom::FontCache(&mrp, // resource_provider + rtc.get(), // remotetypefacecache + ALLOW_THIS_IN_INITIALIZER_LIST(base::Bind( + &FontCacheTest::DummyOnTypefaceLoadEvent, + base::Unretained(this))), + "en-US")) {} + +TEST_F(FontCacheTest, FindPostscriptFont) { + const std::string family_name("Dancing Script"); + const std::string postscript_font_name("DancingScript"); + scoped_ptr<FontCache::FontFaceMap> ffm = + CreateFontFaceMapHelper(family_name, postscript_font_name); + font_cache_->SetFontFaceMap(ffm.Pass()); + + EXPECT_CALL(loader_factory_, CreateTypefaceLoaderMock(_, _, _, _, _)) + .Times(0); + + EXPECT_CALL(mock_resource_provider_, + GetLocalTypefaceIfAvailableMock(postscript_font_name)) + .WillOnce(Return(sample_typeface_)); + + FontListFont::State state; + scoped_refptr<render_tree::Font> f = + font_cache_->TryGetFont(family_name, kNormalUpright, 12.0, &state); + + EXPECT_TRUE(f); +} + +TEST_F(FontCacheTest, UseRemote) { + std::string invalid_postscript_font_name = "DancingScriptInvalidName"; + const std::string family_name("Dancing Script"); + scoped_ptr<FontCache::FontFaceMap> ffm = + CreateFontFaceMapHelper(family_name, invalid_postscript_font_name); + font_cache_->SetFontFaceMap(ffm.Pass()); + + EXPECT_CALL(mock_resource_provider_, + GetLocalTypefaceIfAvailableMock(invalid_postscript_font_name)) + .Times(1); + EXPECT_CALL(loader_factory_, CreateTypefaceLoaderMock(_, _, _, _, _)); + + FontListFont::State state; + scoped_refptr<render_tree::Font> f = + font_cache_->TryGetFont(family_name, kNormalUpright, 12.0, &state); + EXPECT_FALSE(f); +} + +} // namespace dom +} // namespace cobalt
diff --git a/src/cobalt/dom/font_list.cc b/src/cobalt/dom/font_list.cc index f91dc45..69fde52 100644 --- a/src/cobalt/dom/font_list.cc +++ b/src/cobalt/dom/font_list.cc
@@ -240,6 +240,7 @@ } } } + DCHECK(primary_font_); return primary_font_; }
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc index 06e16c02..fbd71cd 100644 --- a/src/cobalt/dom/html_element.cc +++ b/src/cobalt/dom/html_element.cc
@@ -664,13 +664,13 @@ void HTMLElement::InvalidateLayoutBoxesFromNodeAndAncestors() { layout_boxes_.reset(); - cached_background_images_.clear(); + ReleaseImagesAndInvalidateComputedStyleIfNecessary(); Node::InvalidateLayoutBoxesFromNodeAndAncestors(); } void HTMLElement::InvalidateLayoutBoxesFromNodeAndDescendants() { layout_boxes_.reset(); - cached_background_images_.clear(); + ReleaseImagesAndInvalidateComputedStyleIfNecessary(); Node::InvalidateLayoutBoxesFromNodeAndDescendants(); } @@ -1083,5 +1083,12 @@ return AsHTMLHtmlElement() != NULL; } +void HTMLElement::ReleaseImagesAndInvalidateComputedStyleIfNecessary() { + if (!cached_background_images_.empty()) { + cached_background_images_.clear(); + computed_style_valid_ = false; + } +} + } // namespace dom } // namespace cobalt
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h index 2075d05..33ffb9a 100644 --- a/src/cobalt/dom/html_element.h +++ b/src/cobalt/dom/html_element.h
@@ -289,6 +289,10 @@ // https://www.w3.org/TR/html5/semantics.html#the-root-element. bool IsRootElement(); + // Releases image resources and invalidates computed style if there are images + // associated with this html element in the image cache. + void ReleaseImagesAndInvalidateComputedStyleIfNecessary(); + // The directionality of the html element is determined by the 'dir' // attribute. // https://dev.w3.org/html5/spec-preview/global-attributes.html#the-directionality
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc index e0f632c..eda59cb 100644 --- a/src/cobalt/dom/html_media_element.cc +++ b/src/cobalt/dom/html_media_element.cc
@@ -53,6 +53,33 @@ namespace { +#define LOG_MEDIA_ELEMENT_ACTIVITIES 0 + +#if LOG_MEDIA_ELEMENT_ACTIVITIES + +template <typename T> +void LogMediaElementActivity(const char* function_name, const T& t) { + LOG(INFO) << function_name << " " << t; +} + +template <typename T1, typename T2> +void LogMediaElementActivity(const char* function_name, const T1& t1, + const T2& t2) { + LOG(INFO) << function_name << " " << t1 << " " << t2; +} + +#define MLOG() LOG(INFO) << __FUNCTION__ +#define MLOG_1(x) LogMediaElementActivity(__FUNCTION__, x) +#define MLOG_2(x, y) LogMediaElementActivity(__FUNCTION__, x, y) + +#else // LOG_MEDIA_ELEMENT_ACTIVITIES + +#define MLOG() do {} while (false) +#define MLOG_1(x) do {} while (false) +#define MLOG_2(x, y) do {} while (false) + +#endif // LOG_MEDIA_ELEMENT_ACTIVITIES + void RaiseMediaKeyException(WebMediaPlayer::MediaKeyException exception, script::ExceptionState* exception_state) { DCHECK_NE(exception, WebMediaPlayer::kMediaKeyExceptionNoError); @@ -119,25 +146,35 @@ pending_load_(false), sent_stalled_event_(false), sent_end_event_(false) { + MLOG(); html_media_element_count_log.Get().count++; } HTMLMediaElement::~HTMLMediaElement() { + MLOG(); SetSourceState(MediaSource::kReadyStateClosed); html_media_element_count_log.Get().count--; } +scoped_refptr<MediaError> HTMLMediaElement::error() const { + MLOG_1(error_->code()); + return error_; +} + std::string HTMLMediaElement::src() const { + MLOG_1(GetAttribute("src").value_or("")); return GetAttribute("src").value_or(""); } void HTMLMediaElement::set_src(const std::string& src) { + MLOG_1(src); SetAttribute("src", src); ClearMediaPlayer(); ScheduleLoad(); } uint16_t HTMLMediaElement::network_state() const { + MLOG_1(network_state_); return static_cast<uint16_t>(network_state_); } @@ -145,13 +182,17 @@ scoped_refptr<TimeRanges> buffered = new TimeRanges; if (!player_) { + MLOG_1("empty"); return buffered; } const ::media::Ranges<base::TimeDelta>& player_buffered = player_->GetBufferedTimeRanges(); + MLOG_1("================================"); for (int i = 0; i < static_cast<int>(player_buffered.size()); ++i) { + MLOG_2(player_buffered.start(i).InSecondsF(), + player_buffered.end(i).InSecondsF()); buffered->Add(player_buffered.start(i).InSecondsF(), player_buffered.end(i).InSecondsF()); } @@ -177,6 +218,7 @@ std::string result = html_element_context()->can_play_type_handler()->CanPlayType(mime_type, key_system); + MLOG_2(mime_type + ',' + key_system, result); DLOG(INFO) << "HTMLMediaElement::canPlayType(" << mime_type << ", " << key_system << ") -> " << result; return result; @@ -186,15 +228,18 @@ const std::string& key_system, const base::optional<scoped_refptr<Uint8Array> >& init_data, script::ExceptionState* exception_state) { + MLOG_1(key_system); // https://dvcs.w3.org/hg/html-media/raw-file/eme-v0.1b/encrypted-media/encrypted-media.html#dom-generatekeyrequest // 1. If the first argument is null, throw a SYNTAX_ERR. if (key_system.empty()) { + MLOG_1("syntax error"); DOMException::Raise(DOMException::kSyntaxErr, exception_state); return; } // 2. If networkState is NETWORK_EMPTY, throw an INVALID_STATE_ERR. if (network_state_ == kNetworkEmpty || !player_) { + MLOG_1("invalid state error"); DOMException::Raise(DOMException::kInvalidStateErr, exception_state); return; } @@ -211,6 +256,7 @@ } if (exception != WebMediaPlayer::kMediaKeyExceptionNoError) { + MLOG_2("exception:", exception); RaiseMediaKeyException(exception, exception_state); } } @@ -220,21 +266,25 @@ const base::optional<scoped_refptr<Uint8Array> >& init_data, const base::optional<std::string>& session_id, script::ExceptionState* exception_state) { + MLOG_1(key_system); // https://dvcs.w3.org/hg/html-media/raw-file/eme-v0.1b/encrypted-media/encrypted-media.html#dom-addkey // 1. If the first or second argument is null, throw a SYNTAX_ERR. if (key_system.empty() || !key) { + MLOG_1("syntax error"); DOMException::Raise(DOMException::kSyntaxErr, exception_state); return; } // 2. If the second argument is an empty array, throw a TYPE_MISMATCH_ERR. if (!key->length()) { + MLOG_1("type mismatch error"); DOMException::Raise(DOMException::kTypeMismatchErr, exception_state); return; } // 3. If networkState is NETWORK_EMPTY, throw an INVALID_STATE_ERR. if (network_state_ == kNetworkEmpty || !player_) { + MLOG_1("invalid state error"); DOMException::Raise(DOMException::kInvalidStateErr, exception_state); return; } @@ -253,6 +303,7 @@ } if (exception != WebMediaPlayer::kMediaKeyExceptionNoError) { + MLOG_2("exception:", exception); RaiseMediaKeyException(exception, exception_state); } } @@ -264,11 +315,13 @@ // https://dvcs.w3.org/hg/html-media/raw-file/eme-v0.1b/encrypted-media/encrypted-media.html#dom-addkey // 1. If the first argument is null, throw a SYNTAX_ERR. if (key_system.empty()) { + MLOG_1("syntax error"); DOMException::Raise(DOMException::kSyntaxErr, exception_state); return; } if (!player_) { + MLOG_1("invalid state error"); DOMException::Raise(DOMException::kInvalidStateErr, exception_state); return; } @@ -277,28 +330,36 @@ WebMediaPlayer::MediaKeyException exception = player_->CancelKeyRequest(key_system, session_id.value_or("")); if (exception != WebMediaPlayer::kMediaKeyExceptionNoError) { + MLOG_2("exception:", exception); RaiseMediaKeyException(exception, exception_state); } } WebMediaPlayer::ReadyState HTMLMediaElement::ready_state() const { + MLOG_1(ready_state_); return ready_state_; } -bool HTMLMediaElement::seeking() const { return seeking_; } +bool HTMLMediaElement::seeking() const { + MLOG_1(seeking_); + return seeking_; +} float HTMLMediaElement::current_time( script::ExceptionState* exception_state) const { UNREFERENCED_PARAMETER(exception_state); if (!player_) { + MLOG_2("player is NULL", 0); return 0; } if (seeking_) { + MLOG_2("seeking", last_seek_time_); return last_seek_time_; } + MLOG_2("player time", player_->GetCurrentTime()); return player_->GetCurrentTime(); } @@ -310,36 +371,49 @@ // WebMediaPlayer::kReadyStateHaveNothing, then raise an INVALID_STATE_ERR // exception. if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing || !player_) { + MLOG_1("invalid state error"); DOMException::Raise(DOMException::kInvalidStateErr, exception_state); return; } + MLOG_2("seek to", time); Seek(time); } float HTMLMediaElement::duration() const { if (player_ && ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata) { + MLOG_2("player duration", player_->GetDuration()); return player_->GetDuration(); } + MLOG_1("NaN"); return std::numeric_limits<float>::quiet_NaN(); } -bool HTMLMediaElement::paused() const { return paused_; } +bool HTMLMediaElement::paused() const { + MLOG_1(paused_); + return paused_; +} float HTMLMediaElement::default_playback_rate() const { + MLOG_1(default_playback_rate_); return default_playback_rate_; } void HTMLMediaElement::set_default_playback_rate(float rate) { + MLOG_1(rate); if (default_playback_rate_ != rate) { default_playback_rate_ = rate; ScheduleEvent(base::Tokens::ratechange()); } } -float HTMLMediaElement::playback_rate() const { return playback_rate_; } +float HTMLMediaElement::playback_rate() const { + MLOG_1(playback_rate_); + return playback_rate_; +} void HTMLMediaElement::set_playback_rate(float rate) { + MLOG_1(rate); if (playback_rate_ != rate) { playback_rate_ = rate; ScheduleEvent(base::Tokens::ratechange()); @@ -351,6 +425,7 @@ } const scoped_refptr<TimeRanges>& HTMLMediaElement::played() { + MLOG(); if (playing_) { float time = current_time(NULL); if (time > last_seek_time_) { @@ -367,8 +442,10 @@ scoped_refptr<TimeRanges> HTMLMediaElement::seekable() const { if (player_ && player_->GetMaxTimeSeekable() != 0) { + MLOG_2(0, player_->GetMaxTimeSeekable()); return new TimeRanges(0, player_->GetMaxTimeSeekable()); } + MLOG_1("empty"); return new TimeRanges; } @@ -376,12 +453,17 @@ // 4.8.10.8 Playing the media resource // The ended attribute must return true if the media element has ended // playback and the direction of playback is forwards, and false otherwise. + MLOG_1(EndedPlayback() && playback_rate_ > 0); return EndedPlayback() && playback_rate_ > 0; } -bool HTMLMediaElement::autoplay() const { return HasAttribute("autoplay"); } +bool HTMLMediaElement::autoplay() const { + MLOG_1(HasAttribute("autoplay")); + return HasAttribute("autoplay"); +} void HTMLMediaElement::set_autoplay(bool autoplay) { + MLOG_1(autoplay); // The value of 'autoplay' is true when the 'autoplay' attribute is present. // The value of the attribute is irrelevant. if (autoplay) { @@ -391,11 +473,18 @@ } } -bool HTMLMediaElement::loop() const { return loop_; } +bool HTMLMediaElement::loop() const { + MLOG_1(loop_); + return loop_; +} -void HTMLMediaElement::set_loop(bool loop) { loop_ = loop; } +void HTMLMediaElement::set_loop(bool loop) { + MLOG_1(loop); + loop_ = loop; +} void HTMLMediaElement::Play() { + MLOG(); // 4.8.10.9. Playing the media resource if (!player_ || network_state_ == kNetworkEmpty) { ScheduleLoad(); @@ -421,6 +510,7 @@ } void HTMLMediaElement::Pause() { + MLOG(); // 4.8.10.9. Playing the media resource if (!player_ || network_state_ == kNetworkEmpty) { ScheduleLoad(); @@ -437,36 +527,45 @@ UpdatePlayState(); } -bool HTMLMediaElement::controls() const { return controls_; } +bool HTMLMediaElement::controls() const { + MLOG_1(controls_); + return controls_; +} void HTMLMediaElement::set_controls(bool controls) { + MLOG_1(controls); controls_ = controls; ConfigureMediaControls(); } float HTMLMediaElement::volume(script::ExceptionState* exception_state) const { UNREFERENCED_PARAMETER(exception_state); - + MLOG_1(volume_); return volume_; } -void HTMLMediaElement::set_volume(float vol, +void HTMLMediaElement::set_volume(float volume, script::ExceptionState* exception_state) { - if (vol < 0.0f || vol > 1.0f) { + MLOG_1(volume); + if (volume < 0.0f || volume > 1.0f) { DOMException::Raise(DOMException::kIndexSizeErr, exception_state); return; } - if (volume_ != vol) { - volume_ = vol; + if (volume_ != volume) { + volume_ = volume; UpdateVolume(); ScheduleEvent(base::Tokens::volumechange()); } } -bool HTMLMediaElement::muted() const { return muted_; } +bool HTMLMediaElement::muted() const { + MLOG_1(muted_); + return muted_; +} void HTMLMediaElement::set_muted(bool muted) { + MLOG_1(muted); if (muted_ != muted) { muted_ = muted; // Avoid recursion when the player reports volume changes. @@ -489,6 +588,7 @@ } void HTMLMediaElement::CreateMediaPlayer() { + MLOG(); if (src().empty()) { reduced_image_cache_capacity_request_ = base::nullopt; } else if (html_element_context() @@ -726,6 +826,7 @@ } void HTMLMediaElement::ClearMediaPlayer() { + MLOG(); SetSourceState(MediaSource::kReadyStateClosed); player_.reset(NULL); @@ -744,6 +845,7 @@ } void HTMLMediaElement::NoneSupported() { + MLOG(); StopPeriodicTimers(); load_state_ = kWaitingForSource; @@ -874,6 +976,7 @@ } void HTMLMediaElement::ScheduleEvent(base::Token event_name) { + MLOG_1(event_name); scoped_refptr<Event> event = new Event(event_name, Event::kNotBubbles, Event::kCancelable); event->set_target(this); @@ -1227,6 +1330,7 @@ } void HTMLMediaElement::MediaEngineError(scoped_refptr<MediaError> error) { + MLOG_1(error->code()); DLOG(WARNING) << "HTMLMediaElement::MediaEngineError " << error->code(); // 1 - The user agent should cancel the fetching process. @@ -1370,6 +1474,7 @@ void HTMLMediaElement::KeyAdded(const std::string& key_system, const std::string& session_id) { + MLOG_1(key_system); event_queue_.Enqueue(new MediaKeyCompleteEvent(key_system, session_id)); } @@ -1377,6 +1482,7 @@ const std::string& session_id, MediaKeyErrorCode error_code, uint16 system_code) { + MLOG_1(key_system); MediaKeyError::Code code; switch (error_code) { case kUnknownError: @@ -1411,6 +1517,7 @@ const unsigned char* message, unsigned int message_length, const std::string& default_url) { + MLOG_1(key_system); event_queue_.Enqueue(new MediaKeyMessageEvent( key_system, session_id, new Uint8Array(NULL, message, message_length, NULL), default_url)); @@ -1420,12 +1527,14 @@ const std::string& session_id, const unsigned char* init_data, unsigned int init_data_length) { + MLOG_1(key_system); event_queue_.Enqueue(new MediaKeyNeededEvent( key_system, session_id, new Uint8Array(NULL, init_data, init_data_length, NULL))); } void HTMLMediaElement::SetSourceState(MediaSource::ReadyState ready_state) { + MLOG_1(ready_state); if (!media_source_) { return; }
diff --git a/src/cobalt/dom/html_media_element.h b/src/cobalt/dom/html_media_element.h index 7bd360e..1d9dfc2 100644 --- a/src/cobalt/dom/html_media_element.h +++ b/src/cobalt/dom/html_media_element.h
@@ -53,7 +53,7 @@ // Web API: HTMLMediaElement // // Error state - scoped_refptr<MediaError> error() const { return error_; } + scoped_refptr<MediaError> error() const; // Network state std::string src() const;
diff --git a/src/cobalt/dom/memory_info.cc b/src/cobalt/dom/memory_info.cc new file mode 100644 index 0000000..75c99f8 --- /dev/null +++ b/src/cobalt/dom/memory_info.cc
@@ -0,0 +1,45 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cobalt/dom/memory_info.h" + +#include "cobalt/base/polymorphic_downcast.h" +#include "cobalt/dom/dom_settings.h" +#include "cobalt/script/javascript_engine.h" + +namespace cobalt { +namespace dom { + +uint32 MemoryInfo::total_js_heap_size( + script::EnvironmentSettings* settings) const { + DOMSettings* dom_settings = + base::polymorphic_downcast<dom::DOMSettings*>(settings); + size_t total_memory = + dom_settings->javascript_engine()->UpdateMemoryStatsAndReturnReserved(); + return static_cast<uint32>(total_memory); +} + +uint32 MemoryInfo::used_js_heap_size( + script::EnvironmentSettings* settings) const { + DOMSettings* dom_settings = + base::polymorphic_downcast<dom::DOMSettings*>(settings); + size_t total_memory = + dom_settings->javascript_engine()->UpdateMemoryStatsAndReturnReserved(); + return static_cast<uint32>(total_memory); +} + +} // namespace dom +} // namespace cobalt
diff --git a/src/cobalt/dom/memory_info.h b/src/cobalt/dom/memory_info.h new file mode 100644 index 0000000..dad9d79 --- /dev/null +++ b/src/cobalt/dom/memory_info.h
@@ -0,0 +1,48 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COBALT_DOM_MEMORY_INFO_H_ +#define COBALT_DOM_MEMORY_INFO_H_ + +#include "cobalt/script/environment_settings.h" +#include "cobalt/script/wrappable.h" + +namespace cobalt { +namespace dom { + +// This interface contains information related to JS memory usage. +// This is a non-standard interface in Chromium. +// https://docs.webplatform.org/wiki/apis/timing/properties/memory +class MemoryInfo : public script::Wrappable { + public: + MemoryInfo() {} + + uint32 total_js_heap_size(script::EnvironmentSettings* settings) const; + + uint32 used_js_heap_size(script::EnvironmentSettings* settings) const; + + DEFINE_WRAPPABLE_TYPE(MemoryInfo); + + private: + ~MemoryInfo() OVERRIDE {} + + DISALLOW_COPY_AND_ASSIGN(MemoryInfo); +}; + +} // namespace dom +} // namespace cobalt + +#endif // COBALT_DOM_MEMORY_INFO_H_
diff --git a/src/cobalt/dom/performance.cc b/src/cobalt/dom/performance.cc index a2a9482..519c47c 100644 --- a/src/cobalt/dom/performance.cc +++ b/src/cobalt/dom/performance.cc
@@ -17,12 +17,13 @@ #include "cobalt/dom/performance.h" #include "base/time.h" +#include "cobalt/dom/memory_info.h" namespace cobalt { namespace dom { Performance::Performance(const scoped_refptr<base::Clock>& clock) - : timing_(new PerformanceTiming(clock)) {} + : timing_(new PerformanceTiming(clock)), memory_(new MemoryInfo()) {} double Performance::Now() const { return timing_->GetNavigationStartClock()->Now().InMillisecondsF(); @@ -32,5 +33,7 @@ scoped_refptr<PerformanceTiming> Performance::timing() const { return timing_; } +scoped_refptr<MemoryInfo> Performance::memory() const { return memory_; } + } // namespace dom } // namespace cobalt
diff --git a/src/cobalt/dom/performance.h b/src/cobalt/dom/performance.h index cb2f0dd..5a382d1 100644 --- a/src/cobalt/dom/performance.h +++ b/src/cobalt/dom/performance.h
@@ -17,13 +17,15 @@ #ifndef COBALT_DOM_PERFORMANCE_H_ #define COBALT_DOM_PERFORMANCE_H_ -#include "cobalt/script/wrappable.h" #include "cobalt/base/clock.h" #include "cobalt/dom/performance_timing.h" +#include "cobalt/script/wrappable.h" namespace cobalt { namespace dom { +class MemoryInfo; + // Implements the Performance IDL interface, an instance of which is created // and owned by the Window object. // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#sec-window.performance-attribute @@ -31,17 +33,21 @@ public: explicit Performance(const scoped_refptr<base::Clock>& clock); + // Web API: Performance + scoped_refptr<PerformanceTiming> timing() const; + scoped_refptr<MemoryInfo> memory() const; + + // Custom, not in any spec. // Returns the time since timing()->navigation_start(), in milliseconds. double Now() const; - scoped_refptr<PerformanceTiming> timing() const; - DEFINE_WRAPPABLE_TYPE(Performance); private: ~Performance() OVERRIDE; scoped_refptr<PerformanceTiming> timing_; + scoped_refptr<MemoryInfo> memory_; DISALLOW_COPY_AND_ASSIGN(Performance); };
diff --git a/src/cobalt/dom/url_utils.cc b/src/cobalt/dom/url_utils.cc index a31a07f..0ff0097 100644 --- a/src/cobalt/dom/url_utils.cc +++ b/src/cobalt/dom/url_utils.cc
@@ -89,9 +89,15 @@ return url_.has_ref() ? "#" + url_.ref() : ""; } +// Algorithm for set_hash: +// https://www.w3.org/TR/2014/WD-url-1-20141209/#dom-urlutils-hash void URLUtils::set_hash(const std::string& hash) { + // 3. Let input be the given value with a single leading "#" removed, if any. + std::string hash_value = + !hash.empty() && hash[0] == '#' ? hash.substr(1) : hash; + GURL::Replacements replacements; - replacements.SetRefStr(hash); + replacements.SetRefStr(hash_value); GURL new_url = url_.ReplaceComponents(replacements); RunPreUpdateSteps(new_url, ""); } @@ -100,9 +106,15 @@ return url_.has_query() ? "?" + url_.query() : ""; } +// Algorithm for set_search: +// https://www.w3.org/TR/2014/WD-url-1-20141209/#dom-urlutils-search void URLUtils::set_search(const std::string& search) { + // 3. Let input be the given value with a single leading "?" removed, if any. + std::string search_value = + !search.empty() && search[0] == '?' ? search.substr(1) : search; + GURL::Replacements replacements; - replacements.SetQueryStr(search); + replacements.SetQueryStr(search_value); GURL new_url = url_.ReplaceComponents(replacements); RunPreUpdateSteps(new_url, ""); } @@ -111,6 +123,8 @@ // https://www.w3.org/TR/2014/WD-url-1-20141209/#pre-update-steps void URLUtils::RunPreUpdateSteps(const GURL& new_url, const std::string& value) { + DLOG(INFO) << "Update URL to " << new_url.spec(); + // 1. If value is not given, let value be the result of serializing the // associated url. // 2, Run the update steps with value.
diff --git a/src/cobalt/dom/url_utils_test.cc b/src/cobalt/dom/url_utils_test.cc index 133b8b9..29c4721 100644 --- a/src/cobalt/dom/url_utils_test.cc +++ b/src/cobalt/dom/url_utils_test.cc
@@ -92,6 +92,11 @@ EXPECT_TRUE(url_utils.url().is_valid()); EXPECT_EQ("https://user:pass@google.com:99/foo;bar?q=a#hash", url_utils.href()); + + url_utils.set_hash("#hash2"); + EXPECT_TRUE(url_utils.url().is_valid()); + EXPECT_EQ("https://user:pass@google.com:99/foo;bar?q=a#hash2", + url_utils.href()); } TEST(URLUtilsTest, SetSearchShouldWorkAsExpected) { @@ -100,6 +105,11 @@ EXPECT_TRUE(url_utils.url().is_valid()); EXPECT_EQ("https://user:pass@google.com:99/foo;bar?b=c#ref", url_utils.href()); + + url_utils.set_search("?d=e"); + EXPECT_TRUE(url_utils.url().is_valid()); + EXPECT_EQ("https://user:pass@google.com:99/foo;bar?d=e#ref", + url_utils.href()); } } // namespace dom
diff --git a/src/cobalt/h5vcc/H5vccSystem.idl b/src/cobalt/h5vcc/H5vccSystem.idl index 25bbe3b..abf2017 100644 --- a/src/cobalt/h5vcc/H5vccSystem.idl +++ b/src/cobalt/h5vcc/H5vccSystem.idl
@@ -20,6 +20,7 @@ readonly attribute DOMString platform; readonly attribute DOMString region; readonly attribute DOMString version; + attribute boolean recordStats; boolean triggerHelp(); DOMString getVideoContainerSizeOverride(); };
diff --git a/src/cobalt/h5vcc/h5vcc.cc b/src/cobalt/h5vcc/h5vcc.cc index 9792fcb..16cb6c9 100644 --- a/src/cobalt/h5vcc/h5vcc.cc +++ b/src/cobalt/h5vcc/h5vcc.cc
@@ -27,7 +27,7 @@ new H5vccRuntime(settings.event_dispatcher, settings.initial_deep_link); settings_ = new H5vccSettings(settings.media_module); storage_ = new H5vccStorage(settings.network_module); - system_ = new H5vccSystem(); + system_ = new H5vccSystem(settings.on_set_record_stats); } } // namespace h5vcc
diff --git a/src/cobalt/h5vcc/h5vcc.h b/src/cobalt/h5vcc/h5vcc.h index 369cad3..8f46d2f 100644 --- a/src/cobalt/h5vcc/h5vcc.h +++ b/src/cobalt/h5vcc/h5vcc.h
@@ -45,6 +45,7 @@ account::AccountManager* account_manager; base::EventDispatcher* event_dispatcher; std::string initial_deep_link; + base::Callback<void(bool)> on_set_record_stats; }; explicit H5vcc(const Settings& config);
diff --git a/src/cobalt/h5vcc/h5vcc_system.cc b/src/cobalt/h5vcc/h5vcc_system.cc index 3bf8cf3..5b668cd 100644 --- a/src/cobalt/h5vcc/h5vcc_system.cc +++ b/src/cobalt/h5vcc/h5vcc_system.cc
@@ -24,7 +24,9 @@ namespace cobalt { namespace h5vcc { -H5vccSystem::H5vccSystem() {} +H5vccSystem::H5vccSystem(const base::Callback<void(bool)>& on_set_record_stats) + : on_set_record_stats_(on_set_record_stats) { +} bool H5vccSystem::are_keys_reversed() const { return deprecated::PlatformDelegate::Get()->AreKeysReversed();
diff --git a/src/cobalt/h5vcc/h5vcc_system.h b/src/cobalt/h5vcc/h5vcc_system.h index be0db79..3ce8764 100644 --- a/src/cobalt/h5vcc/h5vcc_system.h +++ b/src/cobalt/h5vcc/h5vcc_system.h
@@ -26,13 +26,21 @@ class H5vccSystem : public script::Wrappable { public: - H5vccSystem(); + explicit H5vccSystem(const base::Callback<void(bool)>& on_set_record_stats); bool are_keys_reversed() const; std::string build_id() const; std::string platform() const; std::string region() const; std::string version() const; + bool record_stats() const { + return record_stats_; + } + void set_record_stats(bool record_stats) { + record_stats_ = record_stats; + + on_set_record_stats_.Run(record_stats); + } bool TriggerHelp() const; std::string GetVideoContainerSizeOverride() const; @@ -40,6 +48,8 @@ DEFINE_WRAPPABLE_TYPE(H5vccSystem); private: + base::Callback<void(bool)> on_set_record_stats_; + bool record_stats_; DISALLOW_COPY_AND_ASSIGN(H5vccSystem); };
diff --git a/src/cobalt/layout/container_box.cc b/src/cobalt/layout/container_box.cc index 1d55190..a2c79bb 100644 --- a/src/cobalt/layout/container_box.cc +++ b/src/cobalt/layout/container_box.cc
@@ -400,7 +400,7 @@ Vector2dLayoutUnit GetOffsetFromContainingBlockToStackingContext( Box* child_box) { - DCHECK(child_box->IsPositioned()); + DCHECK(child_box->IsPositioned() || child_box->IsTransformed()); Vector2dLayoutUnit relative_position; for (Box *containing_block = child_box->GetContainingBlock(), @@ -454,7 +454,7 @@ if (!current_box) { // Positioned elements may have their containing block farther // up the hierarchy than the stacking context, so handle this case here. - DCHECK(child_box->IsPositioned()); + DCHECK(child_box->IsPositioned() || child_box->IsTransformed()); return -GetOffsetFromContainingBlockToStackingContext(child_box); } #if !defined(NDEBUG)
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-2-font-face-font-family-hides-system-font-family.html b/src/cobalt/layout_tests/testdata/css3-fonts/4-2-font-face-font-family-hides-system-font-family.html index ce75b15..d50693a 100644 --- a/src/cobalt/layout_tests/testdata/css3-fonts/4-2-font-face-font-family-hides-system-font-family.html +++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-2-font-face-font-family-hides-system-font-family.html
@@ -34,11 +34,12 @@ } @font-face { font-family: Roboto; - src: local(cursive); + src: local(DancingScript); /* Try using a Postscript name of a typeface. + */ } @font-face { font-family: serif; - src: local(casual); + src: local(Coming Soon); /* Try using a Full Name of a typeface. */ } </style> </head>
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-first-available-local-font-face.html b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-first-available-local-font-face.html index 18b941d..0d87b10 100644 --- a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-first-available-local-font-face.html +++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-first-available-local-font-face.html
@@ -37,25 +37,25 @@ } @font-face { font-family: font-face-1; - src: local(cursive); + src: local(DancingScript); /* Lookup using font's postscript name. */ } @font-face { font-family: font-face-2; src: local(invalid1), - local(casual); + local(Coming Soon); /* Lookup using font's full name. */ } @font-face { font-family: font-face-3; src: local(invalid1), local(invalid2), - local(sans-serif-smallcaps); + local(CarroisGothicSC-Regular); } @font-face { font-family: font-face-4; src: local(invalid1), - local(cursive), + local(DancingScript), /* Looking using font's postscript name. */ local(invalid2), - local(casual), + local(Coming Soon), /* Lookup using font's full name. */ local(invalid3); } </style>
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-next-font-family-if-font-face-sources-unavailable.html b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-next-font-family-if-font-face-sources-unavailable.html index 593ccdf..fe1ac19 100644 --- a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-next-font-family-if-font-face-sources-unavailable.html +++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-next-font-family-if-font-face-sources-unavailable.html
@@ -39,12 +39,12 @@ } @font-face { font-family: font-face-1; - src: local(cursive); + src: local(DancingScript); /* Lookup using font's postscript name. */ } @font-face { font-family: font-face-2; src: local(invalid1), - local(casual); + local(Coming Soon); /* Lookup using font's full name. */ } @font-face { font-family: font-face-3; @@ -55,9 +55,9 @@ @font-face { font-family: font-face-4; src: local(invalid1), - local(cursive), + local(DancingScript), /* Lookup using font's postscript name. */ local(invalid2), - local(casual), + local(Coming Soon), /* Lookup using font's full name. */ local(invalid3); } </style>
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set-expected.png index 0e42727..e894c76 100644 --- a/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set-expected.png +++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set-expected.png Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set.html b/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set.html index 74a3b50..b9bd6d1 100644 --- a/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set.html +++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set.html
@@ -67,29 +67,29 @@ } @font-face { font-family: font-face-1; - src: local(Roboto); + src: local(Roboto-Regular); } @font-face { font-family: font-face-2; - src: local(cursive); + src: local(DancingScript); font-weight: normal; font-style: normal; } @font-face { font-family: font-face-2; - src: local(casual); + src: local(Coming Soon); font-weight: normal; font-style: italic; } @font-face { font-family: font-face-2; - src: local(sans-serif-smallcaps); + src: local(CarroisGothicSC-Regular); font-weight: bold; font-style: normal; } @font-face { font-family: font-face-2; - src: local(monospace); + src: local(Droid Sans Mono); font-weight: bold; font-style: italic; } @@ -98,9 +98,13 @@ <body> <div class="containing-block"> <div class="font-face-1-normal-normal">The Hegemony Consul</div> + <!-- Note: font-face-1 selects a local font file, which only has an regular + style. So, for the next three cases, a normal style is rendered. + --> <div class="font-face-1-normal-italic">The Hegemony Consul</div> <div class="font-face-1-bold-normal">The Hegemony Consul</div> <div class="font-face-1-bold-italic">The Hegemony Consul</div> + <div class="font-face-2-normal-normal">The Hegemony Consul</div> <div class="font-face-2-normal-italic">The Hegemony Consul</div> <div class="font-face-2-bold-normal">The Hegemony Consul</div>
diff --git a/src/cobalt/loader/mock_loader_factory.h b/src/cobalt/loader/mock_loader_factory.h new file mode 100644 index 0000000..b5314d6 --- /dev/null +++ b/src/cobalt/loader/mock_loader_factory.h
@@ -0,0 +1,82 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COBALT_LOADER_MOCK_LOADER_FACTORY_H_ +#define COBALT_LOADER_MOCK_LOADER_FACTORY_H_ + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +#include "base/memory/scoped_ptr.h" +#include "cobalt/csp/content_security_policy.h" +#include "cobalt/loader/font/typeface_decoder.h" +#include "cobalt/loader/image/image_decoder.h" +#include "cobalt/loader/loader.h" +#include "cobalt/loader/loader_factory.h" +#include "googleurl/src/gurl.h" + +namespace cobalt { +namespace loader { + +class MockLoaderFactory { + public: + MOCK_METHOD5(CreateImageLoaderMock, + loader::Loader*( + const GURL& url, + const csp::SecurityCallback& url_security_callback, + const image::ImageDecoder::SuccessCallback& success_callback, + const image::ImageDecoder::FailureCallback& failure_callback, + const image::ImageDecoder::ErrorCallback& error_callback)); + + MOCK_METHOD5( + CreateTypefaceLoaderMock, + loader::Loader*( + const GURL& url, const csp::SecurityCallback& url_security_callback, + const font::TypefaceDecoder::SuccessCallback& success_callback, + const font::TypefaceDecoder::FailureCallback& failure_callback, + const font::TypefaceDecoder::ErrorCallback& error_callback)); + + // This workaround is required since scoped_ptr has no copy constructor. + // see: + // https://groups.google.com/a/chromium.org/forum/#!msg/chromium-dev/01sDxsJ1OYw/I_S0xCBRF2oJ + scoped_ptr<Loader> CreateImageLoader( + const GURL& url, const csp::SecurityCallback& url_security_callback, + const image::ImageDecoder::SuccessCallback& success_callback, + const image::ImageDecoder::FailureCallback& failure_callback, + const image::ImageDecoder::ErrorCallback& error_callback) { + return scoped_ptr<Loader>( + CreateImageLoaderMock(url, url_security_callback, success_callback, + failure_callback, error_callback)); + } + + scoped_ptr<Loader> CreateTypefaceLoader( + const GURL& url, const csp::SecurityCallback& url_security_callback, + const font::TypefaceDecoder::SuccessCallback& success_callback, + const font::TypefaceDecoder::FailureCallback& failure_callback, + const font::TypefaceDecoder::ErrorCallback& error_callback) { + return scoped_ptr<Loader>( + CreateTypefaceLoaderMock(url, url_security_callback, success_callback, + failure_callback, error_callback)); + } + + MOCK_METHOD0(Suspend, void()); + MOCK_METHOD1(Resume, void(render_tree::ResourceProvider* resource_provider)); +}; + +} // namespace loader +} // namespace cobalt + +#endif // COBALT_LOADER_MOCK_LOADER_FACTORY_H_
diff --git a/src/cobalt/media/media.gyp b/src/cobalt/media/media.gyp index 0713216..70c6929 100644 --- a/src/cobalt/media/media.gyp +++ b/src/cobalt/media/media.gyp
@@ -24,6 +24,7 @@ 'can_play_type_handler.h', 'fetcher_buffered_data_source.cc', 'fetcher_buffered_data_source.h', + 'media_module.cc', 'media_module.h', 'media_module_stub.cc', 'media_module_stub.h',
diff --git a/src/cobalt/media/media_module.cc b/src/cobalt/media/media_module.cc new file mode 100644 index 0000000..945a8d2 --- /dev/null +++ b/src/cobalt/media/media_module.cc
@@ -0,0 +1,134 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cobalt/media/media_module.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/synchronization/waitable_event.h" + +namespace cobalt { +namespace media { + +namespace { + +void RunClosureAndSignal(const base::Closure& closure, + base::WaitableEvent* event) { + closure.Run(); + event->Signal(); +} + +void RunClosureOnMessageLoopAndWait( + const scoped_refptr<base::MessageLoopProxy>& message_loop, + const base::Closure& closure) { + base::WaitableEvent waitable_event(true, /* manual_reset */ + false /* initially_signaled */); + message_loop->PostTask( + FROM_HERE, base::Bind(&RunClosureAndSignal, closure, &waitable_event)); + waitable_event.Wait(); +} + +} // namespace + +void MediaModule::Suspend() { + RunClosureOnMessageLoopAndWait( + message_loop_, + base::Bind(&MediaModule::SuspendTask, base::Unretained(this))); +} + +void MediaModule::Resume() { + RunClosureOnMessageLoopAndWait( + message_loop_, + base::Bind(&MediaModule::ResumeTask, base::Unretained(this))); +} + +void MediaModule::RegisterPlayer(WebMediaPlayer* player) { + RunClosureOnMessageLoopAndWait(message_loop_, + base::Bind(&MediaModule::RegisterPlayerTask, + base::Unretained(this), player)); +} + +void MediaModule::UnregisterPlayer(WebMediaPlayer* player) { + RunClosureOnMessageLoopAndWait(message_loop_, + base::Bind(&MediaModule::UnregisterPlayerTask, + base::Unretained(this), player)); +} + +void MediaModule::RegisterDebugState(WebMediaPlayer* player) { + void* debug_state_address = NULL; + size_t debug_state_size = 0; + if (player->GetDebugReportDataAddress(&debug_state_address, + &debug_state_size)) { + base::UserLog::Register(base::UserLog::kWebMediaPlayerState, + "MediaPlyrState", debug_state_address, + debug_state_size); + } +} + +void MediaModule::DeregisterDebugState() { + base::UserLog::Deregister(base::UserLog::kWebMediaPlayerState); +} + +void MediaModule::SuspendTask() { + DCHECK(message_loop_->BelongsToCurrentThread()); + + for (Players::iterator iter = players_.begin(); iter != players_.end(); + ++iter) { + DCHECK(!iter->second); + if (!iter->second) { + iter->first->Suspend(); + } + } +} + +void MediaModule::ResumeTask() { + DCHECK(message_loop_->BelongsToCurrentThread()); + + for (Players::iterator iter = players_.begin(); iter != players_.end(); + ++iter) { + DCHECK(!iter->second); + if (!iter->second) { + iter->first->Resume(); + } + } +} + +void MediaModule::RegisterPlayerTask(WebMediaPlayer* player) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + DCHECK(players_.find(player) == players_.end()); + players_.insert(std::make_pair(player, false)); + + // Track debug state for the most recently added WebMediaPlayer instance. + RegisterDebugState(player); +} + +void MediaModule::UnregisterPlayerTask(WebMediaPlayer* player) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + DCHECK(players_.find(player) != players_.end()); + players_.erase(players_.find(player)); + + if (players_.empty()) { + DeregisterDebugState(); + } else { + RegisterDebugState(players_.begin()->first); + } +} + +} // namespace media +} // namespace cobalt
diff --git a/src/cobalt/media/media_module.h b/src/cobalt/media/media_module.h index 9415df5..3fa53bf 100644 --- a/src/cobalt/media/media_module.h +++ b/src/cobalt/media/media_module.h
@@ -22,8 +22,12 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/threading/thread.h" #include "cobalt/base/user_log.h" #include "cobalt/math/size.h" #include "cobalt/media/can_play_type_handler.h" @@ -59,6 +63,10 @@ typedef ::media::WebMediaPlayer WebMediaPlayer; typedef render_tree::Image Image; + MediaModule() : thread_("media_module") { + thread_.Start(); + message_loop_ = thread_.message_loop_proxy(); + } virtual ~MediaModule() {} // Returns true when the setting is set successfully or if the setting has @@ -70,6 +78,9 @@ return false; } + void Suspend(); + void Resume(); + #if !defined(COBALT_BUILD_TYPE_GOLD) virtual ::media::ShellRawVideoDecoderFactory* GetRawVideoDecoderFactory() { return NULL; @@ -79,51 +90,8 @@ // TODO: Move the following methods into class like MediaModuleBase // to ensure that MediaModule is an interface. // WebMediaPlayerDelegate methods - void RegisterPlayer(WebMediaPlayer* player) OVERRIDE { - DCHECK(players_.find(player) == players_.end()); - players_.insert(std::make_pair(player, false)); - // Track debug state for the most recently added WebMediaPlayer instance. - RegisterDebugState(player); - } - - void UnregisterPlayer(WebMediaPlayer* player) OVERRIDE { - DCHECK(players_.find(player) != players_.end()); - players_.erase(players_.find(player)); - if (players_.empty()) { - DeregisterDebugState(); - } else { - RegisterDebugState(players_.begin()->first); - } - } - - // Functions to allow pause/resume of all active players. Note that the - // caller should block the main thread to ensure that media related JS/DOM - // code doesn't get a chance to run between the call to PauseAllPlayers() and - // ResumeAllPlayers(). Otherwise the JS/DOM code might bring the players back - // to playback states. - void PauseAllPlayers() { - for (Players::iterator iter = players_.begin(); iter != players_.end(); - ++iter) { - DCHECK(!iter->second); - if (!iter->second && !iter->first->IsPaused()) { - iter->first->Pause(); - iter->second = true; - } - } - } - - void ResumeAllPlayers() { - for (Players::iterator iter = players_.begin(); iter != players_.end(); - ++iter) { - if (iter->second) { - DCHECK(iter->first->IsPaused()); - if (iter->first->IsPaused()) { - iter->first->Play(); - } - iter->second = false; - } - } - } + void RegisterPlayer(WebMediaPlayer* player) OVERRIDE; + void UnregisterPlayer(WebMediaPlayer* player) OVERRIDE; // This function should be defined on individual platform to create the // platform specific MediaModule. @@ -133,23 +101,20 @@ const Options& options = Options()); private: - void RegisterDebugState(WebMediaPlayer* player) { - void* debug_state_address = NULL; - size_t debug_state_size = 0; - if (player->GetDebugReportDataAddress(&debug_state_address, - &debug_state_size)) { - base::UserLog::Register(base::UserLog::kWebMediaPlayerState, - "MediaPlyrState", debug_state_address, - debug_state_size); - } - } - void DeregisterDebugState() { - base::UserLog::Deregister(base::UserLog::kWebMediaPlayerState); - } + void RegisterDebugState(WebMediaPlayer* player); + void DeregisterDebugState(); + void SuspendTask(); + void ResumeTask(); + void RegisterPlayerTask(WebMediaPlayer* player); + void UnregisterPlayerTask(WebMediaPlayer* player); // When the value of a particular player is true, it means the player is // paused by us. typedef std::map<WebMediaPlayer*, bool> Players; + + // The thread that |players_| is accessed from, + base::Thread thread_; + scoped_refptr<base::MessageLoopProxy> message_loop_; Players players_; };
diff --git a/src/cobalt/media/media_module_stub.cc b/src/cobalt/media/media_module_stub.cc index 90813e1..f9e218d 100644 --- a/src/cobalt/media/media_module_stub.cc +++ b/src/cobalt/media/media_module_stub.cc
@@ -54,6 +54,10 @@ } float GetMaxTimeSeekable() const OVERRIDE { return 0.f; } + // Suspend/Resume + void Suspend() OVERRIDE {} + void Resume() OVERRIDE {} + // True if the loaded media has a playable video/audio track. bool HasVideo() const OVERRIDE { return false; } bool HasAudio() const OVERRIDE { return false; }
diff --git a/src/cobalt/media/sandbox/media_source_demuxer.cc b/src/cobalt/media/sandbox/media_source_demuxer.cc index 0044342..29ac7f3 100644 --- a/src/cobalt/media/sandbox/media_source_demuxer.cc +++ b/src/cobalt/media/sandbox/media_source_demuxer.cc
@@ -42,7 +42,7 @@ using ::media::DemuxerStream; using ::media::ChunkDemuxer; -typedef base::Callback<void(::media::Buffer*)> AppendBufferCB; +typedef base::Callback<void(::media::DecoderBuffer*)> AppendBufferCB; const char kSourceId[] = "id"; @@ -268,8 +268,9 @@ } } -void MediaSourceDemuxer::AppendBuffer(::media::Buffer* buffer) { +void MediaSourceDemuxer::AppendBuffer(::media::DecoderBuffer* buffer) { AUDescriptor desc = {0}; + desc.is_keyframe = buffer->IsKeyframe(); desc.offset = au_data_.size(); desc.size = buffer->GetDataSize(); desc.timestamp = buffer->GetTimestamp();
diff --git a/src/cobalt/media/sandbox/media_source_demuxer.h b/src/cobalt/media/sandbox/media_source_demuxer.h index f86679a..3221ccb 100644 --- a/src/cobalt/media/sandbox/media_source_demuxer.h +++ b/src/cobalt/media/sandbox/media_source_demuxer.h
@@ -21,7 +21,7 @@ #include "base/basictypes.h" #include "base/time.h" -#include "media/base/buffers.h" +#include "media/base/decoder_buffer.h" #include "media/base/video_decoder_config.h" namespace cobalt { @@ -32,6 +32,7 @@ class MediaSourceDemuxer { public: struct AUDescriptor { + bool is_keyframe; size_t offset; size_t size; base::TimeDelta timestamp; @@ -48,7 +49,7 @@ const ::media::VideoDecoderConfig& config() const { return config_; } private: - void AppendBuffer(::media::Buffer* buffer); + void AppendBuffer(::media::DecoderBuffer* buffer); bool valid_; std::vector<uint8> au_data_;
diff --git a/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc b/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc index d0f37ef..8853031 100644 --- a/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc +++ b/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
@@ -65,7 +65,8 @@ if (au_index_ < demuxer_->GetFrameCount()) { MediaSourceDemuxer::AUDescriptor desc = demuxer_->GetFrame(au_index_); current_au_buffer_ = - ::media::ShellBufferFactory::Instance()->AllocateBufferNow(desc.size); + ::media::ShellBufferFactory::Instance()->AllocateBufferNow( + desc.size, desc.is_keyframe); memcpy(current_au_buffer_->GetWritableData(), &au_data_[0] + desc.offset, desc.size); ++au_index_;
diff --git a/src/cobalt/network/persistent_cookie_store.cc b/src/cobalt/network/persistent_cookie_store.cc index a5dd276..ce0926c 100644 --- a/src/cobalt/network/persistent_cookie_store.cc +++ b/src/cobalt/network/persistent_cookie_store.cc
@@ -55,9 +55,13 @@ get_all.ColumnString(6), base::Time::FromInternalValue(get_all.ColumnInt64(7)), expiry, get_all.ColumnBool(10), get_all.ColumnBool(11)); - cookie->SetLastAccessDate( - base::Time::FromInternalValue(get_all.ColumnInt64(9))); - actual_cookies.push_back(cookie); + if (cookie) { + cookie->SetLastAccessDate( + base::Time::FromInternalValue(get_all.ColumnInt64(9))); + actual_cookies.push_back(cookie); + } else { + DLOG(ERROR) << "Failed to create cookie."; + } } return actual_cookies;
diff --git a/src/cobalt/render_tree/mock_resource_provider.h b/src/cobalt/render_tree/mock_resource_provider.h new file mode 100644 index 0000000..219a980 --- /dev/null +++ b/src/cobalt/render_tree/mock_resource_provider.h
@@ -0,0 +1,136 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COBALT_RENDER_TREE_MOCK_RESOURCE_PROVIDER_H_ +#define COBALT_RENDER_TREE_MOCK_RESOURCE_PROVIDER_H_ + +#include <string> + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "cobalt/render_tree/font.h" +#include "cobalt/render_tree/font_provider.h" +#include "cobalt/render_tree/glyph_buffer.h" +#include "cobalt/render_tree/image.h" +#include "cobalt/render_tree/resource_provider.h" +#include "cobalt/render_tree/typeface.h" + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cobalt { +namespace render_tree { + +class MockResourceProvider : public ResourceProvider { + public: + MOCK_METHOD0(Finish, void()); + MOCK_METHOD1(PixelFormatSupported, bool(PixelFormat pixel_format)); + MOCK_METHOD1(AlphaFormatSupported, bool(AlphaFormat alpha_format)); + MOCK_METHOD3(AllocateImageDataMock, + ImageData*(const math::Size& size, PixelFormat pixel_format, + AlphaFormat alpha_format)); + MOCK_METHOD1(CreateImageMock, Image*(ImageData* pixel_data)); + MOCK_METHOD2(AllocateRawImageMemoryMock, + RawImageMemory*(size_t size_in_bytes, size_t alignment)); + MOCK_METHOD2(CreateMultiPlaneImageFromRawMemoryMock, + Image*(RawImageMemory* raw_image_memory, + const MultiPlaneImageDataDescriptor& descriptor)); + MOCK_CONST_METHOD1(HasLocalFontFamily, bool(const char* font_family_name)); + MOCK_METHOD2(GetLocalTypefaceMock, + Typeface*(const char* font_family_name, FontStyle font_style)); + MOCK_METHOD1(GetLocalTypefaceIfAvailableMock, + Typeface*(const std::string& font_face_name)); + MOCK_METHOD3(GetCharacterFallbackTypefaceMock, + Typeface*(int32 utf32_character, FontStyle font_style, + const std::string& language)); + MOCK_METHOD2(CreateTypefaceFromRawDataMock, + Typeface*(RawTypefaceDataVector* raw_data, + std::string* error_string)); + MOCK_METHOD5( + CreateGlyphBufferMock, + render_tree::GlyphBuffer*(const char16* text_buffer, size_t text_length, + const std::string& language, bool is_rtl, + render_tree::FontProvider* font_provider)); + MOCK_METHOD2( + CreateGlyphBufferMock, + render_tree::GlyphBuffer*(const std::string& utf8_string, + const scoped_refptr<render_tree::Font>& font)); + MOCK_METHOD6(GetTextWidth, + float(const char16* text_buffer, size_t text_length, + const std::string& language, bool is_rtl, + render_tree::FontProvider* font_provider, + render_tree::FontVector* maybe_used_fonts)); + + scoped_ptr<ImageData> AllocateImageData(const math::Size& size, + PixelFormat pixel_format, + AlphaFormat alpha_format) { + return scoped_ptr<ImageData>( + AllocateImageDataMock(size, pixel_format, alpha_format)); + } + scoped_refptr<Image> CreateImage(scoped_ptr<ImageData> pixel_data) { + return scoped_refptr<Image>(CreateImageMock(pixel_data.get())); + } + scoped_ptr<RawImageMemory> AllocateRawImageMemory(size_t size_in_bytes, + size_t alignment) { + return scoped_ptr<RawImageMemory>( + AllocateRawImageMemoryMock(size_in_bytes, alignment)); + } + scoped_refptr<Image> CreateMultiPlaneImageFromRawMemory( + scoped_ptr<RawImageMemory> raw_image_memory, + const MultiPlaneImageDataDescriptor& descriptor) { + return scoped_refptr<Image>(CreateMultiPlaneImageFromRawMemoryMock( + raw_image_memory.get(), descriptor)); + } + scoped_refptr<Typeface> GetLocalTypeface(const char* font_family_name, + FontStyle font_style) { + return scoped_refptr<Typeface>( + GetLocalTypefaceMock(font_family_name, font_style)); + } + scoped_refptr<Typeface> GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) { + return scoped_refptr<Typeface>( + GetLocalTypefaceIfAvailableMock(font_face_name)); + } + scoped_refptr<Typeface> GetCharacterFallbackTypeface( + int32 utf32_character, FontStyle font_style, + const std::string& language) { + return scoped_refptr<Typeface>(GetCharacterFallbackTypefaceMock( + utf32_character, font_style, language)); + } + scoped_refptr<Typeface> CreateTypefaceFromRawData( + scoped_ptr<RawTypefaceDataVector> raw_data, std::string* error_string) { + return scoped_refptr<Typeface>( + CreateTypefaceFromRawDataMock(raw_data.get(), error_string)); + } + scoped_refptr<render_tree::GlyphBuffer> CreateGlyphBuffer( + const char16* text_buffer, size_t text_length, + const std::string& language, bool is_rtl, + render_tree::FontProvider* font_provider) { + return scoped_refptr<render_tree::GlyphBuffer>(CreateGlyphBufferMock( + text_buffer, text_length, language, is_rtl, font_provider)); + } + scoped_refptr<render_tree::GlyphBuffer> CreateGlyphBuffer( + const std::string& utf8_string, + const scoped_refptr<render_tree::Font>& font) { + return scoped_refptr<render_tree::GlyphBuffer>( + CreateGlyphBufferMock(utf8_string, font.get())); + } +}; + +} // namespace render_tree +} // namespace cobalt + +#endif // COBALT_RENDER_TREE_MOCK_RESOURCE_PROVIDER_H_
diff --git a/src/cobalt/render_tree/resource_provider.h b/src/cobalt/render_tree/resource_provider.h index 72c106a..c1bd3cb 100644 --- a/src/cobalt/render_tree/resource_provider.h +++ b/src/cobalt/render_tree/resource_provider.h
@@ -107,6 +107,16 @@ virtual scoped_refptr<Typeface> GetLocalTypeface(const char* font_family_name, FontStyle font_style) = 0; + // Given a set of typeface information, this method returns the locally + // available typeface that best fits the specified parameters. In the case + // where no typeface is found that matches the font family name, NULL is + // returned. + // + // Font's typeface (aka face name) is combination of a style and a font + // family. Font's style consists of weight, and a slant (but not size). + virtual scoped_refptr<Typeface> GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) = 0; + // Given a UTF-32 character, a set of typeface information, and a language, // this method returns the best-fit locally available fallback typeface that // provides a glyph for the specified character. In the case where no fallback
diff --git a/src/cobalt/render_tree/resource_provider_stub.h b/src/cobalt/render_tree/resource_provider_stub.h index 1430f5f..bf0a8bd 100644 --- a/src/cobalt/render_tree/resource_provider_stub.h +++ b/src/cobalt/render_tree/resource_provider_stub.h
@@ -213,6 +213,12 @@ return make_scoped_refptr(new TypefaceStub(NULL)); } + scoped_refptr<render_tree::Typeface> GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) OVERRIDE { + UNREFERENCED_PARAMETER(font_face_name); + return make_scoped_refptr(new TypefaceStub(NULL)); + } + scoped_refptr<Typeface> GetCharacterFallbackTypeface( int32 utf32_character, FontStyle font_style, const std::string& language) OVERRIDE {
diff --git a/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc b/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc index 9c6a1e2..ae7cbd9 100644 --- a/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc +++ b/src/cobalt/renderer/rasterizer/blitter/resource_provider.cc
@@ -92,6 +92,13 @@ font_style); } +scoped_refptr<render_tree::Typeface> +ResourceProvider::GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) { + return skia_resource_provider_->GetLocalTypefaceByFaceNameIfAvailable( + font_face_name); +} + scoped_refptr<Typeface> ResourceProvider::GetCharacterFallbackTypeface( int32 utf32_character, FontStyle font_style, const std::string& language) { return skia_resource_provider_->GetCharacterFallbackTypeface(
diff --git a/src/cobalt/renderer/rasterizer/blitter/resource_provider.h b/src/cobalt/renderer/rasterizer/blitter/resource_provider.h index 078a683..a7edd28 100644 --- a/src/cobalt/renderer/rasterizer/blitter/resource_provider.h +++ b/src/cobalt/renderer/rasterizer/blitter/resource_provider.h
@@ -64,6 +64,9 @@ scoped_refptr<render_tree::Typeface> GetLocalTypeface( const char* font_family_name, render_tree::FontStyle font_style) OVERRIDE; + scoped_refptr<render_tree::Typeface> GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) OVERRIDE; + scoped_refptr<render_tree::Typeface> GetCharacterFallbackTypeface( int32 utf32_character, render_tree::FontStyle font_style, const std::string& language) OVERRIDE;
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc index d79a244..1f97820 100644 --- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc +++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -25,6 +25,7 @@ #include "cobalt/renderer/rasterizer/skia/gl_format_conversions.h" #include "cobalt/renderer/rasterizer/skia/glyph_buffer.h" #include "cobalt/renderer/rasterizer/skia/hardware_image.h" +#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h" #include "cobalt/renderer/rasterizer/skia/typeface.h" #include "third_party/ots/include/opentype-sanitiser.h" #include "third_party/ots/include/ots-memory-stream.h" @@ -166,6 +167,25 @@ } scoped_refptr<render_tree::Typeface> +HardwareResourceProvider::GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) { + TRACE_EVENT0("cobalt::renderer", + "HardwareResourceProvider::GetLocalTypefaceIfAvailable()"); + + SkFontMgr_Cobalt* font_manager = + base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager_.get()); + + SkTypeface* typeface = font_manager->matchFaceNameOnlyIfFound(font_face_name); + SkiaTypeface* skia_type_face = NULL; + if (typeface != NULL) { + SkAutoTUnref<SkTypeface> typeface_unref_helper(typeface); + skia_type_face = new SkiaTypeface(typeface); + } + + return scoped_refptr<render_tree::Typeface>(skia_type_face); +} + +scoped_refptr<render_tree::Typeface> HardwareResourceProvider::GetCharacterFallbackTypeface( int32 character, render_tree::FontStyle font_style, const std::string& language) {
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h index 54a439d..8d85fea 100644 --- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h +++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
@@ -63,6 +63,9 @@ scoped_refptr<render_tree::Typeface> GetLocalTypeface( const char* font_family_name, render_tree::FontStyle font_style) OVERRIDE; + scoped_refptr<render_tree::Typeface> GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) OVERRIDE; + scoped_refptr<render_tree::Typeface> GetCharacterFallbackTypeface( int32 character, render_tree::FontStyle font_style, const std::string& language) OVERRIDE;
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/google_logging.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/google_logging.cc index bab22ce..bc53d2f 100644 --- a/src/cobalt/renderer/rasterizer/skia/skia/src/google_logging.cc +++ b/src/cobalt/renderer/rasterizer/skia/skia/src/google_logging.cc
@@ -19,7 +19,9 @@ base::StringAppendV(&message, format, ap); va_end(ap); - logging::LogMessage(file, line, - fatal ? logging::LOG_FATAL : logging::LOG_INFO).stream() - << message; + if (fatal) { + logging::LogMessage(file, line, logging::LOG_FATAL).stream() << message; + } else if (DLOG_IS_ON(INFO)) { + logging::LogMessage(file, line, logging::LOG_INFO).stream() << message; + } }
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc index 013d0dc..63f1e67 100644 --- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc +++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
@@ -250,6 +250,7 @@ const char* name = attributes[i]; const char* value = attributes[i + 1]; size_t name_len = strlen(name); + if (name_len == 4 && strncmp(name, "name", name_len) == 0) { SkAutoAsciiToLC to_lowercase(value); family->names.push_back().set(to_lowercase.lc()); @@ -268,25 +269,79 @@ } void FontElementHandler(FontFileInfo* file, const char** attributes) { - // A <font> should have weight (integer) and style (normal, italic)attributes. + DCHECK(file != NULL); + + // A <font> should have following attributes: + // weight (integer), style (normal, italic), font_name (string), and + // postscript_name (string). // The element should contain a filename. + + enum SeenAttributeFlags { + kSeenNone = 0, + kSeenFontFullName = 1, + kSeenFontPostscriptName = 1 << 1, + kSeenWeight = 1 << 2, + kSeenStyle = 1 << 3 + }; + + uint32_t seen_attributes_flag = kSeenNone; for (size_t i = 0; attributes[i] != NULL && attributes[i + 1] != NULL; i += 2) { const char* name = attributes[i]; const char* value = attributes[i + 1]; - size_t name_len = strlen(name); - if (name_len == 6 && strncmp("weight", name, name_len) == 0) { - if (!ParseNonNegativeInteger(value, &file->weight)) { - SkDebugf("---- Font weight %s (INVALID)", value); - file->weight = 0; - } - } else if (name_len == 5 && strncmp("style", name, name_len) == 0) { - size_t value_len = strlen(value); - if (value_len == 6 && strncmp("italic", value, value_len) == 0) { - file->style = FontFileInfo::kItalic_FontStyle; - } + + switch (strlen(name)) { + case 9: + if (strncmp("font_name", name, 9) == 0) { + file->full_font_name = value; + seen_attributes_flag |= kSeenFontFullName; + continue; + } + break; + case 15: + if (strncmp("postscript_name", name, 15) == 0) { + file->postcript_name = value; + seen_attributes_flag |= kSeenFontPostscriptName; + continue; + } + break; + case 6: + if (strncmp("weight", name, 6) == 0) { + if (!ParseNonNegativeInteger(value, &file->weight)) { + DLOG(WARNING) << "Invalid font weight [" << value << "]"; + file->weight = 0; + } else { + seen_attributes_flag |= kSeenWeight; + } + continue; + } + break; + case 5: + if (strncmp("style", name, 5) == 0) { + if (strncmp("italic", value, 6) == 0) { + file->style = FontFileInfo::kItalic_FontStyle; + seen_attributes_flag |= kSeenStyle; + continue; + } else if (strncmp("normal", value, 6) == 0) { + file->style = FontFileInfo::kNormal_FontStyle; + seen_attributes_flag |= kSeenStyle; + continue; + } else { + NOTREACHED() << "Unsupported style [" << value << "]"; + } + } + break; + default: + break; } + + NOTREACHED() << "Unsupported attribute [" << name << "]"; } + + DCHECK_EQ(seen_attributes_flag, kSeenFontFullName | kSeenFontPostscriptName | + kSeenWeight | kSeenStyle); + DCHECK(!file->full_font_name.isEmpty()); + DCHECK(!file->postcript_name.isEmpty()); } FontFamily* FindFamily(FamilyData* family_data, const char* family_name) {
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc index 21b6b4c..964fad6 100644 --- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc +++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
@@ -32,6 +32,7 @@ #include "SkString.h" #include "SkTArray.h" #include "SkTSearch.h" +#include "third_party/skia/src/ports/SkFontHost_FreeType_common.h" /////////////////////////////////////////////////////////////////////////////// @@ -257,8 +258,14 @@ ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant); - styles_.push_back().reset(SkNEW_ARGS(SkFontStyleSetEntry_Cobalt, - (path_name, font_file.index, style))); + std::string full_font_name(font_file.full_font_name.c_str(), + font_file.full_font_name.size()); + std::string postcript_name(font_file.postcript_name.c_str(), + font_file.postcript_name.size()); + + styles_.push_back().reset(SkNEW_ARGS( + SkFontStyleSetEntry_Cobalt, + (path_name, font_file.index, style, full_font_name, postcript_name))); } } @@ -636,6 +643,79 @@ return NULL; } +SkTypeface* SkFontMgr_Cobalt::matchFullFontFaceNameHelper( + SkFontStyleSet_Cobalt* style_set, + SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style) const { + DCHECK(style_set != NULL); + if (!style) { + NOTREACHED() << "style should not be NULL."; + return NULL; + } + + if (style->typeface == NULL) { + if (!style_set) { + return NULL; + } + style_set->CreateSystemTypeface(style); + } + + if (style->typeface != NULL) { + return SkRef(style->typeface.get()); + } + + return NULL; +} + +SkTypeface* SkFontMgr_Cobalt::matchFaceNameOnlyIfFound( + const std::string& font_face_name) const { + // Prioritize looking it up postscript name first since some of our client + // applications prefer this method to specify face names. + SkTypeface* typeface = matchPostScriptName(font_face_name); + if (typeface != NULL) return typeface; + + typeface = matchFullFontFaceName(font_face_name); + if (typeface != NULL) return typeface; + + return NULL; +} + +SkTypeface* SkFontMgr_Cobalt::matchFullFontFaceName( + const std::string& font_face_name) const { + SkAutoMutexAcquire scoped_mutex(style_sets_mutex_); + + if (font_face_name.empty()) { + return NULL; + } + + FullFontNameToFontFaceInfoMap::const_iterator font_face_iterator = + fullfontname_to_fontface_info_map_.find(font_face_name); + + if (font_face_iterator != fullfontname_to_fontface_info_map_.end()) { + return matchFullFontFaceNameHelper( + font_face_iterator->second.style_set_entry_parent, + font_face_iterator->second.style_set_entry); + } + + return NULL; +} + +SkTypeface* SkFontMgr_Cobalt::matchPostScriptName( + const std::string& font_face_name) const { + if (font_face_name.empty()) { + return NULL; + } + + PostScriptToFontFaceInfoMap::const_iterator font_face_iterator = + postscriptname_to_fontface_info_map_.find(font_face_name); + if (font_face_iterator != postscriptname_to_fontface_info_map_.end()) { + return matchFullFontFaceNameHelper( + font_face_iterator->second.style_set_entry_parent, + font_face_iterator->second.style_set_entry); + } + + return NULL; +} + SkTypeface* SkFontMgr_Cobalt::onMatchFamilyStyle( const char family_name[], const SkFontStyle& style) const { SkTypeface* tf = NULL; @@ -768,6 +848,54 @@ continue; } + for (SkAutoTUnref<SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt>* + font_style_set_entry = new_set->styles_.begin(); + font_style_set_entry != new_set->styles_.end(); + ++font_style_set_entry) { + if (!font_style_set_entry) { + NOTREACHED() << " Font Style entry is invalid"; + continue; + } else if ((*font_style_set_entry).get() == NULL) { + NOTREACHED() << " Font Style entry is NULL"; + continue; + } + + const std::string& full_font_name = + (*font_style_set_entry)->full_font_name; + DCHECK(!full_font_name.empty()); + if (fullfontname_to_fontface_info_map_.find(full_font_name) == + fullfontname_to_fontface_info_map_.end()) { + DLOG(INFO) << "Adding Full font name [" << full_font_name << "]."; + fullfontname_to_fontface_info_map_[full_font_name] = + FullFontNameToFontFaceInfoMap::mapped_type( + font_style_set_entry->get(), new_set.get()); + } else { + // Purposely, not overwriting the entry gives priority to the + // earlier entry. This is consistent with how fonts.xml gives + // priority to fonts that are specified earlier in the file. + NOTREACHED() << "Full font name [" << full_font_name + << "] already registered in BuildNameToFamilyMap."; + } + + const std::string& postscript_font_name = + (*font_style_set_entry)->font_postscript_name; + DCHECK(!postscript_font_name.empty()); + if (postscriptname_to_fontface_info_map_.find(postscript_font_name) == + postscriptname_to_fontface_info_map_.end()) { + DLOG(INFO) << "Adding Postscript name [" << postscript_font_name + << "]."; + postscriptname_to_fontface_info_map_[postscript_font_name] = + PostScriptToFontFaceInfoMap::mapped_type( + font_style_set_entry->get(), new_set.get()); + } else { + // Purposely, not overwriting the entry gives priority to the + // earlier entry. This is consistent with how fonts.xml gives + // priority to fonts that are specified earlier in the file. + NOTREACHED() << "Adding Postscript name [" << postscript_font_name + << "] already registered in BuildNameToFamilyMap."; + } + } + font_style_sets_.push_back().reset(SkRef(new_set.get())); if (named_font) {
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h index e09b727..cebba88 100644 --- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h +++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
@@ -26,7 +26,6 @@ #include "cobalt/base/poller.h" #include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h" #include "SkFontHost.h" -#include "SkFontHost_FreeType_common.h" #include "SkFontDescriptor.h" #include "SkFontMgr.h" #include "SkThread.h" @@ -48,15 +47,25 @@ public: struct SkFontStyleSetEntry_Cobalt : public SkRefCnt { SkFontStyleSetEntry_Cobalt(const SkString& file_path, const int index, - const SkFontStyle& style) + const SkFontStyle& style, + const std::string& full_name, + const std::string& postscript_name) : font_file_path(file_path), ttc_index(index), font_style(style), + full_font_name(full_name.data(), full_name.size()), + font_postscript_name(postscript_name.data(), postscript_name.size()), typeface(NULL) {} const SkString font_file_path; const int ttc_index; const SkFontStyle font_style; + + // these two members are declared as std::string since we have a hasher + // for std::string, but not SkString at this point. + const std::string full_font_name; + const std::string font_postscript_name; + SkAutoTUnref<SkTypeface> typeface; }; @@ -129,7 +138,19 @@ SkFontMgr_Cobalt(const char* directory, const SkTArray<SkString, true>& default_fonts); + // Note: Unlike the other similar onMatch* functions, this function can return + // NULL. This is so that we can try other things in case the match is not + // found. + SkTypeface* matchFaceNameOnlyIfFound(const std::string& font_face_name) const; + protected: + // Note: These match*Name helper functions can return NULL. + SkTypeface* matchFullFontFaceName(const std::string& font_face_name) const; + SkTypeface* matchPostScriptName(const std::string& font_face_name) const; + SkTypeface* matchFullFontFaceNameHelper( + SkFontStyleSet_Cobalt* style_set, + SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style) const; + // From SkFontMgr virtual int onCountFamilies() const SK_OVERRIDE; @@ -184,6 +205,20 @@ // the same (non-replicated) set of typefaces. typedef base::hash_map<std::string, SkFontStyleSet_Cobalt*> NameToFamilyMap; + struct FontFaceInfo { + FontFaceInfo() : style_set_entry(NULL), style_set_entry_parent(NULL) {} + FontFaceInfo(SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* entry, + SkFontStyleSet_Cobalt* parent) + : style_set_entry(entry), style_set_entry_parent(parent) {} + + SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt* style_set_entry; + SkFontStyleSet_Cobalt* style_set_entry_parent; + }; + + typedef base::hash_map<std::string, FontFaceInfo> + FullFontNameToFontFaceInfoMap; + typedef base::hash_map<std::string, FontFaceInfo> PostScriptToFontFaceInfoMap; + void BuildNameToFamilyMap(const char* base_path, SkTDArray<FontFamily*>* families); void FindDefaultFont(const SkTArray<SkString, true>& default_fonts); @@ -223,6 +258,8 @@ SkTArray<SkString> family_names_; NameToFamilyMap name_to_family_map_; + FullFontNameToFontFaceInfoMap fullfontname_to_fontface_info_map_; + PostScriptToFontFaceInfoMap postscriptname_to_fontface_info_map_; SkTArray<SkFontStyleSet_Cobalt*> fallback_families_;
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h index 5e12828..020517c 100644 --- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h +++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
@@ -25,7 +25,6 @@ #include "SkString.h" #include "SkTDArray.h" - // The font_character_map namespace contains all of the constants, typedefs, and // utility functions used with determining whether or not a font supports a // character. @@ -110,6 +109,9 @@ int index; int weight; FontStyle style; + + SkString full_font_name; + SkString postcript_name; }; // A font family provides one or more names for a collection of fonts, each of
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkMemory_starboard.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkMemory_starboard.cc index 8d843b7..531621f 100644 --- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkMemory_starboard.cc +++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkMemory_starboard.cc
@@ -54,7 +54,7 @@ void sk_free(void* p) { if (p) { - SbMemoryFree(p); + SbMemoryDeallocate(p); } }
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc index 04ca7c1..be05ccf 100644 --- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc +++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
@@ -21,6 +21,7 @@ #include "cobalt/renderer/rasterizer/skia/cobalt_skia_type_conversions.h" #include "cobalt/renderer/rasterizer/skia/font.h" #include "cobalt/renderer/rasterizer/skia/glyph_buffer.h" +#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h" #include "cobalt/renderer/rasterizer/skia/software_image.h" #include "cobalt/renderer/rasterizer/skia/typeface.h" #include "third_party/ots/include/opentype-sanitiser.h" @@ -108,7 +109,8 @@ scoped_refptr<render_tree::Typeface> SoftwareResourceProvider::GetLocalTypeface( const char* font_family_name, render_tree::FontStyle font_style) { - TRACE_EVENT0("cobalt::renderer", "SoftwareResourceProvider::GetLocalFont()"); + TRACE_EVENT0("cobalt::renderer", + "SoftwareResourceProvider::GetLocalTypeface()"); SkAutoTUnref<SkTypeface> typeface(font_manager_->matchFamilyStyle( font_family_name, CobaltFontStyleToSkFontStyle(font_style))); @@ -116,6 +118,24 @@ } scoped_refptr<render_tree::Typeface> +SoftwareResourceProvider::GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) { + TRACE_EVENT0("cobalt::renderer", + "SoftwareResourceProvider::GetLocalTypefaceIfAvailable()"); + + SkFontMgr_Cobalt* font_manager = + base::polymorphic_downcast<SkFontMgr_Cobalt*>(font_manager_.get()); + + SkTypeface* typeface = font_manager->matchFaceNameOnlyIfFound(font_face_name); + if (typeface != NULL) { + SkAutoTUnref<SkTypeface> typeface_unref_helper(typeface); + return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface)); + } + + return NULL; +} + +scoped_refptr<render_tree::Typeface> SoftwareResourceProvider::GetCharacterFallbackTypeface( int32 character, render_tree::FontStyle font_style, const std::string& language) {
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h index 7be9105..6b979ce 100644 --- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h +++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
@@ -58,6 +58,9 @@ scoped_refptr<render_tree::Typeface> GetLocalTypeface( const char* font_family_name, render_tree::FontStyle font_style) OVERRIDE; + scoped_refptr<render_tree::Typeface> GetLocalTypefaceByFaceNameIfAvailable( + const std::string& font_face_name) OVERRIDE; + scoped_refptr<render_tree::Typeface> GetCharacterFallbackTypeface( int32 character, render_tree::FontStyle font_style, const std::string& language) OVERRIDE;
diff --git a/src/cobalt/script/javascript_engine.h b/src/cobalt/script/javascript_engine.h index 7c5a607..cda4f91 100644 --- a/src/cobalt/script/javascript_engine.h +++ b/src/cobalt/script/javascript_engine.h
@@ -41,6 +41,11 @@ // Javascript object. This may mean collection needs to happen sooner. virtual void ReportExtraMemoryCost(size_t bytes) = 0; + // Updates the memory usage and returns the total memory that is reserved by + // the engine. This includes the part that is actually occupied by JS objects, + // and the part that is not yet. + virtual size_t UpdateMemoryStatsAndReturnReserved() = 0; + protected: virtual ~JavaScriptEngine() {} friend class scoped_ptr<JavaScriptEngine>;
diff --git a/src/cobalt/script/javascriptcore/jsc_engine.cc b/src/cobalt/script/javascriptcore/jsc_engine.cc index 08cfcbb..178f66b 100644 --- a/src/cobalt/script/javascriptcore/jsc_engine.cc +++ b/src/cobalt/script/javascriptcore/jsc_engine.cc
@@ -21,7 +21,6 @@ #include "base/synchronization/lock.h" #include "base/time.h" #include "cobalt/base/c_val.h" -#include "cobalt/base/poller.h" #include "cobalt/script/javascriptcore/jsc_global_environment.h" #include "cobalt/script/javascriptcore/jsc_global_object.h" #include "third_party/WebKit/Source/JavaScriptCore/runtime/InitializeThreading.h" @@ -33,12 +32,6 @@ namespace { -#if defined(__LB_SHELL__FOR_RELEASE__) -const int kPollerPeriodMs = 2000; -#else // #if defined(__LB_SHELL__FOR_RELEASE__) -const int kPollerPeriodMs = 20; -#endif // #if defined(__LB_SHELL__FOR_RELEASE__) - class JSCEngineStats { public: JSCEngineStats(); @@ -58,31 +51,24 @@ --js_engine_count_; } + size_t UpdateMemoryStatsAndReturnReserved() { + base::AutoLock auto_lock(lock_); + if (js_engine_count_.value() == 0) { + return 0; + } + return OSAllocator::getCurrentBytesAllocated(); + } + private: friend struct StaticMemorySingletonTraits<JSCEngineStats>; - void Update() { - base::AutoLock auto_lock(lock_); - if (js_engine_count_.value() > 0) { - js_memory_ = OSAllocator::getCurrentBytesAllocated(); - } - } - base::Lock lock_; - base::CVal<base::cval::SizeInBytes, base::CValPublic> js_memory_; base::CVal<size_t> js_engine_count_; - scoped_ptr<base::PollerWithThread> poller_; }; JSCEngineStats::JSCEngineStats() - : js_memory_("Memory.JS", 0, - "Total memory occupied by the JSC page allocator."), - js_engine_count_("Count.JS.Engine", 0, - "Total JavaScript engine registered.") { - poller_.reset(new base::PollerWithThread( - base::Bind(&JSCEngineStats::Update, base::Unretained(this)), - base::TimeDelta::FromMilliseconds(kPollerPeriodMs))); -} + : js_engine_count_("Count.JS.Engine", 0, + "Total JavaScript engine registered.") {} } // namespace @@ -115,6 +101,10 @@ global_data_->heap.reportExtraMemoryCost(bytes); } +size_t JSCEngine::UpdateMemoryStatsAndReturnReserved() { + return JSCEngineStats::GetInstance()->UpdateMemoryStatsAndReturnReserved(); +} + } // namespace javascriptcore scoped_ptr<JavaScriptEngine> JavaScriptEngine::CreateEngine() {
diff --git a/src/cobalt/script/javascriptcore/jsc_engine.h b/src/cobalt/script/javascriptcore/jsc_engine.h index 5ef1068..7ee06e0 100644 --- a/src/cobalt/script/javascriptcore/jsc_engine.h +++ b/src/cobalt/script/javascriptcore/jsc_engine.h
@@ -30,9 +30,12 @@ public: JSCEngine(); ~JSCEngine() OVERRIDE; + scoped_refptr<GlobalEnvironment> CreateGlobalEnvironment() OVERRIDE; void CollectGarbage() OVERRIDE; void ReportExtraMemoryCost(size_t bytes) OVERRIDE; + size_t UpdateMemoryStatsAndReturnReserved() OVERRIDE; + JSC::JSGlobalData* global_data() { return global_data_.get(); } ScriptObjectRegistry* script_object_registry() { return &script_object_registry_;
diff --git a/src/cobalt/script/mozjs/mozjs_engine.cc b/src/cobalt/script/mozjs/mozjs_engine.cc index 39f47bb..d5076b8 100644 --- a/src/cobalt/script/mozjs/mozjs_engine.cc +++ b/src/cobalt/script/mozjs/mozjs_engine.cc
@@ -20,7 +20,6 @@ #include "base/logging.h" #include "cobalt/base/c_val.h" -#include "cobalt/base/poller.h" #include "cobalt/browser/web_module.h" #include "cobalt/script/mozjs/mozjs_global_environment.h" #include "third_party/mozjs/cobalt_config/include/jscustomallocator.h" @@ -43,12 +42,6 @@ MozjsGlobalEnvironment::CheckEval }; -#if defined(__LB_SHELL__FOR_RELEASE__) -const int kPollerPeriodMs = 2000; -#else // #if defined(__LB_SHELL__FOR_RELEASE__) -const int kPollerPeriodMs = 20; -#endif // #if defined(__LB_SHELL__FOR_RELEASE__) - class EngineStats { public: EngineStats(); @@ -68,36 +61,30 @@ --engine_count_; } - void Update() { + size_t UpdateMemoryStatsAndReturnReserved() { base::AutoLock auto_lock(lock_); + if (engine_count_.value() == 0) { + return 0; + } allocated_memory_ = MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated(); mapped_memory_ = MemoryAllocatorReporter::Get()->GetCurrentBytesMapped(); - memory_sum_ = allocated_memory_ + mapped_memory_; + return allocated_memory_ + mapped_memory_; } private: base::Lock lock_; base::CVal<size_t, base::CValPublic> allocated_memory_; base::CVal<size_t, base::CValPublic> mapped_memory_; - base::CVal<size_t, base::CValPublic> memory_sum_; base::CVal<size_t> engine_count_; - - // Repeating timer to query the used bytes. - scoped_ptr<base::PollerWithThread> poller_; }; EngineStats::EngineStats() : allocated_memory_("Memory.JS.AllocatedMemory", 0, "JS memory occupied by the Mozjs allocator."), mapped_memory_("Memory.JS.MappedMemory", 0, "JS mapped memory."), - memory_sum_("Memory.JS", 0, - "Total memory occupied by the Mozjs allocator and heap."), engine_count_("Count.JS.Engine", 0, "Total JavaScript engine registered.") { - poller_.reset(new base::PollerWithThread( - base::Bind(&EngineStats::Update, base::Unretained(this)), - base::TimeDelta::FromMilliseconds(kPollerPeriodMs))); } } // namespace @@ -158,6 +145,10 @@ void MozjsEngine::ReportExtraMemoryCost(size_t bytes) { NOTIMPLEMENTED(); } +size_t MozjsEngine::UpdateMemoryStatsAndReturnReserved() { + return EngineStats::GetInstance()->UpdateMemoryStatsAndReturnReserved(); +} + JSBool MozjsEngine::ContextCallback(JSContext* context, unsigned context_op) { JSRuntime* runtime = JS_GetRuntime(context); MozjsEngine* engine =
diff --git a/src/cobalt/script/mozjs/mozjs_engine.h b/src/cobalt/script/mozjs/mozjs_engine.h index a678a15..2a86ce5 100644 --- a/src/cobalt/script/mozjs/mozjs_engine.h +++ b/src/cobalt/script/mozjs/mozjs_engine.h
@@ -34,6 +34,7 @@ scoped_refptr<GlobalEnvironment> CreateGlobalEnvironment() OVERRIDE; void CollectGarbage() OVERRIDE; void ReportExtraMemoryCost(size_t bytes) OVERRIDE; + size_t UpdateMemoryStatsAndReturnReserved() OVERRIDE; private: static JSBool ContextCallback(JSContext* context, unsigned context_op);
diff --git a/src/cobalt/speech/SpeechRecognitionResult.idl b/src/cobalt/speech/SpeechRecognitionResult.idl index 6cc3071..ef1e97d 100644 --- a/src/cobalt/speech/SpeechRecognitionResult.idl +++ b/src/cobalt/speech/SpeechRecognitionResult.idl
@@ -19,5 +19,6 @@ interface SpeechRecognitionResult { readonly attribute unsigned long length; getter SpeechRecognitionAlternative item(unsigned long index); - readonly attribute boolean final; + // isFinal is different from the spec., but follows with Chromium. + readonly attribute boolean isFinal; };
diff --git a/src/cobalt/speech/mic.h b/src/cobalt/speech/mic.h index 4eac5e1..b83b875 100644 --- a/src/cobalt/speech/mic.h +++ b/src/cobalt/speech/mic.h
@@ -17,6 +17,8 @@ #ifndef COBALT_SPEECH_MIC_H_ #define COBALT_SPEECH_MIC_H_ +#include <string> + #include "base/callback.h" #include "media/base/audio_bus.h" @@ -60,6 +62,8 @@ const ErrorCallback error_callback_; }; +std::string GetSpeechAPIKey(); + } // namespace speech } // namespace cobalt
diff --git a/src/cobalt/speech/mic_linux.cc b/src/cobalt/speech/mic_linux.cc index 5621116..d7f6809 100644 --- a/src/cobalt/speech/mic_linux.cc +++ b/src/cobalt/speech/mic_linux.cc
@@ -38,5 +38,7 @@ new MicLinux(sample_rate, data_received, completion, error)); } +std::string GetSpeechAPIKey() { return ""; } + } // namespace speech } // namespace cobalt
diff --git a/src/cobalt/speech/mic_starboard.cc b/src/cobalt/speech/mic_starboard.cc index 1b164ba..c818dab 100644 --- a/src/cobalt/speech/mic_starboard.cc +++ b/src/cobalt/speech/mic_starboard.cc
@@ -38,5 +38,7 @@ new MicStarboard(sample_rate, data_received, completion, error)); } +std::string GetSpeechAPIKey() { return ""; } + } // namespace speech } // namespace cobalt
diff --git a/src/cobalt/speech/mic_win.cc b/src/cobalt/speech/mic_win.cc index 2025566..80c49fc 100644 --- a/src/cobalt/speech/mic_win.cc +++ b/src/cobalt/speech/mic_win.cc
@@ -38,5 +38,7 @@ new MicWin(sample_rate, data_received, completion, error)); } +std::string GetSpeechAPIKey() { return ""; } + } // namespace speech } // namespace cobalt
diff --git a/src/cobalt/speech/speech.gyp b/src/cobalt/speech/speech.gyp index 264a7e2..90ba3b1 100644 --- a/src/cobalt/speech/speech.gyp +++ b/src/cobalt/speech/speech.gyp
@@ -56,6 +56,7 @@ '<(DEPTH)/cobalt/base/base.gyp:base', '<(DEPTH)/cobalt/dom/dom.gyp:dom', '<(DEPTH)/third_party/flac/flac.gyp:libflac', + '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite', ], 'include_dirs': [ # Get protobuf headers from the chromium tree.
diff --git a/src/cobalt/speech/speech_recognition_manager.cc b/src/cobalt/speech/speech_recognition_manager.cc index 6f6966e..d7cd9dd 100644 --- a/src/cobalt/speech/speech_recognition_manager.cc +++ b/src/cobalt/speech/speech_recognition_manager.cc
@@ -34,9 +34,7 @@ event_callback_(event_callback), ALLOW_THIS_IN_INITIALIZER_LIST( recognizer_(network_module, - base::Bind(&SpeechRecognitionManager::OnRecognizerResult, - base::Unretained(this)), - base::Bind(&SpeechRecognitionManager::OnRecognizerError, + base::Bind(&SpeechRecognitionManager::OnRecognizerEvent, base::Unretained(this)))), ALLOW_THIS_IN_INITIALIZER_LIST(mic_(Mic::Create( kSampleRate, base::Bind(&SpeechRecognitionManager::OnDataReceived, @@ -93,12 +91,12 @@ recognizer_.RecognizeAudio(dummy_audio_bus.Pass(), true); } -void SpeechRecognitionManager::OnRecognizerResult( - const scoped_refptr<SpeechRecognitionEvent>& event) { +void SpeechRecognitionManager::OnRecognizerEvent( + const scoped_refptr<dom::Event>& event) { if (!main_message_loop_->BelongsToCurrentThread()) { // Called from recognizer thread. main_message_loop_->PostTask( - FROM_HERE, base::Bind(&SpeechRecognitionManager::OnRecognizerResult, + FROM_HERE, base::Bind(&SpeechRecognitionManager::OnRecognizerEvent, weak_this_, event)); return; } @@ -106,21 +104,6 @@ event_callback_.Run(event); } -void SpeechRecognitionManager::OnRecognizerError() { - if (!main_message_loop_->BelongsToCurrentThread()) { - // Called from recognizer thread. - main_message_loop_->PostTask( - FROM_HERE, - base::Bind(&SpeechRecognitionManager::OnRecognizerError, weak_this_)); - return; - } - - // TODO: Could be other error types based on the recognizer response. - event_callback_.Run( - scoped_refptr<SpeechRecognitionError>(new SpeechRecognitionError( - SpeechRecognitionError::kNetwork, "Recognition Failed."))); -} - void SpeechRecognitionManager::OnMicError() { if (!main_message_loop_->BelongsToCurrentThread()) { // Called from mic thread.
diff --git a/src/cobalt/speech/speech_recognition_manager.h b/src/cobalt/speech/speech_recognition_manager.h index dda56b2..4c20577 100644 --- a/src/cobalt/speech/speech_recognition_manager.h +++ b/src/cobalt/speech/speech_recognition_manager.h
@@ -55,8 +55,7 @@ void OnMicError(); // Callbacks from recognizer. - void OnRecognizerResult(const scoped_refptr<SpeechRecognitionEvent>& event); - void OnRecognizerError(); + void OnRecognizerEvent(const scoped_refptr<dom::Event>& event); base::WeakPtrFactory<SpeechRecognitionManager> weak_ptr_factory_; // We construct a WeakPtr upon SpeechRecognitionManager's construction in
diff --git a/src/cobalt/speech/speech_recognition_result.h b/src/cobalt/speech/speech_recognition_result.h index 6ebb193..a7432b1 100644 --- a/src/cobalt/speech/speech_recognition_result.h +++ b/src/cobalt/speech/speech_recognition_result.h
@@ -49,7 +49,7 @@ // The final MUST be set to true if this is the final time the speech service // will return this particular index value. If the value is false, then this // represents an interim result that could still be changed. - bool final() const { return final_; } + bool is_final() const { return final_; } DEFINE_WRAPPABLE_TYPE(SpeechRecognitionResult);
diff --git a/src/cobalt/speech/speech_recognizer.cc b/src/cobalt/speech/speech_recognizer.cc index f46df90..a9f27b0 100644 --- a/src/cobalt/speech/speech_recognizer.cc +++ b/src/cobalt/speech/speech_recognizer.cc
@@ -21,8 +21,12 @@ #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "cobalt/deprecated/platform_delegate.h" #include "cobalt/loader/fetcher_factory.h" #include "cobalt/network/network_module.h" +#include "cobalt/speech/google_streaming_api.pb.h" +#include "cobalt/speech/mic.h" +#include "cobalt/speech/speech_recognition_error.h" #include "net/base/escape.h" #include "net/url_request/url_fetcher.h" @@ -32,8 +36,6 @@ namespace { const char kBaseStreamURL[] = "https://www.google.com/speech-api/full-duplex/v1"; -// TODO: hide this key to somewhere else. -const char kSpeechAPIKey[] = ""; const char kUp[] = "up"; const char kDown[] = "down"; const char kClient[] = "com.speech.tv"; @@ -66,16 +68,85 @@ return url.ReplaceComponents(replacements); } +SpeechRecognitionResultList::SpeechRecognitionResults +ProcessProtoSuccessResults(const proto::SpeechRecognitionEvent& event) { + DCHECK_EQ(event.status(), proto::SpeechRecognitionEvent::STATUS_SUCCESS); + + SpeechRecognitionResultList::SpeechRecognitionResults results; + for (int i = 0; i < event.result_size(); ++i) { + SpeechRecognitionResult::SpeechRecognitionAlternatives alternatives; + const proto::SpeechRecognitionResult& kProtoResult = event.result(i); + for (int j = 0; j < kProtoResult.alternative_size(); ++j) { + const proto::SpeechRecognitionAlternative& kAlternative = + kProtoResult.alternative(j); + scoped_refptr<SpeechRecognitionAlternative> alternative( + new SpeechRecognitionAlternative(kAlternative.transcript(), + kAlternative.confidence())); + alternatives.push_back(alternative); + } + bool final = kProtoResult.has_final() && kProtoResult.final(); + scoped_refptr<SpeechRecognitionResult> recognition_result( + new SpeechRecognitionResult(alternatives, final)); + results.push_back(recognition_result); + } + return results; +} + +// TODO: Feed error messages when creating SpeechRecognitionError. +void ProcessAndFireErrorEvent( + const proto::SpeechRecognitionEvent& event, + const SpeechRecognizer::EventCallback& event_callback) { + scoped_refptr<dom::Event> error_event; + switch (event.status()) { + case proto::SpeechRecognitionEvent::STATUS_SUCCESS: + NOTREACHED(); + return; + case proto::SpeechRecognitionEvent::STATUS_NO_SPEECH: + error_event = + new SpeechRecognitionError(SpeechRecognitionError::kNoSpeech, ""); + break; + case proto::SpeechRecognitionEvent::STATUS_ABORTED: + error_event = + new SpeechRecognitionError(SpeechRecognitionError::kAborted, ""); + break; + case proto::SpeechRecognitionEvent::STATUS_AUDIO_CAPTURE: + error_event = + new SpeechRecognitionError(SpeechRecognitionError::kAudioCapture, ""); + break; + case proto::SpeechRecognitionEvent::STATUS_NETWORK: + error_event = + new SpeechRecognitionError(SpeechRecognitionError::kNetwork, ""); + break; + case proto::SpeechRecognitionEvent::STATUS_NOT_ALLOWED: + error_event = + new SpeechRecognitionError(SpeechRecognitionError::kNotAllowed, ""); + break; + case proto::SpeechRecognitionEvent::STATUS_SERVICE_NOT_ALLOWED: + error_event = new SpeechRecognitionError( + SpeechRecognitionError::kServiceNotAllowed, ""); + break; + case proto::SpeechRecognitionEvent::STATUS_BAD_GRAMMAR: + error_event = + new SpeechRecognitionError(SpeechRecognitionError::kBadGrammar, ""); + break; + case proto::SpeechRecognitionEvent::STATUS_LANGUAGE_NOT_SUPPORTED: + error_event = new SpeechRecognitionError( + SpeechRecognitionError::kLanguageNotSupported, ""); + break; + } + + DCHECK(error_event); + event_callback.Run(error_event); +} + } // namespace SpeechRecognizer::SpeechRecognizer(network::NetworkModule* network_module, - const ResultCallback& result_callback, - const ErrorCallback& error_callback) + const EventCallback& event_callback) : network_module_(network_module), thread_("speech_recognizer"), started_(false), - result_callback_(result_callback), - error_callback_(error_callback) { + event_callback_(event_callback) { thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0)); } @@ -110,11 +181,26 @@ void SpeechRecognizer::OnURLFetchDownloadData( const net::URLFetcher* source, scoped_ptr<std::string> download_data) { DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); - // TODO: Parse the serialized protocol buffers data. - NOTIMPLEMENTED(); - UNREFERENCED_PARAMETER(source); - UNREFERENCED_PARAMETER(download_data); + if (source == downstream_fetcher_.get()) { + chunked_byte_buffer_.Append(*download_data); + while (chunked_byte_buffer_.HasChunks()) { + scoped_ptr<std::vector<uint8_t> > chunk = + chunked_byte_buffer_.PopChunk().Pass(); + + proto::SpeechRecognitionEvent event; + if (!event.ParseFromString(std::string(chunk->begin(), chunk->end()))) { + DLOG(WARNING) << "Parse proto string error."; + return; + } + + if (event.status() == proto::SpeechRecognitionEvent::STATUS_SUCCESS) { + ProcessAndFireSuccessEvent(ProcessProtoSuccessResults(event)); + } else { + ProcessAndFireErrorEvent(event, event_callback_); + } + } + } } void SpeechRecognizer::OnURLFetchComplete(const net::URLFetcher* source) { @@ -157,10 +243,15 @@ up_url = AppendQueryParameter(up_url, "client", kClient); up_url = AppendQueryParameter(up_url, "pair", pair); up_url = AppendQueryParameter(up_url, "output", "pb"); - up_url = AppendQueryParameter(up_url, "key", kSpeechAPIKey); + up_url = AppendQueryParameter(up_url, "key", GetSpeechAPIKey()); + // Language is required. If no language is specified, use the system language. if (!config.lang.empty()) { up_url = AppendQueryParameter(up_url, "lang", config.lang); + } else { + up_url = AppendQueryParameter( + up_url, "lang", + cobalt::deprecated::PlatformDelegate::Get()->GetSystemLanguage()); } if (config.max_alternatives) { @@ -195,6 +286,9 @@ upstream_fetcher_.reset(); downstream_fetcher_.reset(); encoder_.reset(); + + // Clear the final results. + final_results_.clear(); } void SpeechRecognizer::UploadAudioDataInternal(scoped_ptr<AudioBus> audio_bus, @@ -216,5 +310,31 @@ } } +void SpeechRecognizer::ProcessAndFireSuccessEvent( + const SpeechRecognitionResults& new_results) { + SpeechRecognitionResults success_results; + size_t total_size = final_results_.size() + new_results.size(); + success_results.reserve(total_size); + success_results = final_results_; + success_results.insert(success_results.end(), new_results.begin(), + new_results.end()); + + size_t result_index = final_results_.size(); + // Update final results list. + for (size_t i = 0; i < new_results.size(); ++i) { + if (new_results[i]->is_final()) { + final_results_.push_back(new_results[i]); + } + } + + scoped_refptr<SpeechRecognitionResultList> recognition_list( + new SpeechRecognitionResultList(success_results)); + scoped_refptr<SpeechRecognitionEvent> recognition_event( + new SpeechRecognitionEvent(SpeechRecognitionEvent::kResult, + static_cast<uint32>(result_index), + recognition_list)); + event_callback_.Run(recognition_event); +} + } // namespace speech } // namespace cobalt
diff --git a/src/cobalt/speech/speech_recognizer.h b/src/cobalt/speech/speech_recognizer.h index 7b54584..cb76a05 100644 --- a/src/cobalt/speech/speech_recognizer.h +++ b/src/cobalt/speech/speech_recognizer.h
@@ -23,6 +23,7 @@ #include "base/threading/thread.h" #include "cobalt/network/network_module.h" #include "cobalt/speech/audio_encoder_flac.h" +#include "cobalt/speech/chunked_byte_buffer.h" #include "cobalt/speech/speech_recognition_config.h" #include "cobalt/speech/speech_recognition_event.h" #include "media/base/audio_bus.h" @@ -42,13 +43,12 @@ class SpeechRecognizer : public net::URLFetcherDelegate { public: typedef ::media::AudioBus AudioBus; - typedef base::Callback<void(const scoped_refptr<SpeechRecognitionEvent>&)> - ResultCallback; - typedef base::Callback<void(void)> ErrorCallback; + typedef base::Callback<void(const scoped_refptr<dom::Event>&)> EventCallback; + typedef SpeechRecognitionResultList::SpeechRecognitionResults + SpeechRecognitionResults; SpeechRecognizer(network::NetworkModule* network_module, - const ResultCallback& result_callback, - const ErrorCallback& error_callback); + const EventCallback& event_callback); ~SpeechRecognizer() OVERRIDE; // Multiple calls to Start/Stop are allowed, the implementation should take @@ -73,6 +73,7 @@ void StopInternal(); void UploadAudioDataInternal(scoped_ptr<AudioBus> audio_bus, bool is_last_chunk); + void ProcessAndFireSuccessEvent(const SpeechRecognitionResults& new_results); // This is used for creating fetchers. network::NetworkModule* network_module_; @@ -87,8 +88,11 @@ scoped_ptr<net::URLFetcher> upstream_fetcher_; // Fetcher for receiving the streaming results. scoped_ptr<net::URLFetcher> downstream_fetcher_; - ResultCallback result_callback_; - ErrorCallback error_callback_; + EventCallback event_callback_; + // Used for processing proto buffer data. + ChunkedByteBuffer chunked_byte_buffer_; + // Used for accumulating final results. + SpeechRecognitionResults final_results_; }; } // namespace speech
diff --git a/src/cobalt/webdriver/element_driver.cc b/src/cobalt/webdriver/element_driver.cc index a5c3315..6d05638 100644 --- a/src/cobalt/webdriver/element_driver.cc +++ b/src/cobalt/webdriver/element_driver.cc
@@ -64,10 +64,12 @@ ElementDriver::ElementDriver( const protocol::ElementId& element_id, const base::WeakPtr<dom::Element>& element, ElementMapping* element_mapping, + KeyboardEventInjector keyboard_event_injector, const scoped_refptr<base::MessageLoopProxy>& message_loop) : element_id_(element_id), element_(element), element_mapping_(element_mapping), + keyboard_injector_(keyboard_event_injector), element_message_loop_(message_loop) {} util::CommandResult<std::string> ElementDriver::GetTagName() { @@ -157,7 +159,7 @@ } util::CommandResult<void> ElementDriver::SendKeysInternal( - scoped_ptr<KeyboardEventVector> events) { + scoped_ptr<Keyboard::KeyboardEventVector> events) { typedef util::CommandResult<void> CommandResult; DCHECK_EQ(base::MessageLoopProxy::current(), element_message_loop_); if (!element_) { @@ -174,7 +176,8 @@ if (!element_) { return CommandResult(protocol::Response::kStaleElementReference); } - element_->DispatchEvent((*events)[i]); + + keyboard_injector_.Run(element_.get(), (*events)[i]); } return CommandResult(protocol::Response::kSuccess); }
diff --git a/src/cobalt/webdriver/element_driver.h b/src/cobalt/webdriver/element_driver.h index 22e2ee0..645a0e0 100644 --- a/src/cobalt/webdriver/element_driver.h +++ b/src/cobalt/webdriver/element_driver.h
@@ -28,6 +28,7 @@ #include "cobalt/dom/element.h" #include "cobalt/dom/keyboard_event.h" #include "cobalt/webdriver/element_mapping.h" +#include "cobalt/webdriver/keyboard.h" #include "cobalt/webdriver/protocol/element_id.h" #include "cobalt/webdriver/protocol/keys.h" #include "cobalt/webdriver/protocol/search_strategy.h" @@ -46,9 +47,14 @@ // will map to a method on this class. class ElementDriver { public: + typedef base::Callback<void(scoped_refptr<dom::Element>, + const dom::KeyboardEvent::Data&)> + KeyboardEventInjector; + ElementDriver(const protocol::ElementId& element_id, const base::WeakPtr<dom::Element>& element, ElementMapping* element_mapping, + KeyboardEventInjector keyboard_injector, const scoped_refptr<base::MessageLoopProxy>& message_loop); const protocol::ElementId& element_id() { return element_id_; } @@ -67,7 +73,6 @@ const std::string& property_name); private: - typedef std::vector<scoped_refptr<dom::KeyboardEvent> > KeyboardEventVector; typedef std::vector<protocol::ElementId> ElementIdVector; // Get the dom::Element* that this ElementDriver wraps. This must be called @@ -75,7 +80,7 @@ dom::Element* GetWeakElement(); util::CommandResult<void> SendKeysInternal( - scoped_ptr<KeyboardEventVector> keyboard_events); + scoped_ptr<Keyboard::KeyboardEventVector> keyboard_events); // Shared logic between FindElement and FindElements. template <typename T> @@ -90,6 +95,7 @@ // These should only be accessed from |element_message_loop_|. base::WeakPtr<dom::Element> element_; ElementMapping* element_mapping_; + KeyboardEventInjector keyboard_injector_; scoped_refptr<base::MessageLoopProxy> element_message_loop_; friend class WindowDriver;
diff --git a/src/cobalt/webdriver/keyboard.cc b/src/cobalt/webdriver/keyboard.cc index c69496f..32d4fbc 100644 --- a/src/cobalt/webdriver/keyboard.cc +++ b/src/cobalt/webdriver/keyboard.cc
@@ -421,7 +421,7 @@ KeyLocationCode location) { const bool kIsRepeat = false; uint32 modifiers = GetModifierStateBitfield(); - event_vector_->push_back(new dom::KeyboardEvent( + event_vector_->push_back(dom::KeyboardEvent::Data( type, location, modifiers, key_code, char_code, kIsRepeat)); }
diff --git a/src/cobalt/webdriver/keyboard.h b/src/cobalt/webdriver/keyboard.h index feeab6f..57a5c5f 100644 --- a/src/cobalt/webdriver/keyboard.h +++ b/src/cobalt/webdriver/keyboard.h
@@ -32,7 +32,8 @@ kReleaseModifiers, kKeepModifiers, }; - typedef std::vector<scoped_refptr<dom::KeyboardEvent> > KeyboardEventVector; + typedef std::vector<dom::KeyboardEvent::Data> + KeyboardEventVector; static void TranslateToKeyEvents(const std::string& utf8_keys, TerminationBehaviour termination_behaviour, KeyboardEventVector* out_events);
diff --git a/src/cobalt/webdriver/keyboard_test.cc b/src/cobalt/webdriver/keyboard_test.cc index 1f71598..7994bd5 100644 --- a/src/cobalt/webdriver/keyboard_test.cc +++ b/src/cobalt/webdriver/keyboard_test.cc
@@ -31,25 +31,34 @@ namespace webdriver { namespace { -int32 GetKeyCode(const scoped_refptr<dom::KeyboardEvent>& event) { - DCHECK(event); - return event->key_code(); +int32 GetKeyCode(const dom::KeyboardEvent::Data& event) { + scoped_refptr<dom::KeyboardEvent> keyboard_event( + new dom::KeyboardEvent(event)); + return keyboard_event->key_code(); } -int32 GetCharCode(const scoped_refptr<dom::KeyboardEvent>& event) { - return event->char_code(); +int32 GetCharCode(const dom::KeyboardEvent::Data& event) { + scoped_refptr<dom::KeyboardEvent> keyboard_event( + new dom::KeyboardEvent(event)); + return keyboard_event->char_code(); } -uint32 GetModifierBitfield(const scoped_refptr<dom::KeyboardEvent>& event) { - return event->modifiers(); +uint32 GetModifierBitfield(const dom::KeyboardEvent::Data& event) { + scoped_refptr<dom::KeyboardEvent> keyboard_event( + new dom::KeyboardEvent(event)); + return keyboard_event->modifiers(); } -std::string GetType(const scoped_refptr<dom::KeyboardEvent>& event) { - return event->type().c_str(); +std::string GetType(const dom::KeyboardEvent::Data& event) { + scoped_refptr<dom::KeyboardEvent> keyboard_event( + new dom::KeyboardEvent(event)); + return keyboard_event->type().c_str(); } -int GetLocation(const scoped_refptr<dom::KeyboardEvent>& event) { - return event->location(); +int GetLocation(const dom::KeyboardEvent::Data& event) { + scoped_refptr<dom::KeyboardEvent> keyboard_event( + new dom::KeyboardEvent(event)); + return keyboard_event->location(); } class KeyboardTest : public ::testing::Test {
diff --git a/src/cobalt/webdriver/protocol/server_status.cc b/src/cobalt/webdriver/protocol/server_status.cc index e98ebe2..bcb283c 100644 --- a/src/cobalt/webdriver/protocol/server_status.cc +++ b/src/cobalt/webdriver/protocol/server_status.cc
@@ -16,9 +16,6 @@ #include "cobalt/webdriver/protocol/server_status.h" -// TODO: Support running WebDriver on platforms other than Linux. -#include <sys/utsname.h> - #include "cobalt/version.h" namespace cobalt { @@ -26,11 +23,26 @@ namespace protocol { ServerStatus::ServerStatus() { - struct utsname name_buffer; - if (uname(&name_buffer) == 0) { - os_name_ = name_buffer.sysname; - os_version_ = name_buffer.version; - os_arch_ = name_buffer.machine; + const size_t kSystemPropertyMaxLength = 1024; + char value[kSystemPropertyMaxLength]; + bool result; + + result = SbSystemGetProperty(kSbSystemPropertyPlatformName, value, + kSystemPropertyMaxLength); + if (result) { + os_name_ = value; + } + + result = SbSystemGetProperty(kSbSystemPropertyFirmwareVersion, value, + kSystemPropertyMaxLength); + if (result) { + os_version_ = value; + } + + result = SbSystemGetProperty(kSbSystemPropertyChipsetModelNumber, value, + kSystemPropertyMaxLength); + if (result) { + os_arch_ = value; } build_time_ = __DATE__ " (" __TIME__ ")"; build_version_ = COBALT_VERSION; @@ -42,9 +54,16 @@ build_value->SetString("version", status.build_version_); scoped_ptr<base::DictionaryValue> os_value(new base::DictionaryValue()); - os_value->SetString("arch", status.os_arch_); - os_value->SetString("name", status.os_name_); - os_value->SetString("version", status.os_version_); + + if (status.os_arch_) { + os_value->SetString("arch", *status.os_arch_); + } + if (status.os_name_) { + os_value->SetString("name", *status.os_name_); + } + if (status.os_version_) { + os_value->SetString("version", *status.os_version_); + } scoped_ptr<base::DictionaryValue> status_value(new base::DictionaryValue()); status_value->Set("os", os_value.release());
diff --git a/src/cobalt/webdriver/protocol/server_status.h b/src/cobalt/webdriver/protocol/server_status.h index dcd825a..cdef9a4 100644 --- a/src/cobalt/webdriver/protocol/server_status.h +++ b/src/cobalt/webdriver/protocol/server_status.h
@@ -20,6 +20,7 @@ #include <string> #include "base/memory/scoped_ptr.h" +#include "base/optional.h" #include "base/values.h" namespace cobalt { @@ -36,9 +37,9 @@ static scoped_ptr<base::Value> ToValue(const ServerStatus& status); private: - std::string os_name_; - std::string os_arch_; - std::string os_version_; + base::optional<std::string> os_name_; + base::optional<std::string> os_arch_; + base::optional<std::string> os_version_; std::string build_time_; std::string build_version_; };
diff --git a/src/cobalt/webdriver/window_driver.cc b/src/cobalt/webdriver/window_driver.cc index 3e77e54..a21d3b6 100644 --- a/src/cobalt/webdriver/window_driver.cc +++ b/src/cobalt/webdriver/window_driver.cc
@@ -158,10 +158,12 @@ const protocol::WindowId& window_id, const base::WeakPtr<dom::Window>& window, const GetGlobalEnvironmentFunction& get_global_environment_function, + KeyboardEventInjector keyboard_injector, const scoped_refptr<base::MessageLoopProxy>& message_loop) : window_id_(window_id), window_(window), get_global_environment_(get_global_environment_function), + keyboard_injector_(keyboard_injector), window_message_loop_(message_loop), element_driver_map_deleter_(&element_drivers_), next_element_id_(0) { @@ -351,6 +353,7 @@ std::pair<ElementDriverMapIt, bool> pair_it = element_drivers_.insert(std::make_pair( element_id.id(), new ElementDriver(element_id, weak_element, this, + keyboard_injector_, window_message_loop_))); DCHECK(pair_it.second) << "An ElementDriver was already mapped to the element id: " @@ -418,7 +421,7 @@ } util::CommandResult<void> WindowDriver::SendKeysInternal( - scoped_ptr<KeyboardEventVector> events) { + scoped_ptr<Keyboard::KeyboardEventVector> events) { typedef util::CommandResult<void> CommandResult; DCHECK_EQ(base::MessageLoopProxy::current(), window_message_loop_); if (!window_) { @@ -426,8 +429,7 @@ } for (size_t i = 0; i < events->size(); ++i) { - // InjectEvent will send to the focused element. - window_->InjectEvent((*events)[i]); + keyboard_injector_.Run(scoped_refptr<dom::Element>(), (*events)[i]); } return CommandResult(protocol::Response::kSuccess); }
diff --git a/src/cobalt/webdriver/window_driver.h b/src/cobalt/webdriver/window_driver.h index ae03a9f..f67d272 100644 --- a/src/cobalt/webdriver/window_driver.h +++ b/src/cobalt/webdriver/window_driver.h
@@ -34,6 +34,7 @@ #include "cobalt/dom/window.h" #include "cobalt/webdriver/element_driver.h" #include "cobalt/webdriver/element_mapping.h" +#include "cobalt/webdriver/keyboard.h" #include "cobalt/webdriver/protocol/cookie.h" #include "cobalt/webdriver/protocol/frame_id.h" #include "cobalt/webdriver/protocol/keys.h" @@ -54,11 +55,15 @@ // will map to a method on this class. class WindowDriver : private ElementMapping { public: + typedef base::Callback<void(scoped_refptr<dom::Element>, + const dom::KeyboardEvent::Data&)> + KeyboardEventInjector; typedef base::Callback<scoped_refptr<script::GlobalEnvironment>()> GetGlobalEnvironmentFunction; WindowDriver(const protocol::WindowId& window_id, const base::WeakPtr<dom::Window>& window, const GetGlobalEnvironmentFunction& get_global_environment, + KeyboardEventInjector keyboard_injector, const scoped_refptr<base::MessageLoopProxy>& message_loop); ~WindowDriver(); const protocol::WindowId& window_id() { return window_id_; } @@ -89,7 +94,6 @@ typedef base::hash_map<std::string, ElementDriver*> ElementDriverMap; typedef ElementDriverMap::iterator ElementDriverMapIt; typedef std::vector<protocol::ElementId> ElementIdVector; - typedef std::vector<scoped_refptr<dom::KeyboardEvent> > KeyboardEventVector; // ScriptExecutor::ElementMapping implementation. protocol::ElementId ElementToId( @@ -116,7 +120,7 @@ const protocol::Script& script); util::CommandResult<void> SendKeysInternal( - scoped_ptr<KeyboardEventVector> keyboard_events); + scoped_ptr<Keyboard::KeyboardEventVector> keyboard_events); util::CommandResult<void> NavigateInternal(const GURL& url); @@ -129,6 +133,8 @@ // Bound to the WebDriver thread. base::ThreadChecker thread_checker_; + KeyboardEventInjector keyboard_injector_; + // Anything that interacts with the window must be run on this message loop. scoped_refptr<base::MessageLoopProxy> window_message_loop_;
diff --git a/src/cobalt/webdriver_benchmarks/__init__.py b/src/cobalt/webdriver_benchmarks/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/cobalt/webdriver_benchmarks/__init__.py
diff --git a/src/cobalt/webdriver_benchmarks/partial_layout_benchmark.py b/src/cobalt/webdriver_benchmarks/partial_layout_benchmark.py new file mode 100755 index 0000000..41503c6 --- /dev/null +++ b/src/cobalt/webdriver_benchmarks/partial_layout_benchmark.py
@@ -0,0 +1,221 @@ +#!/usr/bin/python +"""Webdriver-based benchmarks for partial layout. + +Benchmarks for partial layout changes in Cobalt. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import argparse +import importlib +import os +import re +import socket +import sys +import threading +import unittest + +arg_parser = argparse.ArgumentParser( + description="Runs Webdriver-based Cobalt benchmarks") +arg_parser.add_argument( + "-p", "--platform", + help="Cobalt platform, eg 'linux-x64x11'." + "Fetched from environment if absent.") +arg_parser.add_argument( + "-e", "--executable", + help="Path to cobalt executable. " + "Auto-derived if absent.") +arg_parser.add_argument( + "-c", "--config", + choices=["debug", "devel", "qa", "gold"], + help="Build config (eg, 'qa' or 'devel'). Not used if " + "--executable is specified. Fetched from environment " + "if needed and absent.") +arg_parser.add_argument( + "-d", "--devkit_name", + help="Devkit or IP address for app_launcher." + "Current hostname used if absent.") +arg_parser.add_argument( + "-o", "--log_file", help="Logfile pathname. stdout if absent.") + +# Pattern to match Cobalt log line for when the WebDriver port has been +# opened. +RE_WEBDRIVER_LISTEN = re.compile(r"Starting WebDriver server on port (\d+)$") + +COBALT_WEBDRIVER_CAPABILITIES = { + "browserName": "cobalt", + "javascriptEnabled": True, + "platform": "LINUX" +} + +_webdriver = None + + +def GetWebDriver(): + """Returns the active connect WebDriver instance.""" + return _webdriver + + +def ImportSeleniumModule(submodule=None): + """Dynamically imports a selenium.webdriver submodule. + + This is done because selenium 3.0 is not commonly pre-installed + on workstations, and we want to have a friendly error message for that + case. + + Args: + submodule: module subpath underneath "selenium.webdriver" + Returns: + appropriate module + """ + if submodule: + module_path = ".".join(("selenium", submodule)) + else: + module_path = "selenium" + # As of this writing, Google uses selenium 3.0.0b2 internally, so + # thats what we will target here as well. + try: + module = importlib.import_module(module_path) + if submodule is None: + # Only the top-level module has __version__ + if not module.__version__.startswith("3.0"): + raise ImportError("Not version 3.0.x") + except ImportError: + sys.stderr.write("Could not import {}\n" + "Please install selenium >= 3.0.0b2.\n" + "Commonly: \"sudo pip install 'selenium>=3.0.0b2'\"\n" + .format(module_path)) + sys.exit(1) + return module + + +class CobaltRunner(object): + """Runs a Cobalt browser w/ a WebDriver client attached.""" + test_script_started = threading.Event() + should_exit = threading.Event() + selenium_webdriver_module = None + webdriver = None + launcher = None + log_file_path = None + thread = None + + def __init__(self, platform, executable, devkit_name, log_file_path): + self.selenium_webdriver_module = ImportSeleniumModule("webdriver") + + script_path = os.path.dirname(__file__) + sys.path.append(script_path + "/../../tools/lbshell/") + app_launcher = importlib.import_module("app_launcher") + self.launcher = app_launcher.CreateLauncher( + platform, executable, devkit_name=devkit_name) + + self.launcher.SetArgs(["--enable_webdriver"]) + self.launcher.SetOutputCallback(self._HandleLine) + self.log_file_path = log_file_path + + def __enter__(self): + self.thread = threading.Thread(target=self.Run) + self.thread.start() + self.WaitForStart() + + def __exit__(self, exc_type, exc_value, traceback): + self.SetShouldExit() + self.thread.join() + + def _HandleLine(self, line): + """Internal log line callback.""" + + done = self.should_exit.is_set() + # Wait for WebDriver port here then connect + if self.test_script_started.is_set(): + return done + + match = RE_WEBDRIVER_LISTEN.search(line) + if not match: + return done + + port = match.group(1) + self._StartWebdriver(port) + return done + + def SetShouldExit(self): + """Indicates cobalt process should exit. Done at next log line output.""" + self.should_exit.set() + + def _GetIPAddress(self): + return self.launcher.GetIPAddress() + + def _StartWebdriver(self, port): + global _webdriver + url = "http://{}:{}/".format(self._GetIPAddress(), port) + self.webdriver = self.selenium_webdriver_module.Remote( + url, COBALT_WEBDRIVER_CAPABILITIES) + _webdriver = self.webdriver + self.test_script_started.set() + + def WaitForStart(self): + """Waits for the webdriver client to attach to cobalt.""" + self.test_script_started.wait() + + def Run(self): + """Thread run routine.""" + + # Use stdout if log_file_path is unspecified + # If log_file_path is specified, make sure to close it + to_close = None + try: + if self.log_file_path: + log_file = open(self.log_file_path, "w") + to_close = log_file + else: + log_file = sys.stdout + + self.launcher.SetOutputFile(log_file) + self.launcher.Run() + finally: + if to_close: + to_close.close() + return 0 + + +def GetCobaltExecutablePath(platform, config): + """Auto-derives a path to a cobalt executable.""" + if config is None: + try: + config = os.environ["BUILD_TYPE"] + except KeyError: + sys.stderr.write("Must specify --config or --executable\n") + sys.exit(1) + script_dir = os.path.dirname(os.path.realpath(__file__)) + out_dir = os.path.join(script_dir, "..", "..", "out") + executable_directory = os.path.join(out_dir, "{}_{}".format(platform, config)) + return os.path.join(executable_directory, "cobalt") + + +def main(): + args = arg_parser.parse_args() + + platform = args.platform + if platform is None: + try: + platform = os.environ["BUILD_PLATFORM"] + except KeyError: + sys.stderr.write("Must specify --platform\n") + sys.exit(1) + + executable = args.executable + if executable is None: + executable = GetCobaltExecutablePath(platform, args.config) + + devkit_name = args.devkit_name + if devkit_name is None: + devkit_name = socket.gethostname() + + with CobaltRunner(platform, executable, devkit_name, args.log_file): + unittest.main() + return 0 + + +if __name__ == "__main__": + sys.exit(main())
diff --git a/src/cobalt/webdriver_benchmarks/tests/__init__.py b/src/cobalt/webdriver_benchmarks/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/cobalt/webdriver_benchmarks/tests/__init__.py
diff --git a/src/cobalt/webdriver_benchmarks/tests/shelf.py b/src/cobalt/webdriver_benchmarks/tests/shelf.py new file mode 100755 index 0000000..b81478b --- /dev/null +++ b/src/cobalt/webdriver_benchmarks/tests/shelf.py
@@ -0,0 +1,60 @@ +#!/usr/bin/python +"""Simple shelf navigation test.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import sys +import time + +# The parent directory is a module +sys.path.insert(0, os.path.dirname(os.path.dirname( + os.path.realpath(__file__)))) + +# pylint: disable=C6204,C6203 +import tv +import tv_testcase +import partial_layout_benchmark + +# selenium imports +keys = partial_layout_benchmark.ImportSeleniumModule("webdriver.common.keys") + +DEFAULT_SHELVES_COUNT = 10 +SHELF_ITEMS_COUNT = 10 + + +class ShelfTest(tv_testcase.TvTestCase): + + def _wait_for_layout(self): + while int(self.get_webdriver().execute_script( + "return h5vcc.cVal.getValue('Event.MainWebModule.IsProcessing')")): + time.sleep(0.1) + + def test_simple(self): + self.load_tv() + self.assert_displayed(tv.FOCUSED_SHELF) + + print(str(self.get_webdriver().execute_script( + "h5vcc.system.recordStats = true"))) + + for _ in xrange(DEFAULT_SHELVES_COUNT): + self.send_keys(tv.FOCUSED_SHELF, keys.Keys.ARROW_DOWN) + self.poll_until_found(tv.FOCUSED_SHELF) + self.assert_displayed(tv.FOCUSED_SHELF_TITLE) + self._wait_for_layout() + + for _ in xrange(SHELF_ITEMS_COUNT): + self.send_keys(tv.FOCUSED_TILE, keys.Keys.ARROW_RIGHT) + self.poll_until_found(tv.FOCUSED_TILE) + self.assert_displayed(tv.FOCUSED_SHELF_TITLE) + self._wait_for_layout() + + print("ShelfTest event durations" + + str(self.get_webdriver().execute_script( + "return h5vcc.cVal.getValue(" + "'Event.Durations.MainWebModule.KeyUp')"))) + +if __name__ == "__main__": + tv_testcase.main()
diff --git a/src/cobalt/webdriver_benchmarks/tv.py b/src/cobalt/webdriver_benchmarks/tv.py new file mode 100644 index 0000000..f9c0411 --- /dev/null +++ b/src/cobalt/webdriver_benchmarks/tv.py
@@ -0,0 +1,10 @@ +"""CSS Constants.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +FOCUSED_GUIDE = '.focused.guide' +FOCUSED_SHELF = '.focused.selected.shelf' +FOCUSED_SHELF_TITLE = '.focused.selected.shelf .shelf-header-title .main' +FOCUSED_TILE = '.focused.tile'
diff --git a/src/cobalt/webdriver_benchmarks/tv_testcase.py b/src/cobalt/webdriver_benchmarks/tv_testcase.py new file mode 100644 index 0000000..39bfe41 --- /dev/null +++ b/src/cobalt/webdriver_benchmarks/tv_testcase.py
@@ -0,0 +1,149 @@ +"""Base class for WebDriver tests.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import sys +import time +import unittest +import urlparse + +# This directory is a package +sys.path.insert(0, os.path.abspath(".")) +# pylint: disable=C6204,C6203 +import partial_layout_benchmark +import tv + +# selenium imports +# pylint: disable=C0103 +WebDriverWait = partial_layout_benchmark.ImportSeleniumModule( + submodule="webdriver.support.ui").WebDriverWait + +ElementNotVisibleException = ( + partial_layout_benchmark.ImportSeleniumModule( + submodule="common.exceptions").ElementNotVisibleException) + +BASE_URL = "https://www.youtube.com/tv" +PAGE_LOAD_WAIT_SECONDS = 30 + + +class TvTestCase(unittest.TestCase): + """Base class for WebDriver tests. + + Style note: snake_case is used for function names here so as to match + with an internal class with the same name. + """ + + def get_webdriver(self): + return partial_layout_benchmark.GetWebDriver() + + def goto(self, path): + """Goes to a path off of BASE_URL. + + Args: + path: URL path + Raises: + Underlying WebDriver exceptions + """ + self.get_webdriver().get(urlparse.urljoin(BASE_URL, path)) + + def load_tv(self): + """Loads the main TV page and waits for it to display. + + Raises: + Underlying WebDriver exceptions + """ + self.goto("") + # Note that the internal tests use "expect_transition" which is + # a mechanism that sets a maximum timeout for a "@with_retries" + # decorator-driven success retry loop for subsequent webdriver requests. + # + # We'll skip that sophistication here. + self.poll_until_found(tv.FOCUSED_SHELF) + + def poll_until_found(self, css_selector): + """Polls until an element is found. + + Args: + css_selector: A CSS selector + Raises: + Underlying WebDriver exceptions + """ + start_time = time.time() + while ((not self.find_elements(css_selector)) and + (time.time() - start_time < PAGE_LOAD_WAIT_SECONDS)): + time.sleep(1) + self.assert_displayed(css_selector) + + def unique_find(self, unique_selector): + """Finds and returns a uniquely selected element. + + Args: + unique_selector: A CSS selector that will select only one element + Raises: + Underlying WebDriver exceptions + AssertError: the element isn't unique + Returns: + Element + """ + return self.find_elements(unique_selector, expected_num=1)[0] + + def assert_displayed(self, css_selector): + """Asserts that an element is displayed. + + Args: + css_selector: A CSS selector + Raises: + Underlying WebDriver exceptions + AssertError: the element isn't found + """ + # TODO does not actually assert that it's visible, like webdriver.py + # probably does. + self.assertTrue(self.unique_find(css_selector)) + + def find_elements(self, css_selector, expected_num=None): + """Finds elements based on a selector. + + Args: + css_selector: A CSS selector + expected_num: Expected number of matching elements + Raises: + Underlying WebDriver exceptions + AssertError: expected_num isn't met + Returns: + Array of selected elements + """ + elements = self.get_webdriver().find_elements_by_css_selector(css_selector) + if expected_num is not None: + self.assertEqual(len(elements), expected_num) + return elements + + def send_keys(self, css_selector, keys): + """Sends keys to an element uniquely identified by a selector. + + This method retries for a timeout period if the selected element + could not be immediately found. If the retries do not succeed, + the underlying exception is passed through. + + Raises: + Underlying WebDriver exceptions + """ + start_time = time.time() + while True: + try: + element = self.unique_find(css_selector) + element.send_keys(keys) + return + except ElementNotVisibleException: + # TODO ElementNotVisibleException seems to be considered + # a "falsy" exception in the internal tests, which seems to mean + # it would not be retried. But here, it seems essential. + if time.time() - start_time >= PAGE_LOAD_WAIT_SECONDS: + raise + time.sleep(1) + + +def main(): + partial_layout_benchmark.main()
diff --git a/src/cobalt/xhr/xml_http_request_event_target.cc b/src/cobalt/xhr/xml_http_request_event_target.cc index ef9eedb..20b9eeb 100644 --- a/src/cobalt/xhr/xml_http_request_event_target.cc +++ b/src/cobalt/xhr/xml_http_request_event_target.cc
@@ -64,37 +64,65 @@ void XMLHttpRequestEventTarget::set_onabort( const EventListenerScriptObject& listener) { - onabort_listener_.emplace(this, listener); + if (listener.IsNull()) { + onabort_listener_ = base::nullopt; + } else { + onabort_listener_.emplace(this, listener); + } SetAttributeEventListener(base::Tokens::abort(), listener); } void XMLHttpRequestEventTarget::set_onerror( const EventListenerScriptObject& listener) { - onerror_listener_.emplace(this, listener); + if (listener.IsNull()) { + onerror_listener_ = base::nullopt; + } else { + onerror_listener_.emplace(this, listener); + } SetAttributeEventListener(base::Tokens::error(), listener); } void XMLHttpRequestEventTarget::set_onload( const EventListenerScriptObject& listener) { - onload_listener_.emplace(this, listener); + if (listener.IsNull()) { + onload_listener_ = base::nullopt; + } else { + onload_listener_.emplace(this, listener); + } SetAttributeEventListener(base::Tokens::load(), listener); } void XMLHttpRequestEventTarget::set_onloadend( const EventListenerScriptObject& listener) { - onloadend_listener_.emplace(this, listener); + if (listener.IsNull()) { + onloadend_listener_ = base::nullopt; + } else { + onloadend_listener_.emplace(this, listener); + } SetAttributeEventListener(base::Tokens::loadend(), listener); } void XMLHttpRequestEventTarget::set_onloadstart( const EventListenerScriptObject& listener) { - onloadstart_listener_.emplace(this, listener); + if (listener.IsNull()) { + onloadstart_listener_ = base::nullopt; + } else { + onloadstart_listener_.emplace(this, listener); + } SetAttributeEventListener(base::Tokens::loadstart(), listener); } void XMLHttpRequestEventTarget::set_onprogress( const EventListenerScriptObject& listener) { - onprogress_listener_.emplace(this, listener); + if (listener.IsNull()) { + onprogress_listener_ = base::nullopt; + } else { + onprogress_listener_.emplace(this, listener); + } SetAttributeEventListener(base::Tokens::progress(), listener); } void XMLHttpRequestEventTarget::set_ontimeout( const EventListenerScriptObject& listener) { - ontimeout_listener_.emplace(this, listener); + if (listener.IsNull()) { + ontimeout_listener_ = base::nullopt; + } else { + ontimeout_listener_.emplace(this, listener); + } SetAttributeEventListener(base::Tokens::timeout(), listener); } } // namespace xhr
diff --git a/src/glimp/gles/program.cc b/src/glimp/gles/program.cc index ff02fbe..0309920 100644 --- a/src/glimp/gles/program.cc +++ b/src/glimp/gles/program.cc
@@ -163,7 +163,7 @@ // Clear all stored uniform information and values. void Program::ClearUniforms() { for (size_t i = 0; i < uniforms_.size(); ++i) { - SbMemoryFree(uniforms_[i].data); + SbMemoryDeallocate(uniforms_[i].data); } uniforms_.clear(); active_uniform_locations_.clear(); @@ -206,7 +206,7 @@ // We need to reallocate data if the information has changed. uniform->info = new_info; - SbMemoryFree(uniform->data); + SbMemoryDeallocate(uniform->data); uniform->data = SbMemoryAllocate(DataSizeForType(count, elem_size, type)); } SbMemoryCopy(uniform->data, v, DataSizeForType(count, elem_size, type));
diff --git a/src/media/base/decoder_buffer.cc b/src/media/base/decoder_buffer.cc index 31790ff..14c4151 100644 --- a/src/media/base/decoder_buffer.cc +++ b/src/media/base/decoder_buffer.cc
@@ -23,8 +23,8 @@ // static scoped_refptr<DecoderBuffer> DecoderBuffer::CreateEOSBuffer( base::TimeDelta timestamp) { - scoped_refptr<DecoderBuffer> eos = scoped_refptr<DecoderBuffer>( - new DecoderBuffer(NULL, 0)); + scoped_refptr<DecoderBuffer> eos = + scoped_refptr<DecoderBuffer>(new DecoderBuffer(NULL, 0, true)); eos->SetTimestamp(timestamp); return eos; } @@ -34,12 +34,15 @@ size_ = size; } -DecoderBuffer::DecoderBuffer(uint8* reusable_buffer, size_t size) - : Buffer(kNoTimestamp(), kInfiniteDuration()) - , buffer_(reusable_buffer) - , size_(size) - , allocated_size_(size) - , is_decrypted_(false) { +DecoderBuffer::DecoderBuffer(uint8* reusable_buffer, + size_t size, + bool is_keyframe) + : Buffer(kNoTimestamp(), kInfiniteDuration()), + buffer_(reusable_buffer), + size_(size), + allocated_size_(size), + is_decrypted_(false), + is_keyframe_(is_keyframe) { if (buffer_) { // Retain a reference to the buffer factory, to ensure that we do not // outlive it.
diff --git a/src/media/base/decoder_buffer.h b/src/media/base/decoder_buffer.h index 26e524f..16f5cce 100644 --- a/src/media/base/decoder_buffer.h +++ b/src/media/base/decoder_buffer.h
@@ -33,12 +33,14 @@ base::TimeDelta timestamp); // Buffer implementation. - virtual const uint8* GetData() const OVERRIDE { return buffer_; } + const uint8* GetData() const OVERRIDE { return buffer_; } // Data size can be less than allocated size after ShrinkTo is called. - virtual int GetDataSize() const OVERRIDE { return static_cast<int>(size_); } + int GetDataSize() const OVERRIDE { return static_cast<int>(size_); } + int GetAllocatedSize() const { return static_cast<int>(allocated_size_); } // This is used by the data that we don't know the exact size before reading. void ShrinkTo(int size); + bool IsKeyframe() const { return is_keyframe_; } // Returns a read-write pointer to the buffer data. virtual uint8* GetWritableData() { return buffer_; } @@ -55,7 +57,7 @@ friend class ShellBufferFactory; // Should only be called by ShellBufferFactory, consumers should use // ShellBufferFactory::AllocateBuffer to make a DecoderBuffer. - DecoderBuffer(uint8* reusable_buffer, size_t size); + DecoderBuffer(uint8* reusable_buffer, size_t size, bool is_keyframe); // For deferred allocation create a shell buffer with buffer_ NULL but a // non-zero size. Then we use the SetBuffer() method below to actually // set the reusable buffer pointer when it becomes available @@ -68,6 +70,7 @@ scoped_refptr<ShellBufferFactory> buffer_factory_; scoped_ptr<DecryptConfig> decrypt_config_; bool is_decrypted_; + bool is_keyframe_; DISALLOW_IMPLICIT_CONSTRUCTORS(DecoderBuffer); };
diff --git a/src/media/base/decoder_buffer_cache.cc b/src/media/base/decoder_buffer_cache.cc new file mode 100644 index 0000000..92d35ee --- /dev/null +++ b/src/media/base/decoder_buffer_cache.cc
@@ -0,0 +1,126 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "media/base/decoder_buffer_cache.h" + +namespace media { + +DecoderBufferCache::DecoderBufferCache() + : audio_buffer_index_(0), video_buffer_index_(0) {} + +void DecoderBufferCache::AddBuffer(DemuxerStream::Type type, + const scoped_refptr<DecoderBuffer>& buffer) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (type == DemuxerStream::AUDIO) { + audio_buffers_.push_back(buffer); + if (buffer->IsKeyframe()) { + audio_key_frame_timestamps_.push_back(buffer->GetTimestamp()); + } + } else { + DCHECK_EQ(type, DemuxerStream::VIDEO); + video_buffers_.push_back(buffer); + if (buffer->IsKeyframe()) { + video_key_frame_timestamps_.push_back(buffer->GetTimestamp()); + } + } +} + +void DecoderBufferCache::ClearSegmentsBeforeMediaTime( + base::TimeDelta media_time) { + DCHECK(thread_checker_.CalledOnValidThread()); + + ClearSegmentsBeforeMediaTime(media_time, &audio_buffers_, + &audio_key_frame_timestamps_); + ClearSegmentsBeforeMediaTime(media_time, &video_buffers_, + &video_key_frame_timestamps_); +} + +void DecoderBufferCache::ClearAll() { + DCHECK(thread_checker_.CalledOnValidThread()); + + audio_buffers_.clear(); + audio_key_frame_timestamps_.clear(); + video_buffers_.clear(); + video_key_frame_timestamps_.clear(); +} + +void DecoderBufferCache::StartResuming() { + DCHECK(thread_checker_.CalledOnValidThread()); + + audio_buffer_index_ = 0; + video_buffer_index_ = 0; +} + +scoped_refptr<DecoderBuffer> DecoderBufferCache::GetBuffer( + DemuxerStream::Type type) const { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (type == DemuxerStream::AUDIO) { + if (audio_buffer_index_ < audio_buffers_.size()) { + return audio_buffers_[audio_buffer_index_]; + } + return NULL; + } + + DCHECK_EQ(type, DemuxerStream::VIDEO); + if (video_buffer_index_ < video_buffers_.size()) { + return video_buffers_[video_buffer_index_]; + } + return NULL; +} + +void DecoderBufferCache::AdvanceToNextBuffer(DemuxerStream::Type type) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (type == DemuxerStream::AUDIO) { + ++audio_buffer_index_; + } else { + DCHECK_EQ(type, DemuxerStream::VIDEO); + ++video_buffer_index_; + } +} + +// static +void DecoderBufferCache::ClearSegmentsBeforeMediaTime( + base::TimeDelta media_time, + Buffers* buffers, + KeyFrameTimestamps* key_frame_timestamps) { + // Use K to denote a key frame and N for non-key frame. If the cache contains + // K N N N N N N N N K N N N N N N N N K N N N N N N N N + // | + // media_time + // Then we should remove everything before the key frame before the + // |media_time| and turn the cache into: + // K N N N N N N N N K N N N N N N N N + // | + // media_time + // So we need at least two keyframes before we can remove any frames. + while (key_frame_timestamps->size() > 1 && + key_frame_timestamps->at(1) <= media_time) { + key_frame_timestamps->erase(key_frame_timestamps->begin()); + } + if (key_frame_timestamps->empty()) { + return; + } + while (scoped_refptr<DecoderBuffer> buffer = buffers->front()) { + if (buffer->IsKeyframe() && + buffer->GetTimestamp() == key_frame_timestamps->front()) { + break; + } + buffers->pop_front(); + } +} + +} // namespace media
diff --git a/src/media/base/decoder_buffer_cache.h b/src/media/base/decoder_buffer_cache.h new file mode 100644 index 0000000..49ba5ec --- /dev/null +++ b/src/media/base/decoder_buffer_cache.h
@@ -0,0 +1,70 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MEDIA_BASE_DECODER_BUFFER_CACHE_H_ +#define MEDIA_BASE_DECODER_BUFFER_CACHE_H_ + +#include <deque> + +#include "base/memory/ref_counted.h" +#include "base/threading/thread_checker.h" +#include "base/time.h" +#include "media/base/decoder_buffer.h" +#include "media/base/demuxer_stream.h" + +namespace media { + +// This class can be used to hold media buffers in decoding order. It also +// provides function that given a media time, the function will find a key frame +// before the media time and clear all buffers before the key frame. This class +// can be used to "replay" the video from the current playback position and can +// be useful to implement suspend/resume. +class DecoderBufferCache { + public: + DecoderBufferCache(); + + void AddBuffer(DemuxerStream::Type type, + const scoped_refptr<DecoderBuffer>& buffer); + void ClearSegmentsBeforeMediaTime(base::TimeDelta media_time); + void ClearAll(); + + // Start resuming, reset indices to audio/video buffers to the very beginning. + void StartResuming(); + scoped_refptr<DecoderBuffer> GetBuffer(DemuxerStream::Type type) const; + void AdvanceToNextBuffer(DemuxerStream::Type type); + + private: + typedef std::deque<scoped_refptr<DecoderBuffer> > Buffers; + typedef std::deque<base::TimeDelta> KeyFrameTimestamps; + + static void ClearSegmentsBeforeMediaTime( + base::TimeDelta media_time, + Buffers* buffers, + KeyFrameTimestamps* key_frame_timestamps); + + base::ThreadChecker thread_checker_; + + Buffers audio_buffers_; + KeyFrameTimestamps audio_key_frame_timestamps_; + + Buffers video_buffers_; + KeyFrameTimestamps video_key_frame_timestamps_; + + size_t audio_buffer_index_; + size_t video_buffer_index_; +}; + +} // namespace media + +#endif // MEDIA_BASE_DECODER_BUFFER_CACHE_H_
diff --git a/src/media/base/decoder_buffer_pool.cc b/src/media/base/decoder_buffer_pool.cc index 3982108..0d52b2a 100644 --- a/src/media/base/decoder_buffer_pool.cc +++ b/src/media/base/decoder_buffer_pool.cc
@@ -47,7 +47,8 @@ scoped_refptr<DecoderBuffer> DecoderBufferPool::AllocateFromShellBufferFactory( size_t size_in_bytes) { - return ShellBufferFactory::Instance()->AllocateBufferNow(size_in_bytes); + return ShellBufferFactory::Instance()->AllocateBufferNow(size_in_bytes, + false); } } // namespace media
diff --git a/src/media/base/pipeline.h b/src/media/base/pipeline.h index 0912c6b..ec4bb7c 100644 --- a/src/media/base/pipeline.h +++ b/src/media/base/pipeline.h
@@ -77,6 +77,9 @@ virtual ~Pipeline() {} + virtual void Suspend() {} + virtual void Resume() {} + // Build a pipeline to using the given filter collection to construct a filter // chain, executing |seek_cb| when the initial seek/preroll has completed. //
diff --git a/src/media/base/sbplayer_pipeline.cc b/src/media/base/sbplayer_pipeline.cc index 7c0f067..b9d2262 100644 --- a/src/media/base/sbplayer_pipeline.cc +++ b/src/media/base/sbplayer_pipeline.cc
@@ -12,15 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include <map> #include <vector> #include "base/basictypes.h" // For COMPILE_ASSERT #include "base/bind.h" #include "base/callback_helpers.h" #include "base/logging.h" +#include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/synchronization/lock.h" +#include "base/synchronization/waitable_event.h" #include "base/time.h" #include "media/base/audio_decoder_config.h" #include "media/base/bind_to_loop.h" @@ -34,9 +35,10 @@ #include "media/base/pipeline.h" #include "media/base/pipeline_status.h" #include "media/base/ranges.h" +#include "media/base/sbplayer_set_bounds_helper.h" +#include "media/base/starboard_player.h" #include "media/base/video_decoder_config.h" #include "media/crypto/starboard_decryptor.h" -#include "starboard/player.h" #include "ui/gfx/size.h" namespace media { @@ -48,102 +50,6 @@ namespace { -SbMediaAudioCodec SbMediaAudioCodecFromMediaAudioCodec(AudioCodec codec) { - if (codec == kCodecAAC) { - return kSbMediaAudioCodecAac; - } else if (codec == kCodecVorbis) { - return kSbMediaAudioCodecVorbis; - } else if (codec == kCodecOpus) { - return kSbMediaAudioCodecOpus; - } - DLOG(ERROR) << "Unsupported audio codec " << codec; - return kSbMediaAudioCodecNone; -} - -SbMediaVideoCodec SbMediaVideoCodecFromMediaVideoCodec(VideoCodec codec) { - if (codec == kCodecH264) { - return kSbMediaVideoCodecH264; - } else if (codec == kCodecVC1) { - return kSbMediaVideoCodecVc1; - } else if (codec == kCodecMPEG2) { - return kSbMediaVideoCodecMpeg2; - } else if (codec == kCodecTheora) { - return kSbMediaVideoCodecTheora; - } else if (codec == kCodecVP8) { - return kSbMediaVideoCodecVp8; - } else if (codec == kCodecVP9) { - return kSbMediaVideoCodecVp9; - } - DLOG(ERROR) << "Unsupported video codec " << codec; - return kSbMediaVideoCodecNone; -} - -TimeDelta SbMediaTimeToTimeDelta(SbMediaTime timestamp) { - return TimeDelta::FromMicroseconds(timestamp * Time::kMicrosecondsPerSecond / - kSbMediaTimeSecond); -} - -SbMediaTime TimeDeltaToSbMediaTime(TimeDelta timedelta) { - return timedelta.InMicroseconds() * kSbMediaTimeSecond / - Time::kMicrosecondsPerSecond; -} - -bool IsEncrypted(const scoped_refptr<DemuxerStream>& stream) { - if (stream->type() == DemuxerStream::AUDIO) { - return stream->audio_decoder_config().is_encrypted(); - } else { - DCHECK_EQ(stream->type(), DemuxerStream::VIDEO); - return stream->video_decoder_config().is_encrypted(); - } -} - -void FillDrmSampleInfo(const scoped_refptr<DecoderBuffer>& buffer, - SbDrmSampleInfo* drm_info, - SbDrmSubSampleMapping* subsample_mapping) { - DCHECK(drm_info); - DCHECK(subsample_mapping); - - const DecryptConfig* config = buffer->GetDecryptConfig(); - if (!config || config->iv().empty() || config->key_id().empty()) { - drm_info->initialization_vector_size = 0; - drm_info->identifier_size = 0; - drm_info->subsample_count = 0; - drm_info->subsample_mapping = NULL; - return; - } - - DCHECK_LE(config->iv().size(), sizeof(drm_info->initialization_vector)); - DCHECK_LE(config->key_id().size(), sizeof(drm_info->identifier)); - - if (config->iv().size() > sizeof(drm_info->initialization_vector) || - config->key_id().size() > sizeof(drm_info->identifier)) { - drm_info->initialization_vector_size = 0; - drm_info->identifier_size = 0; - drm_info->subsample_count = 0; - drm_info->subsample_mapping = NULL; - return; - } - - memcpy(drm_info->initialization_vector, &config->iv()[0], - config->iv().size()); - drm_info->initialization_vector_size = config->iv().size(); - memcpy(drm_info->identifier, &config->key_id()[0], config->key_id().size()); - drm_info->identifier_size = config->key_id().size(); - drm_info->subsample_count = config->subsamples().size(); - - if (drm_info->subsample_count > 0) { - COMPILE_ASSERT(sizeof(SbDrmSubSampleMapping) == sizeof(SubsampleEntry), - SubSampleEntrySizesMatch); - drm_info->subsample_mapping = - reinterpret_cast<const SbDrmSubSampleMapping*>( - &config->subsamples()[0]); - } else { - drm_info->subsample_mapping = subsample_mapping; - subsample_mapping->clear_byte_count = 0; - subsample_mapping->encrypted_byte_count = buffer->GetDataSize(); - } -} - // Used to post parameters to SbPlayerPipeline::StartTask() as the number of // parameters exceed what base::Bind() can support. struct StartTaskParameters { @@ -156,32 +62,11 @@ base::Closure duration_change_cb; }; -class SetBoundsCaller : public base::RefCountedThreadSafe<SetBoundsCaller> { - public: - SetBoundsCaller() : player_(kSbPlayerInvalid) {} - void SetPlayer(SbPlayer player) { - base::Lock lock_; - player_ = player; - } - bool SetBounds(const gfx::Rect& rect) { - base::AutoLock auto_lock(lock_); - if (!SbPlayerIsValid(player_)) { - return false; - } - SbPlayerSetBounds(player_, rect.x(), rect.y(), rect.width(), rect.height()); - return true; - } - - private: - base::Lock lock_; - SbPlayer player_; - - DISALLOW_COPY_AND_ASSIGN(SetBoundsCaller); -}; - // SbPlayerPipeline is a PipelineBase implementation that uses the SbPlayer // interface internally. -class MEDIA_EXPORT SbPlayerPipeline : public Pipeline, public DemuxerHost { +class MEDIA_EXPORT SbPlayerPipeline : public Pipeline, + public DemuxerHost, + public StarboardPlayer::Host { public: // Constructs a media pipeline that will execute on |message_loop|. SbPlayerPipeline(PipelineWindow window, @@ -189,6 +74,8 @@ MediaLog* media_log); ~SbPlayerPipeline() OVERRIDE; + void Suspend() OVERRIDE; + void Resume() OVERRIDE; void Start(scoped_ptr<FilterCollection> filter_collection, const SetDecryptorReadyCB& decryptor_ready_cb, const PipelineStatusCB& ended_cb, @@ -218,13 +105,6 @@ SetBoundsCB GetSetBoundsCB() OVERRIDE; private: - // A map from raw data pointer returned by DecoderBuffer::GetData() to the - // DecoderBuffer and a reference count. The reference count indicates how - // many instances of the DecoderBuffer is currently being decoded in the - // pipeline. - typedef std::map<const void*, std::pair<scoped_refptr<DecoderBuffer>, int> > - DecodingBuffers; - void StartTask(const StartTaskParameters& parameters); void SetVolumeTask(float volume); void SetPlaybackRateTask(float volume); @@ -245,31 +125,18 @@ void OnDemuxerSeeked(PipelineStatus status); void OnDemuxerStopped(); void OnDemuxerStreamRead(DemuxerStream::Type type, - int ticket, DemuxerStream::Status status, const scoped_refptr<DecoderBuffer>& buffer); - void OnDecoderStatus(SbMediaType type, - SbPlayerDecoderState state, - int ticket); - void OnPlayerStatus(SbPlayerState state, int ticket); - void OnDeallocateSample(const void* sample_buffer); - - static void DecoderStatusCB(SbPlayer player, - void* context, - SbMediaType type, - SbPlayerDecoderState state, - int ticket); - static void PlayerStatusCB(SbPlayer player, - void* context, - SbPlayerState state, - int ticket); - static void DeallocateSampleCB(SbPlayer player, - void* context, - const void* sample_buffer); + // StarboardPlayer::Host implementation. + void OnNeedData(DemuxerStream::Type type) OVERRIDE; + void OnPlayerStatus(SbPlayerState state) OVERRIDE; void UpdateDecoderConfig(const scoped_refptr<DemuxerStream>& stream); + void SuspendTask(base::WaitableEvent* done_event); + void ResumeTask(base::WaitableEvent* done_event); + // Message loop used to execute pipeline tasks. It is thread-safe. scoped_refptr<base::MessageLoopProxy> message_loop_; @@ -277,9 +144,6 @@ // dtor and accesed once by SbPlayerCreate(). PipelineWindow window_; - // The current ticket associated with the |player_|. - int ticket_; - // Lock used to serialize access for the following member variables. mutable base::Lock lock_; @@ -335,8 +199,9 @@ bool video_read_in_progress_; TimeDelta duration_; - DecodingBuffers decoding_buffers_; - scoped_refptr<SetBoundsCaller> set_bounds_caller_; + scoped_refptr<SbPlayerSetBoundsHelper> set_bounds_helper_; + + bool flushing_; // The following member variables can be accessed from WMPI thread but all // modifications to them happens on the pipeline thread. So any access of @@ -346,8 +211,9 @@ // Temporary callback used for Start() and Seek(). PipelineStatusCB seek_cb_; - SbMediaTime seek_time_; - SbPlayer player_; + base::TimeDelta seek_time_; + scoped_ptr<StarboardPlayer> player_; + bool suspended_; DISALLOW_COPY_AND_ASSIGN(SbPlayerPipeline); }; @@ -357,7 +223,6 @@ const scoped_refptr<base::MessageLoopProxy>& message_loop, MediaLog* media_log) : window_(window), - ticket_(SB_PLAYER_INITIAL_TICKET), message_loop_(message_loop), total_bytes_(0), natural_size_(0, 0), @@ -367,12 +232,34 @@ has_video_(false), audio_read_in_progress_(false), video_read_in_progress_(false), - set_bounds_caller_(new SetBoundsCaller), - seek_time_(0), - player_(kSbPlayerInvalid) {} + flushing_(false), + set_bounds_helper_(new SbPlayerSetBoundsHelper), + suspended_(false) {} SbPlayerPipeline::~SbPlayerPipeline() { - DCHECK(player_ == kSbPlayerInvalid); + DCHECK(!player_); +} + +void SbPlayerPipeline::Suspend() { + DCHECK(!message_loop_->BelongsToCurrentThread()); + + base::WaitableEvent waitable_event(true, /* manual_reset */ + false /* initially_signaled */); + message_loop_->PostTask(FROM_HERE, + base::Bind(&SbPlayerPipeline::SuspendTask, + base::Unretained(this), &waitable_event)); + waitable_event.Wait(); +} + +void SbPlayerPipeline::Resume() { + DCHECK(!message_loop_->BelongsToCurrentThread()); + + base::WaitableEvent waitable_event(true, /* manual_reset */ + false /* initially_signaled */); + message_loop_->PostTask(FROM_HERE, + base::Bind(&SbPlayerPipeline::ResumeTask, + base::Unretained(this), &waitable_event)); + waitable_event.Wait(); } void SbPlayerPipeline::Start(scoped_ptr<FilterCollection> filter_collection, @@ -407,16 +294,15 @@ DCHECK(stop_cb_.is_null()); DCHECK(!stop_cb.is_null()); - if (SbPlayerIsValid(player_)) { - set_bounds_caller_->SetPlayer(kSbPlayerInvalid); - SbPlayer player = player_; + if (player_) { + scoped_ptr<StarboardPlayer> player; { base::AutoLock auto_lock(lock_); - player_ = kSbPlayerInvalid; + player = player_.Pass(); } DLOG(INFO) << "Destroying SbPlayer."; - SbPlayerDestroy(player); + player.reset(); DLOG(INFO) << "SbPlayer destroyed."; } @@ -437,20 +323,27 @@ return; } - if (!SbPlayerIsValid(player_)) { + if (!player_) { seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); } DCHECK(seek_cb_.is_null()); DCHECK(!seek_cb.is_null()); - // Increase |ticket_| so all upcoming need data requests from the SbPlayer - // are ignored. - ++ticket_; + flushing_ = true; + + if (audio_read_in_progress_ || video_read_in_progress_) { + message_loop_->PostTask( + FROM_HERE, base::Bind(&SbPlayerPipeline::Seek, this, time, seek_cb)); + return; + } + + player_->PrepareForSeek(); + { base::AutoLock auto_lock(lock_); seek_cb_ = seek_cb; - seek_time_ = TimeDeltaToSbMediaTime(time); + seek_time_ = time; } demuxer_->Seek(time, BindToCurrentLoop(base::Bind( &SbPlayerPipeline::OnDemuxerSeeked, this))); @@ -500,17 +393,16 @@ TimeDelta SbPlayerPipeline::GetMediaTime() const { base::AutoLock auto_lock(lock_); - if (!SbPlayerIsValid(player_)) { + if (!seek_cb_.is_null()) { + return seek_time_; + } + if (!player_) { return TimeDelta(); } - if (!seek_cb_.is_null()) { - return SbMediaTimeToTimeDelta(seek_time_); - } - SbPlayerInfo info; - SbPlayerGetInfo(player_, &info); - statistics_.video_frames_decoded = info.total_video_frames; - statistics_.video_frames_dropped = info.dropped_video_frames; - return SbMediaTimeToTimeDelta(info.current_media_pts); + base::TimeDelta media_time; + player_->GetInfo(&statistics_.video_frames_decoded, + &statistics_.video_frames_dropped, &media_time); + return media_time; } Ranges<TimeDelta> SbPlayerPipeline::GetBufferedTimeRanges() { @@ -564,7 +456,7 @@ Pipeline::SetBoundsCB SbPlayerPipeline::GetSetBoundsCB() { #if SB_IS(PLAYER_PUNCHED_OUT) - return base::Bind(&SetBoundsCaller::SetBounds, set_bounds_caller_); + return base::Bind(&SbPlayerSetBoundsHelper::SetBounds, set_bounds_helper_); #else // SB_IS(PLAYER_PUNCHED_OUT) return Pipeline::SetBoundsCB(); #endif // SB_IS(PLAYER_PUNCHED_OUT) @@ -594,16 +486,16 @@ void SbPlayerPipeline::SetVolumeTask(float volume) { DCHECK(message_loop_->BelongsToCurrentThread()); - if (SbPlayerIsValid(player_)) { - SbPlayerSetVolume(player_, volume_); + if (player_) { + player_->SetVolume(volume_); } } void SbPlayerPipeline::SetPlaybackRateTask(float volume) { DCHECK(message_loop_->BelongsToCurrentThread()); - if (SbPlayerIsValid(player_)) { - SbPlayerSetPause(player_, playback_rate_ == 0.0); + if (player_) { + player_->SetPause(playback_rate_ == 0.0); } } @@ -654,41 +546,36 @@ void SbPlayerPipeline::CreatePlayer(SbDrmSystem drm_system) { DCHECK(message_loop_->BelongsToCurrentThread()); + if (suspended_) { + message_loop_->PostTask( + FROM_HERE, + base::Bind(&SbPlayerPipeline::CreatePlayer, this, drm_system)); + return; + } + + // TODO: Check |suspended_| here as the pipeline can be suspended before the + // player is created. In this case we should delay creating the player as the + // creation of player may fail. const AudioDecoderConfig& audio_config = demuxer_->GetStream(DemuxerStream::AUDIO)->audio_decoder_config(); - SbMediaAudioHeader audio_header; - audio_header.format_tag = 0x00ff; - audio_header.number_of_channels = - ChannelLayoutToChannelCount(audio_config.channel_layout()); - audio_header.samples_per_second = audio_config.samples_per_second(); - audio_header.average_bytes_per_second = 1; - audio_header.block_alignment = 4; - audio_header.bits_per_sample = audio_config.bits_per_channel(); - audio_header.audio_specific_config_size = 0; - const VideoDecoderConfig& video_config = demuxer_->GetStream(DemuxerStream::VIDEO)->video_decoder_config(); - SbMediaAudioCodec audio_codec = - SbMediaAudioCodecFromMediaAudioCodec(audio_config.codec()); - SbMediaVideoCodec video_codec = - SbMediaVideoCodecFromMediaVideoCodec(video_config.codec()); - { base::AutoLock auto_lock(lock_); - player_ = - SbPlayerCreate(window_, video_codec, audio_codec, SB_PLAYER_NO_DURATION, - drm_system, &audio_header, DeallocateSampleCB, - DecoderStatusCB, PlayerStatusCB, this); + player_.reset(new StarboardPlayer(message_loop_, audio_config, video_config, + window_, drm_system, this, + set_bounds_helper_.get())); SetPlaybackRateTask(playback_rate_); SetVolumeTask(volume_); } - if (SbPlayerIsValid(player_)) { - set_bounds_caller_->SetPlayer(player_); + if (player_->IsValid()) { return; } + player_.reset(); + PipelineStatusCB seek_cb; { base::AutoLock auto_lock(lock_); @@ -750,14 +637,8 @@ DCHECK(message_loop_->BelongsToCurrentThread()); if (status == PIPELINE_OK) { - if (audio_read_in_progress_ || video_read_in_progress_) { - message_loop_->PostTask( - FROM_HERE, - base::Bind(&SbPlayerPipeline::OnDemuxerSeeked, this, status)); - return; - } - ++ticket_; - SbPlayerSeek(player_, seek_time_, ticket_); + flushing_ = false; + player_->Seek(seek_time_); } } @@ -773,7 +654,6 @@ void SbPlayerPipeline::OnDemuxerStreamRead( DemuxerStream::Type type, - int ticket, DemuxerStream::Status status, const scoped_refptr<DecoderBuffer>& buffer) { DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO) @@ -782,21 +662,14 @@ if (!message_loop_->BelongsToCurrentThread()) { message_loop_->PostTask( FROM_HERE, base::Bind(&SbPlayerPipeline::OnDemuxerStreamRead, this, - type, ticket, status, buffer)); + type, status, buffer)); return; } scoped_refptr<DemuxerStream> stream = demuxer_->GetStream(type); - if (ticket != ticket_) { - if (status == DemuxerStream::kConfigChanged) { - UpdateDecoderConfig(stream); - } - return; - } - // In case if Stop() has been called. - if (!SbPlayerIsValid(player_)) { + if (!player_) { return; } @@ -824,115 +697,57 @@ NOTIMPLEMENTED() << "Update decoder config"; UpdateDecoderConfig(stream); stream->Read( - base::Bind(&SbPlayerPipeline::OnDemuxerStreamRead, this, type, ticket)); + base::Bind(&SbPlayerPipeline::OnDemuxerStreamRead, this, type)); return; } - bool is_encrypted = IsEncrypted(stream); - SbDrmSampleInfo drm_info; - SbDrmSubSampleMapping subsample_mapping; - - if (is_encrypted && !buffer->IsEndOfStream()) { - FillDrmSampleInfo(buffer, &drm_info, &subsample_mapping); - } - if (type == DemuxerStream::AUDIO) { audio_read_in_progress_ = false; - if (buffer->IsEndOfStream()) { - SbPlayerWriteEndOfStream(player_, kSbMediaTypeAudio); - return; - } - DecodingBuffers::iterator iter = decoding_buffers_.find(buffer->GetData()); - if (iter == decoding_buffers_.end()) { - decoding_buffers_[buffer->GetData()] = std::make_pair(buffer, 1); - } else { - ++iter->second.second; - } - SbPlayerWriteSample(player_, kSbMediaTypeAudio, buffer->GetData(), - buffer->GetDataSize(), - TimeDeltaToSbMediaTime(buffer->GetTimestamp()), NULL, - is_encrypted ? &drm_info : NULL); - return; + } else { + video_read_in_progress_ = false; } - video_read_in_progress_ = false; - if (buffer->IsEndOfStream()) { - SbPlayerWriteEndOfStream(player_, kSbMediaTypeVideo); - return; - } - SbMediaVideoSampleInfo video_info; - NOTIMPLEMENTED() << "Fill video_info"; - video_info.is_key_frame = false; - video_info.frame_width = 1; - video_info.frame_height = 1; - DecodingBuffers::iterator iter = decoding_buffers_.find(buffer->GetData()); - if (iter == decoding_buffers_.end()) { - decoding_buffers_[buffer->GetData()] = std::make_pair(buffer, 1); - } else { - ++iter->second.second; - } - SbPlayerWriteSample(player_, kSbMediaTypeVideo, buffer->GetData(), - buffer->GetDataSize(), - TimeDeltaToSbMediaTime(buffer->GetTimestamp()), - &video_info, is_encrypted ? &drm_info : NULL); + player_->WriteBuffer(type, buffer); } -void SbPlayerPipeline::OnDecoderStatus(SbMediaType type, - SbPlayerDecoderState state, - int ticket) { +void SbPlayerPipeline::OnNeedData(DemuxerStream::Type type) { DCHECK(message_loop_->BelongsToCurrentThread()); + // In case if Stop() has been called. - if (!SbPlayerIsValid(player_)) { - return; - } - if (ticket != ticket_) { + if (!player_) { return; } - switch (state) { - case kSbPlayerDecoderStateNeedsData: - break; - case kSbPlayerDecoderStateBufferFull: - DLOG(WARNING) << "kSbPlayerDecoderStateBufferFull has been deprecated."; - return; - case kSbPlayerDecoderStateDestroyed: - return; + if (flushing_) { + return; } - DCHECK_EQ(state, kSbPlayerDecoderStateNeedsData); - if (type == kSbMediaTypeAudio) { + if (type == DemuxerStream::AUDIO) { if (audio_read_in_progress_) { return; } audio_read_in_progress_ = true; } else { - DCHECK_EQ(type, kSbMediaTypeVideo); + DCHECK_EQ(type, DemuxerStream::VIDEO); if (video_read_in_progress_) { return; } video_read_in_progress_ = true; } - DemuxerStream::Type stream_type = - (type == kSbMediaTypeAudio) ? DemuxerStream::AUDIO : DemuxerStream::VIDEO; - scoped_refptr<DemuxerStream> stream = demuxer_->GetStream(stream_type); - stream->Read(base::Bind(&SbPlayerPipeline::OnDemuxerStreamRead, this, - stream_type, ticket)); + scoped_refptr<DemuxerStream> stream = demuxer_->GetStream(type); + stream->Read(base::Bind(&SbPlayerPipeline::OnDemuxerStreamRead, this, type)); } -void SbPlayerPipeline::OnPlayerStatus(SbPlayerState state, int ticket) { +void SbPlayerPipeline::OnPlayerStatus(SbPlayerState state) { DCHECK(message_loop_->BelongsToCurrentThread()); // In case if Stop() has been called. - if (!SbPlayerIsValid(player_)) { - return; - } - if (ticket != ticket_) { + if (!player_) { return; } switch (state) { case kSbPlayerStateInitialized: - ++ticket_; - SbPlayerSeek(player_, 0, ticket_); + NOTREACHED(); break; case kSbPlayerStatePrerolling: break; @@ -960,57 +775,10 @@ } } -void SbPlayerPipeline::OnDeallocateSample(const void* sample_buffer) { - DCHECK(message_loop_->BelongsToCurrentThread()); - DecodingBuffers::iterator iter = decoding_buffers_.find(sample_buffer); - DCHECK(iter != decoding_buffers_.end()); - if (iter == decoding_buffers_.end()) { - LOG(ERROR) << "SbPlayerPipeline::OnDeallocateSample encounters unknown " - << "sample_buffer " << sample_buffer; - return; - } - --iter->second.second; - if (iter->second.second == 0) { - decoding_buffers_.erase(iter); - } -} - -// static -void SbPlayerPipeline::DecoderStatusCB(SbPlayer player, - void* context, - SbMediaType type, - SbPlayerDecoderState state, - int ticket) { - SbPlayerPipeline* pipeline = reinterpret_cast<SbPlayerPipeline*>(context); - pipeline->message_loop_->PostTask( - FROM_HERE, base::Bind(&SbPlayerPipeline::OnDecoderStatus, pipeline, type, - state, ticket)); -} - -// static -void SbPlayerPipeline::PlayerStatusCB(SbPlayer player, - void* context, - SbPlayerState state, - int ticket) { - SbPlayerPipeline* pipeline = reinterpret_cast<SbPlayerPipeline*>(context); - pipeline->message_loop_->PostTask( - FROM_HERE, - base::Bind(&SbPlayerPipeline::OnPlayerStatus, pipeline, state, ticket)); -} - -// static -void SbPlayerPipeline::DeallocateSampleCB(SbPlayer player, - void* context, - const void* sample_buffer) { - SbPlayerPipeline* pipeline = reinterpret_cast<SbPlayerPipeline*>(context); - pipeline->message_loop_->PostTask( - FROM_HERE, base::Bind(&SbPlayerPipeline::OnDeallocateSample, pipeline, - sample_buffer)); -} - void SbPlayerPipeline::UpdateDecoderConfig( const scoped_refptr<DemuxerStream>& stream) { DCHECK(message_loop_->BelongsToCurrentThread()); + if (stream->type() == DemuxerStream::AUDIO) { stream->audio_decoder_config(); } else { @@ -1018,9 +786,49 @@ const VideoDecoderConfig& decoder_config = stream->video_decoder_config(); base::AutoLock auto_lock(lock_); natural_size_ = decoder_config.natural_size(); + player_->UpdateVideoResolution(static_cast<int>(natural_size_.width()), + static_cast<int>(natural_size_.height())); } } +void SbPlayerPipeline::SuspendTask(base::WaitableEvent* done_event) { + DCHECK(message_loop_->BelongsToCurrentThread()); + DCHECK(done_event); + DCHECK(!suspended_); + + if (suspended_) { + done_event->Signal(); + return; + } + + if (player_) { + player_->Suspend(); + } + + suspended_ = true; + + done_event->Signal(); +} + +void SbPlayerPipeline::ResumeTask(base::WaitableEvent* done_event) { + DCHECK(message_loop_->BelongsToCurrentThread()); + DCHECK(done_event); + DCHECK(suspended_); + + if (!suspended_) { + done_event->Signal(); + return; + } + + if (player_) { + player_->Resume(); + } + + suspended_ = false; + + done_event->Signal(); +} + } // namespace #endif // SB_HAS(PLAYER)
diff --git a/src/media/base/sbplayer_set_bounds_helper.cc b/src/media/base/sbplayer_set_bounds_helper.cc new file mode 100644 index 0000000..5e96a94 --- /dev/null +++ b/src/media/base/sbplayer_set_bounds_helper.cc
@@ -0,0 +1,35 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "media/base/sbplayer_set_bounds_helper.h" + +#include "media/base/starboard_player.h" + +namespace media { + +void SbPlayerSetBoundsHelper::SetPlayer(StarboardPlayer* player) { + base::Lock lock_; + player_ = player; +} + +bool SbPlayerSetBoundsHelper::SetBounds(const gfx::Rect& rect) { + base::AutoLock auto_lock(lock_); + if (!player_) { + return false; + } + player_->SetBounds(rect); + return true; +} + +} // namespace media
diff --git a/src/media/base/sbplayer_set_bounds_helper.h b/src/media/base/sbplayer_set_bounds_helper.h new file mode 100644 index 0000000..06affcf --- /dev/null +++ b/src/media/base/sbplayer_set_bounds_helper.h
@@ -0,0 +1,43 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MEDIA_BASE_SBPLAYER_SET_BOUNDS_HELPER_H_ +#define MEDIA_BASE_SBPLAYER_SET_BOUNDS_HELPER_H_ + +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "ui/gfx/rect.h" + +namespace media { + +class StarboardPlayer; + +class SbPlayerSetBoundsHelper + : public base::RefCountedThreadSafe<SbPlayerSetBoundsHelper> { + public: + SbPlayerSetBoundsHelper() : player_(NULL) {} + + void SetPlayer(StarboardPlayer* player); + bool SetBounds(const gfx::Rect& rect); + + private: + base::Lock lock_; + StarboardPlayer* player_; + + DISALLOW_COPY_AND_ASSIGN(SbPlayerSetBoundsHelper); +}; + +} // namespace media + +#endif // MEDIA_BASE_SBPLAYER_SET_BOUNDS_HELPER_H_
diff --git a/src/media/base/shell_buffer_factory.cc b/src/media/base/shell_buffer_factory.cc index 6ff2f08..dc78fe9 100644 --- a/src/media/base/shell_buffer_factory.cc +++ b/src/media/base/shell_buffer_factory.cc
@@ -55,7 +55,9 @@ } } -bool ShellBufferFactory::AllocateBuffer(size_t size, AllocCB cb) { +bool ShellBufferFactory::AllocateBuffer(size_t size, + bool is_keyframe, + AllocCB cb) { TRACE_EVENT1("media_stack", "ShellBufferFactory::AllocateBuffer()", "size", size); // Zero-size buffers are allocation error, allocate an EOS buffer explicity @@ -77,7 +79,7 @@ if (pending_allocs_.size() == 0) { uint8* bytes = Allocate_Locked(size); if (bytes) { - instant_buffer = new DecoderBuffer(bytes, size); + instant_buffer = new DecoderBuffer(bytes, size, is_keyframe); TRACE_EVENT0( "media_stack", "ShellBufferFactory::AllocateBuffer() finished allocation."); @@ -89,7 +91,7 @@ TRACE_EVENT0("media_stack", "ShellBufferFactory::AllocateBuffer() deferred."); pending_allocs_.push_back( - std::make_pair(cb, new DecoderBuffer(NULL, size))); + std::make_pair(cb, new DecoderBuffer(NULL, size, is_keyframe))); } } @@ -101,7 +103,8 @@ } scoped_refptr<DecoderBuffer> ShellBufferFactory::AllocateBufferNow( - size_t size) { + size_t size, + bool is_keyframe) { TRACE_EVENT1("media_stack", "ShellBufferFactory::AllocateBufferNow()", "size", size); // Zero-size buffers are allocation error, allocate an EOS buffer explicity @@ -121,7 +124,8 @@ "ShellBufferFactory::AllocateBufferNow() failed as size is too large."); return NULL; } - scoped_refptr<DecoderBuffer> buffer = new DecoderBuffer(bytes, size); + scoped_refptr<DecoderBuffer> buffer = + new DecoderBuffer(bytes, size, is_keyframe); TRACE_EVENT0("media_stack", "ShellBufferFactory::AllocateBufferNow() finished allocation."); DCHECK(!buffer->IsEndOfStream());
diff --git a/src/media/base/shell_buffer_factory.h b/src/media/base/shell_buffer_factory.h index eb172d7..8a18156 100644 --- a/src/media/base/shell_buffer_factory.h +++ b/src/media/base/shell_buffer_factory.h
@@ -75,10 +75,10 @@ // Returns false if the allocator will never be able to allocate a buffer // of the requested size. Note that if memory is currently available this // function will call the callback provided _before_ returning true. - bool AllocateBuffer(size_t size, AllocCB cb); + bool AllocateBuffer(size_t size, bool is_keyframe, AllocCB cb); // This function tries to allocate a DecoderBuffer immediately. It returns // NULL on failure. - scoped_refptr<DecoderBuffer> AllocateBufferNow(size_t size); + scoped_refptr<DecoderBuffer> AllocateBufferNow(size_t size, bool is_keyframe); // Returns a newly allocated byte field if there's room for it, or NULL if // there isn't. Note that this raw allocation method provides no guarantee // that ShellBufferFactory will still exist when the memory is to be freed.
diff --git a/src/media/base/shell_cached_decoder_buffer.cc b/src/media/base/shell_cached_decoder_buffer.cc index 8fe62b9..28873ba 100644 --- a/src/media/base/shell_cached_decoder_buffer.cc +++ b/src/media/base/shell_cached_decoder_buffer.cc
@@ -22,7 +22,7 @@ const scoped_refptr<media::DecoderBuffer>& source_buffer, void* destination, FreeCB free_cb) - : media::DecoderBuffer(NULL, 0), // Initialize with empty data first. + : media::DecoderBuffer(NULL, 0, source_buffer->IsKeyframe()), source_buffer_(source_buffer), free_cb_(free_cb) { DCHECK(source_buffer);
diff --git a/src/media/base/shell_cached_decoder_buffer.h b/src/media/base/shell_cached_decoder_buffer.h index e0f1c27..db3baad 100644 --- a/src/media/base/shell_cached_decoder_buffer.h +++ b/src/media/base/shell_cached_decoder_buffer.h
@@ -38,10 +38,10 @@ FreeCB free_cb); ~ShellCachedDecoderBuffer(); - virtual const media::DecryptConfig* GetDecryptConfig() const OVERRIDE { + const media::DecryptConfig* GetDecryptConfig() const OVERRIDE { return source_buffer_->GetDecryptConfig(); } - virtual void SetDecryptConfig(scoped_ptr<media::DecryptConfig>) OVERRIDE { + void SetDecryptConfig(scoped_ptr<media::DecryptConfig>) OVERRIDE { NOTREACHED(); }
diff --git a/src/media/base/starboard_player.cc b/src/media/base/starboard_player.cc new file mode 100644 index 0000000..6febc39 --- /dev/null +++ b/src/media/base/starboard_player.cc
@@ -0,0 +1,394 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "media/base/starboard_player.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "media/base/starboard_utils.h" + +namespace media { + +StarboardPlayer::StarboardPlayer( + const scoped_refptr<base::MessageLoopProxy>& message_loop, + const AudioDecoderConfig& audio_config, + const VideoDecoderConfig& video_config, + SbWindow window, + SbDrmSystem drm_system, + Host* host, + SbPlayerSetBoundsHelper* set_bounds_helper) + : message_loop_(message_loop), + window_(window), + drm_system_(drm_system), + host_(host), + set_bounds_helper_(set_bounds_helper), + weak_this_(AsWeakPtr()), + frame_width_(1), + frame_height_(1), + ticket_(SB_PLAYER_INITIAL_TICKET), + volume_(1.0), + paused_(true), + state_(kPlaying) { + DCHECK(audio_config.IsValidConfig()); + DCHECK(video_config.IsValidConfig()); + DCHECK(host_); + DCHECK(set_bounds_helper_); + + audio_config_.CopyFrom(audio_config); + video_config_.CopyFrom(video_config); + + CreatePlayer(); +} + +StarboardPlayer::~StarboardPlayer() { + DCHECK(message_loop_->BelongsToCurrentThread()); + + set_bounds_helper_->SetPlayer(NULL); + SbPlayerDestroy(player_); +} + +void StarboardPlayer::UpdateVideoResolution(int frame_width, int frame_height) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + frame_width_ = frame_width; + frame_height_ = frame_height; +} + +void StarboardPlayer::WriteBuffer(DemuxerStream::Type type, + const scoped_refptr<DecoderBuffer>& buffer) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + // When |state_| is kPlaying, cache all buffer appended. When |state_| is + // kSuspended, there may still be left-over buffers appended from the pipeline + // so they also should be cached. + // When |state_| is resuming, all buffers come from the cache and shouldn't be + // cached. + if (state_ != kResuming) { + decoder_buffer_cache_.AddBuffer(type, buffer); + } + + if (state_ == kSuspended) { + DCHECK(!SbPlayerIsValid(player_)); + return; + } + + DCHECK(SbPlayerIsValid(player_)); + + if (buffer->IsEndOfStream()) { + SbPlayerWriteEndOfStream(player_, DemuxerStreamTypeToSbMediaType(type)); + return; + } + + DecodingBuffers::iterator iter = decoding_buffers_.find(buffer->GetData()); + if (iter == decoding_buffers_.end()) { + decoding_buffers_[buffer->GetData()] = std::make_pair(buffer, 1); + } else { + ++iter->second.second; + } + + SbDrmSampleInfo drm_info; + SbDrmSubSampleMapping subsample_mapping; + bool is_encrypted = buffer->GetDecryptConfig(); + SbMediaVideoSampleInfo video_info; + + drm_info.subsample_count = 0; + video_info.is_key_frame = buffer->IsKeyframe(); + video_info.frame_width = frame_width_; + video_info.frame_height = frame_height_; + + if (is_encrypted) { + FillDrmSampleInfo(buffer, &drm_info, &subsample_mapping); + } + SbPlayerWriteSample(player_, DemuxerStreamTypeToSbMediaType(type), + buffer->GetData(), buffer->GetDataSize(), + TimeDeltaToSbMediaTime(buffer->GetTimestamp()), + type == DemuxerStream::VIDEO ? &video_info : NULL, + drm_info.subsample_count > 0 ? &drm_info : NULL); +} + +void StarboardPlayer::SetBounds(const gfx::Rect& rect) { + DCHECK(SbPlayerIsValid(player_)); + + SbPlayerSetBounds(player_, rect.x(), rect.y(), rect.width(), rect.height()); +} + +void StarboardPlayer::PrepareForSeek() { + DCHECK(message_loop_->BelongsToCurrentThread()); + ++ticket_; +} + +void StarboardPlayer::Seek(base::TimeDelta time) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + decoder_buffer_cache_.ClearAll(); + + if (state_ == kSuspended) { + DCHECK(!SbPlayerIsValid(player_)); + preroll_timestamp_ = time; + return; + } + + // If a seek happens during resuming, the pipeline will write samples from the + // seek target time again so resuming can be aborted. + if (state_ == kResuming) { + state_ = kPlaying; + } + + DCHECK(SbPlayerIsValid(player_)); + + ++ticket_; + SbPlayerSeek(player_, TimeDeltaToSbMediaTime(time), ticket_); +} + +void StarboardPlayer::SetVolume(float volume) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + volume_ = volume; + + if (state_ == kSuspended) { + DCHECK(!SbPlayerIsValid(player_)); + return; + } + + DCHECK(SbPlayerIsValid(player_)); + SbPlayerSetVolume(player_, volume); +} + +void StarboardPlayer::SetPause(bool pause) { + DCHECK(message_loop_->BelongsToCurrentThread()); + DCHECK(SbPlayerIsValid(player_)); + + SbPlayerSetPause(player_, pause); + paused_ = pause; +} + +void StarboardPlayer::GetInfo(uint32* video_frames_decoded, + uint32* video_frames_dropped, + base::TimeDelta* media_time) { + DCHECK(video_frames_decoded); + DCHECK(video_frames_dropped); + DCHECK(media_time); + + base::AutoLock auto_lock(lock_); + if (state_ == kSuspended) { + DCHECK(!SbPlayerIsValid(player_)); + + *video_frames_decoded = cached_video_frames_decoded_; + *video_frames_dropped = cached_video_frames_dropped_; + *media_time = preroll_timestamp_; + return; + } + + DCHECK(SbPlayerIsValid(player_)); + + SbPlayerInfo info; + SbPlayerGetInfo(player_, &info); + *video_frames_decoded = info.total_video_frames; + *video_frames_dropped = info.dropped_video_frames; + *media_time = SbMediaTimeToTimeDelta(info.current_media_pts); +} + +void StarboardPlayer::Suspend() { + DCHECK(message_loop_->BelongsToCurrentThread()); + + // Check if the player is already suspended. + if (state_ == kSuspended) { + DCHECK(!SbPlayerIsValid(player_)); + return; + } + + DCHECK(SbPlayerIsValid(player_)); + + SbPlayerSetPause(player_, true); + + base::AutoLock auto_lock(lock_); + + state_ = kSuspended; + + SbPlayerInfo info; + SbPlayerGetInfo(player_, &info); + cached_video_frames_decoded_ = info.total_video_frames; + cached_video_frames_dropped_ = info.dropped_video_frames; + preroll_timestamp_ = SbMediaTimeToTimeDelta(info.current_media_pts); + + set_bounds_helper_->SetPlayer(NULL); + SbPlayerDestroy(player_); + + player_ = kSbPlayerInvalid; +} + +void StarboardPlayer::Resume() { + DCHECK(message_loop_->BelongsToCurrentThread()); + + // Check if the player is already resumed. + if (state_ != kSuspended) { + DCHECK(SbPlayerIsValid(player_)); + return; + } + + DCHECK(!SbPlayerIsValid(player_)); + + decoder_buffer_cache_.StartResuming(); + + CreatePlayer(); + + base::AutoLock auto_lock(lock_); + state_ = kResuming; +} + +void StarboardPlayer::CreatePlayer() { + DCHECK(message_loop_->BelongsToCurrentThread()); + + SbMediaAudioHeader audio_header; + // TODO: Make this work with non AAC audio. + audio_header.format_tag = 0x00ff; + audio_header.number_of_channels = + ChannelLayoutToChannelCount(audio_config_.channel_layout()); + audio_header.samples_per_second = audio_config_.samples_per_second(); + audio_header.average_bytes_per_second = 1; + audio_header.block_alignment = 4; + audio_header.bits_per_sample = audio_config_.bits_per_channel(); + audio_header.audio_specific_config_size = 0; + + SbMediaAudioCodec audio_codec = + MediaAudioCodecToSbMediaAudioCodec(audio_config_.codec()); + SbMediaVideoCodec video_codec = + MediaVideoCodecToSbMediaVideoCodec(video_config_.codec()); + + player_ = SbPlayerCreate(window_, video_codec, audio_codec, + SB_PLAYER_NO_DURATION, drm_system_, &audio_header, + &StarboardPlayer::DeallocateSampleCB, + &StarboardPlayer::DecoderStatusCB, + &StarboardPlayer::PlayerStatusCB, this); + set_bounds_helper_->SetPlayer(this); +} + +void StarboardPlayer::OnDecoderStatus(SbPlayer player, + SbMediaType type, + SbPlayerDecoderState state, + int ticket) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + if (player_ != player || ticket != ticket_) { + return; + } + + DCHECK_NE(state_, kSuspended); + + switch (state) { + case kSbPlayerDecoderStateNeedsData: + break; + case kSbPlayerDecoderStateBufferFull: + DLOG(WARNING) << "kSbPlayerDecoderStateBufferFull has been deprecated."; + return; + case kSbPlayerDecoderStateDestroyed: + return; + } + + if (state_ == kResuming) { + DemuxerStream::Type stream_type = SbMediaTypeToDemuxerStreamType(type); + if (decoder_buffer_cache_.GetBuffer(stream_type)) { + WriteBuffer(stream_type, decoder_buffer_cache_.GetBuffer(stream_type)); + decoder_buffer_cache_.AdvanceToNextBuffer(stream_type); + return; + } + if (!decoder_buffer_cache_.GetBuffer(DemuxerStream::AUDIO) && + !decoder_buffer_cache_.GetBuffer(DemuxerStream::VIDEO)) { + state_ = kPlaying; + } + } + + host_->OnNeedData(SbMediaTypeToDemuxerStreamType(type)); +} + +void StarboardPlayer::OnPlayerStatus(SbPlayer player, + SbPlayerState state, + int ticket) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + if (player_ != player) { + return; + } + + DCHECK_NE(state_, kSuspended); + + if (ticket != SB_PLAYER_INITIAL_TICKET && ticket != ticket_) { + return; + } + + if (state == kSbPlayerStateInitialized) { + if (ticket_ == SB_PLAYER_INITIAL_TICKET) { + ++ticket_; + } + SbPlayerSeek(player_, TimeDeltaToSbMediaTime(preroll_timestamp_), ticket_); + SetVolume(volume_); + if (paused_) { + SetPause(paused_); + } + return; + } + host_->OnPlayerStatus(state); +} + +void StarboardPlayer::OnDeallocateSample(const void* sample_buffer) { + DCHECK(message_loop_->BelongsToCurrentThread()); + + DecodingBuffers::iterator iter = decoding_buffers_.find(sample_buffer); + DCHECK(iter != decoding_buffers_.end()); + if (iter == decoding_buffers_.end()) { + LOG(ERROR) << "StarboardPlayer::OnDeallocateSample encounters unknown " + << "sample_buffer " << sample_buffer; + return; + } + --iter->second.second; + if (iter->second.second == 0) { + decoding_buffers_.erase(iter); + } +} + +// static +void StarboardPlayer::DecoderStatusCB(SbPlayer player, + void* context, + SbMediaType type, + SbPlayerDecoderState state, + int ticket) { + StarboardPlayer* helper = reinterpret_cast<StarboardPlayer*>(context); + helper->message_loop_->PostTask( + FROM_HERE, base::Bind(&StarboardPlayer::OnDecoderStatus, + helper->weak_this_, player, type, state, ticket)); +} + +// static +void StarboardPlayer::PlayerStatusCB(SbPlayer player, + void* context, + SbPlayerState state, + int ticket) { + StarboardPlayer* helper = reinterpret_cast<StarboardPlayer*>(context); + helper->message_loop_->PostTask( + FROM_HERE, base::Bind(&StarboardPlayer::OnPlayerStatus, + helper->weak_this_, player, state, ticket)); +} + +// static +void StarboardPlayer::DeallocateSampleCB(SbPlayer player, + void* context, + const void* sample_buffer) { + StarboardPlayer* helper = reinterpret_cast<StarboardPlayer*>(context); + helper->message_loop_->PostTask( + FROM_HERE, base::Bind(&StarboardPlayer::OnDeallocateSample, + helper->weak_this_, sample_buffer)); +} + +} // namespace media
diff --git a/src/media/base/starboard_player.h b/src/media/base/starboard_player.h new file mode 100644 index 0000000..bf2bb5a --- /dev/null +++ b/src/media/base/starboard_player.h
@@ -0,0 +1,145 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MEDIA_BASE_STARBOARD_PLAYER_H_ +#define MEDIA_BASE_STARBOARD_PLAYER_H_ + +#include <map> + +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop_proxy.h" +#include "base/synchronization/lock.h" +#include "base/time.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/decoder_buffer.h" +#include "media/base/decoder_buffer_cache.h" +#include "media/base/demuxer_stream.h" +#include "media/base/sbplayer_set_bounds_helper.h" +#include "media/base/video_decoder_config.h" +#include "starboard/media.h" +#include "starboard/player.h" + +namespace media { + +// TODO: Add switch to disable caching +class StarboardPlayer : public base::SupportsWeakPtr<StarboardPlayer> { + public: + class Host { + public: + virtual void OnNeedData(DemuxerStream::Type type) = 0; + virtual void OnPlayerStatus(SbPlayerState state) = 0; + + protected: + ~Host() {} + }; + + StarboardPlayer(const scoped_refptr<base::MessageLoopProxy>& message_loop, + const AudioDecoderConfig& audio_config, + const VideoDecoderConfig& video_config, + SbWindow window, + SbDrmSystem drm_system, + Host* host, + SbPlayerSetBoundsHelper* set_bounds_helper); + ~StarboardPlayer(); + + bool IsValid() const { return SbPlayerIsValid(player_); } + + void UpdateVideoResolution(int frame_width, int frame_height); + + void WriteBuffer(DemuxerStream::Type type, + const scoped_refptr<DecoderBuffer>& buffer); + void SetBounds(const gfx::Rect& rect); + + void PrepareForSeek(); + void Seek(base::TimeDelta time); + + void SetVolume(float volume); + void SetPause(bool pause); + void GetInfo(uint32* video_frames_decoded, + uint32* video_frames_dropped, + base::TimeDelta* media_time); + + void Suspend(); + void Resume(); + + private: + enum State { + kPlaying, + kSuspended, + kResuming, + }; + + // A map from raw data pointer returned by DecoderBuffer::GetData() to the + // DecoderBuffer and a reference count. The reference count indicates how + // many instances of the DecoderBuffer is currently being decoded in the + // pipeline. + typedef std::map<const void*, std::pair<scoped_refptr<DecoderBuffer>, int> > + DecodingBuffers; + + void CreatePlayer(); + + void OnDecoderStatus(SbPlayer player, + SbMediaType type, + SbPlayerDecoderState state, + int ticket); + void OnPlayerStatus(SbPlayer player, SbPlayerState state, int ticket); + void OnDeallocateSample(const void* sample_buffer); + + static void DecoderStatusCB(SbPlayer player, + void* context, + SbMediaType type, + SbPlayerDecoderState state, + int ticket); + static void PlayerStatusCB(SbPlayer player, + void* context, + SbPlayerState state, + int ticket); + static void DeallocateSampleCB(SbPlayer player, + void* context, + const void* sample_buffer); + + // The following variables are initialized in the ctor and never changed. + const scoped_refptr<base::MessageLoopProxy> message_loop_; + AudioDecoderConfig audio_config_; + VideoDecoderConfig video_config_; + const SbWindow window_; + const SbDrmSystem drm_system_; + Host* const host_; + SbPlayerSetBoundsHelper* const set_bounds_helper_; + const base::WeakPtr<StarboardPlayer> weak_this_; + + // The following variables are only changed or accessed from the + // |message_loop_|. + int frame_width_; + int frame_height_; + DecodingBuffers decoding_buffers_; + int ticket_; + float volume_; + bool paused_; + DecoderBufferCache decoder_buffer_cache_; + + // The following variables can be accessed from GetInfo(), which can be called + // from any threads. So some of their usages have to be guarded by |lock_|. + base::Lock lock_; + State state_; + SbPlayer player_; + uint32 cached_video_frames_decoded_; + uint32 cached_video_frames_dropped_; + base::TimeDelta preroll_timestamp_; +}; + +} // namespace media + +#endif // MEDIA_BASE_STARBOARD_PLAYER_H_
diff --git a/src/media/base/starboard_utils.cc b/src/media/base/starboard_utils.cc new file mode 100644 index 0000000..94fba6b --- /dev/null +++ b/src/media/base/starboard_utils.cc
@@ -0,0 +1,128 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "media/base/starboard_utils.h" + +#include "base/logging.h" + +using base::Time; +using base::TimeDelta; + +namespace media { + +SbMediaAudioCodec MediaAudioCodecToSbMediaAudioCodec(AudioCodec codec) { + if (codec == kCodecAAC) { + return kSbMediaAudioCodecAac; + } else if (codec == kCodecVorbis) { + return kSbMediaAudioCodecVorbis; + } else if (codec == kCodecOpus) { + return kSbMediaAudioCodecOpus; + } + DLOG(ERROR) << "Unsupported audio codec " << codec; + return kSbMediaAudioCodecNone; +} + +SbMediaVideoCodec MediaVideoCodecToSbMediaVideoCodec(VideoCodec codec) { + if (codec == kCodecH264) { + return kSbMediaVideoCodecH264; + } else if (codec == kCodecVC1) { + return kSbMediaVideoCodecVc1; + } else if (codec == kCodecMPEG2) { + return kSbMediaVideoCodecMpeg2; + } else if (codec == kCodecTheora) { + return kSbMediaVideoCodecTheora; + } else if (codec == kCodecVP8) { + return kSbMediaVideoCodecVp8; + } else if (codec == kCodecVP9) { + return kSbMediaVideoCodecVp9; + } + DLOG(ERROR) << "Unsupported video codec " << codec; + return kSbMediaVideoCodecNone; +} + +TimeDelta SbMediaTimeToTimeDelta(SbMediaTime timestamp) { + return TimeDelta::FromMicroseconds(timestamp * Time::kMicrosecondsPerSecond / + kSbMediaTimeSecond); +} + +SbMediaTime TimeDeltaToSbMediaTime(TimeDelta timedelta) { + return timedelta.InMicroseconds() * kSbMediaTimeSecond / + Time::kMicrosecondsPerSecond; +} + +DemuxerStream::Type SbMediaTypeToDemuxerStreamType(SbMediaType type) { + if (type == kSbMediaTypeAudio) { + return DemuxerStream::AUDIO; + } + DCHECK_EQ(type, kSbMediaTypeVideo); + return DemuxerStream::VIDEO; +} + +SbMediaType DemuxerStreamTypeToSbMediaType(DemuxerStream::Type type) { + if (type == DemuxerStream::AUDIO) { + return kSbMediaTypeAudio; + } + DCHECK_EQ(type, DemuxerStream::VIDEO); + return kSbMediaTypeVideo; +} + +void FillDrmSampleInfo(const scoped_refptr<DecoderBuffer>& buffer, + SbDrmSampleInfo* drm_info, + SbDrmSubSampleMapping* subsample_mapping) { + DCHECK(drm_info); + DCHECK(subsample_mapping); + + const DecryptConfig* config = buffer->GetDecryptConfig(); + if (!config || config->iv().empty() || config->key_id().empty()) { + drm_info->initialization_vector_size = 0; + drm_info->identifier_size = 0; + drm_info->subsample_count = 0; + drm_info->subsample_mapping = NULL; + return; + } + + DCHECK_LE(config->iv().size(), sizeof(drm_info->initialization_vector)); + DCHECK_LE(config->key_id().size(), sizeof(drm_info->identifier)); + + if (config->iv().size() > sizeof(drm_info->initialization_vector) || + config->key_id().size() > sizeof(drm_info->identifier)) { + drm_info->initialization_vector_size = 0; + drm_info->identifier_size = 0; + drm_info->subsample_count = 0; + drm_info->subsample_mapping = NULL; + return; + } + + memcpy(drm_info->initialization_vector, &config->iv()[0], + config->iv().size()); + drm_info->initialization_vector_size = config->iv().size(); + memcpy(drm_info->identifier, &config->key_id()[0], config->key_id().size()); + drm_info->identifier_size = config->key_id().size(); + drm_info->subsample_count = config->subsamples().size(); + + if (drm_info->subsample_count > 0) { + COMPILE_ASSERT(sizeof(SbDrmSubSampleMapping) == sizeof(SubsampleEntry), + SubSampleEntrySizesMatch); + drm_info->subsample_mapping = + reinterpret_cast<const SbDrmSubSampleMapping*>( + &config->subsamples()[0]); + } else { + drm_info->subsample_count = 1; + drm_info->subsample_mapping = subsample_mapping; + subsample_mapping->clear_byte_count = 0; + subsample_mapping->encrypted_byte_count = buffer->GetDataSize(); + } +} + +} // namespace media
diff --git a/src/media/base/starboard_utils.h b/src/media/base/starboard_utils.h new file mode 100644 index 0000000..ff3323b --- /dev/null +++ b/src/media/base/starboard_utils.h
@@ -0,0 +1,42 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MEDIA_BASE_STARBOARD_UTILS_H_ +#define MEDIA_BASE_STARBOARD_UTILS_H_ + +#include "media/base/audio_decoder_config.h" +#include "media/base/decoder_buffer.h" +#include "media/base/demuxer_stream.h" +#include "media/base/video_decoder_config.h" +#include "starboard/drm.h" +#include "starboard/media.h" + +namespace media { + +SbMediaAudioCodec MediaAudioCodecToSbMediaAudioCodec(AudioCodec codec); +SbMediaVideoCodec MediaVideoCodecToSbMediaVideoCodec(VideoCodec codec); + +base::TimeDelta SbMediaTimeToTimeDelta(SbMediaTime timestamp); +SbMediaTime TimeDeltaToSbMediaTime(base::TimeDelta timedelta); + +DemuxerStream::Type SbMediaTypeToDemuxerStreamType(SbMediaType type); +SbMediaType DemuxerStreamTypeToSbMediaType(DemuxerStream::Type type); + +void FillDrmSampleInfo(const scoped_refptr<DecoderBuffer>& buffer, + SbDrmSampleInfo* drm_info, + SbDrmSubSampleMapping* subsample_mapping); + +} // namespace media + +#endif // MEDIA_BASE_STARBOARD_UTILS_H_
diff --git a/src/media/base/stream_parser_buffer.cc b/src/media/base/stream_parser_buffer.cc index 769f67b..6a6c4a5 100644 --- a/src/media/base/stream_parser_buffer.cc +++ b/src/media/base/stream_parser_buffer.cc
@@ -54,21 +54,19 @@ } #if defined(__LB_SHELL__) || defined(COBALT) -StreamParserBuffer::StreamParserBuffer( - uint8* data, - int data_size, - bool is_keyframe) - : DecoderBuffer(data, data_size), - is_keyframe_(is_keyframe), +StreamParserBuffer::StreamParserBuffer(uint8* data, + int data_size, + bool is_keyframe) + : DecoderBuffer(data, data_size, is_keyframe), decode_timestamp_(kNoTimestamp()), config_id_(kInvalidConfigId) { SetDuration(kNoTimestamp()); } #else -StreamParserBuffer::StreamParserBuffer(const uint8* data, int data_size, +StreamParserBuffer::StreamParserBuffer(const uint8* data, + int data_size, bool is_keyframe) - : DecoderBuffer(data, data_size), - is_keyframe_(is_keyframe), + : DecoderBuffer(data, data_size, is_keyframe), decode_timestamp_(kNoTimestamp()), config_id_(kInvalidConfigId) { SetDuration(kNoTimestamp());
diff --git a/src/media/base/stream_parser_buffer.h b/src/media/base/stream_parser_buffer.h index eecc147..a5471d9 100644 --- a/src/media/base/stream_parser_buffer.h +++ b/src/media/base/stream_parser_buffer.h
@@ -19,8 +19,6 @@ static scoped_refptr<StreamParserBuffer> CopyFrom( const uint8* data, int data_size, bool is_keyframe); - bool IsKeyframe() const { return is_keyframe_; } - // Decode timestamp. If not explicitly set, or set to kNoTimestamp(), the // value will be taken from the normal timestamp. base::TimeDelta GetDecodeTimestamp() const; @@ -39,7 +37,6 @@ #endif virtual ~StreamParserBuffer(); - bool is_keyframe_; base::TimeDelta decode_timestamp_; int config_id_; DISALLOW_COPY_AND_ASSIGN(StreamParserBuffer);
diff --git a/src/media/filters/chunk_demuxer.cc b/src/media/filters/chunk_demuxer.cc index ab2b490..76cc2c8 100644 --- a/src/media/filters/chunk_demuxer.cc +++ b/src/media/filters/chunk_demuxer.cc
@@ -32,6 +32,9 @@ #if defined(OS_STARBOARD) #include "starboard/configuration.h" +#if SB_HAS_QUIRK(SEEK_TO_KEYFRAME) +#define CHUNK_DEMUXER_SEEK_TO_KEYFRAME +#endif // SB_HAS_QUIRK(SEEK_TO_KEYFRAME) #endif // defined(OS_STARBOARD) using base::TimeDelta; @@ -232,6 +235,7 @@ void Seek(TimeDelta time); void CancelPendingSeek(); bool IsSeekPending() const; + base::TimeDelta GetSeekKeyframeTimestamp() const; // Add buffers to this stream. Buffers are stored in SourceBufferStreams, // which handle ordering and overlap resolution. @@ -375,6 +379,11 @@ return stream_->IsSeekPending(); } +base::TimeDelta ChunkDemuxerStream::GetSeekKeyframeTimestamp() const { + base::AutoLock auto_lock(lock_); + return stream_->GetSeekKeyframeTimestamp(); +} + void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { base::AutoLock auto_lock(lock_); DCHECK(!end_of_stream_); @@ -646,6 +655,7 @@ const NeedKeyCB& need_key_cb, const LogCB& log_cb) : state_(WAITING_FOR_INIT), + delayed_audio_seek_(false), host_(NULL), open_cb_(open_cb), need_key_cb_(need_key_cb), @@ -695,11 +705,19 @@ base::AutoLock auto_lock(lock_); if (state_ == INITIALIZED || state_ == ENDED) { - if (audio_) - audio_->Seek(time); - if (video_) video_->Seek(time); +#if defined(CHUNK_DEMUXER_SEEK_TO_KEYFRAME) + // We only need to do a delayed audio seek when there are both audio and + // video streams and the seek on the video stream is pending. + delayed_audio_seek_ = audio_ && video_ && video_->IsSeekPending(); + if (audio_ && !delayed_audio_seek_) { + audio_->Seek(video_->GetSeekKeyframeTimestamp()); + } +#else // defined(CHUNK_DEMUXER_SEEK_TO_KEYFRAME) + if (audio_) + audio_->Seek(time); +#endif // defined(CHUNK_DEMUXER_SEEK_TO_KEYFRAME) if (IsSeekPending_Locked()) { DVLOG(1) << "Seek() : waiting for more data to arrive."; @@ -961,6 +979,12 @@ return false; } + if (delayed_audio_seek_ && !video_->IsSeekPending()) { + DCHECK(audio_); + audio_->Seek(video_->GetSeekKeyframeTimestamp()); + delayed_audio_seek_ = false; + } + // Check to see if data was appended at the pending seek point. This // indicates we have parsed enough data to complete the seek. if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) {
diff --git a/src/media/filters/chunk_demuxer.h b/src/media/filters/chunk_demuxer.h index e127c08..6e09181 100644 --- a/src/media/filters/chunk_demuxer.h +++ b/src/media/filters/chunk_demuxer.h
@@ -186,6 +186,7 @@ PipelineStatusCB init_cb_; PipelineStatusCB seek_cb_; + bool delayed_audio_seek_; scoped_refptr<ChunkDemuxerStream> audio_; scoped_refptr<ChunkDemuxerStream> video_;
diff --git a/src/media/filters/shell_demuxer.cc b/src/media/filters/shell_demuxer.cc index 6671985..3d18888 100644 --- a/src/media/filters/shell_demuxer.cc +++ b/src/media/filters/shell_demuxer.cc
@@ -342,7 +342,8 @@ // AllocateBuffer will return false if the requested size is larger // than the maximum limit for a single buffer. if (!ShellBufferFactory::Instance()->AllocateBuffer( - au->GetMaxSize(), base::Bind(&ShellDemuxer::BufferAllocated, this))) { + au->GetMaxSize(), au->IsKeyframe(), + base::Bind(&ShellDemuxer::BufferAllocated, this))) { DLOG(ERROR) << "buffer allocation failed."; host_->OnDemuxerError(PIPELINE_ERROR_COULD_NOT_RENDER); return;
diff --git a/src/media/filters/source_buffer_stream.cc b/src/media/filters/source_buffer_stream.cc index 31e64b6..7f3678d 100644 --- a/src/media/filters/source_buffer_stream.cc +++ b/src/media/filters/source_buffer_stream.cc
@@ -968,6 +968,7 @@ SetSelectedRange(ranges_.front()); ranges_.front()->SeekToStart(); seek_pending_ = false; + seek_buffer_timestamp_ = GetNextBufferTimestamp(); return; } @@ -986,12 +987,18 @@ SetSelectedRange(*itr); selected_range_->Seek(timestamp); seek_pending_ = false; + seek_buffer_timestamp_ = GetNextBufferTimestamp(); } bool SourceBufferStream::IsSeekPending() const { return seek_pending_; } +base::TimeDelta SourceBufferStream::GetSeekKeyframeTimestamp() const { + DCHECK(!IsSeekPending()); + return seek_buffer_timestamp_; +} + void SourceBufferStream::OnSetDuration(base::TimeDelta duration) { RangeList::iterator itr = ranges_.end(); for (itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
diff --git a/src/media/filters/source_buffer_stream.h b/src/media/filters/source_buffer_stream.h index 4f0ff4b..babcb65 100644 --- a/src/media/filters/source_buffer_stream.h +++ b/src/media/filters/source_buffer_stream.h
@@ -72,6 +72,11 @@ // buffered data and is waiting for more data to be appended. bool IsSeekPending() const; + // Returns the timestamp of the keyframe before the seek timestamp. Note that + // this value is only valid (thus this function should only be called) when + // IsSeekPending() returns false. + base::TimeDelta GetSeekKeyframeTimestamp() const; + // Notifies the SourceBufferStream that the media duration has been changed to // |duration| so it should drop any data past that point. void OnSetDuration(base::TimeDelta duration); @@ -269,6 +274,9 @@ // false if no Seek() has been requested or the Seek() is completed. bool seek_pending_; + // The timestamp of the keyframe right before the seek timestamp. + base::TimeDelta seek_keyframe_timestamp_; + // Timestamp of the last request to Seek(). base::TimeDelta seek_buffer_timestamp_;
diff --git a/src/media/media.gyp b/src/media/media.gyp index c2faa35..12ebe12 100644 --- a/src/media/media.gyp +++ b/src/media/media.gyp
@@ -716,7 +716,15 @@ ['sb_media_platform == "starboard"', { 'sources': [ 'audio/shell_audio_streamer_starboard.cc', + 'base/decoder_buffer_cache.cc', + 'base/decoder_buffer_cache.h', + 'base/sbplayer_set_bounds_helper.cc', + 'base/sbplayer_set_bounds_helper.h', 'base/sbplayer_pipeline.cc', + 'base/starboard_player.cc', + 'base/starboard_player.h', + 'base/starboard_utils.cc', + 'base/starboard_utils.h', 'crypto/starboard_decryptor.cc', 'crypto/starboard_decryptor.h', ],
diff --git a/src/media/player/web_media_player.h b/src/media/player/web_media_player.h index ef6b89a..6b97161 100644 --- a/src/media/player/web_media_player.h +++ b/src/media/player/web_media_player.h
@@ -102,6 +102,10 @@ virtual const Ranges<base::TimeDelta>& GetBufferedTimeRanges() = 0; virtual float GetMaxTimeSeekable() const = 0; + // Suspend/Resume + virtual void Suspend() = 0; + virtual void Resume() = 0; + // True if the loaded media has a playable video/audio track. virtual bool HasVideo() const = 0; virtual bool HasAudio() const = 0;
diff --git a/src/media/player/web_media_player_impl.cc b/src/media/player/web_media_player_impl.cc index 1defe0f..d3b4a19 100644 --- a/src/media/player/web_media_player_impl.cc +++ b/src/media/player/web_media_player_impl.cc
@@ -536,6 +536,14 @@ return static_cast<float>(pipeline_->GetMediaDuration().InSecondsF()); } +void WebMediaPlayerImpl::Suspend() { + pipeline_->Suspend(); +} + +void WebMediaPlayerImpl::Resume() { + pipeline_->Resume(); +} + bool WebMediaPlayerImpl::DidLoadingProgress() const { DCHECK_EQ(main_loop_, MessageLoop::current()); return pipeline_->DidLoadingProgress();
diff --git a/src/media/player/web_media_player_impl.h b/src/media/player/web_media_player_impl.h index fcc1030..6b1db75 100644 --- a/src/media/player/web_media_player_impl.h +++ b/src/media/player/web_media_player_impl.h
@@ -137,6 +137,10 @@ const Ranges<base::TimeDelta>& GetBufferedTimeRanges() OVERRIDE; float GetMaxTimeSeekable() const OVERRIDE; + // Suspend/Resume + void Suspend() OVERRIDE; + void Resume() OVERRIDE; + // True if the loaded media has a playable video/audio track. bool HasVideo() const OVERRIDE; bool HasAudio() const OVERRIDE;
diff --git a/src/nb/reuse_allocator.cc b/src/nb/reuse_allocator.cc index 70898ae..c12375d 100644 --- a/src/nb/reuse_allocator.cc +++ b/src/nb/reuse_allocator.cc
@@ -266,21 +266,8 @@ } void ReuseAllocator::Free(void* memory) { - if (!memory) { - return; - } - - AllocatedBlockMap::iterator it = allocated_blocks_.find(memory); - SB_DCHECK(it != allocated_blocks_.end()); - - // Mark this block as free and remove it from the allocated set. - const MemoryBlock& block = (*it).second; - AddFreeBlock(block); - - SB_DCHECK(block.size() <= total_allocated_); - total_allocated_ -= block.size(); - - allocated_blocks_.erase(it); + bool result = TryFree(memory); + SB_DCHECK(result); } void ReuseAllocator::PrintAllocations() const { @@ -302,4 +289,25 @@ SB_LOG(INFO) << "Total allocations: " << allocated_blocks_.size(); } +bool ReuseAllocator::TryFree(void* memory) { + if (!memory) { + return true; + } + + AllocatedBlockMap::iterator it = allocated_blocks_.find(memory); + if (it == allocated_blocks_.end()) { + return false; + } + + // Mark this block as free and remove it from the allocated set. + const MemoryBlock& block = (*it).second; + AddFreeBlock(block); + + SB_DCHECK(block.size() <= total_allocated_); + total_allocated_ -= block.size(); + + allocated_blocks_.erase(it); + return true; +} + } // namespace nb
diff --git a/src/nb/reuse_allocator.h b/src/nb/reuse_allocator.h index 7686930..71d43d8 100644 --- a/src/nb/reuse_allocator.h +++ b/src/nb/reuse_allocator.h
@@ -65,6 +65,8 @@ void PrintAllocations() const; + bool TryFree(void* memory); + private: class MemoryBlock { public:
diff --git a/src/nb/reuse_allocator_benchmark.cc b/src/nb/reuse_allocator_benchmark.cc index 5e48ba7..ac53c08 100644 --- a/src/nb/reuse_allocator_benchmark.cc +++ b/src/nb/reuse_allocator_benchmark.cc
@@ -181,7 +181,7 @@ void* Allocate(std::size_t size, std::size_t alignment) SB_OVERRIDE { return SbMemoryAllocateAligned(alignment, size); } - void Free(void* memory) SB_OVERRIDE { SbMemoryFree(memory); } + void Free(void* memory) SB_OVERRIDE { SbMemoryDeallocate(memory); } std::size_t GetCapacity() const SB_OVERRIDE { return 0; } std::size_t GetAllocated() const SB_OVERRIDE { return 0; } void PrintAllocations() const SB_OVERRIDE {} @@ -210,7 +210,7 @@ SB_DLOG(INFO) << "Allocator high water mark: " << allocator_high_water_mark; SB_DLOG(INFO) << "Elapsed (ms): " << elapsed_time / kSbTimeMillisecond; - SbMemoryFree(fixed_no_free_memory); + SbMemoryDeallocate(fixed_no_free_memory); // Test again using the system allocator, to compare performance. DefaultAllocator default_allocator;
diff --git a/src/net/http/http_auth_handler_ntlm.cc b/src/net/http/http_auth_handler_ntlm.cc index ceca94a..aa0142a 100644 --- a/src/net/http/http_auth_handler_ntlm.cc +++ b/src/net/http/http_auth_handler_ntlm.cc
@@ -15,7 +15,7 @@ #if defined(OS_STARBOARD) #include "starboard/memory.h" -#define free SbMemoryFree +#define free SbMemoryDeallocate #endif namespace net {
diff --git a/src/net/http/http_auth_handler_ntlm_portable.cc b/src/net/http/http_auth_handler_ntlm_portable.cc index dbcfd94..63cdcee 100644 --- a/src/net/http/http_auth_handler_ntlm_portable.cc +++ b/src/net/http/http_auth_handler_ntlm_portable.cc
@@ -7,7 +7,7 @@ #if defined(OS_STARBOARD) #include "starboard/memory.h" #define malloc SbMemoryAllocate -#define free SbMemoryFree +#define free SbMemoryDeallocate #else #include <stdlib.h> #endif
diff --git a/src/starboard/client_porting/poem/stdio_poem.h b/src/starboard/client_porting/poem/stdio_poem.h index d68c688..eab3f05 100644 --- a/src/starboard/client_porting/poem/stdio_poem.h +++ b/src/starboard/client_porting/poem/stdio_poem.h
@@ -34,10 +34,10 @@ #define sprintf SbStringFormatUnsafeF #define vsscanf SbStringScan #define sscanf SbStringScanF -#define malloc(sz) SbMemoryAllocateUnchecked(sz) +#define malloc(sz) SbMemoryAllocate(sz) #define calloc(c, s) SbMemoryCalloc(c, s) -#define free(a) SbMemoryFree(a) -#define realloc(m, sz) SbMemoryReallocateUnchecked(m, sz) +#define free(a) SbMemoryDeallocate(a) +#define realloc(m, sz) SbMemoryReallocate(m, sz) #endif // POEM_NO_EMULATION
diff --git a/src/starboard/common/common.gyp b/src/starboard/common/common.gyp index b0bc5df..0503988 100644 --- a/src/starboard/common/common.gyp +++ b/src/starboard/common/common.gyp
@@ -19,8 +19,12 @@ 'targets': [ { 'target_name': 'common', - 'type': 'none', + 'type': 'static_library', + 'variables': { + 'includes_starboard': 1, + }, 'sources': [ + 'memory.cc', 'move.h', 'reset_and_return.h', 'scoped_ptr.h',
diff --git a/src/starboard/common/memory.cc b/src/starboard/common/memory.cc new file mode 100644 index 0000000..6067214 --- /dev/null +++ b/src/starboard/common/memory.cc
@@ -0,0 +1,88 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "starboard/memory.h" + +inline void* SbMemoryAllocateImpl(size_t size); +inline void* SbMemoryAllocateAlignedImpl(size_t alignment, size_t size); +inline void* SbMemoryReallocateImpl(void* memory, size_t size); + +void* SbMemoryAllocate(size_t size) { + void* memory = SbMemoryAllocateImpl(size); + return memory; +} + +void* SbMemoryAllocateAligned(size_t alignment, size_t size) { + void* memory = SbMemoryAllocateAlignedImpl(alignment, size); + return memory; +} + +void* SbMemoryReallocate(void* memory, size_t size) { + void* new_memory = SbMemoryReallocateImpl(memory, size); + return new_memory; +} + +void SbMemoryDeallocate(void* memory) { + SbMemoryFree(memory); +} + +void SbMemoryDeallocateAligned(void* memory) { + SbMemoryFreeAligned(memory); +} + +// Same as SbMemoryReallocateUnchecked, but will abort() in the case of an +// allocation failure +void* SbMemoryReallocateChecked(void* memory, size_t size) { + void* address = SbMemoryReallocateUnchecked(memory, size); + SbAbortIfAllocationFailed(size, address); + return address; +} + +// Same as SbMemoryAllocateAlignedUnchecked, but will abort() in the case of an +// allocation failure +void* SbMemoryAllocateAlignedChecked(size_t alignment, size_t size) { + void* address = SbMemoryAllocateAlignedUnchecked(alignment, size); + SbAbortIfAllocationFailed(size, address); + return address; +} + +void* SbMemoryAllocateChecked(size_t size) { + void* address = SbMemoryAllocateUnchecked(size); + SbAbortIfAllocationFailed(size, address); + return address; +} + +inline void* SbMemoryAllocateImpl(size_t size) { +#if SB_ABORT_ON_ALLOCATION_FAILURE + return SbMemoryAllocateChecked(size); +#else + return SbMemoryAllocateUnchecked(size); +#endif +} + +inline void* SbMemoryAllocateAlignedImpl(size_t alignment, size_t size) { +#if SB_ABORT_ON_ALLOCATION_FAILURE + return SbMemoryAllocateAlignedChecked(alignment, size); +#else + return SbMemoryAllocateAlignedUnchecked(alignment, size); +#endif +} + +inline void* SbMemoryReallocateImpl(void* memory, size_t size) { +#if SB_ABORT_ON_ALLOCATION_FAILURE + return SbMemoryReallocateChecked(memory, size); +#else + return SbMemoryReallocateUnchecked(memory, size); +#endif +}
diff --git a/src/starboard/common/scoped_ptr.h b/src/starboard/common/scoped_ptr.h index a762268..b62f1c6 100644 --- a/src/starboard/common/scoped_ptr.h +++ b/src/starboard/common/scoped_ptr.h
@@ -362,7 +362,7 @@ // passed as a template argument to scoped_ptr_malloc below. class ScopedPtrMallocFree { public: - inline void operator()(void* x) const { SbMemoryFree(x); } + inline void operator()(void* x) const { SbMemoryDeallocate(x); } }; // scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h index e075b47..1334ac8 100644 --- a/src/starboard/configuration.h +++ b/src/starboard/configuration.h
@@ -186,6 +186,26 @@ #endif // SB_IS(COMPILER_MSVC) #endif // !defined(SB_UNLIKELY) +// SB_DEPRECATED(int Foo(int bar)); +// Annotates the function as deprecated, which will trigger a compiler +// warning when referenced. +#if SB_IS(COMPILER_GCC) +#define SB_DEPRECATED(FUNC) FUNC __attribute__((deprecated)) +#elif SB_IS(COMPILER_MSVC) +#define SB_DEPRECATED(FUNC) __declspec(deprecated) FUNC +#else +// Empty definition for other compilers. +#define SB_DEPRECATED(FUNC) FUNC +#endif + +// SB_DEPRECATED_EXTERNAL(...) annotates the function as deprecated for +// external clients, but not deprecated for starboard. +#if defined(STARBOARD_IMPLEMENTATION) +#define SB_DEPRECATED_EXTERNAL(FUNC) FUNC +#else +#define SB_DEPRECATED_EXTERNAL(FUNC) SB_DEPRECATED(FUNC) +#endif + // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #define SB_DISALLOW_COPY_AND_ASSIGN(TypeName) \ @@ -368,6 +388,20 @@ #error "Your platform must define SB_HAS_THREAD_PRIORITY_SUPPORT." #endif +#if SB_HAS(THREAD_PRIORITY_SUPPORT) + +#if !defined(SB_HAS_REAL_TIME_PRIORITY_SUPPORT) +#error "Your platform must define SB_HAS_REAL_TIME_PRIORITY_SUPPORT." +#endif + +#else // SB_HAS(THREAD_PRIORITY_SUPPORT) + +#if defined(SB_HAS_REAL_TIME_PRIORITY_SUPPORT) +#error "Don't define SB_HAS_REAL_TIME_PRIORITY_SUPPORT without priorities." +#endif + +#endif // SB_HAS(THREAD_PRIORITY_SUPPORT) + #if !defined(SB_PREFERRED_RGBA_BYTE_ORDER) // Legal values for SB_PREFERRED_RGBA_BYTE_ORDER are defined in this file above // as SB_PREFERRED_RGBA_BYTE_ORDER_*.
diff --git a/src/starboard/examples/glclear/main.cc b/src/starboard/examples/glclear/main.cc index 7d520ec..129c06c 100644 --- a/src/starboard/examples/glclear/main.cc +++ b/src/starboard/examples/glclear/main.cc
@@ -125,7 +125,7 @@ } SB_DCHECK(surface_ != EGL_NO_SURFACE); - SbMemoryFree(configs); + SbMemoryDeallocate(configs); eglQuerySurface(display_, surface_, EGL_WIDTH, &egl_surface_width_); eglQuerySurface(display_, surface_, EGL_HEIGHT, &egl_surface_height_);
diff --git a/src/starboard/memory.h b/src/starboard/memory.h index f418c30..f48b44e 100644 --- a/src/starboard/memory.h +++ b/src/starboard/memory.h
@@ -11,12 +11,18 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - +// // Memory allocation, alignment, copying, and comparing. +// +// DO NOT CALL SbMemoryAllocateUnchecked(), SbMemoryAllocateChecked() +// SbMemoryReallocateUnchecked(), SbMemoryReallocateChecked(), +// SbMemoryAllocateAlignedUnchecked(), SbMemoryAllocateAlignedChecked(), +// SbMemoryFree(), SbMemoryFreeAligned(). They are internal. #ifndef STARBOARD_MEMORY_H_ #define STARBOARD_MEMORY_H_ +#include "starboard/configuration.h" #include "starboard/export.h" #include "starboard/system.h" #include "starboard/types.h" @@ -27,16 +33,6 @@ #define SB_MEMORY_MAP_FAILED ((void*)-1) // NOLINT(readability/casting) -#if defined(SB_ABORT_ON_ALLOCATION_FAILURE) -#define SbMemoryAllocate SbMemoryAllocateChecked -#define SbMemoryReallocate SbMemoryReallocateChecked -#define SbMemoryAllocateAligned SbMemoryAllocateAlignedChecked -#else -#define SbMemoryAllocate SbMemoryAllocateUnchecked -#define SbMemoryReallocate SbMemoryReallocateUnchecked -#define SbMemoryAllocateAligned SbMemoryAllocateAlignedUnchecked -#endif - // The bitwise OR of these flags should be passed to SbMemoryMap to indicate // how the mapped memory can be used. typedef enum SbMemoryMapFlags { @@ -71,16 +67,10 @@ // Allocates a chunk of memory of at least |size| bytes, returning it. If unable // to allocate the memory, it returns NULL. If |size| is 0, it may return NULL // or it may return a unique pointer value that can be passed to -// SbMemoryFree. Meant to be a drop-in replacement for malloc. -SB_EXPORT void* SbMemoryAllocateUnchecked(size_t size); - -// Same as SbMemoryAllocateUnchecked, but will abort() in the case of an -// allocation failure. -static SB_C_FORCE_INLINE void* SbMemoryAllocateChecked(size_t size) { - void* address = SbMemoryAllocateUnchecked(size); - SbAbortIfAllocationFailed(size, address); - return address; -} +// SbMemoryDeallocate. Meant to be a drop-in replacement for malloc. +// +// This memory function should be called from the Cobalt codebase. +SB_EXPORT void* SbMemoryAllocate(size_t size); // Attempts to resize |memory| to be at least |size| bytes, without touching the // contents. If it cannot perform the fast resize, it will allocate a new chunk @@ -89,42 +79,72 @@ // return NULL, leaving the given memory chunk unchanged. |memory| may be NULL, // in which case it behaves exactly like SbMemoryAllocateUnchecked. If |size| // is 0, it may return NULL or it may return a unique pointer value that can be -// passed to SbMemoryFree. Meant to be a drop-in replacement for realloc. -SB_EXPORT void* SbMemoryReallocateUnchecked(void* memory, size_t size); +// passed to SbMemoryDeallocate. Meant to be a drop-in replacement for realloc. +// +// This memory function should be called from the Cobalt codebase. +SB_EXPORT void* SbMemoryReallocate(void* memory, size_t size); -// Same as SbMemoryReallocateUnchecked, but will abort() in the case of an -// allocation failure -static SB_C_FORCE_INLINE void* SbMemoryReallocateChecked(void* memory, - size_t size) { - void* address = SbMemoryReallocateUnchecked(memory, size); - SbAbortIfAllocationFailed(size, address); - return address; -} +// Allocates a chunk of memory of at least |size| bytes, aligned to +// |alignment|, returning it. |alignment| must be a power of two, otherwise +// behavior is undefined. If unable to allocate the memory, it returns NULL. +// If |size| is 0, it may return NULL or it may return a unique aligned pointer +// value that can be passed to SbMemoryDeallocateAligned. Meant to be a drop-in +// replacement for memalign. +// +// This memory function should be called from the Cobalt codebase. +SB_EXPORT void* SbMemoryAllocateAligned(size_t alignment, size_t size); // Frees a previously allocated chunk of memory. If |memory| is NULL, then it // does nothing. Meant to be a drop-in replacement for free. -SB_EXPORT void SbMemoryFree(void* memory); - -// Allocates a chunk of memory of at least |size| bytes, aligned to |alignment|, -// returning it. |alignment| must be a power of two, otherwise behavior is -// undefined. If unable to allocate the memory, it returns NULL. If |size| is 0, -// it may return NULL or it may return a unique aligned pointer value that can -// be passed to SbMemoryFreeAligned. Meant to be a drop-in replacement for -// memalign. -SB_EXPORT void* SbMemoryAllocateAlignedUnchecked(size_t alignment, size_t size); - -// Same as SbMemoryAllocateAlignedUnchecked, but will abort() in the case of an -// allocation failure -static SB_C_FORCE_INLINE void* SbMemoryAllocateAlignedChecked(size_t alignment, - size_t size) { - void* address = SbMemoryAllocateAlignedUnchecked(alignment, size); - SbAbortIfAllocationFailed(size, address); - return address; -} +// +// This memory function should be called from the Cobalt codebase. +SB_EXPORT void SbMemoryDeallocate(void* memory); // Frees a previously allocated chunk of aligned memory. If |memory| is NULL, // then it does nothing. Meant to be a drop-in replacement for _aligned_free. -SB_EXPORT void SbMemoryFreeAligned(void* memory); +// +// This memory function should be called from the Cobalt codebase. +SB_EXPORT void SbMemoryDeallocateAligned(void* memory); + +///////////////////////////////////////////////////////////////// +// The following functions must be provided by Starboard ports. +///////////////////////////////////////////////////////////////// + +// This is the implementation of SbMemoryAllocate that must be +// provided by Starboard ports. +// +// DO NOT CALL. Call SbMemoryAllocate(...) instead. +SB_DEPRECATED_EXTERNAL( + SB_EXPORT void* SbMemoryAllocateUnchecked(size_t size)); + +// This is the implementation of SbMemoryReallocate that must be +// provided by Starboard ports. +// +// DO NOT CALL. Call SbMemoryReallocate(...) instead. +SB_DEPRECATED_EXTERNAL( + SB_EXPORT void* SbMemoryReallocateUnchecked(void* memory, size_t size)); + +// This is the implementation of SbMemoryAllocateAligned that must be +// provided by Starboard ports. +// +// DO NOT CALL. Call SbMemoryAllocateAligned(...) instead. +SB_DEPRECATED_EXTERNAL( + SB_EXPORT void* SbMemoryAllocateAlignedUnchecked(size_t alignment, + size_t size)); + +// This is the implementation of SbMemoryDeallocate that must be provided by +// Starboard ports. +// +// DO NOT CALL. Call SbMemoryDeallocate(...) instead. +SB_DEPRECATED_EXTERNAL( + SB_EXPORT void SbMemoryFree(void* memory)); + +// This is the implementation of SbMemoryFreeAligned that must be provided by +// Starboard ports. +// +// DO NOT CALL. Call SbMemoryDeallocateAligned(...) instead. +SB_DEPRECATED_EXTERNAL( + SB_EXPORT void SbMemoryFreeAligned(void* memory)); #if SB_HAS(MMAP) // Allocates |size_bytes| worth of physical memory pages and maps them into an @@ -206,6 +226,32 @@ return result; } +///////////////////////////////////////////////////////////////// +// Deprecated. Do not use. +///////////////////////////////////////////////////////////////// + +// Same as SbMemoryAllocateUnchecked, but will abort() in the case of an +// allocation failure. +// +// DO NOT CALL. Call SbMemoryAllocate(...) instead. +SB_DEPRECATED_EXTERNAL( + SB_EXPORT void* SbMemoryAllocateChecked(size_t size)); + +// Same as SbMemoryReallocateUnchecked, but will abort() in the case of an +// allocation failure. +// +// DO NOT CALL. Call SbMemoryReallocate(...) instead. +SB_DEPRECATED_EXTERNAL( + SB_EXPORT void* SbMemoryReallocateChecked(void* memory, size_t size)); + +// Same as SbMemoryAllocateAlignedUnchecked, but will abort() in the case of an +// allocation failure. +// +// DO NOT CALL. Call SbMemoryAllocateAligned(...) instead. +SB_DEPRECATED_EXTERNAL( + SB_EXPORT void* SbMemoryAllocateAlignedChecked(size_t alignment, + size_t size)); + #ifdef __cplusplus } // extern "C" #endif
diff --git a/src/starboard/nplb/memory_allocate_aligned_test.cc b/src/starboard/nplb/memory_allocate_aligned_test.cc index 72cb82b..dbdc217 100644 --- a/src/starboard/nplb/memory_allocate_aligned_test.cc +++ b/src/starboard/nplb/memory_allocate_aligned_test.cc
@@ -29,7 +29,7 @@ void* memory = SbMemoryAllocateAligned(align, kSize); ASSERT_NE(static_cast<void*>(NULL), memory); EXPECT_TRUE(SbMemoryIsAligned(memory, align)); - SbMemoryFreeAligned(memory); + SbMemoryDeallocateAligned(memory); } } @@ -43,7 +43,7 @@ if (memory) { EXPECT_TRUE(SbMemoryIsAligned(memory, align)); } - SbMemoryFreeAligned(memory); + SbMemoryDeallocateAligned(memory); } } @@ -60,7 +60,7 @@ EXPECT_EQ(data[i], static_cast<char>(i)); } - SbMemoryFreeAligned(memory); + SbMemoryDeallocateAligned(memory); } } // namespace
diff --git a/src/starboard/nplb/memory_allocate_test.cc b/src/starboard/nplb/memory_allocate_test.cc index 1da3ae6..87e252c 100644 --- a/src/starboard/nplb/memory_allocate_test.cc +++ b/src/starboard/nplb/memory_allocate_test.cc
@@ -24,20 +24,20 @@ TEST(SbMemoryAllocateTest, AllocatesNormally) { void* memory = SbMemoryAllocate(kSize); EXPECT_NE(static_cast<void*>(NULL), memory); - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryAllocateTest, AllocatesZero) { void* memory = SbMemoryAllocate(0); // We can't expect anything here because some implementations may return an // allocated zero-size memory block, and some implementations may return NULL. - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryAllocateTest, AllocatesOne) { void* memory = SbMemoryAllocate(1); EXPECT_NE(static_cast<void*>(NULL), memory); - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryAllocateTest, CanReadWriteToResult) { @@ -52,7 +52,7 @@ EXPECT_EQ(data[i], static_cast<char>(i)); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } } // namespace
diff --git a/src/starboard/nplb/memory_compare_test.cc b/src/starboard/nplb/memory_compare_test.cc index f0d07c1..2057df7 100644 --- a/src/starboard/nplb/memory_compare_test.cc +++ b/src/starboard/nplb/memory_compare_test.cc
@@ -36,8 +36,8 @@ int result = SbMemoryCompare(memory1, memory2, kSize); EXPECT_EQ(0, result); - SbMemoryFree(memory1); - SbMemoryFree(memory2); + SbMemoryDeallocate(memory1); + SbMemoryDeallocate(memory2); } TEST(SbMemoryCompareTest, SunnyDayLessAndMore) { @@ -62,8 +62,8 @@ result = SbMemoryCompare(memory2, memory1, kSize); EXPECT_GT(0, result); - SbMemoryFree(memory1); - SbMemoryFree(memory2); + SbMemoryDeallocate(memory1); + SbMemoryDeallocate(memory2); } } // namespace
diff --git a/src/starboard/nplb/memory_copy_test.cc b/src/starboard/nplb/memory_copy_test.cc index 1142615..f8d3342 100644 --- a/src/starboard/nplb/memory_copy_test.cc +++ b/src/starboard/nplb/memory_copy_test.cc
@@ -41,8 +41,8 @@ EXPECT_EQ(data2[i], static_cast<char>(i)); } - SbMemoryFree(memory1); - SbMemoryFree(memory2); + SbMemoryDeallocate(memory1); + SbMemoryDeallocate(memory2); } TEST(SbMemoryCopyTest, CopiesZeroData) { @@ -65,8 +65,8 @@ EXPECT_EQ(data2[i], static_cast<char>(0)); } - SbMemoryFree(memory1); - SbMemoryFree(memory2); + SbMemoryDeallocate(memory1); + SbMemoryDeallocate(memory2); } } // namespace
diff --git a/src/starboard/nplb/memory_free_aligned_test.cc b/src/starboard/nplb/memory_deallocate_aligned_test.cc similarity index 84% rename from src/starboard/nplb/memory_free_aligned_test.cc rename to src/starboard/nplb/memory_deallocate_aligned_test.cc index 5fbc8da..39cea85 100644 --- a/src/starboard/nplb/memory_free_aligned_test.cc +++ b/src/starboard/nplb/memory_deallocate_aligned_test.cc
@@ -21,16 +21,16 @@ const size_t kSize = 1024 * 128; -TEST(SbMemoryFreeAlignedTest, FreesAligned) { +TEST(SbMemoryDeallocateAlignedTest, DeallocatesAligned) { const size_t kMaxAlign = 4096 + 1; for (size_t align = 2; align < kMaxAlign; align <<= 1) { void* memory = SbMemoryAllocateAligned(align, kSize); - SbMemoryFreeAligned(memory); + SbMemoryDeallocateAligned(memory); } } -TEST(SbMemoryFreeAlignedTest, FreesNull) { - SbMemoryFreeAligned(NULL); +TEST(SbMemoryDeallocateAlignedTest, FreesNull) { + SbMemoryDeallocateAligned(NULL); } } // namespace
diff --git a/src/starboard/nplb/memory_free_test.cc b/src/starboard/nplb/memory_deallocate_test.cc similarity index 86% rename from src/starboard/nplb/memory_free_test.cc rename to src/starboard/nplb/memory_deallocate_test.cc index 3e25330..9bd8739 100644 --- a/src/starboard/nplb/memory_free_test.cc +++ b/src/starboard/nplb/memory_deallocate_test.cc
@@ -21,14 +21,14 @@ const size_t kSize = 1024 * 128; -TEST(SbMemoryFreeTest, FreesNormally) { +TEST(SbMemoryDeallocateTest, FreesNormally) { void* memory = SbMemoryAllocate(kSize); EXPECT_NE(static_cast<void*>(NULL), memory); - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } -TEST(SbMemoryFreeTest, FreesNull) { - SbMemoryFree(NULL); +TEST(SbMemoryDeallocateTest, FreesNull) { + SbMemoryDeallocate(NULL); } } // namespace
diff --git a/src/starboard/nplb/memory_move_test.cc b/src/starboard/nplb/memory_move_test.cc index 590a51e..c4b0e39 100644 --- a/src/starboard/nplb/memory_move_test.cc +++ b/src/starboard/nplb/memory_move_test.cc
@@ -41,8 +41,8 @@ EXPECT_EQ(data2[i], static_cast<char>(i)); } - SbMemoryFree(memory1); - SbMemoryFree(memory2); + SbMemoryDeallocate(memory1); + SbMemoryDeallocate(memory2); } TEST(SbMemoryMoveTest, MovesZeroData) { @@ -65,8 +65,8 @@ EXPECT_EQ(data2[i], static_cast<char>(i + 1)); } - SbMemoryFree(memory1); - SbMemoryFree(memory2); + SbMemoryDeallocate(memory1); + SbMemoryDeallocate(memory2); } TEST(SbMemoryMoveTest, MovesOverlappingDataForward) { @@ -84,7 +84,7 @@ EXPECT_EQ(data[i + 3], static_cast<char>(i)); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryMoveTest, MovesOverlappingDataBackwards) { @@ -102,7 +102,7 @@ EXPECT_EQ(data[i], static_cast<char>(i + 3)); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } } // namespace
diff --git a/src/starboard/nplb/memory_reallocate_test.cc b/src/starboard/nplb/memory_reallocate_test.cc index 72d0036..7ca252c 100644 --- a/src/starboard/nplb/memory_reallocate_test.cc +++ b/src/starboard/nplb/memory_reallocate_test.cc
@@ -24,20 +24,20 @@ TEST(SbMemoryReallocateTest, AllocatesNormally) { void* memory = SbMemoryReallocate(NULL, kSize); EXPECT_NE(static_cast<void*>(NULL), memory); - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryReallocateTest, AllocatesZero) { void* memory = SbMemoryReallocate(NULL, 0); // We can't expect anything here because some implementations may return an // allocated zero-size memory block, and some implementations may return NULL. - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryReallocateTest, AllocatesOne) { void* memory = SbMemoryReallocate(NULL, 1); EXPECT_NE(static_cast<void*>(NULL), memory); - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryReallocateTest, CanReadWriteToResult) { @@ -52,7 +52,7 @@ EXPECT_EQ(data[i], static_cast<char>(i)); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryReallocateTest, ReallocatesSmaller) { @@ -74,7 +74,7 @@ EXPECT_EQ(data[i], static_cast<char>(i)); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryReallocateTest, ReallocatesBigger) { @@ -104,7 +104,7 @@ EXPECT_EQ(data[i], static_cast<char>(i)); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryReallocateTest, ReallocatestoZero) { @@ -112,7 +112,7 @@ ASSERT_NE(static_cast<void*>(NULL), memory); memory = SbMemoryReallocate(memory, 0); // See allocates zero above. - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemoryReallocateTest, ReallocatestoSameSize) { @@ -134,7 +134,7 @@ EXPECT_EQ(data[i], static_cast<char>(i)); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } } // namespace
diff --git a/src/starboard/nplb/memory_set_test.cc b/src/starboard/nplb/memory_set_test.cc index 0874104..a086170 100644 --- a/src/starboard/nplb/memory_set_test.cc +++ b/src/starboard/nplb/memory_set_test.cc
@@ -34,7 +34,7 @@ ASSERT_EQ('\xCD', data[i]); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemorySetTest, SetsZeroData) { @@ -50,7 +50,7 @@ ASSERT_EQ(static_cast<char>(i), data[i]); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } TEST(SbMemorySetTest, IgnoresExtraData) { @@ -66,7 +66,7 @@ ASSERT_EQ('\xCD', data[i]); } - SbMemoryFree(memory); + SbMemoryDeallocate(memory); } } // namespace
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp index 1938621..da63d88 100644 --- a/src/starboard/nplb/nplb.gyp +++ b/src/starboard/nplb/nplb.gyp
@@ -114,8 +114,8 @@ 'memory_compare_test.cc', 'memory_copy_test.cc', 'memory_find_byte_test.cc', - 'memory_free_aligned_test.cc', - 'memory_free_test.cc', + 'memory_deallocate_aligned_test.cc', + 'memory_deallocate_test.cc', 'memory_get_stack_bounds_test.cc', 'memory_map_test.cc', 'memory_move_test.cc',
diff --git a/src/starboard/nplb/socket_send_to_test.cc b/src/starboard/nplb/socket_send_to_test.cc index b7b2f06..9db1d36 100644 --- a/src/starboard/nplb/socket_send_to_test.cc +++ b/src/starboard/nplb/socket_send_to_test.cc
@@ -15,19 +15,78 @@ // SendTo is largely tested with ReceiveFrom, so look there for more invovled // tests. +#include "starboard/memory.h" +#include "starboard/nplb/socket_helpers.h" #include "starboard/socket.h" +#include "starboard/thread.h" +#include "starboard/time.h" #include "testing/gtest/include/gtest/gtest.h" namespace starboard { namespace nplb { namespace { +// Thread entry point to continuously write to a socket that is expected to +// be closed on another thread. +void* SendToServerSocketEntryPoint(void* trio_as_void_ptr) { + ConnectedTrio* trio = static_cast<ConnectedTrio*>(trio_as_void_ptr); + // The contents of this buffer are inconsequential. + const size_t kBufSize = 1024; + char* send_buf = new char[kBufSize]; + SbMemorySet(send_buf, 0, kBufSize); + + // Continue sending to the socket until it fails to send. It's expected that + // SbSocketSendTo will fail when the server socket closes, but the application + // should + // not terminate. + SbTime start = SbTimeGetNow(); + SbTime now = start; + SbTime kTimeout = kSbTimeSecond; + int result = 0; + while (result >= 0 && (now - start < kTimeout)) { + result = SbSocketSendTo(trio->server_socket, send_buf, kBufSize, NULL); + now = SbTimeGetNow(); + } + + delete[] send_buf; + return NULL; +} + TEST(SbSocketSendToTest, RainyDayInvalidSocket) { char buf[16]; int result = SbSocketSendTo(NULL, buf, sizeof(buf), NULL); EXPECT_EQ(-1, result); } +TEST(SbSocketSendToTest, RainyDaySendToClosedSocket) { + ConnectedTrio trio = + CreateAndConnect(GetPortNumberForTests(), kSocketTimeout); + EXPECT_NE(trio.client_socket, kSbSocketInvalid); + EXPECT_NE(trio.server_socket, kSbSocketInvalid); + EXPECT_NE(trio.listen_socket, kSbSocketInvalid); + + // We don't need the listen socket, so close it. + EXPECT_TRUE(SbSocketDestroy(trio.listen_socket)); + + // Start a thread to write to the client socket. + const bool kJoinable = true; + SbThread send_thread = SbThreadCreate( + 0, kSbThreadNoPriority, kSbThreadNoAffinity, kJoinable, "SendToTest", + SendToServerSocketEntryPoint, static_cast<void*>(&trio)); + + // Close the client, which should cause writes to the server socket to fail. + EXPECT_TRUE(SbSocketDestroy(trio.client_socket)); + + // Wait for the thread to exit and check the last socket error. + void* thread_result; + EXPECT_TRUE(SbThreadJoin(send_thread, &thread_result)); + // Check that the server_socket failed, as expected. + EXPECT_EQ(SbSocketGetLastError(trio.server_socket), kSbSocketErrorFailed); + + // Clean up the server socket. + EXPECT_TRUE(SbSocketDestroy(trio.server_socket)); +} + } // namespace } // namespace nplb } // namespace starboard
diff --git a/src/starboard/nplb/string_duplicate_test.cc b/src/starboard/nplb/string_duplicate_test.cc index d61e0c2..17b794b 100644 --- a/src/starboard/nplb/string_duplicate_test.cc +++ b/src/starboard/nplb/string_duplicate_test.cc
@@ -26,7 +26,7 @@ EXPECT_NE(kNull, dupe); EXPECT_EQ(0, SbStringCompareNoCase(input, dupe)); EXPECT_EQ(SbStringGetLength(input), SbStringGetLength(dupe)); - SbMemoryFree(dupe); + SbMemoryDeallocate(dupe); } TEST(SbStringDuplicateTest, SunnyDay) {
diff --git a/src/starboard/raspi/1/gyp_configuration.gypi b/src/starboard/raspi/1/gyp_configuration.gypi index 12a59f3..1b41d36 100644 --- a/src/starboard/raspi/1/gyp_configuration.gypi +++ b/src/starboard/raspi/1/gyp_configuration.gypi
@@ -32,7 +32,8 @@ # This should have a default value in cobalt/base.gypi. See the comment # there for acceptable values for this variable. - 'javascript_engine': 'javascriptcore', + 'javascript_engine': 'mozjs', + 'cobalt_enable_jit': 1, # RasPi 1 is ARMv6 'arm_version': 6,
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc index d60f480..0d04361 100644 --- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc +++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
@@ -82,7 +82,7 @@ } void ReleaseBuffer(AVCodecContext*, AVFrame* frame) { - SbMemoryFree(frame->opaque); + SbMemoryDeallocate(frame->opaque); frame->opaque = NULL; // The FFmpeg API expects us to zero the data pointers in this callback.
diff --git a/src/starboard/shared/posix/socket_receive_from.cc b/src/starboard/shared/posix/socket_receive_from.cc index 6acea4c..c4819b6 100644 --- a/src/starboard/shared/posix/socket_receive_from.cc +++ b/src/starboard/shared/posix/socket_receive_from.cc
@@ -27,6 +27,12 @@ char* out_data, int data_size, SbSocketAddress* out_source) { +#if defined(MSG_NOSIGNAL) + const int kRecvFlags = MSG_NOSIGNAL; +#else + const int kRecvFlags = 0; +#endif + if (!SbSocketIsValid(socket)) { errno = EBADF; return -1; @@ -52,7 +58,8 @@ } } - ssize_t bytes_read = recv(socket->socket_fd, out_data, data_size, 0); + ssize_t bytes_read = + recv(socket->socket_fd, out_data, data_size, kRecvFlags); if (bytes_read >= 0) { socket->error = kSbSocketOk; return static_cast<int>(bytes_read); @@ -66,8 +73,9 @@ return -1; } else if (socket->protocol == kSbSocketProtocolUdp) { sbposix::SockAddr sock_addr; - ssize_t bytes_read = recvfrom(socket->socket_fd, out_data, data_size, 0, - sock_addr.sockaddr(), &sock_addr.length); + ssize_t bytes_read = + recvfrom(socket->socket_fd, out_data, data_size, kRecvFlags, + sock_addr.sockaddr(), &sock_addr.length); if (bytes_read >= 0) { if (out_source) {
diff --git a/src/starboard/shared/posix/socket_send_to.cc b/src/starboard/shared/posix/socket_send_to.cc index 23e134d..6cd0c70 100644 --- a/src/starboard/shared/posix/socket_send_to.cc +++ b/src/starboard/shared/posix/socket_send_to.cc
@@ -26,6 +26,11 @@ const char* data, int data_size, const SbSocketAddress* destination) { +#if defined(MSG_NOSIGNAL) + const int kSendFlags = MSG_NOSIGNAL; +#else + const int kSendFlags = 0; +#endif if (!SbSocketIsValid(socket)) { errno = EBADF; return -1; @@ -39,7 +44,8 @@ return -1; } - ssize_t bytes_written = send(socket->socket_fd, data, data_size, 0); + ssize_t bytes_written = + send(socket->socket_fd, data, data_size, kSendFlags); if (bytes_written >= 0) { socket->error = kSbSocketOk; return static_cast<int>(bytes_written); @@ -70,8 +76,8 @@ sockaddr_length = sock_addr.length; } - ssize_t bytes_written = sendto(socket->socket_fd, data, data_size, 0, - sockaddr, sockaddr_length); + ssize_t bytes_written = sendto(socket->socket_fd, data, data_size, + kSendFlags, sockaddr, sockaddr_length); if (bytes_written >= 0) { socket->error = kSbSocketOk; return static_cast<int>(bytes_written);
diff --git a/src/starboard/shared/pthread/thread_create.cc b/src/starboard/shared/pthread/thread_create.cc index 1971d0d..8718ba4 100644 --- a/src/starboard/shared/pthread/thread_create.cc +++ b/src/starboard/shared/pthread/thread_create.cc
@@ -16,23 +16,27 @@ #include <pthread.h> #include <sched.h> +#include <sys/resource.h> #include <unistd.h> #include "starboard/log.h" #include "starboard/shared/pthread/is_success.h" #include "starboard/string.h" -#if SB_HAS(THREAD_PRIORITY_SUPPORT) +#if SB_HAS(THREAD_PRIORITY_SUPPORT) && SB_HAS(REAL_TIME_PRIORITY_SUPPORT) #if !defined(_POSIX_PRIORITY_SCHEDULING) #error "The _POSIX_PRIORITY_SCHEDULING define indicates that a pthreads \ system supports thread priorities, however this define is not \ defined on this system, contradicting the Starboard configuration \ indicating that priority scheduling is supported." #endif // !defined(_POSIX_PRIORITY_SCHEDULING) -#endif // SB_HAS(THREAD_PRIORITY_SUPPORT) +#endif // SB_HAS(THREAD_PRIORITY_SUPPORT) && SB_HAS(REAL_TIME_PRIORITY_SUPPORT) namespace { +#if SB_HAS(THREAD_PRIORITY_SUPPORT) +#if SB_HAS(REAL_TIME_PRIORITY_SUPPORT) + int SbThreadPriorityToPthread(SbThreadPriority priority) { switch (priority) { case kSbThreadPriorityLowest: @@ -52,14 +56,39 @@ } } +#else // SB_HAS(REAL_TIME_PRIORITY_SUPPORT) + +int SbThreadPriorityToNice(SbThreadPriority priority) { + switch (priority) { + case kSbThreadPriorityLowest: + return 10; + case kSbThreadPriorityLow: + return 5; + case kSbThreadNoPriority: + // Fall through on purpose to default to kThreadPriority_Normal. + case kSbThreadPriorityNormal: + return -5; + case kSbThreadPriorityHigh: + return -15; + case kSbThreadPriorityHighest: + return -18; + case kSbThreadPriorityRealTime: + return -19; + default: + SB_NOTREACHED(); + return 0; + } +} + +#endif // #if SB_HAS(REAL_TIME_PRIORITY_SUPPORT) +#endif // #if SB_HAS(THREAD_PRIORITY_SUPPORT) + struct ThreadParams { SbThreadAffinity affinity; SbThreadEntryPoint entry_point; char name[128]; void* context; -#if SB_HAS(THREAD_PRIORITY_SUPPORT) SbThreadPriority priority; -#endif // #if SB_HAS(THREAD_PRIORITY_SUPPORT) }; void* ThreadFunc(void* context) { @@ -72,6 +101,7 @@ } #if SB_HAS(THREAD_PRIORITY_SUPPORT) +#if SB_HAS(REAL_TIME_PRIORITY_SUPPORT) // Use Linux' regular scheduler for lowest priority threads. Real-time // priority threads (of any priority) will always have priority over // non-real-time threads (e.g. threads whose scheduler is setup to be @@ -84,7 +114,12 @@ SbThreadPriorityToPthread(thread_params->priority); sched_setscheduler(0, SCHED_FIFO, &thread_sched_param); } -#endif // #if SB_HAS(THREAD_PRIORITY_SUPPORT) +#else // #if SB_HAS(REAL_TIME_PRIORITY_SUPPORT) + // If we don't have real time thread priority support, then set the nice + // value instead for soft priority support. + setpriority(PRIO_PROCESS, 0, SbThreadPriorityToNice(thread_params->priority)); +#endif // SB_HAS(REAL_TIME_PRIORITY_SUPPORT) +#endif // SB_HAS(THREAD_PRIORITY_SUPPORT) delete thread_params; @@ -143,9 +178,7 @@ params->name[0] = '\0'; } -#if SB_HAS(THREAD_PRIORITY_SUPPORT) params->priority = priority; -#endif // #if SB_HAS(THREAD_PRIORITY_SUPPORT) SbThread thread = kSbThreadInvalid; result = pthread_create(&thread, &attributes, ThreadFunc, params);
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc index 26e08db..4498156 100644 --- a/src/starboard/shared/starboard/application.cc +++ b/src/starboard/shared/starboard/application.cc
@@ -77,7 +77,7 @@ reinterpret_cast<SbAtomicPtr>(NULL))); SB_DCHECK(old_instance); SB_DCHECK(old_instance == this); - SbMemoryFree(start_link_); + SbMemoryDeallocate(start_link_); } int Application::Run(int argc, char** argv) { @@ -141,7 +141,7 @@ #endif // SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT) void Application::SetStartLink(const char* start_link) { - SbMemoryFree(start_link_); + SbMemoryDeallocate(start_link_); if (start_link) { start_link_ = SbStringDuplicate(start_link); } else {
diff --git a/src/starboard/shared/starboard/log_message.cc b/src/starboard/shared/starboard/log_message.cc index 8e654b4..444bcd6 100644 --- a/src/starboard/shared/starboard/log_message.cc +++ b/src/starboard/shared/starboard/log_message.cc
@@ -51,7 +51,11 @@ } SbLogPriority GetMinLogLevel() { +#if SB_LOGGING_IS_OFFICIAL_BUILD + return SB_LOG_FATAL; +#else return g_min_log_level; +#endif } void Break() {
diff --git a/src/starboard/shared/starboard/new.cc b/src/starboard/shared/starboard/new.cc index bf4f97b..7e08ed0 100644 --- a/src/starboard/shared/starboard/new.cc +++ b/src/starboard/shared/starboard/new.cc
@@ -22,7 +22,7 @@ } void operator delete(void* pointer) { - SbMemoryFree(pointer); + SbMemoryDeallocate(pointer); } void* operator new[](size_t size) { @@ -30,5 +30,5 @@ } void operator delete[](void* pointer) { - SbMemoryFree(pointer); + SbMemoryDeallocate(pointer); }
diff --git a/src/starboard/string.h b/src/starboard/string.h index 9b72dfa..5782023 100644 --- a/src/starboard/string.h +++ b/src/starboard/string.h
@@ -77,7 +77,8 @@ int destination_size); // Copies the string |source| into a buffer allocated by this function that can -// be freed with SbMemoryFree. Meant to be a drop-in replacement for strdup. +// be freed with SbMemoryDeallocate. Meant to be a drop-in replacement for +// strdup. SB_EXPORT char* SbStringDuplicate(const char* source); // Finds the first occurrence of |character| in |str|, returning a pointer to
diff --git a/src/starboard/time_zone.h b/src/starboard/time_zone.h index c194154..ce67d09 100644 --- a/src/starboard/time_zone.h +++ b/src/starboard/time_zone.h
@@ -30,7 +30,7 @@ // For example: PST/PDT is 480 minutes (28800 seconds, 8 hours). typedef int SbTimeZone; -// Gets the system's current SbTimeZone. +// Gets the system's current SbTimeZone in minutes. SB_EXPORT SbTimeZone SbTimeZoneGetCurrent(); // Gets the three-letter code of the current timezone in standard time,
diff --git a/src/testing/gtest/src/gtest.cc b/src/testing/gtest/src/gtest.cc index 430695d..837c26f 100644 --- a/src/testing/gtest/src/gtest.cc +++ b/src/testing/gtest/src/gtest.cc
@@ -772,7 +772,9 @@ // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { -#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) || defined(__LB_XB1__) +#if GTEST_OS_STARBOARD + return SbTimeGetNow() / kSbTimeMillisecond; +#elif GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) || defined(__LB_XB1__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta =
diff --git a/src/third_party/libevent/starboard/event-starboard-internal.h b/src/third_party/libevent/starboard/event-starboard-internal.h index 98d02a1..33a0747 100644 --- a/src/third_party/libevent/starboard/event-starboard-internal.h +++ b/src/third_party/libevent/starboard/event-starboard-internal.h
@@ -20,7 +20,7 @@ #include "starboard/memory.h" #define calloc SbMemoryCalloc -#define free SbMemoryFree +#define free SbMemoryDeallocate #define malloc SbMemoryAllocate #define realloc SbMemoryReallocate
diff --git a/src/third_party/libwebp/starboard_private.h b/src/third_party/libwebp/starboard_private.h index 5733157..242ef00 100644 --- a/src/third_party/libwebp/starboard_private.h +++ b/src/third_party/libwebp/starboard_private.h
@@ -29,7 +29,7 @@ #define abs(x) webp_abs(x) #define calloc SbMemoryCalloc -#define free SbMemoryFree +#define free SbMemoryDeallocate #define malloc SbMemoryAllocate #define memcpy SbMemoryCopy #define memmove SbMemoryMove
diff --git a/src/third_party/libxml/src/timsort.h b/src/third_party/libxml/src/timsort.h index 2a8f236..101847b 100644 --- a/src/third_party/libxml/src/timsort.h +++ b/src/third_party/libxml/src/timsort.h
@@ -22,7 +22,7 @@ #include "starboard/system.h" #include "starboard/types.h" #define exit(x) SbSystemBreakIntoDebugger() -#define free SbMemoryFree +#define free SbMemoryDeallocate #define memcpy SbMemoryCopy #define realloc SbMemoryReallocate #else
diff --git a/src/third_party/libxml/starboard/config.h b/src/third_party/libxml/starboard/config.h index ff6d707..1f42d44 100644 --- a/src/third_party/libxml/starboard/config.h +++ b/src/third_party/libxml/starboard/config.h
@@ -343,7 +343,7 @@ #define XML_REALLOC SbMemoryReallocate /* free() wrapping */ -#define XML_FREE SbMemoryFree +#define XML_FREE SbMemoryDeallocate /* memcmp() wrapping */ #define XML_MEMCMP SbMemoryCompare
diff --git a/src/third_party/mozjs/js/src/TraceLogging.cpp b/src/third_party/mozjs/js/src/TraceLogging.cpp index e82bde2..e1c346a 100644 --- a/src/third_party/mozjs/js/src/TraceLogging.cpp +++ b/src/third_party/mozjs/js/src/TraceLogging.cpp
@@ -59,6 +59,12 @@ return(result); } +#else +static __inline__ uint64_t +rdtsc(void) +{ + return 0; +} #endif const char* const TraceLogging::type_name[] = { @@ -157,7 +163,7 @@ void TraceLogging::log(Type type, JSScript* script) { - this->log(type, script->filename, script->lineno); + this->log(type, script->filename(), script->lineno); } void
diff --git a/src/third_party/mozjs/js/src/assembler/assembler/MIPSAssembler.h b/src/third_party/mozjs/js/src/assembler/assembler/MIPSAssembler.h index 45619c3..3beacdc 100644 --- a/src/third_party/mozjs/js/src/assembler/assembler/MIPSAssembler.h +++ b/src/third_party/mozjs/js/src/assembler/assembler/MIPSAssembler.h
@@ -31,11 +31,10 @@ #if ENABLE(ASSEMBLER) && CPU(MIPS) -#include "AssemblerBuffer.h" +#include "assembler/assembler/AssemblerBuffer.h" #include "assembler/wtf/Assertions.h" #include "assembler/wtf/SegmentedVector.h" -#include "methodjit/Logging.h" #define IPFX " %s" #define ISPFX " " #ifdef JS_METHODJIT_SPEW @@ -181,6 +180,10 @@ { } + bool isSet() const { + return m_offset != -1; + }; + private: JmpSrc(int offset) : m_offset(offset)
diff --git a/src/third_party/mozjs/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/src/third_party/mozjs/js/src/assembler/assembler/MacroAssemblerCodeRef.h index 16159f3..b92cddc 100644 --- a/src/third_party/mozjs/js/src/assembler/assembler/MacroAssemblerCodeRef.h +++ b/src/third_party/mozjs/js/src/assembler/assembler/MacroAssemblerCodeRef.h
@@ -30,6 +30,7 @@ #ifndef assembler_assembler_MacroAssemblerCodeRef_h #define assembler_assembler_MacroAssemblerCodeRef_h +#include "assembler/wtf/Assertions.h" #include "assembler/wtf/Platform.h" #include "assembler/jit/ExecutableAllocator.h"
diff --git a/src/third_party/mozjs/js/src/assembler/assembler/MacroAssemblerMIPS.h b/src/third_party/mozjs/js/src/assembler/assembler/MacroAssemblerMIPS.h index 6c6db42..50a18d1 100644 --- a/src/third_party/mozjs/js/src/assembler/assembler/MacroAssemblerMIPS.h +++ b/src/third_party/mozjs/js/src/assembler/assembler/MacroAssemblerMIPS.h
@@ -2335,6 +2335,7 @@ m_assembler.lwc1(dest, addrTempRegister, address.offset); m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, address.offset + 4); } else { + /* sll addrTemp, address.index, address.scale addu addrTemp, addrTemp, address.base li immTemp, address.offset @@ -2349,6 +2350,7 @@ immTempRegister); m_assembler.lwc1(dest, addrTempRegister, 0); m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4); + } #else if (address.offset >= -32768 && address.offset <= 32767 && !m_fixedWidth) { @@ -2781,6 +2783,13 @@ MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); } +public: + void load16Unaligned(BaseIndex address, RegisterID dest) { + JS_NOT_REACHED("NYI_COBALT"); + } + void load8(BaseIndex address, RegisterID dest) { + JS_NOT_REACHED("NYI_COBALT"); + } }; }
diff --git a/src/third_party/mozjs/js/src/jit/AsmJS.cpp b/src/third_party/mozjs/js/src/jit/AsmJS.cpp index 60d15f2..774019e 100644 --- a/src/third_party/mozjs/js/src/jit/AsmJS.cpp +++ b/src/third_party/mozjs/js/src/jit/AsmJS.cpp
@@ -588,7 +588,6 @@ // outer parent +/- expression pass in Use::AddOrSub so that the inner // expression knows to return type Int instead of Intish. // -// TODO: remove the remaining use of Use class Use { public: @@ -1527,13 +1526,13 @@ JS_ASSERT(elemIndex == module_->numFuncPtrTableElems()); // Global accesses in function bodies -#ifdef JS_CPU_ARM +#if defined(JS_CPU_ARM) JS_ASSERT(globalAccesses_.length() == 0); // The AsmJSHeapAccess offsets need to be updated to reflect the // "actualOffset" (an ARM distinction). module_->convertBoundsChecksToActualOffset(masm_); -#else +#elif defined(JS_CPU_X86) || defined(JS_CPU_X64) for (unsigned i = 0; i < globalAccesses_.length(); i++) { AsmJSGlobalAccess access = globalAccesses_[i]; @@ -5028,7 +5027,7 @@ static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * STACK_SLOT_SIZE + NonVolatileRegs.fpus().size() * sizeof(double); -#ifndef JS_CPU_ARM +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) static bool GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFunc) { @@ -5128,7 +5127,7 @@ masm.ret(); return true; } -#else +#elif defined(JS_CPU_ARM) // defined(JS_CPU_X86) || defined(JS_CPU_X64 static bool GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFunc) { @@ -5241,6 +5240,105 @@ masm.abiret(); return true; } +#elif defined(JS_CPU_MIPS) // defined(JS_CPU_X86) || defined(JS_CPU_X64 +static bool +GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFunc) +{ + MacroAssembler &masm = m.masm(); + + // In constrast to the system ABI, the Ion convention is that all registers + // are clobbered by calls. Thus, we must save the caller's non-volatile + // registers. + // + // NB: GenerateExits assumes that masm.framePushed() == 0 before + // PushRegsInMask(NonVolatileRegs). + masm.setFramePushed(0); + masm.PushRegsInMask(NonVolatileRegs); + JS_ASSERT(masm.framePushed() == FramePushedAfterSave); + + // Remember the stack pointer in the current AsmJSActivation. This will be + // used by error exit paths to set the stack pointer back to what it was + // right after the (C++) caller's non-volatile registers were saved so that + // they can be restored. + Register activation = ABIArgGenerator::NonArgReturnVolatileReg0; + LoadAsmJSActivationIntoRegister(masm, activation); + masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfErrorRejoinSP())); + + // Get 'argv' into a non-arg register and save it on the stack. + Register argv = ABIArgGenerator::NonArgReturnVolatileReg0; + Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1; + masm.movePtr(IntArgReg0, argv); + masm.Push(argv); + + // Bump the stack for the call. + // const ModuleCompiler::Func &func = *m.lookupFunction(exportedFunc.name()); + // unsigned stackDec = StackDecrementForCall(masm, func.sig().args()); + // masm.reserveStack(stackDec); + // CAREFUL_COBALT + // Bump the stack for the call. + const ModuleCompiler::Func &func = *m.lookupFunction(exportedFunc.name()); + unsigned stackDec = StackDecrementForCall(masm, func.argMIRTypes()); + masm.reserveStack(stackDec); + + // Copy parameters out of argv and into the registers/stack-slots specified by + // the system ABI. + for (ABIArgIter iter(func.argMIRTypes()); !iter.done(); iter++) { + unsigned argOffset = iter.index() * sizeof(uint64_t); + Address src(argv, argOffset); + switch (iter->kind()) { + case ABIArg::GPR: + masm.load32(src, iter->gpr()); + break; + case ABIArg::FPU: + masm.loadDouble(src, iter->fpu()); + break; + case ABIArg::Stack: + if (iter.mirType() == MIRType_Int32) { + masm.load32(src, scratch); + masm.storePtr(scratch, Address(StackPointer, iter->offsetFromArgBase())); + } else { + JS_ASSERT(iter.mirType() == MIRType_Double); + masm.loadDouble(src, ScratchFloatReg); + masm.storeDouble(ScratchFloatReg, Address(StackPointer, iter->offsetFromArgBase())); + } + break; + } + } + + // Call into the real function. + AssertStackAlignment(masm); + // masm.call(CallSiteDesc::Entry(), func.code()); + masm.call(func.codeLabel()); + + // Pop the stack and recover the original 'argv' argument passed to the + // trampoline (which was pushed on the stack). + masm.freeStack(stackDec); + masm.Pop(argv); + + // Store the return value in argv[0] + switch (func.returnType().which()) { + case RetType::Void: + break; + case RetType::Signed: + masm.storeValue(JSVAL_TYPE_INT32, ReturnReg, Address(argv, 0)); + break; + case RetType::Double: + masm.canonicalizeDouble(ReturnFloatReg); + masm.storeDouble(ReturnFloatReg, Address(argv, 0)); + break; + } + + // Restore clobbered non-volatile registers of the caller. + masm.PopRegsInMask(NonVolatileRegs); + + JS_ASSERT(masm.framePushed() == 0); + + masm.move32(Imm32(true), ReturnReg); + masm.abiret(); + return true; +} +#else // defined(JS_CPU_X86) || defined(JS_CPU_X64 +#error "Unknown CPU architecture." #endif static bool @@ -5445,14 +5543,14 @@ CodeOffsetLabel label; #if defined(JS_CPU_X64) label = masm.leaRipRelative(i->gpr()); -#else +#else // defined(JS_CPU_X64) if (i->kind() == ABIArg::GPR) { label = masm.movlWithPatch(Imm32(0), i->gpr()); } else { label = masm.movlWithPatch(Imm32(0), scratch); masm.movl(scratch, Operand(StackPointer, i->offsetFromArgBase())); } -#endif +#endif // defined(JS_CPU_X64) unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex); m.addGlobalAccess(AsmJSGlobalAccess(label.offset(), globalDataOffset)); i++; @@ -5499,14 +5597,18 @@ // registers to restore. masm.freeStack(stackDec); masm.ret(); -#else +#else // defined(JS_CPU_X86) || defined(JS_CPU_X64) const unsigned arrayLength = Max<size_t>(1, exit.argTypes().length()); const unsigned arraySize = arrayLength * sizeof(Value); const unsigned reserveSize = AlignBytes(arraySize, StackAlignment) + ShadowStackSpace; const unsigned callerArgsOffset = reserveSize + NativeFrameSize + sizeof(int32_t); masm.setFramePushed(0); + +#if defined(JS_CPU_ARM) masm.Push(lr); +#endif // defined(JS_CPU_ARM) + masm.reserveStack(reserveSize + sizeof(int32_t)); // Store arguments @@ -5544,15 +5646,15 @@ masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); #if defined(JS_CPU_ARM) && !defined(JS_CPU_ARM_HARDFP) masm.loadValue(argv, softfpReturnOperand); -#else +#else // defined(JS_CPU_ARM) && !defined(JS_CPU_ARM_HARDFP) masm.loadDouble(argv, ReturnFloatReg); -#endif +#endif // defined(JS_CPU_ARM) && !defined(JS_CPU_ARM_HARDFP) break; } masm.freeStack(reserveSize + sizeof(int32_t)); masm.ret(); -#endif +#endif // defined(JS_CPU_X86) || defined(JS_CPU_X64) } static int32_t @@ -5886,7 +5988,7 @@ masm.align(CodeAlignment); masm.bind(&m.operationCallbackLabel()); -#ifndef JS_CPU_ARM +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) // Be very careful here not to perturb the machine state before saving it // to the stack. In particular, add/sub instructions may set conditions in // the flags register. @@ -5906,10 +6008,12 @@ // We know that StackPointer is word-aligned, but not necessarily // stack-aligned, so we need to align it dynamically. masm.mov(StackPointer, ABIArgGenerator::NonVolatileReg); + #if defined(JS_CPU_X86) // Ensure that at least one slot is pushed for passing 'cx' below. masm.push(Imm32(0)); #endif + masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer); if (ShadowStackSpace) masm.subPtr(Imm32(ShadowStackSpace), StackPointer); @@ -5933,7 +6037,8 @@ masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP) masm.popFlags(); // after this, nothing that sets conditions masm.ret(); // pop resumePC into PC -#else + +#elif defined(JS_CPU_ARM) // defined(JS_CPU_X86) || defined(JS_CPU_X64) masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(Registers::AllMask & ~(1<<Registers::sp)), FloatRegisterSet(uint32_t(0)))); // save all GP registers,excep sp @@ -5981,8 +6086,11 @@ masm.transferReg(lr); masm.finishDataTransfer(); masm.ret(); - -#endif +#elif defined(JS_CPU_MIPS) // defined(JS_CPU_X86) || defined(JS_CPU_X64) + JS_NOT_REACHED("NYI_COBALT"); +#else // defined(JS_CPU_X86) || defined(JS_CPU_X64) +#error "Unknown CPU architecture."; +#endif // defined(JS_CPU_X86) || defined(JS_CPU_X64) }
diff --git a/src/third_party/mozjs/js/src/jit/AsmJS.h b/src/third_party/mozjs/js/src/jit/AsmJS.h index 2e4ac30..2f13754 100644 --- a/src/third_party/mozjs/js/src/jit/AsmJS.h +++ b/src/third_party/mozjs/js/src/jit/AsmJS.h
@@ -7,6 +7,11 @@ #ifndef jit_AsmJS_h #define jit_AsmJS_h +#if defined(JS_CPU_MIPS) +#include <stddef.h> +#include "vm/ObjectImpl.h" +#endif // defined(JS_CPU_MIPS) + #ifdef XP_MACOSX # include <pthread.h> # include <mach/mach.h>
diff --git a/src/third_party/mozjs/js/src/jit/BaselineBailouts.cpp b/src/third_party/mozjs/js/src/jit/BaselineBailouts.cpp index 5d89825..eeebfa2 100644 --- a/src/third_party/mozjs/js/src/jit/BaselineBailouts.cpp +++ b/src/third_party/mozjs/js/src/jit/BaselineBailouts.cpp
@@ -344,9 +344,9 @@ JS_ASSERT(BaselineFrameReg == FramePointer); priorOffset -= sizeof(void *); return virtualPointerAtStackOffset(priorOffset); -#elif defined(JS_CPU_X64) || defined(JS_CPU_ARM) - // On X64 and ARM, the frame pointer save location depends on the caller of the - // the rectifier frame. +#elif defined(JS_CPU_X64) || defined(JS_CPU_ARM) || defined(JS_CPU_MIPS) + // On X64, ARM, and MIPS, the frame pointer save location depends on + // the caller of the the rectifier frame. BufferPointer<IonRectifierFrameLayout> priorFrame = pointerAtStackOffset<IonRectifierFrameLayout>(priorOffset); FrameType priorType = priorFrame->prevType(); @@ -1175,9 +1175,10 @@ SnapshotIterator snapIter(iter); RootedFunction callee(cx, iter.maybeCallee()); + RootedScript scr(cx, iter.script()); if (callee) { IonSpew(IonSpew_BaselineBailouts, " Callee function (%s:%u)", - callee->existingScript()->filename(), callee->existingScript()->lineno); + scr->filename(), scr->lineno); } else { IonSpew(IonSpew_BaselineBailouts, " No callee!"); } @@ -1194,7 +1195,6 @@ RootedScript caller(cx); jsbytecode *callerPC = NULL; RootedFunction fun(cx, callee); - RootedScript scr(cx, iter.script()); AutoValueVector startFrameFormals(cx); while (true) { IonSpew(IonSpew_BaselineBailouts, " FrameNo %d", frameNo); @@ -1217,7 +1217,7 @@ caller = scr; callerPC = callPC; fun = nextCallee; - scr = fun->existingScript(); + scr = fun->existingScriptForInlinedFunction(); snapIter.nextFrame(); frameNo++;
diff --git a/src/third_party/mozjs/js/src/jit/BaselineCompiler.cpp b/src/third_party/mozjs/js/src/jit/BaselineCompiler.cpp index 173cc71..42de75c 100644 --- a/src/third_party/mozjs/js/src/jit/BaselineCompiler.cpp +++ b/src/third_party/mozjs/js/src/jit/BaselineCompiler.cpp
@@ -294,6 +294,8 @@ // On ARM, save the link register before calling. It contains the return // address. The |masm.ret()| later will pop this into |pc| to return. masm.push(lr); +#elif defined(JS_CPU_MIPS) + masm.push(ra); #endif masm.setupUnalignedABICall(2, scratch);
diff --git a/src/third_party/mozjs/js/src/jit/BaselineCompiler.h b/src/third_party/mozjs/js/src/jit/BaselineCompiler.h index a28775d..f8f78c7 100644 --- a/src/third_party/mozjs/js/src/jit/BaselineCompiler.h +++ b/src/third_party/mozjs/js/src/jit/BaselineCompiler.h
@@ -26,8 +26,12 @@ # include "x86/BaselineCompiler-x86.h" #elif defined(JS_CPU_X64) # include "x64/BaselineCompiler-x64.h" -#else +#elif defined(JS_CPU_ARM) # include "arm/BaselineCompiler-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/BaselineCompiler-mips.h" +#else +# error "Unknown CPU architecture." #endif namespace js {
diff --git a/src/third_party/mozjs/js/src/jit/BaselineHelpers.h b/src/third_party/mozjs/js/src/jit/BaselineHelpers.h index 2c400d5..4d73840 100644 --- a/src/third_party/mozjs/js/src/jit/BaselineHelpers.h +++ b/src/third_party/mozjs/js/src/jit/BaselineHelpers.h
@@ -15,6 +15,8 @@ # include "x64/BaselineHelpers-x64.h" #elif defined(JS_CPU_ARM) # include "arm/BaselineHelpers-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/BaselineHelpers-mips.h" #else # error "Unknown architecture!" #endif
diff --git a/src/third_party/mozjs/js/src/jit/BaselineIC.cpp b/src/third_party/mozjs/js/src/jit/BaselineIC.cpp index ed1f2c9..a9e7ef5 100644 --- a/src/third_party/mozjs/js/src/jit/BaselineIC.cpp +++ b/src/third_party/mozjs/js/src/jit/BaselineIC.cpp
@@ -656,7 +656,7 @@ masm.bind(&isTenured); // void PostWriteBarrier(JSRuntime *rt, JSObject *obj); -#ifdef JS_CPU_ARM +#if defined(JS_CPU_ARM) || defined(JS_CPU_MIPS) saveRegs.add(BaselineTailCallReg); #endif saveRegs = GeneralRegisterSet::Intersect(saveRegs, GeneralRegisterSet::Volatile()); @@ -1918,8 +1918,12 @@ // Compare payload regs of R0 and R1. Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); +#if defined(JS_CPU_MIPS) + masm.cmp32Set(cond, left, right, left); +#else masm.cmp32(left, right); masm.emitSet(cond, left); +#endif // Box the result and return masm.tagValue(JSVAL_TYPE_BOOLEAN, left, R0); @@ -2090,9 +2094,18 @@ // Compare payload regs of R0 and R1. Assembler::Condition cond = JSOpToCondition(op_, /* signed = */true); +#if defined(JS_CPU_MIPS) + masm.cmp32Set( + cond, + lhsIsInt32_ ? int32Reg : boolReg, + lhsIsInt32_ ? boolReg : int32Reg, + R0.scratchReg() + ); +#else masm.cmp32(lhsIsInt32_ ? int32Reg : boolReg, lhsIsInt32_ ? boolReg : int32Reg); masm.emitSet(cond, R0.scratchReg()); +#endif // Box the result and return masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.scratchReg(), R0); @@ -2218,8 +2231,12 @@ masm.branchTestInt32(Assembler::NotEqual, R0, &failure); Label ifFalse; +#if defined(JS_CPU_MIPS) + masm.branchTestInt32Truthy(false, R0, &ifFalse); +#else Assembler::Condition cond = masm.testInt32Truthy(false, R0); masm.j(cond, &ifFalse); +#endif masm.moveValue(BooleanValue(true), R0); EmitReturnFromIC(masm); @@ -2245,8 +2262,12 @@ masm.branchTestString(Assembler::NotEqual, R0, &failure); Label ifFalse; +#if defined(JS_CPU_MIPS) + masm.branchTestStringTruthy(false, R0, &ifFalse); +#else Assembler::Condition cond = masm.testStringTruthy(false, R0); masm.j(cond, &ifFalse); +#endif masm.moveValue(BooleanValue(true), R0); EmitReturnFromIC(masm); @@ -2292,8 +2313,12 @@ Label failure, ifTrue; masm.branchTestDouble(Assembler::NotEqual, R0, &failure); masm.unboxDouble(R0, FloatReg0); +#if defined(JS_CPU_MIPS) + masm.branchTestDoubleTruthy(true, FloatReg0, &ifTrue); +#else Assembler::Condition cond = masm.testDoubleTruthy(true, FloatReg0); masm.j(cond, &ifTrue); +#endif masm.moveValue(BooleanValue(false), R0); EmitReturnFromIC(masm); @@ -2320,8 +2345,12 @@ Register objReg = masm.extractObject(R0, ExtractTemp0); Register scratch = R1.scratchReg(); +#if defined(JS_CPU_MIPS) + masm.branchTestObjectTruthy(false, objReg, scratch, &slowPath, &ifFalse); +#else Assembler::Condition cond = masm.branchTestObjectTruthy(false, objReg, scratch, &slowPath); masm.j(cond, &ifFalse); +#endif // If object doesn't emulate undefined, it evaulates to true. masm.moveValue(BooleanValue(true), R0); @@ -2335,6 +2364,9 @@ masm.setupUnalignedABICall(1, scratch); masm.passABIArg(objReg); masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ObjectEmulatesUndefined)); +#if defined(JS_CPU_MIPS) + masm.convertBoolToInt32(ReturnReg, ReturnReg); +#endif masm.xor32(Imm32(1), ReturnReg); masm.tagValue(JSVAL_TYPE_BOOLEAN, ReturnReg, R0); EmitReturnFromIC(masm); @@ -2825,6 +2857,15 @@ case JSOP_ADD: { Label fixOverflow; +#if defined(JS_CPU_MIPS) + masm.branchAdd32(Assembler::Overflow, rhsReg, lhsReg, &fixOverflow); + masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0); + EmitReturnFromIC(masm); + + masm.bind(&fixOverflow); + masm.sub32(rhsReg, lhsReg); + // Proceed to failure below. +#else masm.add32(rhsReg, lhsReg); masm.j(Assembler::Overflow, &fixOverflow); masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0); @@ -2833,11 +2874,21 @@ masm.bind(&fixOverflow); masm.sub32(rhsReg, lhsReg); masm.jump(&failure); +#endif break; } case JSOP_SUB: { Label fixOverflow; +#if defined(JS_CPU_MIPS) + masm.branchSub32(Assembler::Overflow, rhsReg, lhsReg, &fixOverflow); + masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0); + EmitReturnFromIC(masm); + + masm.bind(&fixOverflow); + masm.add32(rhsReg, lhsReg); + // Proceed to failure below. +#else masm.sub32(rhsReg, lhsReg); masm.j(Assembler::Overflow, &fixOverflow); masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0); @@ -2846,6 +2897,7 @@ masm.bind(&fixOverflow); masm.add32(rhsReg, lhsReg); masm.jump(&failure); +#endif break; } case JSOP_BITOR: { @@ -7268,8 +7320,17 @@ Address expectedScript(BaselineStubReg, ICCall_Scripted::offsetOfCalleeScript()); masm.branchPtr(Assembler::NotEqual, expectedScript, callee, &failure); } else { +#if defined(JS_CPU_MIPS) + if (isConstructing_) { + masm.branchIfNotInterpretedConstructor(callee, regs.getAny(), &failure); + } else { + masm.branchIfFunctionHasNoScript(callee, &failure); + } + masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee); +#else masm.branchIfFunctionHasNoScript(callee, &failure); masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee); +#endif } // Load the start of the target IonCode. @@ -7901,8 +7962,13 @@ // Set output to true if props_cursor < props_end. masm.loadPtr(Address(nativeIterator, offsetof(NativeIterator, props_end)), scratch); +#if defined(JS_CPU_MIPS) + Address cursorAddr = Address(nativeIterator, offsetof(NativeIterator, props_cursor)); + masm.cmpPtrSet(Assembler::LessThan, cursorAddr, scratch, scratch); +#else masm.cmpPtr(Address(nativeIterator, offsetof(NativeIterator, props_cursor)), scratch); masm.emitSet(Assembler::LessThan, scratch); +#endif masm.tagValue(JSVAL_TYPE_BOOLEAN, scratch, R0); EmitReturnFromIC(masm);
diff --git a/src/third_party/mozjs/js/src/jit/BaselineIC.h b/src/third_party/mozjs/js/src/jit/BaselineIC.h index 63da318..3928295 100644 --- a/src/third_party/mozjs/js/src/jit/BaselineIC.h +++ b/src/third_party/mozjs/js/src/jit/BaselineIC.h
@@ -1025,11 +1025,17 @@ inline GeneralRegisterSet availableGeneralRegs(size_t numInputs) const { GeneralRegisterSet regs(GeneralRegisterSet::All()); JS_ASSERT(!regs.has(BaselineStackReg)); + #ifdef JS_CPU_ARM JS_ASSERT(!regs.has(BaselineTailCallReg)); +#elif defined(JS_CPU_MIPS) + JS_ASSERT(!regs.has(BaselineTailCallReg)); + JS_ASSERT(!regs.has(BaselineSecondScratchReg)); #endif + regs.take(BaselineFrameReg); regs.take(BaselineStubReg); + #ifdef JS_CPU_X64 regs.take(ExtractTemp0); regs.take(ExtractTemp1);
diff --git a/src/third_party/mozjs/js/src/jit/BaselineRegisters.h b/src/third_party/mozjs/js/src/jit/BaselineRegisters.h index 0bc20fd..ea625a7 100644 --- a/src/third_party/mozjs/js/src/jit/BaselineRegisters.h +++ b/src/third_party/mozjs/js/src/jit/BaselineRegisters.h
@@ -13,8 +13,12 @@ # include "x86/BaselineRegisters-x86.h" #elif defined(JS_CPU_X64) # include "x64/BaselineRegisters-x64.h" -#else +#elif defined(JS_CPU_ARM) # include "arm/BaselineRegisters-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/BaselineRegisters-mips.h" +#else +#error "Unknown CPU architecture." #endif namespace js {
diff --git a/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp b/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp index ab8ea02..4ab2f2f 100644 --- a/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp +++ b/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp
@@ -372,9 +372,14 @@ // Perform a fast-path check of the object's class flags if the object's // not a proxy. Let out-of-line code handle the slow cases that require // saving registers, making a function call, and restoring registers. +#if defined(JS_CPU_MIPS) + masm.branchTestObjectTruthy(false, objreg, scratch, ool->entry(), ifTruthy); + masm.jump(ifFalsy); +#else Assembler::Condition cond = masm.branchTestObjectTruthy(true, objreg, scratch, ool->entry()); masm.j(cond, ifTruthy); masm.jump(ifFalsy); +#endif } void @@ -385,7 +390,9 @@ OutOfLineTestObject *ool) { Register tag = masm.splitTagForTest(value); +#if !defined(JS_CPU_MIPS) Assembler::Condition cond; +#endif // Eventually we will want some sort of type filter here. For now, just // emit all easy cases. For speed we use the cached tag for all comparison, @@ -402,8 +409,12 @@ Label notInt32; masm.branchTestInt32(Assembler::NotEqual, tag, ¬Int32); +#if defined(JS_CPU_MIPS) + masm.branchTestInt32Truthy(false, value, ifFalsy); +#else cond = masm.testInt32Truthy(false, value); masm.j(cond, ifFalsy); +#endif masm.jump(ifTruthy); masm.bind(¬Int32); @@ -423,15 +434,23 @@ // Test if a string is non-empty. Label notString; masm.branchTestString(Assembler::NotEqual, tag, ¬String); +#if defined(JS_CPU_MIPS) + masm.branchTestStringTruthy(false, value, ifFalsy); +#else cond = masm.testStringTruthy(false, value); masm.j(cond, ifFalsy); +#endif masm.jump(ifTruthy); masm.bind(¬String); // If we reach here the value is a double. masm.unboxDouble(value, fr); +#if defined(JS_CPU_MIPS) + masm.branchTestDoubleTruthy(false, fr, ifFalsy); +#else cond = masm.testDoubleTruthy(false, fr); masm.j(cond, ifFalsy); +#endif masm.jump(ifTruthy); } @@ -1560,12 +1579,25 @@ // Guard that calleereg is actually a function object. masm.loadObjClass(calleereg, nargsreg); +#if defined(JS_CPU_MIPS) + masm.branchPtr(Assembler::NotEqual, nargsreg, ImmWord(&JSFunction::class_), &uncompiled); +#else masm.cmpPtr(nargsreg, ImmWord(&JSFunction::class_)); if (!bailoutIf(Assembler::NotEqual, call->snapshot())) return false; +#endif +#if defined(JS_CPU_MIPS) + // Guard that calleereg is an interpreted function with a JSScript. + // If we are constructing, also ensure the callee is a constructor. + if (call->mir()->isConstructing()) + masm.branchIfNotInterpretedConstructor(calleereg, nargsreg, &uncompiled); + else + masm.branchIfFunctionHasNoScript(calleereg, &uncompiled); +#else // Guard that calleereg is an interpreted function with a JSScript: masm.branchIfFunctionHasNoScript(calleereg, &uncompiled); +#endif // Knowing that calleereg is a non-native function, load the JSScript. masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg); @@ -1587,8 +1619,12 @@ // Check whether the provided arguments satisfy target argc. masm.load16ZeroExtend(Address(calleereg, offsetof(JSFunction, nargs)), nargsreg); +#if defined(JS_CPU_MIPS) + masm.branch32(Assembler::Above, nargsreg, Imm32(call->numStackArgs()), &thunk); +#else masm.cmp32(nargsreg, Imm32(call->numStackArgs())); masm.j(Assembler::Above, &thunk); +#endif masm.jump(&makeCall); @@ -1883,9 +1919,16 @@ // Unless already known, guard that calleereg is actually a function object. if (!apply->hasSingleTarget()) { masm.loadObjClass(calleereg, objreg); +#if defined(JS_CPU_MIPS) + ImmWord ptr = ImmWord(&JSFunction::class_); + if (!bailoutCmpPtr(Assembler::NotEqual, objreg, ptr, apply->snapshot())) { + return false; + } +#else masm.cmpPtr(objreg, ImmWord(&JSFunction::class_)); if (!bailoutIf(Assembler::NotEqual, apply->snapshot())) return false; +#endif } // Copy the arguments of the current function. @@ -1937,11 +1980,19 @@ // Check whether the provided arguments satisfy target argc. if (!apply->hasSingleTarget()) { masm.load16ZeroExtend(Address(calleereg, offsetof(JSFunction, nargs)), copyreg); +#if defined(JS_CPU_MIPS) + masm.branch32(Assembler::Below, argcreg, copyreg, &underflow); +#else masm.cmp32(argcreg, copyreg); masm.j(Assembler::Below, &underflow); +#endif } else { +#if defined(JS_CPU_MIPS) + masm.branch32(Assembler::Below, argcreg, Imm32(apply->getSingleTarget()->nargs), &underflow); +#else masm.cmp32(argcreg, Imm32(apply->getSingleTarget()->nargs)); masm.j(Assembler::Below, &underflow); +#endif } // Skip the construction of the rectifier frame because we have no @@ -2022,8 +2073,14 @@ masm.loadValue(Address(StackPointer, 0), out); masm.adjustStack(sizeof(Value)); +#if defined(JS_CPU_MIPS) + Label undefined; + masm.branchTestUndefined(Assembler::Equal, out, &undefined); + return bailoutFrom(&undefined, lir->snapshot()); +#else Assembler::Condition cond = masm.testUndefined(Assembler::Equal, out); return bailoutIf(cond, lir->snapshot()); +#endif } bool @@ -2645,10 +2702,14 @@ masm.passABIArg(temp1); masm.passABIArg(temp2); masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewSlots)); - +#if defined(JS_CPU_MIPS) + if (!bailoutTestPtr(Assembler::Zero, output, output, lir->snapshot())) + return false; +#else masm.testPtr(output, output); if (!bailoutIf(Assembler::Zero, lir->snapshot())) return false; +#endif return true; } @@ -3307,6 +3368,20 @@ JS_ASSERT(first == output); +#if defined(JS_CPU_MIPS) + Label done; + Assembler::Condition cond = ins->mir()->isMax() + ? Assembler::GreaterThan + : Assembler::LessThan; + + if (ins->second()->isConstant()) { + masm.branch32(cond, first, Imm32(ToInt32(ins->second())), &done); + masm.move32(Imm32(ToInt32(ins->second())), output); + } else { + masm.branch32(cond, first, ToRegister(ins->second()), &done); + masm.move32(ToRegister(ins->second()), output); + } +#else if (ins->second()->isConstant()) masm.cmp32(first, Imm32(ToInt32(ins->second()))); else @@ -3323,6 +3398,7 @@ else masm.mov(ToRegister(ins->second()), output); +#endif masm.bind(&done); return true; @@ -3331,6 +3407,22 @@ bool CodeGenerator::visitAbsI(LAbsI *ins) { +#if defined(JS_CPU_MIPS) + Register input = ToRegister(ins->input()); + Label positive; + + JS_ASSERT(input == ToRegister(ins->output())); + masm.branchTest32(Assembler::NotSigned, input, input, &positive); + masm.neg32(input); + LSnapshot *snapshot = ins->snapshot(); + if (snapshot && !bailoutCmp32(Assembler::Equal, input, Imm32(INT32_MIN), snapshot)) + return false; + masm.bind(&positive); + + return true; + +#else // defined(JS_CPU_MIPS) + Register input = ToRegister(ins->input()); Label positive; @@ -3343,6 +3435,7 @@ masm.bind(&positive); return true; +#endif // defined(JS_CPU_MIPS) } bool @@ -3755,6 +3848,13 @@ JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE); +#if defined(JS_CPU_MIPS) + Assembler::Condition cond = JSOpToCondition(compareType, op); + if (compareType == MCompare::Compare_Null) + masm.testNullSet(cond, value, output); + else + masm.testUndefinedSet(cond, value, output); +#else Assembler::Condition cond = JSOpToCondition(compareType, op); if (compareType == MCompare::Compare_Null) cond = masm.testNull(cond, value); @@ -3762,6 +3862,7 @@ cond = masm.testUndefined(cond, value); masm.emitSet(cond, output); +#endif return true; } @@ -3821,6 +3922,13 @@ JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE); +#if defined(JS_CPU_MIPS) + Assembler::Condition cond = JSOpToCondition(compareType, op); + if (compareType == MCompare::Compare_Null) + testNullEmitBranch(cond, value, lir->ifTrue(), lir->ifFalse()); + else + testUndefinedEmitBranch(cond, value, lir->ifTrue(), lir->ifFalse()); +#else Assembler::Condition cond = JSOpToCondition(compareType, op); if (compareType == MCompare::Compare_Null) cond = masm.testNull(cond, value); @@ -3828,6 +3936,8 @@ cond = masm.testUndefined(cond, value); emitBranch(cond, lir->ifTrue(), lir->ifFalse()); +#endif + return true; } @@ -3961,8 +4071,13 @@ masm.store16(scratch, Address(to, 0)); masm.addPtr(Imm32(2), from); masm.addPtr(Imm32(2), to); + +#if defined(JS_CPU_MIPS) + masm.branchSub32(Assembler::NonZero, Imm32(1), len, &start); +#else masm.sub32(Imm32(1), len); masm.j(Assembler::NonZero, &start); +#endif } IonCode * @@ -4221,17 +4336,92 @@ return true; return bailout(lir->snapshot()); } +#if defined(JS_CPU_MIPS) + return bailoutCmp32(Assembler::BelowOrEqual, ToOperand(lir->length()), Imm32(index), lir->snapshot()); +#else masm.cmp32(ToOperand(lir->length()), Imm32(index)); return bailoutIf(Assembler::BelowOrEqual, lir->snapshot()); +#endif } if (lir->length()->isConstant()) { +#if defined(JS_CPU_MIPS) + return bailoutCmp32(Assembler::AboveOrEqual, ToRegister(lir->index()), Imm32(ToInt32(lir->length())), lir->snapshot()); +#else masm.cmp32(ToRegister(lir->index()), Imm32(ToInt32(lir->length()))); return bailoutIf(Assembler::AboveOrEqual, lir->snapshot()); +#endif } +#if defined(JS_CPU_MIPS) + return bailoutCmp32(Assembler::BelowOrEqual, ToOperand(lir->length()), ToRegister(lir->index()), lir->snapshot()); +#else masm.cmp32(ToOperand(lir->length()), ToRegister(lir->index())); return bailoutIf(Assembler::BelowOrEqual, lir->snapshot()); +#endif } +#if defined(JS_CPU_MIPS) +bool +CodeGenerator::visitBoundsCheckRange(LBoundsCheckRange *lir) +{ + int32_t min = lir->mir()->minimum(); + int32_t max = lir->mir()->maximum(); + JS_ASSERT(max >= min); + + Register temp = ToRegister(lir->getTemp(0)); + if (lir->index()->isConstant()) { + int32_t nmin, nmax; + int32_t index = ToInt32(lir->index()); + if (SafeAdd(index, min, &nmin) && SafeAdd(index, max, &nmax) && nmin >= 0) { + return bailoutCmp32(Assembler::BelowOrEqual, ToOperand(lir->length()), Imm32(nmax), + lir->snapshot()); + } + masm.mov(Imm32(index), temp); + } else { + masm.mov(ToRegister(lir->index()), temp); + } + + // If the minimum and maximum differ then do an underflow check first. + // If the two are the same then doing an unsigned comparison on the + // length will also catch a negative index. + if (min != max) { + if (min != 0) { + Label bail; + masm.branchAdd32(Assembler::Overflow, Imm32(min), temp, &bail); + if (!bailoutFrom(&bail, lir->snapshot())) + return false; + } + + if (!bailoutCmp32(Assembler::LessThan, temp, Imm32(0), lir->snapshot())) + return false; + + if (min != 0) { + int32_t diff; + if (SafeSub(max, min, &diff)) + max = diff; + else + masm.sub32(Imm32(min), temp); + } + } + + // Compute the maximum possible index. No overflow check is needed when + // max > 0. We can only wraparound to a negative number, which will test as + // larger than all nonnegative numbers in the unsigned comparison, and the + // length is required to be nonnegative (else testing a negative length + // would succeed on any nonnegative index). + if (max != 0) { + if (max < 0) { + Label bail; + masm.branchAdd32(Assembler::Overflow, Imm32(max), temp, &bail); + if (!bailoutFrom(&bail, lir->snapshot())) + return false; + } else { + masm.add32(Imm32(max), temp); + } + } + + return bailoutCmp32(Assembler::BelowOrEqual, ToOperand(lir->length()), temp, lir->snapshot()); +} +#else bool CodeGenerator::visitBoundsCheckRange(LBoundsCheckRange *lir) { @@ -4261,7 +4451,6 @@ if (!bailoutIf(Assembler::Overflow, lir->snapshot())) return false; } - masm.cmp32(temp, Imm32(0)); if (!bailoutIf(Assembler::LessThan, lir->snapshot())) return false; @@ -4290,13 +4479,19 @@ masm.cmp32(ToOperand(lir->length()), temp); return bailoutIf(Assembler::BelowOrEqual, lir->snapshot()); } +#endif bool CodeGenerator::visitBoundsCheckLower(LBoundsCheckLower *lir) { int32_t min = lir->mir()->minimum(); +#if defined(JS_CPU_MIPS) + return bailoutCmp32(Assembler::LessThan, ToRegister(lir->index()), Imm32(min), + lir->snapshot()); +#else masm.cmp32(ToRegister(lir->index()), Imm32(min)); return bailoutIf(Assembler::LessThan, lir->snapshot()); +#endif } class OutOfLineStoreElementHole : public OutOfLineCodeBase<CodeGenerator> @@ -4325,12 +4520,24 @@ bool CodeGenerator::emitStoreHoleCheck(Register elements, const LAllocation *index, LSnapshot *snapshot) { +#if defined(JS_CPU_MIPS) + Label bail; + if (index->isConstant()) { + masm.branchTestMagic(Assembler::Equal, + Address(elements, ToInt32(index) * sizeof(js::Value)), &bail); + } else { + masm.branchTestMagic(Assembler::Equal, + BaseIndex(elements, ToRegister(index), TimesEight), &bail); + } + return bailoutFrom(&bail, snapshot); +#else Assembler::Condition cond; if (index->isConstant()) cond = masm.testMagic(Assembler::Equal, Address(elements, ToInt32(index) * sizeof(js::Value))); else cond = masm.testMagic(Assembler::Equal, BaseIndex(elements, ToRegister(index), TimesEight)); return bailoutIf(cond, snapshot); +#endif } bool @@ -4428,6 +4635,94 @@ static const VMFunction SetObjectElementInfo = FunctionInfo<SetObjectElementFn>(SetObjectElement); +#if defined(JS_CPU_MIPS) +bool +CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool) +{ + Register object, elements; + LInstruction *ins = ool->ins(); + const LAllocation *index; + MIRType valueType; + ConstantOrRegister value; + + if (ins->isStoreElementHoleV()) { + LStoreElementHoleV *store = ins->toStoreElementHoleV(); + object = ToRegister(store->object()); + elements = ToRegister(store->elements()); + index = store->index(); + valueType = store->mir()->value()->type(); + value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value)); + } else { + LStoreElementHoleT *store = ins->toStoreElementHoleT(); + object = ToRegister(store->object()); + elements = ToRegister(store->elements()); + index = store->index(); + valueType = store->mir()->value()->type(); + if (store->value()->isConstant()) + value = ConstantOrRegister(*store->value()->toConstant()); + else + value = TypedOrValueRegister(valueType, ToAnyRegister(store->value())); + } + + // If index == initializedLength, try to bump the initialized length inline. + // If index > initializedLength, call a stub. Note that this relies on the + // condition flags sticking from the incoming branch. + Label callStub; + // Had to reimplement for MIPS because there are no flags. + Address initLength(elements, ObjectElements::offsetOfInitializedLength()); + masm.branchKey(Assembler::NotEqual, initLength, ToInt32Key(index), &callStub); + + Int32Key key = ToInt32Key(index); + + // Check array capacity. + masm.branchKey(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()), + key, &callStub); + + // Update initialized length. The capacity guard above ensures this won't overflow, + // due to NELEMENTS_LIMIT. + masm.bumpKey(&key, 1); + masm.storeKey(key, Address(elements, ObjectElements::offsetOfInitializedLength())); + + // Update length if length < initializedLength. + Label dontUpdate; + masm.branchKey(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()), + key, &dontUpdate); + masm.storeKey(key, Address(elements, ObjectElements::offsetOfLength())); + masm.bind(&dontUpdate); + + masm.bumpKey(&key, -1); + + if (ins->isStoreElementHoleT() && valueType != MIRType_Double) { + // The inline path for StoreElementHoleT does not always store the type tag, + // so we do the store on the OOL path. We use MIRType_None for the element type + // so that storeElementTyped will always store the type tag. + storeElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType_None, elements, + index); + masm.jump(ool->rejoin()); + } else { + // Jump to the inline path where we will store the value. + masm.jump(ool->rejoinStore()); + } + + masm.bind(&callStub); + saveLive(ins); + + pushArg(Imm32(current->mir()->strict())); + pushArg(value); + if (index->isConstant()) + pushArg(Imm32(ToInt32(index))); + else + pushArg(ToRegister(index)); + pushArg(object); + // if (!callVM(SetDenseElementInfo, ins)) + if (!callVM(SetObjectElementInfo, ins)) + return false; + + restoreLive(ins); + masm.jump(ool->rejoin()); + return true; +} +#else bool CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool) { @@ -4584,6 +4879,7 @@ JS_ASSERT(false); return false; } +#endif typedef bool (*ArrayPopShiftFn)(JSContext *, HandleObject, MutableHandleValue); static const VMFunction ArrayPopDenseInfo = FunctionInfo<ArrayPopShiftFn>(jit::ArrayPopDense); @@ -4971,8 +5267,12 @@ // Set output to true if props_cursor < props_end. masm.loadPtr(Address(output, offsetof(NativeIterator, props_end)), temp); +#if defined(JS_CPU_MIPS) + masm.cmpPtrSet(Assembler::LessThan, Address(output, offsetof(NativeIterator, props_cursor)), temp, output); +#else masm.cmpPtr(Address(output, offsetof(NativeIterator, props_cursor)), temp); masm.emitSet(Assembler::LessThan, output); +#endif masm.bind(ool->rejoin()); return true; @@ -5225,6 +5525,7 @@ Linker linker(masm); IonCode *code = linker.newCode(cx, JSC::ION_CODE); + if (!code) return false; @@ -5373,9 +5674,16 @@ const ValueOperand value = ToValue(ins, LUnboxDouble::Input); if (ins->mir()->fallible()) { +#if defined(JS_CPU_MIPS) + Label bail; + masm.branchTestInt32(Assembler::NotEqual, value, &bail); + if (!bailoutFrom(&bail, ins->snapshot())) + return false; +#else Assembler::Condition cond = masm.testInt32(Assembler::NotEqual, value); if (!bailoutIf(cond, ins->snapshot())) return false; +#endif } masm.int32ValueToDouble(value, ToFloatRegister(ins->output())); masm.jump(ool->rejoin()); @@ -6050,6 +6358,28 @@ return true; } +#if defined(JS_CPU_MIPS) +bool +CodeGenerator::visitLoadElementV(LLoadElementV *load) +{ + Register elements = ToRegister(load->elements()); + const ValueOperand out = ToOutValue(load); + + if (load->index()->isConstant()) + masm.loadValue(Address(elements, ToInt32(load->index()) * sizeof(Value)), out); + else + masm.loadValue(BaseIndex(elements, ToRegister(load->index()), TimesEight), out); + + if (load->mir()->needsHoleCheck()) { + Label testMagic; + masm.branchTestMagic(Assembler::Equal, out, &testMagic); + if (!bailoutFrom(&testMagic, load->snapshot())) + return false; + } + + return true; +} +#else bool CodeGenerator::visitLoadElementV(LLoadElementV *load) { @@ -6069,6 +6399,7 @@ return true; } +#endif bool CodeGenerator::visitLoadElementHole(LLoadElementHole *lir) @@ -6825,8 +7156,12 @@ masm.jump(&done); masm.bind(¬Function); +#if defined(JS_CPU_MIPS) + masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::Class, call)), ImmWord((void*)NULL), output); +#else masm.cmpPtr(Address(output, offsetof(js::Class, call)), ImmWord((void *)NULL)); masm.emitSet(Assembler::NonZero, output); +#endif masm.bind(&done); return true; @@ -6880,8 +7215,12 @@ masm.loadObjClass(lhs, temp); masm.loadObjClass(rhs, output); +#if defined(JS_CPU_MIPS) + masm.cmpPtrSet(Assembler::Equal, temp, output, output); +#else masm.cmpPtr(temp, output); masm.emitSet(Assembler::Equal, output); +#endif return true; }
diff --git a/src/third_party/mozjs/js/src/jit/CodeGenerator.h b/src/third_party/mozjs/js/src/jit/CodeGenerator.h index 94854d4..e92477c 100644 --- a/src/third_party/mozjs/js/src/jit/CodeGenerator.h +++ b/src/third_party/mozjs/js/src/jit/CodeGenerator.h
@@ -13,8 +13,10 @@ # include "x64/CodeGenerator-x64.h" #elif defined(JS_CPU_ARM) # include "arm/CodeGenerator-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/CodeGenerator-mips.h" #else -#error "CPU Not Supported" +# error "CPU Not Supported" #endif namespace js {
diff --git a/src/third_party/mozjs/js/src/jit/Ion.cpp b/src/third_party/mozjs/js/src/jit/Ion.cpp index c12df1b..66cce66 100644 --- a/src/third_party/mozjs/js/src/jit/Ion.cpp +++ b/src/third_party/mozjs/js/src/jit/Ion.cpp
@@ -38,6 +38,10 @@ # include "x64/Lowering-x64.h" #elif defined(JS_CPU_ARM) # include "arm/Lowering-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/Lowering-mips.h" +#else +# error "Unknown CPU architecture." #endif #include "gc/Marking.h" @@ -185,6 +189,11 @@ functionWrappers_(NULL), osrTempData_(NULL), flusher_(NULL) +#if defined(JS_CPU_MIPS) + , + exceptionTail_(NULL), + bailoutTail_(NULL) +#endif { } @@ -194,6 +203,108 @@ freeOsrTempData(); } +#if defined(JS_CPU_MIPS) +bool +IonRuntime::initialize(JSContext *cx) +{ + // JS_ASSERT(cx->runtime()->currentThreadHasExclusiveAccess()); + // JS_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); + + // AutoCompartment ac(cx, cx->atomsCompartment()); + + IonContext ictx(cx, NULL); + AutoFlushCache afc("IonRuntime::initialize"); + + execAlloc_ = cx->runtime()->getExecAlloc(cx); + if (!execAlloc_) + return false; + + if (!cx->compartment()->ensureIonCompartmentExists(cx)) + return false; + + functionWrappers_ = cx->new_<VMWrapperMap>(cx); + if (!functionWrappers_ || !functionWrappers_->init()) + return false; + + IonSpew(IonSpew_Codegen, "# Emitting exception tail stub"); + exceptionTail_ = generateExceptionTailStub(cx); + if (!exceptionTail_) + return false; + + IonSpew(IonSpew_Codegen, "# Emitting bailout tail stub"); + bailoutTail_ = generateBailoutTailStub(cx); + if (!bailoutTail_) + return false; + + if (cx->runtime()->jitSupportsFloatingPoint) { + IonSpew(IonSpew_Codegen, "# Emitting bailout tables"); + + // Initialize some Ion-only stubs that require floating-point support. + if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId())) + return false; + + for (uint32_t id = 0;; id++) { + FrameSizeClass class_ = FrameSizeClass::FromClass(id); + if (class_ == FrameSizeClass::ClassLimit()) + break; + bailoutTables_.infallibleAppend((IonCode *)NULL); + bailoutTables_[id] = generateBailoutTable(cx, id); + if (!bailoutTables_[id]) + return false; + } + + IonSpew(IonSpew_Codegen, "# Emitting bailout handler"); + bailoutHandler_ = generateBailoutHandler(cx); + if (!bailoutHandler_) + return false; + + IonSpew(IonSpew_Codegen, "# Emitting invalidator"); + invalidator_ = generateInvalidator(cx); + if (!invalidator_) + return false; + } + + IonSpew(IonSpew_Codegen, "# Emitting sequential arguments rectifier"); + argumentsRectifier_ = generateArgumentsRectifier(cx, SequentialExecution, &argumentsRectifierReturnAddr_); + if (!argumentsRectifier_) + return false; + +#ifdef JS_THREADSAFE + IonSpew(IonSpew_Codegen, "# Emitting parallel arguments rectifier"); + parallelArgumentsRectifier_ = generateArgumentsRectifier(cx, ParallelExecution, NULL); + if (!parallelArgumentsRectifier_) + return false; +#endif + + IonSpew(IonSpew_Codegen, "# Emitting EnterJIT sequence"); + enterJIT_ = generateEnterJIT(cx, EnterJitOptimized); + if (!enterJIT_) + return false; + + IonSpew(IonSpew_Codegen, "# Emitting EnterBaselineJIT sequence"); + enterBaselineJIT_ = generateEnterJIT(cx, EnterJitBaseline); + if (!enterBaselineJIT_) + return false; + + IonSpew(IonSpew_Codegen, "# Emitting Pre Barrier for Value"); + valuePreBarrier_ = generatePreBarrier(cx, MIRType_Value); + if (!valuePreBarrier_) + return false; + + IonSpew(IonSpew_Codegen, "# Emitting Pre Barrier for Shape"); + shapePreBarrier_ = generatePreBarrier(cx, MIRType_Shape); + if (!shapePreBarrier_) + return false; + + IonSpew(IonSpew_Codegen, "# Emitting VM function wrappers"); + for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) { + if (!generateVMWrapper(cx, *fun)) + return false; + } + + return true; +} +#else bool IonRuntime::initialize(JSContext *cx) { @@ -270,6 +381,7 @@ return true; } +#endif IonCode * IonRuntime::debugTrapHandler(JSContext *cx) @@ -2368,6 +2480,69 @@ runtime_ = rt; } +#if defined(JS_CPU_MIPS) +AutoFlushCache::~AutoFlushCache() +{ + if (!runtime_) { + return; + } + + flushAnyway(); + IonSpewCont(IonSpew_CacheFlush, ">", name_); + if (runtime_->flusher() == this) { + IonSpewFin(IonSpew_CacheFlush); + runtime_->setFlusher(NULL); + } +} + +void +AutoFlushCache::update(uintptr_t newStart, size_t len) { + uintptr_t newStop = newStart + len; + if (this == NULL) { + // just flush right here and now. + JSC::ExecutableAllocator::cacheFlush((void*)newStart, len); + return; + } + used_ = true; + if (!start_) { + IonSpewCont(IonSpew_CacheFlush, "."); + start_ = newStart; + stop_ = newStop; + return; + } + + if (newStop < start_ - 4096 || newStart > stop_ + 4096) { + // If this would add too many pages to the range, bail and just do the flush now. + IonSpewCont(IonSpew_CacheFlush, "*"); + JSC::ExecutableAllocator::cacheFlush((void*)newStart, len); + return; + } + start_ = Min(start_, newStart); + stop_ = Max(stop_, newStop); + IonSpewCont(IonSpew_CacheFlush, "."); +} + +void +AutoFlushCache::flushAnyway() +{ + if (!runtime_) + return; + + IonSpewCont(IonSpew_CacheFlush, "|", name_); + + if (!used_) + return; + + if (start_) { + JSC::ExecutableAllocator::cacheFlush((void *)start_, size_t(stop_ - start_ + sizeof(Instruction))); + } else { + JSC::ExecutableAllocator::cacheFlush(NULL, 0xff000000); + } + used_ = false; +} + +#endif // defined(JS_CPU_MIPS) + AutoFlushInhibitor::AutoFlushInhibitor(IonCompartment *ic) : ic_(ic), afc(NULL)
diff --git a/src/third_party/mozjs/js/src/jit/IonCaches.h b/src/third_party/mozjs/js/src/jit/IonCaches.h index cf13df9..610f8da 100644 --- a/src/third_party/mozjs/js/src/jit/IonCaches.h +++ b/src/third_party/mozjs/js/src/jit/IonCaches.h
@@ -10,6 +10,11 @@ #include "IonCode.h" #include "Registers.h" +#if defined(JS_CPU_MIPS) +#include "jit/mips/Assembler-mips.h" +#include "jit/shared/Assembler-shared.h" +#endif // defined(JS_CPU_MIPS) + #include "vm/ForkJoin.h" class JSFunction; @@ -337,13 +342,16 @@ // Offset from the initial jump to the rejoin label. #ifdef JS_CPU_ARM static const size_t REJOIN_LABEL_OFFSET = 4; +#elif defined(JS_CPU_MIPS) + // The size of jump created by MacroAssemblerMIPSCompat::jumpWithPatch. + static const size_t REJOIN_LABEL_OFFSET = 4 * sizeof(void *); #else static const size_t REJOIN_LABEL_OFFSET = 0; #endif CodeLocationLabel rejoinLabel() const { uint8_t *ptr = initialJump_.raw(); -#ifdef JS_CPU_ARM +#if defined(JS_CPU_ARM) || defined(JS_CPU_MIPS) uint32_t i = 0; while (i < REJOIN_LABEL_OFFSET) ptr = Assembler::nextInstruction(ptr, &i);
diff --git a/src/third_party/mozjs/js/src/jit/IonCompartment.h b/src/third_party/mozjs/js/src/jit/IonCompartment.h index 88107ed..d1b0dbf 100644 --- a/src/third_party/mozjs/js/src/jit/IonCompartment.h +++ b/src/third_party/mozjs/js/src/jit/IonCompartment.h
@@ -195,6 +195,22 @@ if (!flusher_ || !fl) flusher_ = fl; } + +#if defined(JS_CPU_MIPS) + // Shared post-bailout-handler tail. + IonCode* bailoutTail_; + IonCode* getBailoutTail() const { + return bailoutTail_; + } + + IonCode* exceptionTail_; + IonCode* getExceptionTail() const { + return exceptionTail_; + } + + IonCode *generateExceptionTailStub(JSContext *cx); + IonCode *generateBailoutTailStub(JSContext *cx); +#endif }; class IonCompartment
diff --git a/src/third_party/mozjs/js/src/jit/IonFrames.cpp b/src/third_party/mozjs/js/src/jit/IonFrames.cpp index 6cdd786..4d0fc05 100644 --- a/src/third_party/mozjs/js/src/jit/IonFrames.cpp +++ b/src/third_party/mozjs/js/src/jit/IonFrames.cpp
@@ -1307,7 +1307,7 @@ // Inlined functions may be clones that still point to the lazy script // for the executed script, if they are clones. The actual script // exists though, just make sure the function points to it. - script_ = callee_->existingScript(); + script_ = callee_->existingScriptForInlinedFunction(); pc_ = script_->code + si_.pcOffset(); }
diff --git a/src/third_party/mozjs/js/src/jit/IonFrames.h b/src/third_party/mozjs/js/src/jit/IonFrames.h index fcd33e6..573d7ea 100644 --- a/src/third_party/mozjs/js/src/jit/IonFrames.h +++ b/src/third_party/mozjs/js/src/jit/IonFrames.h
@@ -292,6 +292,8 @@ # include "jit/shared/IonFrames-x86-shared.h" #elif defined (JS_CPU_ARM) # include "jit/arm/IonFrames-arm.h" +#elif defined(JS_CPU_MIPS) +# include "jit/mips/IonFrames-mips.h" #else # error "unsupported architecture" #endif
diff --git a/src/third_party/mozjs/js/src/jit/IonMacroAssembler.cpp b/src/third_party/mozjs/js/src/jit/IonMacroAssembler.cpp index fe4bd23..0a563e2 100644 --- a/src/third_party/mozjs/js/src/jit/IonMacroAssembler.cpp +++ b/src/third_party/mozjs/js/src/jit/IonMacroAssembler.cpp
@@ -134,6 +134,44 @@ template void MacroAssembler::guardType(const ValueOperand &value, types::Type type, Register scratch, Label *matched, Label *miss); +#if defined(JS_CPU_MIPS) +void +MacroAssembler::PushRegsInMask(RegisterSet set) +{ + int32_t diffG = set.gprs().size() * STACK_SLOT_SIZE; + int32_t diffF = set.fpus().size() * sizeof(double); + + reserveStack(diffG); + // BackwardIterator in 31. + for (GeneralRegisterIterator iter(set.gprs()); iter.more(); iter++) { + diffG -= STACK_SLOT_SIZE; + storePtr(*iter, Address(StackPointer, diffG)); + } + MOZ_ASSERT(diffG == 0); + + // Double values have to be aligned. We reserve extra space so that we can + // start writing from the first aligned location. + // We reserve a whole extra double so that the buffer has even size. + ma_and(SecondScratchReg, sp, Imm32(~(StackAlignment - 1))); + reserveStack(diffF + sizeof(double)); + + // ForwardIterator in 31. + for (FloatRegisterIterator iter(set.fpus()); iter.more(); iter++) { + // Use assembly s.d because we have alligned the stack. + // :TODO: (Bug 972836) Fix this once odd regs can be used as + // float32 only. For now we skip saving odd regs for O32 ABI. + + // :TODO: (Bug 985881) Make a switch for N32 ABI. + if ((*iter).code() % 2 == 0) { + as_sd(*iter, SecondScratchReg, -diffF); + } + + diffF -= sizeof(double); + } + + MOZ_ASSERT(diffF == 0); +} +#else // defined(JS_CPU_MIPS) void MacroAssembler::PushRegsInMask(RegisterSet set) { @@ -172,10 +210,14 @@ #endif JS_ASSERT(diffF == 0); } +#endif // defined(JS_CPU_MIPS) void MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore) { +#if defined(JS_CPU_MIPS) + MacroAssemblerSpecific::PopRegsInMaskIgnore(set, ignore); +#else int32_t diffG = set.gprs().size() * STACK_SLOT_SIZE; int32_t diffF = set.fpus().size() * sizeof(double); const int32_t reservedG = diffG; @@ -219,6 +261,7 @@ freeStack(reservedG); } JS_ASSERT(diffG == 0); +#endif // defined(JS_CPU_MIPS) } void @@ -270,8 +313,14 @@ convertUInt32ToDouble(temp, dest.fpu()); } else { load32(src, dest.gpr()); - test32(dest.gpr(), dest.gpr()); + +#if defined(JS_CPU_MIPS) + branchTest32(Assembler::Signed, dest.gpr(), dest.gpr(), fail); +#else + test32(dest.gpr(), dest.gpr()); // Resolved mips conflict. j(Assembler::Signed, fail); +#endif + } break; case TypedArray::TYPE_FLOAT32: @@ -311,12 +360,20 @@ case TypedArray::TYPE_UINT32: // Don't clobber dest when we could fail, instead use temp. load32(src, temp); +#if defined(JS_CPU_MIPS) + // Nothing... +#else test32(temp, temp); +#endif if (allowDouble) { // If the value fits in an int32, store an int32 type tag. // Else, convert the value to double and box it. Label done, isDouble; +#if defined(JS_CPU_MIPS) + branchTest32(Assembler::Signed, temp, temp, &isDouble); +#else j(Assembler::Signed, &isDouble); +#endif { tagValue(JSVAL_TYPE_INT32, temp, dest); jump(&done); @@ -329,7 +386,11 @@ bind(&done); } else { // Bailout if the value does not fit in an int32. +#if defined(JS_CPU_MIPS) + branchTest32(Assembler::Signed, temp, temp, fail); +#else j(Assembler::Signed, fail); +#endif tagValue(JSVAL_TYPE_INT32, temp, dest); } break; @@ -642,8 +703,12 @@ branchTest32(Assembler::Zero, result, atomBit, ¬Atom); branchTest32(Assembler::Zero, temp, atomBit, ¬Atom); +#if defined(JS_CPU_MIPS) + cmpPtrSet(JSOpToCondition(MCompare::Compare_String, op), left, right, result); +#else cmpPtr(left, right); emitSet(JSOpToCondition(MCompare::Compare_String, op), result); +#endif jump(&done); bind(¬Atom); @@ -682,6 +747,7 @@ bind(&osrRemoved); } +#if !defined(JS_CPU_MIPS) void MacroAssembler::performOsr() { @@ -740,6 +806,7 @@ enterOsr(calleeToken, code); ret(); } +#endif // !defined(JS_CPU_MIPS) void MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo) @@ -1251,3 +1318,44 @@ if (!done()) gen_.next(types_[i_]); } + +#if defined(JS_CPU_MIPS) +void MacroAssembler::branchIfNotInterpretedConstructor(Register fun, Register scratch, Label *label) +{ + // 16-bit loads are slow and unaligned 32-bit loads may be too so + // perform an aligned 32-bit load and adjust the bitmask accordingly. + JS_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0); + JS_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2); + JS_STATIC_ASSERT(IS_LITTLE_ENDIAN); + + // Emit code for the following test: + // + // bool isInterpretedConstructor() const { + // return isInterpreted() && !isFunctionPrototype() && !isArrow() && + // (!isSelfHostedBuiltin() || isSelfHostedConstructor()); + // } + + // First, ensure it's a scripted function. + load32(Address(fun, JSFunction::offsetOfNargs()), scratch); + branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::INTERPRETED << 16), label); + + // Common case: if IS_FUN_PROTO, ARROW and SELF_HOSTED are not set, + // the function is an interpreted constructor and we're done. + Label done; + uint32_t bits = (JSFunction::IS_FUN_PROTO | JSFunction::ARROW | JSFunction::SELF_HOSTED) << 16; + branchTest32(Assembler::Zero, scratch, Imm32(bits), &done); + { + // The callee is either Function.prototype, an arrow function or + // self-hosted. None of these are constructible, except self-hosted + // constructors, so branch to |label| if SELF_HOSTED_CTOR is not set. + branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::SELF_HOSTED_CTOR << 16), label); + +#ifdef DEBUG + // Function.prototype should not have the SELF_HOSTED_CTOR flag. + branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::IS_FUN_PROTO << 16), &done); + breakpoint(); +#endif + } + bind(&done); +} +#endif
diff --git a/src/third_party/mozjs/js/src/jit/IonMacroAssembler.h b/src/third_party/mozjs/js/src/jit/IonMacroAssembler.h index c6c08f2..f1206d8 100644 --- a/src/third_party/mozjs/js/src/jit/IonMacroAssembler.h +++ b/src/third_party/mozjs/js/src/jit/IonMacroAssembler.h
@@ -18,6 +18,10 @@ # include "jit/x64/MacroAssembler-x64.h" #elif defined(JS_CPU_ARM) # include "jit/arm/MacroAssembler-arm.h" +#elif defined(JS_CPU_MIPS) +# include "jit/mips/MacroAssembler-mips.h" +#else +# error "Unknown CPU architecture." #endif #include "jit/AsmJS.h" #include "jit/IonCompartment.h" @@ -174,6 +178,22 @@ branchPtr(cond, Address(obj, JSObject::offsetOfShape()), shape, label); } +#if defined(JS_CPU_MIPS) + template <typename Value> + void branchTestMIRType(Condition cond, const Value &val, MIRType type, Label *label) { + switch (type) { + case MIRType_Null: return branchTestNull(cond, val, label); + case MIRType_Undefined: return branchTestUndefined(cond, val, label); + case MIRType_Boolean: return branchTestBoolean(cond, val, label); + case MIRType_Int32: return branchTestInt32(cond, val, label); + case MIRType_String: return branchTestString(cond, val, label); + case MIRType_Object: return branchTestObject(cond, val, label); + case MIRType_Double: return branchTestDouble(cond, val, label); + default: + JS_NOT_REACHED("Bad MIRType"); + } + } +#else // defined(JS_CPU_MIPS) template <typename Value> Condition testMIRType(Condition cond, const Value &val, MIRType type) { JS_ASSERT(type == MIRType_Null || type == MIRType_Undefined || @@ -198,6 +218,7 @@ cond = testMIRType(cond, val, type); j(cond, label); } +#endif // defined(JS_CPU_MIPS) // Branches to |label| if |reg| is false. |reg| should be a C++ bool. void branchIfFalseBool(const Register ®, Label *label) { @@ -358,6 +379,10 @@ branchTest32(Assembler::NonZero, address, Imm32(bit), label); } +#if defined(JS_CPU_MIPS) + void branchIfNotInterpretedConstructor(Register fun, Register scratch, Label *label); +#endif + using MacroAssemblerSpecific::Push; void Push(jsid id, Register scratchReg) { @@ -721,6 +746,23 @@ return ret; } +#if defined(JS_CPU_MIPS) + void branchTestObjectTruthy(bool truthy, Register objReg, Register scratch, + Label *slowCheck, Label *checked) + { + // The branches to out-of-line code here implement a conservative version + // of the JSObject::isWrapper test performed in EmulatesUndefined. If none + // of the branches are taken, we can check class flags directly. + loadObjClass(objReg, scratch); + + branchPtr(Assembler::Equal, scratch, ImmWord(&ObjectProxyClass), slowCheck); + branchPtr(Assembler::Equal, scratch, ImmWord(&OuterWindowProxyClass), slowCheck); + branchPtr(Assembler::Equal, scratch, ImmWord(&FunctionProxyClass), slowCheck); + + Condition cond = truthy ? Assembler::Zero : Assembler::NonZero; + branchTest32(cond, Address(scratch, Class::offsetOfFlags()), Imm32(JSCLASS_EMULATES_UNDEFINED), checked); + } +#else // defined(JS_CPU_MIPS) Condition branchTestObjectTruthy(bool truthy, Register objReg, Register scratch, Label *slowCheck) { @@ -735,6 +777,7 @@ test32(Address(scratch, Class::offsetOfFlags()), Imm32(JSCLASS_EMULATES_UNDEFINED)); return truthy ? Assembler::Zero : Assembler::NonZero; } +#endif // defined(JS_CPU_MIPS) void tagCallee(Register callee, ExecutionMode mode); void clearCalleeTag(Register callee, ExecutionMode mode);
diff --git a/src/third_party/mozjs/js/src/jit/IonSpewer.cpp b/src/third_party/mozjs/js/src/jit/IonSpewer.cpp index 1c67001..5a2e306 100644 --- a/src/third_party/mozjs/js/src/jit/IonSpewer.cpp +++ b/src/third_party/mozjs/js/src/jit/IonSpewer.cpp
@@ -219,7 +219,7 @@ if (LoggingChecked) return; LoggingChecked = true; - const char *env = getenv("IONFLAGS"); + const char* env = NULL; if (!env) return; if (strstr(env, "help")) { @@ -261,6 +261,7 @@ exit(0); /*NOTREACHED*/ } + if (ContainsFlag(env, "aborts")) EnableChannel(IonSpew_Abort); if (ContainsFlag(env, "alias"))
diff --git a/src/third_party/mozjs/js/src/jit/LIR-Common.h b/src/third_party/mozjs/js/src/jit/LIR-Common.h index fb43cfc..877cb27 100644 --- a/src/third_party/mozjs/js/src/jit/LIR-Common.h +++ b/src/third_party/mozjs/js/src/jit/LIR-Common.h
@@ -1495,6 +1495,43 @@ } }; +#if defined(JS_CPU_MIPS) +class LCompareDAndBranch : public LControlInstructionHelper<2, 2, 0> +{ + MCompare *cmpMir_; + + public: + LIR_HEADER(CompareDAndBranch) + LCompareDAndBranch(MCompare *cmpMir, const LAllocation &left, const LAllocation &right, + MBasicBlock *ifTrue, MBasicBlock *ifFalse) + : cmpMir_(cmpMir) + { + setOperand(0, left); + setOperand(1, right); + setSuccessor(0, ifTrue); + setSuccessor(1, ifFalse); + } + + MBasicBlock *ifTrue() const { + return getSuccessor(0); + } + MBasicBlock *ifFalse() const { + return getSuccessor(1); + } + const LAllocation *left() { + return getOperand(0); + } + const LAllocation *right() { + return getOperand(1); + } + MTest *mir() const { + return mir_->toTest(); + } + MCompare *cmpMir() const { + return cmpMir_; + } +}; +#else // defined(JS_CPU_MIPS) class LCompareDAndBranch : public LControlInstructionHelper<2, 2, 0> { public: @@ -1524,6 +1561,7 @@ return mir_->toCompare(); } }; +#endif // defined(JS_CPU_MIPS) class LCompareS : public LInstructionHelper<1, 2, 1> {
diff --git a/src/third_party/mozjs/js/src/jit/LIR.h b/src/third_party/mozjs/js/src/jit/LIR.h index 436faf0..27e90ad 100644 --- a/src/third_party/mozjs/js/src/jit/LIR.h +++ b/src/third_party/mozjs/js/src/jit/LIR.h
@@ -1440,6 +1440,10 @@ # include "shared/LIR-x86-shared.h" #elif defined(JS_CPU_ARM) # include "arm/LIR-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/LIR-mips.h" +#else +# error "Unknown CPU architecture." #endif #undef LIR_HEADER
diff --git a/src/third_party/mozjs/js/src/jit/LOpcodes.h b/src/third_party/mozjs/js/src/jit/LOpcodes.h index dfbd53a..f9539b5 100644 --- a/src/third_party/mozjs/js/src/jit/LOpcodes.h +++ b/src/third_party/mozjs/js/src/jit/LOpcodes.h
@@ -247,6 +247,10 @@ # include "x64/LOpcodes-x64.h" #elif defined(JS_CPU_ARM) # include "arm/LOpcodes-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/LOpcodes-mips.h" +#else +# error "Unknown CPU architecture." #endif #define LIR_OPCODE_LIST(_) \
diff --git a/src/third_party/mozjs/js/src/jit/Lowering.cpp b/src/third_party/mozjs/js/src/jit/Lowering.cpp index 19e7425..a7db9c6 100644 --- a/src/third_party/mozjs/js/src/jit/Lowering.cpp +++ b/src/third_party/mozjs/js/src/jit/Lowering.cpp
@@ -657,7 +657,11 @@ if (comp->isDoubleComparison()) { LAllocation lhs = useRegister(left); LAllocation rhs = useRegister(right); +#if defined(JS_CPU_MIPS) + LCompareDAndBranch *lir = new LCompareDAndBranch(comp, lhs, rhs, ifTrue, ifFalse); +#else LCompareDAndBranch *lir = new LCompareDAndBranch(lhs, rhs, ifTrue, ifFalse); +#endif return add(lir, comp); } @@ -2260,7 +2264,12 @@ return assignSafepoint(lir, ins); } +#if defined(JS_CPU_MIPS) + LGetPropertyCacheT *lir = new LGetPropertyCacheT(useRegister(ins->object()), + tempForDispatchCache(ins->type())); +#else LGetPropertyCacheT *lir = newLGetPropertyCacheT(ins); +#endif if (!define(lir, ins)) return false; return assignSafepoint(lir, ins);
diff --git a/src/third_party/mozjs/js/src/jit/Lowering.h b/src/third_party/mozjs/js/src/jit/Lowering.h index 3d67a2d..b2df2ce 100644 --- a/src/third_party/mozjs/js/src/jit/Lowering.h +++ b/src/third_party/mozjs/js/src/jit/Lowering.h
@@ -20,6 +20,8 @@ # include "x64/Lowering-x64.h" #elif defined(JS_CPU_ARM) # include "arm/Lowering-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/Lowering-mips.h" #else # error "CPU!" #endif
diff --git a/src/third_party/mozjs/js/src/jit/MIR.h b/src/third_party/mozjs/js/src/jit/MIR.h index ef1df1b..ad4a52b 100644 --- a/src/third_party/mozjs/js/src/jit/MIR.h +++ b/src/third_party/mozjs/js/src/jit/MIR.h
@@ -3476,6 +3476,25 @@ bool fallible(); bool truncate(); + +#if defined(JS_CPU_MIPS) + // isTruncatedDirectly_ defaults to false in SpiderMonkey 31. + bool isTruncatedIndirectly() const { + return false; + } + bool canTruncateInfinities() const { + return isTruncated(); + } + bool canTruncateRemainder() const { + return isTruncated(); + } + bool canTruncateOverflow() const { + return isTruncated() || isTruncatedIndirectly(); + } + bool canTruncateNegativeZero() const { + return isTruncated() || isTruncatedIndirectly(); + } +#endif }; class MMod : public MBinaryArithInstruction @@ -3511,6 +3530,29 @@ void computeRange(); bool truncate(); + +#if defined(JS_CPU_MIPS) + // Can be negativeDividend defaults to true in SpiderMonkey31 and is set + // to 0 in several areas that analyze the code. Since false seems to be + // more restrictive, we return that here. This seems to be ok so far, + // however we should be careful when this code is run. + bool canBeNegativeDividend() const { + JS_ASSERT(specialization_ == MIRType_Int32); + SB_LOG(WARNING) << "canBeNegativeDividend() returning false"; + return false; + } + + bool + canBeDivideByZero() const { + JS_ASSERT(specialization_ == MIRType_Int32); + return !rhs()->isConstant() || rhs()->toConstant()->value().toInt32() == 0; + } + + // unsigned_ defaults to false in SpiderMonkey31. + bool isUnsigned() const { + return false; + } +#endif }; class MConcat
diff --git a/src/third_party/mozjs/js/src/jit/MoveEmitter.h b/src/third_party/mozjs/js/src/jit/MoveEmitter.h index b861ac0..792b8ef 100644 --- a/src/third_party/mozjs/js/src/jit/MoveEmitter.h +++ b/src/third_party/mozjs/js/src/jit/MoveEmitter.h
@@ -11,6 +11,8 @@ # include "jit/shared/MoveEmitter-x86-shared.h" #elif defined(JS_CPU_ARM) # include "jit/arm/MoveEmitter-arm.h" +#elif defined(JS_CPU_MIPS) +# include "jit/mips/MoveEmitter-mips.h" #else # error "CPU Not Supported" #endif
diff --git a/src/third_party/mozjs/js/src/jit/MoveResolver.h b/src/third_party/mozjs/js/src/jit/MoveResolver.h index 228aba4..4705dc8 100644 --- a/src/third_party/mozjs/js/src/jit/MoveResolver.h +++ b/src/third_party/mozjs/js/src/jit/MoveResolver.h
@@ -74,6 +74,11 @@ bool isEffectiveAddress() const { return kind_ == EFFECTIVE_ADDRESS; } +#if defined(JS_CPU_MIPS) + bool isMemoryOrEffectiveAddress() const { + return isMemory() || isEffectiveAddress(); + } +#endif Register reg() const { JS_ASSERT(isGeneralReg()); return Register::FromCode(code_);
diff --git a/src/third_party/mozjs/js/src/jit/ParallelFunctions.cpp b/src/third_party/mozjs/js/src/jit/ParallelFunctions.cpp index ba1513b..f6e73ef 100644 --- a/src/third_party/mozjs/js/src/jit/ParallelFunctions.cpp +++ b/src/third_party/mozjs/js/src/jit/ParallelFunctions.cpp
@@ -81,7 +81,7 @@ if (traceMode == NotSet) { // Racy, but that's ok. - const char *env = getenv("IONFLAGS"); + const char* env = ""; if (strstr(env, "trace-all")) traceMode = All; else
diff --git a/src/third_party/mozjs/js/src/jit/RegisterAllocator.h b/src/third_party/mozjs/js/src/jit/RegisterAllocator.h index c6199a6..b4f76cd 100644 --- a/src/third_party/mozjs/js/src/jit/RegisterAllocator.h +++ b/src/third_party/mozjs/js/src/jit/RegisterAllocator.h
@@ -309,7 +309,7 @@ #if defined(JS_CPU_X64) if (mir->compilingAsmJS()) allRegisters_.take(AnyRegister(HeapReg)); -#elif defined(JS_CPU_ARM) +#elif defined(JS_CPU_ARM) || defined(JS_CPU_MIPS) if (mir->compilingAsmJS()) { allRegisters_.take(AnyRegister(HeapReg)); allRegisters_.take(AnyRegister(GlobalReg));
diff --git a/src/third_party/mozjs/js/src/jit/RegisterSets.h b/src/third_party/mozjs/js/src/jit/RegisterSets.h index a181b61..f6f860f 100644 --- a/src/third_party/mozjs/js/src/jit/RegisterSets.h +++ b/src/third_party/mozjs/js/src/jit/RegisterSets.h
@@ -445,12 +445,17 @@ uint32_t bits() const { return bits_; } + uint32_t size() const { +#if defined(JS_CPU_MIPS) + return __builtin_popcount(bits_); +#else uint32_t sum2 = (bits_ & 0x55555555) + ((bits_ & 0xaaaaaaaa) >> 1); uint32_t sum4 = (sum2 & 0x33333333) + ((sum2 & 0xcccccccc) >> 2); uint32_t sum8 = (sum4 & 0x0f0f0f0f) + ((sum4 & 0xf0f0f0f0) >> 4); uint32_t sum16 = (sum8 & 0x00ff00ff) + ((sum8 & 0xff00ff00) >> 8); return sum16; +#endif } bool operator ==(const TypedRegisterSet<T> &other) const { return other.bits_ == bits_; @@ -794,6 +799,12 @@ {} #endif +#if defined(JS_CPU_MIPS) + explicit AsmJSHeapAccess(uint32_t offset) + : offset_(offset) + {} +#endif + uint32_t offset() const { return offset_; } unsigned opLength() const { return opLength_; } bool isLoad() const { return loadedReg_ != UINT8_MAX; }
diff --git a/src/third_party/mozjs/js/src/jit/Registers.h b/src/third_party/mozjs/js/src/jit/Registers.h index 6997c6d..52b53ac 100644 --- a/src/third_party/mozjs/js/src/jit/Registers.h +++ b/src/third_party/mozjs/js/src/jit/Registers.h
@@ -15,6 +15,10 @@ # include "x64/Architecture-x64.h" #elif defined(JS_CPU_ARM) # include "arm/Architecture-arm.h" +#elif defined(JS_CPU_MIPS) +# include "mips/Architecture-mips.h" +#else +# error "Unknown CPU architecture." #endif #include "FixedArityList.h"
diff --git a/src/third_party/mozjs/js/src/jit/Snapshots.cpp b/src/third_party/mozjs/js/src/jit/Snapshots.cpp index 80d219d..fa3bb73 100644 --- a/src/third_party/mozjs/js/src/jit/Snapshots.cpp +++ b/src/third_party/mozjs/js/src/jit/Snapshots.cpp
@@ -344,7 +344,11 @@ { JS_ASSERT(uint32_t(type) <= MAX_TYPE_FIELD_VALUE); JS_ASSERT(uint32_t(regCode) <= MAX_REG_FIELD_VALUE); +#if defined(JS_CPU_MIPS) + // Note: This static assert fails on MIPS, but seems safe. +#else JS_STATIC_ASSERT(Registers::Total < MIN_REG_FIELD_ESC); +#endif uint8_t byte = uint32_t(type) | (regCode << 3); writer_.writeByte(byte);
diff --git a/src/third_party/mozjs/js/src/jit/mips/Architecture-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/Architecture-mips.cpp index d0d61ff..639b567 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Architecture-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/Architecture-mips.cpp
@@ -47,30 +47,6 @@ return js::jit::GetMIPSFlags() & HWCAP_FPU; } -Registers::Code -Registers::FromName(const char *name) -{ - for (size_t i = 0; i < Total; i++) { - if (strcmp(GetName(i), name) == 0) - return Code(i); - } - - return Invalid; -} - -FloatRegisters::Code -FloatRegisters::FromName(const char *name) -{ - for (size_t i = 0; i < Total; i++) { - if (strcmp(GetName(i), name) == 0) - return Code(i); - } - - return Invalid; -} - - - } // namespace ion } // namespace js
diff --git a/src/third_party/mozjs/js/src/jit/mips/Architecture-mips.h b/src/third_party/mozjs/js/src/jit/mips/Architecture-mips.h index 0bc7346..5b36a12 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Architecture-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/Architecture-mips.h
@@ -15,11 +15,22 @@ // gcc appears to use _mips_hard_float to denote // that the target is a hard-float target. #ifdef _mips_hard_float -#define JS_CODEGEN_MIPS_HARDFP +#define JS_CPU_MIPS_HARDFP #endif namespace js { namespace jit { +// In bytes: slots needed for potential memory->memory move spills. +// +8 for cycles +// +4 for gpr spills +// +8 for double spills +static const ptrdiff_t STACK_SLOT_SIZE = 4; +// static const uint32_t STACK_SLOT_SIZE = 4; +static const uint32_t DOUBLE_STACK_ALIGNMENT = 2; + +// An offset that is illegal for a local variable's stack allocation. +static const int32_t INVALID_STACK_SLOT = -1; + // Shadow stack space is not required on MIPS. static const uint32_t ShadowStackSpace = 0; @@ -36,7 +47,7 @@ class Registers { public: - enum RegisterID { + typedef enum RegisterID { r0 = 0, r1, r2, @@ -102,7 +113,7 @@ fp = r30, ra = r31, invalid_reg - }; + } RegisterID; typedef RegisterID Code; static const char *GetName(Code code) { @@ -117,8 +128,6 @@ return GetName(Code(i)); } - static Code FromName(const char *name); - static const Code StackPointer = sp; static const Code Invalid = invalid_reg; @@ -144,6 +153,8 @@ (1 << Registers::t6) | (1 << Registers::t7); + // We use this constant to save registers when entering functions. This + // is why $ra is added here even though it is not "Non Volatile". static const uint32_t NonVolatileMask = (1 << Registers::s0) | (1 << Registers::s1) | @@ -152,7 +163,8 @@ (1 << Registers::s4) | (1 << Registers::s5) | (1 << Registers::s6) | - (1 << Registers::s7); + (1 << Registers::s7) | + (1 << Registers::ra); static const uint32_t WrapperMask = VolatileMask | // = arguments @@ -176,8 +188,8 @@ // Registers returned from a JS -> JS call. static const uint32_t JSCallMask = - (1 << Registers::v0) | - (1 << Registers::v1); + (1 << Registers::a2) | + (1 << Registers::a3); // Registers returned from a JS -> C call. static const uint32_t CallMask = @@ -254,8 +266,6 @@ return GetName(Code(i)); } - static Code FromName(const char *name); - static const Code Invalid = invalid_freg; static const uint32_t Total = 32;
diff --git a/src/third_party/mozjs/js/src/jit/mips/Assembler-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/Assembler-mips.cpp index 57fe57b..7b53b33 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Assembler-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/Assembler-mips.cpp
@@ -14,7 +14,7 @@ #include "assembler/jit/ExecutableAllocator.h" #include "gc/Marking.h" -#include "jit/JitCompartment.h" +#include "jit/IonCompartment.h" using mozilla::DebugOnly; @@ -30,7 +30,7 @@ ABIArg ABIArgGenerator::next(MIRType type) { - MOZ_ASSUME_UNREACHABLE("NYI"); + JS_NOT_REACHED("NYI"); return ABIArg(); } const Register ABIArgGenerator::NonArgReturnVolatileReg0 = t0; @@ -126,7 +126,7 @@ Assembler::updateLuiOriValue(inst1, inst2, (uint32_t)label.raw()); - AutoFlushICache::flush(uintptr_t(inst1), 8); + AutoFlushCache::updateTop(uintptr_t(inst1), 8); } void @@ -150,7 +150,7 @@ updateLuiOriValue(inst1, inst1->next(), (uint32_t)buffer + value); } - AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size()); + AutoFlushCache::updateTop((uintptr_t)buffer, m_buffer.size()); } uint32_t @@ -166,7 +166,7 @@ } uint8_t * -Assembler::PatchableJumpAddress(JitCode *code, uint32_t pe_) +Assembler::PatchableJumpAddress(IonCode *code, uint32_t pe_) { return code->raw() + pe_; } @@ -201,20 +201,20 @@ return Assembler::extractLuiOriValue(inst, inst->next()); } -static JitCode * +static IonCode * CodeFromJump(Instruction *jump) { uint8_t *target = (uint8_t *)Assembler::extractLuiOriValue(jump, jump->next()); - return JitCode::FromExecutable(target); + return IonCode::FromExecutable(target); } void -Assembler::TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader) +Assembler::TraceJumpRelocations(JSTracer *trc, IonCode *code, CompactBufferReader &reader) { RelocationIterator iter(reader); while (iter.read()) { - JitCode *child = CodeFromJump((Instruction *)(code->raw() + iter.offset())); - MarkJitCodeUnbarriered(trc, &child, "rel32"); + IonCode *child = CodeFromJump((Instruction *)(code->raw() + iter.offset())); + MarkIonCodeUnbarriered(trc, &child, "rel32"); } } @@ -246,7 +246,7 @@ } void -Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader) +Assembler::TraceDataRelocations(JSTracer *trc, IonCode *code, CompactBufferReader &reader) { ::TraceDataRelocations(trc, code->raw(), reader); } @@ -277,10 +277,10 @@ { for (size_t i = 0; i < jumps_.length(); i++) { RelativePatch &rp = jumps_[i]; - if (rp.kind == Relocation::JITCODE) { - JitCode *code = JitCode::FromExecutable((uint8_t *)rp.target); - MarkJitCodeUnbarriered(trc, &code, "masmrel32"); - JS_ASSERT(code == JitCode::FromExecutable((uint8_t *)rp.target)); + if (rp.kind == Relocation::IONCODE) { + IonCode *code = IonCode::FromExecutable((uint8_t *)rp.target); + MarkIonCodeUnbarriered(trc, &code, "masmrel32"); + JS_ASSERT(code == IonCode::FromExecutable((uint8_t *)rp.target)); } } if (dataRelocations_.length()) { @@ -346,7 +346,7 @@ case NotSigned: return Signed; default: - MOZ_ASSUME_UNREACHABLE("unexpected condition"); + JS_NOT_REACHED("unexpected condition"); return Equal; } } @@ -384,7 +384,7 @@ case DoubleLessThanOrEqualOrUnordered: return DoubleGreaterThan; default: - MOZ_ASSUME_UNREACHABLE("unexpected condition"); + JS_NOT_REACHED("unexpected condition"); return DoubleEqual; } } @@ -450,7 +450,7 @@ BufferOffset Assembler::writeInst(uint32_t x, uint32_t *dest) { - if (dest == nullptr) + if (dest == NULL) return m_buffer.putInt(x); writeInstStatic(x, dest); @@ -460,7 +460,7 @@ void Assembler::writeInstStatic(uint32_t x, uint32_t *dest) { - JS_ASSERT(dest != nullptr); + JS_ASSERT(dest != NULL); *dest = x; } @@ -585,7 +585,7 @@ case Assembler::LessThanOrEqual: return InstImm(op_blez, s, zero, BOffImm16(0)); default: - MOZ_ASSUME_UNREACHABLE("Condition not supported."); + JS_NOT_REACHED("Condition not supported."); } } @@ -1336,7 +1336,7 @@ inst[3] = InstNOP(); // Ensure everyone sees the code that was just written into memory. - AutoFlushICache::flush(uintptr_t(inst), patchWrite_NearCallSize()); + AutoFlushCache::updateTop(uintptr_t(inst), patchWrite_NearCallSize()); } uint32_t @@ -1371,8 +1371,8 @@ } void -Assembler::patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue, - PatchedImmPtr expectedValue) +Assembler::patchDataWithValueCheck(CodeLocationLabel label, ImmWord newValue, + ImmWord expectedValue) { Instruction *inst = (Instruction *) label.raw(); @@ -1383,14 +1383,7 @@ // Replace with new value Assembler::updateLuiOriValue(inst, inst->next(), uint32_t(newValue.value)); - AutoFlushICache::flush(uintptr_t(inst), 8); -} - -void -Assembler::patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, ImmPtr expectedValue) -{ - patchDataWithValueCheck(label, PatchedImmPtr(newValue.value), - PatchedImmPtr(expectedValue.value)); + AutoFlushCache::updateTop(uintptr_t(inst), 8); } // This just stomps over memory with 32 bits of raw data. Its purpose is to @@ -1412,7 +1405,7 @@ Assembler::nextInstruction(uint8_t *inst_, uint32_t *count) { Instruction *inst = reinterpret_cast<Instruction*>(inst_); - if (count != nullptr) + if (count != NULL) *count += sizeof(Instruction); return reinterpret_cast<uint8_t*>(inst->next()); } @@ -1457,7 +1450,7 @@ return branch; } - MOZ_ASSUME_UNREACHABLE("Error creating long branch."); + JS_NOT_REACHED("Error creating long branch."); return branch; case op_cop1: @@ -1472,7 +1465,7 @@ return branch; } - MOZ_ASSUME_UNREACHABLE("Error creating long branch."); + JS_NOT_REACHED("Error creating long branch."); return branch; } @@ -1485,7 +1478,7 @@ // We converted beq to andi, so now we restore it. inst->setOpcode(op_beq); - AutoFlushICache::flush(uintptr_t(inst), 4); + AutoFlushCache::updateTop(uintptr_t(inst), 4); } void @@ -1498,7 +1491,7 @@ // Replace "beq $zero, $zero, offset" with "andi $zero, $zero, offset" inst->setOpcode(op_andi); - AutoFlushICache::flush(uintptr_t(inst), 4); + AutoFlushCache::updateTop(uintptr_t(inst), 4); } void @@ -1520,10 +1513,12 @@ *i2 = nop; } - AutoFlushICache::flush(uintptr_t(i2), 4); + AutoFlushCache::updateTop(uintptr_t(i2), 4); } void Assembler::updateBoundsCheck(uint32_t heapSize, Instruction *inst) { - MOZ_ASSUME_UNREACHABLE("NYI"); + JS_NOT_REACHED("NYI"); } + +
diff --git a/src/third_party/mozjs/js/src/jit/mips/Assembler-mips.h b/src/third_party/mozjs/js/src/jit/mips/Assembler-mips.h index c5ce1f1..3514e2c 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Assembler-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/Assembler-mips.h
@@ -7,9 +7,11 @@ #ifndef jit_mips_Assembler_mips_h #define jit_mips_Assembler_mips_h -#include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" #include "mozilla/MathAlgorithms.h" +#include "mozilla/Util.h" + +#include "jit/shared/Assembler-shared.h" #include "jit/CompactBuffer.h" #include "jit/IonCode.h" @@ -21,59 +23,60 @@ namespace js { namespace jit { -static MOZ_CONSTEXPR_VAR Register zero = { Registers::zero }; -static MOZ_CONSTEXPR_VAR Register at = { Registers::at }; -static MOZ_CONSTEXPR_VAR Register v0 = { Registers::v0 }; -static MOZ_CONSTEXPR_VAR Register v1 = { Registers::v1 }; -static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 }; -static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 }; -static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 }; -static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 }; -static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 }; -static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 }; -static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 }; -static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 }; -static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 }; -static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 }; -static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 }; -static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 }; -static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 }; -static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 }; -static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 }; -static MOZ_CONSTEXPR_VAR Register s3 = { Registers::s3 }; -static MOZ_CONSTEXPR_VAR Register s4 = { Registers::s4 }; -static MOZ_CONSTEXPR_VAR Register s5 = { Registers::s5 }; -static MOZ_CONSTEXPR_VAR Register s6 = { Registers::s6 }; -static MOZ_CONSTEXPR_VAR Register s7 = { Registers::s7 }; -static MOZ_CONSTEXPR_VAR Register t8 = { Registers::t8 }; -static MOZ_CONSTEXPR_VAR Register t9 = { Registers::t9 }; -static MOZ_CONSTEXPR_VAR Register k0 = { Registers::k0 }; -static MOZ_CONSTEXPR_VAR Register k1 = { Registers::k1 }; -static MOZ_CONSTEXPR_VAR Register gp = { Registers::gp }; -static MOZ_CONSTEXPR_VAR Register sp = { Registers::sp }; -static MOZ_CONSTEXPR_VAR Register fp = { Registers::fp }; -static MOZ_CONSTEXPR_VAR Register ra = { Registers::ra }; +static const MOZ_CONSTEXPR Register zero = { Registers::zero }; +static const MOZ_CONSTEXPR Register at = { Registers::at }; +static const MOZ_CONSTEXPR Register v0 = { Registers::v0 }; +static const MOZ_CONSTEXPR Register v1 = { Registers::v1 }; +static const MOZ_CONSTEXPR Register a0 = { Registers::a0 }; +static const MOZ_CONSTEXPR Register a1 = { Registers::a1 }; +static const MOZ_CONSTEXPR Register a2 = { Registers::a2 }; +static const MOZ_CONSTEXPR Register a3 = { Registers::a3 }; +static const MOZ_CONSTEXPR Register t0 = { Registers::t0 }; +static const MOZ_CONSTEXPR Register t1 = { Registers::t1 }; +static const MOZ_CONSTEXPR Register t2 = { Registers::t2 }; +static const MOZ_CONSTEXPR Register t3 = { Registers::t3 }; +static const MOZ_CONSTEXPR Register t4 = { Registers::t4 }; +static const MOZ_CONSTEXPR Register t5 = { Registers::t5 }; +static const MOZ_CONSTEXPR Register t6 = { Registers::t6 }; +static const MOZ_CONSTEXPR Register t7 = { Registers::t7 }; +static const MOZ_CONSTEXPR Register s0 = { Registers::s0 }; +static const MOZ_CONSTEXPR Register s1 = { Registers::s1 }; +static const MOZ_CONSTEXPR Register s2 = { Registers::s2 }; +static const MOZ_CONSTEXPR Register s3 = { Registers::s3 }; +static const MOZ_CONSTEXPR Register s4 = { Registers::s4 }; +static const MOZ_CONSTEXPR Register s5 = { Registers::s5 }; +static const MOZ_CONSTEXPR Register s6 = { Registers::s6 }; +static const MOZ_CONSTEXPR Register s7 = { Registers::s7 }; +static const MOZ_CONSTEXPR Register t8 = { Registers::t8 }; +static const MOZ_CONSTEXPR Register t9 = { Registers::t9 }; +static const MOZ_CONSTEXPR Register k0 = { Registers::k0 }; +static const MOZ_CONSTEXPR Register k1 = { Registers::k1 }; +static const MOZ_CONSTEXPR Register gp = { Registers::gp }; +static const MOZ_CONSTEXPR Register sp = { Registers::sp }; +static const MOZ_CONSTEXPR Register fp = { Registers::fp }; +static const MOZ_CONSTEXPR Register ra = { Registers::ra }; -static MOZ_CONSTEXPR_VAR Register ScratchRegister = at; -static MOZ_CONSTEXPR_VAR Register SecondScratchReg = t8; +static const MOZ_CONSTEXPR Register ScratchRegister = at; +static const MOZ_CONSTEXPR Register SecondScratchReg = t8; // Use arg reg from EnterJIT function as OsrFrameReg. -static MOZ_CONSTEXPR_VAR Register OsrFrameReg = a3; -static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = s3; -static MOZ_CONSTEXPR_VAR Register CallTempReg0 = t0; -static MOZ_CONSTEXPR_VAR Register CallTempReg1 = t1; -static MOZ_CONSTEXPR_VAR Register CallTempReg2 = t2; -static MOZ_CONSTEXPR_VAR Register CallTempReg3 = t3; -static MOZ_CONSTEXPR_VAR Register CallTempReg4 = t4; -static MOZ_CONSTEXPR_VAR Register CallTempReg5 = t5; +static const MOZ_CONSTEXPR Register OsrFrameReg = a3; +static const MOZ_CONSTEXPR Register ArgumentsRectifierReg = s3; +static const MOZ_CONSTEXPR Register CallTempReg0 = t0; +static const MOZ_CONSTEXPR Register CallTempReg1 = t1; +static const MOZ_CONSTEXPR Register CallTempReg2 = t2; +static const MOZ_CONSTEXPR Register CallTempReg3 = t3; +static const MOZ_CONSTEXPR Register CallTempReg4 = t4; +static const MOZ_CONSTEXPR Register CallTempReg5 = t5; +static const MOZ_CONSTEXPR Register CallTempReg6 = t6; -static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0; -static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1; -static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2; -static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3; -static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin -static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin -static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { t0, t1, t2, t3, t4 }; +static const MOZ_CONSTEXPR Register IntArgReg0 = a0; +static const MOZ_CONSTEXPR Register IntArgReg1 = a1; +static const MOZ_CONSTEXPR Register IntArgReg2 = a2; +static const MOZ_CONSTEXPR Register IntArgReg3 = a3; +static const MOZ_CONSTEXPR Register GlobalReg = s6; // used by Odin +static const MOZ_CONSTEXPR Register HeapReg = s7; // used by Odin +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { t0, t1, t2, t3, t4 }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); class ABIArgGenerator @@ -98,38 +101,38 @@ static const Register NonArgReturnVolatileReg1; }; -static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1; +static const MOZ_CONSTEXPR Register PreBarrierReg = a1; -static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg }; -static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg }; +static const MOZ_CONSTEXPR Register InvalidReg = { Registers::invalid_reg }; +static const MOZ_CONSTEXPR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg }; -static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = v1; -static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = v0; -static MOZ_CONSTEXPR_VAR Register StackPointer = sp; -static MOZ_CONSTEXPR_VAR Register FramePointer = fp; -static MOZ_CONSTEXPR_VAR Register ReturnReg = v0; -static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::f0 }; -static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::f18 }; -static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloatReg = { FloatRegisters::f16 }; +static const MOZ_CONSTEXPR Register JSReturnReg_Type = v1; +static const MOZ_CONSTEXPR Register JSReturnReg_Data = v0; +static const MOZ_CONSTEXPR Register StackPointer = sp; +static const MOZ_CONSTEXPR Register FramePointer = fp; +static const MOZ_CONSTEXPR Register ReturnReg = v0; +static const MOZ_CONSTEXPR FloatRegister ReturnFloatReg = { FloatRegisters::f0 }; +static const MOZ_CONSTEXPR FloatRegister ScratchFloatReg = { FloatRegisters::f18 }; +static const MOZ_CONSTEXPR FloatRegister SecondScratchFloatReg = { FloatRegisters::f16 }; -static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::f30 }; +static const MOZ_CONSTEXPR FloatRegister NANReg = { FloatRegisters::f30 }; -static MOZ_CONSTEXPR_VAR FloatRegister f0 = {FloatRegisters::f0}; -static MOZ_CONSTEXPR_VAR FloatRegister f2 = {FloatRegisters::f2}; -static MOZ_CONSTEXPR_VAR FloatRegister f4 = {FloatRegisters::f4}; -static MOZ_CONSTEXPR_VAR FloatRegister f6 = {FloatRegisters::f6}; -static MOZ_CONSTEXPR_VAR FloatRegister f8 = {FloatRegisters::f8}; -static MOZ_CONSTEXPR_VAR FloatRegister f10 = {FloatRegisters::f10}; -static MOZ_CONSTEXPR_VAR FloatRegister f12 = {FloatRegisters::f12}; -static MOZ_CONSTEXPR_VAR FloatRegister f14 = {FloatRegisters::f14}; -static MOZ_CONSTEXPR_VAR FloatRegister f16 = {FloatRegisters::f16}; -static MOZ_CONSTEXPR_VAR FloatRegister f18 = {FloatRegisters::f18}; -static MOZ_CONSTEXPR_VAR FloatRegister f20 = {FloatRegisters::f20}; -static MOZ_CONSTEXPR_VAR FloatRegister f22 = {FloatRegisters::f22}; -static MOZ_CONSTEXPR_VAR FloatRegister f24 = {FloatRegisters::f24}; -static MOZ_CONSTEXPR_VAR FloatRegister f26 = {FloatRegisters::f26}; -static MOZ_CONSTEXPR_VAR FloatRegister f28 = {FloatRegisters::f28}; -static MOZ_CONSTEXPR_VAR FloatRegister f30 = {FloatRegisters::f30}; +static const MOZ_CONSTEXPR FloatRegister f0 = {FloatRegisters::f0}; +static const MOZ_CONSTEXPR FloatRegister f2 = {FloatRegisters::f2}; +static const MOZ_CONSTEXPR FloatRegister f4 = {FloatRegisters::f4}; +static const MOZ_CONSTEXPR FloatRegister f6 = {FloatRegisters::f6}; +static const MOZ_CONSTEXPR FloatRegister f8 = {FloatRegisters::f8}; +static const MOZ_CONSTEXPR FloatRegister f10 = {FloatRegisters::f10}; +static const MOZ_CONSTEXPR FloatRegister f12 = {FloatRegisters::f12}; +static const MOZ_CONSTEXPR FloatRegister f14 = {FloatRegisters::f14}; +static const MOZ_CONSTEXPR FloatRegister f16 = {FloatRegisters::f16}; +static const MOZ_CONSTEXPR FloatRegister f18 = {FloatRegisters::f18}; +static const MOZ_CONSTEXPR FloatRegister f20 = {FloatRegisters::f20}; +static const MOZ_CONSTEXPR FloatRegister f22 = {FloatRegisters::f22}; +static const MOZ_CONSTEXPR FloatRegister f24 = {FloatRegisters::f24}; +static const MOZ_CONSTEXPR FloatRegister f26 = {FloatRegisters::f26}; +static const MOZ_CONSTEXPR FloatRegister f28 = {FloatRegisters::f28}; +static const MOZ_CONSTEXPR FloatRegister f30 = {FloatRegisters::f30}; // MIPS CPUs can only load multibyte data that is "naturally" // four-byte-aligned, sp register should be eight-byte-aligned. @@ -371,9 +374,6 @@ ff_c_ule_fmt = 55, }; -class MacroAssemblerMIPS; -class Operand; - // A BOffImm16 is a 16 bit immediate that is used for branches. class BOffImm16 { @@ -565,7 +565,7 @@ class Assembler; typedef js::jit::AssemblerBuffer<1024, Instruction> MIPSBuffer; -class Assembler : public AssemblerShared +class Assembler { public: @@ -582,6 +582,7 @@ LessThanOrEqual, Overflow, Signed, + Unsigned, NotSigned, Zero, NonZero, @@ -647,7 +648,7 @@ public: uint32_t actualOffset(uint32_t) const; uint32_t actualIndex(uint32_t) const; - static uint8_t *PatchableJumpAddress(JitCode *code, uint32_t index); + static uint8_t *PatchableJumpAddress(IonCode *code, uint32_t index); protected: // structure for fixing up pc-relative loads/jumps when a the machine code @@ -724,12 +725,6 @@ void copyPreBarrierTable(uint8_t *dest); bool addCodeLabel(CodeLabel label); - size_t numCodeLabels() const { - return codeLabels_.length(); - } - CodeLabel codeLabel(size_t i) { - return codeLabels_[i]; - } // Size of the instruction stream, in bytes. size_t size() const; @@ -742,13 +737,13 @@ size_t bytesNeeded() const; // Write a blob of binary into the instruction stream *OR* - // into a destination address. If dest is nullptr (the default), then the + // into a destination address. If dest is NULL (the default), then the // instruction gets written into the instruction stream. If dest is not null // it is interpreted as a pointer to the location that we want the // instruction to be written. - BufferOffset writeInst(uint32_t x, uint32_t *dest = nullptr); + BufferOffset writeInst(uint32_t x, uint32_t *dest = NULL); // A static variant for the cases where we don't want to have an assembler - // object at all. Normally, you would use the dummy (nullptr) object. + // object at all. Normally, you would use the dummy (NULL) object. static void writeInstStatic(uint32_t x, uint32_t *dest); public: @@ -938,15 +933,15 @@ void as_break(uint32_t code); public: - static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader); - static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader); + static void TraceJumpRelocations(JSTracer *trc, IonCode *code, CompactBufferReader &reader); + static void TraceDataRelocations(JSTracer *trc, IonCode *code, CompactBufferReader &reader); protected: InstImm invertBranch(InstImm branch, BOffImm16 skipOffset); void bind(InstImm *inst, uint32_t branch, uint32_t target); - void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { - enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); - if (kind == Relocation::JITCODE) + void addPendingJump(BufferOffset src, void* target, Relocation::Kind kind) { + enoughMemory_ &= jumps_.append(RelativePatch(src, target, kind)); + if (kind == Relocation::IONCODE) writeRelocation(src); } @@ -978,16 +973,14 @@ Register reg, uint32_t value); static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall); - static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue, - PatchedImmPtr expectedValue); - static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, - ImmPtr expectedValue); + static void patchDataWithValueCheck(CodeLocationLabel label, ImmWord newValue, + ImmWord expectedValue); static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm); static uint32_t alignDoubleArg(uint32_t offset) { return (offset + 1U) &~ 1U; } - static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr); + static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = NULL); static void ToggleToJmp(CodeLocationLabel inst_); static void ToggleToCmp(CodeLocationLabel inst_); @@ -997,9 +990,6 @@ static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst); void processCodeLabels(uint8_t *rawCode); - bool bailed() { - return m_buffer.bail(); - } }; // Assembler // An Instruction is a structure for both encoding and decoding any and all @@ -1246,7 +1236,7 @@ { JS_ASSERT(usedArgSlots >= NumIntArgRegs); // Even register arguments have place reserved on stack. - return usedArgSlots * sizeof(intptr_t); + return usedArgSlots * STACK_SLOT_SIZE; } } // namespace jit
diff --git a/src/third_party/mozjs/js/src/jit/mips/Bailouts-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/Bailouts-mips.cpp index 4cde9d7..2d5364e 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Bailouts-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/Bailouts-mips.cpp
@@ -9,6 +9,10 @@ #include "jscntxt.h" #include "jscompartment.h" +#include "jit/Bailouts.h" +#include "jit/IonCompartment.h" +#include "jit/IonFrames-inl.h" + using namespace js; using namespace js::jit; @@ -21,7 +25,7 @@ uint8_t *fp = sp + bailout->frameSize(); current_ = fp; - type_ = JitFrame_IonJS; + type_ = IonFrame_OptimizedJS; topFrameSize_ = current_ - sp; topIonScript_ = script()->ionScript(); @@ -32,14 +36,19 @@ // Compute the snapshot offset from the bailout ID. JitActivation *activation = activations.activation()->asJit(); - JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); - JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); + + JSCompartment* jsCompartment = activation->compartment(); + + IonCompartment* ionCompartment = jsCompartment->ionCompartment(); + + IonCode* code = ionCompartment->getBailoutTable(bailout->frameClass()); + uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw()); - MOZ_ASSERT(tableOffset >= tableStart && + JS_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); - MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); + JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); @@ -57,7 +66,7 @@ const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_); current_ = (uint8_t*) bailout->fp(); - type_ = JitFrame_IonJS; + type_ = IonFrame_OptimizedJS; topFrameSize_ = current_ - bailout->sp(); snapshotOffset_ = osiIndex->snapshotOffset(); }
diff --git a/src/third_party/mozjs/js/src/jit/mips/Bailouts-mips.h b/src/third_party/mozjs/js/src/jit/mips/Bailouts-mips.h index dd14d1e..2f82a77 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Bailouts-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/Bailouts-mips.h
@@ -8,7 +8,6 @@ #define jit_mips_Bailouts_mips_h #include "jit/Bailouts.h" -#include "jit/JitCompartment.h" namespace js { namespace jit { @@ -26,8 +25,8 @@ }; protected: - mozilla::Array<double, FloatRegisters::Total> fpregs_; - mozilla::Array<uintptr_t, Registers::Total> regs_; + double fpregs_[FloatRegisters::Total]; + uintptr_t regs_[Registers::Total]; uintptr_t snapshotOffset_; uintptr_t padding_;
diff --git a/src/third_party/mozjs/js/src/jit/mips/BaselineCompiler-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/BaselineCompiler-mips.cpp index 69c935b..aa925a4 100644 --- a/src/third_party/mozjs/js/src/jit/mips/BaselineCompiler-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/BaselineCompiler-mips.cpp
@@ -9,8 +9,8 @@ using namespace js; using namespace js::jit; -BaselineCompilerMIPS::BaselineCompilerMIPS(JSContext *cx, TempAllocator &alloc, +BaselineCompilerMIPS::BaselineCompilerMIPS(JSContext *cx, HandleScript script) - : BaselineCompilerShared(cx, alloc, script) + : BaselineCompilerShared(cx, script) { }
diff --git a/src/third_party/mozjs/js/src/jit/mips/BaselineCompiler-mips.h b/src/third_party/mozjs/js/src/jit/mips/BaselineCompiler-mips.h index 7db49b3..e160900 100644 --- a/src/third_party/mozjs/js/src/jit/mips/BaselineCompiler-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/BaselineCompiler-mips.h
@@ -15,7 +15,7 @@ class BaselineCompilerMIPS : public BaselineCompilerShared { protected: - BaselineCompilerMIPS(JSContext *cx, TempAllocator &alloc, HandleScript script); + BaselineCompilerMIPS(JSContext *cx, HandleScript script); }; typedef BaselineCompilerMIPS BaselineCompilerSpecific;
diff --git a/src/third_party/mozjs/js/src/jit/mips/BaselineHelpers-mips.h b/src/third_party/mozjs/js/src/jit/mips/BaselineHelpers-mips.h index 565e8df..ea87db6 100644 --- a/src/third_party/mozjs/js/src/jit/mips/BaselineHelpers-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/BaselineHelpers-mips.h
@@ -79,7 +79,7 @@ } inline void -EmitTailCallVM(JitCode *target, MacroAssembler &masm, uint32_t argSize) +EmitTailCallVM(IonCode *target, MacroAssembler &masm, uint32_t argSize) { // We assume during this that R0 and R1 have been pushed, and that R2 is // unused. @@ -99,7 +99,7 @@ // keep it there through the stub calls), but the VMWrapper code being // called expects the return address to also be pushed on the stack. MOZ_ASSERT(BaselineTailCallReg == ra); - masm.makeFrameDescriptor(t6, JitFrame_BaselineJS); + masm.makeFrameDescriptor(t6, IonFrame_BaselineJS); masm.subPtr(Imm32(sizeof(IonCommonFrameLayout)), StackPointer); masm.storePtr(t6, Address(StackPointer, IonCommonFrameLayout::offsetOfDescriptor())); masm.storePtr(ra, Address(StackPointer, IonCommonFrameLayout::offsetOfReturnAddress())); @@ -116,11 +116,11 @@ masm.addPtr(Imm32(sizeof(intptr_t) * 2), reg); masm.subPtr(BaselineStackReg, reg); - masm.makeFrameDescriptor(reg, JitFrame_BaselineStub); + masm.makeFrameDescriptor(reg, IonFrame_BaselineStub); } inline void -EmitCallVM(JitCode *target, MacroAssembler &masm) +EmitCallVM(IonCode *target, MacroAssembler &masm) { EmitCreateStubFrameDescriptor(masm, t6); masm.push(t6); @@ -153,7 +153,7 @@ // BaselineStubFrame if needed. // Push frame descriptor and return address. - masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS); + masm.makeFrameDescriptor(scratch, IonFrame_BaselineJS); masm.subPtr(Imm32(STUB_FRAME_SIZE), StackPointer); masm.storePtr(scratch, Address(StackPointer, offsetof(BaselineStubFrame, descriptor))); masm.storePtr(BaselineTailCallReg, Address(StackPointer, @@ -241,7 +241,7 @@ } inline void -EmitCallTypeUpdateIC(MacroAssembler &masm, JitCode *code, uint32_t objectOffset) +EmitCallTypeUpdateIC(MacroAssembler &masm, IonCode *code, uint32_t objectOffset) { // R0 contains the value that needs to be typechecked. // The object we're updating is a boxed Value on the stack, at offset
diff --git a/src/third_party/mozjs/js/src/jit/mips/BaselineIC-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/BaselineIC-mips.cpp index 777f5a6..68a0a06 100644 --- a/src/third_party/mozjs/js/src/jit/mips/BaselineIC-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/BaselineIC-mips.cpp
@@ -178,7 +178,7 @@ } break; default: - MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_Int32."); + JS_NOT_REACHED("Unhandled op for BinaryArith_Int32."); } EmitReturnFromIC(masm); @@ -207,7 +207,7 @@ masm.neg32(R0.payloadReg()); break; default: - MOZ_ASSUME_UNREACHABLE("Unexpected op"); + JS_NOT_REACHED("Unexpected op"); return false; }
diff --git a/src/third_party/mozjs/js/src/jit/mips/BaselineRegisters-mips.h b/src/third_party/mozjs/js/src/jit/mips/BaselineRegisters-mips.h index 6ecdfea..2c93ed0 100644 --- a/src/third_party/mozjs/js/src/jit/mips/BaselineRegisters-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/BaselineRegisters-mips.h
@@ -14,31 +14,31 @@ namespace js { namespace jit { -static MOZ_CONSTEXPR_VAR Register BaselineFrameReg = s5; -static MOZ_CONSTEXPR_VAR Register BaselineStackReg = sp; +static const Register BaselineFrameReg = s5; +static const Register BaselineStackReg = sp; -static MOZ_CONSTEXPR_VAR ValueOperand R0(v1, v0); -static MOZ_CONSTEXPR_VAR ValueOperand R1(s7, s6); -static MOZ_CONSTEXPR_VAR ValueOperand R2(t7, t6); +static const ValueOperand R0(v1, v0); +static const ValueOperand R1(s7, s6); +static const ValueOperand R2(t7, t6); // BaselineTailCallReg and BaselineStubReg // These use registers that are not preserved across calls. -static MOZ_CONSTEXPR_VAR Register BaselineTailCallReg = ra; -static MOZ_CONSTEXPR_VAR Register BaselineStubReg = t5; +static const Register BaselineTailCallReg = ra; +static const Register BaselineStubReg = t5; -static MOZ_CONSTEXPR_VAR Register ExtractTemp0 = InvalidReg; -static MOZ_CONSTEXPR_VAR Register ExtractTemp1 = InvalidReg; +static const Register ExtractTemp0 = InvalidReg; +static const Register ExtractTemp1 = InvalidReg; // Register used internally by MacroAssemblerMIPS. -static MOZ_CONSTEXPR_VAR Register BaselineSecondScratchReg = SecondScratchReg; +static const Register BaselineSecondScratchReg = SecondScratchReg; // Note that BaselineTailCallReg is actually just the link register. // In MIPS code emission, we do not clobber BaselineTailCallReg since we keep // the return address for calls there. // FloatReg0 must be equal to ReturnFloatReg. -static MOZ_CONSTEXPR_VAR FloatRegister FloatReg0 = f0; -static MOZ_CONSTEXPR_VAR FloatRegister FloatReg1 = f2; +static const FloatRegister FloatReg0 = f0; +static const FloatRegister FloatReg1 = f2; } // namespace jit } // namespace js
diff --git a/src/third_party/mozjs/js/src/jit/mips/CodeGenerator-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/CodeGenerator-mips.cpp index fd9be18..5e5c085 100644 --- a/src/third_party/mozjs/js/src/jit/mips/CodeGenerator-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/CodeGenerator-mips.cpp
@@ -12,9 +12,10 @@ #include "jscompartment.h" #include "jsnum.h" +#include "jit/PerfSpewer.h" #include "jit/CodeGenerator.h" #include "jit/IonFrames.h" -#include "jit/JitCompartment.h" +#include "jit/IonCompartment.h" #include "jit/MIR.h" #include "jit/MIRGraph.h" #include "vm/Shape.h" @@ -23,16 +24,15 @@ #include "jit/shared/CodeGenerator-shared-inl.h" +#include "jit/MoveEmitter.h" + using namespace js; using namespace js::jit; -using mozilla::FloorLog2; -using mozilla::NegativeInfinity; -using JS::GenericNaN; - // shared CodeGeneratorMIPS::CodeGeneratorMIPS(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm) - : CodeGeneratorShared(gen, graph, masm) + : CodeGeneratorShared(gen, graph, masm), + deoptLabel_(NULL) { } @@ -49,13 +49,15 @@ masm.checkStackAlignment(); } + returnLabel_ = new HeapLabel(); + return true; } bool CodeGeneratorMIPS::generateEpilogue() { - masm.bind(&returnLabel_); + masm.bind(returnLabel_); #if JS_TRACE_LOGGING masm.tracelogStop(); #endif @@ -79,30 +81,7 @@ MBasicBlock *mir, Assembler::DoubleCondition cond) { Label *label = mir->lir()->label(); - if (Label *oolEntry = labelForBackedgeWithImplicitCheck(mir)) { - // Note: the backedge is initially a jump to the next instruction. - // It will be patched to the target block's label during link(). - RepatchLabel rejoin; - - CodeOffsetJump backedge; - Label skip; - if (fmt == Assembler::DoubleFloat) - masm.ma_bc1d(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); - else - masm.ma_bc1s(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); - - backedge = masm.jumpWithPatch(&rejoin); - masm.bind(&rejoin); - masm.bind(&skip); - - if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry))) - MOZ_CRASH(); - } else { - if (fmt == Assembler::DoubleFloat) - masm.branchDouble(cond, lhs, rhs, mir->lir()->label()); - else - masm.branchFloat(cond, lhs, rhs, mir->lir()->label()); - } + masm.branchDouble(cond, lhs, rhs, mir->lir()->label()); } bool @@ -143,7 +122,7 @@ bool CodeGeneratorMIPS::visitCompareAndBranch(LCompareAndBranch *comp) { - Assembler::Condition cond = JSOpToCondition(comp->cmpMir()->compareType(), comp->jsop()); + Assembler::Condition cond = JSOpToCondition(comp->mir()->compareType(), comp->jsop()); if (comp->right()->isConstant()) { emitBranch(ToRegister(comp->left()), Imm32(ToInt32(comp->right())), cond, comp->ifTrue(), comp->ifFalse()); @@ -164,9 +143,9 @@ if (!CodeGeneratorShared::generateOutOfLineCode()) return false; - if (deoptLabel_.used()) { + if (deoptLabel_) { // All non-table-based bailouts will go here. - masm.bind(&deoptLabel_); + masm.bind(deoptLabel_); // Push the frame size, so the handler can recover the IonScript. // Frame size is stored in 'ra' and pushed by GenerateBailoutThunk @@ -174,7 +153,9 @@ // the same. masm.move32(Imm32(frameSize()), ra); - JitCode *handler = gen->jitRuntime()->getGenericBailoutHandler(); + // IonCode *handler = gen->jitRuntime()->getGenericBailoutHandler(); + IonCompartment *ion = GetIonContext()->compartment->ionCompartment(); + IonCode *handler = ion->getGenericBailoutHandler(); masm.branch(handler); } @@ -185,16 +166,13 @@ bool CodeGeneratorMIPS::bailoutFrom(Label *label, LSnapshot *snapshot) { - if (masm.bailed()) - return false; - MOZ_ASSERT(label->used()); - MOZ_ASSERT(!label->bound()); + JS_ASSERT(label->used() && !label->bound()); CompileInfo &info = snapshot->mir()->block()->info(); switch (info.executionMode()) { case ParallelExecution: { // in parallel mode, make no attempt to recover, just signal an error. - OutOfLineAbortPar *ool = oolAbortPar(ParallelBailoutUnsupported, + OutOfLineParallelAbort* ool = oolParallelAbort(ParallelBailoutUnsupported, snapshot->mir()->block(), snapshot->mir()->pc()); masm.retarget(label, ool->entry()); @@ -203,7 +181,7 @@ case SequentialExecution: break; default: - MOZ_ASSUME_UNREACHABLE("No such execution mode"); + JS_NOT_REACHED("No such execution mode"); } if (!encode(snapshot)) @@ -212,11 +190,11 @@ // Though the assembler doesn't track all frame pushes, at least make sure // the known value makes sense. We can't use bailout tables if the stack // isn't properly aligned to the static frame size. - MOZ_ASSERT_IF(frameClass_ != FrameSizeClass::None(), + JS_ASSERT_IF(frameClass_ != FrameSizeClass::None(), frameClass_.frameSize() == masm.framePushed()); // We don't use table bailouts because retargeting is easier this way. - OutOfLineBailout *ool = new(alloc()) OutOfLineBailout(snapshot, masm.framePushed()); + OutOfLineBailout *ool = new OutOfLineBailout(snapshot, masm.framePushed()); if (!addOutOfLineCode(ool)) { return false; } @@ -237,11 +215,15 @@ bool CodeGeneratorMIPS::visitOutOfLineBailout(OutOfLineBailout *ool) { + if (!deoptLabel_) { + deoptLabel_ = new HeapLabel(); + } + // Push snapshotOffset and make sure stack is aligned. masm.subPtr(Imm32(2 * sizeof(void *)), StackPointer); masm.storePtr(ImmWord(ool->snapshot()->snapshotOffset()), Address(StackPointer, 0)); - masm.jump(&deoptLabel_); + masm.jump(deoptLabel_); return true; } @@ -284,7 +266,7 @@ masm.ma_b(&done, ShortJump); masm.bind(&nan); - masm.loadConstantDouble(GenericNaN(), output); + masm.loadStaticDouble(&js_NaN, output); masm.ma_b(&done, ShortJump); masm.bind(&returnSecond); @@ -304,15 +286,6 @@ } bool -CodeGeneratorMIPS::visitAbsF(LAbsF *ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - MOZ_ASSERT(input == ToFloatRegister(ins->output())); - masm.as_abss(input, input); - return true; -} - -bool CodeGeneratorMIPS::visitSqrtD(LSqrtD *ins) { FloatRegister input = ToFloatRegister(ins->input()); @@ -322,15 +295,6 @@ } bool -CodeGeneratorMIPS::visitSqrtF(LSqrtF *ins) -{ - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); - masm.as_sqrts(output, input); - return true; -} - -bool CodeGeneratorMIPS::visitAddI(LAddI *ins) { const LAllocation *lhs = ins->getOperand(0); @@ -437,7 +401,8 @@ } break; default: - uint32_t shift = FloorLog2(constant); + uint32_t shift; + JS_FLOOR_LOG2(shift, constant); if (!mul->canOverflow() && (constant > 0)) { // If it cannot overflow, we can do lots of optimizations. @@ -453,7 +418,9 @@ // If the constant cannot be encoded as (1<<C1), see if it can // be encoded as (1<<C1) | (1<<C2), which can be computed // using an add and a shift. - uint32_t shift_rest = FloorLog2(rest); + uint32_t shift_rest; + JS_FLOOR_LOG2(shift_rest, rest); + if (src != dest && (1u << shift_rest) == rest) { masm.ma_sll(dest, src, Imm32(shift - shift_rest)); masm.add32(src, dest); @@ -620,12 +587,6 @@ return false; } - if (!mir->canBeNegativeDividend()) { - // Numerator is unsigned, so needs no adjusting. Do the shift. - masm.ma_sra(dest, lhs, Imm32(shift)); - return true; - } - // Adjust the value so that shifting produces a correctly rounded result // when the numerator is negative. See 10-1 "Signed Division by a Known // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight. @@ -770,7 +731,7 @@ } if (mir->canBeNegativeDividend()) { if (!mir->isTruncated()) { - MOZ_ASSERT(mir->fallible()); + JS_ASSERT(mir->fallible()); if (!bailoutCmp32(Assembler::Equal, out, zero, ins->snapshot())) return false; } else { @@ -787,20 +748,22 @@ Register src = ToRegister(ins->getOperand(0)); Register dest = ToRegister(ins->getDef(0)); Register tmp = ToRegister(ins->getTemp(0)); + MMod *mir = ins->mir(); if (!mir->isTruncated() && mir->canBeNegativeDividend()) { - MOZ_ASSERT(mir->fallible()); + JS_ASSERT(mir->fallible()); Label bail; masm.ma_mod_mask(src, dest, tmp, ins->shift(), &bail); if (!bailoutFrom(&bail, ins->snapshot())) return false; } else { - masm.ma_mod_mask(src, dest, tmp, ins->shift(), nullptr); + masm.ma_mod_mask(src, dest, tmp, ins->shift(), NULL); } return true; } + bool CodeGeneratorMIPS::visitBitNotI(LBitNotI *ins) { @@ -839,7 +802,7 @@ masm.ma_and(ToRegister(dest), ToRegister(lhs), ToRegister(rhs)); break; default: - MOZ_ASSUME_UNREACHABLE("unexpected binary opcode"); + JS_NOT_REACHED("unexpected binary opcode"); } return true; @@ -880,7 +843,7 @@ } break; default: - MOZ_ASSUME_UNREACHABLE("Unexpected shift op"); + JS_NOT_REACHED("Unexpected shift op"); } } else { // The shift amounts should be AND'ed into the 0-31 range @@ -902,7 +865,7 @@ } break; default: - MOZ_ASSUME_UNREACHABLE("Unexpected shift op"); + JS_NOT_REACHED("Unexpected shift op"); } } @@ -937,7 +900,7 @@ Label done, skip; // Masm.pow(-Infinity, 0.5) == Infinity. - masm.loadConstantDouble(NegativeInfinity<double>(), ScratchFloatReg); + masm.loadConstantDouble(js_NegativeInfinity, ScratchFloatReg); masm.ma_bc1d(input, ScratchFloatReg, &skip, Assembler::DoubleNotEqualOrUnordered, ShortJump); masm.as_negd(output, ScratchFloatReg); masm.ma_b(&done, ShortJump); @@ -953,6 +916,8 @@ return true; } +typedef MoveResolver::MoveOperand MoveOperand; + MoveOperand CodeGeneratorMIPS::toMoveOperand(const LAllocation *a) const { @@ -1041,7 +1006,7 @@ // To fill in the CodeLabels for the case entries, we need to first // generate the case entries (we don't yet know their offsets in the // instruction stream). - OutOfLineTableSwitch *ool = new(alloc()) OutOfLineTableSwitch(mir); + OutOfLineTableSwitch *ool = new OutOfLineTableSwitch(mir); if (!addOutOfLineCode(ool)) return false; @@ -1075,33 +1040,7 @@ masm.as_divd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); break; default: - MOZ_ASSUME_UNREACHABLE("unexpected opcode"); - } - return true; -} - -bool -CodeGeneratorMIPS::visitMathF(LMathF *math) -{ - const LAllocation *src1 = math->getOperand(0); - const LAllocation *src2 = math->getOperand(1); - const LDefinition *output = math->getDef(0); - - switch (math->jsop()) { - case JSOP_ADD: - masm.as_adds(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_SUB: - masm.as_subs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_MUL: - masm.as_muls(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - case JSOP_DIV: - masm.as_divs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2)); - break; - default: - MOZ_ASSUME_UNREACHABLE("unexpected opcode"); + JS_NOT_REACHED("unexpected opcode"); } return true; } @@ -1144,43 +1083,6 @@ } bool -CodeGeneratorMIPS::visitFloorF(LFloorF *lir) -{ - FloatRegister input = ToFloatRegister(lir->input()); - FloatRegister scratch = ScratchFloatReg; - Register output = ToRegister(lir->output()); - - Label skipCheck, done; - - // If Nan, 0 or -0 check for bailout - masm.loadConstantFloat32(0.0, scratch); - masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); - - // If binary value is not zero, it is NaN or -0, so we bail. - masm.moveFromDoubleLo(input, SecondScratchReg); - if (!bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot())) - return false; - - // Input was zero, so return zero. - masm.move32(Imm32(0), output); - masm.ma_b(&done, ShortJump); - - masm.bind(&skipCheck); - masm.as_floorws(scratch, input); - masm.moveFromDoubleLo(scratch, output); - - if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot())) - return false; - - if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot())) - return false; - - masm.bind(&done); - - return true; -} - -bool CodeGeneratorMIPS::visitRound(LRound *lir) { FloatRegister input = ToFloatRegister(lir->input()); @@ -1247,83 +1149,11 @@ } bool -CodeGeneratorMIPS::visitRoundF(LRoundF *lir) -{ - FloatRegister input = ToFloatRegister(lir->input()); - FloatRegister temp = ToFloatRegister(lir->temp()); - FloatRegister scratch = ScratchFloatReg; - Register output = ToRegister(lir->output()); - - Label bail, negative, end, skipCheck; - - // Load 0.5 in the temp register. - masm.loadConstantFloat32(0.5, temp); - - // Branch to a slow path for negative inputs. Doesn't catch NaN or -0. - masm.loadConstantFloat32(0.0, scratch); - masm.ma_bc1s(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump); - - // If Nan, 0 or -0 check for bailout - masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump); - - // If binary value is not zero, it is NaN or -0, so we bail. - masm.moveFromFloat32(input, SecondScratchReg); - if (!bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot())) - return false; - - // Input was zero, so return zero. - masm.move32(Imm32(0), output); - masm.ma_b(&end, ShortJump); - - masm.bind(&skipCheck); - masm.loadConstantFloat32(0.5, scratch); - masm.as_adds(scratch, input, scratch); - masm.as_floorws(scratch, scratch); - - masm.moveFromFloat32(scratch, output); - - if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot())) - return false; - - if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot())) - return false; - - masm.jump(&end); - - // Input is negative, but isn't -0. - masm.bind(&negative); - masm.as_adds(temp, input, temp); - - // If input + 0.5 >= 0, input is a negative number >= -0.5 and the - // result is -0. - masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail); - if (!bailoutFrom(&bail, lir->snapshot())) - return false; - - // Truncate and round toward zero. - // This is off-by-one for everything but integer-valued inputs. - masm.as_floorws(scratch, temp); - masm.moveFromFloat32(scratch, output); - - if (!bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot())) - return false; - - masm.bind(&end); - return true; -} - -bool CodeGeneratorMIPS::visitTruncateDToInt32(LTruncateDToInt32 *ins) { return emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output())); } -bool -CodeGeneratorMIPS::visitTruncateFToInt32(LTruncateFToInt32 *ins) -{ - return emitTruncateFloat32(ToFloatRegister(ins->input()), ToRegister(ins->output())); -} - static const uint32_t FrameSizes[] = { 128, 256, 512, 1024 }; FrameSizeClass @@ -1400,22 +1230,6 @@ } bool -CodeGeneratorMIPS::visitBoxFloatingPoint(LBoxFloatingPoint *box) -{ - const LDefinition *payload = box->getDef(PAYLOAD_INDEX); - const LDefinition *type = box->getDef(TYPE_INDEX); - const LAllocation *in = box->getOperand(0); - - FloatRegister reg = ToFloatRegister(in); - if (box->type() == MIRType_Float32) { - masm.convertFloat32ToDouble(reg, ScratchFloatReg); - reg = ScratchFloatReg; - } - masm.ma_mv(reg, ValueOperand(ToRegister(type), ToRegister(payload))); - return true; -} - -bool CodeGeneratorMIPS::visitUnbox(LUnbox *unbox) { // Note that for unbox, the type and payload indexes are switched on the @@ -1440,14 +1254,6 @@ return true; } -bool -CodeGeneratorMIPS::visitFloat32(LFloat32 *ins) -{ - const LDefinition *out = ins->getDef(0); - masm.loadConstantFloat32(ins->getFloat(), ToFloatRegister(out)); - return true; -} - Register CodeGeneratorMIPS::splitTagForTest(const ValueOperand &value) { @@ -1478,29 +1284,6 @@ } bool -CodeGeneratorMIPS::visitTestFAndBranch(LTestFAndBranch *test) -{ - FloatRegister input = ToFloatRegister(test->input()); - - MBasicBlock *ifTrue = test->ifTrue(); - MBasicBlock *ifFalse = test->ifFalse(); - - masm.loadConstantFloat32(0.0, ScratchFloatReg); - // If 0, or NaN, the result is false. - - if (isNextBlock(ifFalse->lir())) { - branchToBlock(Assembler::SingleFloat, input, ScratchFloatReg, ifTrue, - Assembler::DoubleNotEqual); - } else { - branchToBlock(Assembler::SingleFloat, input, ScratchFloatReg, ifFalse, - Assembler::DoubleEqualOrUnordered); - jumpToBlock(ifTrue); - } - - return true; -} - -bool CodeGeneratorMIPS::visitCompareD(LCompareD *comp) { FloatRegister lhs = ToFloatRegister(comp->left()); @@ -1513,19 +1296,6 @@ } bool -CodeGeneratorMIPS::visitCompareF(LCompareF *comp) -{ - FloatRegister lhs = ToFloatRegister(comp->left()); - FloatRegister rhs = ToFloatRegister(comp->right()); - Register dest = ToRegister(comp->output()); - - Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop()); - masm.ma_cmp_set_float32(dest, lhs, rhs, cond); - return true; -} - - -bool CodeGeneratorMIPS::visitCompareDAndBranch(LCompareDAndBranch *comp) { FloatRegister lhs = ToFloatRegister(comp->left()); @@ -1547,27 +1317,6 @@ } bool -CodeGeneratorMIPS::visitCompareFAndBranch(LCompareFAndBranch *comp) -{ - FloatRegister lhs = ToFloatRegister(comp->left()); - FloatRegister rhs = ToFloatRegister(comp->right()); - - Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop()); - MBasicBlock *ifTrue = comp->ifTrue(); - MBasicBlock *ifFalse = comp->ifFalse(); - - if (isNextBlock(ifFalse->lir())) { - branchToBlock(Assembler::SingleFloat, lhs, rhs, ifTrue, cond); - } else { - branchToBlock(Assembler::SingleFloat, lhs, rhs, ifFalse, - Assembler::InvertCondition(cond)); - jumpToBlock(ifTrue); - } - - return true; -} - -bool CodeGeneratorMIPS::visitCompareB(LCompareB *lir) { MCompare *mir = lir->mir(); @@ -1601,7 +1350,7 @@ bool CodeGeneratorMIPS::visitCompareBAndBranch(LCompareBAndBranch *lir) { - MCompare *mir = lir->cmpMir(); + MCompare *mir = lir->mir(); const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs); const LAllocation *rhs = lir->rhs(); @@ -1649,7 +1398,7 @@ bool CodeGeneratorMIPS::visitCompareVAndBranch(LCompareVAndBranch *lir) { - MCompare *mir = lir->cmpMir(); + MCompare *mir = lir->mir(); Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop()); const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput); const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput); @@ -1666,32 +1415,13 @@ } bool -CodeGeneratorMIPS::visitBitAndAndBranch(LBitAndAndBranch *lir) -{ - if (lir->right()->isConstant()) - masm.ma_and(ScratchRegister, ToRegister(lir->left()), Imm32(ToInt32(lir->right()))); - else - masm.ma_and(ScratchRegister, ToRegister(lir->left()), ToRegister(lir->right())); - emitBranch(ScratchRegister, ScratchRegister, Assembler::NonZero, lir->ifTrue(), - lir->ifFalse()); - return true; -} - -bool -CodeGeneratorMIPS::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble *lir) +CodeGeneratorMIPS::visitUInt32ToDouble(LUInt32ToDouble *lir) { masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output())); return true; } bool -CodeGeneratorMIPS::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32 *lir) -{ - masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output())); - return true; -} - -bool CodeGeneratorMIPS::visitNotI(LNotI *ins) { masm.cmp32Set(Assembler::Equal, ToRegister(ins->input()), Imm32(0), @@ -1722,28 +1452,6 @@ } bool -CodeGeneratorMIPS::visitNotF(LNotF *ins) -{ - // Since this operation is not, we want to set a bit if - // the float32 is falsey, which means 0.0, -0.0 or NaN. - FloatRegister in = ToFloatRegister(ins->input()); - Register dest = ToRegister(ins->output()); - - Label falsey, done; - masm.loadConstantFloat32(0.0, ScratchFloatReg); - masm.ma_bc1s(in, ScratchFloatReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump); - - masm.move32(Imm32(0), dest); - masm.ma_b(&done, ShortJump); - - masm.bind(&falsey); - masm.move32(Imm32(1), dest); - - masm.bind(&done); - return true; -} - -bool CodeGeneratorMIPS::visitLoadSlotV(LLoadSlotV *load) { const ValueOperand out = ToOutValue(load); @@ -1925,19 +1633,8 @@ return true; } -bool -CodeGeneratorMIPS::visitInterruptCheck(LInterruptCheck *lir) -{ - OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing()); - if (!ool) - return false; - - masm.branch32(Assembler::NotEqual, - AbsoluteAddress(GetIonContext()->runtime->addressOfInterrupt()), Imm32(0), - ool->entry()); - masm.bind(ool->rejoin()); - return true; -} +typedef bool (*InterruptCheckFn)(JSContext *); +static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck); bool CodeGeneratorMIPS::generateInvalidateEpilogue() @@ -1956,122 +1653,26 @@ // Push the Ion script onto the stack (when we determine what that // pointer is). invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1))); - JitCode *thunk = gen->jitRuntime()->getInvalidationThunk(); + IonCode* thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk(); masm.branch(thunk); // We should never reach this point in JIT code -- the invalidation thunk // should pop the invalidated JS frame and return directly to its caller. - masm.assumeUnreachable("Should have returned directly to its caller instead of here."); + // masm.assumeUnreachable("Should have returned directly to its caller instead of here."); + masm.breakpoint(); return true; } void -DispatchIonCache::initializeAddCacheState(LInstruction *ins, AddCacheState *addState) +ParallelGetPropertyIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState) { - // Can always use the scratch register on MIPS. + // Can always use the scratch register on ARM. + JS_ASSERT(ins->isGetPropertyCacheV() || ins->isGetPropertyCacheT()); addState->dispatchScratch = ScratchRegister; } bool -CodeGeneratorMIPS::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins) -{ - MOZ_ASSUME_UNREACHABLE("NYI"); -} - -bool -CodeGeneratorMIPS::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins) -{ - MOZ_ASSUME_UNREACHABLE("NYI"); -} - -bool -CodeGeneratorMIPS::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins) -{ - const MAsmJSLoadHeap *mir = ins->mir(); - const LAllocation *ptr = ins->ptr(); - const LDefinition *out = ins->output(); - - bool isSigned; - int size; - bool isFloat = false; - switch (mir->viewType()) { - case ArrayBufferView::TYPE_INT8: isSigned = true; size = 8; break; - case ArrayBufferView::TYPE_UINT8: isSigned = false; size = 8; break; - case ArrayBufferView::TYPE_INT16: isSigned = true; size = 16; break; - case ArrayBufferView::TYPE_UINT16: isSigned = false; size = 16; break; - case ArrayBufferView::TYPE_INT32: isSigned = true; size = 32; break; - case ArrayBufferView::TYPE_UINT32: isSigned = false; size = 32; break; - case ArrayBufferView::TYPE_FLOAT64: isFloat = true; size = 64; break; - case ArrayBufferView::TYPE_FLOAT32: isFloat = true; size = 32; break; - default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); - } - - if (ptr->isConstant()) { - MOZ_ASSERT(mir->skipBoundsCheck()); - int32_t ptrImm = ptr->toConstant()->toInt32(); - MOZ_ASSERT(ptrImm >= 0); - if (isFloat) { - if (size == 32) { - masm.loadFloat32(Address(HeapReg, ptrImm), ToFloatRegister(out)); - } else { - masm.loadDouble(Address(HeapReg, ptrImm), ToFloatRegister(out)); - } - } else { - masm.ma_load(ToRegister(out), Address(HeapReg, ptrImm), - static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend); - } - return true; - } - - Register ptrReg = ToRegister(ptr); - - if (mir->skipBoundsCheck()) { - if (isFloat) { - if (size == 32) { - masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); - } else { - masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); - } - } else { - masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne), - static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend); - } - return true; - } - - BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister); - - Label outOfRange; - Label done; - masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump); - // Offset is ok, let's load value. - if (isFloat) { - if (size == 32) - masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); - else - masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); - } else { - masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne), - static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend); - } - masm.ma_b(&done, ShortJump); - masm.bind(&outOfRange); - // Offset is out of range. Load default values. - if (isFloat) { - if (size == 32) - masm.convertDoubleToFloat32(NANReg, ToFloatRegister(out)); - else - masm.moveDouble(NANReg, ToFloatRegister(out)); - } else { - masm.move32(Imm32(0), ToRegister(out)); - } - masm.bind(&done); - - return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset())); -} - -bool CodeGeneratorMIPS::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins) { const MAsmJSStoreHeap *mir = ins->mir(); @@ -2090,17 +1691,16 @@ case ArrayBufferView::TYPE_UINT32: isSigned = false; size = 32; break; case ArrayBufferView::TYPE_FLOAT64: isFloat = true; size = 64; break; case ArrayBufferView::TYPE_FLOAT32: isFloat = true; size = 32; break; - default: MOZ_ASSUME_UNREACHABLE("unexpected array type"); + default: JS_NOT_REACHED("unexpected array type"); } if (ptr->isConstant()) { - MOZ_ASSERT(mir->skipBoundsCheck()); int32_t ptrImm = ptr->toConstant()->toInt32(); MOZ_ASSERT(ptrImm >= 0); if (isFloat) { if (size == 32) { - masm.storeFloat32(ToFloatRegister(value), Address(HeapReg, ptrImm)); + JS_NOT_REACHED("No 32-bit floats in SpiderMonkey 24."); } else { masm.storeDouble(ToFloatRegister(value), Address(HeapReg, ptrImm)); } @@ -2114,18 +1714,16 @@ Register ptrReg = ToRegister(ptr); Address dstAddr(ptrReg, 0); - if (mir->skipBoundsCheck()) { - if (isFloat) { - if (size == 32) { - masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); - } else - masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); - } else { - masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne), - static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend); - } - return true; + if (isFloat) { + if (size == 32) { + JS_NOT_REACHED("No 32-bit floats in SpiderMonkey 24."); + } else + masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); + } else { + masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne), + static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend); } + return true; BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister); @@ -2135,7 +1733,7 @@ // Offset is ok, let's store value. if (isFloat) { if (size == 32) { - masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); + JS_NOT_REACHED("No 32-bit floats in SM42."); } else masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne)); } else { @@ -2253,8 +1851,6 @@ unsigned addr = mir->globalDataOffset(); if (mir->type() == MIRType_Int32) masm.load32(Address(GlobalReg, addr), ToRegister(ins->output())); - else if (mir->type() == MIRType_Float32) - masm.loadFloat32(Address(GlobalReg, addr), ToFloatRegister(ins->output())); else masm.loadDouble(Address(GlobalReg, addr), ToFloatRegister(ins->output())); return true; @@ -2270,8 +1866,6 @@ unsigned addr = mir->globalDataOffset(); if (mir->value()->type() == MIRType_Int32) masm.store32(ToRegister(ins->value()), Address(GlobalReg, addr)); - else if (mir->value()->type() == MIRType_Float32) - masm.storeFloat32(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); else masm.storeDouble(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); return true; @@ -2321,23 +1915,152 @@ } bool -CodeGeneratorMIPS::visitNegF(LNegF *ins) +CodeGeneratorMIPS::visitOsrValue(LOsrValue *value) { - FloatRegister input = ToFloatRegister(ins->input()); - FloatRegister output = ToFloatRegister(ins->output()); + const LAllocation *frame = value->getOperand(0); + const ValueOperand out = ToOutValue(value); - masm.as_negs(output, input); + const ptrdiff_t frameOffset = value->mir()->frameOffset(); + + masm.loadValue(Address(ToRegister(frame), frameOffset), out); return true; } bool -CodeGeneratorMIPS::visitForkJoinGetSlice(LForkJoinGetSlice *ins) +CodeGeneratorMIPS::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins) { - MOZ_ASSUME_UNREACHABLE("NYI"); + JS_NOT_REACHED("NYI"); } -JitCode * -JitRuntime::generateForkJoinGetSliceStub(JSContext *cx) +bool +CodeGeneratorMIPS::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins) { - MOZ_ASSUME_UNREACHABLE("NYI"); + JS_NOT_REACHED("NYI"); } + + +bool +CodeGeneratorMIPS::visitInterruptCheck(LInterruptCheck *lir) +{ + OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing()); + if (!ool) + return false; + + masm.branch32(Assembler::NotEqual, + AbsoluteAddress((void*)&gen->compartment->rt->interrupt), Imm32(0), + ool->entry()); + masm.bind(ool->rejoin()); + return true; +} + +bool +CodeGeneratorMIPS::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins) +{ + const MAsmJSLoadHeap *mir = ins->mir(); + const LAllocation *ptr = ins->ptr(); + const LDefinition *out = ins->output(); + + bool isSigned; + int size; + bool isFloat = false; + switch (mir->viewType()) { + case ArrayBufferView::TYPE_INT8: isSigned = true; size = 8; break; + case ArrayBufferView::TYPE_UINT8: isSigned = false; size = 8; break; + case ArrayBufferView::TYPE_INT16: isSigned = true; size = 16; break; + case ArrayBufferView::TYPE_UINT16: isSigned = false; size = 16; break; + case ArrayBufferView::TYPE_INT32: isSigned = true; size = 32; break; + case ArrayBufferView::TYPE_UINT32: isSigned = false; size = 32; break; + case ArrayBufferView::TYPE_FLOAT64: isFloat = true; size = 64; break; + case ArrayBufferView::TYPE_FLOAT32: isFloat = true; size = 32; break; + default: JS_NOT_REACHED("unexpected array type"); + } + + if (ptr->isConstant()) { + int32_t ptrImm = ptr->toConstant()->toInt32(); + MOZ_ASSERT(ptrImm >= 0); + if (isFloat) { + masm.loadDouble(Address(HeapReg, ptrImm), ToFloatRegister(out)); + } else { + masm.ma_load(ToRegister(out), Address(HeapReg, ptrImm), + static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend); + } + return true; + } + + Register ptrReg = ToRegister(ptr); + + BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister); + + Label outOfRange; + Label done; + masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump); + // Offset is ok, let's load value. + if (isFloat) { + if (size == 32) + JS_NOT_REACHED("No 32-bit floats in SpiderMonkey 24."); + else + masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out)); + } else { + masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne), + static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend); + } + masm.ma_b(&done, ShortJump); + masm.bind(&outOfRange); + // Offset is out of range. Load default values. + if (isFloat) { + masm.moveDouble(NANReg, ToFloatRegister(out)); + } else { + masm.move32(Imm32(0), ToRegister(out)); + } + masm.bind(&done); + + return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset())); +} + +bool +CodeGeneratorMIPS::visitBoxDouble(LBoxDouble* box) +{ + const LDefinition *payload = box->getDef(PAYLOAD_INDEX); + const LDefinition *type = box->getDef(TYPE_INDEX); + const LAllocation *in = box->getOperand(0); + + FloatRegister reg = ToFloatRegister(in); + masm.ma_mv(reg, ValueOperand(ToRegister(type), ToRegister(payload))); + return true; +} + +bool +CodeGeneratorMIPS::visitMoveGroup(LMoveGroup *group) +{ + if (!group->numMoves()) + return true; + + MoveResolver &resolver = masm.moveResolver(); + + for (size_t i = 0; i < group->numMoves(); i++) { + const LMove &move = group->getMove(i); + + const LAllocation *from = move.from(); + const LAllocation *to = move.to(); + + // No bogus moves. + JS_ASSERT(*from != *to); + JS_ASSERT(!from->isConstant()); + JS_ASSERT(from->isDouble() == to->isDouble()); + + MoveResolver::Move::Kind kind = from->isDouble() ? MoveResolver::Move::DOUBLE : MoveResolver::Move::GENERAL; + + if (!resolver.addMove(toMoveOperand(from), toMoveOperand(to), kind)) + return false; + } + + if (!resolver.resolve()) + return false; + + MoveEmitter emitter(masm); + emitter.emit(resolver); + emitter.finish(); + + return true; +} +
diff --git a/src/third_party/mozjs/js/src/jit/mips/CodeGenerator-mips.h b/src/third_party/mozjs/js/src/jit/mips/CodeGenerator-mips.h index 95933a4..43b7ecd 100644 --- a/src/third_party/mozjs/js/src/jit/mips/CodeGenerator-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/CodeGenerator-mips.h
@@ -26,8 +26,8 @@ protected: // Label for the common return path. - NonAssertingLabel returnLabel_; - NonAssertingLabel deoptLabel_; + HeapLabel *returnLabel_; + HeapLabel *deoptLabel_; inline Address ToAddress(const LAllocation &a) { MOZ_ASSERT(a.isMemory()); @@ -70,7 +70,7 @@ return ToOperand(def->output()); } - MoveOperand toMoveOperand(const LAllocation *a) const; + MoveResolver::MoveOperand toMoveOperand(const LAllocation* a) const; template <typename T1, typename T2> bool bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) { @@ -87,7 +87,7 @@ return bailoutCmp32(c, lhs.toReg(), rhs, snapshot); if (lhs.getTag() == Operand::MEM) return bailoutCmp32(c, lhs.toAddress(), rhs, snapshot); - MOZ_ASSUME_UNREACHABLE("Invalid operand tag."); + MOZ_NOT_REACHED("Invalid operand tag."); return false; } template<typename T> @@ -114,30 +114,28 @@ bool generateEpilogue(); bool generateOutOfLineCode(); + void branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, + MBasicBlock *mir, Assembler::DoubleCondition cond); + + // Generate a jump to the start of the specified block, adding information + // if this is a loop backedge. Use this in place of jumping directly to + // mir->lir()->label(), or use getJumpLabelForBranch() if a label to use + // directly is needed. + void jumpToBlock(MBasicBlock *mir) { + // No jump necessary if we can fall through to the next block. + if (isNextBlock(mir->lir())) { + return; + } + + masm.jump(mir->lir()->label()); + } + template <typename T> void branchToBlock(Register lhs, T rhs, MBasicBlock *mir, Assembler::Condition cond) { Label *label = mir->lir()->label(); - if (Label *oolEntry = labelForBackedgeWithImplicitCheck(mir)) { - // Note: the backedge is initially a jump to the next instruction. - // It will be patched to the target block's label during link(). - RepatchLabel rejoin; - CodeOffsetJump backedge; - Label skip; - - masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); - backedge = masm.jumpWithPatch(&rejoin); - masm.bind(&rejoin); - masm.bind(&skip); - - if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry))) - MOZ_CRASH(); - } else { - masm.ma_b(lhs, rhs, label, cond); - } + masm.ma_b(lhs, rhs, label, cond); } - void branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, - MBasicBlock *mir, Assembler::DoubleCondition cond); // Emits a branch that directs control flow to the true block if |cond| is // true, and the false block if |cond| is false. @@ -152,6 +150,7 @@ jumpToBlock(mirTrue); } } + void testNullEmitBranch(Assembler::Condition cond, const ValueOperand &value, MBasicBlock *ifTrue, MBasicBlock *ifFalse) { @@ -169,9 +168,7 @@ // Instruction visitors. virtual bool visitMinMaxD(LMinMaxD *ins); virtual bool visitAbsD(LAbsD *ins); - virtual bool visitAbsF(LAbsF *ins); virtual bool visitSqrtD(LSqrtD *ins); - virtual bool visitSqrtF(LSqrtF *ins); virtual bool visitAddI(LAddI *ins); virtual bool visitSubI(LSubI *ins); virtual bool visitBitNotI(LBitNotI *ins); @@ -192,30 +189,20 @@ virtual bool visitCompare(LCompare *comp); virtual bool visitCompareAndBranch(LCompareAndBranch *comp); virtual bool visitTestDAndBranch(LTestDAndBranch *test); - virtual bool visitTestFAndBranch(LTestFAndBranch *test); virtual bool visitCompareD(LCompareD *comp); - virtual bool visitCompareF(LCompareF *comp); virtual bool visitCompareDAndBranch(LCompareDAndBranch *comp); - virtual bool visitCompareFAndBranch(LCompareFAndBranch *comp); virtual bool visitCompareB(LCompareB *lir); virtual bool visitCompareBAndBranch(LCompareBAndBranch *lir); virtual bool visitCompareV(LCompareV *lir); virtual bool visitCompareVAndBranch(LCompareVAndBranch *lir); - virtual bool visitBitAndAndBranch(LBitAndAndBranch *lir); - virtual bool visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble *lir); - virtual bool visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32 *lir); + virtual bool visitUInt32ToDouble(LUInt32ToDouble *lir); virtual bool visitNotI(LNotI *ins); virtual bool visitNotD(LNotD *ins); - virtual bool visitNotF(LNotF *ins); virtual bool visitMathD(LMathD *math); - virtual bool visitMathF(LMathF *math); virtual bool visitFloor(LFloor *lir); - virtual bool visitFloorF(LFloorF *lir); virtual bool visitRound(LRound *lir); - virtual bool visitRoundF(LRoundF *lir); virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins); - virtual bool visitTruncateFToInt32(LTruncateFToInt32 *ins); // Out of line visitors. bool visitOutOfLineBailout(OutOfLineBailout *ool); @@ -237,11 +224,11 @@ public: bool visitBox(LBox *box); - bool visitBoxFloatingPoint(LBoxFloatingPoint *box); + bool visitBoxDouble(LBoxDouble *box); bool visitUnbox(LUnbox *unbox); bool visitValue(LValue *value); + bool visitOsrValue(LOsrValue *value); bool visitDouble(LDouble *ins); - bool visitFloat32(LFloat32 *ins); bool visitLoadSlotV(LLoadSlotV *load); bool visitLoadSlotT(LLoadSlotT *load); @@ -258,7 +245,6 @@ bool visitNegI(LNegI *lir); bool visitNegD(LNegD *lir); - bool visitNegF(LNegF *lir); bool visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins); bool visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins); bool visitAsmJSLoadHeap(LAsmJSLoadHeap *ins); @@ -270,8 +256,6 @@ bool visitAsmJSPassStackArg(LAsmJSPassStackArg *ins); - bool visitForkJoinGetSlice(LForkJoinGetSlice *ins); - bool generateInvalidateEpilogue(); protected: void postAsmJSCall(LAsmJSCall *lir) {} @@ -279,6 +263,10 @@ bool visitEffectiveAddress(LEffectiveAddress *ins); bool visitUDiv(LUDiv *ins); bool visitUMod(LUMod *ins); + + public: + bool bailoutIf(Assembler::Condition condition, LSnapshot *snapshot); + bool visitMoveGroup(LMoveGroup *group); }; typedef CodeGeneratorMIPS CodeGeneratorSpecific;
diff --git a/src/third_party/mozjs/js/src/jit/mips/IonFrames-mips.h b/src/third_party/mozjs/js/src/jit/mips/IonFrames-mips.h new file mode 100644 index 0000000..c9d4ba8 --- /dev/null +++ b/src/third_party/mozjs/js/src/jit/mips/IonFrames-mips.h
@@ -0,0 +1,558 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_mips_IonFrames_mips_h +#define jit_mips_IonFrames_mips_h + +#include "jit/shared/IonFrames-shared.h" + +namespace js { +namespace jit { + +class IonFramePrefix; +// Layout of the frame prefix. This assumes the stack architecture grows down. +// If this is ever not the case, we'll have to refactor. +class IonCommonFrameLayout +{ + uint8_t *returnAddress_; + uintptr_t descriptor_; + + static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1; + + public: + static size_t offsetOfDescriptor() { + return offsetof(IonCommonFrameLayout, descriptor_); + } + static size_t offsetOfReturnAddress() { + return offsetof(IonCommonFrameLayout, returnAddress_); + } + FrameType prevType() const { + return FrameType(descriptor_ & FrameTypeMask); + } + void changePrevType(FrameType type) { + descriptor_ &= ~FrameTypeMask; + descriptor_ |= type; + } + size_t prevFrameLocalSize() const { + return descriptor_ >> FRAMESIZE_SHIFT; + } + void setFrameDescriptor(size_t size, FrameType type) { + descriptor_ = (size << FRAMESIZE_SHIFT) | type; + } + uint8_t *returnAddress() const { + return returnAddress_; + } + void setReturnAddress(uint8_t *addr) { + returnAddress_ = addr; + } +}; + +// this is the layout of the frame that is used when we enter Ion code from EABI code +class IonEntryFrameLayout : public IonCommonFrameLayout +{ + public: + static inline size_t Size() { + return sizeof(IonEntryFrameLayout); + } +}; + +class IonJSFrameLayout : public IonEntryFrameLayout +{ + protected: + void *calleeToken_; + uintptr_t numActualArgs_; + + public: + void *calleeToken() const { + return calleeToken_; + } + void replaceCalleeToken(void *calleeToken) { + calleeToken_ = calleeToken; + } + + static size_t offsetOfCalleeToken() { + return offsetof(IonJSFrameLayout, calleeToken_); + } + static size_t offsetOfNumActualArgs() { + return offsetof(IonJSFrameLayout, numActualArgs_); + } + static size_t offsetOfThis() { + IonJSFrameLayout *base = NULL; + return reinterpret_cast<size_t>(&base->argv()[0]); + } + static size_t offsetOfActualArgs() { + IonJSFrameLayout *base = NULL; + // +1 to skip |this|. + return reinterpret_cast<size_t>(&base->argv()[1]); + } + static size_t offsetOfActualArg(size_t arg) { + return offsetOfActualArgs() + arg * sizeof(Value); + } + + Value thisv() { + return argv()[0]; + } + Value *argv() { + return (Value *)(this + 1); + } + uintptr_t numActualArgs() const { + return numActualArgs_; + } + + // Computes a reference to a slot, where a slot is a distance from the base + // frame pointer (as would be used for LStackSlot). + uintptr_t *slotRef(uint32_t slot) { + return (uintptr_t *)((uint8_t *)this - (slot * STACK_SLOT_SIZE)); + } + + static inline size_t Size() { + return sizeof(IonJSFrameLayout); + } +}; + +class IonRectifierFrameLayout : public IonJSFrameLayout +{ + public: + static inline size_t Size() { + return sizeof(IonRectifierFrameLayout); + } +}; + +class IonUnwoundRectifierFrameLayout : public IonJSFrameLayout +{ + public: + static inline size_t Size() { + // On X86, there is a +sizeof(uintptr_t) to account for an extra callee token. + // This is not needed here because sizeof(IonExitFrame) == sizeof(IonRectifierFrame) + // due to extra padding. + return sizeof(IonUnwoundRectifierFrameLayout); + } +}; + +// GC related data used to keep alive data surrounding the Exit frame. +class IonExitFooterFrame +{ + const VMFunction *function_; + IonCode *ionCode_; + + public: + static inline size_t Size() { + return sizeof(IonExitFooterFrame); + } + inline IonCode *ionCode() const { + return ionCode_; + } + inline IonCode **addressOfIonCode() { + return &ionCode_; + } + inline const VMFunction *function() const { + return function_; + } + + // This should only be called for function()->outParam == Type_Handle + template <typename T> + T *outParam() { + return reinterpret_cast<T *>(reinterpret_cast<char *>(this) - sizeof(T)); + } +}; + +class IonOsrFrameLayout : public IonJSFrameLayout +{ + public: + static inline size_t Size() { + return sizeof(IonOsrFrameLayout); + } +}; + +class ICStub; + +class IonBaselineStubFrameLayout : public IonCommonFrameLayout +{ + public: + static inline size_t Size() { + return sizeof(IonBaselineStubFrameLayout); + } + + static inline int reverseOffsetOfStubPtr() { + return -int(sizeof(void *)); + } + static inline int reverseOffsetOfSavedFramePtr() { + return -int(2 * sizeof(void *)); + } + + inline ICStub *maybeStubPtr() { + uint8_t *fp = reinterpret_cast<uint8_t *>(this); + return *reinterpret_cast<ICStub **>(fp + reverseOffsetOfStubPtr()); + } +}; + +class IonNativeExitFrameLayout; +class IonOOLNativeGetterExitFrameLayout; +class IonOOLPropertyOpExitFrameLayout; +class IonOOLProxyGetExitFrameLayout; +class IonDOMExitFrameLayout; + +// this is the frame layout when we are exiting ion code, and about to enter EABI code +class IonExitFrameLayout : public IonCommonFrameLayout +{ + inline uint8_t *top() { + return reinterpret_cast<uint8_t *>(this + 1); + } + + public: + static inline size_t Size() { + return sizeof(IonExitFrameLayout); + } + static inline size_t SizeWithFooter() { + return Size() + IonExitFooterFrame::Size(); + } + + inline IonExitFooterFrame *footer() { + uint8_t *sp = reinterpret_cast<uint8_t *>(this); + return reinterpret_cast<IonExitFooterFrame *>(sp - IonExitFooterFrame::Size()); + } + + // argBase targets the point which precedes the exit frame. Arguments of VM + // each wrapper are pushed before the exit frame. This correspond exactly + // to the value of the argBase register of the generateVMWrapper function. + inline uint8_t *argBase() { + JS_ASSERT(footer()->ionCode() != NULL); + return top(); + } + + inline bool isWrapperExit() { + return footer()->function() != NULL; + } + inline bool isNativeExit() { + return footer()->ionCode() == NULL; + } + inline bool isOOLNativeGetterExit() { + return footer()->ionCode() == ION_FRAME_OOL_NATIVE_GETTER; + } + inline bool isOOLPropertyOpExit() { + return footer()->ionCode() == ION_FRAME_OOL_PROPERTY_OP; + } + inline bool isOOLProxyGetExit() { + return footer()->ionCode() == ION_FRAME_OOL_PROXY_GET; + } + inline bool isDomExit() { + IonCode *code = footer()->ionCode(); + return + code == ION_FRAME_DOMGETTER || + code == ION_FRAME_DOMSETTER || + code == ION_FRAME_DOMMETHOD; + } + + inline IonNativeExitFrameLayout *nativeExit() { + // see CodeGenerator::visitCallNative + JS_ASSERT(isNativeExit()); + return reinterpret_cast<IonNativeExitFrameLayout *>(footer()); + } + inline IonOOLNativeGetterExitFrameLayout *oolNativeGetterExit() { + JS_ASSERT(isOOLNativeGetterExit()); + return reinterpret_cast<IonOOLNativeGetterExitFrameLayout *>(footer()); + } + inline IonOOLPropertyOpExitFrameLayout *oolPropertyOpExit() { + JS_ASSERT(isOOLPropertyOpExit()); + return reinterpret_cast<IonOOLPropertyOpExitFrameLayout *>(footer()); + } + inline IonOOLProxyGetExitFrameLayout *oolProxyGetExit() { + JS_ASSERT(isOOLProxyGetExit()); + return reinterpret_cast<IonOOLProxyGetExitFrameLayout *>(footer()); + } + inline IonDOMExitFrameLayout *DOMExit() { + JS_ASSERT(isDomExit()); + return reinterpret_cast<IonDOMExitFrameLayout *>(footer()); + } +}; + +// Cannot inherit implementa<tion since we need to extend the top of +// IonExitFrameLayout. +class IonNativeExitFrameLayout +{ + IonExitFooterFrame footer_; + IonExitFrameLayout exit_; + uintptr_t argc_; + + // We need to split the Value into 2 fields of 32 bits, otherwise the C++ + // compiler may add some padding between the fields. + uint32_t loCalleeResult_; + uint32_t hiCalleeResult_; + + public: + static inline size_t Size() { + return sizeof(IonNativeExitFrameLayout); + } + + static size_t offsetOfResult() { + return offsetof(IonNativeExitFrameLayout, loCalleeResult_); + } + inline Value *vp() { + return reinterpret_cast<Value*>(&loCalleeResult_); + } + inline uintptr_t argc() const { + return argc_; + } +}; + +class IonOOLNativeGetterExitFrameLayout +{ + IonExitFooterFrame footer_; + IonExitFrameLayout exit_; + + // We need to split the Value into 2 fields of 32 bits, otherwise the C++ + // compiler may add some padding between the fields. + uint32_t loCalleeResult_; + uint32_t hiCalleeResult_; + + // The frame includes the object argument. + uint32_t loThis_; + uint32_t hiThis_; + + // pointer to root the stub's IonCode + IonCode *stubCode_; + + public: + static inline size_t Size() { + return sizeof(IonOOLNativeGetterExitFrameLayout); + } + + static size_t offsetOfResult() { + return offsetof(IonOOLNativeGetterExitFrameLayout, loCalleeResult_); + } + + inline IonCode **stubCode() { + return &stubCode_; + } + inline Value *vp() { + return reinterpret_cast<Value*>(&loCalleeResult_); + } + inline Value *thisp() { + return reinterpret_cast<Value*>(&loThis_); + } + inline uintptr_t argc() const { + return 0; + } +}; + +class IonOOLPropertyOpExitFrameLayout +{ + IonExitFooterFrame footer_; + IonExitFrameLayout exit_; + + // Object for HandleObject + JSObject *obj_; + + // id for HandleId + jsid id_; + + // space for MutableHandleValue result + // use two uint32_t so compiler doesn't align. + uint32_t vp0_; + uint32_t vp1_; + + // pointer to root the stub's IonCode + IonCode *stubCode_; + + public: + static inline size_t Size() { + return sizeof(IonOOLPropertyOpExitFrameLayout); + } + + static size_t offsetOfResult() { + return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_); + } + + inline IonCode **stubCode() { + return &stubCode_; + } + inline Value *vp() { + return reinterpret_cast<Value*>(&vp0_); + } + inline jsid *id() { + return &id_; + } + inline JSObject **obj() { + return &obj_; + } +}; + +// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, +// MutableHandleValue vp) +class IonOOLProxyGetExitFrameLayout +{ + protected: // only to silence a clang warning about unused private fields + IonExitFooterFrame footer_; + IonExitFrameLayout exit_; + + // The proxy object. + JSObject *proxy_; + + // Object for HandleObject + JSObject *receiver_; + + // id for HandleId + jsid id_; + + // space for MutableHandleValue result + // use two uint32_t so compiler doesn't align. + uint32_t vp0_; + uint32_t vp1_; + + // pointer to root the stub's IonCode + IonCode *stubCode_; + + public: + static inline size_t Size() { + return sizeof(IonOOLProxyGetExitFrameLayout); + } + + static size_t offsetOfResult() { + return offsetof(IonOOLProxyGetExitFrameLayout, vp0_); + } + + inline IonCode **stubCode() { + return &stubCode_; + } + inline Value *vp() { + return reinterpret_cast<Value*>(&vp0_); + } + inline jsid *id() { + return &id_; + } + inline JSObject **receiver() { + return &receiver_; + } + inline JSObject **proxy() { + return &proxy_; + } +}; + +class IonDOMExitFrameLayout +{ + IonExitFooterFrame footer_; + IonExitFrameLayout exit_; + JSObject *thisObj; + + // We need to split the Value in 2 fields of 32 bits, otherwise the C++ + // compiler may add some padding between the fields. + uint32_t loCalleeResult_; + uint32_t hiCalleeResult_; + + public: + static inline size_t Size() { + return sizeof(IonDOMExitFrameLayout); + } + + static size_t offsetOfResult() { + return offsetof(IonDOMExitFrameLayout, loCalleeResult_); + } + inline Value *vp() { + return reinterpret_cast<Value*>(&loCalleeResult_); + } + inline JSObject **thisObjAddress() { + return &thisObj; + } + inline bool isMethodFrame() { + return footer_.ionCode() == ION_FRAME_DOMMETHOD; + } +}; + +struct IonDOMMethodExitFrameLayoutTraits; + +class IonDOMMethodExitFrameLayout +{ + IonExitFooterFrame footer_; + IonExitFrameLayout exit_; + // This must be the last thing pushed, so as to stay common with + // IonDOMExitFrameLayout. + JSObject *thisObj_; + Value *argv_; + uintptr_t argc_; + + // We need to split the Value in 2 fields of 32 bits, otherwise the C++ + // compiler may add some padding between the fields. + uint32_t loCalleeResult_; + uint32_t hiCalleeResult_; + + friend struct IonDOMMethodExitFrameLayoutTraits; + + public: + static inline size_t Size() { + return sizeof(IonDOMMethodExitFrameLayout); + } + + static size_t offsetOfResult() { + return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_); + } + + inline Value *vp() { + // The code in visitCallDOMNative depends on this static assert holding + JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) == + (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t))); + return reinterpret_cast<Value*>(&loCalleeResult_); + } + inline JSObject **thisObjAddress() { + return &thisObj_; + } + inline uintptr_t argc() { + return argc_; + } +}; + +struct IonDOMMethodExitFrameLayoutTraits { + static const size_t offsetOfArgcFromArgv = + offsetof(IonDOMMethodExitFrameLayout, argc_) - + offsetof(IonDOMMethodExitFrameLayout, argv_); +}; + +// An invalidation bailout stack is at the stack pointer for the callee frame. +class InvalidationBailoutStack +{ + double fpregs_[FloatRegisters::Total]; + uintptr_t regs_[Registers::Total]; + IonScript *ionScript_; + uint8_t *osiPointReturnAddress_; + + public: + uint8_t *sp() const { + return (uint8_t *) this + sizeof(InvalidationBailoutStack); + } + + IonJSFrameLayout *fp() const { + return (IonJSFrameLayout*) (sp() + ionScript_->frameSize()); + } + + MachineState machine() { + return MachineState::FromBailout(regs_, fpregs_); + } + + IonScript *ionScript() const { + return ionScript_; + } + + uint8_t *osiPointReturnAddress() const { + return osiPointReturnAddress_; + } + + void checkInvariants() const { +#ifdef DEBUG + // NYI_COBALT +#endif + } + + static size_t offsetOfFpRegs() { + return offsetof(InvalidationBailoutStack, fpregs_); + } + static size_t offsetOfRegs() { + return offsetof(InvalidationBailoutStack, regs_); + } +}; + +} // namespace jit +} // namespace js + +#endif /* jit_mips_IonFrames_mips_h */
diff --git a/src/third_party/mozjs/js/src/jit/mips/LIR-mips.h b/src/third_party/mozjs/js/src/jit/mips/LIR-mips.h index 7a7d51c..6e92c57 100644 --- a/src/third_party/mozjs/js/src/jit/mips/LIR-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/LIR-mips.h
@@ -17,7 +17,7 @@ public: LIR_HEADER(Box); - LBox(const LAllocation &in_payload, MIRType type) + LBox(const LAllocation& in_payload, MIRType type) : type_(type) { setOperand(0, in_payload); @@ -31,14 +31,14 @@ } }; -class LBoxFloatingPoint : public LInstructionHelper<2, 1, 1> +class LBoxDouble : public LInstructionHelper<2, 1, 1> { MIRType type_; public: - LIR_HEADER(BoxFloatingPoint); + LIR_HEADER(BoxDouble); - LBoxFloatingPoint(const LAllocation &in, const LDefinition &temp, MIRType type) + LBoxDouble(const LAllocation &in, const LDefinition &temp, MIRType type) : type_(type) { setOperand(0, in); @@ -72,54 +72,31 @@ } }; -class LUnboxFloatingPoint : public LInstructionHelper<1, 2, 0> +class LUnboxDouble : public LInstructionHelper<1, 2, 0> { MIRType type_; public: - LIR_HEADER(UnboxFloatingPoint); + LIR_HEADER(UnboxDouble); static const size_t Input = 0; - LUnboxFloatingPoint(MIRType type) - : type_(type) - { } - MUnbox *mir() const { return mir_->toUnbox(); } - - MIRType type() const { - return type_; - } - const char *extraName() const { - return StringFromMIRType(type_); - } }; // Convert a 32-bit unsigned integer to a double. -class LAsmJSUInt32ToDouble : public LInstructionHelper<1, 1, 0> +class LUInt32ToDouble : public LInstructionHelper<1, 1, 0> { public: - LIR_HEADER(AsmJSUInt32ToDouble) + LIR_HEADER(UInt32ToDouble) - LAsmJSUInt32ToDouble(const LAllocation &input) { + LUInt32ToDouble(const LAllocation &input) { setOperand(0, input); } }; -// Convert a 32-bit unsigned integer to a float32. -class LAsmJSUInt32ToFloat32 : public LInstructionHelper<1, 1, 0> -{ - public: - LIR_HEADER(AsmJSUInt32ToFloat32) - - LAsmJSUInt32ToFloat32(const LAllocation &input) { - setOperand(0, input); - } -}; - - class LDivI : public LBinaryMath<1> { public: @@ -132,7 +109,7 @@ setTemp(0, temp); } - MDiv *mir() const { + MDiv* mir() const { return mir_->toDiv(); } }; @@ -144,14 +121,14 @@ public: LIR_HEADER(DivPowTwoI) - LDivPowTwoI(const LAllocation &lhs, int32_t shift, const LDefinition &temp) + LDivPowTwoI(const LAllocation& lhs, int32_t shift, const LDefinition& temp) : shift_(shift) { setOperand(0, lhs); setTemp(0, temp); } - const LAllocation *numerator() { + const LAllocation* numerator() { return getOperand(0); } @@ -159,7 +136,7 @@ return shift_; } - MDiv *mir() const { + MDiv* mir() const { return mir_->toDiv(); } }; @@ -177,7 +154,7 @@ setTemp(0, callTemp); } - const LDefinition *callTemp() { + const LDefinition* callTemp() { return getTemp(0); } @@ -197,7 +174,7 @@ return shift_; } - LModPowTwoI(const LAllocation &lhs, int32_t shift) + LModPowTwoI(const LAllocation& lhs, int32_t shift) : shift_(shift) { setOperand(0, lhs); @@ -208,7 +185,7 @@ } }; -class LModMaskI : public LInstructionHelper<1, 1, 1> +class LModMaskI : public LInstructionHelper<1, 1, 2> { const int32_t shift_; @@ -216,7 +193,7 @@ LIR_HEADER(ModMaskI); LModMaskI(const LAllocation &lhs, const LDefinition &temp1, int32_t shift) - : shift_(shift) + : shift_(shift) { setOperand(0, lhs); setTemp(0, temp1); @@ -235,14 +212,14 @@ { public: LIR_HEADER(PowHalfD); - LPowHalfD(const LAllocation &input) { + LPowHalfD(const LAllocation& input) { setOperand(0, input); } - const LAllocation *input() { + const LAllocation* input() { return getOperand(0); } - const LDefinition *output() { + const LDefinition* output() { return getDef(0); } }; @@ -261,19 +238,19 @@ setMir(ins); } - MTableSwitch *mir() const { + MTableSwitch* mir() const { return mir_->toTableSwitch(); } const LAllocation *index() { return getOperand(0); } - const LDefinition *tempInt() { - return getTemp(0); + const LAllocation *tempInt() { + return getTemp(0)->output(); } // This is added to share the same CodeGenerator prefixes. - const LDefinition *tempPointer() { - return getTemp(1); + const LAllocation *tempPointer() { + return getTemp(1)->output(); } }; @@ -283,8 +260,8 @@ public: LIR_HEADER(TableSwitchV); - LTableSwitchV(const LDefinition &inputCopy, const LDefinition &floatCopy, - const LDefinition &jumpTablePointer, MTableSwitch *ins) + LTableSwitchV(const LDefinition& inputCopy, const LDefinition& floatCopy, + const LDefinition& jumpTablePointer, MTableSwitch* ins) { setTemp(0, inputCopy); setTemp(1, floatCopy); @@ -292,20 +269,20 @@ setMir(ins); } - MTableSwitch *mir() const { + MTableSwitch* mir() const { return mir_->toTableSwitch(); } static const size_t InputValue = 0; - const LDefinition *tempInt() { - return getTemp(0); + const LAllocation* tempInt() { + return getTemp(0)->output(); } - const LDefinition *tempFloat() { - return getTemp(1); + const LAllocation* tempFloat() { + return getTemp(1)->output(); } - const LDefinition *tempPointer() { - return getTemp(2); + const LAllocation* tempPointer() { + return getTemp(2)->output(); } }; @@ -314,14 +291,14 @@ public: LIR_HEADER(GuardShape); - LGuardShape(const LAllocation &in, const LDefinition &temp) { + LGuardShape(const LAllocation& in, const LDefinition& temp) { setOperand(0, in); setTemp(0, temp); } - const MGuardShape *mir() const { + const MGuardShape* mir() const { return mir_->toGuardShape(); } - const LDefinition *tempInt() { + const LDefinition* tempInt() { return getTemp(0); } }; @@ -354,7 +331,7 @@ public: LIR_HEADER(MulI); - MMul *mir() { + MMul* mir() { return mir_->toMul(); } }; @@ -364,7 +341,7 @@ public: LIR_HEADER(UDiv); - MDiv *mir() { + MDiv* mir() { return mir_->toDiv(); } }; @@ -374,7 +351,7 @@ public: LIR_HEADER(UMod); - MMod *mir() { + MMod* mir() { return mir_->toMod(); } };
diff --git a/src/third_party/mozjs/js/src/jit/mips/LOpcodes-mips.h b/src/third_party/mozjs/js/src/jit/mips/LOpcodes-mips.h index cb2aa37..46f4978 100644 --- a/src/third_party/mozjs/js/src/jit/mips/LOpcodes-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/LOpcodes-mips.h
@@ -9,19 +9,19 @@ #define LIR_CPU_OPCODE_LIST(_) \ _(Unbox) \ - _(UnboxFloatingPoint) \ + _(UnboxDouble) \ _(Box) \ - _(BoxFloatingPoint) \ + _(BoxDouble) \ _(DivI) \ _(DivPowTwoI) \ _(ModI) \ _(ModPowTwoI) \ _(ModMaskI) \ _(PowHalfD) \ - _(AsmJSUInt32ToDouble) \ - _(AsmJSUInt32ToFloat32) \ + _(UInt32ToDouble) \ _(UDiv) \ _(UMod) \ _(AsmJSLoadFuncPtr) + #endif // jit_mips_LOpcodes_mips_h__
diff --git a/src/third_party/mozjs/js/src/jit/mips/Lowering-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/Lowering-mips.cpp index 6f84a5f..e0bc7b1 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Lowering-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/Lowering-mips.cpp
@@ -16,8 +16,6 @@ using namespace js; using namespace js::jit; -using mozilla::FloorLog2; - bool LIRGeneratorMIPS::useBox(LInstruction *lir, size_t n, MDefinition *mir, LUse::Policy policy, bool useAtStart) @@ -60,13 +58,7 @@ bool LIRGeneratorMIPS::lowerConstantDouble(double d, MInstruction *mir) { - return define(new(alloc()) LDouble(d), mir); -} - -bool -LIRGeneratorMIPS::lowerConstantFloat32(float d, MInstruction *mir) -{ - return define(new(alloc()) LFloat32(d), mir); + return define(new LDouble(d), mir); } bool @@ -75,9 +67,6 @@ if (ins->type() == MIRType_Double) return lowerConstantDouble(ins->value().toDouble(), ins); - if (ins->type() == MIRType_Float32) - return lowerConstantFloat32(ins->value().toDouble(), ins); - // Emit non-double constants at their uses. if (ins->canEmitAtUses()) return emitAtUses(ins); @@ -91,17 +80,18 @@ MDefinition *inner = box->getOperand(0); // If the box wrapped a double, it needs a new register. - if (IsFloatingPointType(inner->type())) - return defineBox(new(alloc()) LBoxFloatingPoint(useRegisterAtStart(inner), + if (inner->type() == MIRType_Double) { + return defineBox(new LBoxDouble(useRegisterAtStart(inner), tempCopy(inner, 0), inner->type()), box); + } if (box->canEmitAtUses()) return emitAtUses(box); if (inner->isConstant()) - return defineBox(new(alloc()) LValue(inner->toConstant()->value()), box); + return defineBox(new LValue(inner->toConstant()->value()), box); - LBox *lir = new(alloc()) LBox(use(inner), inner->type()); + LBox *lir = new LBox(use(inner), inner->type()); // Otherwise, we should not define a new register for the payload portion // of the output, so bypass defineBox(). @@ -133,18 +123,20 @@ if (!ensureDefined(inner)) return false; - if (IsFloatingPointType(unbox->type())) { - LUnboxFloatingPoint *lir = new(alloc()) LUnboxFloatingPoint(unbox->type()); - if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind())) + if (unbox->type() == MIRType_Double) { + LUnboxDouble* lir = new LUnboxDouble(); + if (unbox->fallible() && !assignSnapshot(lir, unbox->bailoutKind())) { return false; - if (!useBox(lir, LUnboxFloatingPoint::Input, inner)) + } + if (!useBox(lir, LUnboxDouble::Input, inner)) { return false; + } return define(lir, unbox); } // Swap the order we use the box pieces so we can re-use the payload // register. - LUnbox *lir = new(alloc()) LUnbox; + LUnbox *lir = new LUnbox(); lir->setOperand(0, usePayloadInRegisterAtStart(inner)); lir->setOperand(1, useType(inner, LUse::REGISTER)); @@ -166,7 +158,7 @@ MDefinition *opd = ret->getOperand(0); MOZ_ASSERT(opd->type() == MIRType_Value); - LReturn *ins = new(alloc()) LReturn; + LReturn *ins = new LReturn(); ins->setOperand(0, LUse(JSReturnReg_Type)); ins->setOperand(1, LUse(JSReturnReg_Data)); return fillBoxUses(ins, 0, opd) && add(ins); @@ -213,15 +205,6 @@ } bool -LIRGeneratorMIPS::lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir, - MDefinition *lhs, MDefinition *rhs) -{ - baab->setOperand(0, useRegisterAtStart(lhs)); - baab->setOperand(1, useRegisterOrConstantAtStart(rhs)); - return add(baab, mir); -} - -bool LIRGeneratorMIPS::defineUntypedPhi(MPhi *phi, size_t lirIndex) { LPhi *type = current->getPhi(lirIndex + VREG_TYPE_OFFSET); @@ -269,9 +252,6 @@ bool LIRGeneratorMIPS::lowerDivI(MDiv *div) { - if (div->isUnsigned()) - return lowerUDiv(div); - // Division instructions are slow. Division by constant denominators can be // rewritten to use other instructions. if (div->rhs()->isConstant()) { @@ -281,17 +261,20 @@ // possible; division by negative powers of two can be optimized in a // similar manner as positive powers of two, and division by other // constants can be optimized by a reciprocal multiplication technique. - int32_t shift = FloorLog2(rhs); + + int32_t shift; + JS_FLOOR_LOG2(shift, rhs); + if (rhs > 0 && 1 << shift == rhs) { - LDivPowTwoI *lir = new(alloc()) LDivPowTwoI(useRegister(div->lhs()), shift, temp()); - if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) + LDivPowTwoI *lir = new LDivPowTwoI(useRegister(div->lhs()), shift, temp()); + if (div->fallible() && !assignSnapshot(lir)) return false; return define(lir, div); } } - LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp()); - if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) + LDivI *lir = new LDivI(useRegister(div->lhs()), useRegister(div->rhs()), temp()); + if (div->fallible() && !assignSnapshot(lir)) return false; return define(lir, div); } @@ -299,8 +282,8 @@ bool LIRGeneratorMIPS::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs) { - LMulI *lir = new(alloc()) LMulI; - if (mul->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) + LMulI *lir = new LMulI; + if (mul->fallible() && !assignSnapshot(lir)) return false; return lowerForALU(lir, mul, lhs, rhs); @@ -314,24 +297,30 @@ if (mod->rhs()->isConstant()) { int32_t rhs = mod->rhs()->toConstant()->value().toInt32(); - int32_t shift = FloorLog2(rhs); + + int32_t shift; + JS_FLOOR_LOG2(shift, rhs); + if (rhs > 0 && 1 << shift == rhs) { - LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegister(mod->lhs()), shift); - if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) + LModPowTwoI *lir = new LModPowTwoI(useRegister(mod->lhs()), shift); + if (mod->fallible() && !assignSnapshot(lir)) return false; return define(lir, mod); } else if (shift < 31 && (1 << (shift + 1)) - 1 == rhs) { - LModMaskI *lir = new(alloc()) LModMaskI(useRegister(mod->lhs()), - temp(LDefinition::GENERAL), shift + 1); - if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) + LModMaskI *lir = new LModMaskI( + useRegister(mod->lhs()), + temp(LDefinition::GENERAL), + shift + 1 + ); + if (mod->fallible() && !assignSnapshot(lir)) return false; return define(lir, mod); } } - LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()), useRegister(mod->rhs()), + LModI *lir = new LModI(useRegister(mod->lhs()), useRegister(mod->rhs()), temp(LDefinition::GENERAL)); - if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) + if (mod->fallible() && !assignSnapshot(lir)) return false; return define(lir, mod); } @@ -341,7 +330,7 @@ { MDefinition *input = ins->input(); MOZ_ASSERT(input->type() == MIRType_Double); - LPowHalfD *lir = new(alloc()) LPowHalfD(useRegisterAtStart(input)); + LPowHalfD *lir = new LPowHalfD(useRegisterAtStart(input)); return defineReuseInput(lir, ins, 0); } @@ -349,13 +338,13 @@ LIRGeneratorMIPS::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy, MTableSwitch *tableswitch) { - return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch); + return new LTableSwitch(in, inputCopy, temp(), tableswitch); } LTableSwitchV * LIRGeneratorMIPS::newLTableSwitchV(MTableSwitch *tableswitch) { - return new(alloc()) LTableSwitchV(temp(), tempFloat32(), temp(), tableswitch); + return new LTableSwitchV(temp(), tempFloat(), temp(), tableswitch); } bool @@ -364,7 +353,7 @@ MOZ_ASSERT(ins->obj()->type() == MIRType_Object); LDefinition tempObj = temp(LDefinition::OBJECT); - LGuardShape *guard = new(alloc()) LGuardShape(useRegister(ins->obj()), tempObj); + LGuardShape *guard = new LGuardShape(useRegister(ins->obj()), tempObj); if (!assignSnapshot(guard, ins->bailoutKind())) return false; if (!add(guard, ins)) @@ -378,7 +367,7 @@ MOZ_ASSERT(ins->obj()->type() == MIRType_Object); LDefinition tempObj = temp(LDefinition::OBJECT); - LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()), tempObj); + LGuardObjectType *guard = new LGuardObjectType(useRegister(ins->obj()), tempObj); if (!assignSnapshot(guard)) return false; if (!add(guard, ins)) @@ -395,7 +384,7 @@ MOZ_ASSERT(lhs->type() == MIRType_Int32); MOZ_ASSERT(rhs->type() == MIRType_Int32); - LUrshD *lir = new(alloc()) LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp()); + LUrshD *lir = new LUrshD(useRegister(lhs), useRegisterOrConstant(rhs), temp()); return define(lir, mir); } @@ -403,13 +392,10 @@ LIRGeneratorMIPS::visitAsmJSNeg(MAsmJSNeg *ins) { if (ins->type() == MIRType_Int32) - return define(new(alloc()) LNegI(useRegisterAtStart(ins->input())), ins); - - if (ins->type() == MIRType_Float32) - return define(new(alloc()) LNegF(useRegisterAtStart(ins->input())), ins); + return define(new LNegI(useRegisterAtStart(ins->input())), ins); MOZ_ASSERT(ins->type() == MIRType_Double); - return define(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins); + return define(new LNegD(useRegisterAtStart(ins->input())), ins); } bool @@ -418,10 +404,10 @@ MDefinition *lhs = div->getOperand(0); MDefinition *rhs = div->getOperand(1); - LUDiv *lir = new(alloc()) LUDiv; + LUDiv *lir = new LUDiv; lir->setOperand(0, useRegister(lhs)); lir->setOperand(1, useRegister(rhs)); - if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) + if (div->fallible() && !assignSnapshot(lir)) return false; return define(lir, div); @@ -433,10 +419,10 @@ MDefinition *lhs = mod->getOperand(0); MDefinition *rhs = mod->getOperand(1); - LUMod *lir = new(alloc()) LUMod; + LUMod *lir = new LUMod; lir->setOperand(0, useRegister(lhs)); lir->setOperand(1, useRegister(rhs)); - if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) + if (mod->fallible() && !assignSnapshot(lir)) return false; return define(lir, mod); @@ -446,16 +432,67 @@ LIRGeneratorMIPS::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins) { MOZ_ASSERT(ins->input()->type() == MIRType_Int32); - LAsmJSUInt32ToDouble *lir = new(alloc()) LAsmJSUInt32ToDouble(useRegisterAtStart(ins->input())); + LUInt32ToDouble *lir = new LUInt32ToDouble(useRegisterAtStart(ins->input())); return define(lir, ins); } bool -LIRGeneratorMIPS::visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins) +LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) { - MOZ_ASSERT(ins->input()->type() == MIRType_Int32); - LAsmJSUInt32ToFloat32 *lir = new(alloc()) LAsmJSUInt32ToFloat32(useRegisterAtStart(ins->input())); - return define(lir, ins); + LAsmJSStoreHeap *lir; + switch (ins->viewType()) { + case ArrayBufferView::TYPE_INT8: case ArrayBufferView::TYPE_UINT8: + case ArrayBufferView::TYPE_INT16: case ArrayBufferView::TYPE_UINT16: + case ArrayBufferView::TYPE_INT32: case ArrayBufferView::TYPE_UINT32: + lir = new LAsmJSStoreHeap(useRegisterAtStart(ins->ptr()), + useRegisterAtStart(ins->value())); + break; + case ArrayBufferView::TYPE_FLOAT32: + case ArrayBufferView::TYPE_FLOAT64: + lir = new LAsmJSStoreHeap(useRegisterAtStart(ins->ptr()), + useRegisterAtStart(ins->value())); + break; + default: JS_NOT_REACHED("unexpected array type"); + } + + return add(lir, ins); +} + +bool +LIRGeneratorMIPS::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins) +{ + return define(new LAsmJSLoadFuncPtr(useRegister(ins->index()), temp()), ins); +} + +bool +LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32 *ins) +{ + MDefinition *opd = ins->input(); + MOZ_ASSERT(opd->type() == MIRType_Double); + + return define(new LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); +} + +bool +LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins) +{ + JS_NOT_REACHED("NYI"); +} + +bool LIRGeneratorMIPS::visitAsmJSUDiv(MAsmJSUDiv* ins) { + // LAsmJSDivOrMod doesn't exist in MIPS, not clear how to implement this. + // It doesn't look like it's called anywhere... + JS_NOT_REACHED("NYI_COBALT"); + return false; +} + +bool LIRGeneratorMIPS::visitInterruptCheck(MInterruptCheck *ins) { + LInterruptCheck *lir = new LInterruptCheck(); + if (!add(lir)) + return false; + if (!assignSafepoint(lir, ins)) + return false; + return true; } bool @@ -467,7 +504,9 @@ // For MIPS it is best to keep the 'ptr' in a register if a bounds check // is needed. - if (ptr->isConstant() && ins->skipBoundsCheck()) { + // if (ptr->isConstant() && ins->skipBoundsCheck()) { + JS_NOT_REACHED("NYI_COBALT"); + if (ptr->isConstant() && false) { int32_t ptrValue = ptr->toConstant()->value().toInt32(); // A bounds check is only skipped for a positive index. MOZ_ASSERT(ptrValue >= 0); @@ -475,57 +514,6 @@ } else ptrAlloc = useRegisterAtStart(ptr); - return define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins); + return define(new LAsmJSLoadHeap(ptrAlloc), ins); } -bool -LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) -{ - MDefinition *ptr = ins->ptr(); - MOZ_ASSERT(ptr->type() == MIRType_Int32); - LAllocation ptrAlloc; - - if (ptr->isConstant() && ins->skipBoundsCheck()) { - MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0); - ptrAlloc = LAllocation(ptr->toConstant()->vp()); - } else - ptrAlloc = useRegisterAtStart(ptr); - - return add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins); -} - -bool -LIRGeneratorMIPS::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins) -{ - return define(new(alloc()) LAsmJSLoadFuncPtr(useRegister(ins->index()), temp()), ins); -} - -bool -LIRGeneratorMIPS::lowerTruncateDToInt32(MTruncateToInt32 *ins) -{ - MDefinition *opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Double); - - return define(new(alloc()) LTruncateDToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); -} - -bool -LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32 *ins) -{ - MDefinition *opd = ins->input(); - MOZ_ASSERT(opd->type() == MIRType_Float32); - - return define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); -} - -bool -LIRGeneratorMIPS::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins) -{ - MOZ_ASSUME_UNREACHABLE("NYI"); -} - -bool -LIRGeneratorMIPS::visitForkJoinGetSlice(MForkJoinGetSlice *ins) -{ - MOZ_ASSUME_UNREACHABLE("NYI"); -}
diff --git a/src/third_party/mozjs/js/src/jit/mips/Lowering-mips.h b/src/third_party/mozjs/js/src/jit/mips/Lowering-mips.h index 0deab80..fe0ff26 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Lowering-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/Lowering-mips.h
@@ -56,8 +56,6 @@ MDefinition *src); bool lowerForFPU(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs, MDefinition *rhs); - bool lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruction *mir, - MDefinition *lhs, MDefinition *rhs); bool lowerConstantDouble(double d, MInstruction *ins); bool lowerConstantFloat32(float d, MInstruction *ins); bool lowerTruncateDToInt32(MTruncateToInt32 *ins); @@ -83,12 +81,13 @@ bool visitGuardShape(MGuardShape *ins); bool visitGuardObjectType(MGuardObjectType *ins); bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins); - bool visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins); bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins); bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins); bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins); bool visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins); - bool visitForkJoinGetSlice(MForkJoinGetSlice *ins); + bool visitAsmJSUDiv(MAsmJSUDiv* ins); + bool visitAsmJSUMod(MAsmJSUDiv* ins); + bool visitInterruptCheck(MInterruptCheck *ins); static bool allowFloat32Optimizations() { return true;
diff --git a/src/third_party/mozjs/js/src/jit/mips/MacroAssembler-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/MacroAssembler-mips.cpp index cee93a5..e1c7601 100644 --- a/src/third_party/mozjs/js/src/jit/mips/MacroAssembler-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/MacroAssembler-mips.cpp
@@ -67,18 +67,6 @@ as_addd(dest, dest, SecondScratchFloatReg); } -void -MacroAssemblerMIPS::convertUInt32ToFloat32(const Register &src, const FloatRegister &dest) -{ - MOZ_ASSUME_UNREACHABLE("NYI"); -} - -void -MacroAssemblerMIPS::convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest) -{ - as_cvtsd(dest, src); -} - // Convert the floating point value to an integer, if it did not fit, then it // was clamped to INT32_MIN/INT32_MAX, and we can test it. // NOTE: if the value really was supposed to be INT32_MAX / INT32_MIN then it @@ -120,65 +108,6 @@ } } -// Checks whether a float32 is representable as a 32-bit integer. If so, the -// integer is written to the output register. Otherwise, a bailout is taken to -// the given snapshot. This function overwrites the scratch float register. -void -MacroAssemblerMIPS::convertFloat32ToInt32(const FloatRegister &src, const Register &dest, - Label *fail, bool negativeZeroCheck) -{ - // convert the floating point value to an integer, if it did not fit, then - // when we convert it *back* to a float, it will have a different value, - // which we can test. - as_cvtws(ScratchFloatReg, src); - as_mfc1(dest, ScratchFloatReg); - as_cvtsw(ScratchFloatReg, ScratchFloatReg); - ma_bc1s(src, ScratchFloatReg, fail, Assembler::DoubleNotEqualOrUnordered); - - if (negativeZeroCheck) { - Label notZero; - ma_b(dest, Imm32(0), ¬Zero, Assembler::NotEqual, ShortJump); - // Test and bail for -0.0, when integer result is 0 - // Move the top word of the double into the output reg, - // if it is non-zero, then the original value was -0.0 - moveFromDoubleHi(src, dest); - ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal); - bind(¬Zero); - } -} - -void -MacroAssemblerMIPS::convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest) -{ - as_cvtds(dest, src); -} - -void -MacroAssemblerMIPS::branchTruncateFloat32(const FloatRegister &src, const Register &dest, - Label *fail) -{ - Label test, success; - as_truncws(ScratchFloatReg, src); - as_mfc1(dest, ScratchFloatReg); - - ma_b(dest, Imm32(INT32_MAX), fail, Assembler::Equal); -} - -void -MacroAssemblerMIPS::convertInt32ToFloat32(const Register &src, const FloatRegister &dest) -{ - as_mtc1(src, dest); - as_cvtsw(dest, dest); -} - -void -MacroAssemblerMIPS::convertInt32ToFloat32(const Address &src, FloatRegister dest) -{ - ma_lw(ScratchRegister, src); - as_mtc1(ScratchRegister, dest); - as_cvtsw(dest, dest); -} - void MacroAssemblerMIPS::addDouble(FloatRegister src, FloatRegister dest) { @@ -266,7 +195,6 @@ } } - // This method generates lui and ori instruction pair that can be modified by // updateLuiOriValue, either during compilation (eg. Assembler::bind), or // during execution (eg. jit::PatchJump). @@ -279,7 +207,7 @@ } void -MacroAssemblerMIPS::ma_liPatchable(Register dest, ImmPtr imm) +MacroAssemblerMIPS::ma_liPatchable(Register dest, ImmWord imm) { return ma_liPatchable(dest, Imm32(int32_t(imm.value))); } @@ -609,82 +537,6 @@ ma_div_branch_overflow(rd, rs, ScratchRegister, overflow); } -void -MacroAssemblerMIPS::ma_mod_mask(Register src, Register dest, Register hold, int32_t shift, - Label *negZero) -{ - // MATH: - // We wish to compute x % (1<<y) - 1 for a known constant, y. - // First, let b = (1<<y) and C = (1<<y)-1, then think of the 32 bit - // dividend as a number in base b, namely - // c_0*1 + c_1*b + c_2*b^2 ... c_n*b^n - // now, since both addition and multiplication commute with modulus, - // x % C == (c_0 + c_1*b + ... + c_n*b^n) % C == - // (c_0 % C) + (c_1%C) * (b % C) + (c_2 % C) * (b^2 % C)... - // now, since b == C + 1, b % C == 1, and b^n % C == 1 - // this means that the whole thing simplifies to: - // c_0 + c_1 + c_2 ... c_n % C - // each c_n can easily be computed by a shift/bitextract, and the modulus - // can be maintained by simply subtracting by C whenever the number gets - // over C. - int32_t mask = (1 << shift) - 1; - Label head, negative, sumSigned, done; - - // hold holds -1 if the value was negative, 1 otherwise. - // ScratchRegister holds the remaining bits that have not been processed - // lr serves as a temporary location to store extracted bits into as well - // as holding the trial subtraction as a temp value dest is the - // accumulator (and holds the final result) - - // move the whole value into the scratch register, setting the codition - // codes so we can muck with them later. - ma_move(ScratchRegister, src); - // Zero out the dest. - ma_subu(dest, dest, dest); - // Set the hold appropriately. - ma_b(ScratchRegister, ScratchRegister, &negative, Signed, ShortJump); - ma_li(hold, Imm32(1)); - ma_b(&head, ShortJump); - - bind(&negative); - ma_li(hold, Imm32(-1)); - ma_negu(ScratchRegister, ScratchRegister); - - // Begin the main loop. - bind(&head); - - // Extract the bottom bits into lr. - ma_and(SecondScratchReg, ScratchRegister, Imm32(mask)); - // Add those bits to the accumulator. - as_addu(dest, dest, SecondScratchReg); - // Do a trial subtraction, this is the same operation as cmp, but we - // store the dest - ma_subu(SecondScratchReg, dest, Imm32(mask)); - // If (sum - C) > 0, store sum - C back into sum, thus performing a - // modulus. - ma_b(SecondScratchReg, SecondScratchReg, &sumSigned, Signed, ShortJump); - ma_move(dest, SecondScratchReg); - bind(&sumSigned); - // Get rid of the bits that we extracted before. - as_srl(ScratchRegister, ScratchRegister, shift); - // If the shift produced zero, finish, otherwise, continue in the loop. - ma_b(ScratchRegister, ScratchRegister, &head, NonZero, ShortJump); - // Check the hold to see if we need to negate the result. - ma_b(hold, hold, &done, NotSigned, ShortJump); - - // If the hold was non-zero, negate the result to be in line with - // what JS wants - if (negZero != nullptr) { - // Jump out in case of negative zero. - ma_b(hold, hold, negZero, Zero); - ma_negu(dest, dest); - } else { - ma_negu(dest, dest); - } - - bind(&done); -} - // Memory. void @@ -720,7 +572,7 @@ as_lw(dest, base, encodedOffset); break; default: - MOZ_ASSUME_UNREACHABLE("Invalid argument for ma_load"); + JS_NOT_REACHED("Invalid argument for ma_load"); break; } } @@ -760,7 +612,7 @@ as_sw(data, base, encodedOffset); break; default: - MOZ_ASSUME_UNREACHABLE("Invalid argument for ma_store"); + JS_NOT_REACHED("Invalid argument for ma_store"); break; } } @@ -1062,13 +914,13 @@ case Always: case Signed: case NotSigned: - MOZ_ASSUME_UNREACHABLE("There is a better way to compare for equality."); + JS_NOT_REACHED("There is a better way to compare for equality."); break; case Overflow: - MOZ_ASSUME_UNREACHABLE("Overflow condition not supported for MIPS."); + JS_NOT_REACHED("Overflow condition not supported for MIPS."); break; default: - MOZ_ASSUME_UNREACHABLE("Invalid condition for branch."); + JS_NOT_REACHED("Invalid condition for branch."); } return Always; } @@ -1163,7 +1015,7 @@ as_xori(rd, rd, 1); break; default: - MOZ_ASSUME_UNREACHABLE("Invalid condition for ma_cmp_set."); + JS_NOT_REACHED("Invalid condition for ma_cmp_set."); break; } } @@ -1231,7 +1083,7 @@ *testKind = TestForTrue; break; default: - MOZ_ASSUME_UNREACHABLE("Invalid DoubleCondition."); + JS_NOT_REACHED("Invalid DoubleCondition."); break; } } @@ -1459,7 +1311,7 @@ CodeLabel cl; ma_li(scratch, cl.dest()); - uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); + uint32_t descriptor = MakeFrameDescriptor(framePushed(), IonFrame_OptimizedJS); Push(Imm32(descriptor)); Push(scratch); @@ -1473,35 +1325,35 @@ bool MacroAssemblerMIPSCompat::buildOOLFakeExitFrame(void *fakeReturnAddr) { - DebugOnly<uint32_t> initialDepth = framePushed(); - uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); + // DebugOnly<uint32_t> initialDepth = framePushed(); + uint32_t descriptor = MakeFrameDescriptor(framePushed(), IonFrame_OptimizedJS); Push(Imm32(descriptor)); // descriptor_ - Push(ImmPtr(fakeReturnAddr)); + Push(ImmWord(fakeReturnAddr)); return true; } void -MacroAssemblerMIPSCompat::callWithExitFrame(JitCode *target) +MacroAssemblerMIPSCompat::callWithExitFrame(IonCode *target) { - uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); + uint32_t descriptor = MakeFrameDescriptor(framePushed(), IonFrame_OptimizedJS); Push(Imm32(descriptor)); // descriptor - addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE); - ma_liPatchable(ScratchRegister, ImmPtr(target->raw())); + addPendingJump(m_buffer.nextOffset(), target->raw(), Relocation::IONCODE); + ma_liPatchable(ScratchRegister, ImmWord(target->raw())); ma_callIonHalfPush(ScratchRegister); } void -MacroAssemblerMIPSCompat::callWithExitFrame(JitCode *target, Register dynStack) +MacroAssemblerMIPSCompat::callWithExitFrame(IonCode *target, Register dynStack) { ma_addu(dynStack, dynStack, Imm32(framePushed())); - makeFrameDescriptor(dynStack, JitFrame_IonJS); + makeFrameDescriptor(dynStack, IonFrame_OptimizedJS); Push(dynStack); // descriptor - addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE); - ma_liPatchable(ScratchRegister, ImmPtr(target->raw())); + addPendingJump(m_buffer.nextOffset(), target->raw(), Relocation::IONCODE); + ma_liPatchable(ScratchRegister, ImmWord(target->raw())); ma_callIonHalfPush(ScratchRegister); } @@ -1541,72 +1393,6 @@ } void -MacroAssembler::PushRegsInMask(RegisterSet set) -{ - int32_t diffF = set.fpus().size() * sizeof(double); - int32_t diffG = set.gprs().size() * sizeof(intptr_t); - - reserveStack(diffG); - for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) { - diffG -= sizeof(intptr_t); - storePtr(*iter, Address(StackPointer, diffG)); - } - MOZ_ASSERT(diffG == 0); - - // Double values have to be aligned. We reserve extra space so that we can - // start writing from the first aligned location. - // We reserve a whole extra double so that the buffer has even size. - ma_and(SecondScratchReg, sp, Imm32(~(StackAlignment - 1))); - reserveStack(diffF + sizeof(double)); - - for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) { - // Use assembly s.d because we have alligned the stack. - // :TODO: (Bug 972836) Fix this once odd regs can be used as - // float32 only. For now we skip saving odd regs for O32 ABI. - - // :TODO: (Bug 985881) Make a switch for N32 ABI. - if ((*iter).code() % 2 == 0) - as_sd(*iter, SecondScratchReg, -diffF); - diffF -= sizeof(double); - } - MOZ_ASSERT(diffF == 0); -} - -void -MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore) -{ - int32_t diffG = set.gprs().size() * sizeof(intptr_t); - int32_t diffF = set.fpus().size() * sizeof(double); - const int32_t reservedG = diffG; - const int32_t reservedF = diffF; - - // Read the buffer form the first aligned location. - ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double))); - ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(StackAlignment - 1))); - - for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) { - // :TODO: (Bug 972836) Fix this once odd regs can be used as - // float32 only. For now we skip loading odd regs for O32 ABI. - - // :TODO: (Bug 985881) Make a switch for N32 ABI. - if (!ignore.has(*iter) && ((*iter).code() % 2 == 0)) - // Use assembly l.d because we have alligned the stack. - as_ld(*iter, SecondScratchReg, -diffF); - diffF -= sizeof(double); - } - freeStack(reservedF + sizeof(double)); - MOZ_ASSERT(diffF == 0); - - for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) { - diffG -= sizeof(intptr_t); - if (!ignore.has(*iter)) - loadPtr(Address(StackPointer, diffG), *iter); - } - freeStack(reservedG); - MOZ_ASSERT(diffG == 0); -} - -void MacroAssemblerMIPSCompat::add32(Register src, Register dest) { as_addu(dest, dest, src); @@ -1757,16 +1543,6 @@ { ma_li(dest, imm); } -void -MacroAssemblerMIPSCompat::movePtr(const ImmPtr &imm, const Register &dest) -{ - movePtr(ImmWord(uintptr_t(imm.value)), dest); -} -void -MacroAssemblerMIPSCompat::movePtr(const AsmJSImmPtr &imm, const Register &dest) -{ - MOZ_ASSUME_UNREACHABLE("NYI"); -} void MacroAssemblerMIPSCompat::load8ZeroExtend(const Address &address, const Register &dest) @@ -1853,12 +1629,6 @@ ma_li(ScratchRegister, Imm32((uint32_t)address.addr)); as_lw(dest, ScratchRegister, 0); } -void -MacroAssemblerMIPSCompat::loadPtr(const AsmJSAbsoluteAddress &address, const Register &dest) -{ - movePtr(AsmJSImmPtr(address.kind()), ScratchRegister); - loadPtr(Address(ScratchRegister, 0x0), dest); -} void MacroAssemblerMIPSCompat::loadPrivate(const Address &address, const Register &dest) @@ -1889,21 +1659,9 @@ void MacroAssemblerMIPSCompat::loadFloatAsDouble(const BaseIndex &src, const FloatRegister &dest) { - loadFloat32(src, dest); - as_cvtds(dest, dest); -} - -void -MacroAssemblerMIPSCompat::loadFloat32(const Address &address, const FloatRegister &dest) -{ - ma_ls(dest, address); -} - -void -MacroAssemblerMIPSCompat::loadFloat32(const BaseIndex &src, const FloatRegister &dest) -{ computeScaledAddress(src, SecondScratchReg); ma_ls(dest, Address(SecondScratchReg, src.offset)); + as_cvtds(dest, dest); } void @@ -1976,12 +1734,6 @@ } void -MacroAssemblerMIPSCompat::store32(const Imm32 &imm, const BaseIndex &dest) -{ - ma_store(imm, dest, SizeWord); -} - -void MacroAssemblerMIPSCompat::store32(const Register &src, const BaseIndex &dest) { ma_store(src, dest, SizeWord); @@ -1995,12 +1747,6 @@ } void -MacroAssemblerMIPSCompat::storePtr(ImmPtr imm, const Address &address) -{ - storePtr(ImmWord(uintptr_t(imm.value)), address); -} - -void MacroAssemblerMIPSCompat::storePtr(ImmGCPtr imm, const Address &address) { ma_li(ScratchRegister, imm); @@ -2047,13 +1793,6 @@ ma_bc1d(lhs, rhs, label, cond); } -void -MacroAssemblerMIPSCompat::branchFloat(DoubleCondition cond, const FloatRegister &lhs, - const FloatRegister &rhs, Label *label) -{ - ma_bc1s(lhs, rhs, label, cond); -} - // higher level tag testing code Operand ToPayload(Operand base) @@ -2404,24 +2143,6 @@ } void -MacroAssemblerMIPSCompat::unboxString(const ValueOperand &operand, const Register &dest) -{ - ma_move(dest, operand.payloadReg()); -} - -void -MacroAssemblerMIPSCompat::unboxString(const Address &src, const Register &dest) -{ - ma_lw(dest, Address(src.base, src.offset + PAYLOAD_OFFSET)); -} - -void -MacroAssemblerMIPSCompat::unboxObject(const ValueOperand &src, const Register &dest) -{ - ma_move(dest, src.payloadReg()); -} - -void MacroAssemblerMIPSCompat::unboxValue(const ValueOperand &src, AnyRegister dest) { if (dest.isFloat()) { @@ -2474,28 +2195,6 @@ } void -MacroAssemblerMIPSCompat::boolValueToFloat32(const ValueOperand &operand, - const FloatRegister &dest) -{ - - convertBoolToInt32(ScratchRegister, operand.payloadReg()); - convertInt32ToFloat32(ScratchRegister, dest); -} - -void -MacroAssemblerMIPSCompat::int32ValueToFloat32(const ValueOperand &operand, - const FloatRegister &dest) -{ - convertInt32ToFloat32(operand.payloadReg(), dest); -} - -void -MacroAssemblerMIPSCompat::loadConstantFloat32(float f, const FloatRegister &dest) -{ - ma_lis(dest, f); -} - -void MacroAssemblerMIPSCompat::loadInt32OrDouble(const Address &src, const FloatRegister &dest) { Label notInt32, end; @@ -2545,40 +2244,6 @@ ma_lid(dest, dp); } -void -MacroAssemblerMIPSCompat::branchTestInt32Truthy(bool b, const ValueOperand &value, Label *label) -{ - ma_and(ScratchRegister, value.payloadReg(), value.payloadReg()); - ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero); -} - -void -MacroAssemblerMIPSCompat::branchTestStringTruthy(bool b, const ValueOperand &value, Label *label) -{ - Register string = value.payloadReg(); - size_t mask = (0xFFFFFFFF << JSString::LENGTH_SHIFT); - ma_lw(SecondScratchReg, Address(string, JSString::offsetOfLengthAndFlags())); - - // Use SecondScratchReg because ma_and will clobber ScratchRegister - ma_and(ScratchRegister, SecondScratchReg, Imm32(mask)); - ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero); -} - -void -MacroAssemblerMIPSCompat::branchTestDoubleTruthy(bool b, const FloatRegister &value, Label *label) -{ - ma_lid(ScratchFloatReg, 0.0); - DoubleCondition cond = b ? DoubleNotEqual : DoubleEqualOrUnordered; - ma_bc1d(value, ScratchFloatReg, label, cond); -} - -void -MacroAssemblerMIPSCompat::branchTestBooleanTruthy(bool b, const ValueOperand &operand, - Label *label) -{ - ma_b(operand.payloadReg(), operand.payloadReg(), label, b ? NonZero : Zero); -} - Register MacroAssemblerMIPSCompat::extractObject(const Address &address, Register scratch) { @@ -2834,8 +2499,8 @@ void MacroAssemblerMIPSCompat::linkExitFrame() { - uint8_t *dest = (uint8_t*)GetIonContext()->runtime->addressOfIonTop(); - movePtr(ImmPtr(dest), ScratchRegister); + uint8_t *dest = ((uint8_t*)GetIonContext()->compartment->rt) + offsetof(JSRuntime, mainThread.ionTop); + movePtr(ImmWord(dest), ScratchRegister); ma_sw(StackPointer, Address(ScratchRegister, 0)); } @@ -2868,18 +2533,12 @@ } void -MacroAssemblerMIPS::ma_call(ImmPtr dest) +MacroAssemblerMIPS::ma_call(void* dest) { - ma_liPatchable(CallReg, dest); - as_jalr(CallReg); - as_nop(); -} + MOZ_STATIC_ASSERT(sizeof(void*) == 4, "Must be 32 bit arch."); -void -MacroAssemblerMIPS::ma_jump(ImmPtr dest) -{ - ma_liPatchable(ScratchRegister, dest); - as_jr(ScratchRegister); + ma_liPatchable(CallReg, Imm32(reinterpret_cast<uint32_t>(dest))); + as_jalr(CallReg); as_nop(); } @@ -2915,7 +2574,7 @@ passedArgs_ = 0; usedArgSlots_ = 0; - firstArgType = MoveOp::GENERAL; + firstArgType = GENERAL; } void @@ -2940,95 +2599,6 @@ as_sw(scratch, StackPointer, 0); } -void -MacroAssemblerMIPSCompat::passABIArg(const MoveOperand &from, MoveOp::Type type) -{ - ++passedArgs_; - if (!enoughMemory_) - return; - switch (type) { - case MoveOp::FLOAT32: - if (!usedArgSlots_) { - if (from.floatReg() != f12) - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f12), type); - firstArgType = MoveOp::FLOAT32; - } else if ((usedArgSlots_ == 1 && firstArgType == MoveOp::FLOAT32) || - (usedArgSlots_ == 2 && firstArgType == MoveOp::DOUBLE)) { - if (from.floatReg() != f14) - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f14), type); - } else { - Register destReg; - if (GetIntArgReg(usedArgSlots_, &destReg)) { - if (from.isGeneralReg() && from.reg() == destReg) { - // Nothing to do. Value is in the right register already - } else { - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(destReg), type); - } - } else { - uint32_t disp = GetArgStackDisp(usedArgSlots_); - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type); - } - } - usedArgSlots_++; - break; - case MoveOp::DOUBLE: - if (!usedArgSlots_) { - if (from.floatReg() != f12) - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f12), type); - usedArgSlots_ = 2; - firstArgType = MoveOp::DOUBLE; - } else if (usedArgSlots_ <= 2) { - if ((usedArgSlots_ == 1 && firstArgType == MoveOp::FLOAT32) || - (usedArgSlots_ == 2 && firstArgType == MoveOp::DOUBLE)) { - if (from.floatReg() != f14) - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f14), type); - } else { - // Create two moves so that cycles are found. Move emitter - // will have special case to handle this. - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(a2), type); - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(a3), type); - } - usedArgSlots_ = 4; - } else { - // Align if necessary - usedArgSlots_ += usedArgSlots_ % 2; - - uint32_t disp = GetArgStackDisp(usedArgSlots_); - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type); - usedArgSlots_ += 2; - } - break; - case MoveOp::GENERAL: - Register destReg; - if (GetIntArgReg(usedArgSlots_, &destReg)) { - if (from.isGeneralReg() && from.reg() == destReg) { - // Nothing to do. Value is in the right register already - } else { - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(destReg), type); - } - } else { - uint32_t disp = GetArgStackDisp(usedArgSlots_); - enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type); - } - usedArgSlots_++; - break; - default: - MOZ_ASSUME_UNREACHABLE("Unexpected argument type"); - } -} - -void -MacroAssemblerMIPSCompat::passABIArg(const Register ®) -{ - passABIArg(MoveOperand(reg), MoveOp::GENERAL); -} - -void -MacroAssemblerMIPSCompat::passABIArg(const FloatRegister &freg, MoveOp::Type type) -{ - passABIArg(MoveOperand(freg), type); -} - void MacroAssemblerMIPSCompat::checkStackAlignment() { #ifdef DEBUG @@ -3088,7 +2658,7 @@ } void -MacroAssemblerMIPSCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result) +MacroAssemblerMIPSCompat::callWithABIPost(uint32_t stackAdjust, Result result) { // Restore ra value (as stored in callWithABIPre()). ma_lw(ra, Address(StackPointer, stackAdjust - sizeof(intptr_t))); @@ -3107,25 +2677,16 @@ } void -MacroAssemblerMIPSCompat::callWithABI(void *fun, MoveOp::Type result) +MacroAssemblerMIPSCompat::callWithABI(void *fun, Result result) { uint32_t stackAdjust; callWithABIPre(&stackAdjust); - ma_call(ImmPtr(fun)); + ma_call(fun); callWithABIPost(stackAdjust, result); } void -MacroAssemblerMIPSCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result) -{ - uint32_t stackAdjust; - callWithABIPre(&stackAdjust); - call(imm); - callWithABIPost(stackAdjust, result); -} - -void -MacroAssemblerMIPSCompat::callWithABI(const Address &fun, MoveOp::Type result) +MacroAssemblerMIPSCompat::callWithABI(const Address &fun, Result result) { // Load the callee in t9, no instruction between the lw and call // should clobber it. Note that we can't use fun.base because it may @@ -3138,6 +2699,206 @@ } +CodeOffsetLabel +MacroAssemblerMIPSCompat::toggledJump(Label *label) +{ + CodeOffsetLabel ret(nextOffset().getOffset()); + ma_b(label); + return ret; +} + +CodeOffsetLabel +MacroAssemblerMIPSCompat::toggledCall(IonCode *target, bool enabled) +{ + BufferOffset bo = nextOffset(); + CodeOffsetLabel offset(bo.getOffset()); + addPendingJump(bo, target->raw(), Relocation::IONCODE); + ma_liPatchable(ScratchRegister, ImmWord(target->raw())); + if (enabled) { + as_jalr(ScratchRegister); + as_nop(); + } else { + as_nop(); + as_nop(); + } + MOZ_ASSERT(nextOffset().getOffset() - offset.offset() == ToggledCallSize()); + return offset; +} + +void MacroAssemblerMIPSCompat::call(const Register reg) { + as_jalr(reg); + as_nop(); +} + +void MacroAssemblerMIPSCompat::call(Label *label) { + ma_bal(label); +} + +void MacroAssemblerMIPSCompat::call(ImmWord imm) { + // call(imm.asPointer()); + // 31 version converts this to an ImmPtr and then calls that. + BufferOffset bo = m_buffer.nextOffset(); + // addPendingJump(bo, imm, Relocation::HARDCODED); + addPendingJump(bo, imm.asPointer(), Relocation::HARDCODED); + ma_call(imm.asPointer()); +} + +void +MacroAssemblerMIPSCompat::call(IonCode *c) { + BufferOffset bo = m_buffer.nextOffset(); + addPendingJump(bo, c->raw(), Relocation::IONCODE); + ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); + ma_callIonHalfPush(ScratchRegister); +} + +void +MacroAssemblerMIPSCompat::storePtr(Register src, const BaseIndex& address) +{ + ma_store(src, address, SizeWord); +} + +void +MacroAssemblerMIPSCompat::testUndefinedSet(Condition cond, const ValueOperand& value, Register dest) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_cmp_set(dest, value.typeReg(), ImmType(JSVAL_TYPE_UNDEFINED), cond); +} + +void +MacroAssemblerMIPSCompat::testNullSet(Condition cond, const ValueOperand& value, Register dest) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_cmp_set(dest, value.typeReg(), ImmType(JSVAL_TYPE_NULL), cond); +} + +void +MacroAssemblerMIPSCompat::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore) +{ + // int32_t diffG = set.gprs().size() * sizeof(intptr_t); + int32_t diffG = set.gprs().size() * STACK_SLOT_SIZE; + int32_t diffF = set.fpus().size() * sizeof(double); + const int32_t reservedG = diffG; + const int32_t reservedF = diffF; + + // Read the buffer form the first aligned location. + ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double))); + ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(StackAlignment - 1))); + + for (FloatRegisterIterator iter(set.fpus()); iter.more(); iter++) { + // :TODO: (Bug 972836) Fix this once odd regs can be used as + // float32 only. For now we skip loading odd regs for O32 ABI. + + // :TODO: (Bug 985881) Make a switch for N32 ABI. + if (!ignore.has(*iter) && ((*iter).code() % 2 == 0)) { + // Use assembly l.d because we have alligned the stack. + as_ld(*iter, SecondScratchReg, -diffF); + } + diffF -= sizeof(double); + } + freeStack(reservedF + sizeof(double)); + MOZ_ASSERT(diffF == 0); + + for (GeneralRegisterIterator iter(set.gprs()); iter.more(); iter++) { + diffG -= STACK_SLOT_SIZE; + if (!ignore.has(*iter)) { + loadPtr(Address(StackPointer, diffG), *iter); + } + } + + freeStack(reservedG); + + MOZ_ASSERT(diffG == 0); +} + +void +MacroAssemblerMIPSCompat::passABIArg(const MoveOperand &from) +{ + ++passedArgs_; + if (!enoughMemory_) + { + return; + } + + if (from.isDouble()) + { + Move::Kind type = Move::Kind::DOUBLE; + + if (!usedArgSlots_) + { + if (from.floatReg() != f12) + { + enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f12), type); + } + usedArgSlots_ = 2; + firstArgType = DOUBLE; + } + else if (usedArgSlots_ <= 2) + { + if ((usedArgSlots_ == 1 && false) || + (usedArgSlots_ == 2 && firstArgType == DOUBLE)) + { + if (from.floatReg() != f14) + { + enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f14), type); + } + } + else + { + // Create two moves so that cycles are found. Move emitter + // will have special case to handle this. + enoughMemory_ = moveResolver_.addMove(from, MoveOperand(a2), type); + enoughMemory_ = moveResolver_.addMove(from, MoveOperand(a3), type); + } + usedArgSlots_ = 4; + } + else + { + // Align if necessary + usedArgSlots_ += usedArgSlots_ % 2; + + uint32_t disp = GetArgStackDisp(usedArgSlots_); + enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type); + usedArgSlots_ += 2; + } + } + else + { + Move::Kind type = Move::Kind::GENERAL; + + Register destReg; + if (GetIntArgReg(usedArgSlots_, &destReg)) + { + if (from.isGeneralReg() && from.reg() == destReg) + { + // Nothing to do. Value is in the right register already + } + else + { + enoughMemory_ = moveResolver_.addMove(from, MoveOperand(destReg), type); + } + } + else + { + uint32_t disp = GetArgStackDisp(usedArgSlots_); + enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type); + } + usedArgSlots_++; + + } +} + +void +MacroAssemblerMIPSCompat::passABIArg(const Register ®) +{ + passABIArg(MoveOperand(reg)); +} + +void +MacroAssemblerMIPSCompat::passABIArg(const FloatRegister &freg) +{ + passABIArg(MoveOperand(freg)); +} + void MacroAssemblerMIPSCompat::handleFailureWithHandler(void *handler) { @@ -3151,7 +2912,7 @@ passABIArg(a0); callWithABI(handler); - JitCode *excTail = GetIonContext()->runtime->jitRuntime()->getExceptionTail(); + IonCode* excTail = GetIonContext()->runtime->ionRuntime()->getExceptionTail(); branch(excTail); } @@ -3170,7 +2931,7 @@ branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_CATCH), &catch_); branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_FINALLY), &finally); branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_); - branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout); + // branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout); breakpoint(); // Invalid kind. @@ -3221,53 +2982,83 @@ // If we are bailing out to baseline to handle an exception, jump to // the bailout tail stub. - bind(&bailout); - ma_lw(a2, Address(sp, offsetof(ResumeFromException, bailoutInfo))); - ma_li(ReturnReg, Imm32(BAILOUT_RETURN_OK)); - ma_lw(a1, Address(sp, offsetof(ResumeFromException, target))); - jump(a1); + // bind(&bailout); + // ma_lw(a2, Address(sp, offsetof(ResumeFromException, bailoutInfo))); + // ma_li(ReturnReg, Imm32(BAILOUT_RETURN_OK)); + // ma_lw(a1, Address(sp, offsetof(ResumeFromException, target))); + // jump(a1); } -CodeOffsetLabel -MacroAssemblerMIPSCompat::toggledJump(Label *label) +void MacroAssemblerMIPS::ma_mod_mask(Register src, Register dest, Register hold, int32_t shift, Label *negZero) { - CodeOffsetLabel ret(nextOffset().getOffset()); - ma_b(label); - return ret; -} + // MATH: + // We wish to compute x % (1<<y) - 1 for a known constant, y. + // First, let b = (1<<y) and C = (1<<y)-1, then think of the 32 bit + // dividend as a number in base b, namely + // c_0*1 + c_1*b + c_2*b^2 ... c_n*b^n + // now, since both addition and multiplication commute with modulus, + // x % C == (c_0 + c_1*b + ... + c_n*b^n) % C == + // (c_0 % C) + (c_1%C) * (b % C) + (c_2 % C) * (b^2 % C)... + // now, since b == C + 1, b % C == 1, and b^n % C == 1 + // this means that the whole thing simplifies to: + // c_0 + c_1 + c_2 ... c_n % C + // each c_n can easily be computed by a shift/bitextract, and the modulus + // can be maintained by simply subtracting by C whenever the number gets + // over C. + int32_t mask = (1 << shift) - 1; + Label head, negative, sumSigned, done; -CodeOffsetLabel -MacroAssemblerMIPSCompat::toggledCall(JitCode *target, bool enabled) -{ - BufferOffset bo = nextOffset(); - CodeOffsetLabel offset(bo.getOffset()); - addPendingJump(bo, ImmPtr(target->raw()), Relocation::JITCODE); - ma_liPatchable(ScratchRegister, ImmPtr(target->raw())); - if (enabled) { - as_jalr(ScratchRegister); - as_nop(); + // hold holds -1 if the value was negative, 1 otherwise. + // ScratchRegister holds the remaining bits that have not been processed + // lr serves as a temporary location to store extracted bits into as well + // as holding the trial subtraction as a temp value dest is the + // accumulator (and holds the final result) + + // move the whole value into the scratch register, setting the codition + // codes so we can muck with them later. + ma_move(ScratchRegister, src); + // Zero out the dest. + ma_subu(dest, dest, dest); + // Set the hold appropriately. + ma_b(ScratchRegister, ScratchRegister, &negative, Signed, ShortJump); + ma_li(hold, Imm32(1)); + ma_b(&head, ShortJump); + + bind(&negative); + ma_li(hold, Imm32(-1)); + ma_negu(ScratchRegister, ScratchRegister); + + // Begin the main loop. + bind(&head); + + // Extract the bottom bits into lr. + ma_and(SecondScratchReg, ScratchRegister, Imm32(mask)); + // Add those bits to the accumulator. + as_addu(dest, dest, SecondScratchReg); + // Do a trial subtraction, this is the same operation as cmp, but we + // store the dest + ma_subu(SecondScratchReg, dest, Imm32(mask)); + // If (sum - C) > 0, store sum - C back into sum, thus performing a + // modulus. + ma_b(SecondScratchReg, SecondScratchReg, &sumSigned, Signed, ShortJump); + ma_move(dest, SecondScratchReg); + bind(&sumSigned); + // Get rid of the bits that we extracted before. + as_srl(ScratchRegister, ScratchRegister, shift); + // If the shift produced zero, finish, otherwise, continue in the loop. + ma_b(ScratchRegister, ScratchRegister, &head, NonZero, ShortJump); + // Check the hold to see if we need to negate the result. + ma_b(hold, hold, &done, NotSigned, ShortJump); + + // If the hold was non-zero, negate the result to be in line with + // what JS wants + if (negZero != nullptr) { + // Jump out in case of negative zero. + ma_b(hold, hold, negZero, Zero); + ma_negu(dest, dest); } else { - as_nop(); - as_nop(); + ma_negu(dest, dest); } - MOZ_ASSERT(nextOffset().getOffset() - offset.offset() == ToggledCallSize()); - return offset; -} -void -MacroAssemblerMIPSCompat::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) -{ - JS_ASSERT(temp != InvalidReg); - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); - - // ptr and temp may be the same register, in which case we mustn't trash it - // before we use its contents. - if (ptr == temp) { - addPtr(ImmWord(-ptrdiff_t(nursery.start())), ptr); - branchPtr(Assembler::Below, ptr, Imm32(Nursery::NurserySize), label); - } else { - movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - addPtr(ptr, temp); - branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); - } + bind(&done); }
diff --git a/src/third_party/mozjs/js/src/jit/mips/MacroAssembler-mips.h b/src/third_party/mozjs/js/src/jit/mips/MacroAssembler-mips.h index ed1f566..47c306b 100644 --- a/src/third_party/mozjs/js/src/jit/mips/MacroAssembler-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/MacroAssembler-mips.h
@@ -61,24 +61,17 @@ class MacroAssemblerMIPS : public Assembler { public: - void convertBoolToInt32(Register source, Register dest); void convertInt32ToDouble(const Register &src, const FloatRegister &dest); void convertInt32ToDouble(const Address &src, FloatRegister dest); void convertUInt32ToDouble(const Register &src, const FloatRegister &dest); - void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest); - void convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest); + void convertDoubleToFloat(const FloatRegister &src, const FloatRegister &dest) { + as_cvtsd(dest, src); + } + void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail); void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail, bool negativeZeroCheck = true); - void convertFloat32ToInt32(const FloatRegister &src, const Register &dest, Label *fail, - bool negativeZeroCheck = true); - - void convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest); - void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail); - void convertInt32ToFloat32(const Register &src, const FloatRegister &dest); - void convertInt32ToFloat32(const Address &src, FloatRegister dest); - void addDouble(FloatRegister src, FloatRegister dest); void subDouble(FloatRegister src, FloatRegister dest); @@ -98,7 +91,7 @@ void ma_li(Register dest, Imm32 imm); void ma_liPatchable(Register dest, Imm32 imm); - void ma_liPatchable(Register dest, ImmPtr imm); + void ma_liPatchable(Register dest, ImmWord imm); // Shift operations void ma_sll(Register rd, Register rt, Imm32 shift); @@ -190,7 +183,7 @@ // fast mod, uses scratch registers, and thus needs to be in the assembler // implicitly assumes that we can overwrite dest at the beginning of the sequence void ma_mod_mask(Register src, Register dest, Register hold, int32_t shift, - Label *negZero = nullptr); + Label *negZero = NULL); // memory // shortcut for when we know we're transferring 32 bits of data @@ -210,6 +203,24 @@ void ma_b(Label *l, JumpKind jumpKind = LongJump); void ma_bal(Label *l, JumpKind jumpKind = LongJump); + void ma_b(Register lhs, ImmWord imm, Label* l, Condition c, JumpKind jumpKind = LongJump) { + ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind); + } + void ma_b(Address addr, Register rhs, Label* l, Condition c, JumpKind jumpKind = LongJump) { + MOZ_ASSERT(rhs != ScratchRegister); + ma_lw(ScratchRegister, addr); + ma_b(ScratchRegister, rhs, l, c, jumpKind); + } + void ma_b(Register lhs, ImmGCPtr imm, Label* l, Condition c, JumpKind jumpKind = LongJump) { + MOZ_ASSERT(lhs != ScratchRegister); + ma_li(ScratchRegister, imm); + ma_b(lhs, ScratchRegister, l, c, jumpKind); + } + void ma_b(Address addr, ImmGCPtr imm, Label* l, Condition c, JumpKind jumpKind = LongJump) { + ma_lw(SecondScratchReg, addr); + ma_b(SecondScratchReg, imm, l, c, jumpKind); + } + // fp instructions void ma_lis(FloatRegister dest, float value); void ma_lid(FloatRegister dest, double value); @@ -268,7 +279,7 @@ DoubleCondition c, FloatTestKind *testKind, FPConditionBit fcc = FCC0); - public: +public: // calls an Ion function, assumes that the stack is untouched (8 byte alinged) void ma_callIon(const Register reg); // callso an Ion function, assuming that sp has already been decremented @@ -276,9 +287,9 @@ // calls an ion function, assuming that the stack is currently not 8 byte aligned void ma_callIonHalfPush(const Register reg); - void ma_call(ImmPtr dest); + void ma_call(void* dest); - void ma_jump(ImmPtr dest); + void ma_jump(ImmWord dest); void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c); void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c); @@ -286,10 +297,28 @@ void ma_cmp_set(Register dst, Address lhs, Register imm, Condition c); void ma_cmp_set_double(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c); void ma_cmp_set_float32(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c); + + void ma_cmp_set(Register dst, Register lhs, ImmWord imm, Condition c) { + ma_cmp_set(dst, lhs, Imm32(uint32_t(imm.value)), c); + } + void ma_cmp_set(Register dst, Address lhs, ImmWord imm, Condition c) { + ma_lw(ScratchRegister, lhs); + ma_li(SecondScratchReg, Imm32(uint32_t(imm.value))); + ma_cmp_set(dst, ScratchRegister, SecondScratchReg, c); + } }; class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS { +public: + typedef MoveResolver::MoveOperand MoveOperand; + typedef MoveResolver::Move Move; + + enum Result { + GENERAL, + DOUBLE + }; + // Number of bytes the stack is adjusted inside a call to C. Calls to C may // not be nested. bool inCall_; @@ -299,7 +328,7 @@ uint32_t passedArgs_; uint32_t usedArgSlots_; - MoveOp::Type firstArgType; + Result firstArgType; bool dynamicAlignment_; @@ -346,47 +375,24 @@ void mov(ImmWord imm, Register dest) { ma_li(dest, Imm32(imm.value)); } - void mov(ImmPtr imm, Register dest) { - mov(ImmWord(uintptr_t(imm.value)), dest); + void mov(Imm32 imm, Register dest) { + mov(ImmWord(imm.value), dest); } void mov(Register src, Address dest) { - MOZ_ASSUME_UNREACHABLE("NYI-IC"); + JS_NOT_REACHED("NYI-IC"); } void mov(Address src, Register dest) { - MOZ_ASSUME_UNREACHABLE("NYI-IC"); + JS_NOT_REACHED("NYI-IC"); } - void call(const Register reg) { - as_jalr(reg); - as_nop(); - } - - void call(Label *label) { - // for now, assume that it'll be nearby? - ma_bal(label); - } - - void call(ImmWord imm) { - call(ImmPtr((void*)imm.value)); - } - void call(ImmPtr imm) { + void call(const Register reg); + void call(Label *label); + void call(Imm32 imm); + void call(ImmWord imm); + void call(IonCode *c); + void branch(IonCode *c) { BufferOffset bo = m_buffer.nextOffset(); - addPendingJump(bo, imm, Relocation::HARDCODED); - ma_call(imm); - } - void call(AsmJSImmPtr imm) { - movePtr(imm, CallReg); - call(CallReg); - } - void call(JitCode *c) { - BufferOffset bo = m_buffer.nextOffset(); - addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); - ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); - ma_callIonHalfPush(ScratchRegister); - } - void branch(JitCode *c) { - BufferOffset bo = m_buffer.nextOffset(); - addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); + addPendingJump(bo, c->raw(), Relocation::IONCODE); ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); as_jr(ScratchRegister); as_nop(); @@ -422,22 +428,12 @@ ma_li(ScratchRegister, imm); ma_push(ScratchRegister); } - void push(const Address &address) { - ma_lw(ScratchRegister, address); - ma_push(ScratchRegister); - } void push(const Register ®) { ma_push(reg); } - void push(const FloatRegister ®) { - ma_push(reg); - } void pop(const Register ®) { ma_pop(reg); } - void pop(const FloatRegister ®) { - ma_pop(reg); - } // Emit a branch that can be toggled to a non-operation. On MIPS we use // "andi" instruction to toggle the branch. @@ -446,7 +442,7 @@ // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch // this instruction. - CodeOffsetLabel toggledCall(JitCode *target, bool enabled); + CodeOffsetLabel toggledCall(IonCode *target, bool enabled); static size_t ToggledCallSize() { // Four instructions used in: MacroAssemblerMIPSCompat::toggledCall @@ -464,9 +460,6 @@ ma_liPatchable(dest, Imm32(imm.value)); return label; } - CodeOffsetLabel movWithPatch(ImmPtr imm, Register dest) { - return movWithPatch(ImmWord(uintptr_t(imm.value)), dest); - } void jump(Label *label) { ma_b(label); @@ -475,11 +468,6 @@ as_jr(reg); as_nop(); } - void jump(const Address &address) { - ma_lw(ScratchRegister, address); - as_jr(ScratchRegister); - as_nop(); - } void neg32(Register reg) { ma_negu(reg, reg); @@ -510,9 +498,6 @@ void unboxBoolean(const Address &src, const Register &dest); void unboxDouble(const ValueOperand &operand, const FloatRegister &dest); void unboxDouble(const Address &src, const FloatRegister &dest); - void unboxString(const ValueOperand &operand, const Register &dest); - void unboxString(const Address &src, const Register &dest); - void unboxObject(const ValueOperand &src, const Register &dest); void unboxValue(const ValueOperand &src, AnyRegister dest); void unboxPrivate(const ValueOperand &src, Register dest); @@ -548,17 +533,41 @@ void loadInt32OrDouble(const Address &address, const FloatRegister &dest); void loadInt32OrDouble(Register base, Register index, const FloatRegister &dest, int32_t shift = defaultShift); + void loadStaticDouble(const double *dp, const FloatRegister &dest) { + loadConstantDouble(*dp, dest); + } void loadConstantDouble(double dp, const FloatRegister &dest); - void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest); - void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest); - void loadConstantFloat32(float f, const FloatRegister &dest); - void branchTestInt32(Condition cond, const ValueOperand &value, Label *label); void branchTestInt32(Condition cond, const Register &tag, Label *label); void branchTestInt32(Condition cond, const Address &address, Label *label); void branchTestInt32(Condition cond, const BaseIndex &src, Label *label); + void branchTestInt32Truthy(bool b, const ValueOperand& value, Label* label) { + ma_and(ScratchRegister, value.payloadReg(), value.payloadReg()); + ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero); + } + + void branchTestStringTruthy(bool b, const ValueOperand& value, Label* label) { + Register string = value.payloadReg(); + size_t mask = (0xFFFFFFFF << JSString::LENGTH_SHIFT); + ma_lw(SecondScratchReg, Address(string, JSString::offsetOfLengthAndFlags())); + + // Use SecondScratchReg because ma_and will clobber ScratchRegister + ma_and(ScratchRegister, SecondScratchReg, Imm32(mask)); + ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero); + } + + void branchTestDoubleTruthy(bool b, FloatRegister value, Label* label) { + ma_lid(ScratchFloatReg, 0.0); + DoubleCondition cond = b ? DoubleNotEqual : DoubleEqualOrUnordered; + ma_bc1d(value, ScratchFloatReg, label, cond); + } + + void branchTestBooleanTruthy(bool b, const ValueOperand& operand, Label* label) { + ma_b(operand.payloadReg(), operand.payloadReg(), label, b ? NonZero : Zero); + } + void branchTestBoolean(Condition cond, const ValueOperand &value, Label *label); void branchTestBoolean(Condition cond, const Register &tag, Label *label); void branchTestBoolean(Condition cond, const BaseIndex &src, Label *label); @@ -595,7 +604,7 @@ branch32(cond, lhs, rhs, label); } - void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) { + void branchPrivatePtr(Condition cond, const Address &lhs, ImmWord ptr, Label *label) { branchPtr(cond, lhs, ptr, label); } @@ -639,7 +648,7 @@ void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why, Label *label) { - MOZ_ASSERT(cond == Equal || cond == NotEqual); + JS_ASSERT(cond == Equal || cond == NotEqual); // Test for magic Label notmagic; branchTestMagic(cond, val, ¬magic); @@ -648,16 +657,8 @@ bind(¬magic); } - void branchTestInt32Truthy(bool b, const ValueOperand &value, Label *label); - - void branchTestStringTruthy(bool b, const ValueOperand &value, Label *label); - - void branchTestDoubleTruthy(bool b, const FloatRegister &value, Label *label); - - void branchTestBooleanTruthy(bool b, const ValueOperand &operand, Label *label); - void branchTest32(Condition cond, const Register &lhs, const Register &rhs, Label *label) { - MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned); + JS_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned); if (lhs == rhs) { ma_b(lhs, rhs, label, cond); } else { @@ -692,13 +693,7 @@ void branchPtr(Condition cond, Register lhs, ImmWord imm, Label *label) { ma_b(lhs, Imm32(imm.value), label, cond); } - void branchPtr(Condition cond, Register lhs, ImmPtr imm, Label *label) { - branchPtr(cond, lhs, ImmWord(uintptr_t(imm.value)), label); - } - void branchPtr(Condition cond, Register lhs, AsmJSImmPtr imm, Label *label) { - movePtr(imm, ScratchRegister); - branchPtr(cond, lhs, ScratchRegister, label); - } + void branchPtr(Condition cond, Register lhs, Imm32 imm, Label *label) { ma_b(lhs, imm, label, cond); } @@ -744,18 +739,16 @@ ma_lw(SecondScratchReg, addr); ma_b(SecondScratchReg, Imm32(ptr.value), label, cond); } - void branchPtr(Condition cond, Address addr, ImmPtr ptr, Label *label) { + + void branchPtr(Condition cond, Address addr, Imm32 ptr, Label *label) { branchPtr(cond, addr, ImmWord(uintptr_t(ptr.value)), label); } + void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) { loadPtr(addr, ScratchRegister); ma_b(ScratchRegister, ptr, label, cond); } - void branchPtr(Condition cond, const AsmJSAbsoluteAddress &addr, const Register &ptr, - Label *label) { - loadPtr(addr, ScratchRegister); - ma_b(ScratchRegister, ptr, label, cond); - } + void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) { loadPtr(lhs, SecondScratchReg); // ma_b might use scratch ma_b(SecondScratchReg, rhs, label, cond); @@ -782,8 +775,8 @@ void moveValue(const Value &val, const ValueOperand &dest); void moveValue(const ValueOperand &src, const ValueOperand &dest) { - MOZ_ASSERT(src.typeReg() != dest.payloadReg()); - MOZ_ASSERT(src.payloadReg() != dest.typeReg()); + JS_ASSERT(src.typeReg() != dest.payloadReg()); + JS_ASSERT(src.payloadReg() != dest.typeReg()); if (src.typeReg() != dest.typeReg()) ma_move(dest.typeReg(), src.typeReg()); if (src.payloadReg() != dest.payloadReg()) @@ -820,14 +813,6 @@ ma_push(reg); } void pushValue(const Address &addr); - void Push(const ValueOperand &val) { - pushValue(val); - framePushed_ += sizeof(Value); - } - void Pop(const ValueOperand &val) { - popValue(val); - framePushed_ -= sizeof(Value); - } void storePayload(const Value &val, Address dest); void storePayload(Register src, Address dest); void storePayload(const Value &val, Register base, Register index, int32_t shift = defaultShift); @@ -852,25 +837,22 @@ // The following functions are exposed for use in platform-shared code. void Push(const Register ®) { ma_push(reg); - adjustFrame(sizeof(intptr_t)); + adjustFrame(STACK_SLOT_SIZE); } void Push(const Imm32 imm) { ma_li(ScratchRegister, imm); ma_push(ScratchRegister); - adjustFrame(sizeof(intptr_t)); + adjustFrame(STACK_SLOT_SIZE); } void Push(const ImmWord imm) { ma_li(ScratchRegister, Imm32(imm.value)); ma_push(ScratchRegister); - adjustFrame(sizeof(intptr_t)); - } - void Push(const ImmPtr imm) { - Push(ImmWord(uintptr_t(imm.value))); + adjustFrame(STACK_SLOT_SIZE); } void Push(const ImmGCPtr ptr) { ma_li(ScratchRegister, ptr); ma_push(ScratchRegister); - adjustFrame(sizeof(intptr_t)); + adjustFrame(STACK_SLOT_SIZE); } void Push(const FloatRegister &f) { ma_push(f); @@ -881,16 +863,18 @@ framePushed_ += sizeof(word.value); return pushWithPatch(word); } - CodeOffsetLabel PushWithPatch(const ImmPtr &imm) { + + CodeOffsetLabel PushWithPatch(const Imm32 &imm) + { return PushWithPatch(ImmWord(uintptr_t(imm.value))); } void Pop(const Register ®) { ma_pop(reg); - adjustFrame(-sizeof(intptr_t)); + adjustFrame(-STACK_SLOT_SIZE); } void implicitPop(uint32_t args) { - MOZ_ASSERT(args % sizeof(intptr_t) == 0); + JS_ASSERT(args % STACK_SLOT_SIZE == 0); adjustFrame(-args); } uint32_t framePushed() const { @@ -904,8 +888,8 @@ // non-function. Returns offset to be passed to markSafepointAt(). bool buildFakeExitFrame(const Register &scratch, uint32_t *offset); - void callWithExitFrame(JitCode *target); - void callWithExitFrame(JitCode *target, Register dynStack); + void callWithExitFrame(IonCode *target); + void callWithExitFrame(IonCode *target, Register dynStack); // Makes an Ion call using the only two methods that it is sane for // indep code to make a call @@ -941,8 +925,6 @@ void movePtr(const Register &src, const Register &dest); void movePtr(const ImmWord &imm, const Register &dest); - void movePtr(const ImmPtr &imm, const Register &dest); - void movePtr(const AsmJSImmPtr &imm, const Register &dest); void movePtr(const ImmGCPtr &imm, const Register &dest); void load8SignExtend(const Address &address, const Register &dest); @@ -960,11 +942,11 @@ void load32(const Address &address, const Register &dest); void load32(const BaseIndex &address, const Register &dest); void load32(const AbsoluteAddress &address, const Register &dest); + void load32(Operand&, Register); void loadPtr(const Address &address, const Register &dest); void loadPtr(const BaseIndex &src, const Register &dest); void loadPtr(const AbsoluteAddress &address, const Register &dest); - void loadPtr(const AsmJSAbsoluteAddress &address, const Register &dest); void loadPrivate(const Address &address, const Register &dest); @@ -975,9 +957,6 @@ void loadFloatAsDouble(const Address &addr, const FloatRegister &dest); void loadFloatAsDouble(const BaseIndex &src, const FloatRegister &dest); - void loadFloat32(const Address &addr, const FloatRegister &dest); - void loadFloat32(const BaseIndex &src, const FloatRegister &dest); - void store8(const Register &src, const Address &address); void store8(const Imm32 &imm, const Address &address); void store8(const Register &src, const BaseIndex &address); @@ -992,29 +971,35 @@ void store32(const Register &src, const Address &address); void store32(const Register &src, const BaseIndex &address); void store32(const Imm32 &src, const Address &address); - void store32(const Imm32 &src, const BaseIndex &address); + void store32(const Imm32 &src, const BaseIndex &address) { + move32(src, ScratchRegister); + storePtr(ScratchRegister, address); + } void storePtr(ImmWord imm, const Address &address); - void storePtr(ImmPtr imm, const Address &address); void storePtr(ImmGCPtr imm, const Address &address); void storePtr(Register src, const Address &address); void storePtr(const Register &src, const AbsoluteAddress &dest); + void storePtr(Register src, const BaseIndex& address); + void storeDouble(FloatRegister src, Address addr) { ma_sd(src, addr); } void storeDouble(FloatRegister src, BaseIndex addr) { - MOZ_ASSERT(addr.offset == 0); + JS_ASSERT(addr.offset == 0); ma_sd(src, addr); } - void moveDouble(FloatRegister src, FloatRegister dest) { + void storeDouble(const FloatRegister&, Operand); + void moveDouble(FloatRegister src, FloatRegister dest) + { as_movd(dest, src); } - void storeFloat32(FloatRegister src, Address addr) { + void storeFloat(FloatRegister src, Address addr) { ma_ss(src, addr); } - void storeFloat32(FloatRegister src, BaseIndex addr) { - MOZ_ASSERT(addr.offset == 0); + void storeFloat(FloatRegister src, BaseIndex addr) { + JS_ASSERT(addr.offset == 0); ma_ss(src, addr); } @@ -1023,7 +1008,8 @@ moveToDoubleHi(zero, reg); } - void clampIntToUint8(Register reg) { + void clampIntToUint8(Register reg, Register dest) + { // look at (reg >> 8) if it is 0, then src shouldn't be clamped // if it is <0, then we want to clamp to 0, // otherwise, we wish to clamp to 255 @@ -1047,23 +1033,17 @@ } void subPtr(Imm32 imm, const Register dest); - void addPtr(Imm32 imm, const Register dest); void addPtr(Imm32 imm, const Address &dest); void addPtr(ImmWord imm, const Register dest) { addPtr(Imm32(imm.value), dest); } - void addPtr(ImmPtr imm, const Register dest) { - addPtr(ImmWord(uintptr_t(imm.value)), dest); - } + void addPtr(Imm32 imm, const Register dest); void breakpoint(); void branchDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs, Label *label); - void branchFloat(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs, - Label *label); - void checkStackAlignment(); void alignPointerUp(Register src, Register dest, uint32_t alignment); @@ -1097,55 +1077,93 @@ // automatically adjusted. It is extremely important that sp-relative // addresses are computed *after* setupABICall(). Furthermore, no // operations should be emitted while setting arguments. - void passABIArg(const MoveOperand &from, MoveOp::Type type); - void passABIArg(const Register ®); - void passABIArg(const FloatRegister ®, MoveOp::Type type); - void passABIArg(const ValueOperand ®s); - protected: - bool buildOOLFakeExitFrame(void *fakeReturnAddr); + void passABIArg(const MoveOperand& from); + void passABIArg(const Register& reg); + void passABIArg(const FloatRegister& reg); + void passABIArg(const ValueOperand& regs); + + bool buildOOLFakeExitFrame(void* fakeReturnAddr); private: void callWithABIPre(uint32_t *stackAdjust); - void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result); + // void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result); + void callWithABIPost(uint32_t stackAdjust, Result result); public: // Emits a call to a C/C++ function, resolving all argument moves. - void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL); - void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL); - void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL); + void callWithABI(void *fun, Result result = GENERAL); + void callWithABI(const Address &fun, Result result = GENERAL); CodeOffsetLabel labelForPatch() { return CodeOffsetLabel(nextOffset().getOffset()); } - void memIntToValue(Address Source, Address Dest) { - MOZ_ASSUME_UNREACHABLE("NYI"); - } - - void lea(Operand addr, Register dest) { - MOZ_ASSUME_UNREACHABLE("NYI"); - } - - void abiret() { - MOZ_ASSUME_UNREACHABLE("NYI"); - } - void ma_storeImm(Imm32 imm, const Address &addr) { ma_sw(imm, addr); } + void lea(Operand addr, Register dest) { + ma_addu(dest, addr.baseReg(), Imm32(addr.disp())); + } + + void abiret() { + as_jr(ra); + as_nop(); + } + + void memIntToValue(Address Source, Address Dest) { + load32(Source, SecondScratchReg); + storeValue(JSVAL_TYPE_INT32, SecondScratchReg, Dest); + } + + template <typename T1, typename T2> + void cmp32Set(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest) + { + ma_cmp_set(dest, lhs, rhs, cond); + } + + template <typename T1, typename T2> + void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest) + { + ma_cmp_set(dest, lhs, rhs, cond); + } + + void testNullSet(Condition cond, const ValueOperand& value, Register dest); + void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest); + template <typename T> + void branchAdd32(Condition cond, T src, Register dest, Label* overflow) { + switch (cond) { + case Overflow: + ma_addTestOverflow(dest, dest, src, overflow); + break; + default: + JS_NOT_REACHED("NYI"); + } + } + template <typename T> + void branchSub32(Condition cond, T src, Register dest, Label* overflow) { + switch (cond) { + case Overflow: + ma_subTestOverflow(dest, dest, src, overflow); + break; + case NonZero: + case Zero: + sub32(src, dest); + ma_b(dest, dest, overflow, cond); + break; + default: + JS_NOT_REACHED("NYI"); + } + } + + void PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore); + BufferOffset ma_BoundsCheck(Register bounded) { BufferOffset bo = m_buffer.nextOffset(); ma_liPatchable(bounded, Imm32(0)); return bo; } - - void moveFloat32(FloatRegister src, FloatRegister dest) { - as_movs(dest, src); - } - - void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); }; typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific;
diff --git a/src/third_party/mozjs/js/src/jit/mips/MoveEmitter-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/MoveEmitter-mips.cpp index 12864b0..00cfd22 100644 --- a/src/third_party/mozjs/js/src/jit/mips/MoveEmitter-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/MoveEmitter-mips.cpp
@@ -72,7 +72,7 @@ } void -MoveEmitterMIPS::breakCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type) +MoveEmitterMIPS::breakCycle(const MoveOperand &from, const MoveOperand &to, Move::Kind kind) { // There is some pattern: // (A -> B) @@ -80,17 +80,8 @@ // // This case handles (A -> B), which we reach first. We save B, then allow // the original move to continue. - switch (type) { - case MoveOp::FLOAT32: - if (to.isMemory()) { - FloatRegister temp = ScratchFloatReg; - masm.loadFloat32(getAdjustedAddress(to), temp); - masm.storeFloat32(temp, cycleSlot()); - } else { - masm.storeFloat32(to.floatReg(), cycleSlot()); - } - break; - case MoveOp::DOUBLE: + switch (kind) { + case Move::DOUBLE: if (to.isMemory()) { FloatRegister temp = ScratchFloatReg; masm.loadDouble(getAdjustedAddress(to), temp); @@ -99,9 +90,7 @@ masm.storeDouble(to.floatReg(), cycleSlot()); } break; - case MoveOp::INT32: - MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t)); - case MoveOp::GENERAL: + case Move::GENERAL: if (to.isMemory()) { Register temp = tempReg(); masm.loadPtr(getAdjustedAddress(to), temp); @@ -113,12 +102,12 @@ } break; default: - MOZ_ASSUME_UNREACHABLE("Unexpected move type"); + JS_NOT_REACHED("Unexpected move type"); } } void -MoveEmitterMIPS::completeCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type) +MoveEmitterMIPS::completeCycle(const MoveOperand &from, const MoveOperand &to, Move::Kind kind) { // There is some pattern: // (A -> B) @@ -126,17 +115,8 @@ // // This case handles (B -> A), which we reach last. We emit a move from the // saved value of B, to A. - switch (type) { - case MoveOp::FLOAT32: - if (to.isMemory()) { - FloatRegister temp = ScratchFloatReg; - masm.loadFloat32(cycleSlot(), temp); - masm.storeFloat32(temp, getAdjustedAddress(to)); - } else { - masm.loadFloat32(cycleSlot(), to.floatReg()); - } - break; - case MoveOp::DOUBLE: + switch (kind) { + case Move::DOUBLE: if (to.isMemory()) { FloatRegister temp = ScratchFloatReg; masm.loadDouble(cycleSlot(), temp); @@ -145,9 +125,7 @@ masm.loadDouble(cycleSlot(), to.floatReg()); } break; - case MoveOp::INT32: - MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t)); - case MoveOp::GENERAL: + case Move::GENERAL: if (to.isMemory()) { Register temp = tempReg(); masm.loadPtr(cycleSlot(), temp); @@ -159,7 +137,7 @@ } break; default: - MOZ_ASSUME_UNREACHABLE("Unexpected move type"); + JS_NOT_REACHED("Unexpected move type"); } } @@ -175,7 +153,7 @@ else if (to.isMemory()) masm.storePtr(from.reg(), getAdjustedAddress(to)); else - MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments."); + JS_NOT_REACHED("Invalid emitMove arguments."); } else if (from.isMemory()) { if (to.isGeneralReg()) { masm.loadPtr(getAdjustedAddress(from), to.reg()); @@ -183,7 +161,7 @@ masm.loadPtr(getAdjustedAddress(from), tempReg()); masm.storePtr(tempReg(), getAdjustedAddress(to)); } else { - MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments."); + JS_NOT_REACHED("Invalid emitMove arguments."); } } else if (from.isEffectiveAddress()) { if (to.isGeneralReg()) { @@ -192,44 +170,10 @@ masm.computeEffectiveAddress(getAdjustedAddress(from), tempReg()); masm.storePtr(tempReg(), getAdjustedAddress(to)); } else { - MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments."); + JS_NOT_REACHED("Invalid emitMove arguments."); } } else { - MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments."); - } -} - -void -MoveEmitterMIPS::emitFloat32Move(const MoveOperand &from, const MoveOperand &to) -{ - // Ensure that we can use ScratchFloatReg in memory move. - MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloatReg); - MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloatReg); - - if (from.isFloatReg()) { - if (to.isFloatReg()) { - masm.moveFloat32(from.floatReg(), to.floatReg()); - } else if (to.isGeneralReg()) { - // This should only be used when passing float parameter in a1,a2,a3 - MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); - masm.moveFromFloat32(from.floatReg(), to.reg()); - } else { - MOZ_ASSERT(to.isMemory()); - masm.storeFloat32(from.floatReg(), getAdjustedAddress(to)); - } - } else if (to.isFloatReg()) { - MOZ_ASSERT(from.isMemory()); - masm.loadFloat32(getAdjustedAddress(from), to.floatReg()); - } else if (to.isGeneralReg()) { - MOZ_ASSERT(from.isMemory()); - // This should only be used when passing float parameter in a1,a2,a3 - MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); - masm.loadPtr(getAdjustedAddress(from), to.reg()); - } else { - MOZ_ASSERT(from.isMemory()); - MOZ_ASSERT(to.isMemory()); - masm.loadFloat32(getAdjustedAddress(from), ScratchFloatReg); - masm.storeFloat32(ScratchFloatReg, getAdjustedAddress(to)); + JS_NOT_REACHED("Invalid emitMove arguments."); } } @@ -252,7 +196,7 @@ else if(to.reg() == a3) masm.moveFromDoubleHi(from.floatReg(), a3); else - MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments."); + JS_NOT_REACHED("Invalid emitDoubleMove arguments."); } else { MOZ_ASSERT(to.isMemory()); masm.storeDouble(from.floatReg(), getAdjustedAddress(to)); @@ -270,7 +214,7 @@ else if(to.reg() == a3) masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3); else - MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments."); + JS_NOT_REACHED("Invalid emitDoubleMove arguments."); } else { MOZ_ASSERT(from.isMemory()); MOZ_ASSERT(to.isMemory()); @@ -280,38 +224,26 @@ } void -MoveEmitterMIPS::emit(const MoveOp &move) +MoveEmitterMIPS::emit(const Move &move) { - const MoveOperand &from = move.from(); - const MoveOperand &to = move.to(); + const MoveOperand& from = move.from(); + const MoveOperand& to = move.to(); - if (move.isCycleEnd()) { - MOZ_ASSERT(inCycle_); - completeCycle(from, to, move.type()); - inCycle_ = false; - return; - } + if (move.inCycle()) { + if (inCycle_) { + completeCycle(from, to, move.kind()); + inCycle_ = false; - if (move.isCycleBegin()) { - MOZ_ASSERT(!inCycle_); - breakCycle(from, to, move.endCycleType()); + return; + } + + breakCycle(from, to, move.kind()); inCycle_ = true; } - - switch (move.type()) { - case MoveOp::FLOAT32: - emitFloat32Move(from, to); - break; - case MoveOp::DOUBLE: + if (move.kind() == Move::DOUBLE) { emitDoubleMove(from, to); - break; - case MoveOp::INT32: - MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t)); - case MoveOp::GENERAL: + } else { emitMove(from, to); - break; - default: - MOZ_ASSUME_UNREACHABLE("Unexpected move type"); } }
diff --git a/src/third_party/mozjs/js/src/jit/mips/MoveEmitter-mips.h b/src/third_party/mozjs/js/src/jit/mips/MoveEmitter-mips.h index d17820a..829dfaa 100644 --- a/src/third_party/mozjs/js/src/jit/mips/MoveEmitter-mips.h +++ b/src/third_party/mozjs/js/src/jit/mips/MoveEmitter-mips.h
@@ -17,6 +17,9 @@ class MoveEmitterMIPS { + typedef MoveResolver::Move Move; + typedef MoveResolver::MoveOperand MoveOperand; + bool inCycle_; MacroAssemblerMIPSCompat &masm; @@ -28,6 +31,7 @@ // stack space has been allocated for that particular spill. int32_t pushedAtCycle_; int32_t pushedAtSpill_; + int32_t pushedAtDoubleSpill_; // These are registers that are available for temporary use. They may be // assigned InvalidReg. If no corresponding spill space has been assigned, @@ -39,15 +43,15 @@ Register tempReg(); FloatRegister tempFloatReg(); Address cycleSlot() const; + Operand doubleSpillSlot() const; int32_t getAdjustedOffset(const MoveOperand &operand); Address getAdjustedAddress(const MoveOperand &operand); void emitMove(const MoveOperand &from, const MoveOperand &to); - void emitFloat32Move(const MoveOperand &from, const MoveOperand &to); void emitDoubleMove(const MoveOperand &from, const MoveOperand &to); - void breakCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type); - void completeCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type); - void emit(const MoveOp &move); + void breakCycle(const MoveOperand &from, const MoveOperand &to, Move::Kind kind); + void completeCycle(const MoveOperand &from, const MoveOperand &to, Move::Kind kind); + void emit(const Move& move); public: MoveEmitterMIPS(MacroAssemblerMIPSCompat &masm);
diff --git a/src/third_party/mozjs/js/src/jit/mips/Trampoline-mips.cpp b/src/third_party/mozjs/js/src/jit/mips/Trampoline-mips.cpp index b456845..2335147 100644 --- a/src/third_party/mozjs/js/src/jit/mips/Trampoline-mips.cpp +++ b/src/third_party/mozjs/js/src/jit/mips/Trampoline-mips.cpp
@@ -7,10 +7,12 @@ #include "jscompartment.h" #include "jit/Bailouts.h" +#include "jit/IonCompartment.h" +#include "jit/IonLinker.h" #include "jit/IonFrames.h" #include "jit/IonLinker.h" #include "jit/IonSpewer.h" -#include "jit/JitCompartment.h" +#include "jit/Bailouts.h" #include "jit/mips/Bailouts-mips.h" #include "jit/mips/BaselineHelpers-mips.h" #ifdef JS_ION_PERF @@ -18,7 +20,7 @@ #endif #include "jit/VMFunctions.h" -#include "jit/ExecutionMode-inl.h" +#include "jit/mips/Bailouts-mips.h" using namespace js; using namespace js::jit; @@ -55,7 +57,7 @@ void *jitcode; // <- sp points here when function is entered. int maxArgc; Value *maxArgv; - InterpreterFrame *fp; + StackFrame* fp; // Arguments on stack CalleeToken calleeToken; @@ -126,8 +128,8 @@ * CalleeToken calleeToken, JSObject *scopeChain, Value *vp) * ...using standard EABI calling convention */ -JitCode * -JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) +IonCode * +IonRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) { const Register reg_code = a0; const Register reg_argc = a1; @@ -187,7 +189,7 @@ masm.storePtr(s2, Address(StackPointer, 0)); // callee token masm.subPtr(StackPointer, s4); - masm.makeFrameDescriptor(s4, JitFrame_Entry); + masm.makeFrameDescriptor(s4, IonFrame_Entry); masm.push(s4); // descriptor CodeLabel returnLabel; @@ -229,7 +231,7 @@ // Enter exit frame. masm.addPtr(Imm32(BaselineFrame::Size() + BaselineFrame::FramePointerOffset), scratch); - masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS); + masm.makeFrameDescriptor(scratch, IonFrame_BaselineJS); // Push frame descriptor and fake return address. masm.reserveStack(2 * sizeof(uintptr_t)); @@ -301,18 +303,17 @@ GenerateReturn(masm, ShortJump); Linker linker(masm); - AutoFlushICache afc("GenerateEnterJIT"); - JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("GenerateEnterJIT"); #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "EnterJIT"); + writePerfSpewerIonCodeProfile(code, "EnterJIT"); #endif - return code; + return linker.newCode(cx, JSC::OTHER_CODE); } -JitCode * -JitRuntime::generateInvalidator(JSContext *cx) +IonCode * +IonRuntime::generateInvalidator(JSContext *cx) { MacroAssembler masm(cx); @@ -336,9 +337,12 @@ // Save floating point registers // We can use as_sd because stack is alligned. - for (uint32_t i = 0; i < FloatRegisters::Total; i++) - masm.as_sd(FloatRegister::FromCode(i), StackPointer, - InvalidationBailoutStack::offsetOfFpRegs() + i * sizeof(double)); + for (uint32_t i = 0; i < FloatRegisters::Total; i++) { + if (i % 2 == 0) { + masm.as_sd(FloatRegister::FromCode(i), StackPointer, + InvalidationBailoutStack::offsetOfFpRegs() + (i/2) * sizeof(double)); + } + } // Pass pointer to InvalidationBailoutStack structure. masm.movePtr(StackPointer, a0); @@ -367,23 +371,19 @@ masm.addPtr(a1, StackPointer); // Jump to shared bailout tail. The BailoutInfo pointer has to be in r2. - JitCode *bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail(); + IonCode* bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail(); masm.branch(bailoutTail); Linker linker(masm); - AutoFlushICache afc("Invalidator"); - JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("Invalidator"); + IonCode* code = linker.newCode(cx, JSC::OTHER_CODE); IonSpew(IonSpew_Invalidate, " invalidation thunk created at %p", (void *) code->raw()); -#ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "Invalidator"); -#endif - return code; } -JitCode * -JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut) +IonCode * +IonRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut) { MacroAssembler masm(cx); @@ -402,7 +402,12 @@ // Load the number of |undefined|s to push into t1. masm.loadPtr(Address(StackPointer, IonRectifierFrameLayout::offsetOfCalleeToken()), calleeTokenReg); - masm.load16ZeroExtend(Address(calleeTokenReg, JSFunction::offsetOfNargs()), numArgsReg); + masm.load16ZeroExtend( + Address( + calleeTokenReg, + offsetof(JSFunction, nargs) + ), numArgsReg + ); masm.ma_subu(t1, numArgsReg, s3); @@ -455,7 +460,7 @@ masm.lshiftPtr(Imm32(3), t0); // Construct sizeDescriptor. - masm.makeFrameDescriptor(t0, JitFrame_Rectifier); + masm.makeFrameDescriptor(t0, IonFrame_Rectifier); // Construct IonJSFrameLayout. masm.subPtr(Imm32(3 * sizeof(uintptr_t)), StackPointer); @@ -503,8 +508,8 @@ masm.ret(); Linker linker(masm); - AutoFlushICache afc("ArgumentsRectifier"); - JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("ArgumentsRectifier"); + IonCode *code = linker.newCode(cx, JSC::OTHER_CODE); CodeOffsetLabel returnLabel(returnOffset); returnLabel.fixup(&masm); @@ -512,7 +517,7 @@ *returnAddrOut = (void *) (code->raw() + returnLabel.offset()); #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "ArgumentsRectifier"); + writePerfSpewerIonCodeProfile(code, "ArgumentsRectifier"); #endif return code; @@ -522,7 +527,7 @@ * represented via class BailoutStack. * * - First case is when bailout is done trough bailout table. In this case - * table offset is stored in $ra (look at JitRuntime::generateBailoutTable()) + * table offset is stored in $ra (look at IonRuntime::generateBailoutTable()) * and thunk code should save it on stack. In this case frameClassId_ cannot * be NO_FRAME_SIZE_CLASS_ID. Members snapshotOffset_ and padding_ are not on * the stack. @@ -533,7 +538,7 @@ * on stack. Other difference is that members snapshotOffset_ and padding_ are * pushed to the stack by CodeGeneratorMIPS::visitOutOfLineBailout(). Field * frameClassId_ is forced to be NO_FRAME_SIZE_CLASS_ID - * (See: JitRuntime::generateBailoutHandler). + * (See: IonRuntime::generateBailoutHandler). */ static void GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32_t frameClass) @@ -557,12 +562,16 @@ // Save floating point registers // We can use as_sd because stack is alligned. - for (uintptr_t i = 0; i < FloatRegisters::Total; i++) - masm.as_sd(FloatRegister::FromCode(i), StackPointer, - BailoutStack::offsetOfFpRegs() + i * sizeof(double)); + for (uintptr_t i = 0; i < FloatRegisters::Total; i++) { + if (i % 2 == 0) { + masm.as_sd(FloatRegister::FromCode(i), StackPointer, + BailoutStack::offsetOfFpRegs() + (i/2) * sizeof(double)); + } + + } // Store the frameSize_ or tableOffset_ stored in ra - // See: JitRuntime::generateBailoutTable() + // See: IonRuntime::generateBailoutTable() // See: CodeGeneratorMIPS::generateOutOfLineCode() masm.storePtr(ra, Address(StackPointer, BailoutStack::offsetOfFrameSize())); @@ -573,7 +582,7 @@ masm.movePtr(StackPointer, a0); // Put pointer to BailoutInfo masm.subPtr(Imm32(bailoutInfoOutParamSize), StackPointer); - masm.storePtr(ImmPtr(nullptr), Address(StackPointer, 0)); + masm.storePtr(ImmWord((void*)NULL), Address(StackPointer, 0)); masm.movePtr(StackPointer, a1); masm.setupAlignedABICall(2); @@ -601,12 +610,12 @@ } // Jump to shared bailout tail. The BailoutInfo pointer has to be in a2. - JitCode *bailoutTail = cx->runtime()->jitRuntime()->getBailoutTail(); + IonCode* bailoutTail = cx->runtime()->ionRuntime()->getBailoutTail(); masm.branch(bailoutTail); } -JitCode * -JitRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass) +IonCode * +IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass) { MacroAssembler masm(cx); @@ -624,41 +633,45 @@ GenerateBailoutThunk(cx, masm, frameClass); Linker linker(masm); - AutoFlushICache afc("BailoutTable"); - JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("BailoutTable"); + IonCode *code = linker.newCode(cx, JSC::OTHER_CODE); #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "BailoutTable"); + writePerfSpewerIonCodeProfile(code, "BailoutTable"); #endif return code; } -JitCode * -JitRuntime::generateBailoutHandler(JSContext *cx) +IonCode * +IonRuntime::generateBailoutHandler(JSContext *cx) { MacroAssembler masm(cx); GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID); Linker linker(masm); - AutoFlushICache afc("BailoutHandler"); - JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("BailoutHandler"); + IonCode *code = linker.newCode(cx, JSC::OTHER_CODE); #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "BailoutHandler"); + writePerfSpewerIonCodeProfile(code, "BailoutHandler"); #endif return code; } -JitCode * -JitRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) +IonCode * +IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) { + typedef MoveResolver::MoveOperand MoveOperand; + MOZ_ASSERT(functionWrappers_); MOZ_ASSERT(functionWrappers_->initialized()); VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f); - if (p) - return p->value(); + + if (p) { + return p->value; + } MacroAssembler masm(cx); @@ -720,15 +733,6 @@ masm.movePtr(StackPointer, outReg); break; - case Type_Double: - outReg = t0; - regs.take(outReg); - // Double outparam has to be 8 byte aligned because the called - // function can use sdc1 or ldc1 instructions to access it. - masm.reserveStack((StackAlignment - sizeof(uintptr_t)) + sizeof(double)); - masm.alignPointerUp(StackPointer, outReg, StackAlignment); - break; - default: MOZ_ASSERT(f.outParam == Type_Void); break; @@ -744,24 +748,22 @@ MoveOperand from; switch (f.argProperties(explicitArg)) { case VMFunction::WordByValue: - masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::GENERAL); + masm.passABIArg(MoveOperand(argsBase, argDisp)); argDisp += sizeof(uint32_t); break; case VMFunction::DoubleByValue: // Values should be passed by reference, not by value, so we // assert that the argument is a double-precision float. MOZ_ASSERT(f.argPassedInFloatReg(explicitArg)); - masm.passABIArg(MoveOperand(argsBase, argDisp), MoveOp::DOUBLE); + masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::FLOAT)); argDisp += sizeof(double); break; case VMFunction::WordByRef: - masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS), - MoveOp::GENERAL); + masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE)); argDisp += sizeof(uint32_t); break; case VMFunction::DoubleByRef: - masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE_ADDRESS), - MoveOp::GENERAL); + masm.passABIArg(MoveOperand(argsBase, argDisp, MoveOperand::EFFECTIVE)); argDisp += sizeof(double); break; } @@ -774,16 +776,30 @@ masm.callWithABI(f.wrapped); // Test for failure. + Label failureLabel; switch (f.failType()) { case Type_Object: - masm.branchTestPtr(Assembler::Zero, v0, v0, masm.failureLabel(f.executionMode)); + masm.branchTestPtr(Assembler::Zero, v0, v0, &failureLabel); break; case Type_Bool: // Called functions return bools, which are 0/false and non-zero/true - masm.branchIfFalseBool(v0, masm.failureLabel(f.executionMode)); + masm.branchIfFalseBool(v0, &failureLabel); + break; + case Type_ParallelResult: + // TODO: Remove these comments and warning after proxy object issue is + // fixed. + // Type_ParallelResult was removed in SpiderMonkey31, so we should be + // careful when this is run. + // In ARM, it is: + // masm.branch32(Assembler::NotEqual, r0, Imm32(TP_SUCCESS), &failure); - arm + // In x86, it is: + // masm.branchPtr(Assembler::NotEqual, eax, Imm32(TP_SUCCESS), &failure); - x86 + SB_LOG(WARNING) << "masm.branchPtr(Assembler::NotEqual, v0, Imm32(TP_SUCCESS), &failureLabel)"; + masm.branchPtr(Assembler::NotEqual, v0, Imm32(TP_SUCCESS), &failureLabel); + break; default: - MOZ_ASSUME_UNREACHABLE("unknown failure kind"); + JS_NOT_REACHED("unknown failure kind"); } // Load the outparam and free any allocated stack. @@ -817,17 +833,6 @@ masm.freeStack(sizeof(uintptr_t)); break; - case Type_Double: - if (cx->runtime()->jitSupportsFloatingPoint) { - masm.alignPointerUp(StackPointer, SecondScratchReg, StackAlignment); - // Address is aligned, so we can use as_ld. - masm.as_ld(ReturnFloatReg, SecondScratchReg, 0); - } else { - masm.assumeUnreachable("Unable to load into float reg, with no FP support."); - } - masm.freeStack((StackAlignment - sizeof(uintptr_t)) + sizeof(double)); - break; - default: MOZ_ASSERT(f.outParam == Type_Void); break; @@ -837,26 +842,29 @@ f.explicitStackSlots() * sizeof(uintptr_t) + f.extraValuesToPop * sizeof(Value))); + masm.bind(&failureLabel); + masm.handleFailure(f.executionMode); + Linker linker(masm); - AutoFlushICache afc("VMWrapper"); - JitCode *wrapper = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("VMWrapper"); + IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE); if (!wrapper) - return nullptr; + return NULL; // linker.newCode may trigger a GC and sweep functionWrappers_ so we have // to use relookupOrAdd instead of add. if (!functionWrappers_->relookupOrAdd(p, &f, wrapper)) - return nullptr; + return NULL; #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(wrapper, "VMWrapper"); + writePerfSpewerIonCodeProfile(wrapper, "VMWrapper"); #endif return wrapper; } -JitCode * -JitRuntime::generatePreBarrier(JSContext *cx, MIRType type) +IonCode * +IonRuntime::generatePreBarrier(JSContext *cx, MIRType type) { MacroAssembler masm(cx); @@ -871,7 +879,7 @@ masm.PushRegsInMask(save); MOZ_ASSERT(PreBarrierReg == a1); - masm.movePtr(ImmPtr(cx->runtime()), a0); + masm.movePtr(ImmWord(cx->runtime()), a0); masm.setupUnalignedABICall(2, a2); masm.passABIArg(a0); @@ -888,21 +896,21 @@ masm.ret(); Linker linker(masm); - AutoFlushICache afc("PreBarrier"); - JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("PreBarrier"); + IonCode *code = linker.newCode(cx, JSC::OTHER_CODE); #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "PreBarrier"); + writePerfSpewerIonCodeProfile(code, "PreBarrier"); #endif return code; } -typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, bool *); +typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, JSBool *); static const VMFunction HandleDebugTrapInfo = FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap); -JitCode * -JitRuntime::generateDebugTrapHandler(JSContext *cx) +IonCode * +IonRuntime::generateDebugTrapHandler(JSContext *cx) { MacroAssembler masm(cx); @@ -916,12 +924,13 @@ // Enter a stub frame and call the HandleDebugTrap VM function. Ensure // the stub frame has a nullptr ICStub pointer, since this pointer is // marked during GC. - masm.movePtr(ImmPtr(nullptr), BaselineStubReg); + masm.movePtr(ImmWord((void*)NULL), BaselineStubReg); EmitEnterStubFrame(masm, scratch2); - JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(HandleDebugTrapInfo); + IonCompartment* ion = cx->compartment()->ionCompartment(); + IonCode* code = ion->getVMWrapper(HandleDebugTrapInfo); if (!code) - return nullptr; + return NULL; masm.subPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer); masm.storePtr(ra, Address(StackPointer, sizeof(uintptr_t))); @@ -948,48 +957,48 @@ masm.ret(); Linker linker(masm); - AutoFlushICache afc("DebugTrapHandler"); - JitCode *codeDbg = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("DebugTrapHandler"); + IonCode *codeDbg = linker.newCode(cx, JSC::OTHER_CODE); #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(codeDbg, "DebugTrapHandler"); + writePerfSpewerIonCodeProfile(codeDbg, "DebugTrapHandler"); #endif return codeDbg; } -JitCode * -JitRuntime::generateExceptionTailStub(JSContext *cx) +IonCode * +IonRuntime::generateExceptionTailStub(JSContext *cx) { MacroAssembler masm; masm.handleFailureWithHandlerTail(); Linker linker(masm); - AutoFlushICache afc("ExceptionTailStub"); - JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("ExceptionTailStub"); + IonCode *code = linker.newCode(cx, JSC::OTHER_CODE); #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "ExceptionTailStub"); + writePerfSpewerIonCodeProfile(code, "ExceptionTailStub"); #endif return code; } -JitCode * -JitRuntime::generateBailoutTailStub(JSContext *cx) +IonCode * +IonRuntime::generateBailoutTailStub(JSContext *cx) { MacroAssembler masm; masm.generateBailoutTail(a1, a2); Linker linker(masm); - AutoFlushICache afc("BailoutTailStub"); - JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE); + AutoFlushCache afc("BailoutTailStub"); + IonCode *code = linker.newCode(cx, JSC::OTHER_CODE); #ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(code, "BailoutTailStub"); + writePerfSpewerIonCodeProfile(code, "BailoutTailStub"); #endif return code;
diff --git a/src/third_party/mozjs/js/src/jit/shared/CodeGenerator-shared.cpp b/src/third_party/mozjs/js/src/jit/shared/CodeGenerator-shared.cpp index efeb860..abec162 100644 --- a/src/third_party/mozjs/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/src/third_party/mozjs/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -64,7 +64,7 @@ // An MAsmJSCall does not align the stack pointer at calls sites but instead // relies on the a priori stack adjustment (in the prologue) on platforms // (like x64) which require the stack to be aligned. -#ifdef JS_CPU_ARM +#if defined(JS_CPU_ARM) || defined(JS_CPU_MIPS) bool forceAlign = true; #else bool forceAlign = false;
diff --git a/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBuffer.h b/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBuffer.h index 07c9786..12de936 100644 --- a/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBuffer.h +++ b/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBuffer.h
@@ -199,6 +199,18 @@ tail = tmp; } +#if defined(JS_CPU_MIPS) + void executableCopy(uint8_t* dest_) { + if (this->oom()) + return; + + for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) { + memcpy(dest_, &cur->instructions, cur->size()); + dest_ += cur->size(); + } + } +#endif // defined(JS_CPU_MIPS) + class AssemblerBufferInstIterator { private: BufferOffset bo;
diff --git a/src/third_party/mozjs/js/src/jsfun.h b/src/third_party/mozjs/js/src/jsfun.h index c4a9313..7ebe845 100644 --- a/src/third_party/mozjs/js/src/jsfun.h +++ b/src/third_party/mozjs/js/src/jsfun.h
@@ -196,6 +196,10 @@ static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); } static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); } +#if defined(JS_CPU_MIPS) + static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs); } + static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags); } +#endif static bool createScriptForLazilyInterpretedFunction(JSContext *cx, js::HandleFunction fun); @@ -236,6 +240,8 @@ inline JSScript *existingScript(); + inline JSScript* existingScriptForInlinedFunction(); + JSScript *nonLazyScript() const { JS_ASSERT(hasScript()); return JS::HandleScript::fromMarkedLocation(&u.i.s.script_);
diff --git a/src/third_party/mozjs/js/src/jsfuninlines.h b/src/third_party/mozjs/js/src/jsfuninlines.h index c334ffd..e1fe414 100644 --- a/src/third_party/mozjs/js/src/jsfuninlines.h +++ b/src/third_party/mozjs/js/src/jsfuninlines.h
@@ -258,6 +258,33 @@ return u.i.s.script_; } +inline JSScript* +JSFunction::existingScriptForInlinedFunction() { + JS_ASSERT(isInterpreted()); + if (isInterpretedLazy()) { + // Get the script from the canonical function. Ion used the + // canonical function to inline the script and because it has + // Baseline code it has not been relazified. Note that we can't + // use lazyScript->script_ here as it may be null in some cases, + // see bug 976536. + + js::LazyScript *lazy = lazyScript(); + JSFunction* fun = lazy->function(); + JS_ASSERT(fun); + JSScript *script = fun->nonLazyScript(); + + if (zone()->needsBarrier()) + js::LazyScript::writeBarrierPre(lazy); + + flags &= ~INTERPRETED_LAZY; + flags |= INTERPRETED; + initScript(script); + } + JS_ASSERT(hasScript()); + JS_ASSERT(u.i.s.script_); + return u.i.s.script_; +} + inline void JSFunction::setScript(JSScript *script_) {
diff --git a/src/third_party/mozjs/js/src/yarr/YarrJIT.cpp b/src/third_party/mozjs/js/src/yarr/YarrJIT.cpp index d570f46..0823654 100644 --- a/src/third_party/mozjs/js/src/yarr/YarrJIT.cpp +++ b/src/third_party/mozjs/js/src/yarr/YarrJIT.cpp
@@ -868,7 +868,17 @@ sub32(Imm32(term->quantityCount.unsafeGet()), countRegister); Label loop(this); - BaseIndex address(input, countRegister, m_charScale, (Checked<int>(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)) * static_cast<int>(m_charSize == Char8 ? sizeof(char) : sizeof(UChar))).unsafeGet()); + Checked<int, RecordOverflow> checkedOffset(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)); + if (!checkedOffset.hasOverflowed()) { + checkedOffset *= static_cast<int>(m_charSize == Char8 ? sizeof(char) : sizeof(UChar)); + } + if (checkedOffset.hasOverflowed()) { + // There has been an integer overflow, so bail out and fall back to + // the interpreter. + m_shouldFallBack = true; + return; + } + BaseIndex address(input, countRegister, m_charScale, checkedOffset.unsafeGet()); if (m_charSize == Char8) load8(address, character); @@ -1018,10 +1028,19 @@ Label loop(this); JumpList matchDest; + Checked<int, RecordOverflow> checkedOffset(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)); + if (!checkedOffset.hasOverflowed()) { + checkedOffset *= static_cast<int>(m_charSize == Char8 ? sizeof(char) : sizeof(UChar)); + } + if (checkedOffset.hasOverflowed()) { + // If there has been integer overflow, fall back to the interpreter. + m_shouldFallBack = true; + return; + } if (m_charSize == Char8) - load8(BaseIndex(input, countRegister, TimesOne, (Checked<int>(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)) * static_cast<int>(sizeof(char))).unsafeGet()), character); + load8(BaseIndex(input, countRegister, TimesOne, checkedOffset.unsafeGet()), character); else - load16(BaseIndex(input, countRegister, TimesTwo, (Checked<int>(term->inputPosition - m_checked + Checked<int64_t>(term->quantityCount)) * static_cast<int>(sizeof(UChar))).unsafeGet()), character); + load16(BaseIndex(input, countRegister, TimesTwo, checkedOffset.unsafeGet()), character); matchCharacterClass(character, matchDest, term->characterClass); if (term->invert())
diff --git a/src/third_party/mozjs/mozjs.gyp b/src/third_party/mozjs/mozjs.gyp index bede0e6..8895e64 100644 --- a/src/third_party/mozjs/mozjs.gyp +++ b/src/third_party/mozjs/mozjs.gyp
@@ -66,6 +66,12 @@ 'JS_NUNBOX32=1', ], }], + [ 'target_arch == "mips"', { + 'defines': [ + 'JS_CPU_MIPS=1', + 'JS_NUNBOX32=1', + ], + }], [ 'cobalt_enable_jit == 1', { 'defines': [ '<@(common_jit_defines)', @@ -76,6 +82,12 @@ 'MOZ_ASAN', ], }], + [ 'cobalt_config == "debug"', { + 'defines': [ + 'DEBUG', + 'JS_DEBUG', + ], + }], ], }, 'targets': [ @@ -165,6 +177,21 @@ '<@(mozjs_jit_sources)', ], }], + [ 'target_arch == "mips" and cobalt_enable_jit == 1', { + 'sources': [ + 'js/src/jit/mips/Architecture-mips.cpp', + 'js/src/jit/mips/Assembler-mips.cpp', + 'js/src/jit/mips/Bailouts-mips.cpp', + 'js/src/jit/mips/BaselineCompiler-mips.cpp', + 'js/src/jit/mips/BaselineIC-mips.cpp', + 'js/src/jit/mips/CodeGenerator-mips.cpp', + 'js/src/jit/mips/Lowering-mips.cpp', + 'js/src/jit/mips/MacroAssembler-mips.cpp', + 'js/src/jit/mips/MoveEmitter-mips.cpp', + 'js/src/jit/mips/Trampoline-mips.cpp', + '<@(mozjs_jit_sources)', + ] + }] ], 'dependencies': [ 'build_include_directory',
diff --git a/src/third_party/openssl/openssl.gyp b/src/third_party/openssl/openssl.gyp index 6020ce1..e84bd8d 100644 --- a/src/third_party/openssl/openssl.gyp +++ b/src/third_party/openssl/openssl.gyp
@@ -642,8 +642,8 @@ 'openssl/crypto/aes/asm/aes-mips.S', 'openssl/crypto/bn/asm/bn-mips.S', 'openssl/crypto/bn/asm/mips-mont.S', - 'openssl/crypto/sha/sha1-mips.S', - 'openssl/crypto/sha/sha256-mips.S', + 'openssl/crypto/sha/asm/sha1-mips.S', + 'openssl/crypto/sha/asm/sha256-mips.S', ], }], ['clang==1', {
diff --git a/src/third_party/protobuf/config.h b/src/third_party/protobuf/config.h index 439a95b..62e4c3c 100644 --- a/src/third_party/protobuf/config.h +++ b/src/third_party/protobuf/config.h
@@ -58,8 +58,11 @@ /* Define to 1 if you have the `mkdir' function. */ #define HAVE_MKDIR 1 +// Starboard has its own thread management. +#ifndef STARBOARD /* Define if you have POSIX threads libraries and header files. */ #define HAVE_PTHREAD 1 +#endif // STARBOARD /* Define to 1 if you have the <stdint.h> header file. */ #define HAVE_STDINT_H 1
diff --git a/src/third_party/protobuf/protobuf.gyp b/src/third_party/protobuf/protobuf.gyp index b679cad..c9d2455 100644 --- a/src/third_party/protobuf/protobuf.gyp +++ b/src/third_party/protobuf/protobuf.gyp
@@ -6,6 +6,21 @@ 'conditions': [ ['use_system_protobuf==0', { 'conditions': [ + ['OS!="starboard" and actual_target_arch=="win"', { + 'target_defaults': { + 'msvs_disabled_warnings': [ + # forcing value to bool 'true' or 'false' (performance warning) + 4800, + ], + }, + }], + ['OS!="starboard" and actual_target_arch=="ps3"', { + 'target_defaults': { + 'cflags_cc_host': [ + '-Wno-unused-result', + ], + }, + }], ['OS!="win"', { 'variables': { 'config_h_dir':
diff --git a/src/third_party/protobuf/src/google/protobuf/io/coded_stream.cc b/src/third_party/protobuf/src/google/protobuf/io/coded_stream.cc index 402a3ad..203babd 100644 --- a/src/third_party/protobuf/src/google/protobuf/io/coded_stream.cc +++ b/src/third_party/protobuf/src/google/protobuf/io/coded_stream.cc
@@ -38,9 +38,9 @@ // will not cross the end of the buffer, since we can avoid a lot // of branching in this case. -#include <google/protobuf/io/coded_stream_inl.h> #include <algorithm> #include <limits.h> +#include <google/protobuf/io/coded_stream_inl.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stl_util-inl.h>
diff --git a/src/third_party/protobuf/src/google/protobuf/stubs/common.cc b/src/third_party/protobuf/src/google/protobuf/stubs/common.cc index 7b15be4..1f35af4 100644 --- a/src/third_party/protobuf/src/google/protobuf/stubs/common.cc +++ b/src/third_party/protobuf/src/google/protobuf/stubs/common.cc
@@ -32,14 +32,23 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/once.h> -#include <stdio.h> -#include <errno.h> -#include <vector> #include "config.h" +#ifdef STARBOARD +#include "starboard/client_porting/poem/stdio_poem.h" +#include "starboard/log.h" +#include "starboard/mutex.h" +#include "starboard/system.h" +#define abort SbSystemBreakIntoDebugger +#define fflush(stderr) SbLogFlush() +#else // STARBOARD +#include <errno.h> +#include <stdio.h> #ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN // We only need minimal includes +#endif // WIN32_LEAN_AND_MEAN #include <windows.h> #define snprintf _snprintf // see comment in strutil.cc #elif defined(HAVE_PTHREAD) @@ -47,6 +56,9 @@ #else #error "No suitable threading library available." #endif +#endif // STARBOARD + +#include <vector> namespace google { namespace protobuf { @@ -110,8 +122,14 @@ // We use fprintf() instead of cerr because we want this to work at static // initialization time. +#ifndef STARBOARD fprintf(stderr, "libprotobuf %s %s:%d] %s\n", level_names[level], filename, line, message.c_str()); +#else + SbLogRawFormatF("libprotobuf %s %s:%d] %s\n", level_names[level], filename, + line, message.c_str()); +#endif // STARBOARD + fflush(stderr); // Needed on MSVC. } @@ -282,6 +300,37 @@ #endif } +#elif defined(STARBOARD) + +struct Mutex::Internal { + SbMutex mutex; +}; + +Mutex::Mutex() : mInternal(new Internal) { + SbMutexCreate(&mInternal->mutex); +} + +Mutex::~Mutex() { + SbMutexDestroy(&mInternal->mutex); + delete mInternal; +} + +void Mutex::Lock() { + if (!SbMutexIsSuccess(SbMutexAcquire(&mInternal->mutex))) { + GOOGLE_LOG(FATAL) << "SbMutexAcquire failed."; + } +} + +void Mutex::Unlock() { + if (!SbMutexRelease(&mInternal->mutex)) { + GOOGLE_LOG(FATAL) << "SbMutexRelease failed."; + } +} + +void Mutex::AssertHeld() { + // Starboard doesn't provide a way to check which thread holds the mutex. +} + #elif defined(HAVE_PTHREAD) struct Mutex::Internal {
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py index f6bc330..e1f025c 100755 --- a/src/tools/gyp/pylib/gyp/generator/ninja.py +++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -91,7 +91,7 @@ return arg # No quoting necessary. if flavor in ['win', 'xb1']: return gyp.msvs_emulation.QuoteForRspFile(arg) - elif flavor in ['ps3', 'ps4'] : + elif flavor in ['ps3', 'ps3-starboard', 'ps4'] : # Escape double quotes. return '"' + arg.replace('\"', '\\\"') + '"' return "'" + arg.replace("'", "'" + '"\'"' + "'") + "'" @@ -183,7 +183,7 @@ # For bundles, the .TOC should be produced for the binary, not for # FinalOutput(). But the naive approach would put the TOC file into the # bundle, so don't do this for bundles for now. - if flavor in ['win', 'xb1', 'ps3', 'ps4'] or self.bundle: + if flavor in ['win', 'xb1', 'ps3', 'ps3-starboard', 'ps4'] or self.bundle: return False return self.type in ('shared_library', 'loadable_module') @@ -251,7 +251,7 @@ self.abs_build_dir = abs_build_dir self.obj_ext = '.obj' if flavor == 'win' else '.o' - if flavor in ['win', 'ps3', 'xb1', 'ps4']: + if flavor in ['win', 'ps3', 'ps3-starboard', 'xb1', 'ps4']: # See docstring of msvs_emulation.GenerateEnvironmentFiles(). self.win_env = {} for arch in ('x86', 'x64'): @@ -411,7 +411,7 @@ self.xcode_settings = self.msvs_settings = None if self.flavor == 'mac': self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec) - if (self.flavor in ['win', 'ps3', 'xb1', 'ps4'] + if (self.flavor in ['win', 'ps3', 'ps3-starboard', 'xb1', 'ps4'] and is_windows): self.msvs_settings = gyp.msvs_emulation.MsvsSettings(spec, generator_flags) @@ -580,7 +580,7 @@ return False elif self.flavor == 'win': return self.msvs_settings.IsRuleRunUnderCygwin(action) - elif self.flavor in ['ps3', 'xb1', 'ps4'] : + elif self.flavor in ['ps3', 'ps3-starboard', 'xb1', 'ps4'] : return str(action.get('msvs_cygwin_shell', 1)) != '0' return False @@ -976,7 +976,7 @@ if (self.flavor in ['win', 'xb1'] and target.component_objs and self.msvs_settings.IsUseLibraryDependencyInputs(config_name)): extra_link_deps.extend(target.component_objs) - elif (self.flavor in ['win', 'xb1', 'ps3'] and + elif (self.flavor in ['win', 'xb1', 'ps3', 'ps3-starboard'] and target.import_lib): extra_link_deps.append(target.import_lib) elif target.UsesToc(self.flavor): @@ -1058,7 +1058,7 @@ extra_bindings.append(('implibflag', '/IMPLIB:%s' % self.target.import_lib)) output = [output, self.target.import_lib] - elif self.flavor == 'ps3': + elif self.flavor in ['ps3', 'ps3-starboard']: # Tell Ninja we'll be generating a .sprx and a stub library. # Bind the variable '$prx' to our output binary so we can # refer to it in the linker rules. @@ -1322,7 +1322,7 @@ type_in_output_root = ['executable', 'loadable_module'] if self.flavor == 'mac' and self.toolset == 'target': type_in_output_root += ['shared_library', 'static_library'] - elif self.flavor in ['win', 'ps3'] and self.toolset == 'target': + elif self.flavor in ['win', 'ps3', 'ps3-starboard'] and self.toolset == 'target': type_in_output_root += ['shared_library'] if type in type_in_output_root or self.is_standalone_static_library: @@ -1380,7 +1380,7 @@ rspfile = None rspfile_content = None args = [self.ExpandSpecial(arg, self.base_to_build) for arg in args] - if (self.flavor in ['win', 'ps3', 'xb1', 'ps4'] + if (self.flavor in ['win', 'ps3', 'ps3-starboard', 'xb1', 'ps4'] and is_windows): rspfile = rule_name + '.$unique_name.rsp' # The cygwin case handles this inside the bash sub-shell. @@ -1461,7 +1461,7 @@ default_variables['MSVS_OS_BITS'] = 64 else: default_variables['MSVS_OS_BITS'] = 32 - elif flavor == 'ps3': + elif flavor in ['ps3', 'ps3-starboard']: if is_windows: # This is required for BuildCygwinBashCommandLine() to work. import gyp.generator.msvs as msvs_generator @@ -1607,7 +1607,7 @@ # - If there is no 'make_global_settings' for CC.host/CXX.host or # 'CC_host'/'CXX_host' enviroment variable, cc_host/cxx_host should be set # to cc/cxx. - if (flavor == 'win' or (flavor in ['ps3', 'ps4'] and is_windows)): + if (flavor == 'win' or (flavor in ['ps3', 'ps3-starboard', 'ps4'] and is_windows)): cc = 'cl.exe' cxx = 'cl.exe' ld = 'link.exe' @@ -1680,11 +1680,11 @@ master_ninja.variable('asm', 'ml.exe') master_ninja.variable('mt', 'mt.exe') master_ninja.variable('use_dep_database', '1') - elif flavor in ['ps3', 'ps4']: + elif flavor in ['ps3', 'ps3-starboard', 'ps4']: # Require LD to be set. master_ninja.variable('ld', os.environ.get('LD')) master_ninja.variable('ar', os.environ.get('AR', 'ar')) - if flavor =='ps3': + if flavor in ['ps3', 'ps3-starboard']: master_ninja.variable('prx_export_pickup', os.environ['PRX_EXPORT_PICKUP']) ar_flags = os.environ.get('ARFLAGS', 'rcs') master_ninja.variable('arFlags', ar_flags) @@ -1737,9 +1737,9 @@ master_ninja.newline() if flavor not in ['win', 'xb1']: - if flavor in ['ps3', 'ps4'] : + if flavor in ['ps3', 'ps3-starboard', 'ps4'] : # uca := Unnamed Console A - dep_format = 'snc' if (flavor == 'ps3') else 'uca' + dep_format = 'snc' if (flavor in ['ps3', 'ps3-starboard']) else 'uca' master_ninja.rule( 'cc', description='CC $out', @@ -1830,7 +1830,7 @@ ld_cmd = '$ld' - if flavor in ['ps3', 'ps4'] and is_windows: + if flavor in ['ps3', 'ps3-starboard', 'ps4'] and is_windows: alink_command = 'cmd.exe /c ' + alink_command alink_thin_command = 'cmd.exe /c ' + alink_thin_command ld_cmd = '%s gyp-win-tool link-wrapper $arch $ld' % python_exec @@ -1848,7 +1848,7 @@ rspfile='$out.rsp', rspfile_content='$in_newline') - if flavor == 'ps3': + if flavor in ['ps3', 'ps3-starboard']: # TODO: Can we suppress the warnings from verlog.txt rather than # rm'ing it? ld_cmd = 'rm -f $verlog && ' + ld_cmd @@ -1903,7 +1903,7 @@ command=(mtime_preserving_solink_base % { 'suffix': '-Wl,--start-group $in $solibs -Wl,--end-group $libs'})) - if flavor in ['ps3', 'ps4']: + if flavor in ['ps3', 'ps3-starboard', 'ps4']: # PS3 and PS4 linkers don't know about rpath. rpath = '' else: