mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
Merge the last PGO-green inbound changeset to m-c.
This commit is contained in:
commit
b7ab9ce7e3
@ -190,9 +190,6 @@ pref("app.privacyURL", "http://www.mozilla.com/%LOCALE%/m/privacy.html");
|
||||
pref("app.creditsURL", "http://www.mozilla.org/credits/");
|
||||
pref("app.featuresURL", "http://www.mozilla.com/%LOCALE%/b2g/features/");
|
||||
pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/b2g/faq/");
|
||||
// Whether we want to report crashes (headless)
|
||||
//XXX Remove this pref when bug 801932 is fixed
|
||||
pref("app.reportCrashes", true);
|
||||
|
||||
// Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror)
|
||||
pref("security.alternate_certificate_error_page", "certerror");
|
||||
@ -239,7 +236,10 @@ pref("ui.dragThresholdY", 25);
|
||||
|
||||
// Layers Acceleration
|
||||
pref("layers.acceleration.disabled", false);
|
||||
#ifndef XP_WIN
|
||||
//TODO: turn this on for Windows in bug 808016
|
||||
pref("layers.offmainthreadcomposition.enabled", true);
|
||||
#endif
|
||||
pref("layers.offmainthreadcomposition.animate-opacity", true);
|
||||
pref("layers.offmainthreadcomposition.animate-transform", true);
|
||||
pref("layers.async-video.enabled", true);
|
||||
|
@ -59,20 +59,13 @@ function identityCall(message) {
|
||||
sendAsyncMessage(kIdentityControllerDoMethod, message);
|
||||
}
|
||||
|
||||
function identityFinished() {
|
||||
log("identity finished. closing dialog");
|
||||
closeIdentityDialog(function notifySuccess() {
|
||||
// get ready for next call with a reinit
|
||||
func = null; options = null;
|
||||
|
||||
sendAsyncMessage(kIdentityDelegateFinished);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify the UI to close the dialog and return to the caller application
|
||||
* To close the dialog, we first tell the gecko SignInToWebsite manager that it
|
||||
* can clean up. Then we tell the gaia component that we are finished. It is
|
||||
* necessary to notify gecko first, so that the message can be sent before gaia
|
||||
* destroys our context.
|
||||
*/
|
||||
function closeIdentityDialog(aCallback) {
|
||||
function closeIdentityDialog() {
|
||||
let randomId = uuidgen.generateUUID().toString();
|
||||
let id = kReceivedIdentityAssertion + "-" + randomId;
|
||||
let browser = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
@ -94,6 +87,11 @@ function closeIdentityDialog(aCallback) {
|
||||
}
|
||||
});
|
||||
|
||||
// tell gecko we're done. fire and forget.
|
||||
func = null; options = null;
|
||||
sendAsyncMessage(kIdentityDelegateFinished);
|
||||
|
||||
// tell gaia to shut us down
|
||||
browser.shell.sendChromeEvent(detail);
|
||||
}
|
||||
|
||||
@ -111,7 +109,7 @@ function doInternalWatch() {
|
||||
identityCall(aParams);
|
||||
if (aParams.method === "ready") {
|
||||
log("watch finished.");
|
||||
identityFinished();
|
||||
closeIdentityDialog();
|
||||
}
|
||||
},
|
||||
JSON.stringify({loggedInUser: options.loggedInUser, origin: options.origin}),
|
||||
@ -132,7 +130,7 @@ function doInternalRequest() {
|
||||
log("request -> assertion, so do login");
|
||||
identityCall({method:'login',assertion:assertion});
|
||||
}
|
||||
identityFinished();
|
||||
closeIdentityDialog();
|
||||
},
|
||||
options);
|
||||
}
|
||||
@ -145,7 +143,7 @@ function doInternalLogout(aOptions) {
|
||||
log("logging you out of ", options.origin);
|
||||
BrowserID.internal.logout(options.origin, function() {
|
||||
identityCall({method:'logout'});
|
||||
identityFinished();
|
||||
closeIdentityDialog();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ let Pipe = {
|
||||
* provide a callback for handling messages.
|
||||
*
|
||||
* @param aRpOptions options describing the Relying Party's
|
||||
* (dicitonary) call, such as origin and loggedInEmail.
|
||||
* (dictionary) call, such as origin and loggedInUser.
|
||||
*
|
||||
* @param aGaiaOptions showUI: boolean
|
||||
* (dictionary) message: name of the message to emit
|
||||
@ -289,11 +289,11 @@ let SignInToWebsiteController = {
|
||||
*/
|
||||
_makeDoMethodCallback: function SignInToWebsiteController__makeDoMethodCallback(aRpId) {
|
||||
return function SignInToWebsiteController_methodCallback(aOptions) {
|
||||
log("doMethod:", aOptions);
|
||||
let message = aOptions.json;
|
||||
if (typeof message === 'string') {
|
||||
message = JSON.parse(message);
|
||||
}
|
||||
log("doMethod:", message.method);
|
||||
switch(message.method) {
|
||||
case "ready":
|
||||
IdentityService.doReady(aRpId);
|
||||
|
@ -50,7 +50,7 @@ function uuid() {
|
||||
function mockDoc(aIdentity, aOrigin, aDoFunc) {
|
||||
let mockedDoc = {};
|
||||
mockedDoc.id = uuid();
|
||||
mockedDoc.loggedInEmail = aIdentity;
|
||||
mockedDoc.loggedInUser = aIdentity;
|
||||
mockedDoc.origin = aOrigin;
|
||||
mockedDoc['do'] = aDoFunc;
|
||||
mockedDoc.doReady = partial(aDoFunc, 'ready');
|
||||
|
@ -44,9 +44,6 @@ function checkStyleEditorForSheetAndLine(aStyleSheetIndex, aLine, aCallback) {
|
||||
function doCheck(aEditor) {
|
||||
function checkLineAndCallback() {
|
||||
info("In checkLineAndCallback()");
|
||||
ok(aEditor.sourceEditor != null, "sourceeditor not null");
|
||||
ok(aEditor.sourceEditor.getCaretPosition() != null, "position not null");
|
||||
ok(aEditor.sourceEditor.getCaretPosition().line != null, "line not null");
|
||||
is(aEditor.sourceEditor.getCaretPosition().line, aLine,
|
||||
"Correct line is selected");
|
||||
if (aCallback) {
|
||||
@ -54,10 +51,7 @@ function checkStyleEditorForSheetAndLine(aStyleSheetIndex, aLine, aCallback) {
|
||||
}
|
||||
}
|
||||
|
||||
ok(aEditor, "aEditor is defined.");
|
||||
|
||||
// Source-editor is already loaded, check the current line of caret.
|
||||
if (aEditor.sourceEditor) {
|
||||
function checkForCorrectSheet() {
|
||||
if (aEditor.styleSheetIndex != SEC.selectedStyleSheetIndex) {
|
||||
ok(false, "Correct Style Sheet was not selected.");
|
||||
if (aCallback) {
|
||||
@ -66,30 +60,28 @@ function checkStyleEditorForSheetAndLine(aStyleSheetIndex, aLine, aCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
info("Correct Style Sheet is selected in the editor");
|
||||
info("Editor is already loaded, check the current line of caret");
|
||||
executeSoon(checkLineAndCallback);
|
||||
}
|
||||
|
||||
ok(aEditor, "aEditor is defined.");
|
||||
|
||||
// Source-editor is already loaded, check the current sheet and line.
|
||||
if (aEditor.sourceEditor) {
|
||||
checkForCorrectSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
info("source editor is not loaded, waiting for it.");
|
||||
// Wait for source editor to be loaded.
|
||||
aEditor.addActionListener({
|
||||
onAttach: function onAttach() {
|
||||
info("on attach happened");
|
||||
aEditor.removeActionListener(this);
|
||||
info("this removed");
|
||||
executeSoon(function() {
|
||||
if (aEditor.styleSheetIndex != SEC.selectedStyleSheetIndex) {
|
||||
ok(false, "Correct Style Sheet was not selected.");
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
checkLineAndCallback()
|
||||
});
|
||||
}
|
||||
// Source-editor is not loaded, polling regularly and waiting for it to load
|
||||
waitForSuccess({
|
||||
name: "Wait for the source-editor to load",
|
||||
validatorFn: function()
|
||||
{
|
||||
return aEditor.sourceEditor;
|
||||
},
|
||||
successFn: checkForCorrectSheet,
|
||||
failureFn: aCallback,
|
||||
});
|
||||
}
|
||||
|
||||
@ -138,18 +130,14 @@ let observer = {
|
||||
.getEditorForWindow(content.window);
|
||||
ok(styleEditorWin, "Style Editor Window is defined");
|
||||
waitForFocus(function() {
|
||||
//styleEditorWin.addEventListener("load", function onStyleEditorWinLoad() {
|
||||
//styleEditorWin.removeEventListener("load", onStyleEditorWinLoad);
|
||||
|
||||
checkStyleEditorForSheetAndLine(0, 7, function() {
|
||||
checkStyleEditorForSheetAndLine(1, 6, function() {
|
||||
window.StyleEditor.toggle();
|
||||
styleEditorWin = null;
|
||||
finishTest();
|
||||
});
|
||||
EventUtils.sendMouseEvent({ type: "click" }, nodes[1]);
|
||||
checkStyleEditorForSheetAndLine(0, 7, function() {
|
||||
checkStyleEditorForSheetAndLine(1, 6, function() {
|
||||
window.StyleEditor.toggle();
|
||||
styleEditorWin = null;
|
||||
finishTest();
|
||||
});
|
||||
//});
|
||||
EventUtils.sendMouseEvent({ type: "click" }, nodes[1]);
|
||||
});
|
||||
}, styleEditorWin);
|
||||
});
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import time
|
||||
import re
|
||||
import os
|
||||
import automationutils
|
||||
import tempfile
|
||||
@ -23,6 +24,7 @@ class RemoteAutomation(Automation):
|
||||
|
||||
# Default our product to fennec
|
||||
self._product = "fennec"
|
||||
self.lastTestSeen = "remoteautomation.py"
|
||||
Automation.__init__(self)
|
||||
|
||||
def setDeviceManager(self, deviceManager):
|
||||
@ -61,11 +63,13 @@ class RemoteAutomation(Automation):
|
||||
|
||||
return env
|
||||
|
||||
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsDir):
|
||||
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath):
|
||||
""" Wait for tests to finish (as evidenced by the process exiting),
|
||||
or for maxTime elapse, in which case kill the process regardless.
|
||||
"""
|
||||
# maxTime is used to override the default timeout, we should honor that
|
||||
status = proc.wait(timeout = maxTime)
|
||||
|
||||
print proc.stdout
|
||||
self.lastTestSeen = proc.getLastTestSeen
|
||||
|
||||
if (status == 1 and self._devicemanager.processExist(proc.procName)):
|
||||
# Then we timed out, make sure Fennec is dead
|
||||
@ -128,6 +132,7 @@ class RemoteAutomation(Automation):
|
||||
def __init__(self, dm, cmd, stdout = None, stderr = None, env = None, cwd = None):
|
||||
self.dm = dm
|
||||
self.stdoutlen = 0
|
||||
self.lastTestSeen = "remoteautomation.py"
|
||||
self.proc = dm.launchProcess(cmd, stdout, cwd, env, True)
|
||||
if (self.proc is None):
|
||||
if cmd[0] == 'am':
|
||||
@ -177,6 +182,9 @@ class RemoteAutomation(Automation):
|
||||
|
||||
@property
|
||||
def stdout(self):
|
||||
""" Fetch the full remote log file using devicemanager and return just
|
||||
the new log entries since the last call (as a multi-line string).
|
||||
"""
|
||||
if self.dm.fileExists(self.proc):
|
||||
try:
|
||||
t = self.dm.pullFile(self.proc)
|
||||
@ -185,13 +193,22 @@ class RemoteAutomation(Automation):
|
||||
# function in dmSUT, so an error here is not necessarily
|
||||
# the end of the world
|
||||
return ''
|
||||
tlen = len(t)
|
||||
retVal = t[self.stdoutlen:]
|
||||
self.stdoutlen = tlen
|
||||
return retVal.strip('\n').strip()
|
||||
newLogContent = t[self.stdoutlen:]
|
||||
self.stdoutlen = len(t)
|
||||
# Match the test filepath from the last TEST-START line found in the new
|
||||
# log content. These lines are in the form:
|
||||
# 1234 INFO TEST-START | /filepath/we/wish/to/capture.html\n
|
||||
testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", newLogContent)
|
||||
if testStartFilenames:
|
||||
self.lastTestSeen = testStartFilenames[-1]
|
||||
return newLogContent.strip('\n').strip()
|
||||
else:
|
||||
return ''
|
||||
|
||||
@property
|
||||
def getLastTestSeen(self):
|
||||
return self.lastTestSeen
|
||||
|
||||
def wait(self, timeout = None):
|
||||
timer = 0
|
||||
interval = 5
|
||||
@ -207,6 +224,9 @@ class RemoteAutomation(Automation):
|
||||
if (timer > timeout):
|
||||
break
|
||||
|
||||
# Flush anything added to stdout during the sleep
|
||||
print self.stdout
|
||||
|
||||
if (timer >= timeout):
|
||||
return 1
|
||||
return 0
|
||||
|
@ -107,6 +107,7 @@ check-one-remote:
|
||||
$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
|
||||
-I$(topsrcdir)/build \
|
||||
-I$(topsrcdir)/build/mobile \
|
||||
-I$(topsrcdir)/testing/mozbase/mozdevice/mozdevice \
|
||||
$(testxpcsrcdir)/remotexpcshelltests.py \
|
||||
--symbols-path=$(DIST)/crashreporter-symbols \
|
||||
--build-info-json=$(DEPTH)/mozinfo.json \
|
||||
|
@ -49,7 +49,7 @@ class nsDOMDataChannel : public nsDOMEventTargetHelper,
|
||||
public mozilla::DataChannelListener
|
||||
{
|
||||
public:
|
||||
nsDOMDataChannel(mozilla::DataChannel* aDataChannel)
|
||||
nsDOMDataChannel(already_AddRefed<mozilla::DataChannel> aDataChannel)
|
||||
: mDataChannel(aDataChannel)
|
||||
, mBinaryType(DC_BINARY_TYPE_BLOB)
|
||||
{}
|
||||
@ -92,7 +92,7 @@ private:
|
||||
JSContext *aCx);
|
||||
|
||||
// Owning reference
|
||||
nsAutoPtr<mozilla::DataChannel> mDataChannel;
|
||||
nsRefPtr<mozilla::DataChannel> mDataChannel;
|
||||
nsString mOrigin;
|
||||
enum
|
||||
{
|
||||
@ -492,7 +492,7 @@ nsDOMDataChannel::AppReady()
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
NS_NewDOMDataChannel(mozilla::DataChannel* aDataChannel,
|
||||
NS_NewDOMDataChannel(already_AddRefed<mozilla::DataChannel> aDataChannel,
|
||||
nsPIDOMWindow* aWindow,
|
||||
nsIDOMDataChannel** aDomDataChannel)
|
||||
{
|
||||
|
@ -10,6 +10,7 @@
|
||||
// This defines only what's necessary to create nsDOMDataChannels, since this
|
||||
// gets used with MOZ_INTERNAL_API not set for media/webrtc/signaling/testing
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMDataChannel.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -19,7 +20,7 @@ namespace mozilla {
|
||||
class nsPIDOMWindow;
|
||||
|
||||
nsresult
|
||||
NS_NewDOMDataChannel(mozilla::DataChannel* dataChannel,
|
||||
NS_NewDOMDataChannel(already_AddRefed<mozilla::DataChannel> dataChannel,
|
||||
nsPIDOMWindow* aWindow,
|
||||
nsIDOMDataChannel** domDataChannel);
|
||||
|
||||
|
@ -744,21 +744,21 @@ class nsDOMMemoryFileDataOwnerMemoryReporter
|
||||
sha1.finish(digest);
|
||||
|
||||
nsAutoCString digestString;
|
||||
for (uint8_t i = 0; i < sizeof(digest); i++) {
|
||||
for (size_t i = 0; i < sizeof(digest); i++) {
|
||||
digestString.AppendPrintf("%02x", digest[i]);
|
||||
}
|
||||
|
||||
nsresult rv = aCallback->Callback(
|
||||
/* process */ NS_LITERAL_CSTRING(""),
|
||||
nsPrintfCString(
|
||||
"explicit/dom/memory-file-data/large/file(length=%d, sha1=%s)",
|
||||
"explicit/dom/memory-file-data/large/file(length=%llu, sha1=%s)",
|
||||
owner->mLength, digestString.get()),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES,
|
||||
size,
|
||||
nsPrintfCString(
|
||||
"Memory used to back a memory file of length %d. The file has a "
|
||||
"sha1 of %s.\n\n"
|
||||
"Memory used to back a memory file of length %llu bytes. The file "
|
||||
"has a sha1 of %s.\n\n"
|
||||
"Note that the allocator may round up a memory file's length -- "
|
||||
"that is, an N-byte memory file may take up more than N bytes of "
|
||||
"memory.",
|
||||
|
@ -570,6 +570,7 @@ GK_ATOM(mousethrough, "mousethrough")
|
||||
GK_ATOM(mouseup, "mouseup")
|
||||
GK_ATOM(mozfullscreenchange, "mozfullscreenchange")
|
||||
GK_ATOM(mozfullscreenerror, "mozfullscreenerror")
|
||||
GK_ATOM(mozpasspointerevents, "mozpasspointerevents")
|
||||
GK_ATOM(mozpointerlockchange, "mozpointerlockchange")
|
||||
GK_ATOM(mozpointerlockerror, "mozpointerlockerror")
|
||||
GK_ATOM(moz_opaque, "moz-opaque")
|
||||
|
@ -465,6 +465,8 @@ nsXMLHttpRequest::Init(nsIPrincipal* aPrincipal,
|
||||
nsPIDOMWindow* aOwnerWindow,
|
||||
nsIURI* aBaseURI)
|
||||
{
|
||||
NS_ASSERTION(!aOwnerWindow || aOwnerWindow->IsOuterWindow(),
|
||||
"Expecting an outer window here!");
|
||||
NS_ENSURE_ARG_POINTER(aPrincipal);
|
||||
Construct(aPrincipal,
|
||||
aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nullptr,
|
||||
|
@ -312,14 +312,16 @@ public:
|
||||
static bool IsGStreamerSupportedType(const nsACString& aType);
|
||||
static bool IsH264Type(const nsACString& aType);
|
||||
static const char gH264Types[3][16];
|
||||
static char const *const gH264Codecs[7];
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static bool IsOmxEnabled();
|
||||
static bool IsOmxSupportedType(const nsACString& aType);
|
||||
static const char gOmxTypes[5][16];
|
||||
static char const *const gH264Codecs[7];
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_GSTREAMER) || defined(MOZ_WIDGET_GONK)
|
||||
static char const *const gH264Codecs[9];
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_MEDIA_PLUGINS
|
||||
|
@ -2134,12 +2134,14 @@ nsHTMLMediaElement::IsWebMType(const nsACString& aType)
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_GSTREAMER) || defined(MOZ_WIDGET_GONK)
|
||||
char const *const nsHTMLMediaElement::gH264Codecs[7] = {
|
||||
char const *const nsHTMLMediaElement::gH264Codecs[9] = {
|
||||
"avc1.42E01E", // H.264 Constrained Baseline Profile Level 3.0
|
||||
"avc1.42001E", // H.264 Baseline Profile Level 3.0
|
||||
"avc1.58A01E", // H.264 Extended Profile Level 3.0
|
||||
"avc1.4D401E", // H.264 Main Profile Level 3.0
|
||||
"avc1.64001E", // H.264 High Profile Level 3.0
|
||||
"avc1.64001F", // H.264 High Profile Level 3.1
|
||||
"mp4v.20.3", // 3GPP
|
||||
"mp4a.40.2", // AAC-LC
|
||||
nullptr
|
||||
};
|
||||
|
@ -56,12 +56,13 @@ public:
|
||||
bool found = false;
|
||||
for (uint32_t j = 0; j < mTrackMap.Length(); ++j) {
|
||||
TrackMapEntry* map = &mTrackMap[j];
|
||||
if (map->mInputPort == mInputs[i] && map->mInputTrack == tracks.get()) {
|
||||
if (map->mInputPort == mInputs[i] && map->mInputTrackID == tracks->GetID()) {
|
||||
bool trackFinished;
|
||||
if (map->mOutputTrack->IsEnded()) {
|
||||
StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID);
|
||||
if (!outputTrack || outputTrack->IsEnded()) {
|
||||
trackFinished = true;
|
||||
} else {
|
||||
CopyTrackData(j, aFrom, aTo, &trackFinished);
|
||||
CopyTrackData(tracks.get(), j, aFrom, aTo, &trackFinished);
|
||||
}
|
||||
mappedTracksFinished[j] = trackFinished;
|
||||
mappedTracksWithMatchingInputTracks[j] = true;
|
||||
@ -72,7 +73,7 @@ public:
|
||||
if (!found) {
|
||||
bool trackFinished = false;
|
||||
uint32_t mapIndex = AddTrack(mInputs[i], tracks.get(), aFrom);
|
||||
CopyTrackData(mapIndex, aFrom, aTo, &trackFinished);
|
||||
CopyTrackData(tracks.get(), mapIndex, aFrom, aTo, &trackFinished);
|
||||
mappedTracksFinished.AppendElement(trackFinished);
|
||||
mappedTracksWithMatchingInputTracks.AppendElement(true);
|
||||
}
|
||||
@ -101,8 +102,13 @@ protected:
|
||||
// Only non-ended tracks are allowed to persist in this map.
|
||||
struct TrackMapEntry {
|
||||
MediaInputPort* mInputPort;
|
||||
StreamBuffer::Track* mInputTrack;
|
||||
StreamBuffer::Track* mOutputTrack;
|
||||
// We keep track IDs instead of track pointers because
|
||||
// tracks can be removed without us being notified (e.g.
|
||||
// when a finished track is forgotten.) When we need a Track*,
|
||||
// we call StreamBuffer::FindTrack, which will return null if
|
||||
// the track has been deleted.
|
||||
TrackID mInputTrackID;
|
||||
TrackID mOutputTrackID;
|
||||
nsAutoPtr<MediaSegment> mSegment;
|
||||
};
|
||||
|
||||
@ -137,15 +143,15 @@ protected:
|
||||
|
||||
TrackMapEntry* map = mTrackMap.AppendElement();
|
||||
map->mInputPort = aPort;
|
||||
map->mInputTrack = aTrack;
|
||||
map->mOutputTrack = track;
|
||||
map->mInputTrackID = aTrack->GetID();
|
||||
map->mOutputTrackID = track->GetID();
|
||||
map->mSegment = aTrack->GetSegment()->CreateEmptyClone();
|
||||
return mTrackMap.Length() - 1;
|
||||
}
|
||||
void EndTrack(uint32_t aIndex)
|
||||
{
|
||||
StreamBuffer::Track* outputTrack = mTrackMap[aIndex].mOutputTrack;
|
||||
if (outputTrack->IsEnded())
|
||||
StreamBuffer::Track* outputTrack = mBuffer.FindTrack(mTrackMap[aIndex].mOutputTrackID);
|
||||
if (!outputTrack || outputTrack->IsEnded())
|
||||
return;
|
||||
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
|
||||
MediaStreamListener* l = mListeners[j];
|
||||
@ -159,18 +165,18 @@ protected:
|
||||
}
|
||||
outputTrack->SetEnded();
|
||||
}
|
||||
void CopyTrackData(uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo,
|
||||
void CopyTrackData(StreamBuffer::Track* aInputTrack,
|
||||
uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo,
|
||||
bool* aOutputTrackFinished)
|
||||
{
|
||||
TrackMapEntry* map = &mTrackMap[aMapIndex];
|
||||
StreamBuffer::Track* inputTrack = map->mInputTrack;
|
||||
StreamBuffer::Track* outputTrack = map->mOutputTrack;
|
||||
StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID);
|
||||
MOZ_ASSERT(outputTrack && !outputTrack->IsEnded(), "Can't copy to ended track");
|
||||
|
||||
TrackRate rate = outputTrack->GetRate();
|
||||
MediaSegment* segment = map->mSegment;
|
||||
MediaStream* source = map->mInputPort->GetSource();
|
||||
|
||||
NS_ASSERTION(!outputTrack->IsEnded(), "Can't copy to ended track");
|
||||
|
||||
GraphTime next;
|
||||
*aOutputTrackFinished = false;
|
||||
for (GraphTime t = aFrom; t < aTo; t = next) {
|
||||
@ -194,10 +200,10 @@ protected:
|
||||
StreamTime inputEnd = source->GraphTimeToStreamTime(interval.mEnd);
|
||||
TrackTicks inputTrackEndPoint = TRACK_TICKS_MAX;
|
||||
|
||||
if (inputTrack->IsEnded()) {
|
||||
TrackTicks inputEndTicks = inputTrack->TimeToTicksRoundDown(inputEnd);
|
||||
if (inputTrack->GetEnd() <= inputEndTicks) {
|
||||
inputTrackEndPoint = inputTrack->GetEnd();
|
||||
if (aInputTrack->IsEnded()) {
|
||||
TrackTicks inputEndTicks = aInputTrack->TimeToTicksRoundDown(inputEnd);
|
||||
if (aInputTrack->GetEnd() <= inputEndTicks) {
|
||||
inputTrackEndPoint = aInputTrack->GetEnd();
|
||||
*aOutputTrackFinished = true;
|
||||
}
|
||||
}
|
||||
@ -217,7 +223,7 @@ protected:
|
||||
// We'll take the latest samples we can.
|
||||
TrackTicks inputEndTicks = TimeToTicksRoundUp(rate, inputEnd);
|
||||
TrackTicks inputStartTicks = inputEndTicks - ticks;
|
||||
segment->AppendSlice(*inputTrack->GetSegment(),
|
||||
segment->AppendSlice(*aInputTrack->GetSegment(),
|
||||
NS_MIN(inputTrackEndPoint, inputStartTicks),
|
||||
NS_MIN(inputTrackEndPoint, inputEndTicks));
|
||||
LOG(PR_LOG_DEBUG, ("TrackUnionStream %p appending %lld ticks of input data to track %d",
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "AudioBufferSourceNode.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "GainNode.h"
|
||||
#include "DelayNode.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -94,6 +95,13 @@ AudioContext::CreateGain()
|
||||
return gainNode.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DelayNode>
|
||||
AudioContext::CreateDelay(float aMaxDelayTime)
|
||||
{
|
||||
nsRefPtr<DelayNode> delayNode = new DelayNode(this, aMaxDelayTime);
|
||||
return delayNode.forget();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ class AudioDestinationNode;
|
||||
class AudioBufferSourceNode;
|
||||
class AudioBuffer;
|
||||
class GainNode;
|
||||
class DelayNode;
|
||||
|
||||
class AudioContext MOZ_FINAL : public nsWrapperCache,
|
||||
public EnableWebAudioCheck
|
||||
@ -65,6 +66,9 @@ public:
|
||||
already_AddRefed<GainNode>
|
||||
CreateGain();
|
||||
|
||||
already_AddRefed<DelayNode>
|
||||
CreateDelay(float aMaxDelayTime);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDOMWindow> mWindow;
|
||||
nsRefPtr<AudioDestinationNode> mDestination;
|
||||
|
42
content/media/webaudio/DelayNode.cpp
Normal file
42
content/media/webaudio/DelayNode.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DelayNode.h"
|
||||
#include "mozilla/dom/DelayNodeBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(DelayNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DelayNode, AudioNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDelay)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DelayNode, AudioNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mDelay, AudioParam, "delay value")
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DelayNode)
|
||||
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(DelayNode, AudioNode)
|
||||
NS_IMPL_RELEASE_INHERITED(DelayNode, AudioNode)
|
||||
|
||||
DelayNode::DelayNode(AudioContext* aContext, float aMaxDelay)
|
||||
: AudioNode(aContext)
|
||||
, mDelay(new AudioParam(aContext, 0.0f, 0.0f, aMaxDelay))
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DelayNode::WrapObject(JSContext* aCx, JSObject* aScope,
|
||||
bool* aTriedToWrap)
|
||||
{
|
||||
return DelayNodeBinding::Wrap(aCx, aScope, this, aTriedToWrap);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
51
content/media/webaudio/DelayNode.h
Normal file
51
content/media/webaudio/DelayNode.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DelayNode_h_
|
||||
#define DelayNode_h_
|
||||
|
||||
#include "AudioNode.h"
|
||||
#include "AudioParam.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class AudioContext;
|
||||
|
||||
class DelayNode : public AudioNode
|
||||
{
|
||||
public:
|
||||
DelayNode(AudioContext* aContext, float aMaxDelay);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DelayNode, AudioNode)
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
|
||||
bool* aTriedToWrap);
|
||||
|
||||
virtual uint32_t MaxNumberOfInputs() const MOZ_FINAL MOZ_OVERRIDE
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
virtual uint32_t MaxNumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioParam* DelayTime() const
|
||||
{
|
||||
return mDelay;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<AudioParam> mDelay;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@ CPPSRCS := \
|
||||
AudioNode.cpp \
|
||||
AudioParam.cpp \
|
||||
AudioSourceNode.cpp \
|
||||
DelayNode.cpp \
|
||||
EnableWebAudioCheck.cpp \
|
||||
GainNode.cpp \
|
||||
$(NULL)
|
||||
@ -34,6 +35,7 @@ EXPORTS_mozilla/dom := \
|
||||
AudioNode.h \
|
||||
AudioParam.h \
|
||||
AudioSourceNode.h \
|
||||
DelayNode.h \
|
||||
GainNode.h \
|
||||
$(NULL)
|
||||
|
||||
|
@ -14,6 +14,7 @@ MOCHITEST_FILES := \
|
||||
test_AudioBuffer.html \
|
||||
test_AudioContext.html \
|
||||
test_badConnect.html \
|
||||
test_delayNode.html \
|
||||
test_gainNode.html \
|
||||
test_singleSourceDest.html \
|
||||
$(NULL)
|
||||
|
69
content/media/webaudio/test/test_delayNode.html
Normal file
69
content/media/webaudio/test/test_delayNode.html
Normal file
@ -0,0 +1,69 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test DelayNode</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
SpecialPowers.setBoolPref("media.webaudio.enabled", true);
|
||||
|
||||
var context = new mozAudioContext();
|
||||
var buffer = context.createBuffer(1, 2048, 44100);
|
||||
for (var i = 0; i < 2048; ++i) {
|
||||
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / 44100);
|
||||
}
|
||||
|
||||
var destination = context.destination;
|
||||
|
||||
var source = context.createBufferSource();
|
||||
|
||||
var delay = context.createDelay();
|
||||
|
||||
source.buffer = buffer;
|
||||
|
||||
source.connect(delay);
|
||||
delay.connect(destination);
|
||||
|
||||
ok(delay.delayTime, "The audioparam member must exist");
|
||||
is(delay.delayTime.value, 0, "Correct initial value");
|
||||
is(delay.delayTime.defaultValue, 0, "Correct default value");
|
||||
is(delay.delayTime.minValue, 0, "Correct min value");
|
||||
is(delay.delayTime.maxValue, 1.0, "Correct max value");
|
||||
delay.delayTime.value = 0.5;
|
||||
is(delay.delayTime.value, 0.5, "Correct initial value");
|
||||
is(delay.delayTime.defaultValue, 0, "Correct default value");
|
||||
is(delay.delayTime.minValue, 0, "Correct min value");
|
||||
is(delay.delayTime.maxValue, 1.0, "Correct max value");
|
||||
|
||||
var delay2 = context.createDelay(2);
|
||||
is(delay2.delayTime.value, 0, "Correct initial value");
|
||||
is(delay2.delayTime.defaultValue, 0, "Correct default value");
|
||||
is(delay2.delayTime.minValue, 0, "Correct min value");
|
||||
is(delay2.delayTime.maxValue, 2.0, "Correct max value");
|
||||
delay2.delayTime.value = 0.5;
|
||||
is(delay2.delayTime.value, 0.5, "Correct initial value");
|
||||
is(delay2.delayTime.defaultValue, 0, "Correct default value");
|
||||
is(delay2.delayTime.minValue, 0, "Correct min value");
|
||||
is(delay2.delayTime.maxValue, 2.0, "Correct max value");
|
||||
|
||||
source.start(0);
|
||||
SimpleTest.executeSoon(function() {
|
||||
source.stop(0);
|
||||
source.disconnect();
|
||||
delay.disconnect();
|
||||
|
||||
SpecialPowers.clearUserPref("media.webaudio.enabled");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -806,7 +806,10 @@ nsresult nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
|
||||
if (((spaceLoc < dotLoc || quoteLoc < dotLoc) &&
|
||||
(spaceLoc < colonLoc || quoteLoc < colonLoc) &&
|
||||
(spaceLoc < qMarkLoc || quoteLoc < qMarkLoc)) ||
|
||||
qMarkLoc == 0)
|
||||
qMarkLoc == 0 ||
|
||||
(dotLoc == uint32_t(kNotFound) &&
|
||||
colonLoc == uint32_t(kNotFound) &&
|
||||
qMarkLoc == uint32_t(kNotFound) ) )
|
||||
{
|
||||
KeywordToURI(aURIString, aURI);
|
||||
}
|
||||
|
@ -3666,7 +3666,7 @@ MaxScriptRunTimePrefChangedCallback(const char *aPrefName, void *aClosure)
|
||||
PRTime t;
|
||||
if (time <= 0) {
|
||||
// Let scripts run for a really, really long time.
|
||||
t = LL_INIT(0x40000000, 0);
|
||||
t = 0x40000000LL << 32;
|
||||
} else {
|
||||
t = time * PR_USEC_PER_SEC;
|
||||
}
|
||||
|
@ -140,6 +140,11 @@ DOMInterfaces = {
|
||||
'nativeType': 'nsICSSDeclaration'
|
||||
},
|
||||
|
||||
'DelayNode': [
|
||||
{
|
||||
'resultNotAddRefed': [ 'delayTime' ],
|
||||
}],
|
||||
|
||||
'Document': [
|
||||
{
|
||||
'nativeType': 'nsIDocument',
|
||||
|
@ -1897,6 +1897,14 @@ class IDLValue(IDLObject):
|
||||
else:
|
||||
raise WebIDLError("Value %s is out of range for type %s." %
|
||||
(self.value, type), [location])
|
||||
elif self.type.isInteger() and type.isFloat():
|
||||
# Convert an integer literal into float
|
||||
if -2**24 <= self.value <= 2**24:
|
||||
floatType = BuiltinTypes[IDLBuiltinType.Types.float]
|
||||
return IDLValue(self.location, floatType, float(self.value))
|
||||
else:
|
||||
raise WebIDLError("Converting value %s to %s will lose precision." %
|
||||
(self.value, type), [location])
|
||||
elif self.type.isString() and type.isEnum():
|
||||
# Just keep our string, but make sure it's a valid value for this enum
|
||||
if self.value not in type.inner.values():
|
||||
|
@ -118,6 +118,19 @@ def WebIDLTest(parser, harness):
|
||||
[("Float",
|
||||
[("::TestMethods::doFloats::arg1", "arg1", "Float", False, False)])])
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface A {
|
||||
void foo(optional float bar = 1);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except Exception, x:
|
||||
threw = True
|
||||
harness.ok(not threw, "Should allow integer to float type corecion")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
|
@ -29,11 +29,9 @@ USING_BLUETOOTH_NAMESPACE
|
||||
static struct BluedroidFunctions
|
||||
{
|
||||
bool initialized;
|
||||
bool tried_initialization;
|
||||
|
||||
BluedroidFunctions() :
|
||||
initialized(false),
|
||||
tried_initialization(false)
|
||||
initialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -42,17 +40,13 @@ static struct BluedroidFunctions
|
||||
int (* bt_is_enabled)();
|
||||
} sBluedroidFunctions;
|
||||
|
||||
bool
|
||||
static bool
|
||||
EnsureBluetoothInit()
|
||||
{
|
||||
if (sBluedroidFunctions.tried_initialization)
|
||||
{
|
||||
return sBluedroidFunctions.initialized;
|
||||
if (sBluedroidFunctions.initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sBluedroidFunctions.initialized = false;
|
||||
sBluedroidFunctions.tried_initialization = true;
|
||||
|
||||
void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
|
||||
|
||||
if (!handle) {
|
||||
@ -75,29 +69,12 @@ EnsureBluetoothInit()
|
||||
NS_ERROR("Failed to attach bt_is_enabled function");
|
||||
return false;
|
||||
}
|
||||
|
||||
sBluedroidFunctions.initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
IsBluetoothEnabled()
|
||||
{
|
||||
return sBluedroidFunctions.bt_is_enabled();
|
||||
}
|
||||
|
||||
int
|
||||
EnableBluetooth()
|
||||
{
|
||||
return sBluedroidFunctions.bt_enable();
|
||||
}
|
||||
|
||||
int
|
||||
DisableBluetooth()
|
||||
{
|
||||
return sBluedroidFunctions.bt_disable();
|
||||
}
|
||||
|
||||
nsresult
|
||||
static nsresult
|
||||
StartStopGonkBluetooth(bool aShouldEnable)
|
||||
{
|
||||
bool result;
|
||||
@ -111,16 +88,26 @@ StartStopGonkBluetooth(bool aShouldEnable)
|
||||
}
|
||||
|
||||
// return 1 if it's enabled, 0 if it's disabled, and -1 on error
|
||||
int isEnabled = IsBluetoothEnabled();
|
||||
int isEnabled = sBluedroidFunctions.bt_is_enabled();
|
||||
|
||||
if ((isEnabled == 1 && aShouldEnable) || (isEnabled == 0 && !aShouldEnable)) {
|
||||
result = true;
|
||||
} else if (isEnabled < 0) {
|
||||
result = false;
|
||||
} else if (aShouldEnable) {
|
||||
result = (EnableBluetooth() == 0) ? true : false;
|
||||
return NS_OK;
|
||||
}
|
||||
if (aShouldEnable) {
|
||||
result = (sBluedroidFunctions.bt_enable() == 0) ? true : false;
|
||||
if (sBluedroidFunctions.bt_is_enabled() < 0) {
|
||||
// if isEnabled < 0, this means we brought up the firmware, but something
|
||||
// went wrong with bluetoothd. Post a warning message, but try to proceed
|
||||
// with firmware unloading if that was requested, so we can retry later.
|
||||
NS_WARNING("Bluetooth firmware up, but cannot connect to HCI socket! Check bluetoothd and try stopping/starting bluetooth again.");
|
||||
// Just disable now, return an error.
|
||||
if (sBluedroidFunctions.bt_disable() != 0) {
|
||||
NS_WARNING("Problem shutting down bluetooth after error in bringup!");
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
result = (DisableBluetooth() == 0) ? true : false;
|
||||
result = (sBluedroidFunctions.bt_disable() == 0) ? true : false;
|
||||
}
|
||||
if (!result) {
|
||||
NS_WARNING("Could not set gonk bluetooth firmware!");
|
||||
|
@ -26,6 +26,7 @@ CameraControlImpl::CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThrea
|
||||
, mStartRecordingOnErrorCb(nullptr)
|
||||
, mOnShutterCb(nullptr)
|
||||
, mOnClosedCb(nullptr)
|
||||
, mOnRecorderStateChangeCb(nullptr)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
}
|
||||
@ -221,6 +222,20 @@ CameraControlImpl::Get(nsICameraClosedCallback** aOnClosed)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Set(nsICameraRecorderStateChange* aOnRecorderStateChange)
|
||||
{
|
||||
mOnRecorderStateChangeCb = aOnRecorderStateChange;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::Get(nsICameraRecorderStateChange** aOnRecorderStateChange)
|
||||
{
|
||||
*aOnRecorderStateChange = mOnRecorderStateChangeCb;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<RecorderProfileManager>
|
||||
CameraControlImpl::GetRecorderProfileManager()
|
||||
{
|
||||
@ -239,6 +254,7 @@ CameraControlImpl::Shutdown()
|
||||
mStartRecordingOnErrorCb = nullptr;
|
||||
mOnShutterCb = nullptr;
|
||||
mOnClosedCb = nullptr;
|
||||
mOnRecorderStateChangeCb = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
@ -279,6 +295,18 @@ CameraControlImpl::OnClosed()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CameraControlImpl::OnRecorderStateChange(const nsString& aStateMsg, int32_t aStatus, int32_t aTrackNumber)
|
||||
{
|
||||
DOM_CAMERA_LOGI("OnRecorderStateChange: '%s'\n", NS_ConvertUTF16toUTF8(aStateMsg).get());
|
||||
|
||||
nsCOMPtr<nsIRunnable> onRecorderStateChange = new CameraRecorderStateChange(mOnRecorderStateChangeCb, aStateMsg, aStatus, aTrackNumber, mWindowId);
|
||||
nsresult rv = NS_DispatchToMainThread(onRecorderStateChange);
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Failed to dispatch onRecorderStateChange event to main thread (%d)\n", rv);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
CameraControlImpl::GetPreviewStream(CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError)
|
||||
{
|
||||
|
@ -67,6 +67,8 @@ public:
|
||||
nsresult Get(nsICameraShutterCallback** aOnShutter);
|
||||
nsresult Set(nsICameraClosedCallback* aOnClosed);
|
||||
nsresult Get(nsICameraClosedCallback** aOnClosed);
|
||||
nsresult Set(nsICameraRecorderStateChange* aOnRecorderStateChange);
|
||||
nsresult Get(nsICameraRecorderStateChange** aOnRecorderStateChange);
|
||||
|
||||
nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue)
|
||||
{
|
||||
@ -96,6 +98,7 @@ public:
|
||||
bool ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder);
|
||||
void OnShutter();
|
||||
void OnClosed();
|
||||
void OnRecorderStateChange(const nsString& aStateMsg, int32_t aStatus, int32_t aTrackNumber);
|
||||
|
||||
uint64_t GetWindowId()
|
||||
{
|
||||
@ -145,6 +148,7 @@ protected:
|
||||
nsCOMPtr<nsICameraErrorCallback> mStartRecordingOnErrorCb;
|
||||
nsCOMPtr<nsICameraShutterCallback> mOnShutterCb;
|
||||
nsCOMPtr<nsICameraClosedCallback> mOnClosedCb;
|
||||
nsCOMPtr<nsICameraRecorderStateChange> mOnRecorderStateChangeCb;
|
||||
|
||||
private:
|
||||
CameraControlImpl(const CameraControlImpl&) MOZ_DELETE;
|
||||
@ -607,6 +611,37 @@ public:
|
||||
nsCOMPtr<nsICameraErrorCallback> mOnErrorCb;
|
||||
};
|
||||
|
||||
// Error result runnable
|
||||
class CameraRecorderStateChange : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CameraRecorderStateChange(nsICameraRecorderStateChange* onStateChange, const nsString& aStateMsg, int32_t aStatus, int32_t aTrackNumber, uint64_t aWindowId)
|
||||
: mOnStateChangeCb(onStateChange)
|
||||
, mStateMsg(aStateMsg)
|
||||
, mStatus(aStatus)
|
||||
, mTrackNumber(aTrackNumber)
|
||||
, mWindowId(aWindowId)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mOnStateChangeCb && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
|
||||
// For now, just pass the state message and swallow mStatus and mTrackNumber
|
||||
mOnStateChangeCb->HandleStateChange(mStateMsg);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsICameraRecorderStateChange> mOnStateChangeCb;
|
||||
const nsString mStateMsg;
|
||||
int32_t mStatus;
|
||||
int32_t mTrackNumber;
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CAMERA_CAMERACONTROLIMPL_H
|
||||
|
@ -229,6 +229,18 @@ nsDOMCameraControl::SetOnClosed(nsICameraClosedCallback* aOnClosed)
|
||||
return mCameraControl->Set(aOnClosed);
|
||||
}
|
||||
|
||||
/* attribute nsICameraRecorderStateChange onRecorderStateChange; */
|
||||
NS_IMETHODIMP
|
||||
nsDOMCameraControl::GetOnRecorderStateChange(nsICameraRecorderStateChange** aOnRecorderStateChange)
|
||||
{
|
||||
return mCameraControl->Get(aOnRecorderStateChange);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsDOMCameraControl::SetOnRecorderStateChange(nsICameraRecorderStateChange* aOnRecorderStateChange)
|
||||
{
|
||||
return mCameraControl->Set(aOnRecorderStateChange);
|
||||
}
|
||||
|
||||
/* [implicit_jscontext] void startRecording (in jsval aOptions, in nsIDOMDeviceStorage storageArea, in DOMString filename, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
|
||||
NS_IMETHODIMP
|
||||
nsDOMCameraControl::StartRecording(const JS::Value& aOptions, nsIDOMDeviceStorage* storageArea, const nsAString& filename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
|
||||
@ -237,6 +249,11 @@ nsDOMCameraControl::StartRecording(const JS::Value& aOptions, nsIDOMDeviceStorag
|
||||
NS_ENSURE_TRUE(storageArea, NS_ERROR_INVALID_ARG);
|
||||
|
||||
CameraStartRecordingOptions options;
|
||||
|
||||
// Default values, until the dictionary parser can handle them.
|
||||
options.rotation = 0;
|
||||
options.maxFileSizeBytes = 0;
|
||||
options.maxVideoLengthMs = 0;
|
||||
nsresult rv = options.Init(cx, &aOptions);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "nsThread.h"
|
||||
#include <media/MediaProfiles.h>
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include <media/mediaplayer.h>
|
||||
#include "nsDirectoryServiceDefs.h" // for NS_GetSpecialDirectory
|
||||
#include "nsPrintfCString.h"
|
||||
#include "DOMCameraManager.h"
|
||||
@ -741,7 +742,7 @@ nsGonkCameraControl::StartRecordingImpl(StartRecordingTask* aStartRecording)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = SetupRecording(fd);
|
||||
nsresult rv = SetupRecording(fd, aStartRecording->mOptions.maxFileSizeBytes, aStartRecording->mOptions.maxVideoLengthMs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mRecorder->start() != OK) {
|
||||
@ -914,8 +915,154 @@ nsGonkCameraControl::SetupVideoMode(const nsAString& aProfile)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class GonkRecorderListener : public IMediaRecorderClient
|
||||
{
|
||||
public:
|
||||
GonkRecorderListener(nsGonkCameraControl* aCameraControl)
|
||||
: mCameraControl(aCameraControl)
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p, aCameraControl=%p\n", __func__, __LINE__, this, mCameraControl.get());
|
||||
}
|
||||
|
||||
void notify(int msg, int ext1, int ext2)
|
||||
{
|
||||
if (mCameraControl) {
|
||||
mCameraControl->HandleRecorderEvent(msg, ext1, ext2);
|
||||
}
|
||||
}
|
||||
|
||||
IBinder* onAsBinder()
|
||||
{
|
||||
DOM_CAMERA_LOGE("onAsBinder() called, should NEVER get called!\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
~GonkRecorderListener() { }
|
||||
nsRefPtr<nsGonkCameraControl> mCameraControl;
|
||||
};
|
||||
|
||||
void
|
||||
nsGonkCameraControl::HandleRecorderEvent(int msg, int ext1, int ext2)
|
||||
{
|
||||
/**
|
||||
* Refer to base/include/media/mediarecorder.h for a complete list
|
||||
* of error and info message codes. There are duplicate values
|
||||
* within the status/error code space, as determined by code inspection:
|
||||
*
|
||||
* +------- msg
|
||||
* | +----- ext1
|
||||
* | | +--- ext2
|
||||
* V V V
|
||||
* 1 MEDIA_RECORDER_EVENT_ERROR
|
||||
* 1 MEDIA_RECORDER_ERROR_UNKNOWN
|
||||
* [3] ERROR_MALFORMED
|
||||
* 100 mediaplayer.h::MEDIA_ERROR_SERVER_DIED
|
||||
* 0 <always zero>
|
||||
* 2 MEDIA_RECORDER_EVENT_INFO
|
||||
* 800 MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
|
||||
* 0 <always zero>
|
||||
* 801 MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED
|
||||
* 0 <always zero>
|
||||
* 1000 MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS[1b]
|
||||
* [3] UNKNOWN_ERROR, etc.
|
||||
* 100 MEDIA_ERROR[4]
|
||||
* 100 mediaplayer.h::MEDIA_ERROR_SERVER_DIED
|
||||
* 0 <always zero>
|
||||
* 100 MEDIA_RECORDER_TRACK_EVENT_ERROR
|
||||
* 100 MEDIA_RECORDER_TRACK_ERROR_GENERAL[1a]
|
||||
* [3] UNKNOWN_ERROR, etc.
|
||||
* 200 MEDIA_RECORDER_ERROR_VIDEO_NO_SYNC_FRAME[2]
|
||||
* ? <unknown>
|
||||
* 101 MEDIA_RECORDER_TRACK_EVENT_INFO
|
||||
* 1000 MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS[1a]
|
||||
* [3] UNKNOWN_ERROR, etc.
|
||||
* N see mediarecorder.h::media_recorder_info_type[5]
|
||||
*
|
||||
* 1. a) High 4 bits are the track number, the next 12 bits are reserved,
|
||||
* and the final 16 bits are the actual error code (above).
|
||||
* b) But not in this case.
|
||||
* 2. Never actually used in AOSP code?
|
||||
* 3. Specific error codes are from utils/Errors.h and/or
|
||||
* include/media/stagefright/MediaErrors.h.
|
||||
* 4. Only in frameworks/base/media/libmedia/mediaplayer.cpp.
|
||||
* 5. These are mostly informational and we can ignore them; note that
|
||||
* although the MEDIA_RECORDER_INFO_MAX_DURATION_REACHED and
|
||||
* MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED values are defined in this
|
||||
* enum, they are used with different ext1 codes. /o\
|
||||
*/
|
||||
int trackNum = -1; // no track
|
||||
|
||||
switch (msg) {
|
||||
// Recorder-related events
|
||||
case MEDIA_RECORDER_EVENT_INFO:
|
||||
switch (ext1) {
|
||||
case MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED:
|
||||
DOM_CAMERA_LOGI("recorder-event : info: maximum file size reached\n");
|
||||
OnRecorderStateChange(NS_LITERAL_STRING("FileSizeLimitReached"), ext2, trackNum);
|
||||
return;
|
||||
|
||||
case MEDIA_RECORDER_INFO_MAX_DURATION_REACHED:
|
||||
DOM_CAMERA_LOGI("recorder-event : info: maximum video duration reached\n");
|
||||
OnRecorderStateChange(NS_LITERAL_STRING("VideoLengthLimitReached"), ext2, trackNum);
|
||||
return;
|
||||
|
||||
case MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS:
|
||||
DOM_CAMERA_LOGI("recorder-event : info: track completed\n");
|
||||
OnRecorderStateChange(NS_LITERAL_STRING("TrackCompleted"), ext2, trackNum);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case MEDIA_RECORDER_EVENT_ERROR:
|
||||
switch (ext1) {
|
||||
case MEDIA_RECORDER_ERROR_UNKNOWN:
|
||||
DOM_CAMERA_LOGE("recorder-event : recorder-error: %d (0x%08x)\n", ext2, ext2);
|
||||
OnRecorderStateChange(NS_LITERAL_STRING("MediaRecorderFailed"), ext2, trackNum);
|
||||
return;
|
||||
|
||||
case MEDIA_ERROR_SERVER_DIED:
|
||||
DOM_CAMERA_LOGE("recorder-event : recorder-error: server died\n");
|
||||
OnRecorderStateChange(NS_LITERAL_STRING("MediaServerFailed"), ext2, trackNum);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
// Track-related events, see note 1(a) above.
|
||||
case MEDIA_RECORDER_TRACK_EVENT_INFO:
|
||||
trackNum = (ext1 & 0xF0000000) >> 28;
|
||||
ext1 &= 0xFFFF;
|
||||
switch (ext1) {
|
||||
case MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS:
|
||||
if (ext2 == OK) {
|
||||
DOM_CAMERA_LOGI("recorder-event : track-complete: track %d, %d (0x%08x)\n", trackNum, ext2, ext2);
|
||||
OnRecorderStateChange(NS_LITERAL_STRING("TrackCompleted"), ext2, trackNum);
|
||||
return;
|
||||
}
|
||||
DOM_CAMERA_LOGE("recorder-event : track-error: track %d, %d (0x%08x)\n", trackNum, ext2, ext2);
|
||||
OnRecorderStateChange(NS_LITERAL_STRING("TrackFailed"), ext2, trackNum);
|
||||
return;
|
||||
|
||||
case MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME:
|
||||
DOM_CAMERA_LOGI("recorder-event : track-info: progress in time: %d ms\n", ext2);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case MEDIA_RECORDER_TRACK_EVENT_ERROR:
|
||||
trackNum = (ext1 & 0xF0000000) >> 28;
|
||||
ext1 &= 0xFFFF;
|
||||
DOM_CAMERA_LOGE("recorder-event : track-error: track %d, %d (0x%08x)\n", trackNum, ext2, ext2);
|
||||
OnRecorderStateChange(NS_LITERAL_STRING("TrackFailed"), ext2, trackNum);
|
||||
return;
|
||||
}
|
||||
|
||||
// All unhandled cases wind up here
|
||||
DOM_CAMERA_LOGW("recorder-event : unhandled: msg=%d, ext1=%d, ext2=%d\n", msg, ext1, ext2);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::SetupRecording(int aFd, int aMaxFileSizeBytes, int aMaxVideoLengthMs)
|
||||
nsGonkCameraControl::SetupRecording(int aFd, int64_t aMaxFileSizeBytes, int64_t aMaxVideoLengthMs)
|
||||
{
|
||||
// choosing a size big enough to hold the params
|
||||
const size_t SIZE = 256;
|
||||
@ -929,15 +1076,25 @@ nsGonkCameraControl::SetupRecording(int aFd, int aMaxFileSizeBytes, int aMaxVide
|
||||
|
||||
CHECK_SETARG(mRecorder->setCameraHandle((int32_t)mHwHandle));
|
||||
|
||||
snprintf(buffer, SIZE, "max-duration=%d", aMaxVideoLengthMs);
|
||||
DOM_CAMERA_LOGI("maxVideoLengthMs=%lld\n", aMaxVideoLengthMs);
|
||||
if (aMaxVideoLengthMs == 0) {
|
||||
aMaxVideoLengthMs = -1;
|
||||
}
|
||||
snprintf(buffer, SIZE, "max-duration=%lld", aMaxVideoLengthMs);
|
||||
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||
|
||||
snprintf(buffer, SIZE, "max-duration=%d", aMaxFileSizeBytes);
|
||||
DOM_CAMERA_LOGI("maxFileSizeBytes=%lld\n", aMaxFileSizeBytes);
|
||||
if (aMaxFileSizeBytes == 0) {
|
||||
aMaxFileSizeBytes = -1;
|
||||
}
|
||||
snprintf(buffer, SIZE, "max-filesize=%lld", aMaxFileSizeBytes);
|
||||
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||
|
||||
snprintf(buffer, SIZE, "video-param-rotation-angle-degrees=%d", mVideoRotation);
|
||||
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||
|
||||
CHECK_SETARG(mRecorder->setListener(new GonkRecorderListener(this)));
|
||||
|
||||
// recording API needs file descriptor of output file
|
||||
CHECK_SETARG(mRecorder->setOutputFile(aFd, 0, 0));
|
||||
CHECK_SETARG(mRecorder->prepare());
|
||||
|
@ -54,11 +54,12 @@ public:
|
||||
nsresult GetVideoSizes(nsTArray<CameraSize>& aVideoSizes);
|
||||
nsresult PushParameters();
|
||||
|
||||
nsresult SetupRecording(int aFd, int aMaxFileSizeBytes = -1, int aMaxVideoLengthMs = -1);
|
||||
nsresult SetupRecording(int aFd, int64_t aMaxFileSizeBytes = -1, int64_t aMaxVideoLengthMs = -1);
|
||||
nsresult SetupVideoMode(const nsAString& aProfile);
|
||||
|
||||
void AutoFocusComplete(bool aSuccess);
|
||||
void TakePictureComplete(uint8_t* aData, uint32_t aLength);
|
||||
void HandleRecorderEvent(int msg, int ext1, int ext2);
|
||||
|
||||
protected:
|
||||
~nsGonkCameraControl();
|
||||
|
@ -42,6 +42,8 @@ public:
|
||||
virtual nsresult Get(nsICameraShutterCallback** aOnShutter) = 0;
|
||||
virtual nsresult Set(nsICameraClosedCallback* aOnClosed) = 0;
|
||||
virtual nsresult Get(nsICameraClosedCallback** aOnClosed) = 0;
|
||||
virtual nsresult Set(nsICameraRecorderStateChange* aOnRecorderStateChange) = 0;
|
||||
virtual nsresult Get(nsICameraRecorderStateChange** aOnRecorderStateChange) = 0;
|
||||
virtual nsresult SetFocusAreas(JSContext* aCx, const JS::Value& aValue) = 0;
|
||||
virtual nsresult SetMeteringAreas(JSContext* aCx, const JS::Value& aValue) = 0;
|
||||
virtual nsresult GetVideoSizes(nsTArray<CameraSize>& aVideoSizes) = 0;
|
||||
|
@ -195,8 +195,8 @@ dictionary CameraRecorderOptions
|
||||
dictionary CameraStartRecordingOptions
|
||||
{
|
||||
long rotation;
|
||||
long maxFileSizeBytes;
|
||||
long maxVideoLengthMs;
|
||||
long long maxFileSizeBytes;
|
||||
long long maxVideoLengthMs;
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(0444a687-4bc9-462c-8246-5423f0fe46a4)]
|
||||
@ -235,6 +235,12 @@ interface nsICameraClosedCallback : nsISupports
|
||||
void handleEvent();
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(550d675a-257d-4713-8b3d-0da53eba68fc)]
|
||||
interface nsICameraRecorderStateChange : nsISupports
|
||||
{
|
||||
void handleStateChange(in DOMString newState);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(a302c6c9-3776-4d1d-a395-f4105d47c3d3)]
|
||||
interface nsICameraErrorCallback : nsISupports
|
||||
{
|
||||
@ -245,7 +251,7 @@ interface nsICameraErrorCallback : nsISupports
|
||||
attributes here affect the preview, any pictures taken, and/or
|
||||
any video recorded by the camera.
|
||||
*/
|
||||
[scriptable, uuid(0f206acd-196b-4bdf-8198-44c1a0cd1998)]
|
||||
[scriptable, uuid(70f45209-b69b-4937-bbac-57d82600e2af)]
|
||||
interface nsICameraControl : nsISupports
|
||||
{
|
||||
readonly attribute nsICameraCapabilities capabilities;
|
||||
@ -341,6 +347,11 @@ interface nsICameraControl : nsISupports
|
||||
recent call to get the camera. */
|
||||
attribute nsICameraClosedCallback onClosed;
|
||||
|
||||
/* the function to call when the recorder changes state, either because
|
||||
the recording process encountered an error, or because one of the
|
||||
recording limits (see CameraStartRecordingOptions) was reached. */
|
||||
attribute nsICameraRecorderStateChange onRecorderStateChange;
|
||||
|
||||
/* tell the camera to attempt to focus the image */
|
||||
void autoFocus(in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError);
|
||||
|
||||
|
@ -87,17 +87,17 @@ IDPAuthenticationContext.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
function RPWatchContext(aID, aOrigin, aLoggedInEmail, aTargetMM) {
|
||||
function RPWatchContext(aID, aOrigin, aLoggedInUser, aTargetMM) {
|
||||
this._id = aID;
|
||||
this._origin = aOrigin;
|
||||
this._loggedInEmail = aLoggedInEmail;
|
||||
this._loggedInUser = aLoggedInUser;
|
||||
this._mm = aTargetMM;
|
||||
}
|
||||
|
||||
RPWatchContext.prototype = {
|
||||
get id() this._id,
|
||||
get origin() this._origin,
|
||||
get loggedInEmail() this._loggedInEmail,
|
||||
get loggedInUser() this._loggedInUser,
|
||||
|
||||
doLogin: function RPWatchContext_onlogin(aAssertion) {
|
||||
log("doLogin: " + this.id);
|
||||
@ -221,7 +221,7 @@ this.DOMIdentity = {
|
||||
// Pass an object with the watch members to Identity.jsm so it can call the
|
||||
// callbacks.
|
||||
let context = new RPWatchContext(message.id, message.origin,
|
||||
message.loggedInEmail, targetMM);
|
||||
message.loggedInUser, targetMM);
|
||||
IdentityService.RP.watch(context);
|
||||
},
|
||||
|
||||
|
@ -16,6 +16,7 @@ const MAX_RP_CALLS = 100;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/IdentityUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
@ -78,24 +79,30 @@ nsDOMIdentity.prototype = {
|
||||
|
||||
let message = this.DOMIdentityMessage();
|
||||
|
||||
// loggedInEmail
|
||||
message.loggedInEmail = null;
|
||||
let emailType = typeof(aOptions["loggedInEmail"]);
|
||||
if (aOptions["loggedInEmail"] && aOptions["loggedInEmail"] !== "undefined") {
|
||||
// loggedInUser vs loggedInEmail
|
||||
// https://developer.mozilla.org/en-US/docs/DOM/navigator.id.watch
|
||||
// This parameter, loggedInUser, was renamed from loggedInEmail in early
|
||||
// September, 2012. Both names will continue to work for the time being,
|
||||
// but code should be changed to use loggedInUser instead.
|
||||
checkRenamed(aOptions, "loggedInEmail", "loggedInUser");
|
||||
message["loggedInUser"] = aOptions["loggedInUser"];
|
||||
|
||||
let emailType = typeof(aOptions["loggedInUser"]);
|
||||
if (aOptions["loggedInUser"] && aOptions["loggedInUser"] !== "undefined") {
|
||||
if (emailType !== "string") {
|
||||
throw new Error("loggedInEmail must be a String or null");
|
||||
throw new Error("loggedInUser must be a String or null");
|
||||
}
|
||||
|
||||
// TODO: Bug 767610 - check email format.
|
||||
// See nsHTMLInputElement::IsValidEmailAddress
|
||||
if (aOptions["loggedInEmail"].indexOf("@") == -1
|
||||
|| aOptions["loggedInEmail"].length > MAX_STRING_LENGTH) {
|
||||
throw new Error("loggedInEmail is not valid");
|
||||
if (aOptions["loggedInUser"].indexOf("@") == -1
|
||||
|| aOptions["loggedInUser"].length > MAX_STRING_LENGTH) {
|
||||
throw new Error("loggedInUser is not valid");
|
||||
}
|
||||
// Set loggedInEmail in this block that "undefined" doesn't get through.
|
||||
message.loggedInEmail = aOptions.loggedInEmail;
|
||||
// Set loggedInUser in this block that "undefined" doesn't get through.
|
||||
message.loggedInUser = aOptions.loggedInUser;
|
||||
}
|
||||
this._log("loggedInEmail: " + message.loggedInEmail);
|
||||
this._log("loggedInUser: " + message.loggedInUser);
|
||||
|
||||
this._rpWatcher = aOptions;
|
||||
this._identityInternal._mm.sendAsyncMessage("Identity:RP:Watch", message);
|
||||
|
@ -599,21 +599,19 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mFrontSurface) {
|
||||
#ifdef MOZ_X11
|
||||
if (mFrontSurface &&
|
||||
mFrontSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
|
||||
// This is the "old front buffer" we're about to hand back to
|
||||
// the plugin. We might still have drawing operations
|
||||
// referencing it.
|
||||
mFrontSurface->Finish();
|
||||
|
||||
#ifdef MOZ_X11
|
||||
if (mFrontSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
|
||||
// XSync here to ensure the server has finished operations on the
|
||||
// surface before the plugin starts scribbling on it again, or
|
||||
// worse, destroys it.
|
||||
FinishX(DefaultXDisplay());
|
||||
}
|
||||
#endif
|
||||
// XSync here to ensure the server has finished operations on the
|
||||
// surface before the plugin starts scribbling on it again, or
|
||||
// worse, destroys it.
|
||||
FinishX(DefaultXDisplay());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mFrontSurface && gfxSharedImageSurface::IsSharedImage(mFrontSurface))
|
||||
*prevSurface = static_cast<gfxSharedImageSurface*>(mFrontSurface.get())->GetShmem();
|
||||
|
@ -3866,7 +3866,7 @@ let RIL = {
|
||||
this.sendDOMMessage(message);
|
||||
}
|
||||
|
||||
if (message.messageClass == GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]) {
|
||||
if (message && message.messageClass == GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]) {
|
||||
// `MS shall ensure that the message has been to the SMS data field in
|
||||
// the (U)SIM before sending an ACK to the SC.` ~ 3GPP 23.038 clause 4
|
||||
return PDU_FCS_RESERVED;
|
||||
|
@ -3,6 +3,6 @@ b2g = true
|
||||
browser = false
|
||||
qemu = true
|
||||
|
||||
; Bug 805539
|
||||
;[test_geolocation.js]
|
||||
; gps = true
|
||||
|
||||
[test_geolocation.js]
|
||||
|
||||
|
@ -6,7 +6,8 @@ MARIONETTE_TIMEOUT = 10000;
|
||||
let geolocation = window.navigator.geolocation;
|
||||
ok(geolocation);
|
||||
|
||||
var target = Object();
|
||||
var sample = [];
|
||||
var result = [];
|
||||
var wpid;
|
||||
|
||||
/**
|
||||
@ -14,17 +15,25 @@ var wpid;
|
||||
*/
|
||||
SpecialPowers.addPermission("geolocation", true, document);
|
||||
|
||||
/**
|
||||
* Disable wifi geolocation provider
|
||||
*/
|
||||
wifiUri = SpecialPowers.getCharPref("geo.wifi.uri");
|
||||
SpecialPowers.setCharPref("geo.wifi.uri", "http://mochi.test:8888/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs?action=stop-responding");
|
||||
|
||||
/**
|
||||
* Helper that compares the geolocation against the web API.
|
||||
*/
|
||||
function verifyLocation(callback, expectedLocation) {
|
||||
geolocation.getCurrentPosition(function(position) {
|
||||
log("Expected location: " + expectedLocation.latitude + " " + expectedLocation.longitude);
|
||||
log("Current location: " + position.coords.latitude + " " + position.coords.longitude);
|
||||
is(expectedLocation.latitude, position.coords.latitude);
|
||||
is(expectedLocation.longitude, position.coords.longitude);
|
||||
});
|
||||
window.setTimeout(callback, 0);
|
||||
function verifyLocation() {
|
||||
|
||||
log("Sample:" + sample.join(','));
|
||||
log("Result:" + result.join(','));
|
||||
|
||||
for (i in sample) {
|
||||
is(sample.pop(), result.pop());
|
||||
}
|
||||
|
||||
window.setTimeout(cleanup, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,71 +42,75 @@ function verifyLocation(callback, expectedLocation) {
|
||||
function setup() {
|
||||
log("Providing initial setup: set geographic position watcher.");
|
||||
|
||||
|
||||
wpid = geolocation.watchPosition(function(position) {
|
||||
log("Position changes has found.");
|
||||
log("Watch: Target location: " + target.latitude + " " + target.longitude);
|
||||
log("Watch: Current location: " + position.coords.latitude + " " + position.coords.longitude);
|
||||
is(target.latitude, position.coords.latitude, "Latitude isn't match!");
|
||||
is(target.longitude, position.coords.longitude, "Longitude isn't match!");
|
||||
log("Position changes: (" + position.coords.latitude + "/" + position.coords.longitude + ")");
|
||||
result.push(""+position.coords.latitude + "/" + position.coords.longitude);
|
||||
});
|
||||
|
||||
target.latitude = 0;
|
||||
target.longitude = 0;
|
||||
lat = 0;
|
||||
lon = 0;
|
||||
|
||||
cmd = "geo fix " + target.longitude + " " + target.latitude;
|
||||
cmd = "geo fix " + lon + " " + lat;
|
||||
sample.push(lat+"/"+lon);
|
||||
|
||||
runEmulatorCmd(cmd, function(result) {
|
||||
log("Geolocation setting status: " + result);
|
||||
verifyLocation(movePosition_1, target);
|
||||
window.setTimeout(movePosition_1, 0);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function movePosition_1() {
|
||||
log("Geolocation changes. Move to Position 1.");
|
||||
|
||||
target.latitude = 25;
|
||||
target.longitude = 121.56499833333334;
|
||||
lat = 25;
|
||||
lon = 121.56499833333334;
|
||||
|
||||
cmd = "geo fix " + target.longitude + " " + target.latitude;
|
||||
cmd = "geo fix " + lon + " " + lat;
|
||||
sample.push(lat+"/"+lon);
|
||||
|
||||
runEmulatorCmd(cmd, function(result) {
|
||||
log("Geolocation setting status: " + result);
|
||||
verifyLocation(movePosition_2, target);
|
||||
window.setTimeout(movePosition_2, 0);
|
||||
});
|
||||
}
|
||||
|
||||
function movePosition_2() {
|
||||
log("Geolocation changes to a negative longitude. Move to Position 2.");
|
||||
|
||||
target.latitude = 37.393;
|
||||
target.longitude = -122.08199833333335;
|
||||
lat = 37.393;
|
||||
lon = -122.08199833333335;
|
||||
|
||||
cmd = "geo fix " + target.longitude + " " + target.latitude;
|
||||
cmd = "geo fix " + lon + " " + lat;
|
||||
sample.push(lat+"/"+lon);
|
||||
|
||||
runEmulatorCmd(cmd, function(result) {
|
||||
log("Geolocation setting status: " + result);
|
||||
verifyLocation(movePosition_3, target);
|
||||
window.setTimeout(movePosition_3, 0);
|
||||
});
|
||||
}
|
||||
|
||||
function movePosition_3() {
|
||||
log("Geolocation changes with WatchPosition. Move to Position 3.");
|
||||
|
||||
target.latitude = -22;
|
||||
target.longitude = -43;
|
||||
lat = -22;
|
||||
lon = -43;
|
||||
|
||||
cmd = "geo fix " + target.longitude + " " + target.latitude;
|
||||
cmd = "geo fix " + lon + " " + lat;
|
||||
sample.push(lat+"/"+lon);
|
||||
|
||||
geolocation.getCurrentPosition(function(position) {
|
||||
log("getCurrentPosition: Expected location: ("+lat+"/"+lon+"); Current location: (" + position.coords.latitude + "/" + position.coords.longitude + ")");
|
||||
is(lat, position.coords.latitude);
|
||||
is(lon, position.coords.longitude);
|
||||
});
|
||||
|
||||
runEmulatorCmd(cmd, function(result) {
|
||||
log("Geolocation setting status: " + result);
|
||||
verifyLocation(cleanup, target);
|
||||
window.setTimeout(verifyLocation, 0);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
geolocation.clearWatch(wpid);
|
||||
SpecialPowers.removePermission("geolocation", document);
|
||||
SpecialPowers.setCharPref("geo.wifi.uri", wifiUri);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@ interface mozAudioContext {
|
||||
|
||||
[Creator]
|
||||
GainNode createGain();
|
||||
[Creator]
|
||||
DelayNode createDelay(optional float maxDelayTime = 1);
|
||||
|
||||
};
|
||||
|
||||
|
19
dom/webidl/DelayNode.webidl
Normal file
19
dom/webidl/DelayNode.webidl
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[PrefControlled]
|
||||
interface DelayNode : AudioNode {
|
||||
|
||||
readonly attribute AudioParam delayTime;
|
||||
|
||||
};
|
||||
|
@ -20,6 +20,7 @@ webidl_files = \
|
||||
CanvasRenderingContext2D.webidl \
|
||||
ClientRectList.webidl \
|
||||
CSSStyleDeclaration.webidl \
|
||||
DelayNode.webidl \
|
||||
DOMImplementation.webidl \
|
||||
DOMTokenList.webidl \
|
||||
DOMSettableTokenList.webidl \
|
||||
|
@ -40,14 +40,13 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
||||
// command always succeeds and we do a string/boolean check for the
|
||||
// expected results).
|
||||
var WifiManager = (function() {
|
||||
function getSdkVersionAndDevice() {
|
||||
function getSdkVersion() {
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
let sdkVersion = libcutils.property_get("ro.build.version.sdk");
|
||||
return { sdkVersion: parseInt(sdkVersion, 10),
|
||||
device: libcutils.property_get("ro.product.device") };
|
||||
return parseInt(sdkVersion, 10);
|
||||
}
|
||||
|
||||
let { sdkVersion, device } = getSdkVersionAndDevice();
|
||||
let sdkVersion = getSdkVersion();
|
||||
|
||||
var controlWorker = new ChromeWorker(WIFIWORKER_WORKER);
|
||||
var eventWorker = new ChromeWorker(WIFIWORKER_WORKER);
|
||||
@ -720,7 +719,7 @@ var WifiManager = (function() {
|
||||
}
|
||||
|
||||
manager.start = function() {
|
||||
debug("detected SDK version " + sdkVersion + " and device " + device);
|
||||
debug("detected SDK version " + sdkVersion);
|
||||
connectToSupplicant(connectCallback);
|
||||
}
|
||||
|
||||
@ -1008,15 +1007,11 @@ var WifiManager = (function() {
|
||||
});
|
||||
}
|
||||
|
||||
// Driver startup on the otoro takes longer than it takes for us
|
||||
// Driver startup on certain platforms takes longer than it takes for us
|
||||
// to return from loadDriver, so wait 2 seconds before starting
|
||||
// the supplicant to give it a chance to start.
|
||||
if (device === "otoro") {
|
||||
timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.init(doStartSupplicant, 2000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
} else {
|
||||
doStartSupplicant();
|
||||
}
|
||||
timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.init(doStartSupplicant, 2000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -154,12 +154,26 @@ public:
|
||||
NS_ASSERTION(mWorkerPrivate, "Must have a worker here!");
|
||||
|
||||
if (!mXHR) {
|
||||
nsPIDOMWindow* ownerWindow = mWorkerPrivate->GetWindow();
|
||||
if (ownerWindow) {
|
||||
ownerWindow = ownerWindow->GetOuterWindow();
|
||||
if (!ownerWindow) {
|
||||
NS_ERROR("No outer window?!");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsPIDOMWindow* innerWindow = ownerWindow->GetCurrentInnerWindow();
|
||||
if (mWorkerPrivate->GetWindow() != innerWindow) {
|
||||
NS_WARNING("Window has navigated, cannot create XHR here.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mXHR = new nsXMLHttpRequest();
|
||||
|
||||
if (NS_FAILED(mXHR->Init(mWorkerPrivate->GetPrincipal(),
|
||||
mWorkerPrivate->GetScriptContext(),
|
||||
mWorkerPrivate->GetWindow(),
|
||||
mWorkerPrivate->GetBaseURI()))) {
|
||||
ownerWindow, mWorkerPrivate->GetBaseURI()))) {
|
||||
mXHR = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
@ -136,15 +136,8 @@ PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
|
||||
return false;
|
||||
}
|
||||
|
||||
SkRegion pointRect;
|
||||
pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1)),
|
||||
int32_t(SkFloatToScalar(transformed.y - 1)),
|
||||
int32_t(SkFloatToScalar(transformed.x + 1)),
|
||||
int32_t(SkFloatToScalar(transformed.y + 1)));
|
||||
|
||||
SkRegion pathRegion;
|
||||
|
||||
return pathRegion.setPath(mPath, pointRect);
|
||||
return mPath.contains(SkFloatToScalar(transformed.x),
|
||||
SkFloatToScalar(transformed.y));
|
||||
}
|
||||
|
||||
static Rect SkRectToRect(const SkRect& aBounds)
|
||||
|
@ -727,6 +727,9 @@ public:
|
||||
|
||||
void SetPostScale(float aXScale, float aYScale)
|
||||
{
|
||||
if (mPostXScale == aXScale && mPostYScale == aYScale) {
|
||||
return;
|
||||
}
|
||||
mPostXScale = aXScale;
|
||||
mPostYScale = aYScale;
|
||||
Mutated();
|
||||
@ -1232,6 +1235,9 @@ public:
|
||||
|
||||
void SetPreScale(float aXScale, float aYScale)
|
||||
{
|
||||
if (mPreXScale == aXScale && mPreYScale == aYScale) {
|
||||
return;
|
||||
}
|
||||
mPreXScale = aXScale;
|
||||
mPreYScale = aYScale;
|
||||
Mutated();
|
||||
|
@ -37,7 +37,7 @@ gfxUserFontSet::GetUserFontsLog()
|
||||
#define LOG(args) PR_LOG(GetUserFontsLog(), PR_LOG_DEBUG, args)
|
||||
#define LOG_ENABLED() PR_LOG_TEST(GetUserFontsLog(), PR_LOG_DEBUG)
|
||||
|
||||
static uint64_t sFontSetGeneration = LL_INIT(0, 0);
|
||||
static uint64_t sFontSetGeneration = 0;
|
||||
|
||||
// TODO: support for unicode ranges not yet implemented
|
||||
|
||||
|
@ -16,13 +16,6 @@
|
||||
* We are specializing nsAutoRef class.
|
||||
*/
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<DBusGProxy> : public nsPointerRefTraits<DBusGProxy>
|
||||
{
|
||||
public:
|
||||
static void Release(DBusGProxy* ptr) { g_object_unref(ptr); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<GHashTable> : public nsPointerRefTraits<GHashTable>
|
||||
{
|
||||
@ -71,13 +64,17 @@ private:
|
||||
* Update the currently tracked device.
|
||||
* @return whether everything went ok.
|
||||
*/
|
||||
void UpdateTrackedDevice();
|
||||
void UpdateTrackedDeviceSync();
|
||||
|
||||
/**
|
||||
* Returns a hash table with the properties of aDevice.
|
||||
* Note: the caller has to unref the hash table.
|
||||
*/
|
||||
GHashTable* GetDeviceProperties(const gchar* aDevice);
|
||||
GHashTable* GetDevicePropertiesSync(DBusGProxy* aProxy);
|
||||
void GetDevicePropertiesAsync(DBusGProxy* aProxy);
|
||||
static void GetDevicePropertiesCallback(DBusGProxy* aProxy,
|
||||
DBusGProxyCall* aCall,
|
||||
void* aData);
|
||||
|
||||
/**
|
||||
* Using the device properties (aHashTable), this method updates the member
|
||||
@ -107,6 +104,9 @@ private:
|
||||
// The path of the tracked device.
|
||||
gchar* mTrackedDevice;
|
||||
|
||||
// The DBusGProxy for the tracked device.
|
||||
DBusGProxy* mTrackedDeviceProxy;
|
||||
|
||||
double mLevel;
|
||||
bool mCharging;
|
||||
double mRemainingTime;
|
||||
@ -165,6 +165,7 @@ UPowerClient::UPowerClient()
|
||||
: mDBusConnection(nullptr)
|
||||
, mUPowerProxy(nullptr)
|
||||
, mTrackedDevice(nullptr)
|
||||
, mTrackedDeviceProxy(nullptr)
|
||||
, mLevel(kDefaultLevel)
|
||||
, mCharging(kDefaultCharging)
|
||||
, mRemainingTime(kDefaultRemainingTime)
|
||||
@ -173,7 +174,7 @@ UPowerClient::UPowerClient()
|
||||
|
||||
UPowerClient::~UPowerClient()
|
||||
{
|
||||
NS_ASSERTION(!mDBusConnection && !mUPowerProxy && !mTrackedDevice,
|
||||
NS_ASSERTION(!mDBusConnection && !mUPowerProxy && !mTrackedDevice && !mTrackedDeviceProxy,
|
||||
"The observers have not been correctly removed! "
|
||||
"(StopListening should have been called)");
|
||||
}
|
||||
@ -206,7 +207,7 @@ UPowerClient::BeginListening()
|
||||
"/org/freedesktop/UPower",
|
||||
"org.freedesktop.UPower");
|
||||
|
||||
UpdateTrackedDevice();
|
||||
UpdateTrackedDeviceSync();
|
||||
|
||||
/*
|
||||
* TODO: we should probably listen to DeviceAdded and DeviceRemoved signals.
|
||||
@ -238,6 +239,11 @@ UPowerClient::StopListening()
|
||||
g_free(mTrackedDevice);
|
||||
mTrackedDevice = nullptr;
|
||||
|
||||
if (mTrackedDeviceProxy) {
|
||||
g_object_unref(mTrackedDeviceProxy);
|
||||
mTrackedDeviceProxy = nullptr;
|
||||
}
|
||||
|
||||
g_object_unref(mUPowerProxy);
|
||||
mUPowerProxy = nullptr;
|
||||
|
||||
@ -251,19 +257,27 @@ UPowerClient::StopListening()
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::UpdateTrackedDevice()
|
||||
UPowerClient::UpdateTrackedDeviceSync()
|
||||
{
|
||||
GType typeGPtrArray = dbus_g_type_get_collection("GPtrArray",
|
||||
DBUS_TYPE_G_OBJECT_PATH);
|
||||
GPtrArray* devices = nullptr;
|
||||
GError* error = nullptr;
|
||||
|
||||
// Reset the current tracked device:
|
||||
g_free(mTrackedDevice);
|
||||
mTrackedDevice = nullptr;
|
||||
|
||||
// Reset the current tracked device proxy:
|
||||
if (mTrackedDeviceProxy) {
|
||||
g_object_unref(mTrackedDeviceProxy);
|
||||
mTrackedDeviceProxy = nullptr;
|
||||
}
|
||||
|
||||
// If that fails, that likely means upower isn't installed.
|
||||
if (!dbus_g_proxy_call(mUPowerProxy, "EnumerateDevices", &error, G_TYPE_INVALID,
|
||||
typeGPtrArray, &devices, G_TYPE_INVALID)) {
|
||||
g_printerr ("Error: %s\n", error->message);
|
||||
|
||||
mTrackedDevice = nullptr;
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
@ -274,27 +288,34 @@ UPowerClient::UpdateTrackedDevice()
|
||||
*/
|
||||
for (guint i=0; i<devices->len; ++i) {
|
||||
gchar* devicePath = static_cast<gchar*>(g_ptr_array_index(devices, i));
|
||||
nsAutoRef<GHashTable> hashTable(GetDeviceProperties(devicePath));
|
||||
|
||||
DBusGProxy* proxy = dbus_g_proxy_new_from_proxy(mUPowerProxy,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
devicePath);
|
||||
|
||||
nsAutoRef<GHashTable> hashTable(GetDevicePropertiesSync(proxy));
|
||||
|
||||
if (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(hashTable, "Type"))) == sDeviceTypeBattery) {
|
||||
UpdateSavedInfo(hashTable);
|
||||
mTrackedDevice = devicePath;
|
||||
mTrackedDeviceProxy = proxy;
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_unref(proxy);
|
||||
g_free(devicePath);
|
||||
}
|
||||
|
||||
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 22
|
||||
g_ptr_array_unref(devices);
|
||||
#else
|
||||
g_ptr_array_free(devices, true);
|
||||
#endif
|
||||
g_ptr_array_free(devices, true);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath, UPowerClient* aListener)
|
||||
{
|
||||
if (!aListener->mTrackedDevice) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 16
|
||||
if (g_strcmp0(aObjectPath, aListener->mTrackedDevice)) {
|
||||
#else
|
||||
@ -303,12 +324,7 @@ UPowerClient::DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath, UPower
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoRef<GHashTable> hashTable(aListener->GetDeviceProperties(aObjectPath));
|
||||
aListener->UpdateSavedInfo(hashTable);
|
||||
|
||||
hal::NotifyBatteryChange(hal::BatteryInformation(aListener->mLevel,
|
||||
aListener->mCharging,
|
||||
aListener->mRemainingTime));
|
||||
aListener->GetDevicePropertiesAsync(aListener->mTrackedDeviceProxy);
|
||||
}
|
||||
|
||||
/* static */ DBusHandlerResult
|
||||
@ -325,18 +341,13 @@ UPowerClient::ConnectionSignalFilter(DBusConnection* aConnection,
|
||||
}
|
||||
|
||||
GHashTable*
|
||||
UPowerClient::GetDeviceProperties(const gchar* aDevice)
|
||||
UPowerClient::GetDevicePropertiesSync(DBusGProxy* aProxy)
|
||||
{
|
||||
nsAutoRef<DBusGProxy> proxy(dbus_g_proxy_new_for_name(mDBusConnection,
|
||||
"org.freedesktop.UPower",
|
||||
aDevice,
|
||||
"org.freedesktop.DBus.Properties"));
|
||||
|
||||
GError* error = nullptr;
|
||||
GHashTable* hashTable = nullptr;
|
||||
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE);
|
||||
if (!dbus_g_proxy_call(proxy, "GetAll", &error, G_TYPE_STRING,
|
||||
if (!dbus_g_proxy_call(aProxy, "GetAll", &error, G_TYPE_STRING,
|
||||
"org.freedesktop.UPower.Device", G_TYPE_INVALID,
|
||||
typeGHashTable, &hashTable, G_TYPE_INVALID)) {
|
||||
g_printerr("Error: %s\n", error->message);
|
||||
@ -347,6 +358,35 @@ UPowerClient::GetDeviceProperties(const gchar* aDevice)
|
||||
return hashTable;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::GetDevicePropertiesCallback(DBusGProxy* aProxy,
|
||||
DBusGProxyCall* aCall, void* aData)
|
||||
{
|
||||
GError* error = nullptr;
|
||||
GHashTable* hashTable = nullptr;
|
||||
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE);
|
||||
if (!dbus_g_proxy_end_call(aProxy, aCall, &error, typeGHashTable,
|
||||
&hashTable, G_TYPE_INVALID)) {
|
||||
g_printerr("Error: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
} else {
|
||||
sInstance->UpdateSavedInfo(hashTable);
|
||||
hal::NotifyBatteryChange(hal::BatteryInformation(sInstance->mLevel,
|
||||
sInstance->mCharging,
|
||||
sInstance->mRemainingTime));
|
||||
g_hash_table_unref(hashTable);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::GetDevicePropertiesAsync(DBusGProxy* aProxy)
|
||||
{
|
||||
dbus_g_proxy_begin_call(aProxy, "GetAll", GetDevicePropertiesCallback, nullptr,
|
||||
nullptr, G_TYPE_STRING,
|
||||
"org.freedesktop.UPower.Device", G_TYPE_INVALID);
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::UpdateSavedInfo(GHashTable* aHashTable)
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
|
||||
|
||||
// Since our job is to just notice when an object is signaled and report the
|
||||
// result back to this thread, we can just run on a Windows wait thread.
|
||||
DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE;
|
||||
DWORD wait_flags = WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE;
|
||||
|
||||
if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting,
|
||||
watch, INFINITE, wait_flags)) {
|
||||
|
@ -144,15 +144,6 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
|
||||
DCHECK(pipe_ == INVALID_HANDLE_VALUE);
|
||||
const std::wstring pipe_name = PipeName(channel_id);
|
||||
if (mode == MODE_SERVER) {
|
||||
SECURITY_ATTRIBUTES security_attributes = {0};
|
||||
security_attributes.bInheritHandle = FALSE;
|
||||
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
if (!win_util::GetLogonSessionOnlyDACL(
|
||||
reinterpret_cast<SECURITY_DESCRIPTOR**>(
|
||||
&security_attributes.lpSecurityDescriptor))) {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
pipe_ = CreateNamedPipeW(pipe_name.c_str(),
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE,
|
||||
@ -163,8 +154,7 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
|
||||
// input buffer size (XXX tune)
|
||||
Channel::kReadBufferSize,
|
||||
5000, // timeout in milliseconds (XXX tune)
|
||||
&security_attributes);
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
NULL);
|
||||
} else {
|
||||
pipe_ = CreateFileW(pipe_name.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
|
@ -146,10 +146,12 @@ struct CompartmentStats
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
, gcHeapXML(0)
|
||||
#endif
|
||||
, objectSlots(0)
|
||||
, objectElements(0)
|
||||
, objectMisc(0)
|
||||
, objectPrivate(0)
|
||||
, objectsExtraSlots(0)
|
||||
, objectsExtraElements(0)
|
||||
, objectsExtraArgumentsData(0)
|
||||
, objectsExtraRegExpStatics(0)
|
||||
, objectsExtraPropertyIteratorData(0)
|
||||
, objectsExtraPrivate(0)
|
||||
, stringCharsNonHuge(0)
|
||||
, shapesExtraTreeTables(0)
|
||||
, shapesExtraDictTables(0)
|
||||
@ -186,10 +188,12 @@ struct CompartmentStats
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
, gcHeapXML(other.gcHeapXML)
|
||||
#endif
|
||||
, objectSlots(other.objectSlots)
|
||||
, objectElements(other.objectElements)
|
||||
, objectMisc(other.objectMisc)
|
||||
, objectPrivate(other.objectPrivate)
|
||||
, objectsExtraSlots(other.objectsExtraSlots)
|
||||
, objectsExtraElements(other.objectsExtraElements)
|
||||
, objectsExtraArgumentsData(other.objectsExtraArgumentsData)
|
||||
, objectsExtraRegExpStatics(other.objectsExtraRegExpStatics)
|
||||
, objectsExtraPropertyIteratorData(other.objectsExtraPropertyIteratorData)
|
||||
, objectsExtraPrivate(other.objectsExtraPrivate)
|
||||
, stringCharsNonHuge(other.stringCharsNonHuge)
|
||||
, shapesExtraTreeTables(other.shapesExtraTreeTables)
|
||||
, shapesExtraDictTables(other.shapesExtraDictTables)
|
||||
@ -234,10 +238,12 @@ struct CompartmentStats
|
||||
size_t gcHeapXML;
|
||||
#endif
|
||||
|
||||
size_t objectSlots;
|
||||
size_t objectElements;
|
||||
size_t objectMisc;
|
||||
size_t objectPrivate;
|
||||
size_t objectsExtraSlots;
|
||||
size_t objectsExtraElements;
|
||||
size_t objectsExtraArgumentsData;
|
||||
size_t objectsExtraRegExpStatics;
|
||||
size_t objectsExtraPropertyIteratorData;
|
||||
size_t objectsExtraPrivate;
|
||||
size_t stringCharsNonHuge;
|
||||
size_t shapesExtraTreeTables;
|
||||
size_t shapesExtraDictTables;
|
||||
@ -280,10 +286,12 @@ struct CompartmentStats
|
||||
ADD(gcHeapXML);
|
||||
#endif
|
||||
|
||||
ADD(objectSlots);
|
||||
ADD(objectElements);
|
||||
ADD(objectMisc);
|
||||
ADD(objectPrivate);
|
||||
ADD(objectsExtraSlots);
|
||||
ADD(objectsExtraElements);
|
||||
ADD(objectsExtraArgumentsData);
|
||||
ADD(objectsExtraRegExpStatics);
|
||||
ADD(objectsExtraPropertyIteratorData);
|
||||
ADD(objectsExtraPrivate);
|
||||
ADD(stringCharsNonHuge);
|
||||
ADD(shapesExtraTreeTables);
|
||||
ADD(shapesExtraDictTables);
|
||||
|
@ -255,7 +255,11 @@ class Vector : private AllocPolicy
|
||||
/* private accessors */
|
||||
|
||||
bool usingInlineStorage() const {
|
||||
return mBegin == (T *)storage.addr();
|
||||
return mBegin == inlineStorage();
|
||||
}
|
||||
|
||||
T *inlineStorage() const {
|
||||
return (T *)storage.addr();
|
||||
}
|
||||
|
||||
T *beginNoCheck() const {
|
||||
@ -479,6 +483,8 @@ class Vector : private AllocPolicy
|
||||
* object (which must be heap-allocated) itself.
|
||||
*/
|
||||
size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const;
|
||||
|
||||
void swap(Vector &other);
|
||||
};
|
||||
|
||||
/* This does the re-entrancy check plus several other sanity checks. */
|
||||
@ -995,6 +1001,33 @@ Vector<T,N,AP>::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
|
||||
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
inline void
|
||||
Vector<T,N,AP>::swap(Vector &other)
|
||||
{
|
||||
// TODO Implement N != 0
|
||||
JS_STATIC_ASSERT(N == 0);
|
||||
|
||||
// This only works when inline storage is always empty.
|
||||
if (!usingInlineStorage() && other.usingInlineStorage()) {
|
||||
other.mBegin = mBegin;
|
||||
mBegin = inlineStorage();
|
||||
} else if (usingInlineStorage() && !other.usingInlineStorage()) {
|
||||
mBegin = other.mBegin;
|
||||
other.mBegin = other.inlineStorage();
|
||||
} else if (!usingInlineStorage() && !other.usingInlineStorage()) {
|
||||
Swap(mBegin, other.mBegin);
|
||||
} else {
|
||||
// This case is a no-op, since we'd set both to use their inline storage.
|
||||
}
|
||||
|
||||
Swap(mLength, other.mLength);
|
||||
Swap(mCapacity, other.mCapacity);
|
||||
#ifdef DEBUG
|
||||
Swap(mReserved, other.mReserved);
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -384,6 +384,7 @@ CPPSRCS += ExecutableAllocator.cpp \
|
||||
YarrInterpreter.cpp \
|
||||
YarrPattern.cpp \
|
||||
YarrSyntaxChecker.cpp \
|
||||
YarrCanonicalizeUCS2.cpp \
|
||||
$(NONE)
|
||||
|
||||
ifdef ENABLE_METHODJIT_SPEW
|
||||
|
@ -291,6 +291,11 @@ namespace JSC {
|
||||
{
|
||||
}
|
||||
int offset() {return m_offset;}
|
||||
|
||||
bool isSet() const {
|
||||
return m_offset != -1;
|
||||
}
|
||||
|
||||
private:
|
||||
JmpSrc(int offset)
|
||||
: m_offset(offset)
|
||||
|
@ -457,6 +457,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
bool isSet() const {
|
||||
return m_offset != -1;
|
||||
}
|
||||
|
||||
private:
|
||||
JmpSrc(int offset)
|
||||
: m_offset(offset)
|
||||
|
@ -418,6 +418,8 @@ public:
|
||||
masm->m_assembler.linkJump(m_jmp, label.m_label);
|
||||
}
|
||||
|
||||
bool isSet() const { return m_jmp.isSet(); }
|
||||
|
||||
private:
|
||||
JmpSrc m_jmp;
|
||||
};
|
||||
|
@ -250,6 +250,11 @@ public:
|
||||
m_assembler.eors_r(dest, dest, ARMRegisters::S1);
|
||||
}
|
||||
|
||||
void load8(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
load8ZeroExtend(address, dest);
|
||||
}
|
||||
|
||||
void load8SignExtend(ImplicitAddress address, RegisterID dest)
|
||||
{
|
||||
m_assembler.dataTransferN(true, true, 8, dest, address.base, address.offset);
|
||||
@ -277,6 +282,11 @@ public:
|
||||
{
|
||||
load8ZeroExtend(address, dest);
|
||||
}
|
||||
|
||||
void load16Unaligned(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
load16(address, dest);
|
||||
}
|
||||
|
||||
void load16SignExtend(ImplicitAddress address, RegisterID dest)
|
||||
{
|
||||
|
@ -206,6 +206,13 @@ public:
|
||||
m_executablePool = NULL;
|
||||
}
|
||||
|
||||
MacroAssemblerCodePtr code() {
|
||||
return m_code;
|
||||
}
|
||||
size_t size() {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
MacroAssemblerCodePtr m_code;
|
||||
ExecutablePool* m_executablePool;
|
||||
size_t m_size;
|
||||
|
@ -414,6 +414,11 @@ public:
|
||||
m_assembler.movw_rm(src, address.offset, address.base, address.index, address.scale);
|
||||
}
|
||||
|
||||
void load8(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
load8ZeroExtend(address, dest);
|
||||
}
|
||||
|
||||
void load8ZeroExtend(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
m_assembler.movzbl_mr(address.offset, address.base, address.index, address.scale, dest);
|
||||
@ -454,6 +459,11 @@ public:
|
||||
m_assembler.movzwl_mr(address.offset, address.base, dest);
|
||||
}
|
||||
|
||||
void load16Unaligned(BaseIndex address, RegisterID dest)
|
||||
{
|
||||
load16(address, dest);
|
||||
}
|
||||
|
||||
DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
|
||||
{
|
||||
m_assembler.movl_rm_disp32(src, address.offset, address.base);
|
||||
|
@ -378,6 +378,10 @@ public:
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
bool isSet() const {
|
||||
return m_offset != -1;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_offset;
|
||||
};
|
||||
|
@ -1177,6 +1177,11 @@
|
||||
#define WARN_UNUSED_RETURN
|
||||
#endif
|
||||
|
||||
/* COMPILER(CLANG) - Clang */
|
||||
#if defined(__clang__)
|
||||
#define WTF_COMPILER_CLANG 1
|
||||
#endif
|
||||
|
||||
#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_OS_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
|
||||
#define ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH 1
|
||||
#endif
|
||||
|
@ -22,6 +22,13 @@ JSObject::asPropertyIterator()
|
||||
return *static_cast<js::PropertyIteratorObject *>(this);
|
||||
}
|
||||
|
||||
inline const js::PropertyIteratorObject &
|
||||
JSObject::asPropertyIterator() const
|
||||
{
|
||||
JS_ASSERT(isPropertyIterator());
|
||||
return *static_cast<const js::PropertyIteratorObject *>(this);
|
||||
}
|
||||
|
||||
js::NativeIterator *
|
||||
js::PropertyIteratorObject::getNativeIterator() const
|
||||
{
|
||||
|
@ -687,6 +687,40 @@ FinalizeCount(JSContext *cx, unsigned argc, jsval *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DumpHeapComplete(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
const char *fileName = NULL;
|
||||
JSAutoByteString fileNameBytes;
|
||||
if (argc > 0) {
|
||||
Value v = JS_ARGV(cx, vp)[0];
|
||||
if (v.isString()) {
|
||||
JSString *str = v.toString();
|
||||
if (!fileNameBytes.encode(cx, str))
|
||||
return false;
|
||||
fileName = fileNameBytes.ptr();
|
||||
}
|
||||
}
|
||||
|
||||
FILE *dumpFile;
|
||||
if (!fileName) {
|
||||
dumpFile = stdout;
|
||||
} else {
|
||||
dumpFile = fopen(fileName, "w");
|
||||
if (!dumpFile) {
|
||||
JS_ReportError(cx, "can't open %s", fileName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
js::DumpHeapComplete(JS_GetRuntime(cx), dumpFile);
|
||||
|
||||
fclose(dumpFile);
|
||||
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
MJitChunkLimit(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
@ -860,6 +894,10 @@ static JSFunctionSpecWithHelp TestingFunctions[] = {
|
||||
"isProxy(obj)",
|
||||
" If true, obj is a proxy of some sort"),
|
||||
|
||||
JS_FN_HELP("dumpHeapComplete", DumpHeapComplete, 1, 0,
|
||||
"dumpHeapComplete([filename])",
|
||||
" Dump reachable and unreachable objects to a file."),
|
||||
|
||||
JS_FN_HELP("mjitChunkLimit", MJitChunkLimit, 1, 0,
|
||||
"mjitChunkLimit(N)",
|
||||
" Specify limit on compiled chunk size during mjit compilation."),
|
||||
|
@ -17,7 +17,7 @@ def replaceErrorMsgs(source_files, messages_file, output_file):
|
||||
if len(source_files) == 0:
|
||||
return
|
||||
for line in fileinput.input(source_files):
|
||||
output.write(replaceMessages(line, messages))
|
||||
output.write(replaceMessages(line if line[-1] == '\n' else line + '\n', messages))
|
||||
|
||||
def buildMessagesTable(messages_file):
|
||||
table = {}
|
||||
@ -48,4 +48,4 @@ def main():
|
||||
js2c.JS2C([combined_file, macros_file], [output_file], { 'TYPE': 'CORE', 'COMPRESSION': 'off', 'DEBUG':debug })
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
@ -107,6 +107,7 @@ check-one-remote:
|
||||
$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
|
||||
-I$(topsrcdir)/build \
|
||||
-I$(topsrcdir)/build/mobile \
|
||||
-I$(topsrcdir)/testing/mozbase/mozdevice/mozdevice \
|
||||
$(testxpcsrcdir)/remotexpcshelltests.py \
|
||||
--symbols-path=$(DIST)/crashreporter-symbols \
|
||||
--build-info-json=$(DEPTH)/mozinfo.json \
|
||||
|
@ -313,8 +313,8 @@ ConvertFrames(JSContext *cx, IonActivation *activation, IonBailoutIterator &it)
|
||||
return BAILOUT_RETURN_RECOMPILE_CHECK;
|
||||
case Bailout_BoundsCheck:
|
||||
return BAILOUT_RETURN_BOUNDS_CHECK;
|
||||
case Bailout_Invalidate:
|
||||
return BAILOUT_RETURN_INVALIDATE;
|
||||
case Bailout_ShapeGuard:
|
||||
return BAILOUT_RETURN_SHAPE_GUARD;
|
||||
case Bailout_CachedShapeGuard:
|
||||
return BAILOUT_RETURN_CACHED_SHAPE_GUARD;
|
||||
|
||||
@ -552,7 +552,7 @@ ion::BoundsCheckFailure()
|
||||
}
|
||||
|
||||
uint32
|
||||
ion::ForceInvalidation()
|
||||
ion::ShapeGuardFailure()
|
||||
{
|
||||
JSContext *cx = GetIonContext()->cx;
|
||||
JSScript *script = GetBailedJSScript(cx);
|
||||
@ -560,7 +560,9 @@ ion::ForceInvalidation()
|
||||
JS_ASSERT(script->hasIonScript());
|
||||
JS_ASSERT(!script->ion->invalidated());
|
||||
|
||||
IonSpew(IonSpew_Invalidate, "Forced invalidation bailout");
|
||||
script->failedShapeGuard = true;
|
||||
|
||||
IonSpew(IonSpew_Invalidate, "Invalidating due to shape guard failure");
|
||||
|
||||
return Invalidate(cx, script);
|
||||
}
|
||||
@ -574,6 +576,8 @@ ion::CachedShapeGuardFailure()
|
||||
JS_ASSERT(script->hasIonScript());
|
||||
JS_ASSERT(!script->ion->invalidated());
|
||||
|
||||
script->failedShapeGuard = true;
|
||||
|
||||
// Purge JM caches in the script and all inlined script, to avoid baking in
|
||||
// the same shape guard next time.
|
||||
for (size_t i = 0; i < script->ion->scriptEntries(); i++)
|
||||
|
@ -106,7 +106,7 @@ static const uint32 BAILOUT_RETURN_TYPE_BARRIER = 3;
|
||||
static const uint32 BAILOUT_RETURN_MONITOR = 4;
|
||||
static const uint32 BAILOUT_RETURN_RECOMPILE_CHECK = 5;
|
||||
static const uint32 BAILOUT_RETURN_BOUNDS_CHECK = 6;
|
||||
static const uint32 BAILOUT_RETURN_INVALIDATE = 7;
|
||||
static const uint32 BAILOUT_RETURN_SHAPE_GUARD = 7;
|
||||
static const uint32 BAILOUT_RETURN_OVERRECURSED = 8;
|
||||
static const uint32 BAILOUT_RETURN_CACHED_SHAPE_GUARD = 9;
|
||||
|
||||
@ -222,7 +222,7 @@ uint32 RecompileForInlining();
|
||||
|
||||
uint32 BoundsCheckFailure();
|
||||
|
||||
uint32 ForceInvalidation();
|
||||
uint32 ShapeGuardFailure();
|
||||
|
||||
uint32 CachedShapeGuardFailure();
|
||||
|
||||
|
@ -1270,7 +1270,7 @@ ion::CanEnterAtBranch(JSContext *cx, HandleScript script, StackFrame *fp, jsbyte
|
||||
|
||||
// Attempt compilation. Returns Method_Compiled if already compiled.
|
||||
JSFunction *fun = fp->isFunctionFrame() ? fp->fun() : NULL;
|
||||
MethodStatus status = Compile(cx, script, fun, pc, false);
|
||||
MethodStatus status = Compile(cx, script, fun, pc, fp->isConstructing());
|
||||
if (status != Method_Compiled) {
|
||||
if (status == Method_CantCompile)
|
||||
ForbidCompilation(cx, script);
|
||||
|
@ -35,6 +35,7 @@ IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
|
||||
oracle(oracle),
|
||||
inliningDepth(inliningDepth),
|
||||
failedBoundsCheck_(info->script()->failedBoundsCheck),
|
||||
failedShapeGuard_(info->script()->failedShapeGuard),
|
||||
lazyArguments_(NULL)
|
||||
{
|
||||
script_.init(info->script());
|
||||
@ -406,6 +407,9 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
|
||||
if (callerBuilder->failedBoundsCheck_)
|
||||
failedBoundsCheck_ = true;
|
||||
|
||||
if (callerBuilder->failedShapeGuard_)
|
||||
failedShapeGuard_ = true;
|
||||
|
||||
// Generate single entrance block.
|
||||
current = newBlock(pc);
|
||||
if (!current)
|
||||
@ -4617,10 +4621,8 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
|
||||
|
||||
// If we have a property typeset, the isOwnProperty call will trigger recompilation if
|
||||
// the property is deleted or reconfigured.
|
||||
if (!propertyTypes && shape->configurable()) {
|
||||
MGuardShape *guard = MGuardShape::New(global, globalObj->lastProperty(), Bailout_Invalidate);
|
||||
current->add(guard);
|
||||
}
|
||||
if (!propertyTypes && shape->configurable())
|
||||
global = addShapeGuard(global, globalObj->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
JS_ASSERT(shape->slot() >= globalObj->numFixedSlots());
|
||||
|
||||
@ -4670,10 +4672,8 @@ IonBuilder::jsop_setgname(HandlePropertyName name)
|
||||
// If we have a property type set, the isOwnProperty call will trigger recompilation
|
||||
// if the property is deleted or reconfigured. Without TI, we always need a shape guard
|
||||
// to guard against the property being reconfigured as non-writable.
|
||||
if (!propertyTypes) {
|
||||
MGuardShape *guard = MGuardShape::New(global, globalObj->lastProperty(), Bailout_Invalidate);
|
||||
current->add(guard);
|
||||
}
|
||||
if (!propertyTypes)
|
||||
global = addShapeGuard(global, globalObj->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
JS_ASSERT(shape->slot() >= globalObj->numFixedSlots());
|
||||
|
||||
@ -5436,8 +5436,7 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
|
||||
// are no lookup hooks for this property.
|
||||
MInstruction *wrapper = MConstant::New(ObjectValue(*foundProto));
|
||||
current->add(wrapper);
|
||||
MGuardShape *guard = MGuardShape::New(wrapper, foundProto->lastProperty(), Bailout_Invalidate);
|
||||
current->add(guard);
|
||||
wrapper = addShapeGuard(wrapper, foundProto->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
// Now we have to freeze all the property typesets to ensure there isn't a
|
||||
// lower shadowing getter or setter installed in the future.
|
||||
@ -5961,8 +5960,7 @@ IonBuilder::getPropTryMonomorphic(bool *emitted, HandleId id, types::StackTypeSe
|
||||
// the shape is not in dictionary made. We cannot be sure that the shape is
|
||||
// still a lastProperty, and calling Shape::search() on dictionary mode
|
||||
// shapes that aren't lastProperty is invalid.
|
||||
MGuardShape *guard = MGuardShape::New(obj, objShape, Bailout_CachedShapeGuard);
|
||||
current->add(guard);
|
||||
obj = addShapeGuard(obj, objShape, Bailout_CachedShapeGuard);
|
||||
|
||||
spew("Inlining monomorphic GETPROP");
|
||||
Shape *shape = objShape->search(cx, id);
|
||||
@ -6112,8 +6110,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
|
||||
// long as the shape is not in dictionary mode. We cannot be sure
|
||||
// that the shape is still a lastProperty, and calling Shape::search
|
||||
// on dictionary mode shapes that aren't lastProperty is invalid.
|
||||
MGuardShape *guard = MGuardShape::New(obj, objShape, Bailout_CachedShapeGuard);
|
||||
current->add(guard);
|
||||
obj = addShapeGuard(obj, objShape, Bailout_CachedShapeGuard);
|
||||
|
||||
Shape *shape = objShape->search(cx, NameToId(name));
|
||||
JS_ASSERT(shape);
|
||||
@ -6441,3 +6438,16 @@ IonBuilder::addBoundsCheck(MDefinition *index, MDefinition *length)
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
MInstruction *
|
||||
IonBuilder::addShapeGuard(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind)
|
||||
{
|
||||
MGuardShape *guard = MGuardShape::New(obj, shape, bailoutKind);
|
||||
current->add(guard);
|
||||
|
||||
// If a shape guard failed in the past, don't optimize shape guard.
|
||||
if (failedShapeGuard_)
|
||||
guard->setNotMovable();
|
||||
|
||||
return guard;
|
||||
}
|
||||
|
@ -280,6 +280,7 @@ class IonBuilder : public MIRGenerator
|
||||
MDefinition *walkScopeChain(unsigned hops);
|
||||
|
||||
MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length);
|
||||
MInstruction *addShapeGuard(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind);
|
||||
|
||||
JSObject *getNewArrayTemplateObject(uint32 count);
|
||||
|
||||
@ -473,6 +474,10 @@ class IonBuilder : public MIRGenerator
|
||||
// an outer script.
|
||||
bool failedBoundsCheck_;
|
||||
|
||||
// True if script->failedShapeGuard is set for the current script or
|
||||
// an outer script.
|
||||
bool failedShapeGuard_;
|
||||
|
||||
// If this script can use a lazy arguments object, it wil be pre-created
|
||||
// here.
|
||||
MInstruction *lazyArguments_;
|
||||
|
@ -524,7 +524,7 @@ MacroAssembler::generateBailoutTail(Register scratch)
|
||||
|
||||
branch32(Equal, ReturnReg, Imm32(BAILOUT_RETURN_BOUNDS_CHECK), &boundscheck);
|
||||
branch32(Equal, ReturnReg, Imm32(BAILOUT_RETURN_OVERRECURSED), &overrecursed);
|
||||
branch32(Equal, ReturnReg, Imm32(BAILOUT_RETURN_INVALIDATE), &invalidate);
|
||||
branch32(Equal, ReturnReg, Imm32(BAILOUT_RETURN_SHAPE_GUARD), &invalidate);
|
||||
|
||||
// Fall-through: cached shape guard failure.
|
||||
{
|
||||
@ -539,7 +539,7 @@ MacroAssembler::generateBailoutTail(Register scratch)
|
||||
bind(&invalidate);
|
||||
{
|
||||
setupUnalignedABICall(0, scratch);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, ForceInvalidation));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, ShapeGuardFailure));
|
||||
|
||||
branchTest32(Zero, ReturnReg, ReturnReg, &exception);
|
||||
jump(&interpret);
|
||||
|
@ -52,8 +52,8 @@ enum BailoutKind
|
||||
// A bailout triggered by a bounds-check failure.
|
||||
Bailout_BoundsCheck,
|
||||
|
||||
// Like Bailout_Normal, but invalidate the current IonScript.
|
||||
Bailout_Invalidate,
|
||||
// A shape guard based on TI information failed.
|
||||
Bailout_ShapeGuard,
|
||||
|
||||
// A shape guard based on JM ICs failed.
|
||||
Bailout_CachedShapeGuard
|
||||
|
@ -4484,6 +4484,7 @@ class MGuardShape
|
||||
{
|
||||
setGuard();
|
||||
setMovable();
|
||||
setResultType(MIRType_Object);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -297,9 +297,15 @@ LIRGeneratorARM::newLTableSwitchV(MTableSwitch *tableswitch)
|
||||
bool
|
||||
LIRGeneratorARM::visitGuardShape(MGuardShape *ins)
|
||||
{
|
||||
JS_ASSERT(ins->obj()->type() == MIRType_Object);
|
||||
|
||||
LDefinition tempObj = temp(LDefinition::OBJECT);
|
||||
LGuardShape *guard = new LGuardShape(useRegister(ins->obj()), tempObj);
|
||||
return assignSnapshot(guard, ins->bailoutKind()) && add(guard, ins);
|
||||
if (!assignSnapshot(guard, ins->bailoutKind()))
|
||||
return false;
|
||||
if (!add(guard, ins))
|
||||
return false;
|
||||
return redefine(ins, ins->obj());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -46,8 +46,14 @@ LIRGeneratorX86Shared::visitInterruptCheck(MInterruptCheck *ins)
|
||||
bool
|
||||
LIRGeneratorX86Shared::visitGuardShape(MGuardShape *ins)
|
||||
{
|
||||
JS_ASSERT(ins->obj()->type() == MIRType_Object);
|
||||
|
||||
LGuardShape *guard = new LGuardShape(useRegister(ins->obj()));
|
||||
return assignSnapshot(guard, ins->bailoutKind()) && add(guard, ins);
|
||||
if (!assignSnapshot(guard, ins->bailoutKind()))
|
||||
return false;
|
||||
if (!add(guard, ins))
|
||||
return false;
|
||||
return redefine(ins, ins->obj());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -52,8 +52,9 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal)
|
||||
|
||||
// Steal the contents
|
||||
void *contents;
|
||||
CHECK(JS_StealArrayBufferContents(cx, obj, &contents));
|
||||
CHECK(JS_StealArrayBufferContents(cx, obj, &contents, &data));
|
||||
CHECK(contents != NULL);
|
||||
CHECK(data != NULL);
|
||||
|
||||
// Check that the original ArrayBuffer is neutered
|
||||
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), 0);
|
||||
@ -111,9 +112,11 @@ BEGIN_TEST(testArrayBuffer_bug720949_viewList)
|
||||
buffer = JS_NewArrayBuffer(cx, 2000);
|
||||
js::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
|
||||
void *contents;
|
||||
CHECK(JS_StealArrayBufferContents(cx, buffer, &contents));
|
||||
uint8_t *data;
|
||||
CHECK(JS_StealArrayBufferContents(cx, buffer, &contents, &data));
|
||||
CHECK(contents != NULL);
|
||||
JS_free(cx, contents);
|
||||
CHECK(data != NULL);
|
||||
JS_free(NULL, contents);
|
||||
GC(cx);
|
||||
CHECK(isNeutered(view));
|
||||
CHECK(isNeutered(buffer));
|
||||
@ -137,9 +140,11 @@ BEGIN_TEST(testArrayBuffer_bug720949_viewList)
|
||||
|
||||
// Neuter
|
||||
void *contents;
|
||||
CHECK(JS_StealArrayBufferContents(cx, buffer, &contents));
|
||||
uint8_t *data;
|
||||
CHECK(JS_StealArrayBufferContents(cx, buffer, &contents, &data));
|
||||
CHECK(contents != NULL);
|
||||
JS_free(cx, contents);
|
||||
CHECK(data != NULL);
|
||||
JS_free(NULL, contents);
|
||||
|
||||
CHECK(isNeutered(view1));
|
||||
CHECK(isNeutered(view2));
|
||||
|
@ -99,6 +99,7 @@ TestArrayFromBuffer(JSContext *cx)
|
||||
CHECK_EQUAL(JS_GetTypedArrayLength(array, cx), elts);
|
||||
CHECK_EQUAL(JS_GetTypedArrayByteOffset(array, cx), 0);
|
||||
CHECK_EQUAL(JS_GetTypedArrayByteLength(array, cx), nbytes);
|
||||
CHECK_EQUAL(JS_GetArrayBufferViewBuffer(array, cx), (JSObject*) buffer);
|
||||
|
||||
Element *data;
|
||||
CHECK(data = GetData(array, cx));
|
||||
|
@ -3409,6 +3409,7 @@ JS_realloc(JSContext *cx, void *p, size_t nbytes);
|
||||
/*
|
||||
* A wrapper for js_free(p) that may delay js_free(p) invocation as a
|
||||
* performance optimization.
|
||||
* cx may be NULL.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_free(JSContext *cx, void *p);
|
||||
@ -4617,11 +4618,15 @@ JS_NewArrayBufferWithContents(JSContext *cx, void *contents);
|
||||
/*
|
||||
* Steal the contents of the given array buffer. The array buffer has its
|
||||
* length set to 0 and its contents array cleared. The caller takes ownership
|
||||
* of |contents| and must free it or transfer ownership via
|
||||
* of |*contents| and must free it or transfer ownership via
|
||||
* JS_NewArrayBufferWithContents when done using it.
|
||||
* To free |*contents|, call free().
|
||||
* A pointer to the buffer's data is returned in |*data|. This pointer can
|
||||
* be used until |*contents| is freed or has its ownership transferred.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents);
|
||||
JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
|
||||
uint8_t **data);
|
||||
|
||||
/*
|
||||
* Allocate memory that may be eventually passed to
|
||||
|
@ -732,7 +732,8 @@ JSStructuredCloneWriter::writeTransferMap()
|
||||
return false;
|
||||
|
||||
void *content;
|
||||
if (!JS_StealArrayBufferContents(context(), obj, &content))
|
||||
uint8_t *data;
|
||||
if (!JS_StealArrayBufferContents(context(), obj, &content, &data))
|
||||
return false;
|
||||
|
||||
if (!out.writePair(SCTAG_TRANSFER_MAP, 0) || !out.writePtr(content))
|
||||
|
@ -561,7 +561,11 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
|
||||
ionCompartment_->sweep(fop);
|
||||
#endif
|
||||
|
||||
/* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */
|
||||
/*
|
||||
* JIT code increments activeUseCount for any RegExpShared used by jit
|
||||
* code for the lifetime of the JIT script. Thus, we must perform
|
||||
* sweeping after clearing jit code.
|
||||
*/
|
||||
regExps.sweep(rt);
|
||||
}
|
||||
|
||||
|
@ -597,32 +597,15 @@ js_DumpObject(JSObject *obj)
|
||||
|
||||
#endif
|
||||
|
||||
struct DumpingChildInfo {
|
||||
void *node;
|
||||
JSGCTraceKind kind;
|
||||
|
||||
DumpingChildInfo (void *n, JSGCTraceKind k)
|
||||
: node(n), kind(k)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef HashSet<void *, DefaultHasher<void *>, SystemAllocPolicy> PtrSet;
|
||||
|
||||
struct JSDumpHeapTracer : public JSTracer {
|
||||
PtrSet visited;
|
||||
struct JSDumpHeapTracer : public JSTracer
|
||||
{
|
||||
FILE *output;
|
||||
Vector<DumpingChildInfo, 0, SystemAllocPolicy> nodes;
|
||||
char buffer[200];
|
||||
bool rootTracing;
|
||||
|
||||
JSDumpHeapTracer(FILE *fp)
|
||||
: output(fp)
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind);
|
||||
|
||||
static char
|
||||
MarkDescriptor(void *thing)
|
||||
{
|
||||
@ -634,65 +617,72 @@ MarkDescriptor(void *thing)
|
||||
}
|
||||
|
||||
static void
|
||||
DumpHeapPushIfNew(JSTracer *trc, void **thingp, JSGCTraceKind kind)
|
||||
DumpHeapVisitCompartment(JSRuntime *rt, void *data, JSCompartment *comp)
|
||||
{
|
||||
JS_ASSERT(trc->callback == DumpHeapPushIfNew ||
|
||||
trc->callback == DumpHeapVisitChild);
|
||||
void *thing = *thingp;
|
||||
JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
|
||||
char name[1024];
|
||||
if (rt->compartmentNameCallback)
|
||||
(*rt->compartmentNameCallback)(rt, comp, name, sizeof(name));
|
||||
else
|
||||
strcpy(name, "<unknown>");
|
||||
|
||||
/*
|
||||
* If we're tracing roots, print root information. Do this even if we've
|
||||
* already seen thing, for complete root information.
|
||||
*/
|
||||
if (dtrc->rootTracing) {
|
||||
fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing),
|
||||
JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer)));
|
||||
}
|
||||
JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(data);
|
||||
fprintf(dtrc->output, "# compartment %s\n", name);
|
||||
}
|
||||
|
||||
PtrSet::AddPtr ptrEntry = dtrc->visited.lookupForAdd(thing);
|
||||
if (ptrEntry || !dtrc->visited.add(ptrEntry, thing))
|
||||
return;
|
||||
static void
|
||||
DumpHeapVisitArena(JSRuntime *rt, void *data, gc::Arena *arena,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(data);
|
||||
fprintf(dtrc->output, "# arena allockind=%u size=%u\n",
|
||||
unsigned(arena->aheader.getAllocKind()), unsigned(thingSize));
|
||||
}
|
||||
|
||||
dtrc->nodes.append(DumpingChildInfo(thing, kind));
|
||||
static void
|
||||
DumpHeapVisitCell(JSRuntime *rt, void *data, void *thing,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(data);
|
||||
char cellDesc[1024];
|
||||
JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, thing, traceKind, true);
|
||||
fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing), cellDesc);
|
||||
JS_TraceChildren(dtrc, thing, traceKind);
|
||||
}
|
||||
|
||||
static void
|
||||
DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
|
||||
{
|
||||
JS_ASSERT(trc->callback == DumpHeapVisitChild);
|
||||
JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
|
||||
const char *edgeName = JS_GetTraceEdgeName(dtrc, dtrc->buffer, sizeof(dtrc->buffer));
|
||||
fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp), edgeName);
|
||||
DumpHeapPushIfNew(dtrc, thingp, kind);
|
||||
char buffer[1024];
|
||||
fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp),
|
||||
JS_GetTraceEdgeName(dtrc, buffer, sizeof(buffer)));
|
||||
}
|
||||
|
||||
static void
|
||||
DumpHeapVisitRoot(JSTracer *trc, void **thingp, JSGCTraceKind kind)
|
||||
{
|
||||
JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
|
||||
char buffer[1024];
|
||||
fprintf(dtrc->output, "%p %c %s\n", *thingp, MarkDescriptor(*thingp),
|
||||
JS_GetTraceEdgeName(dtrc, buffer, sizeof(buffer)));
|
||||
}
|
||||
|
||||
void
|
||||
js::DumpHeapComplete(JSRuntime *rt, FILE *fp)
|
||||
{
|
||||
JSDumpHeapTracer dtrc(fp);
|
||||
JS_TracerInit(&dtrc, rt, DumpHeapPushIfNew);
|
||||
if (!dtrc.visited.init(10000))
|
||||
return;
|
||||
|
||||
/* Store and log the root information. */
|
||||
dtrc.rootTracing = true;
|
||||
JS_TracerInit(&dtrc, rt, DumpHeapVisitRoot);
|
||||
TraceRuntime(&dtrc);
|
||||
|
||||
fprintf(dtrc.output, "==========\n");
|
||||
|
||||
/* Log the graph. */
|
||||
dtrc.rootTracing = false;
|
||||
dtrc.callback = DumpHeapVisitChild;
|
||||
JS_TracerInit(&dtrc, rt, DumpHeapVisitChild);
|
||||
IterateCompartmentsArenasCells(rt, &dtrc,
|
||||
DumpHeapVisitCompartment,
|
||||
DumpHeapVisitArena,
|
||||
DumpHeapVisitCell);
|
||||
|
||||
while (!dtrc.nodes.empty()) {
|
||||
DumpingChildInfo dci = dtrc.nodes.popCopy();
|
||||
JS_GetTraceThingInfo(dtrc.buffer, sizeof(dtrc.buffer),
|
||||
&dtrc, dci.node, dci.kind, JS_TRUE);
|
||||
fprintf(fp, "%p %c %s\n", dci.node, MarkDescriptor(dci.node), dtrc.buffer);
|
||||
JS_TraceChildren(&dtrc, dci.node, dci.kind);
|
||||
}
|
||||
|
||||
dtrc.visited.finish();
|
||||
fflush(dtrc.output);
|
||||
}
|
||||
|
||||
|
@ -1335,6 +1335,14 @@ JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx);
|
||||
extern JS_FRIEND_API(void *)
|
||||
JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been
|
||||
* neutered, this will still return the neutered buffer. |obj| must be an
|
||||
* object that would return true for JS_IsArrayBufferViewObject().
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_GetArrayBufferViewBuffer(JSObject *obj, JSContext *maybecx);
|
||||
|
||||
/*
|
||||
* Check whether obj supports JS_GetDataView* APIs. Note that this may fail and
|
||||
* throw an exception if a security wrapper is encountered that denies the
|
||||
|
@ -821,6 +821,12 @@ iterator_iteratorObject(JSContext *cx, HandleObject obj, JSBool keysonly)
|
||||
return obj;
|
||||
}
|
||||
|
||||
size_t
|
||||
PropertyIteratorObject::sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const
|
||||
{
|
||||
return mallocSizeOf(getPrivate());
|
||||
}
|
||||
|
||||
void
|
||||
PropertyIteratorObject::trace(JSTracer *trc, RawObject obj)
|
||||
{
|
||||
|
@ -78,6 +78,8 @@ class PropertyIteratorObject : public JSObject
|
||||
inline NativeIterator *getNativeIterator() const;
|
||||
inline void setNativeIterator(js::NativeIterator *ni);
|
||||
|
||||
size_t sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const;
|
||||
|
||||
private:
|
||||
static void trace(JSTracer *trc, RawObject obj);
|
||||
static void finalize(FreeOp *fop, RawObject obj);
|
||||
|
@ -155,19 +155,23 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
|
||||
} else {
|
||||
cStats->gcHeapObjectsOrdinary += thingSize;
|
||||
}
|
||||
size_t slotsSize, elementsSize, miscSize;
|
||||
obj->sizeOfExcludingThis(rtStats->mallocSizeOf, &slotsSize,
|
||||
&elementsSize, &miscSize);
|
||||
cStats->objectSlots += slotsSize;
|
||||
cStats->objectElements += elementsSize;
|
||||
cStats->objectMisc += miscSize;
|
||||
size_t slotsSize, elementsSize, argumentsDataSize, regExpStaticsSize,
|
||||
propertyIteratorDataSize;
|
||||
obj->sizeOfExcludingThis(rtStats->mallocSizeOf, &slotsSize, &elementsSize,
|
||||
&argumentsDataSize, ®ExpStaticsSize,
|
||||
&propertyIteratorDataSize);
|
||||
cStats->objectsExtraSlots += slotsSize;
|
||||
cStats->objectsExtraElements += elementsSize;
|
||||
cStats->objectsExtraArgumentsData += argumentsDataSize;
|
||||
cStats->objectsExtraRegExpStatics += regExpStaticsSize;
|
||||
cStats->objectsExtraPropertyIteratorData += propertyIteratorDataSize;
|
||||
|
||||
if (ObjectPrivateVisitor *opv = closure->opv) {
|
||||
js::Class *clazz = js::GetObjectClass(obj);
|
||||
if (clazz->flags & JSCLASS_HAS_PRIVATE &&
|
||||
clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)
|
||||
{
|
||||
cStats->objectPrivate += opv->sizeOfIncludingThis(GetObjectPrivate(obj));
|
||||
cStats->objectsExtraPrivate += opv->sizeOfIncludingThis(GetObjectPrivate(obj));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -368,9 +368,10 @@ struct JSObject : public js::ObjectImpl
|
||||
|
||||
inline size_t computedSizeOfThisSlotsElements() const;
|
||||
|
||||
inline void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
|
||||
size_t *slotsSize, size_t *elementsSize,
|
||||
size_t *miscSize) const;
|
||||
inline void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *slotsSize,
|
||||
size_t *elementsSize, size_t *argumentsDataSize,
|
||||
size_t *regExpStaticsSize,
|
||||
size_t *propertyIteratorDataSize) const;
|
||||
|
||||
bool hasIdempotentProtoChain() const;
|
||||
|
||||
@ -1020,6 +1021,7 @@ struct JSObject : public js::ObjectImpl
|
||||
inline js::NormalArgumentsObject &asNormalArguments();
|
||||
inline js::NumberObject &asNumber();
|
||||
inline js::PropertyIteratorObject &asPropertyIterator();
|
||||
inline const js::PropertyIteratorObject &asPropertyIterator() const;
|
||||
inline js::RegExpObject &asRegExp();
|
||||
inline js::ScopeObject &asScope();
|
||||
inline js::SetObject &asSet();
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "jswrapper.h"
|
||||
|
||||
#include "builtin/MapObject.h"
|
||||
#include "builtin/Iterator-inl.h"
|
||||
#include "gc/Barrier.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Root.h"
|
||||
@ -989,9 +990,9 @@ JSObject::computedSizeOfThisSlotsElements() const
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
|
||||
size_t *slotsSize, size_t *elementsSize,
|
||||
size_t *miscSize) const
|
||||
JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *slotsSize,
|
||||
size_t *elementsSize, size_t *argumentsDataSize,
|
||||
size_t *regExpStaticsSize, size_t *propertyIteratorDataSize) const
|
||||
{
|
||||
*slotsSize = 0;
|
||||
if (hasDynamicSlots()) {
|
||||
@ -1004,11 +1005,15 @@ JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
|
||||
}
|
||||
|
||||
/* Other things may be measured in the future if DMD indicates it is worthwhile. */
|
||||
*miscSize = 0;
|
||||
*argumentsDataSize = 0;
|
||||
*regExpStaticsSize = 0;
|
||||
*propertyIteratorDataSize = 0;
|
||||
if (isArguments()) {
|
||||
*miscSize += asArguments().sizeOfMisc(mallocSizeOf);
|
||||
*argumentsDataSize += asArguments().sizeOfMisc(mallocSizeOf);
|
||||
} else if (isRegExpStatics()) {
|
||||
*miscSize += js::SizeOfRegExpStaticsData(this, mallocSizeOf);
|
||||
*regExpStaticsSize += js::SizeOfRegExpStaticsData(this, mallocSizeOf);
|
||||
} else if (isPropertyIterator()) {
|
||||
*propertyIteratorDataSize += asPropertyIterator().sizeOfMisc(mallocSizeOf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,6 +472,9 @@ struct JSScript : public js::gc::Cell
|
||||
#ifdef JS_METHODJIT
|
||||
bool debugMode:1; /* script was compiled in debug mode */
|
||||
bool failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
|
||||
#endif
|
||||
#ifdef JS_ION
|
||||
bool failedShapeGuard:1; /* script has had hoisted shape guard fail */
|
||||
#endif
|
||||
bool invalidatedIdempotentCache:1; /* idempotent cache has triggered invalidation */
|
||||
bool isGenerator:1; /* is a generator */
|
||||
|
@ -461,13 +461,15 @@ ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents)
|
||||
ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents,
|
||||
uint8_t **data)
|
||||
{
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
JSObject *views = *GetViewList(&buffer);
|
||||
js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
|
||||
if (buffer.hasDynamicElements()) {
|
||||
*contents = header;
|
||||
*data = buffer.dataPointer();
|
||||
|
||||
buffer.setFixedElements();
|
||||
header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
|
||||
@ -482,6 +484,7 @@ ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents)
|
||||
|
||||
ArrayBufferObject::setElementsHeader(newheader, length);
|
||||
*contents = newheader;
|
||||
*data = reinterpret_cast<uint8_t *>(newheader + 1);
|
||||
}
|
||||
|
||||
// Neuter the donor ArrayBuffer and all views of it
|
||||
@ -3178,7 +3181,7 @@ IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
|
||||
if (clasp != &TypedArray::classes[TypedArrayTemplate<InternalType>::ArrayTypeID()]) \
|
||||
return NULL; \
|
||||
\
|
||||
*length = obj->getSlot(TypedArray::LENGTH_SLOT).toInt32(); \
|
||||
*length = TypedArray::length(obj); \
|
||||
*data = static_cast<ExternalType *>(TypedArray::viewData(obj)); \
|
||||
\
|
||||
return obj; \
|
||||
@ -3675,7 +3678,8 @@ JS_AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents,
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents)
|
||||
JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
|
||||
uint8_t **data)
|
||||
{
|
||||
if (!(obj = UnwrapObjectChecked(cx, obj)))
|
||||
return false;
|
||||
@ -3685,7 +3689,7 @@ JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ArrayBufferObject::stealContents(cx, obj, contents))
|
||||
if (!ArrayBufferObject::stealContents(cx, obj, contents, data))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -3698,7 +3702,7 @@ JS_GetTypedArrayLength(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getSlot(TypedArray::LENGTH_SLOT).toInt32();
|
||||
return TypedArray::length(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
@ -3708,7 +3712,7 @@ JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getSlot(TypedArray::BYTEOFFSET_SLOT).toInt32();
|
||||
return TypedArray::byteOffset(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
@ -3718,7 +3722,7 @@ JS_GetTypedArrayByteLength(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return obj->getSlot(TypedArray::BYTELENGTH_SLOT).toInt32();
|
||||
return TypedArray::byteLength(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSArrayBufferViewType)
|
||||
@ -3728,7 +3732,7 @@ JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return ArrayBufferView::TYPE_MAX;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
return static_cast<JSArrayBufferViewType>(obj->getSlot(TypedArray::TYPE_SLOT).toInt32());
|
||||
return static_cast<JSArrayBufferViewType>(TypedArray::type(obj));
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int8_t *)
|
||||
@ -3738,7 +3742,7 @@ JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_INT8);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_INT8);
|
||||
return static_cast<int8_t *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3749,7 +3753,7 @@ JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_UINT8);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_UINT8);
|
||||
return static_cast<uint8_t *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3760,7 +3764,7 @@ JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_UINT8_CLAMPED);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_UINT8_CLAMPED);
|
||||
return static_cast<uint8_t *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3771,7 +3775,7 @@ JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_INT16);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_INT16);
|
||||
return static_cast<int16_t *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3782,7 +3786,7 @@ JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_UINT16);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_UINT16);
|
||||
return static_cast<uint16_t *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3793,7 +3797,7 @@ JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_INT32);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_INT32);
|
||||
return static_cast<int32_t *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3804,7 +3808,7 @@ JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_UINT32);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_UINT32);
|
||||
return static_cast<uint32_t *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3815,7 +3819,7 @@ JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_FLOAT32);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_FLOAT32);
|
||||
return static_cast<float *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3826,7 +3830,7 @@ JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray());
|
||||
JS_ASSERT(obj->getSlot(TypedArray::TYPE_SLOT).toInt32() == ArrayBufferView::TYPE_FLOAT64);
|
||||
JS_ASSERT(TypedArray::type(obj) == ArrayBufferView::TYPE_FLOAT64);
|
||||
return static_cast<double *>(TypedArray::viewData(obj));
|
||||
}
|
||||
|
||||
@ -3880,6 +3884,16 @@ JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx)
|
||||
return obj->isDataView() ? obj->asDataView().dataPointer() : TypedArray::viewData(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
JS_GetArrayBufferViewBuffer(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
obj = CheckedUnwrap(maybecx, obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
return &obj->getFixedSlot(BufferView::BUFFER_SLOT).toObject();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *maybecx)
|
||||
{
|
||||
|
@ -132,7 +132,8 @@ class ArrayBufferObject : public JSObject
|
||||
|
||||
static void sweepAll(JSRuntime *rt);
|
||||
|
||||
static bool stealContents(JSContext *cx, JSObject *obj, void **contents);
|
||||
static bool stealContents(JSContext *cx, JSObject *obj, void **contents,
|
||||
uint8_t **data);
|
||||
|
||||
static inline void setElementsHeader(js::ObjectElements *header, uint32_t bytes);
|
||||
|
||||
|
@ -195,7 +195,10 @@ RegExpCode::compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount
|
||||
return false;
|
||||
|
||||
JSGlobalData globalData(execAlloc);
|
||||
jitCompile(yarrPattern, &globalData, codeBlock);
|
||||
jitCompile(yarrPattern,
|
||||
JSC::Yarr::Char16,
|
||||
&globalData,
|
||||
codeBlock);
|
||||
if (!codeBlock.isFallBack())
|
||||
return true;
|
||||
}
|
||||
@ -218,21 +221,23 @@ RegExpRunStatus
|
||||
RegExpCode::execute(JSContext *cx, StableCharPtr chars, size_t length, size_t start,
|
||||
int *output, size_t outputCount)
|
||||
{
|
||||
int result;
|
||||
unsigned result;
|
||||
#if ENABLE_YARR_JIT
|
||||
(void) cx; /* Unused. */
|
||||
if (codeBlock.isFallBack())
|
||||
result = JSC::Yarr::interpret(byteCode, chars.get(), start, length, output);
|
||||
else
|
||||
result = JSC::Yarr::execute(codeBlock, chars.get(), start, length, output);
|
||||
if (codeBlock.isFallBack()) {
|
||||
result = JSC::Yarr::interpret(byteCode, chars.get(), length, start,
|
||||
reinterpret_cast<unsigned *>(output));
|
||||
} else {
|
||||
result = codeBlock.execute(chars.get(), start, length, output).start;
|
||||
}
|
||||
#else
|
||||
result = JSC::Yarr::interpret(byteCode, chars.get(), start, length, output);
|
||||
result = JSC::Yarr::interpret(byteCode, chars.get(), length, start,
|
||||
reinterpret_cast<unsigned *>(output));
|
||||
#endif
|
||||
|
||||
if (result == -1)
|
||||
if (result == JSC::Yarr::offsetNoMatch)
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
|
||||
JS_ASSERT(result >= 0);
|
||||
return RegExpRunStatus_Success;
|
||||
}
|
||||
|
||||
@ -519,18 +524,19 @@ RegExpShared::execute(JSContext *cx, StableCharPtr chars, size_t length, size_t
|
||||
/* RegExpCompartment */
|
||||
|
||||
RegExpCompartment::RegExpCompartment(JSRuntime *rt)
|
||||
: map_(rt)
|
||||
: map_(rt), inUse_(rt)
|
||||
{}
|
||||
|
||||
RegExpCompartment::~RegExpCompartment()
|
||||
{
|
||||
map_.empty();
|
||||
JS_ASSERT(map_.empty());
|
||||
JS_ASSERT(inUse_.empty());
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpCompartment::init(JSContext *cx)
|
||||
{
|
||||
if (!map_.init()) {
|
||||
if (!map_.init() || !inUse_.init()) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
@ -538,12 +544,19 @@ RegExpCompartment::init(JSContext *cx)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* See the comment on RegExpShared lifetime in RegExpObject.h. */
|
||||
void
|
||||
RegExpCompartment::sweep(JSRuntime *rt)
|
||||
{
|
||||
for (Map::Enum e(map_); !e.empty(); e.popFront()) {
|
||||
/* See the comment on RegExpShared lifetime in RegExpObject.h. */
|
||||
RegExpShared *shared = e.front().value;
|
||||
#ifdef DEBUG
|
||||
for (Map::Range r = map_.all(); !r.empty(); r.popFront())
|
||||
JS_ASSERT(inUse_.has(r.front().value));
|
||||
#endif
|
||||
|
||||
map_.clear();
|
||||
|
||||
for (PendingSet::Enum e(inUse_); !e.empty(); e.popFront()) {
|
||||
RegExpShared *shared = e.front();
|
||||
if (shared->activeUseCount == 0 && shared->gcNumberWhenUsed < rt->gcStartNumber) {
|
||||
js_delete(shared);
|
||||
e.removeFront();
|
||||
@ -575,6 +588,12 @@ RegExpCompartment::get(JSContext *cx, JSAtom *keyAtom, JSAtom *source, RegExpFla
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!inUse_.put(shared)) {
|
||||
map_.remove(key);
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since 'error' deletes 'shared', only guard 'shared' on success. This is
|
||||
* safe since 'shared' cannot be deleted by GC until after the call to
|
||||
|
@ -140,9 +140,9 @@ class RegExpCode
|
||||
|
||||
/*
|
||||
* A RegExpShared is the compiled representation of a regexp. A RegExpShared is
|
||||
* pointed to by potentially multiple RegExpObjects. Additionally, C++ code may
|
||||
* have pointers to RegExpShareds on the stack. The RegExpShareds are tracked in
|
||||
* a RegExpCompartment hashtable, and most are destroyed on every GC.
|
||||
* potentially pointed to by multiple RegExpObjects. Additionally, C++ code may
|
||||
* have pointers to RegExpShareds on the stack. The RegExpShareds are kept in a
|
||||
* cache so that they can be reused when compiling the same regex string.
|
||||
*
|
||||
* During a GC, the trace hook for RegExpObject clears any pointers to
|
||||
* RegExpShareds so that there will be no dangling pointers when they are
|
||||
@ -160,6 +160,13 @@ class RegExpCode
|
||||
*
|
||||
* The activeUseCount and gcNumberWhenUsed fields are used to track these
|
||||
* conditions.
|
||||
*
|
||||
* There are two tables used to track RegExpShareds. map_ implements the cache
|
||||
* and is cleared on every GC. inUse_ logically owns all RegExpShareds in the
|
||||
* compartment and attempts to delete all RegExpShareds that aren't kept alive
|
||||
* by the above conditions on every GC sweep phase. It is necessary to use two
|
||||
* separate tables since map_ *must* be fully cleared on each GC since the Key
|
||||
* points to a JSAtom that can become garbage.
|
||||
*/
|
||||
class RegExpShared
|
||||
{
|
||||
@ -251,9 +258,21 @@ class RegExpCompartment
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Cache to reuse RegExpShareds with the same source/flags/etc. The cache
|
||||
* is entirely cleared on each GC.
|
||||
*/
|
||||
typedef HashMap<Key, RegExpShared *, Key, RuntimeAllocPolicy> Map;
|
||||
Map map_;
|
||||
|
||||
/*
|
||||
* The set of all RegExpShareds in the compartment. On every GC, every
|
||||
* RegExpShared that is not actively being used is deleted and removed from
|
||||
* the set.
|
||||
*/
|
||||
typedef HashSet<RegExpShared *, DefaultHasher<RegExpShared*>, RuntimeAllocPolicy> PendingSet;
|
||||
PendingSet inUse_;
|
||||
|
||||
bool get(JSContext *cx, JSAtom *key, JSAtom *source, RegExpFlag flags, Type type,
|
||||
RegExpGuard *g);
|
||||
|
||||
|
714
js/src/yarr/CheckedArithmetic.h
Normal file
714
js/src/yarr/CheckedArithmetic.h
Normal file
@ -0,0 +1,714 @@
|
||||
/* vim: set ts=4 sw=4 tw=99 et:
|
||||
*
|
||||
* Copyright (C) 2011 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CheckedArithmetic_h
|
||||
#define CheckedArithmetic_h
|
||||
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
#include "TypeTraits.h"
|
||||
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# undef min
|
||||
# undef max
|
||||
#endif
|
||||
|
||||
/* Checked<T>
|
||||
*
|
||||
* This class provides a mechanism to perform overflow-safe integer arithmetic
|
||||
* without having to manually ensure that you have all the required bounds checks
|
||||
* directly in your code.
|
||||
*
|
||||
* There are two modes of operation:
|
||||
* - The default is Checked<T, CrashOnOverflow>, and crashes at the point
|
||||
* and overflow has occurred.
|
||||
* - The alternative is Checked<T, RecordOverflow>, which uses an additional
|
||||
* byte of storage to track whether an overflow has occurred, subsequent
|
||||
* unchecked operations will crash if an overflow has occured
|
||||
*
|
||||
* It is possible to provide a custom overflow handler, in which case you need
|
||||
* to support these functions:
|
||||
* - void overflowed();
|
||||
* This function is called when an operation has produced an overflow.
|
||||
* - bool hasOverflowed();
|
||||
* This function must return true if overflowed() has been called on an
|
||||
* instance and false if it has not.
|
||||
* - void clearOverflow();
|
||||
* Used to reset overflow tracking when a value is being overwritten with
|
||||
* a new value.
|
||||
*
|
||||
* Checked<T> works for all integer types, with the following caveats:
|
||||
* - Mixing signedness of operands is only supported for types narrower than
|
||||
* 64bits.
|
||||
* - It does have a performance impact, so tight loops may want to be careful
|
||||
* when using it.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace WTF {
|
||||
|
||||
class CrashOnOverflow {
|
||||
protected:
|
||||
void overflowed()
|
||||
{
|
||||
CRASH();
|
||||
}
|
||||
|
||||
void clearOverflow() { }
|
||||
|
||||
public:
|
||||
bool hasOverflowed() const { return false; }
|
||||
};
|
||||
|
||||
class RecordOverflow {
|
||||
protected:
|
||||
RecordOverflow()
|
||||
: m_overflowed(false)
|
||||
{
|
||||
}
|
||||
|
||||
void overflowed()
|
||||
{
|
||||
m_overflowed = true;
|
||||
}
|
||||
|
||||
void clearOverflow()
|
||||
{
|
||||
m_overflowed = false;
|
||||
}
|
||||
|
||||
public:
|
||||
bool hasOverflowed() const { return m_overflowed; }
|
||||
|
||||
private:
|
||||
unsigned char m_overflowed;
|
||||
};
|
||||
|
||||
template <typename T, class OverflowHandler = CrashOnOverflow> class Checked;
|
||||
template <typename T> struct RemoveChecked;
|
||||
template <typename T> struct RemoveChecked<Checked<T> >;
|
||||
|
||||
template <typename Target, typename Source, bool targetSigned = ::std::numeric_limits<Target>::is_signed, bool sourceSigned = ::std::numeric_limits<Source>::is_signed> struct BoundsChecker;
|
||||
template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> {
|
||||
static bool inBounds(Source value)
|
||||
{
|
||||
// Same signedness so implicit type conversion will always increase precision
|
||||
// to widest type
|
||||
return value <= ::std::numeric_limits<Target>::max();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> {
|
||||
static bool inBounds(Source value)
|
||||
{
|
||||
// Same signedness so implicit type conversion will always increase precision
|
||||
// to widest type
|
||||
return ::std::numeric_limits<Target>::min() <= value && value <= ::std::numeric_limits<Target>::max();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> {
|
||||
static bool inBounds(Source value)
|
||||
{
|
||||
// Target is unsigned so any value less than zero is clearly unsafe
|
||||
if (value < 0)
|
||||
return false;
|
||||
// If our (unsigned) Target is the same or greater width we can
|
||||
// convert value to type Target without losing precision
|
||||
if (sizeof(Target) >= sizeof(Source))
|
||||
return static_cast<Target>(value) <= ::std::numeric_limits<Target>::max();
|
||||
// The signed Source type has greater precision than the target so
|
||||
// max(Target) -> Source will widen.
|
||||
return value <= static_cast<Source>(::std::numeric_limits<Target>::max());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> {
|
||||
static bool inBounds(Source value)
|
||||
{
|
||||
// Signed target with an unsigned source
|
||||
if (sizeof(Target) <= sizeof(Source))
|
||||
return value <= static_cast<Source>(::std::numeric_limits<Target>::max());
|
||||
// Target is Wider than Source so we're guaranteed to fit any value in
|
||||
// unsigned Source
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Target, typename Source, bool SameType = IsSameType<Target, Source>::value> struct BoundsCheckElider;
|
||||
template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> {
|
||||
static bool inBounds(Source) { return true; }
|
||||
};
|
||||
template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> {
|
||||
};
|
||||
|
||||
template <typename Target, typename Source> static inline bool isInBounds(Source value)
|
||||
{
|
||||
return BoundsCheckElider<Target, Source>::inBounds(value);
|
||||
}
|
||||
|
||||
template <typename T> struct RemoveChecked {
|
||||
typedef T CleanType;
|
||||
static const CleanType DefaultValue = 0;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > {
|
||||
typedef typename RemoveChecked<T>::CleanType CleanType;
|
||||
static const CleanType DefaultValue = 0;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > {
|
||||
typedef typename RemoveChecked<T>::CleanType CleanType;
|
||||
static const CleanType DefaultValue = 0;
|
||||
};
|
||||
|
||||
// The ResultBase and SignednessSelector are used to workaround typeof not being
|
||||
// available in MSVC
|
||||
template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase;
|
||||
template <typename U, typename V> struct ResultBase<U, V, true, false> {
|
||||
typedef U ResultType;
|
||||
};
|
||||
|
||||
template <typename U, typename V> struct ResultBase<U, V, false, false> {
|
||||
typedef V ResultType;
|
||||
};
|
||||
|
||||
template <typename U> struct ResultBase<U, U, false, true> {
|
||||
typedef U ResultType;
|
||||
};
|
||||
|
||||
template <typename U, typename V, bool uIsSigned = ::std::numeric_limits<U>::is_signed, bool vIsSigned = ::std::numeric_limits<V>::is_signed> struct SignednessSelector;
|
||||
template <typename U, typename V> struct SignednessSelector<U, V, true, true> {
|
||||
typedef U ResultType;
|
||||
};
|
||||
|
||||
template <typename U, typename V> struct SignednessSelector<U, V, false, false> {
|
||||
typedef U ResultType;
|
||||
};
|
||||
|
||||
template <typename U, typename V> struct SignednessSelector<U, V, true, false> {
|
||||
typedef V ResultType;
|
||||
};
|
||||
|
||||
template <typename U, typename V> struct SignednessSelector<U, V, false, true> {
|
||||
typedef U ResultType;
|
||||
};
|
||||
|
||||
template <typename U, typename V> struct ResultBase<U, V, false, true> {
|
||||
typedef typename SignednessSelector<U, V>::ResultType ResultType;
|
||||
};
|
||||
|
||||
template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> {
|
||||
};
|
||||
|
||||
template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType,
|
||||
bool lhsSigned = ::std::numeric_limits<LHS>::is_signed, bool rhsSigned = ::std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations;
|
||||
|
||||
template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> {
|
||||
// LHS and RHS are signed types
|
||||
|
||||
// Helper function
|
||||
static inline bool signsMatch(LHS lhs, RHS rhs)
|
||||
{
|
||||
return (lhs ^ rhs) >= 0;
|
||||
}
|
||||
|
||||
static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
|
||||
{
|
||||
if (signsMatch(lhs, rhs)) {
|
||||
if (lhs >= 0) {
|
||||
if ((::std::numeric_limits<ResultType>::max() - rhs) < lhs)
|
||||
return false;
|
||||
} else {
|
||||
ResultType temp = lhs - ::std::numeric_limits<ResultType>::min();
|
||||
if (rhs < -temp)
|
||||
return false;
|
||||
}
|
||||
} // if the signs do not match this operation can't overflow
|
||||
result = lhs + rhs;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
|
||||
{
|
||||
if (!signsMatch(lhs, rhs)) {
|
||||
if (lhs >= 0) {
|
||||
if (lhs > ::std::numeric_limits<ResultType>::max() + rhs)
|
||||
return false;
|
||||
} else {
|
||||
if (rhs > ::std::numeric_limits<ResultType>::max() + lhs)
|
||||
return false;
|
||||
}
|
||||
} // if the signs match this operation can't overflow
|
||||
result = lhs - rhs;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
|
||||
{
|
||||
if (signsMatch(lhs, rhs)) {
|
||||
if (lhs >= 0) {
|
||||
if (lhs && (::std::numeric_limits<ResultType>::max() / lhs) < rhs)
|
||||
return false;
|
||||
} else {
|
||||
if (lhs == ::std::numeric_limits<ResultType>::min() || rhs == ::std::numeric_limits<ResultType>::min())
|
||||
return false;
|
||||
if ((::std::numeric_limits<ResultType>::max() / -lhs) < -rhs)
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (lhs < 0) {
|
||||
if (rhs && lhs < (::std::numeric_limits<ResultType>::min() / rhs))
|
||||
return false;
|
||||
} else {
|
||||
if (lhs && rhs < (::std::numeric_limits<ResultType>::min() / lhs))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
result = lhs * rhs;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
|
||||
|
||||
};
|
||||
|
||||
template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> {
|
||||
// LHS and RHS are unsigned types so bounds checks are nice and easy
|
||||
static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
|
||||
{
|
||||
ResultType temp = lhs + rhs;
|
||||
if (temp < lhs)
|
||||
return false;
|
||||
result = temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
|
||||
{
|
||||
ResultType temp = lhs - rhs;
|
||||
if (temp > lhs)
|
||||
return false;
|
||||
result = temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
|
||||
{
|
||||
ResultType temp = lhs * rhs;
|
||||
if (temp < lhs)
|
||||
return false;
|
||||
result = temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
|
||||
|
||||
};
|
||||
|
||||
template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
|
||||
static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
|
||||
{
|
||||
int64_t temp = lhs + rhs;
|
||||
if (temp < ::std::numeric_limits<ResultType>::min())
|
||||
return false;
|
||||
if (temp > ::std::numeric_limits<ResultType>::max())
|
||||
return false;
|
||||
result = static_cast<ResultType>(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
|
||||
{
|
||||
int64_t temp = lhs - rhs;
|
||||
if (temp < ::std::numeric_limits<ResultType>::min())
|
||||
return false;
|
||||
if (temp > ::std::numeric_limits<ResultType>::max())
|
||||
return false;
|
||||
result = static_cast<ResultType>(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
|
||||
{
|
||||
int64_t temp = lhs * rhs;
|
||||
if (temp < ::std::numeric_limits<ResultType>::min())
|
||||
return false;
|
||||
if (temp > ::std::numeric_limits<ResultType>::max())
|
||||
return false;
|
||||
result = static_cast<ResultType>(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool equals(int lhs, unsigned rhs)
|
||||
{
|
||||
return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> {
|
||||
static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
|
||||
{
|
||||
return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result);
|
||||
}
|
||||
|
||||
static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
|
||||
{
|
||||
return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result);
|
||||
}
|
||||
|
||||
static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
|
||||
{
|
||||
return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result);
|
||||
}
|
||||
|
||||
static inline bool equals(unsigned lhs, int rhs)
|
||||
{
|
||||
return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result)
|
||||
{
|
||||
return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result)
|
||||
{
|
||||
return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result)
|
||||
{
|
||||
return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
|
||||
}
|
||||
|
||||
template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs)
|
||||
{
|
||||
return ArithmeticOperations<U, V>::equals(lhs, rhs);
|
||||
}
|
||||
|
||||
enum ResultOverflowedTag { ResultOverflowed };
|
||||
|
||||
// FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801
|
||||
static inline bool workAroundClangBug() { return true; }
|
||||
|
||||
template <typename T, class OverflowHandler> class Checked : public OverflowHandler {
|
||||
public:
|
||||
template <typename _T, class _OverflowHandler> friend class Checked;
|
||||
Checked()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
|
||||
Checked(ResultOverflowedTag)
|
||||
: m_value(0)
|
||||
{
|
||||
// FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801
|
||||
if (workAroundClangBug())
|
||||
this->overflowed();
|
||||
}
|
||||
|
||||
template <typename U> Checked(U value)
|
||||
{
|
||||
if (!isInBounds<T>(value))
|
||||
this->overflowed();
|
||||
m_value = static_cast<T>(value);
|
||||
}
|
||||
|
||||
template <typename V> Checked(const Checked<T, V>& rhs)
|
||||
: m_value(rhs.m_value)
|
||||
{
|
||||
if (rhs.hasOverflowed())
|
||||
this->overflowed();
|
||||
}
|
||||
|
||||
template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
|
||||
: OverflowHandler(rhs)
|
||||
{
|
||||
if (!isInBounds<T>(rhs.m_value))
|
||||
this->overflowed();
|
||||
m_value = static_cast<T>(rhs.m_value);
|
||||
}
|
||||
|
||||
template <typename U, typename V> Checked(const Checked<U, V>& rhs)
|
||||
{
|
||||
if (rhs.hasOverflowed())
|
||||
this->overflowed();
|
||||
if (!isInBounds<T>(rhs.m_value))
|
||||
this->overflowed();
|
||||
m_value = static_cast<T>(rhs.m_value);
|
||||
}
|
||||
|
||||
const Checked& operator=(Checked rhs)
|
||||
{
|
||||
this->clearOverflow();
|
||||
if (rhs.hasOverflowed())
|
||||
this->overflowed();
|
||||
m_value = static_cast<T>(rhs.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U> const Checked& operator=(U value)
|
||||
{
|
||||
return *this = Checked(value);
|
||||
}
|
||||
|
||||
template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
|
||||
{
|
||||
return *this = Checked(rhs);
|
||||
}
|
||||
|
||||
// prefix
|
||||
const Checked& operator++()
|
||||
{
|
||||
if (m_value == ::std::numeric_limits<T>::max())
|
||||
this->overflowed();
|
||||
m_value++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Checked& operator--()
|
||||
{
|
||||
if (m_value == ::std::numeric_limits<T>::min())
|
||||
this->overflowed();
|
||||
m_value--;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// postfix operators
|
||||
const Checked operator++(int)
|
||||
{
|
||||
if (m_value == ::std::numeric_limits<T>::max())
|
||||
this->overflowed();
|
||||
return Checked(m_value++);
|
||||
}
|
||||
|
||||
const Checked operator--(int)
|
||||
{
|
||||
if (m_value == ::std::numeric_limits<T>::min())
|
||||
this->overflowed();
|
||||
return Checked(m_value--);
|
||||
}
|
||||
|
||||
// Boolean operators
|
||||
bool operator!() const
|
||||
{
|
||||
if (this->hasOverflowed())
|
||||
CRASH();
|
||||
return !m_value;
|
||||
}
|
||||
|
||||
typedef void* (Checked::*UnspecifiedBoolType);
|
||||
operator UnspecifiedBoolType*() const
|
||||
{
|
||||
if (this->hasOverflowed())
|
||||
CRASH();
|
||||
return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
|
||||
}
|
||||
|
||||
// Value accessors. unsafeGet() will crash if there's been an overflow.
|
||||
T unsafeGet() const
|
||||
{
|
||||
if (this->hasOverflowed())
|
||||
CRASH();
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool safeGet(T& value) const WARN_UNUSED_RETURN
|
||||
{
|
||||
value = m_value;
|
||||
return this->hasOverflowed();
|
||||
}
|
||||
|
||||
// Mutating assignment
|
||||
template <typename U> const Checked operator+=(U rhs)
|
||||
{
|
||||
if (!safeAdd(m_value, rhs, m_value))
|
||||
this->overflowed();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U> const Checked operator-=(U rhs)
|
||||
{
|
||||
if (!safeSub(m_value, rhs, m_value))
|
||||
this->overflowed();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U> const Checked operator*=(U rhs)
|
||||
{
|
||||
if (!safeMultiply(m_value, rhs, m_value))
|
||||
this->overflowed();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Checked operator*=(double rhs)
|
||||
{
|
||||
double result = rhs * m_value;
|
||||
// Handle +/- infinity and NaN
|
||||
if (!(::std::numeric_limits<T>::min() <= result && ::std::numeric_limits<T>::max() >= result))
|
||||
this->overflowed();
|
||||
m_value = (T)result;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Checked operator*=(float rhs)
|
||||
{
|
||||
return *this *= (double)rhs;
|
||||
}
|
||||
|
||||
template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
|
||||
{
|
||||
if (rhs.hasOverflowed())
|
||||
this->overflowed();
|
||||
return *this += rhs.m_value;
|
||||
}
|
||||
|
||||
template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
|
||||
{
|
||||
if (rhs.hasOverflowed())
|
||||
this->overflowed();
|
||||
return *this -= rhs.m_value;
|
||||
}
|
||||
|
||||
template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
|
||||
{
|
||||
if (rhs.hasOverflowed())
|
||||
this->overflowed();
|
||||
return *this *= rhs.m_value;
|
||||
}
|
||||
|
||||
// Equality comparisons
|
||||
template <typename V> bool operator==(Checked<T, V> rhs)
|
||||
{
|
||||
return unsafeGet() == rhs.unsafeGet();
|
||||
}
|
||||
|
||||
template <typename U> bool operator==(U rhs)
|
||||
{
|
||||
if (this->hasOverflowed())
|
||||
this->overflowed();
|
||||
return safeEquals(m_value, rhs);
|
||||
}
|
||||
|
||||
template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
|
||||
{
|
||||
return unsafeGet() == Checked(rhs.unsafeGet());
|
||||
}
|
||||
|
||||
template <typename U> bool operator!=(U rhs)
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
// Disallow implicit conversion of floating point to integer types
|
||||
Checked(float);
|
||||
Checked(double);
|
||||
void operator=(float);
|
||||
void operator=(double);
|
||||
void operator+=(float);
|
||||
void operator+=(double);
|
||||
void operator-=(float);
|
||||
void operator-=(double);
|
||||
T m_value;
|
||||
};
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
|
||||
{
|
||||
U x = 0;
|
||||
V y = 0;
|
||||
bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
|
||||
typename Result<U, V>::ResultType result = 0;
|
||||
overflowed |= !safeAdd(x, y, result);
|
||||
if (overflowed)
|
||||
return ResultOverflowed;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
|
||||
{
|
||||
U x = 0;
|
||||
V y = 0;
|
||||
bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
|
||||
typename Result<U, V>::ResultType result = 0;
|
||||
overflowed |= !safeSub(x, y, result);
|
||||
if (overflowed)
|
||||
return ResultOverflowed;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
|
||||
{
|
||||
U x = 0;
|
||||
V y = 0;
|
||||
bool overflowed = lhs.safeGet(x) || rhs.safeGet(y);
|
||||
typename Result<U, V>::ResultType result = 0;
|
||||
overflowed |= !safeMultiply(x, y, result);
|
||||
if (overflowed)
|
||||
return ResultOverflowed;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
|
||||
{
|
||||
return lhs + Checked<V, OverflowHandler>(rhs);
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
|
||||
{
|
||||
return lhs - Checked<V, OverflowHandler>(rhs);
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
|
||||
{
|
||||
return lhs * Checked<V, OverflowHandler>(rhs);
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
|
||||
{
|
||||
return Checked<U, OverflowHandler>(lhs) + rhs;
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
|
||||
{
|
||||
return Checked<U, OverflowHandler>(lhs) - rhs;
|
||||
}
|
||||
|
||||
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
|
||||
{
|
||||
return Checked<U, OverflowHandler>(lhs) * rhs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using WTF::Checked;
|
||||
using WTF::RecordOverflow;
|
||||
|
||||
#endif
|
73
js/src/yarr/MatchResult.h
Normal file
73
js/src/yarr/MatchResult.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MatchResult_h
|
||||
#define MatchResult_h
|
||||
|
||||
#include "wtfbridge.h"
|
||||
|
||||
typedef uint64_t EncodedMatchResult;
|
||||
|
||||
struct MatchResult {
|
||||
MatchResult(size_t start, size_t end)
|
||||
: start(start)
|
||||
, end(end)
|
||||
{
|
||||
}
|
||||
|
||||
explicit MatchResult(EncodedMatchResult encoded)
|
||||
{
|
||||
union u {
|
||||
uint64_t encoded;
|
||||
struct s {
|
||||
size_t start;
|
||||
size_t end;
|
||||
} split;
|
||||
} value;
|
||||
value.encoded = encoded;
|
||||
start = value.split.start;
|
||||
end = value.split.end;
|
||||
}
|
||||
|
||||
static MatchResult failed()
|
||||
{
|
||||
return MatchResult(WTF::notFound, 0);
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return start != WTF::notFound;
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return start == end;
|
||||
}
|
||||
|
||||
size_t start;
|
||||
size_t end;
|
||||
};
|
||||
|
||||
#endif
|
261
js/src/yarr/TypeTraits.h
Normal file
261
js/src/yarr/TypeTraits.h
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2009, 2010 Google Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public License
|
||||
* along with this library; see the file COPYING.LIB. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TypeTraits_h
|
||||
#define TypeTraits_h
|
||||
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#if (defined(__GLIBCXX__) && (__GLIBCXX__ >= 20070724) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || (defined(_MSC_VER) && (_MSC_VER >= 1600))
|
||||
#include <type_traits>
|
||||
#if defined(__GLIBCXX__) && (__GLIBCXX__ >= 20070724) && defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
#include <tr1/memory>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace WTF {
|
||||
|
||||
// The following are provided in this file:
|
||||
//
|
||||
// Conditional<Predicate, If, Then>::Type
|
||||
//
|
||||
// IsInteger<T>::value
|
||||
// IsPod<T>::value, see the definition for a note about its limitations
|
||||
// IsConvertibleToInteger<T>::value
|
||||
//
|
||||
// IsArray<T>::value
|
||||
//
|
||||
// IsSameType<T, U>::value
|
||||
//
|
||||
// RemovePointer<T>::Type
|
||||
// RemoveReference<T>::Type
|
||||
// RemoveConst<T>::Type
|
||||
// RemoveVolatile<T>::Type
|
||||
// RemoveConstVolatile<T>::Type
|
||||
// RemoveExtent<T>::Type
|
||||
//
|
||||
// DecayArray<T>::Type
|
||||
//
|
||||
// COMPILE_ASSERT's in TypeTraits.cpp illustrate their usage and what they do.
|
||||
|
||||
template <bool Predicate, class If, class Then> struct Conditional { typedef If Type; };
|
||||
template <class If, class Then> struct Conditional<false, If, Then> { typedef Then Type; };
|
||||
|
||||
template<typename T> struct IsInteger { static const bool value = false; };
|
||||
template<> struct IsInteger<bool> { static const bool value = true; };
|
||||
template<> struct IsInteger<char> { static const bool value = true; };
|
||||
template<> struct IsInteger<signed char> { static const bool value = true; };
|
||||
template<> struct IsInteger<unsigned char> { static const bool value = true; };
|
||||
template<> struct IsInteger<short> { static const bool value = true; };
|
||||
template<> struct IsInteger<unsigned short> { static const bool value = true; };
|
||||
template<> struct IsInteger<int> { static const bool value = true; };
|
||||
template<> struct IsInteger<unsigned int> { static const bool value = true; };
|
||||
template<> struct IsInteger<long> { static const bool value = true; };
|
||||
template<> struct IsInteger<unsigned long> { static const bool value = true; };
|
||||
template<> struct IsInteger<long long> { static const bool value = true; };
|
||||
template<> struct IsInteger<unsigned long long> { static const bool value = true; };
|
||||
#if WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
template<> struct IsInteger<wchar_t> { static const bool value = true; };
|
||||
#endif
|
||||
|
||||
template<typename T> struct IsFloatingPoint { static const bool value = false; };
|
||||
template<> struct IsFloatingPoint<float> { static const bool value = true; };
|
||||
template<> struct IsFloatingPoint<double> { static const bool value = true; };
|
||||
template<> struct IsFloatingPoint<long double> { static const bool value = true; };
|
||||
|
||||
template<typename T> struct IsArithmetic { static const bool value = IsInteger<T>::value || IsFloatingPoint<T>::value; };
|
||||
|
||||
// IsPod is misnamed as it doesn't cover all plain old data (pod) types.
|
||||
// Specifically, it doesn't allow for enums or for structs.
|
||||
template <typename T> struct IsPod { static const bool value = IsArithmetic<T>::value; };
|
||||
template <typename P> struct IsPod<P*> { static const bool value = true; };
|
||||
|
||||
template<typename T> class IsConvertibleToInteger {
|
||||
// Avoid "possible loss of data" warning when using Microsoft's C++ compiler
|
||||
// by not converting int's to doubles.
|
||||
template<bool performCheck, typename U> class IsConvertibleToDouble;
|
||||
template<typename U> class IsConvertibleToDouble<false, U> {
|
||||
public:
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<typename U> class IsConvertibleToDouble<true, U> {
|
||||
typedef char YesType;
|
||||
struct NoType {
|
||||
char padding[8];
|
||||
};
|
||||
|
||||
static YesType floatCheck(long double);
|
||||
static NoType floatCheck(...);
|
||||
static T& t;
|
||||
public:
|
||||
static const bool value = sizeof(floatCheck(t)) == sizeof(YesType);
|
||||
};
|
||||
|
||||
public:
|
||||
static const bool value = IsInteger<T>::value || IsConvertibleToDouble<!IsInteger<T>::value, T>::value;
|
||||
};
|
||||
|
||||
|
||||
template <class T> struct IsArray {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <class T> struct IsArray<T[]> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <class T, size_t N> struct IsArray<T[N]> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename U> struct IsSameType {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename T> struct IsSameType<T, T> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename T, typename U> class IsSubclass {
|
||||
typedef char YesType;
|
||||
struct NoType {
|
||||
char padding[8];
|
||||
};
|
||||
|
||||
static YesType subclassCheck(U*);
|
||||
static NoType subclassCheck(...);
|
||||
static T* t;
|
||||
public:
|
||||
static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType);
|
||||
};
|
||||
|
||||
template <typename T, template<class V> class U> class IsSubclassOfTemplate {
|
||||
typedef char YesType;
|
||||
struct NoType {
|
||||
char padding[8];
|
||||
};
|
||||
|
||||
template<typename W> static YesType subclassCheck(U<W>*);
|
||||
static NoType subclassCheck(...);
|
||||
static T* t;
|
||||
public:
|
||||
static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType);
|
||||
};
|
||||
|
||||
template <typename T, template <class V> class OuterTemplate> struct RemoveTemplate {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T, template <class V> class OuterTemplate> struct RemoveTemplate<OuterTemplate<T>, OuterTemplate> {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveConst {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveConst<const T> {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveVolatile {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveVolatile<volatile T> {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveConstVolatile {
|
||||
typedef typename RemoveVolatile<typename RemoveConst<T>::Type>::Type Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemovePointer {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemovePointer<T*> {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveReference {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveReference<T&> {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveExtent {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T> struct RemoveExtent<T[]> {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <typename T, size_t N> struct RemoveExtent<T[N]> {
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <class T> struct DecayArray {
|
||||
typedef typename RemoveReference<T>::Type U;
|
||||
public:
|
||||
typedef typename Conditional<
|
||||
IsArray<U>::value,
|
||||
typename RemoveExtent<U>::Type*,
|
||||
typename RemoveConstVolatile<U>::Type
|
||||
>::Type Type;
|
||||
};
|
||||
|
||||
#if WTF_COMPILER_CLANG || GCC_VERSION_AT_LEAST(4, 6, 0) || (defined(_MSC_VER) && (_MSC_VER >= 1400) && (_MSC_VER < 1600) && !defined(__INTEL_COMPILER))
|
||||
// VC8 (VS2005) and later has __has_trivial_constructor and __has_trivial_destructor,
|
||||
// but the implementation returns false for built-in types. We add the extra IsPod condition to
|
||||
// work around this.
|
||||
template <typename T> struct HasTrivialConstructor {
|
||||
static const bool value = __has_trivial_constructor(T) || IsPod<RemoveConstVolatile<T> >::value;
|
||||
};
|
||||
template <typename T> struct HasTrivialDestructor {
|
||||
static const bool value = __has_trivial_destructor(T) || IsPod<RemoveConstVolatile<T> >::value;
|
||||
};
|
||||
#elif (defined(__GLIBCXX__) && (__GLIBCXX__ >= 20070724) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || (defined(_MSC_VER) && (_MSC_VER >= 1600))
|
||||
// GCC's libstdc++ 20070724 and later supports C++ TR1 type_traits in the std namespace.
|
||||
// VC10 (VS2010) and later support C++ TR1 type_traits in the std::tr1 namespace.
|
||||
template<typename T> struct HasTrivialConstructor : public std::tr1::has_trivial_constructor<T> { };
|
||||
template<typename T> struct HasTrivialDestructor : public std::tr1::has_trivial_destructor<T> { };
|
||||
#else
|
||||
// For compilers that don't support detection of trivial constructors and destructors in classes,
|
||||
// we use a template that returns true for any POD type that IsPod can detect (see IsPod caveats above),
|
||||
// but false for all other types (which includes all classes). This will give false negatives, which can hurt
|
||||
// performance, but avoids false positives, which would result in incorrect behavior.
|
||||
template <typename T> struct HasTrivialConstructor {
|
||||
static const bool value = IsPod<RemoveConstVolatile<T> >::value;
|
||||
};
|
||||
template <typename T> struct HasTrivialDestructor {
|
||||
static const bool value = IsPod<RemoveConstVolatile<T> >::value;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace WTF
|
||||
|
||||
#endif // TypeTraits_h
|
@ -1,7 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
|
||||
* All rights reserved.
|
||||
@ -26,14 +23,12 @@
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
*/
|
||||
|
||||
#ifndef Yarr_h
|
||||
#define Yarr_h
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "YarrInterpreter.h"
|
||||
#include "YarrPattern.h"
|
||||
|
||||
@ -49,6 +44,7 @@ namespace JSC { namespace Yarr {
|
||||
#define YarrStackSpaceForBackTrackInfoParentheses 2
|
||||
|
||||
static const unsigned quantifyInfinite = UINT_MAX;
|
||||
static const unsigned offsetNoMatch = (unsigned)-1;
|
||||
|
||||
// The below limit restricts the number of "recursive" match calls in order to
|
||||
// avoid spending exponential time on complex regular expressions.
|
||||
@ -63,8 +59,10 @@ enum JSRegExpResult {
|
||||
JSRegExpErrorInternal = -4
|
||||
};
|
||||
|
||||
PassOwnPtr<BytecodePattern> byteCompile(YarrPattern&, BumpPointerAllocator*);
|
||||
int interpret(BytecodePattern*, const UChar* input, unsigned start, unsigned length, int* output);
|
||||
enum YarrCharSize {
|
||||
Char8,
|
||||
Char16
|
||||
};
|
||||
|
||||
} } // namespace JSC::Yarr
|
||||
|
||||
|
463
js/src/yarr/YarrCanonicalizeUCS2.cpp
Normal file
463
js/src/yarr/YarrCanonicalizeUCS2.cpp
Normal file
@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// DO NOT EDIT! - this file autogenerated by YarrCanonicalizeUCS2.js
|
||||
|
||||
#include "YarrCanonicalizeUCS2.h"
|
||||
|
||||
namespace JSC { namespace Yarr {
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t ucs2CharacterSet0[] = { 0x01c4u, 0x01c5u, 0x01c6u, 0 };
|
||||
uint16_t ucs2CharacterSet1[] = { 0x01c7u, 0x01c8u, 0x01c9u, 0 };
|
||||
uint16_t ucs2CharacterSet2[] = { 0x01cau, 0x01cbu, 0x01ccu, 0 };
|
||||
uint16_t ucs2CharacterSet3[] = { 0x01f1u, 0x01f2u, 0x01f3u, 0 };
|
||||
uint16_t ucs2CharacterSet4[] = { 0x0392u, 0x03b2u, 0x03d0u, 0 };
|
||||
uint16_t ucs2CharacterSet5[] = { 0x0395u, 0x03b5u, 0x03f5u, 0 };
|
||||
uint16_t ucs2CharacterSet6[] = { 0x0398u, 0x03b8u, 0x03d1u, 0 };
|
||||
uint16_t ucs2CharacterSet7[] = { 0x0345u, 0x0399u, 0x03b9u, 0x1fbeu, 0 };
|
||||
uint16_t ucs2CharacterSet8[] = { 0x039au, 0x03bau, 0x03f0u, 0 };
|
||||
uint16_t ucs2CharacterSet9[] = { 0x00b5u, 0x039cu, 0x03bcu, 0 };
|
||||
uint16_t ucs2CharacterSet10[] = { 0x03a0u, 0x03c0u, 0x03d6u, 0 };
|
||||
uint16_t ucs2CharacterSet11[] = { 0x03a1u, 0x03c1u, 0x03f1u, 0 };
|
||||
uint16_t ucs2CharacterSet12[] = { 0x03a3u, 0x03c2u, 0x03c3u, 0 };
|
||||
uint16_t ucs2CharacterSet13[] = { 0x03a6u, 0x03c6u, 0x03d5u, 0 };
|
||||
uint16_t ucs2CharacterSet14[] = { 0x1e60u, 0x1e61u, 0x1e9bu, 0 };
|
||||
|
||||
static const size_t UCS2_CANONICALIZATION_SETS = 15;
|
||||
uint16_t* characterSetInfo[UCS2_CANONICALIZATION_SETS] = {
|
||||
ucs2CharacterSet0,
|
||||
ucs2CharacterSet1,
|
||||
ucs2CharacterSet2,
|
||||
ucs2CharacterSet3,
|
||||
ucs2CharacterSet4,
|
||||
ucs2CharacterSet5,
|
||||
ucs2CharacterSet6,
|
||||
ucs2CharacterSet7,
|
||||
ucs2CharacterSet8,
|
||||
ucs2CharacterSet9,
|
||||
ucs2CharacterSet10,
|
||||
ucs2CharacterSet11,
|
||||
ucs2CharacterSet12,
|
||||
ucs2CharacterSet13,
|
||||
ucs2CharacterSet14,
|
||||
};
|
||||
|
||||
const size_t UCS2_CANONICALIZATION_RANGES = 364;
|
||||
UCS2CanonicalizationRange rangeInfo[UCS2_CANONICALIZATION_RANGES] = {
|
||||
{ 0x0000u, 0x0040u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0041u, 0x005au, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x005bu, 0x0060u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0061u, 0x007au, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x007bu, 0x00b4u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x00b5u, 0x00b5u, 0x0009u, CanonicalizeSet },
|
||||
{ 0x00b6u, 0x00bfu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x00c0u, 0x00d6u, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x00d7u, 0x00d7u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x00d8u, 0x00deu, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x00dfu, 0x00dfu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x00e0u, 0x00f6u, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x00f7u, 0x00f7u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x00f8u, 0x00feu, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x00ffu, 0x00ffu, 0x0079u, CanonicalizeRangeLo },
|
||||
{ 0x0100u, 0x012fu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0130u, 0x0131u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0132u, 0x0137u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0138u, 0x0138u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0139u, 0x0148u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x0149u, 0x0149u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x014au, 0x0177u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0178u, 0x0178u, 0x0079u, CanonicalizeRangeHi },
|
||||
{ 0x0179u, 0x017eu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x017fu, 0x017fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0180u, 0x0180u, 0x00c3u, CanonicalizeRangeLo },
|
||||
{ 0x0181u, 0x0181u, 0x00d2u, CanonicalizeRangeLo },
|
||||
{ 0x0182u, 0x0185u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0186u, 0x0186u, 0x00ceu, CanonicalizeRangeLo },
|
||||
{ 0x0187u, 0x0188u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x0189u, 0x018au, 0x00cdu, CanonicalizeRangeLo },
|
||||
{ 0x018bu, 0x018cu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x018du, 0x018du, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x018eu, 0x018eu, 0x004fu, CanonicalizeRangeLo },
|
||||
{ 0x018fu, 0x018fu, 0x00cau, CanonicalizeRangeLo },
|
||||
{ 0x0190u, 0x0190u, 0x00cbu, CanonicalizeRangeLo },
|
||||
{ 0x0191u, 0x0192u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x0193u, 0x0193u, 0x00cdu, CanonicalizeRangeLo },
|
||||
{ 0x0194u, 0x0194u, 0x00cfu, CanonicalizeRangeLo },
|
||||
{ 0x0195u, 0x0195u, 0x0061u, CanonicalizeRangeLo },
|
||||
{ 0x0196u, 0x0196u, 0x00d3u, CanonicalizeRangeLo },
|
||||
{ 0x0197u, 0x0197u, 0x00d1u, CanonicalizeRangeLo },
|
||||
{ 0x0198u, 0x0199u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x019au, 0x019au, 0x00a3u, CanonicalizeRangeLo },
|
||||
{ 0x019bu, 0x019bu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x019cu, 0x019cu, 0x00d3u, CanonicalizeRangeLo },
|
||||
{ 0x019du, 0x019du, 0x00d5u, CanonicalizeRangeLo },
|
||||
{ 0x019eu, 0x019eu, 0x0082u, CanonicalizeRangeLo },
|
||||
{ 0x019fu, 0x019fu, 0x00d6u, CanonicalizeRangeLo },
|
||||
{ 0x01a0u, 0x01a5u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x01a6u, 0x01a6u, 0x00dau, CanonicalizeRangeLo },
|
||||
{ 0x01a7u, 0x01a8u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x01a9u, 0x01a9u, 0x00dau, CanonicalizeRangeLo },
|
||||
{ 0x01aau, 0x01abu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x01acu, 0x01adu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x01aeu, 0x01aeu, 0x00dau, CanonicalizeRangeLo },
|
||||
{ 0x01afu, 0x01b0u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x01b1u, 0x01b2u, 0x00d9u, CanonicalizeRangeLo },
|
||||
{ 0x01b3u, 0x01b6u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x01b7u, 0x01b7u, 0x00dbu, CanonicalizeRangeLo },
|
||||
{ 0x01b8u, 0x01b9u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x01bau, 0x01bbu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x01bcu, 0x01bdu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x01beu, 0x01beu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x01bfu, 0x01bfu, 0x0038u, CanonicalizeRangeLo },
|
||||
{ 0x01c0u, 0x01c3u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x01c4u, 0x01c6u, 0x0000u, CanonicalizeSet },
|
||||
{ 0x01c7u, 0x01c9u, 0x0001u, CanonicalizeSet },
|
||||
{ 0x01cau, 0x01ccu, 0x0002u, CanonicalizeSet },
|
||||
{ 0x01cdu, 0x01dcu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x01ddu, 0x01ddu, 0x004fu, CanonicalizeRangeHi },
|
||||
{ 0x01deu, 0x01efu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x01f0u, 0x01f0u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x01f1u, 0x01f3u, 0x0003u, CanonicalizeSet },
|
||||
{ 0x01f4u, 0x01f5u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x01f6u, 0x01f6u, 0x0061u, CanonicalizeRangeHi },
|
||||
{ 0x01f7u, 0x01f7u, 0x0038u, CanonicalizeRangeHi },
|
||||
{ 0x01f8u, 0x021fu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0220u, 0x0220u, 0x0082u, CanonicalizeRangeHi },
|
||||
{ 0x0221u, 0x0221u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0222u, 0x0233u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0234u, 0x0239u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x023au, 0x023au, 0x2a2bu, CanonicalizeRangeLo },
|
||||
{ 0x023bu, 0x023cu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x023du, 0x023du, 0x00a3u, CanonicalizeRangeHi },
|
||||
{ 0x023eu, 0x023eu, 0x2a28u, CanonicalizeRangeLo },
|
||||
{ 0x023fu, 0x0240u, 0x2a3fu, CanonicalizeRangeLo },
|
||||
{ 0x0241u, 0x0242u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x0243u, 0x0243u, 0x00c3u, CanonicalizeRangeHi },
|
||||
{ 0x0244u, 0x0244u, 0x0045u, CanonicalizeRangeLo },
|
||||
{ 0x0245u, 0x0245u, 0x0047u, CanonicalizeRangeLo },
|
||||
{ 0x0246u, 0x024fu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0250u, 0x0250u, 0x2a1fu, CanonicalizeRangeLo },
|
||||
{ 0x0251u, 0x0251u, 0x2a1cu, CanonicalizeRangeLo },
|
||||
{ 0x0252u, 0x0252u, 0x2a1eu, CanonicalizeRangeLo },
|
||||
{ 0x0253u, 0x0253u, 0x00d2u, CanonicalizeRangeHi },
|
||||
{ 0x0254u, 0x0254u, 0x00ceu, CanonicalizeRangeHi },
|
||||
{ 0x0255u, 0x0255u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0256u, 0x0257u, 0x00cdu, CanonicalizeRangeHi },
|
||||
{ 0x0258u, 0x0258u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0259u, 0x0259u, 0x00cau, CanonicalizeRangeHi },
|
||||
{ 0x025au, 0x025au, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x025bu, 0x025bu, 0x00cbu, CanonicalizeRangeHi },
|
||||
{ 0x025cu, 0x025fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0260u, 0x0260u, 0x00cdu, CanonicalizeRangeHi },
|
||||
{ 0x0261u, 0x0262u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0263u, 0x0263u, 0x00cfu, CanonicalizeRangeHi },
|
||||
{ 0x0264u, 0x0264u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0265u, 0x0265u, 0xa528u, CanonicalizeRangeLo },
|
||||
{ 0x0266u, 0x0267u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0268u, 0x0268u, 0x00d1u, CanonicalizeRangeHi },
|
||||
{ 0x0269u, 0x0269u, 0x00d3u, CanonicalizeRangeHi },
|
||||
{ 0x026au, 0x026au, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x026bu, 0x026bu, 0x29f7u, CanonicalizeRangeLo },
|
||||
{ 0x026cu, 0x026eu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x026fu, 0x026fu, 0x00d3u, CanonicalizeRangeHi },
|
||||
{ 0x0270u, 0x0270u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0271u, 0x0271u, 0x29fdu, CanonicalizeRangeLo },
|
||||
{ 0x0272u, 0x0272u, 0x00d5u, CanonicalizeRangeHi },
|
||||
{ 0x0273u, 0x0274u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0275u, 0x0275u, 0x00d6u, CanonicalizeRangeHi },
|
||||
{ 0x0276u, 0x027cu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x027du, 0x027du, 0x29e7u, CanonicalizeRangeLo },
|
||||
{ 0x027eu, 0x027fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0280u, 0x0280u, 0x00dau, CanonicalizeRangeHi },
|
||||
{ 0x0281u, 0x0282u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0283u, 0x0283u, 0x00dau, CanonicalizeRangeHi },
|
||||
{ 0x0284u, 0x0287u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0288u, 0x0288u, 0x00dau, CanonicalizeRangeHi },
|
||||
{ 0x0289u, 0x0289u, 0x0045u, CanonicalizeRangeHi },
|
||||
{ 0x028au, 0x028bu, 0x00d9u, CanonicalizeRangeHi },
|
||||
{ 0x028cu, 0x028cu, 0x0047u, CanonicalizeRangeHi },
|
||||
{ 0x028du, 0x0291u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0292u, 0x0292u, 0x00dbu, CanonicalizeRangeHi },
|
||||
{ 0x0293u, 0x0344u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0345u, 0x0345u, 0x0007u, CanonicalizeSet },
|
||||
{ 0x0346u, 0x036fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0370u, 0x0373u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0374u, 0x0375u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0376u, 0x0377u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0378u, 0x037au, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x037bu, 0x037du, 0x0082u, CanonicalizeRangeLo },
|
||||
{ 0x037eu, 0x0385u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0386u, 0x0386u, 0x0026u, CanonicalizeRangeLo },
|
||||
{ 0x0387u, 0x0387u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0388u, 0x038au, 0x0025u, CanonicalizeRangeLo },
|
||||
{ 0x038bu, 0x038bu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x038cu, 0x038cu, 0x0040u, CanonicalizeRangeLo },
|
||||
{ 0x038du, 0x038du, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x038eu, 0x038fu, 0x003fu, CanonicalizeRangeLo },
|
||||
{ 0x0390u, 0x0390u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0391u, 0x0391u, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x0392u, 0x0392u, 0x0004u, CanonicalizeSet },
|
||||
{ 0x0393u, 0x0394u, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x0395u, 0x0395u, 0x0005u, CanonicalizeSet },
|
||||
{ 0x0396u, 0x0397u, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x0398u, 0x0398u, 0x0006u, CanonicalizeSet },
|
||||
{ 0x0399u, 0x0399u, 0x0007u, CanonicalizeSet },
|
||||
{ 0x039au, 0x039au, 0x0008u, CanonicalizeSet },
|
||||
{ 0x039bu, 0x039bu, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x039cu, 0x039cu, 0x0009u, CanonicalizeSet },
|
||||
{ 0x039du, 0x039fu, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x03a0u, 0x03a0u, 0x000au, CanonicalizeSet },
|
||||
{ 0x03a1u, 0x03a1u, 0x000bu, CanonicalizeSet },
|
||||
{ 0x03a2u, 0x03a2u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x03a3u, 0x03a3u, 0x000cu, CanonicalizeSet },
|
||||
{ 0x03a4u, 0x03a5u, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x03a6u, 0x03a6u, 0x000du, CanonicalizeSet },
|
||||
{ 0x03a7u, 0x03abu, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x03acu, 0x03acu, 0x0026u, CanonicalizeRangeHi },
|
||||
{ 0x03adu, 0x03afu, 0x0025u, CanonicalizeRangeHi },
|
||||
{ 0x03b0u, 0x03b0u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x03b1u, 0x03b1u, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x03b2u, 0x03b2u, 0x0004u, CanonicalizeSet },
|
||||
{ 0x03b3u, 0x03b4u, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x03b5u, 0x03b5u, 0x0005u, CanonicalizeSet },
|
||||
{ 0x03b6u, 0x03b7u, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x03b8u, 0x03b8u, 0x0006u, CanonicalizeSet },
|
||||
{ 0x03b9u, 0x03b9u, 0x0007u, CanonicalizeSet },
|
||||
{ 0x03bau, 0x03bau, 0x0008u, CanonicalizeSet },
|
||||
{ 0x03bbu, 0x03bbu, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x03bcu, 0x03bcu, 0x0009u, CanonicalizeSet },
|
||||
{ 0x03bdu, 0x03bfu, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x03c0u, 0x03c0u, 0x000au, CanonicalizeSet },
|
||||
{ 0x03c1u, 0x03c1u, 0x000bu, CanonicalizeSet },
|
||||
{ 0x03c2u, 0x03c3u, 0x000cu, CanonicalizeSet },
|
||||
{ 0x03c4u, 0x03c5u, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x03c6u, 0x03c6u, 0x000du, CanonicalizeSet },
|
||||
{ 0x03c7u, 0x03cbu, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x03ccu, 0x03ccu, 0x0040u, CanonicalizeRangeHi },
|
||||
{ 0x03cdu, 0x03ceu, 0x003fu, CanonicalizeRangeHi },
|
||||
{ 0x03cfu, 0x03cfu, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x03d0u, 0x03d0u, 0x0004u, CanonicalizeSet },
|
||||
{ 0x03d1u, 0x03d1u, 0x0006u, CanonicalizeSet },
|
||||
{ 0x03d2u, 0x03d4u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x03d5u, 0x03d5u, 0x000du, CanonicalizeSet },
|
||||
{ 0x03d6u, 0x03d6u, 0x000au, CanonicalizeSet },
|
||||
{ 0x03d7u, 0x03d7u, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x03d8u, 0x03efu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x03f0u, 0x03f0u, 0x0008u, CanonicalizeSet },
|
||||
{ 0x03f1u, 0x03f1u, 0x000bu, CanonicalizeSet },
|
||||
{ 0x03f2u, 0x03f2u, 0x0007u, CanonicalizeRangeLo },
|
||||
{ 0x03f3u, 0x03f4u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x03f5u, 0x03f5u, 0x0005u, CanonicalizeSet },
|
||||
{ 0x03f6u, 0x03f6u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x03f7u, 0x03f8u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x03f9u, 0x03f9u, 0x0007u, CanonicalizeRangeHi },
|
||||
{ 0x03fau, 0x03fbu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x03fcu, 0x03fcu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x03fdu, 0x03ffu, 0x0082u, CanonicalizeRangeHi },
|
||||
{ 0x0400u, 0x040fu, 0x0050u, CanonicalizeRangeLo },
|
||||
{ 0x0410u, 0x042fu, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0x0430u, 0x044fu, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0x0450u, 0x045fu, 0x0050u, CanonicalizeRangeHi },
|
||||
{ 0x0460u, 0x0481u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0482u, 0x0489u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x048au, 0x04bfu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x04c0u, 0x04c0u, 0x000fu, CanonicalizeRangeLo },
|
||||
{ 0x04c1u, 0x04ceu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x04cfu, 0x04cfu, 0x000fu, CanonicalizeRangeHi },
|
||||
{ 0x04d0u, 0x0527u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x0528u, 0x0530u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0531u, 0x0556u, 0x0030u, CanonicalizeRangeLo },
|
||||
{ 0x0557u, 0x0560u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x0561u, 0x0586u, 0x0030u, CanonicalizeRangeHi },
|
||||
{ 0x0587u, 0x109fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x10a0u, 0x10c5u, 0x1c60u, CanonicalizeRangeLo },
|
||||
{ 0x10c6u, 0x1d78u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1d79u, 0x1d79u, 0x8a04u, CanonicalizeRangeLo },
|
||||
{ 0x1d7au, 0x1d7cu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1d7du, 0x1d7du, 0x0ee6u, CanonicalizeRangeLo },
|
||||
{ 0x1d7eu, 0x1dffu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1e00u, 0x1e5fu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x1e60u, 0x1e61u, 0x000eu, CanonicalizeSet },
|
||||
{ 0x1e62u, 0x1e95u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x1e96u, 0x1e9au, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1e9bu, 0x1e9bu, 0x000eu, CanonicalizeSet },
|
||||
{ 0x1e9cu, 0x1e9fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1ea0u, 0x1effu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x1f00u, 0x1f07u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f08u, 0x1f0fu, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f10u, 0x1f15u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f16u, 0x1f17u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f18u, 0x1f1du, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f1eu, 0x1f1fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f20u, 0x1f27u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f28u, 0x1f2fu, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f30u, 0x1f37u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f38u, 0x1f3fu, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f40u, 0x1f45u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f46u, 0x1f47u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f48u, 0x1f4du, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f4eu, 0x1f50u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f51u, 0x1f51u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f52u, 0x1f52u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f53u, 0x1f53u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f54u, 0x1f54u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f55u, 0x1f55u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f56u, 0x1f56u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f57u, 0x1f57u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f58u, 0x1f58u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f59u, 0x1f59u, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f5au, 0x1f5au, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f5bu, 0x1f5bu, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f5cu, 0x1f5cu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f5du, 0x1f5du, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f5eu, 0x1f5eu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1f5fu, 0x1f5fu, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f60u, 0x1f67u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1f68u, 0x1f6fu, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1f70u, 0x1f71u, 0x004au, CanonicalizeRangeLo },
|
||||
{ 0x1f72u, 0x1f75u, 0x0056u, CanonicalizeRangeLo },
|
||||
{ 0x1f76u, 0x1f77u, 0x0064u, CanonicalizeRangeLo },
|
||||
{ 0x1f78u, 0x1f79u, 0x0080u, CanonicalizeRangeLo },
|
||||
{ 0x1f7au, 0x1f7bu, 0x0070u, CanonicalizeRangeLo },
|
||||
{ 0x1f7cu, 0x1f7du, 0x007eu, CanonicalizeRangeLo },
|
||||
{ 0x1f7eu, 0x1fafu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fb0u, 0x1fb1u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1fb2u, 0x1fb7u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fb8u, 0x1fb9u, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1fbau, 0x1fbbu, 0x004au, CanonicalizeRangeHi },
|
||||
{ 0x1fbcu, 0x1fbdu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fbeu, 0x1fbeu, 0x0007u, CanonicalizeSet },
|
||||
{ 0x1fbfu, 0x1fc7u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fc8u, 0x1fcbu, 0x0056u, CanonicalizeRangeHi },
|
||||
{ 0x1fccu, 0x1fcfu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fd0u, 0x1fd1u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1fd2u, 0x1fd7u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fd8u, 0x1fd9u, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1fdau, 0x1fdbu, 0x0064u, CanonicalizeRangeHi },
|
||||
{ 0x1fdcu, 0x1fdfu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fe0u, 0x1fe1u, 0x0008u, CanonicalizeRangeLo },
|
||||
{ 0x1fe2u, 0x1fe4u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fe5u, 0x1fe5u, 0x0007u, CanonicalizeRangeLo },
|
||||
{ 0x1fe6u, 0x1fe7u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1fe8u, 0x1fe9u, 0x0008u, CanonicalizeRangeHi },
|
||||
{ 0x1feau, 0x1febu, 0x0070u, CanonicalizeRangeHi },
|
||||
{ 0x1fecu, 0x1fecu, 0x0007u, CanonicalizeRangeHi },
|
||||
{ 0x1fedu, 0x1ff7u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x1ff8u, 0x1ff9u, 0x0080u, CanonicalizeRangeHi },
|
||||
{ 0x1ffau, 0x1ffbu, 0x007eu, CanonicalizeRangeHi },
|
||||
{ 0x1ffcu, 0x2131u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2132u, 0x2132u, 0x001cu, CanonicalizeRangeLo },
|
||||
{ 0x2133u, 0x214du, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x214eu, 0x214eu, 0x001cu, CanonicalizeRangeHi },
|
||||
{ 0x214fu, 0x215fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2160u, 0x216fu, 0x0010u, CanonicalizeRangeLo },
|
||||
{ 0x2170u, 0x217fu, 0x0010u, CanonicalizeRangeHi },
|
||||
{ 0x2180u, 0x2182u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2183u, 0x2184u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x2185u, 0x24b5u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x24b6u, 0x24cfu, 0x001au, CanonicalizeRangeLo },
|
||||
{ 0x24d0u, 0x24e9u, 0x001au, CanonicalizeRangeHi },
|
||||
{ 0x24eau, 0x2bffu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2c00u, 0x2c2eu, 0x0030u, CanonicalizeRangeLo },
|
||||
{ 0x2c2fu, 0x2c2fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2c30u, 0x2c5eu, 0x0030u, CanonicalizeRangeHi },
|
||||
{ 0x2c5fu, 0x2c5fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2c60u, 0x2c61u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x2c62u, 0x2c62u, 0x29f7u, CanonicalizeRangeHi },
|
||||
{ 0x2c63u, 0x2c63u, 0x0ee6u, CanonicalizeRangeHi },
|
||||
{ 0x2c64u, 0x2c64u, 0x29e7u, CanonicalizeRangeHi },
|
||||
{ 0x2c65u, 0x2c65u, 0x2a2bu, CanonicalizeRangeHi },
|
||||
{ 0x2c66u, 0x2c66u, 0x2a28u, CanonicalizeRangeHi },
|
||||
{ 0x2c67u, 0x2c6cu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x2c6du, 0x2c6du, 0x2a1cu, CanonicalizeRangeHi },
|
||||
{ 0x2c6eu, 0x2c6eu, 0x29fdu, CanonicalizeRangeHi },
|
||||
{ 0x2c6fu, 0x2c6fu, 0x2a1fu, CanonicalizeRangeHi },
|
||||
{ 0x2c70u, 0x2c70u, 0x2a1eu, CanonicalizeRangeHi },
|
||||
{ 0x2c71u, 0x2c71u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2c72u, 0x2c73u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x2c74u, 0x2c74u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2c75u, 0x2c76u, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x2c77u, 0x2c7du, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2c7eu, 0x2c7fu, 0x2a3fu, CanonicalizeRangeHi },
|
||||
{ 0x2c80u, 0x2ce3u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0x2ce4u, 0x2ceau, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2cebu, 0x2ceeu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0x2cefu, 0x2cffu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0x2d00u, 0x2d25u, 0x1c60u, CanonicalizeRangeHi },
|
||||
{ 0x2d26u, 0xa63fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xa640u, 0xa66du, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0xa66eu, 0xa67fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xa680u, 0xa697u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0xa698u, 0xa721u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xa722u, 0xa72fu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0xa730u, 0xa731u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xa732u, 0xa76fu, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0xa770u, 0xa778u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xa779u, 0xa77cu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0xa77du, 0xa77du, 0x8a04u, CanonicalizeRangeHi },
|
||||
{ 0xa77eu, 0xa787u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0xa788u, 0xa78au, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xa78bu, 0xa78cu, 0x0000u, CanonicalizeAlternatingUnaligned },
|
||||
{ 0xa78du, 0xa78du, 0xa528u, CanonicalizeRangeHi },
|
||||
{ 0xa78eu, 0xa78fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xa790u, 0xa791u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0xa792u, 0xa79fu, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xa7a0u, 0xa7a9u, 0x0000u, CanonicalizeAlternatingAligned },
|
||||
{ 0xa7aau, 0xff20u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xff21u, 0xff3au, 0x0020u, CanonicalizeRangeLo },
|
||||
{ 0xff3bu, 0xff40u, 0x0000u, CanonicalizeUnique },
|
||||
{ 0xff41u, 0xff5au, 0x0020u, CanonicalizeRangeHi },
|
||||
{ 0xff5bu, 0xffffu, 0x0000u, CanonicalizeUnique },
|
||||
};
|
||||
|
||||
const size_t LATIN_CANONICALIZATION_RANGES = 20;
|
||||
LatinCanonicalizationRange latinRangeInfo[LATIN_CANONICALIZATION_RANGES] = {
|
||||
{ 0x0000u, 0x0040u, 0x0000u, CanonicalizeLatinSelf },
|
||||
{ 0x0041u, 0x005au, 0x0000u, CanonicalizeLatinMask0x20 },
|
||||
{ 0x005bu, 0x0060u, 0x0000u, CanonicalizeLatinSelf },
|
||||
{ 0x0061u, 0x007au, 0x0000u, CanonicalizeLatinMask0x20 },
|
||||
{ 0x007bu, 0x00bfu, 0x0000u, CanonicalizeLatinSelf },
|
||||
{ 0x00c0u, 0x00d6u, 0x0000u, CanonicalizeLatinMask0x20 },
|
||||
{ 0x00d7u, 0x00d7u, 0x0000u, CanonicalizeLatinSelf },
|
||||
{ 0x00d8u, 0x00deu, 0x0000u, CanonicalizeLatinMask0x20 },
|
||||
{ 0x00dfu, 0x00dfu, 0x0000u, CanonicalizeLatinSelf },
|
||||
{ 0x00e0u, 0x00f6u, 0x0000u, CanonicalizeLatinMask0x20 },
|
||||
{ 0x00f7u, 0x00f7u, 0x0000u, CanonicalizeLatinSelf },
|
||||
{ 0x00f8u, 0x00feu, 0x0000u, CanonicalizeLatinMask0x20 },
|
||||
{ 0x00ffu, 0x00ffu, 0x0000u, CanonicalizeLatinSelf },
|
||||
{ 0x0100u, 0x0177u, 0x0000u, CanonicalizeLatinInvalid },
|
||||
{ 0x0178u, 0x0178u, 0x00ffu, CanonicalizeLatinOther },
|
||||
{ 0x0179u, 0x039bu, 0x0000u, CanonicalizeLatinInvalid },
|
||||
{ 0x039cu, 0x039cu, 0x00b5u, CanonicalizeLatinOther },
|
||||
{ 0x039du, 0x03bbu, 0x0000u, CanonicalizeLatinInvalid },
|
||||
{ 0x03bcu, 0x03bcu, 0x00b5u, CanonicalizeLatinOther },
|
||||
{ 0x03bdu, 0xffffu, 0x0000u, CanonicalizeLatinInvalid },
|
||||
};
|
||||
|
||||
} } // JSC::Yarr
|
||||
|
139
js/src/yarr/YarrCanonicalizeUCS2.h
Normal file
139
js/src/yarr/YarrCanonicalizeUCS2.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef YarrCanonicalizeUCS2_H
|
||||
#define YarrCanonicalizeUCS2_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "wtfbridge.h"
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
|
||||
namespace JSC { namespace Yarr {
|
||||
|
||||
// This set of data (autogenerated using YarrCanonicalizeUCS2.js into YarrCanonicalizeUCS2.cpp)
|
||||
// provides information for each UCS2 code point as to the set of code points that it should
|
||||
// match under the ES5.1 case insensitive RegExp matching rules, specified in 15.10.2.8.
|
||||
enum UCS2CanonicalizationType {
|
||||
CanonicalizeUnique, // No canonically equal values, e.g. 0x0.
|
||||
CanonicalizeSet, // Value indicates a set in characterSetInfo.
|
||||
CanonicalizeRangeLo, // Value is positive delta to pair, E.g. 0x41 has value 0x20, -> 0x61.
|
||||
CanonicalizeRangeHi, // Value is positive delta to pair, E.g. 0x61 has value 0x20, -> 0x41.
|
||||
CanonicalizeAlternatingAligned, // Aligned consequtive pair, e.g. 0x1f4,0x1f5.
|
||||
CanonicalizeAlternatingUnaligned // Unaligned consequtive pair, e.g. 0x241,0x242.
|
||||
};
|
||||
struct UCS2CanonicalizationRange { uint16_t begin, end, value, type; };
|
||||
extern const size_t UCS2_CANONICALIZATION_RANGES;
|
||||
extern uint16_t* characterSetInfo[];
|
||||
extern UCS2CanonicalizationRange rangeInfo[];
|
||||
|
||||
// This table is similar to the full rangeInfo table, however this maps from UCS2 codepoints to
|
||||
// the set of Latin1 codepoints that could match.
|
||||
enum LatinCanonicalizationType {
|
||||
CanonicalizeLatinSelf, // This character is in the Latin1 range, but has no canonical equivalent in the range.
|
||||
CanonicalizeLatinMask0x20, // One of a pair of characters, under the mask 0x20.
|
||||
CanonicalizeLatinOther, // This character is not in the Latin1 range, but canonicalizes to another that is.
|
||||
CanonicalizeLatinInvalid // Cannot match against Latin1 input.
|
||||
};
|
||||
struct LatinCanonicalizationRange { uint16_t begin, end, value, type; };
|
||||
extern const size_t LATIN_CANONICALIZATION_RANGES;
|
||||
extern LatinCanonicalizationRange latinRangeInfo[];
|
||||
|
||||
// This searches in log2 time over ~364 entries, so should typically result in 8 compares.
|
||||
inline UCS2CanonicalizationRange* rangeInfoFor(UChar ch)
|
||||
{
|
||||
UCS2CanonicalizationRange* info = rangeInfo;
|
||||
size_t entries = UCS2_CANONICALIZATION_RANGES;
|
||||
|
||||
while (true) {
|
||||
size_t candidate = entries >> 1;
|
||||
UCS2CanonicalizationRange* candidateInfo = info + candidate;
|
||||
if (ch < candidateInfo->begin)
|
||||
entries = candidate;
|
||||
else if (ch <= candidateInfo->end)
|
||||
return candidateInfo;
|
||||
else {
|
||||
info = candidateInfo + 1;
|
||||
entries -= (candidate + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Should only be called for characters that have one canonically matching value.
|
||||
inline UChar getCanonicalPair(UCS2CanonicalizationRange* info, UChar ch)
|
||||
{
|
||||
ASSERT(ch >= info->begin && ch <= info->end);
|
||||
switch (info->type) {
|
||||
case CanonicalizeRangeLo:
|
||||
return ch + info->value;
|
||||
case CanonicalizeRangeHi:
|
||||
return ch - info->value;
|
||||
case CanonicalizeAlternatingAligned:
|
||||
return ch ^ 1;
|
||||
case CanonicalizeAlternatingUnaligned:
|
||||
return ((ch - 1) ^ 1) + 1;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns true if no other UCS2 codepoint can match this value.
|
||||
inline bool isCanonicallyUnique(UChar ch)
|
||||
{
|
||||
return rangeInfoFor(ch)->type == CanonicalizeUnique;
|
||||
}
|
||||
|
||||
// Returns true if values are equal, under the canonicalization rules.
|
||||
inline bool areCanonicallyEquivalent(UChar a, UChar b)
|
||||
{
|
||||
UCS2CanonicalizationRange* info = rangeInfoFor(a);
|
||||
switch (info->type) {
|
||||
case CanonicalizeUnique:
|
||||
return a == b;
|
||||
case CanonicalizeSet: {
|
||||
for (uint16_t* set = characterSetInfo[info->value]; (a = *set); ++set) {
|
||||
if (a == b)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case CanonicalizeRangeLo:
|
||||
return (a == b) || (a + info->value == b);
|
||||
case CanonicalizeRangeHi:
|
||||
return (a == b) || (a - info->value == b);
|
||||
case CanonicalizeAlternatingAligned:
|
||||
return (a | 1) == (b | 1);
|
||||
case CanonicalizeAlternatingUnaligned:
|
||||
return ((a - 1) | 1) == ((b - 1) | 1);
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
} } // JSC::Yarr
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user