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 v