Bug 957659 - slim down WidgetKeyboardEvent::GetDOMKeyName; r=masayuki

Instead of calling nsAString::Assign several hundred times along with a
switch statement that may or may not get translated into a jump table,
let's implement our own lookup table that we can guarantee will be
constant time.  The KeyNameTable struct is used instead of the more
obvious |const char* const table[]| idiom to avoid runtime relocations.
This commit is contained in:
Nathan Froyd 2014-01-08 11:45:30 -05:00
parent b07161b5dc
commit 7cc4b6c4c7
2 changed files with 71 additions and 14 deletions

View File

@ -127,20 +127,7 @@ public:
}
static void GetDOMKeyName(mozilla::KeyNameIndex aKeyNameIndex,
nsAString& aKeyName)
{
#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) \
case KEY_NAME_INDEX_##aCPPName: \
aKeyName.Assign(NS_LITERAL_STRING(aDOMKeyName)); return;
switch (aKeyNameIndex) {
#include "nsDOMKeyNameList.h"
case KEY_NAME_INDEX_USE_STRING:
default:
aKeyName.Truncate();
return;
}
#undef NS_DEFINE_KEYNAME
}
nsAString& aKeyName);
void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets)
{

View File

@ -237,4 +237,74 @@ WidgetEvent::IsAllowedToDispatchDOMEvent() const
}
}
/******************************************************************************
* mozilla::WidgetKeyboardEvent (TextEvents.h)
******************************************************************************/
/*static*/ void
WidgetKeyboardEvent::GetDOMKeyName(KeyNameIndex aKeyNameIndex,
nsAString& aKeyName)
{
// The expected way to implement this function would be to use a
// switch statement. By using a table-based implementation, below, we
// ensure that this function executes in constant time in cases where
// compilers wouldn't be able to convert the switch statement to a
// jump table. This table-based implementation also minimizes the
// space required by the code and data.
#define KEY_STR_NUM_INTERNAL(line) key##line
#define KEY_STR_NUM(line) KEY_STR_NUM_INTERNAL(line)
// Catch non-ASCII DOM key names in our key name list.
#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) \
static_assert(sizeof(aDOMKeyName) == MOZ_ARRAY_LENGTH(aDOMKeyName), \
"Invalid DOM key name");
#include "nsDOMKeyNameList.h"
#undef NS_DEFINE_KEYNAME
struct KeyNameTable
{
#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) \
char16_t KEY_STR_NUM(__LINE__)[sizeof(aDOMKeyName)];
#include "nsDOMKeyNameList.h"
#undef NS_DEFINE_KEYNAME
};
static const KeyNameTable kKeyNameTable = {
#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) MOZ_UTF16(aDOMKeyName),
#include "nsDOMKeyNameList.h"
#undef NS_DEFINE_KEYNAME
};
static const uint16_t kKeyNameOffsets[] = {
#define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) \
offsetof(struct KeyNameTable, KEY_STR_NUM(__LINE__)),
#include "nsDOMKeyNameList.h"
#undef NS_DEFINE_KEYNAME
// Include this entry so we can compute lengths easily.
sizeof(kKeyNameTable)
};
// Use the sizeof trick rather than MOZ_ARRAY_LENGTH to avoid problems
// with constexpr functions called inside static_assert with some
// compilers.
static_assert(KEY_NAME_INDEX_USE_STRING ==
(sizeof(kKeyNameOffsets)/sizeof(kKeyNameOffsets[0])) - 1,
"Invalid enumeration values!");
if (aKeyNameIndex >= KEY_NAME_INDEX_USE_STRING) {
aKeyName.Truncate();
return;
}
uint16_t offset = kKeyNameOffsets[aKeyNameIndex];
uint16_t nextOffset = kKeyNameOffsets[aKeyNameIndex + 1];
const char16_t* table = reinterpret_cast<const char16_t*>(&kKeyNameTable);
// Subtract off 1 for the null terminator.
aKeyName.Assign(table + offset, nextOffset - offset - 1);
#undef KEY_STR_NUM
#undef KEY_STR_NUM_INTERNAL
}
} // namespace mozilla