From 387384fa3c4f2bd8bafac93344032d24842d2e6d Mon Sep 17 00:00:00 2001 From: Panos Astithas Date: Thu, 12 May 2011 09:29:17 -0300 Subject: [PATCH 001/145] Bug 646025 - Add file location to console.log, info, debug, etc.; f=mihai.sucan r=gavin.sharp --- dom/base/ConsoleAPI.js | 8 +- dom/tests/browser/browser_ConsoleAPITests.js | 52 ++++++++++-- dom/tests/browser/test-console-api.html | 5 ++ .../console/hudservice/HUDService.jsm | 41 +++++----- .../hudservice/tests/browser/Makefile.in | 3 + ...onsole_bug_646025_console_file_location.js | 80 +++++++++++++++++++ ...test-bug-646025-console-file-location.html | 11 +++ .../tests/browser/test-file-location.js | 9 +++ 8 files changed, 180 insertions(+), 29 deletions(-) create mode 100644 toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_646025_console_file_location.js create mode 100644 toolkit/components/console/hudservice/tests/browser/test-bug-646025-console-file-location.html create mode 100644 toolkit/components/console/hudservice/tests/browser/test-file-location.js diff --git a/dom/base/ConsoleAPI.js b/dom/base/ConsoleAPI.js index 194595ee4690..afec5653b218 100644 --- a/dom/base/ConsoleAPI.js +++ b/dom/base/ConsoleAPI.js @@ -122,9 +122,15 @@ ConsoleAPI.prototype = { if (!aID) return; + let stack = this.getStackTrace(); + // Skip the first frame since it contains an internal call. + let frame = stack[1]; let consoleEvent = { ID: aID, level: aLevel, + filename: frame.filename, + lineNumber: frame.lineNumber, + functionName: frame.functionName, arguments: aArguments }; @@ -157,7 +163,7 @@ ConsoleAPI.prototype = { } return stack; - }, + } }; let NSGetFactory = XPCOMUtils.generateNSGetFactory([ConsoleAPI]); diff --git a/dom/tests/browser/browser_ConsoleAPITests.js b/dom/tests/browser/browser_ConsoleAPITests.js index 4c086a85ae26..ae16708cfd2c 100644 --- a/dom/tests/browser/browser_ConsoleAPITests.js +++ b/dom/tests/browser/browser_ConsoleAPITests.js @@ -22,6 +22,7 @@ * David Dahl * Rob Campbell * Mihai Sucan + * Panos Astithas * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -39,7 +40,7 @@ const TEST_URI = "http://example.com/browser/dom/tests/browser/test-console-api.html"; -var gWindow; +var gWindow, gLevel, gArgs; function test() { waitForExplicitFinish(); @@ -65,8 +66,6 @@ function test() { }, false); } -var gWindow; - function testConsoleData(aMessageObject) { let messageWindow = getWindowByWindowId(aMessageObject.ID); is(messageWindow, gWindow, "found correct window by window ID"); @@ -79,9 +78,8 @@ function testConsoleData(aMessageObject) { is(aMessageObject.arguments.toSource(), gArgs.toSource(), "stack trace is correct"); - // Test finished - ConsoleObserver.destroy(); - finish(); + // Now test the location information in console.log() + startLocationTest(); } else { gArgs.forEach(function (a, i) { @@ -95,6 +93,26 @@ function testConsoleData(aMessageObject) { } } +function testLocationData(aMessageObject) { + let messageWindow = getWindowByWindowId(aMessageObject.ID); + is(messageWindow, gWindow, "found correct window by window ID"); + + is(aMessageObject.level, gLevel, "expected level received"); + ok(aMessageObject.arguments, "we have arguments"); + + is(aMessageObject.filename, gArgs[0].filename, "filename matches"); + is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches"); + is(aMessageObject.functionName, gArgs[0].functionName, "functionName matches"); + is(aMessageObject.arguments.length, gArgs[0].arguments.length, "arguments.length matches"); + gArgs[0].arguments.forEach(function (a, i) { + is(aMessageObject.arguments[i], a, "correct arg " + i); + }); + + // Test finished + ConsoleObserver.destroy(); + finish(); +} + function startTraceTest() { gLevel = "trace"; gArgs = [ @@ -109,7 +127,27 @@ function startTraceTest() { EventUtils.synthesizeMouse(button, 2, 2, {}, gWindow); } -var gLevel, gArgs; +function startLocationTest() { + // Reset the observer function to cope with the fabricated test data. + ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) { + try { + testLocationData(aSubject.wrappedJSObject); + } catch (ex) { + // XXX Exceptions in this function currently aren't reported, because of + // some XPConnect weirdness, so report them manually + ok(false, "Exception thrown in CO_observe: " + ex); + } + }; + gLevel = "log"; + gArgs = [ + {filename: TEST_URI, lineNumber: 19, functionName: "foobar646025", arguments: ["omg", "o", "d"]} + ]; + + let button = gWindow.document.getElementById("test-location"); + ok(button, "found #test-location button"); + EventUtils.synthesizeMouse(button, 2, 2, {}, gWindow); +} + function expect(level) { gLevel = level; gArgs = Array.slice(arguments, 1); diff --git a/dom/tests/browser/test-console-api.html b/dom/tests/browser/test-console-api.html index ea58306f420f..58dc264750f7 100644 --- a/dom/tests/browser/test-console-api.html +++ b/dom/tests/browser/test-console-api.html @@ -15,6 +15,10 @@ return foobar585956b(omg + "a"); } + function foobar646025(omg) { + console.log(omg, "o", "d"); + } + function test() { var str = "Test Message." console.foobar(str); // if this throws, we don't execute following funcs @@ -29,5 +33,6 @@

Console API Test Page

+ diff --git a/toolkit/components/console/hudservice/HUDService.jsm b/toolkit/components/console/hudservice/HUDService.jsm index 2b09e5ad9e42..592c9b8ff60b 100644 --- a/toolkit/components/console/hudservice/HUDService.jsm +++ b/toolkit/components/console/hudservice/HUDService.jsm @@ -1972,16 +1972,11 @@ HUD_SERVICE.prototype = * * @param string aHUDId * The ID of the Web Console to which to send the message. - * @param string aLevel - * The level reported by the console service. This will be one of the - * strings "error", "warn", "info", or "log". - * @param Array aArguments - * The list of arguments reported by the console service. + * @param object aMessage + * The message reported by the console service. * @return void */ - logConsoleAPIMessage: function HS_logConsoleAPIMessage(aHUDId, - aLevel, - aArguments) + logConsoleAPIMessage: function HS_logConsoleAPIMessage(aHUDId, aMessage) { // Pipe the message to createMessageNode(). let hud = HUDService.hudReferences[aHUDId]; @@ -1993,32 +1988,36 @@ HUD_SERVICE.prototype = let clipboardText = null; let sourceURL = null; let sourceLine = 0; + let level = aMessage.level; + let args = aMessage.arguments; - switch (aLevel) { + switch (level) { case "log": case "info": case "warn": case "error": case "debug": - let mappedArguments = Array.map(aArguments, formatResult); + let mappedArguments = Array.map(args, formatResult); body = Array.join(mappedArguments, " "); + sourceURL = aMessage.filename; + sourceLine = aMessage.lineNumber; break; case "trace": - let filename = ConsoleUtils.abbreviateSourceURL(aArguments[0].filename); - let functionName = aArguments[0].functionName || + let filename = ConsoleUtils.abbreviateSourceURL(args[0].filename); + let functionName = args[0].functionName || this.getStr("stacktrace.anonymousFunction"); - let lineNumber = aArguments[0].lineNumber; + let lineNumber = args[0].lineNumber; body = this.getFormatStr("stacktrace.outputMessage", [filename, functionName, lineNumber]); - sourceURL = aArguments[0].filename; - sourceLine = aArguments[0].lineNumber; + sourceURL = args[0].filename; + sourceLine = args[0].lineNumber; clipboardText = ""; - aArguments.forEach(function(aFrame) { + args.forEach(function(aFrame) { clipboardText += aFrame.filename + " :: " + aFrame.functionName + " :: " + aFrame.lineNumber + "\n"; @@ -2028,13 +2027,13 @@ HUD_SERVICE.prototype = break; default: - Cu.reportError("Unknown Console API log level: " + aLevel); + Cu.reportError("Unknown Console API log level: " + level); return; } let node = ConsoleUtils.createMessageNode(hud.outputNode.ownerDocument, CATEGORY_WEBDEV, - LEVELS[aLevel], + LEVELS[level], body, sourceURL, sourceLine, @@ -2042,8 +2041,8 @@ HUD_SERVICE.prototype = // Make the node bring up the property panel, to allow the user to inspect // the stack trace. - if (aLevel == "trace") { - node._stacktrace = aArguments; + if (level == "trace") { + node._stacktrace = args; let linkNode = node.querySelector(".webconsole-msg-body"); linkNode.classList.add("hud-clickable"); @@ -3598,7 +3597,7 @@ let ConsoleAPIObserver = { if (!hudId) return; - HUDService.logConsoleAPIMessage(hudId, aMessage.level, aMessage.arguments); + HUDService.logConsoleAPIMessage(hudId, aMessage); } else if (aTopic == "quit-application-granted") { HUDService.shutdown(); diff --git a/toolkit/components/console/hudservice/tests/browser/Makefile.in b/toolkit/components/console/hudservice/tests/browser/Makefile.in index 40aee0b60672..f0e2afb4ecd5 100644 --- a/toolkit/components/console/hudservice/tests/browser/Makefile.in +++ b/toolkit/components/console/hudservice/tests/browser/Makefile.in @@ -135,6 +135,7 @@ _BROWSER_TEST_FILES = \ browser_webconsole_bug_585956_console_trace.js \ browser_webconsole_bug_595223_file_uri.js \ browser_webconsole_bug_632275_getters_document_width.js \ + browser_webconsole_bug_646025_console_file_location.js \ head.js \ $(NULL) @@ -203,6 +204,8 @@ _BROWSER_TEST_PAGES = \ test-bug-632347-iterators-generators.html \ test-bug-585956-console-trace.html \ test-bug-632275-getters.html \ + test-bug-646025-console-file-location.html \ + test-file-location.js \ $(NULL) libs:: $(_BROWSER_TEST_FILES) diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_646025_console_file_location.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_646025_console_file_location.js new file mode 100644 index 000000000000..61701c0a3c1a --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_646025_console_file_location.js @@ -0,0 +1,80 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is DevTools test code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Dahl + * Patrick Walton + * Julian Viereck + * Mihai Sucan + * Panos Astithas + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// Tests that console logging methods display the method location along with +// the output in the console. + +const TEST_URI = "http://example.com/browser/toolkit/components/console/" + + "hudservice/tests/browser/" + + "test-bug-646025-console-file-location.html"; + +function test() { + addTab("data:text/html,Web Console file location display test"); + browser.addEventListener("load", onLoad, true); +} + +function onLoad(aEvent) { + browser.removeEventListener(aEvent.type, arguments.callee, true); + openConsole(); + hudId = HUDService.getHudIdByWindow(content); + + browser.addEventListener("load", testConsoleFileLocation, true); + content.location = TEST_URI; +} + +function testConsoleFileLocation(aEvent) { + browser.removeEventListener(aEvent.type, arguments.callee, true); + + outputNode = HUDService.hudReferences[hudId].outputNode; + + executeSoon(function() { + findLogEntry("test-file-location.js"); + findLogEntry("message for level"); + findLogEntry("test-file-location.js:5"); + findLogEntry("test-file-location.js:6"); + findLogEntry("test-file-location.js:7"); + findLogEntry("test-file-location.js:8"); + findLogEntry("test-file-location.js:9"); + + finishTest(); + }); +} + diff --git a/toolkit/components/console/hudservice/tests/browser/test-bug-646025-console-file-location.html b/toolkit/components/console/hudservice/tests/browser/test-bug-646025-console-file-location.html new file mode 100644 index 000000000000..8ae111f2b728 --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/test-bug-646025-console-file-location.html @@ -0,0 +1,11 @@ + + + Console file location test + + + + +

Web Console File Location Test Page

+ + diff --git a/toolkit/components/console/hudservice/tests/browser/test-file-location.js b/toolkit/components/console/hudservice/tests/browser/test-file-location.js new file mode 100644 index 000000000000..f97ce57259dd --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/test-file-location.js @@ -0,0 +1,9 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +console.log("message for level log"); +console.info("message for level info"); +console.warn("message for level warn"); +console.error("message for level error"); +console.debug("message for level debug"); From cfb9600794d2e3acfc0723ff08573d5da401db1e Mon Sep 17 00:00:00 2001 From: Mihai Sucan Date: Wed, 18 May 2011 14:08:54 +0300 Subject: [PATCH 002/145] Bug 577721 - allow repositioning of the web console: above, below and out into a panel/window; r=rcampbell,sdwilsh --- browser/app/profile/firefox.js | 6 + .../console/hudservice/HUDService.jsm | 474 +++++++++++++++--- .../hudservice/tests/browser/Makefile.in | 1 + .../browser/browser_webconsole_position_ui.js | 170 +++++++ .../chrome/global/headsUpDisplay.properties | 24 + .../themes/gnomestripe/global/webConsole.css | 10 + .../themes/pinstripe/global/webConsole.css | 10 + .../themes/winstripe/global/webConsole.css | 10 + 8 files changed, 646 insertions(+), 59 deletions(-) create mode 100644 toolkit/components/console/hudservice/tests/browser/browser_webconsole_position_ui.js diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 6a84d745129c..902ad847d3ba 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1003,6 +1003,12 @@ pref("devtools.chrome.enabled", false); // Change to -1 if you do not want the Web Console to remember its last height. pref("devtools.hud.height", 0); +// Remember the Web Console position. Possible values: +// above - above the web page, +// below - below the web page, +// window - in a separate window/popup panel. +pref("devtools.webconsole.position", "above"); + // Whether the character encoding menu is under the main Firefox button. This // preference is a string so that localizers can alter it. pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties"); diff --git a/toolkit/components/console/hudservice/HUDService.jsm b/toolkit/components/console/hudservice/HUDService.jsm index 592c9b8ff60b..60c26d496f43 100644 --- a/toolkit/components/console/hudservice/HUDService.jsm +++ b/toolkit/components/console/hudservice/HUDService.jsm @@ -1425,8 +1425,11 @@ HUD_SERVICE.prototype = this.registerActiveContext(nBox.id); this.windowInitializer(window); - if (!aAnimated) { - this.disableAnimation("hud_" + nBox.id); + let hudId = "hud_" + nBox.id; + let hudRef = this.hudReferences[hudId]; + + if (!aAnimated || hudRef.consolePanel) { + this.disableAnimation(hudId); } }, @@ -1441,10 +1444,10 @@ HUD_SERVICE.prototype = { let browser = aContext.linkedBrowser; let window = browser.contentWindow; - let nBox = aContext.ownerDocument.defaultView. - getNotificationBox(window); + let chromeDocument = aContext.ownerDocument; + let nBox = chromeDocument.defaultView.getNotificationBox(window); let hudId = "hud_" + nBox.id; - let displayNode = nBox.querySelector("#" + hudId); + let displayNode = chromeDocument.getElementById(hudId); if (hudId in this.hudReferences && displayNode) { if (!aAnimated) { @@ -1735,7 +1738,7 @@ HUD_SERVICE.prototype = // remove the nodes then. HUDService.clearDisplay(aHUD); - var id, outputNode; + var id, outputNode, ownerDoc; if (typeof(aHUD) === "string") { id = aHUD; outputNode = this.getHeadsUpDisplay(aHUD); @@ -1756,8 +1759,11 @@ HUD_SERVICE.prototype = break; } } - // remove the DOM Nodes - parent.removeChild(outputNode); + + ownerDoc = outputNode.ownerDocument; + ownerDoc.getElementById(id).parentNode.removeChild(outputNode); + + this.hudReferences[id].consoleWindowUnregisterOnHide = false; // remove the HeadsUpDisplay object from memory if ("cssNodes" in this.hudReferences[id]) { @@ -1848,7 +1854,7 @@ HUD_SERVICE.prototype = shutdown: function HS_shutdown() { for (let hudId in this.hudReferences) { - this.unregisterDisplay(hudId); + this.deactivateHUDForContext(this.hudReferences[hudId].tab, false); } }, @@ -2789,6 +2795,11 @@ HUD_SERVICE.prototype = let nBox = gBrowser.getNotificationBox(_browser); let nBoxId = nBox.getAttribute("id"); let hudId = "hud_" + nBoxId; + let windowUI = nBox.ownerDocument.getElementById("console_window_" + hudId); + if (windowUI) { + // The Web Console popup is already open, no need to continue. + return; + } if (!this.canActivateContext(hudId)) { return; @@ -2917,15 +2928,14 @@ HUD_SERVICE.prototype = resetHeight: function HS_resetHeight(aHUDId) { let HUD = this.hudReferences[aHUDId]; - let innerHeight = HUD.contentWindow.innerHeight; - let splitter = HUD.HUDBox.parentNode.querySelector(".hud-splitter"); - let chromeWindow = splitter.ownerDocument.defaultView; - - let splitterStyle = chromeWindow.getComputedStyle(splitter, null); - innerHeight += parseInt(splitterStyle.height) + - parseInt(splitterStyle.borderTopWidth) + - parseInt(splitterStyle.borderBottomWidth); + let chromeWindow = HUD.chromeDocument.defaultView; + if (!HUD.consolePanel) { + let splitterStyle = chromeWindow.getComputedStyle(HUD.splitter, null); + innerHeight += parseInt(splitterStyle.height) + + parseInt(splitterStyle.borderTopWidth) + + parseInt(splitterStyle.borderBottomWidth); + } let boxStyle = chromeWindow.getComputedStyle(HUD.HUDBox, null); innerHeight += parseInt(boxStyle.height) + @@ -3101,6 +3111,7 @@ function HeadsUpDisplay(aConfig) throw new Error(this.ERRORS.PARENTNODE_NOT_FOUND); } this.parentNode = parentNode; + this.notificationBox = parentNode; } // create textNode Factory: @@ -3109,19 +3120,13 @@ function HeadsUpDisplay(aConfig) this.chromeWindow = HUDService.getChromeWindowFromContentWindow(this.contentWindow); // create a panel dynamically and attach to the parentNode - let hudBox = this.createHUD(); - - let splitter = this.chromeDocument.createElement("splitter"); - splitter.setAttribute("class", "hud-splitter"); - - this.notificationBox.insertBefore(splitter, - this.notificationBox.childNodes[1]); + this.createHUD(); this.HUDBox.lastTimestamp = 0; // create the JSTerm input element try { this.createConsoleInput(this.contentWindow, this.consoleWrap, this.outputNode); - this.HUDBox.querySelectorAll(".jsterm-input-node")[0].focus(); + this.jsterm.inputNode.focus(); } catch (ex) { Cu.reportError(ex); @@ -3133,6 +3138,291 @@ function HeadsUpDisplay(aConfig) HeadsUpDisplay.prototype = { + consolePanel: null, + + get mainPopupSet() + { + return this.chromeDocument.getElementById("mainPopupSet"); + }, + + /** + * Get the tab associated to the HeadsUpDisplay object. + */ + get tab() + { + // TODO: we should only keep a reference to the xul:tab object and use + // getters to determine the rest of objects we need - the chrome window, + // document, etc. We should simplify the entire code to use only a single + // tab object ref. See bug 656231. + let tab = null; + let id = this.notificationBox.id; + Array.some(this.chromeDocument.defaultView.gBrowser.tabs, function(aTab) { + if (aTab.linkedPanel == id) { + tab = aTab; + return true; + } + }); + + return tab; + }, + + /** + * Create a panel to open the web console if it should float above + * the content in its own window. + */ + createOwnWindowPanel: function HUD_createOwnWindowPanel() + { + if (this.uiInOwnWindow) { + return this.consolePanel; + } + + let width = 0; + try { + width = Services.prefs.getIntPref("devtools.webconsole.width"); + } + catch (ex) {} + + if (width < 1) { + width = this.HUDBox.clientWidth || this.contentWindow.innerWidth; + } + + let height = this.HUDBox.clientHeight; + + let top = 0; + try { + top = Services.prefs.getIntPref("devtools.webconsole.top"); + } + catch (ex) {} + + let left = 0; + try { + left = Services.prefs.getIntPref("devtools.webconsole.left"); + } + catch (ex) {} + + let panel = this.chromeDocument.createElementNS(XUL_NS, "panel"); + + let label = this.getStr("webConsoleOwnWindowTitle"); + + let config = { id: "console_window_" + this.hudId, + label: label, + titlebar: "normal", + noautohide: "true", + norestorefocus: "true", + close: "true", + flex: "1", + hudId: this.hudId, + width: width, + position: "overlap", + top: top, + left: left, + }; + + for (let attr in config) { + panel.setAttribute(attr, config[attr]); + } + + panel.classList.add("web-console-panel"); + + let onPopupShown = (function HUD_onPopupShown() { + panel.removeEventListener("popupshown", onPopupShown, false); + + // Make sure that the HUDBox size updates when the panel is resized. + + let height = panel.clientHeight; + + this.HUDBox.style.height = "auto"; + this.HUDBox.setAttribute("flex", "1"); + + panel.setAttribute("height", height); + + // Scroll the outputNode back to the last location. + if (lastIndex > -1 && lastIndex < this.outputNode.getRowCount()) { + this.outputNode.ensureIndexIsVisible(lastIndex); + } + + if (this.jsterm) { + this.jsterm.inputNode.focus(); + } + }).bind(this); + + panel.addEventListener("popupshown", onPopupShown,false); + + let onPopupHiding = (function HUD_onPopupHiding(aEvent) { + if (aEvent.target != panel) { + return; + } + + panel.removeEventListener("popuphiding", onPopupHiding, false); + + let width = 0; + try { + width = Services.prefs.getIntPref("devtools.webconsole.width"); + } + catch (ex) { } + + if (width > -1) { + Services.prefs.setIntPref("devtools.webconsole.width", panel.clientWidth); + } + + Services.prefs.setIntPref("devtools.webconsole.top", panel.popupBoxObject.y); + Services.prefs.setIntPref("devtools.webconsole.left", panel.popupBoxObject.x); + + // Make sure we are not going to close again, drop the hudId reference of + // the panel. + panel.removeAttribute("hudId"); + + if (this.consoleWindowUnregisterOnHide) { + HUDService.deactivateHUDForContext(this.tab, false); + } + else { + this.consoleWindowUnregisterOnHide = true; + } + + this.consolePanel = null; + }).bind(this); + + panel.addEventListener("popuphiding", onPopupHiding, false); + + let onPopupHidden = (function HUD_onPopupHidden(aEvent) { + if (aEvent.target != panel) { + return; + } + + panel.removeEventListener("popuphidden", onPopupHidden, false); + this.mainPopupSet.removeChild(panel); + }).bind(this); + + panel.addEventListener("popuphidden", onPopupHidden, false); + + let lastIndex = -1; + + if (this.outputNode.getIndexOfFirstVisibleRow) { + lastIndex = this.outputNode.getIndexOfFirstVisibleRow() + + this.outputNode.getNumberOfVisibleRows() - 1; + } + + if (this.splitter.parentNode) { + this.splitter.parentNode.removeChild(this.splitter); + } + panel.appendChild(this.HUDBox); + + let space = this.chromeDocument.createElement("spacer"); + space.setAttribute("flex", "1"); + + let bottomBox = this.chromeDocument.createElement("hbox"); + space.setAttribute("flex", "1"); + + let resizer = this.chromeDocument.createElement("resizer"); + resizer.setAttribute("dir", "bottomend"); + resizer.setAttribute("element", config.id); + + bottomBox.appendChild(space); + bottomBox.appendChild(resizer); + + panel.appendChild(bottomBox); + + this.mainPopupSet.appendChild(panel); + + Services.prefs.setCharPref("devtools.webconsole.position", "window"); + + panel.openPopup(null, "overlay", left, top, false, false); + + this.consolePanel = panel; + this.consoleWindowUnregisterOnHide = true; + + return panel; + }, + + positions: { + above: 0, // the childNode index + below: 2, + window: null + }, + + consoleWindowUnregisterOnHide: true, + + /** + * Re-position the console + */ + positionConsole: function HUD_positionConsole(aPosition) + { + if (!(aPosition in this.positions)) { + throw new Error("Incorrect argument: " + aPosition + ". Cannot position Web Console"); + } + + if (aPosition == "window") { + this.createOwnWindowPanel(); + this.positionMenuitems.window.setAttribute("checked", true); + if (this.positionMenuitems.last) { + this.positionMenuitems.last.setAttribute("checked", false); + } + this.positionMenuitems.last = this.positionMenuitems[aPosition]; + this.uiInOwnWindow = true; + return; + } + + let height = this.HUDBox.clientHeight; + + // get the node position index + let nodeIdx = this.positions[aPosition]; + let nBox = this.notificationBox; + let node = nBox.childNodes[nodeIdx]; + + // check to see if console is already positioned in aPosition + if (node == this.HUDBox) { + return; + } + + let lastIndex = -1; + + if (this.outputNode.getIndexOfFirstVisibleRow) { + lastIndex = this.outputNode.getIndexOfFirstVisibleRow() + + this.outputNode.getNumberOfVisibleRows() - 1; + } + + // remove the console and splitter and reposition + if (this.splitter.parentNode) { + this.splitter.parentNode.removeChild(this.splitter); + } + + if (aPosition == "below") { + nBox.appendChild(this.splitter); + nBox.appendChild(this.HUDBox); + } + else { + nBox.insertBefore(this.splitter, node); + nBox.insertBefore(this.HUDBox, this.splitter); + } + + this.positionMenuitems[aPosition].setAttribute("checked", true); + if (this.positionMenuitems.last) { + this.positionMenuitems.last.setAttribute("checked", false); + } + this.positionMenuitems.last = this.positionMenuitems[aPosition]; + + Services.prefs.setCharPref("devtools.webconsole.position", aPosition); + + if (lastIndex > -1 && lastIndex < this.outputNode.getRowCount()) { + this.outputNode.ensureIndexIsVisible(lastIndex); + } + + this.uiInOwnWindow = false; + if (this.consolePanel) { + this.HUDBox.removeAttribute("flex"); + this.HUDBox.removeAttribute("height"); + this.HUDBox.style.height = height + "px"; + + // must destroy the consolePanel + this.consoleWindowUnregisterOnHide = false; + this.consolePanel.hidePopup(); + } + + if (this.jsterm) { + this.jsterm.inputNode.focus(); + } + }, + /** * L10N shortcut function * @@ -3225,6 +3515,10 @@ HeadsUpDisplay.prototype = { makeHUDNodes: function HUD_makeHUDNodes() { let self = this; + + this.splitter = this.makeXULNode("splitter"); + this.splitter.setAttribute("class", "hud-splitter"); + this.HUDBox = this.makeXULNode("vbox"); this.HUDBox.setAttribute("id", this.hudId); this.HUDBox.setAttribute("class", "hud-box animated"); @@ -3371,12 +3665,72 @@ HeadsUpDisplay.prototype = { } toolbar.appendChild(this.filterSpacer); + + let positionUI = this.createPositionUI(); + toolbar.appendChild(positionUI); + toolbar.appendChild(this.filterBox); this.makeClearConsoleButton(toolbar); return toolbar; }, + /** + * Creates the UI for re-positioning the console + * + * @return nsIDOMNode + * The xul:toolbarbutton which holds the menu that allows the user to + * change the console position. + */ + createPositionUI: function HUD_createPositionUI() + { + let self = this; + + let button = this.makeXULNode("toolbarbutton"); + button.setAttribute("type", "menu"); + button.setAttribute("label", this.getStr("webConsolePosition")); + button.setAttribute("tooltip", this.getStr("webConsolePositionTooltip")); + + let menuPopup = this.makeXULNode("menupopup"); + button.appendChild(menuPopup); + + let itemAbove = this.makeXULNode("menuitem"); + itemAbove.setAttribute("label", this.getStr("webConsolePositionAbove")); + itemAbove.setAttribute("type", "checkbox"); + itemAbove.setAttribute("autocheck", "false"); + itemAbove.addEventListener("command", function() { + self.positionConsole("above"); + }, false); + menuPopup.appendChild(itemAbove); + + let itemBelow = this.makeXULNode("menuitem"); + itemBelow.setAttribute("label", this.getStr("webConsolePositionBelow")); + itemBelow.setAttribute("type", "checkbox"); + itemBelow.setAttribute("autocheck", "false"); + itemBelow.addEventListener("command", function() { + self.positionConsole("below"); + }, false); + menuPopup.appendChild(itemBelow); + + let itemWindow = this.makeXULNode("menuitem"); + itemWindow.setAttribute("label", this.getStr("webConsolePositionWindow")); + itemWindow.setAttribute("type", "checkbox"); + itemWindow.setAttribute("autocheck", "false"); + itemWindow.addEventListener("command", function() { + self.positionConsole("window"); + }, false); + menuPopup.appendChild(itemWindow); + + this.positionMenuitems = { + last: null, + above: itemAbove, + below: itemBelow, + window: itemWindow, + }; + + return button; + }, + /** * Creates the context menu on the console. * @@ -3490,22 +3844,15 @@ HeadsUpDisplay.prototype = { */ makeCloseButton: function HUD_makeCloseButton(aToolbar) { - let hudId = this.hudId; - - function HUD_closeButton_onCommand() { - let ownerDocument = this.ownerDocument; - let tab = ownerDocument.defaultView.gBrowser.selectedTab; - HUDService.animate(hudId, ANIMATE_OUT, function() { - if (ownerDocument.getElementById(hudId)) { - HUDService.deactivateHUDForContext(tab, true); - } - }); - } + let onCommand = (function HUD_closeButton_onCommand() { + HUDService.animate(this.hudId, ANIMATE_OUT, (function() { + HUDService.deactivateHUDForContext(this.tab, true); + }).bind(this)); + }).bind(this); let closeButton = this.makeXULNode("toolbarbutton"); closeButton.classList.add("webconsole-close-button"); - closeButton.addEventListener("command", HUD_closeButton_onCommand, false); - + closeButton.addEventListener("command", onCommand, false); aToolbar.appendChild(closeButton); }, @@ -3533,22 +3880,24 @@ HeadsUpDisplay.prototype = { aToolbar.appendChild(clearButton); }, + /** + * Create the Web Console UI. + * + * @return nsIDOMNode + * The Web Console container element (HUDBox). + */ createHUD: function HUD_createHUD() { - let self = this; - if (this.HUDBox) { - return this.HUDBox; - } - else { + if (!this.HUDBox) { this.makeHUDNodes(); - - let nodes = this.notificationBox.insertBefore(this.HUDBox, - this.notificationBox.childNodes[0]); - - return this.HUDBox; + let positionPref = Services.prefs.getCharPref("devtools.webconsole.position"); + this.positionConsole(positionPref); } + return this.HUDBox; }, + uiInOwnWindow: false, + get console() { return this.contentWindow.wrappedJSObject.console; }, getLogCount: function HUD_getLogCount() @@ -5502,18 +5851,25 @@ HeadsUpDisplayUICommands = { var hudId = "hud_" + tabId; var ownerDocument = gBrowser.selectedTab.ownerDocument; var hud = ownerDocument.getElementById(hudId); - if (hud) { - HUDService.storeHeight(hudId); + var hudRef = HUDService.hudReferences[hudId]; - HUDService.animate(hudId, ANIMATE_OUT, function() { - // If the user closes the console while the console is animating away, - // then these callbacks will queue up, but all the callbacks after the - // first will have no console to operate on. This test handles this - // case gracefully. - if (ownerDocument.getElementById(hudId)) { - HUDService.deactivateHUDForContext(gBrowser.selectedTab, true); - } - }); + if (hudRef && hud) { + if (hudRef.consolePanel) { + HUDService.deactivateHUDForContext(gBrowser.selectedTab, false); + } + else { + HUDService.storeHeight(hudId); + + HUDService.animate(hudId, ANIMATE_OUT, function() { + // If the user closes the console while the console is animating away, + // then these callbacks will queue up, but all the callbacks after the + // first will have no console to operate on. This test handles this + // case gracefully. + if (ownerDocument.getElementById(hudId)) { + HUDService.deactivateHUDForContext(gBrowser.selectedTab, true); + } + }); + } } else { HUDService.activateHUDForContext(gBrowser.selectedTab, true); diff --git a/toolkit/components/console/hudservice/tests/browser/Makefile.in b/toolkit/components/console/hudservice/tests/browser/Makefile.in index f0e2afb4ecd5..cd00a521bc9d 100644 --- a/toolkit/components/console/hudservice/tests/browser/Makefile.in +++ b/toolkit/components/console/hudservice/tests/browser/Makefile.in @@ -136,6 +136,7 @@ _BROWSER_TEST_FILES = \ browser_webconsole_bug_595223_file_uri.js \ browser_webconsole_bug_632275_getters_document_width.js \ browser_webconsole_bug_646025_console_file_location.js \ + browser_webconsole_position_ui.js \ head.js \ $(NULL) diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_position_ui.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_position_ui.js new file mode 100644 index 000000000000..295602244a81 --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_position_ui.js @@ -0,0 +1,170 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const TEST_URI = "data:text/html,

test for bug 577721"; + +const POSITION_PREF = "devtools.webconsole.position"; +const TOP_PREF = "devtools.webconsole.top"; +const LEFT_PREF = "devtools.webconsole.left"; +const WIDTH_PREF = "devtools.webconsole.width"; +const HEIGHT_PREF = "devtools.hud.height"; + +function test() { + addTab(TEST_URI); + browser.addEventListener("DOMContentLoaded", onLoad, false); + registerCleanupFunction(testEnd); +} + +function testEnd() { + Services.prefs.clearUserPref(POSITION_PREF); + Services.prefs.clearUserPref(WIDTH_PREF); + Services.prefs.clearUserPref(HEIGHT_PREF); + Services.prefs.clearUserPref(TOP_PREF); + Services.prefs.clearUserPref(LEFT_PREF); +} + +function onLoad() { + browser.removeEventListener("DOMContentLoaded", onLoad, false); + + openConsole(); + + testMenuitems(); + + let hudId = HUDService.getHudIdByWindow(content); + let hudRef = HUDService.hudReferences[hudId]; + let hudBox = hudRef.HUDBox; + + is(hudBox.parentNode.childNodes[0].getAttribute("id"), hudId, + "initial console position is correct"); + + is(hudRef.positionMenuitems.above.getAttribute("checked"), "true", + "position menu checkbox is above"); + is(Services.prefs.getCharPref(POSITION_PREF), "above", "pref is above"); + + hudRef.positionConsole("below"); + let id = hudBox.parentNode.childNodes[2].getAttribute("id"); + is(id, hudId, "below position is correct"); + + is(hudRef.positionMenuitems.below.getAttribute("checked"), "true", + "position menu checkbox is below"); + is(Services.prefs.getCharPref(POSITION_PREF), "below", "pref is below"); + + // listen for the panel popupshown event. + document.addEventListener("popupshown", function() { + document.removeEventListener("popupshown", arguments.callee, false); + + document.addEventListener("popuphidden", function() { + document.removeEventListener("popuphidden", arguments.callee, false); + + id = hudBox.parentNode.childNodes[2].getAttribute("id"); + is(id, hudId, "below position is correct after reopen"); + + diffHeight = Math.abs(hudBox.clientHeight - boxHeight); + ok(diffHeight < 3, "hudBox height is still correct"); + + is(Services.prefs.getCharPref(POSITION_PREF), "below", "pref is below"); + is(Services.prefs.getIntPref(WIDTH_PREF), panelWidth, "width pref updated"); + isnot(Services.prefs.getIntPref(TOP_PREF), 50, "top location pref updated"); + isnot(Services.prefs.getIntPref(LEFT_PREF), 51, "left location pref updated"); + + // Close the window console via the toolbar button + let btn = hudBox.querySelector(".webconsole-close-button"); + EventUtils.sendMouseEvent({ type: "click" }, btn); + + openConsole(); + + hudId = HUDService.getHudIdByWindow(content); + hudRef = HUDService.hudReferences[hudId]; + hudBox = hudRef.HUDBox; + + id = hudBox.parentNode.childNodes[2].getAttribute("id"); + is(id, hudId, "below position is correct after another reopen"); + + is(hudRef.positionMenuitems.below.getAttribute("checked"), "true", + "position menu checkbox is below"); + + finishTest(); + }, false); + + let diffHeight = Math.abs(hudBox.clientHeight - boxHeight); + ok(diffHeight < 8, "hudBox height is correct"); + + let consolePanel = hudRef.consolePanel; + + is(consolePanel.getAttribute("width"), panelWidth, "panel width is correct"); + is(consolePanel.getAttribute("top"), 50, "panel top position is correct"); + is(consolePanel.getAttribute("left"), 51, "panel left position is correct"); + + let panelHeight = parseInt(consolePanel.getAttribute("height")); + let boxWidth = hudBox.clientWidth; + boxHeight = hudBox.clientHeight; + + hudRef.consolePanel.sizeTo(panelWidth - 15, panelHeight - 13); + + let popupBoxObject = consolePanel.popupBoxObject; + let screenX = popupBoxObject.screenX; + let screenY = popupBoxObject.screenY; + consolePanel.moveTo(screenX - 11, screenY - 13); + + isnot(hudBox.clientWidth, boxWidth, "hudBox width was updated"); + isnot(hudBox.clientHeight, boxHeight, "hudBox height was updated"); + + isnot(popupBoxObject.screenX, screenX, "panel screenX was updated"); + isnot(popupBoxObject.screenY, screenY, "panel screenY was updated"); + + panelWidth = consolePanel.clientWidth; + boxHeight = hudBox.clientHeight; + + executeSoon(function() { + hudRef.positionConsole("below"); + }); + }, false); + + let boxHeight = content.innerHeight * 0.5; + let panelWidth = content.innerWidth * 0.5; + + hudBox.style.height = boxHeight + "px"; + + boxHeight = hudBox.clientHeight; + + Services.prefs.setIntPref(WIDTH_PREF, panelWidth); + Services.prefs.setIntPref(TOP_PREF, 50); + Services.prefs.setIntPref(LEFT_PREF, 51); + + hudRef.positionConsole("window"); + id = hudBox.parentNode.getAttribute("id"); + is(id, "console_window_" + hudId, "window position is correct"); + is(Services.prefs.getCharPref(POSITION_PREF), "window", "pref is window"); +} + +function testMenuitems() { + let hudId = HUDService.getHudIdByWindow(content); + let hudRef = HUDService.hudReferences[hudId]; + let hudBox = hudRef.HUDBox; + + let positionConsole = hudRef.positionConsole; + is(typeof positionConsole, "function", "positionConsole() is available"); + + let param = null; + hudRef.positionConsole = function(aPosition) { + param = aPosition; + }; + + // Make sure the menuitems call the correct method. + + hudRef.positionMenuitems.above.doCommand(); + + is(param, "above", "menuitem for above positioning calls positionConsole() correctly"); + + hudRef.positionMenuitems.below.doCommand(); + + is(param, "below", "menuitem for below positioning calls positionConsole() correctly"); + + hudRef.positionMenuitems.window.doCommand(); + + is(param, "window", "menuitem for window positioning calls positionConsole() correctly"); + + hudRef.positionConsole = positionConsole; +} + diff --git a/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties b/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties index 34f6c504ad07..22adcba3b687 100644 --- a/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties +++ b/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties @@ -115,6 +115,30 @@ NetworkPanel.imageSizeDeltaDurationMS=%Sx%Spx, Δ%Sms NetworkPanel.responseBodyUnableToDisplay.content=Unable to display responses of type "%S" ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page. +# LOCALIZATION NOTE (webConsolePosition): The label shown for the menu which +# allows the user to toggle between the Web Console positioning types. +webConsolePosition=Position + +# LOCALIZATION NOTE (webConsolePositionTooltip): The tooltip shown when the user +# hovers the Position button in the Web Console toolbar. +webConsolePositionTooltip=Position the Web Console above or below the document + +# LOCALIZATION NOTE (webConsolePositionAbove): When this option is selected the +# Web Console interface is displayed above the web page. +webConsolePositionAbove=Above + +# LOCALIZATION NOTE (webConsolePositionBelow): When this option is selected the +# Web Console interface is displayed below the web page. +webConsolePositionBelow=Below + +# LOCALIZATION NOTE (webConsolePositionWindow): When this option is selected the +# Web Console interface is displayed in a floating panel. +webConsolePositionWindow=Window + +# LOCALIZATION NOTE (webConsoleOwnWindowTitle): The Web Console floating panel +# title. +webConsoleOwnWindowTitle=Web Console + # LOCALIZATION NOTE (stacktrace.anonymousFunction): # This string is used to display JavaScript functions that have no given name - # they are said to be anonymous. See stacktrace.outputMessage. diff --git a/toolkit/themes/gnomestripe/global/webConsole.css b/toolkit/themes/gnomestripe/global/webConsole.css index 0d4e9d9578f9..8ded9ef5cdba 100644 --- a/toolkit/themes/gnomestripe/global/webConsole.css +++ b/toolkit/themes/gnomestripe/global/webConsole.css @@ -301,3 +301,13 @@ font-size: 1em; } +.web-console-panel { + -moz-appearance: none; + background-color: white; +} + +.web-console-panel > .hud-box { + height: 100%; + width: 100%; + background-color: white; +} diff --git a/toolkit/themes/pinstripe/global/webConsole.css b/toolkit/themes/pinstripe/global/webConsole.css index 3840ddac3065..e60477864d8f 100644 --- a/toolkit/themes/pinstripe/global/webConsole.css +++ b/toolkit/themes/pinstripe/global/webConsole.css @@ -385,3 +385,13 @@ border-top: @scopeBarSeparatorBorder@; } +.web-console-panel { + -moz-appearance: none; + background-color: white; +} + +.web-console-panel > .hud-box { + height: 100%; + width: 100%; + background-color: white; +} diff --git a/toolkit/themes/winstripe/global/webConsole.css b/toolkit/themes/winstripe/global/webConsole.css index 17e975d207e8..48d80ff4f6ce 100644 --- a/toolkit/themes/winstripe/global/webConsole.css +++ b/toolkit/themes/winstripe/global/webConsole.css @@ -318,3 +318,13 @@ border-top: none; } +.web-console-panel { + -moz-appearance: none; + background-color: white; +} + +.web-console-panel > .hud-box { + height: 100%; + width: 100%; + background-color: white; +} From b76af19fa6ad11130e5aabefba3d29a08af284fc Mon Sep 17 00:00:00 2001 From: Mihai Sucan Date: Tue, 17 May 2011 17:39:59 +0300 Subject: [PATCH 003/145] Bug 642615 - If I paste over an auto-suggestion in web console, the suggested text remains; f=rcampbell r=rcampbell,dtownsend --- .../console/hudservice/HUDService.jsm | 213 +++++++++--------- .../hudservice/tests/browser/Makefile.in | 1 + ...wser_webconsole_bug_642615_autocomplete.js | 82 +++++++ 3 files changed, 184 insertions(+), 112 deletions(-) create mode 100644 toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642615_autocomplete.js diff --git a/toolkit/components/console/hudservice/HUDService.jsm b/toolkit/components/console/hudservice/HUDService.jsm index 60c26d496f43..5f304b64d976 100644 --- a/toolkit/components/console/hudservice/HUDService.jsm +++ b/toolkit/components/console/hudservice/HUDService.jsm @@ -4479,13 +4479,17 @@ JSTerm.prototype = { init: function JST_init() { this.createSandbox(); + this.inputNode = this.mixins.inputNode; - let eventHandlerKeyDown = this.keyDown(); - this.inputNode.addEventListener('keypress', eventHandlerKeyDown, false); - let eventHandlerInput = this.inputEventHandler(); - this.inputNode.addEventListener('input', eventHandlerInput, false); this.outputNode = this.mixins.outputNode; this.completeNode = this.mixins.completeNode; + + this.inputNode.addEventListener("keypress", + this.keyPress.bind(this), false); + this.inputNode.addEventListener("input", + this.inputEventHandler.bind(this), false); + this.inputNode.addEventListener("keyup", + this.inputEventHandler.bind(this), false); }, get codeInputString() @@ -4907,121 +4911,105 @@ JSTerm.prototype = { this.resizeInput(); }, - inputEventHandler: function JSTF_inputEventHandler() + /** + * The inputNode "input" and "keyup" event handler. + * + * @param nsIDOMEvent aEvent + */ + inputEventHandler: function JSTF_inputEventHandler(aEvent) { - var self = this; - function handleInputEvent(aEvent) { - self.resizeInput(); + if (this.lastInputValue != this.inputNode.value) { + this.resizeInput(); + this.complete(this.COMPLETE_HINT_ONLY); + this.lastInputValue = this.inputNode.value; } - return handleInputEvent; }, - keyDown: function JSTF_keyDown(aEvent) + /** + * The inputNode "keypress" event handler. + * + * @param nsIDOMEvent aEvent + */ + keyPress: function JSTF_keyPress(aEvent) { - var self = this; - function handleKeyDown(aEvent) { - // ctrl-a - var setTimeout = aEvent.target.ownerDocument.defaultView.setTimeout; - var target = aEvent.target; - var tmp; - - if (aEvent.ctrlKey) { - switch (aEvent.charCode) { - case 97: - // control-a - tmp = self.codeInputString; - setTimeout(function() { - self.setInputValue(tmp); - self.inputNode.setSelectionRange(0, 0); - }, 0); - break; - case 101: - // control-e - tmp = self.codeInputString; - self.setInputValue(""); - setTimeout(function(){ - self.setInputValue(tmp); - }, 0); - break; - default: - return; - } - return; - } - else if (aEvent.shiftKey && - aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RETURN) { - // shift return - // TODO: expand the inputNode height by one line - return; - } - else { - switch(aEvent.keyCode) { - case Ci.nsIDOMKeyEvent.DOM_VK_RETURN: - self.execute(); - aEvent.preventDefault(); - break; - - case Ci.nsIDOMKeyEvent.DOM_VK_UP: - // history previous - if (self.canCaretGoPrevious()) { - let updated = self.historyPeruse(HISTORY_BACK); - if (updated && aEvent.cancelable) { - aEvent.preventDefault(); - } - } - break; - - case Ci.nsIDOMKeyEvent.DOM_VK_DOWN: - // history next - if (self.canCaretGoNext()) { - let updated = self.historyPeruse(HISTORY_FORWARD); - if (updated && aEvent.cancelable) { - aEvent.preventDefault(); - } - } - break; - - case Ci.nsIDOMKeyEvent.DOM_VK_RIGHT: - // accept proposed completion - self.acceptProposedCompletion(); - break; - - case Ci.nsIDOMKeyEvent.DOM_VK_TAB: - // If there are more than one possible completion, pressing tab - // means taking the next completion, shift_tab means taking - // the previous completion. - var completionResult; - if (aEvent.shiftKey) { - completionResult = self.complete(self.COMPLETE_BACKWARD); - } - else { - completionResult = self.complete(self.COMPLETE_FORWARD); - } - if (completionResult) { - if (aEvent.cancelable) { - aEvent.preventDefault(); - } - aEvent.target.focus(); - } - break; - - default: - // Store the current inputNode value. If the value is the same - // after keyDown event was handled (after 0ms) then the user - // moved the cursor. If the value changed, then call the complete - // function to show completion on new value. - var value = self.inputNode.value; - setTimeout(function() { - if (self.inputNode.value !== value) { - self.complete(self.COMPLETE_HINT_ONLY); - } - }, 0); - break; - } - return; + if (aEvent.ctrlKey) { + switch (aEvent.charCode) { + case 97: + // control-a + this.inputNode.setSelectionRange(0, 0); + aEvent.preventDefault(); + break; + case 101: + // control-e + this.inputNode.setSelectionRange(this.inputNode.value.length, + this.inputNode.value.length); + aEvent.preventDefault(); + break; + default: + break; } + return; + } + else if (aEvent.shiftKey && + aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RETURN) { + // shift return + // TODO: expand the inputNode height by one line + return; + } + + switch(aEvent.keyCode) { + case Ci.nsIDOMKeyEvent.DOM_VK_RETURN: + this.execute(); + aEvent.preventDefault(); + break; + + case Ci.nsIDOMKeyEvent.DOM_VK_UP: + // history previous + if (this.canCaretGoPrevious()) { + let updated = this.historyPeruse(HISTORY_BACK); + if (updated && aEvent.cancelable) { + aEvent.preventDefault(); + } + } + break; + + case Ci.nsIDOMKeyEvent.DOM_VK_DOWN: + // history next + if (this.canCaretGoNext()) { + let updated = this.historyPeruse(HISTORY_FORWARD); + if (updated && aEvent.cancelable) { + aEvent.preventDefault(); + } + } + break; + + case Ci.nsIDOMKeyEvent.DOM_VK_RIGHT: + // accept proposed completion + this.acceptProposedCompletion(); + break; + + case Ci.nsIDOMKeyEvent.DOM_VK_TAB: + // If there are more than one possible completion, pressing tab + // means taking the next completion, shift_tab means taking + // the previous completion. + var completionResult; + if (aEvent.shiftKey) { + completionResult = this.complete(this.COMPLETE_BACKWARD); + } + else { + completionResult = this.complete(this.COMPLETE_FORWARD); + } + if (completionResult) { + if (aEvent.cancelable) { + aEvent.preventDefault(); + } + aEvent.target.focus(); + } + break; + + default: + break; } - return handleKeyDown; }, /** @@ -5159,6 +5147,7 @@ JSTerm.prototype = { let inputValue = inputNode.value; // If the inputNode has no value, then don't try to complete on it. if (!inputValue) { + this.lastCompletion = null; this.updateCompleteNode(""); return false; } diff --git a/toolkit/components/console/hudservice/tests/browser/Makefile.in b/toolkit/components/console/hudservice/tests/browser/Makefile.in index cd00a521bc9d..820b0403ad82 100644 --- a/toolkit/components/console/hudservice/tests/browser/Makefile.in +++ b/toolkit/components/console/hudservice/tests/browser/Makefile.in @@ -137,6 +137,7 @@ _BROWSER_TEST_FILES = \ browser_webconsole_bug_632275_getters_document_width.js \ browser_webconsole_bug_646025_console_file_location.js \ browser_webconsole_position_ui.js \ + browser_webconsole_bug_642615_autocomplete.js \ head.js \ $(NULL) diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642615_autocomplete.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642615_autocomplete.js new file mode 100644 index 000000000000..f625c80b3e2e --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642615_autocomplete.js @@ -0,0 +1,82 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const TEST_URI = "data:text/html,

test for bug 642615"; + +XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper", + "@mozilla.org/widget/clipboardhelper;1", + "nsIClipboardHelper"); + +function tabLoad(aEvent) { + browser.removeEventListener(aEvent.type, arguments.callee, true); + + openConsole(); + + let hudId = HUDService.getHudIdByWindow(content); + let HUD = HUDService.hudReferences[hudId]; + let jsterm = HUD.jsterm; + let stringToCopy = "foobazbarBug642615"; + + jsterm.clearOutput(); + + ok(!jsterm.completionValue, "no completionValue"); + + jsterm.setInputValue("doc"); + + // wait for key "u" + jsterm.inputNode.addEventListener("keyup", function() { + jsterm.inputNode.removeEventListener("keyup", arguments.callee, false); + + let completionValue = jsterm.completionValue; + ok(completionValue, "we have a completionValue"); + + // wait for paste + jsterm.inputNode.addEventListener("input", function() { + jsterm.inputNode.removeEventListener("input", arguments.callee, false); + + ok(!jsterm.completionValue, "no completionValue after clipboard paste"); + + // wait for undo + jsterm.inputNode.addEventListener("input", function() { + jsterm.inputNode.removeEventListener("input", arguments.callee, false); + + is(jsterm.completionValue, completionValue, + "same completionValue after undo"); + + // wait for paste (via keyboard event) + jsterm.inputNode.addEventListener("keyup", function() { + jsterm.inputNode.removeEventListener("keyup", arguments.callee, false); + + ok(!jsterm.completionValue, + "no completionValue after clipboard paste (via keyboard event)"); + + executeSoon(finishTest); + }, false); + + EventUtils.synthesizeKey("v", {accelKey: true}); + }, false); + + goDoCommand("cmd_undo"); + }, false); + + // Arguments: expected, setup, success, failure. + waitForClipboard( + stringToCopy, + function() { + clipboardHelper.copyString(stringToCopy); + }, + function() { + updateEditUIVisibility(); + goDoCommand("cmd_paste"); + }, + finish); + }, false); + + EventUtils.synthesizeKey("u", {}); +} + +function test() { + addTab(TEST_URI); + browser.addEventListener("load", tabLoad, true); +} From 3cde414dbfa88f5314721bcaa59d486ac575178e Mon Sep 17 00:00:00 2001 From: Mihai Sucan Date: Tue, 17 May 2011 18:07:33 +0300 Subject: [PATCH 004/145] Bug 585991 - Show a popup listing possible completions; r=rcampbell,dtownsend sr=neil --- .../console/hudservice/AutocompletePopup.jsm | 395 ++++++++++++++++++ .../console/hudservice/HUDService.jsm | 296 +++++++------ .../components/console/hudservice/Makefile.in | 1 + .../hudservice/tests/browser/Makefile.in | 2 + ...webconsole_bug_585991_autocomplete_keys.js | 204 +++++++++ ...ebconsole_bug_585991_autocomplete_popup.js | 129 ++++++ ...wser_webconsole_bug_642615_autocomplete.js | 16 +- .../chrome/global/headsUpDisplay.properties | 4 + 8 files changed, 919 insertions(+), 128 deletions(-) create mode 100644 toolkit/components/console/hudservice/AutocompletePopup.jsm create mode 100644 toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585991_autocomplete_keys.js create mode 100644 toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585991_autocomplete_popup.js diff --git a/toolkit/components/console/hudservice/AutocompletePopup.jsm b/toolkit/components/console/hudservice/AutocompletePopup.jsm new file mode 100644 index 000000000000..7267c82c0fca --- /dev/null +++ b/toolkit/components/console/hudservice/AutocompletePopup.jsm @@ -0,0 +1,395 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Autocomplete Popup. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mihai Sucan (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cu = Components.utils; + +// The XUL and XHTML namespace. +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; +const XHTML_NS = "http://www.w3.org/1999/xhtml"; + +const HUD_STRINGS_URI = "chrome://global/locale/headsUpDisplay.properties"; + + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "stringBundle", function () { + return Services.strings.createBundle(HUD_STRINGS_URI); +}); + + +var EXPORTED_SYMBOLS = ["AutocompletePopup"]; + +/** + * Autocomplete popup UI implementation. + * + * @constructor + * @param nsIDOMDocument aDocument + * The document you want the popup attached to. + */ +function AutocompletePopup(aDocument) +{ + this._document = aDocument; + + // Reuse the existing popup elements. + this._panel = this._document.getElementById("webConsole_autocompletePopup"); + if (!this._panel) { + this._panel = this._document.createElementNS(XUL_NS, "panel"); + this._panel.setAttribute("id", "webConsole_autocompletePopup"); + this._panel.setAttribute("label", + stringBundle.GetStringFromName("Autocomplete.label")); + this._panel.setAttribute("noautofocus", "true"); + this._panel.setAttribute("ignorekeys", "true"); + + let mainPopupSet = this._document.getElementById("mainPopupSet"); + if (mainPopupSet) { + mainPopupSet.appendChild(this._panel); + } + else { + this._document.documentElement.appendChild(this._panel); + } + + this._list = this._document.createElementNS(XUL_NS, "richlistbox"); + this._list.flex = 1; + this._panel.appendChild(this._list); + + // Open and hide the panel, so we initialize the API of the richlistbox. + this._panel.width = 1; + this._panel.height = 1; + this._panel.openPopup(null, "overlap", 0, 0, false, false); + this._panel.hidePopup(); + this._panel.width = ""; + this._panel.height = ""; + } + else { + this._list = this._panel.firstChild; + } +} + +AutocompletePopup.prototype = { + _document: null, + _panel: null, + _list: null, + + /** + * Open the autocomplete popup panel. + * + * @param nsIDOMNode aAnchor + * Optional node to anchor the panel to. + */ + openPopup: function AP_openPopup(aAnchor) + { + this._panel.openPopup(aAnchor, "after_start", 0, 0, false, false); + + if (this.onSelect) { + this._list.addEventListener("select", this.onSelect, false); + } + + if (this.onClick) { + this._list.addEventListener("click", this.onClick, false); + } + + this._updateSize(); + }, + + /** + * Hide the autocomplete popup panel. + */ + hidePopup: function AP_hidePopup() + { + this._panel.hidePopup(); + + if (this.onSelect) { + this._list.removeEventListener("select", this.onSelect, false); + } + + if (this.onClick) { + this._list.removeEventListener("click", this.onClick, false); + } + }, + + /** + * Check if the autocomplete popup is open. + */ + get isOpen() { + return this._panel.state == "open"; + }, + + /** + * Destroy the object instance. Please note that the panel DOM elements remain + * in the DOM, because they might still be in use by other instances of the + * same code. It is the responsability of the client code to perform DOM + * cleanup. + */ + destroy: function AP_destroy() + { + if (this.isOpen) { + this.hidePopup(); + } + this.clearItems(); + + this._document = null; + this._list = null; + this._panel = null; + }, + + /** + * Get the autocomplete items array. + * + * @return array + * The array of autocomplete items. + */ + getItems: function AP_getItems() + { + let items = []; + + Array.forEach(this._list.childNodes, function(aItem) { + items.push(aItem._autocompleteItem); + }); + + return items; + }, + + /** + * Set the autocomplete items list, in one go. + * + * @param array aItems + * The list of items you want displayed in the popup list. + */ + setItems: function AP_setItems(aItems) + { + this.clearItems(); + aItems.forEach(this.appendItem, this); + + // Make sure that the new content is properly fitted by the XUL richlistbox. + if (this.isOpen) { + // We need the timeout to allow the content to reflow. Attempting to + // update the richlistbox size too early does not work. + this._document.defaultView.setTimeout(this._updateSize.bind(this), 1); + } + }, + + /** + * Update the panel size to fit the content. + * + * @private + */ + _updateSize: function AP__updateSize() + { + this._list.width = this._panel.clientWidth + + this._scrollbarWidth; + }, + + /** + * Clear all the items from the autocomplete list. + */ + clearItems: function AP_clearItems() + { + while (this._list.hasChildNodes()) { + this._list.removeChild(this._list.firstChild); + } + this._list.width = ""; + }, + + /** + * Getter for the index of the selected item. + * + * @type number + */ + get selectedIndex() { + return this._list.selectedIndex; + }, + + /** + * Setter for the selected index. + * + * @param number aIndex + * The number (index) of the item you want to select in the list. + */ + set selectedIndex(aIndex) { + this._list.selectedIndex = aIndex; + this._list.ensureIndexIsVisible(this._list.selectedIndex); + }, + + /** + * Getter for the selected item. + * @type object + */ + get selectedItem() { + return this._list.selectedItem ? + this._list.selectedItem._autocompleteItem : null; + }, + + /** + * Setter for the selected item. + * + * @param object aItem + * The object you want selected in the list. + */ + set selectedItem(aItem) { + this._list.selectedItem = this._findListItem(aItem); + this._list.ensureIndexIsVisible(this._list.selectedIndex); + }, + + /** + * Append an item into the autocomplete list. + * + * @param object aItem + * The item you want appended to the list. The object must have a + * "label" property which is used as the displayed value. + */ + appendItem: function AP_appendItem(aItem) + { + let description = this._document.createElementNS(XUL_NS, "description"); + description.textContent = aItem.label; + + let listItem = this._document.createElementNS(XUL_NS, "richlistitem"); + listItem.appendChild(description); + listItem._autocompleteItem = aItem; + + this._list.appendChild(listItem); + }, + + /** + * Find the richlistitem element that belongs to an item. + * + * @private + * + * @param object aItem + * The object you want found in the list. + * + * @return nsIDOMNode|null + * The nsIDOMNode that belongs to the given item object. This node is + * the richlistitem element. + */ + _findListItem: function AP__findListItem(aItem) + { + for (let i = 0; i < this._list.childNodes.length; i++) { + let child = this._list.childNodes[i]; + if (child._autocompleteItem == aItem) { + return child; + } + } + return null; + }, + + /** + * Remove an item from the popup list. + * + * @param object aItem + * The item you want removed. + */ + removeItem: function AP_removeItem(aItem) + { + let item = this._findListItem(aItem); + if (!item) { + throw new Error("Item not found!"); + } + this._list.removeChild(item); + }, + + /** + * Getter for the number of items in the popup. + * @type number + */ + get itemCount() { + return this._list.childNodes.length; + }, + + /** + * Select the next item in the list. + * + * @return object + * The newly selected item object. + */ + selectNextItem: function AP_selectNextItem() + { + if (this.selectedIndex < (this.itemCount - 1)) { + this.selectedIndex++; + } + else { + this.selectedIndex = -1; + } + + return this.selectedItem; + }, + + /** + * Select the previous item in the list. + * + * @return object + * The newly selected item object. + */ + selectPreviousItem: function AP_selectPreviousItem() + { + if (this.selectedIndex > -1) { + this.selectedIndex--; + } + else { + this.selectedIndex = this.itemCount - 1; + } + + return this.selectedItem; + }, + + /** + * Determine the scrollbar width in the current document. + * + * @private + */ + get _scrollbarWidth() + { + if (this.__scrollbarWidth) { + return this.__scrollbarWidth; + } + + let hbox = this._document.createElementNS(XUL_NS, "hbox"); + hbox.setAttribute("style", "height: 0%; overflow: hidden"); + + let scrollbar = this._document.createElementNS(XUL_NS, "scrollbar"); + scrollbar.setAttribute("orient", "vertical"); + hbox.appendChild(scrollbar); + + this._document.documentElement.appendChild(hbox); + this.__scrollbarWidth = scrollbar.clientWidth; + this._document.documentElement.removeChild(hbox); + + return this.__scrollbarWidth; + }, +}; + diff --git a/toolkit/components/console/hudservice/HUDService.jsm b/toolkit/components/console/hudservice/HUDService.jsm index 5f304b64d976..e1cac1e0fd84 100644 --- a/toolkit/components/console/hudservice/HUDService.jsm +++ b/toolkit/components/console/hudservice/HUDService.jsm @@ -86,6 +86,17 @@ XPCOMUtils.defineLazyGetter(this, "PropertyPanel", function () { return obj.PropertyPanel; }); +XPCOMUtils.defineLazyGetter(this, "AutocompletePopup", function () { + var obj = {}; + try { + Cu.import("resource://gre/modules/AutocompletePopup.jsm", obj); + } + catch (err) { + Cu.reportError(err); + } + return obj.AutocompletePopup; +}); + XPCOMUtils.defineLazyGetter(this, "namesAndValuesOf", function () { var obj = {}; Cu.import("resource:///modules/PropertyPanel.jsm", obj); @@ -524,8 +535,10 @@ ResponseListener.prototype = function createElement(aDocument, aTag, aAttributes) { let node = aDocument.createElement(aTag); - for (var attr in aAttributes) { - node.setAttribute(attr, aAttributes[attr]); + if (aAttributes) { + for (let attr in aAttributes) { + node.setAttribute(attr, aAttributes[attr]); + } } return node; } @@ -1763,6 +1776,8 @@ HUD_SERVICE.prototype = ownerDoc = outputNode.ownerDocument; ownerDoc.getElementById(id).parentNode.removeChild(outputNode); + this.hudReferences[id].jsterm.autocompletePopup.destroy(); + this.hudReferences[id].consoleWindowUnregisterOnHide = false; // remove the HeadsUpDisplay object from memory @@ -1791,6 +1806,12 @@ HUD_SERVICE.prototype = Services.obs.notifyObservers(id, "web-console-destroyed", null); if (Object.keys(this.hudReferences).length == 0) { + let autocompletePopup = outputNode.ownerDocument. + getElementById("webConsole_autocompletePopup"); + if (autocompletePopup) { + autocompletePopup.parentNode.removeChild(autocompletePopup); + } + this.suspend(); } }, @@ -4158,24 +4179,23 @@ function JSPropertyProvider(aScope, aInputValue) let properties = completionPart.split('.'); let matchProp; if (properties.length > 1) { - matchProp = properties[properties.length - 1].trimLeft(); - properties.pop(); - for each (var prop in properties) { - prop = prop.trim(); + matchProp = properties.pop().trimLeft(); + for (let i = 0; i < properties.length; i++) { + let prop = properties[i].trim(); - // If obj is undefined or null, then there is no change to run - // completion on it. Exit here. - if (typeof obj === "undefined" || obj === null) { - return null; - } - - // Check if prop is a getter function on obj. Functions can change other - // stuff so we can't execute them to get the next object. Stop here. - if (obj.__lookupGetter__(prop)) { - return null; - } - obj = obj[prop]; + // If obj is undefined or null, then there is no change to run completion + // on it. Exit here. + if (typeof obj === "undefined" || obj === null) { + return null; } + + // Check if prop is a getter function on obj. Functions can change other + // stuff so we can't execute them to get the next object. Stop here. + if (obj.__lookupGetter__(prop)) { + return null; + } + obj = obj[prop]; + } } else { matchProp = properties[0].trimLeft(); @@ -4193,17 +4213,15 @@ function JSPropertyProvider(aScope, aInputValue) } let matches = []; - for (var prop in obj) { - matches.push(prop); + for (let prop in obj) { + if (prop.indexOf(matchProp) == 0) { + matches.push(prop); + } } - matches = matches.filter(function(item) { - return item.indexOf(matchProp) == 0; - }).sort(); - return { matchProp: matchProp, - matches: matches + matches: matches.sort(), }; } @@ -4465,6 +4483,9 @@ function JSTerm(aContext, aParentNode, aMixin, aConsole) this.historyIndex = 0; this.historyPlaceHolder = 0; // this.history.length; this.log = LogFactory("*** JSTerm:"); + this.autocompletePopup = new AutocompletePopup(aParentNode.ownerDocument); + this.autocompletePopup.onSelect = this.onAutocompleteSelect.bind(this); + this.autocompletePopup.onClick = this.acceptProposedCompletion.bind(this); this.init(); } @@ -4603,6 +4624,7 @@ JSTerm.prototype = { this.historyIndex++; this.historyPlaceHolder = this.history.length; this.setInputValue(""); + this.clearCompletion(); }, /** @@ -4957,53 +4979,56 @@ JSTerm.prototype = { return; } + let inputUpdated = false; + switch(aEvent.keyCode) { + case Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE: + if (this.autocompletePopup.isOpen) { + this.clearCompletion(); + aEvent.preventDefault(); + } + break; + case Ci.nsIDOMKeyEvent.DOM_VK_RETURN: - this.execute(); + if (this.autocompletePopup.isOpen) { + this.acceptProposedCompletion(); + } + else { + this.execute(); + } aEvent.preventDefault(); break; case Ci.nsIDOMKeyEvent.DOM_VK_UP: - // history previous - if (this.canCaretGoPrevious()) { - let updated = this.historyPeruse(HISTORY_BACK); - if (updated && aEvent.cancelable) { - aEvent.preventDefault(); - } + if (this.autocompletePopup.isOpen) { + inputUpdated = this.complete(this.COMPLETE_BACKWARD); + } + else if (this.canCaretGoPrevious()) { + inputUpdated = this.historyPeruse(HISTORY_BACK); + } + if (inputUpdated) { + aEvent.preventDefault(); } break; case Ci.nsIDOMKeyEvent.DOM_VK_DOWN: - // history next - if (this.canCaretGoNext()) { - let updated = this.historyPeruse(HISTORY_FORWARD); - if (updated && aEvent.cancelable) { - aEvent.preventDefault(); - } + if (this.autocompletePopup.isOpen) { + inputUpdated = this.complete(this.COMPLETE_FORWARD); + } + else if (this.canCaretGoNext()) { + inputUpdated = this.historyPeruse(HISTORY_FORWARD); + } + if (inputUpdated) { + aEvent.preventDefault(); } - break; - - case Ci.nsIDOMKeyEvent.DOM_VK_RIGHT: - // accept proposed completion - this.acceptProposedCompletion(); break; case Ci.nsIDOMKeyEvent.DOM_VK_TAB: - // If there are more than one possible completion, pressing tab - // means taking the next completion, shift_tab means taking - // the previous completion. - var completionResult; - if (aEvent.shiftKey) { - completionResult = this.complete(this.COMPLETE_BACKWARD); - } - else { - completionResult = this.complete(this.COMPLETE_FORWARD); - } - if (completionResult) { - if (aEvent.cancelable) { - aEvent.preventDefault(); - } - aEvent.target.focus(); + // Generate a completion and accept the first proposed value. + if (this.complete(this.COMPLETE_HINT_ONLY) && + this.lastCompletion && + this.acceptProposedCompletion()) { + aEvent.preventDefault(); } break; @@ -5147,96 +5172,127 @@ JSTerm.prototype = { let inputValue = inputNode.value; // If the inputNode has no value, then don't try to complete on it. if (!inputValue) { - this.lastCompletion = null; - this.updateCompleteNode(""); + this.clearCompletion(); return false; } // Only complete if the selection is empty and at the end of the input. if (inputNode.selectionStart == inputNode.selectionEnd && inputNode.selectionEnd != inputValue.length) { - // TODO: shouldnt we do this in the other 'bail' cases? - this.lastCompletion = null; - this.updateCompleteNode(""); + this.clearCompletion(); return false; } - let matches; - let matchIndexToUse; - let matchOffset; + let popup = this.autocompletePopup; - // If there is a saved completion from last time and the used value for - // completion stayed the same, then use the stored completion. - if (this.lastCompletion && inputValue == this.lastCompletion.value) { - matches = this.lastCompletion.matches; - matchOffset = this.lastCompletion.matchOffset; - if (type === this.COMPLETE_BACKWARD) { - this.lastCompletion.index --; - } - else if (type === this.COMPLETE_FORWARD) { - this.lastCompletion.index ++; - } - matchIndexToUse = this.lastCompletion.index; - } - else { - // Look up possible completion values. - let completion = this.propertyProvider(this.sandbox.window, inputValue); - if (!completion) { - this.updateCompleteNode(""); + if (!this.lastCompletion || this.lastCompletion.value != inputValue) { + let properties = this.propertyProvider(this.sandbox.window, inputValue); + if (!properties || !properties.matches.length) { + this.clearCompletion(); return false; } - matches = completion.matches; - matchIndexToUse = 0; - matchOffset = completion.matchProp.length; - // Store this match; - this.lastCompletion = { - index: 0, - value: inputValue, - matches: matches, - matchOffset: matchOffset - }; - } - if (type != this.COMPLETE_HINT_ONLY && matches.length == 1) { - this.acceptProposedCompletion(); - return true; - } - else if (matches.length != 0) { - // Ensure that the matchIndexToUse is always a valid array index. - if (matchIndexToUse < 0) { - matchIndexToUse = matches.length + (matchIndexToUse % matches.length); - if (matchIndexToUse == matches.length) { - matchIndexToUse = 0; + let items = properties.matches.map(function(aMatch) { + return {label: aMatch}; + }); + popup.setItems(items); + this.lastCompletion = {value: inputValue, + matchProp: properties.matchProp}; + + if (items.length > 1 && !popup.isOpen) { + popup.openPopup(this.inputNode); + } + else if (items.length < 2 && popup.isOpen) { + popup.hidePopup(); + } + + if (items.length > 0) { + popup.selectedIndex = 0; + if (items.length == 1) { + // onSelect is not fired when the popup is not open. + this.onAutocompleteSelect(); } } - else { - matchIndexToUse = matchIndexToUse % matches.length; - } + } - let completionStr = matches[matchIndexToUse].substring(matchOffset); - this.updateCompleteNode(completionStr); - return completionStr ? true : false; + let accepted = false; + + if (type != this.COMPLETE_HINT_ONLY && popup.itemCount == 1) { + this.acceptProposedCompletion(); + accepted = true; + } + else if (type == this.COMPLETE_BACKWARD) { + this.autocompletePopup.selectPreviousItem(); + } + else if (type == this.COMPLETE_FORWARD) { + this.autocompletePopup.selectNextItem(); + } + + return accepted || popup.itemCount > 0; + }, + + onAutocompleteSelect: function JSTF_onAutocompleteSelect() + { + let currentItem = this.autocompletePopup.selectedItem; + if (currentItem && this.lastCompletion) { + let suffix = currentItem.label.substring(this.lastCompletion. + matchProp.length); + this.updateCompleteNode(suffix); } else { this.updateCompleteNode(""); } - - return false; }, + /** + * Clear the current completion information and close the autocomplete popup, + * if needed. + */ + clearCompletion: function JSTF_clearCompletion() + { + this.autocompletePopup.clearItems(); + this.lastCompletion = null; + this.updateCompleteNode(""); + if (this.autocompletePopup.isOpen) { + this.autocompletePopup.hidePopup(); + } + }, + + /** + * Accept the proposed input completion. + * + * @return boolean + * True if there was a selected completion item and the input value + * was updated, false otherwise. + */ acceptProposedCompletion: function JSTF_acceptProposedCompletion() { - this.setInputValue(this.inputNode.value + this.completionValue); - this.updateCompleteNode(""); + let updated = false; + + let currentItem = this.autocompletePopup.selectedItem; + if (currentItem && this.lastCompletion) { + let suffix = currentItem.label.substring(this.lastCompletion. + matchProp.length); + this.setInputValue(this.inputNode.value + suffix); + updated = true; + } + + this.clearCompletion(); + + return updated; }, - updateCompleteNode: function JSTF_updateCompleteNode(suffix) + /** + * Update the node that displays the currently selected autocomplete proposal. + * + * @param string aSuffix + * The proposed suffix for the inputNode value. + */ + updateCompleteNode: function JSTF_updateCompleteNode(aSuffix) { - this.completionValue = suffix; - // completion prefix = input, with non-control chars replaced by spaces - let prefix = this.inputNode.value.replace(/[\S]/g, " "); - this.completeNode.value = prefix + this.completionValue; + let prefix = aSuffix ? this.inputNode.value.replace(/[\S]/g, " ") : ""; + this.completeNode.value = prefix + aSuffix; }, }; diff --git a/toolkit/components/console/hudservice/Makefile.in b/toolkit/components/console/hudservice/Makefile.in index 821c9e01da54..46229d128d89 100644 --- a/toolkit/components/console/hudservice/Makefile.in +++ b/toolkit/components/console/hudservice/Makefile.in @@ -46,6 +46,7 @@ include $(DEPTH)/config/autoconf.mk EXTRA_JS_MODULES = HUDService.jsm \ PropertyPanel.jsm \ NetworkHelper.jsm \ + AutocompletePopup.jsm \ $(NULL) ifdef ENABLE_TESTS diff --git a/toolkit/components/console/hudservice/tests/browser/Makefile.in b/toolkit/components/console/hudservice/tests/browser/Makefile.in index 820b0403ad82..b72b3799fd71 100644 --- a/toolkit/components/console/hudservice/tests/browser/Makefile.in +++ b/toolkit/components/console/hudservice/tests/browser/Makefile.in @@ -138,6 +138,8 @@ _BROWSER_TEST_FILES = \ browser_webconsole_bug_646025_console_file_location.js \ browser_webconsole_position_ui.js \ browser_webconsole_bug_642615_autocomplete.js \ + browser_webconsole_bug_585991_autocomplete_popup.js \ + browser_webconsole_bug_585991_autocomplete_keys.js \ head.js \ $(NULL) diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585991_autocomplete_keys.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585991_autocomplete_keys.js new file mode 100644 index 000000000000..acdedc3892c9 --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585991_autocomplete_keys.js @@ -0,0 +1,204 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Web Console test suite. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mihai Sucan + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const TEST_URI = "data:text/html,

bug 585991 - autocomplete popup keyboard usage test"; + +function test() { + addTab(TEST_URI); + browser.addEventListener("load", tabLoaded, true); +} + +function tabLoaded() { + browser.removeEventListener("load", tabLoaded, true); + openConsole(); + + content.wrappedJSObject.foobarBug585991 = { + "item0": "value0", + "item1": "value1", + "item2": "value2", + "item3": "value3", + }; + + let hudId = HUDService.getHudIdByWindow(content); + HUD = HUDService.hudReferences[hudId]; + let jsterm = HUD.jsterm; + let popup = jsterm.autocompletePopup; + let completeNode = jsterm.completeNode; + + ok(!popup.isOpen, "popup is not open"); + + popup._panel.addEventListener("popupshown", function() { + popup._panel.removeEventListener("popupshown", arguments.callee, false); + + ok(popup.isOpen, "popup is open"); + + is(popup.itemCount, 4, "popup.itemCount is correct"); + + let sameItems = popup.getItems(); + is(sameItems.every(function(aItem, aIndex) { + return aItem.label == "item" + aIndex; + }), true, "getItems returns back the same items"); + + let prefix = jsterm.inputNode.value.replace(/[\S]/g, " "); + + is(popup.selectedIndex, 0, "index 0 is selected"); + is(popup.selectedItem.label, "item0", "item0 is selected"); + is(completeNode.value, prefix + "item0", "completeNode.value holds item0"); + + EventUtils.synthesizeKey("VK_DOWN", {}); + + is(popup.selectedIndex, 1, "index 1 is selected"); + is(popup.selectedItem.label, "item1", "item1 is selected"); + is(completeNode.value, prefix + "item1", "completeNode.value holds item1"); + + EventUtils.synthesizeKey("VK_UP", {}); + + is(popup.selectedIndex, 0, "index 0 is selected"); + is(popup.selectedItem.label, "item0", "item0 is selected"); + is(completeNode.value, prefix + "item0", "completeNode.value holds item0"); + + popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false); + + EventUtils.synthesizeKey("VK_TAB", {}); + }, false); + + jsterm.setInputValue("window.foobarBug585991"); + EventUtils.synthesizeKey(".", {}); +} + +function autocompletePopupHidden() +{ + let jsterm = HUD.jsterm; + let popup = jsterm.autocompletePopup; + let completeNode = jsterm.completeNode; + let inputNode = jsterm.inputNode; + + popup._panel.removeEventListener("popuphidden", arguments.callee, false); + + ok(!popup.isOpen, "popup is not open"); + + is(inputNode.value, "window.foobarBug585991.item0", + "completion was successful after VK_TAB"); + + ok(!completeNode.value, "completeNode is empty"); + + popup._panel.addEventListener("popupshown", function() { + popup._panel.removeEventListener("popupshown", arguments.callee, false); + + ok(popup.isOpen, "popup is open"); + + is(popup.itemCount, 4, "popup.itemCount is correct"); + + let prefix = jsterm.inputNode.value.replace(/[\S]/g, " "); + + is(popup.selectedIndex, 0, "index 0 is selected"); + is(popup.selectedItem.label, "item0", "item0 is selected"); + is(completeNode.value, prefix + "item0", "completeNode.value holds item0"); + + popup._panel.addEventListener("popuphidden", function() { + popup._panel.removeEventListener("popuphidden", arguments.callee, false); + + ok(!popup.isOpen, "popup is not open after VK_ESCAPE"); + + is(inputNode.value, "window.foobarBug585991.", + "completion was cancelled"); + + ok(!completeNode.value, "completeNode is empty"); + + executeSoon(testReturnKey); + }, false); + + executeSoon(function() { + EventUtils.synthesizeKey("VK_ESCAPE", {}); + }); + }, false); + + executeSoon(function() { + jsterm.setInputValue("window.foobarBug585991"); + EventUtils.synthesizeKey(".", {}); + }); +} + +function testReturnKey() +{ + let jsterm = HUD.jsterm; + let popup = jsterm.autocompletePopup; + let completeNode = jsterm.completeNode; + let inputNode = jsterm.inputNode; + + popup._panel.addEventListener("popupshown", function() { + popup._panel.removeEventListener("popupshown", arguments.callee, false); + + ok(popup.isOpen, "popup is open"); + + is(popup.itemCount, 4, "popup.itemCount is correct"); + + let prefix = jsterm.inputNode.value.replace(/[\S]/g, " "); + + is(popup.selectedIndex, 0, "index 0 is selected"); + is(popup.selectedItem.label, "item0", "item0 is selected"); + is(completeNode.value, prefix + "item0", "completeNode.value holds item0"); + + EventUtils.synthesizeKey("VK_DOWN", {}); + + is(popup.selectedIndex, 1, "index 1 is selected"); + is(popup.selectedItem.label, "item1", "item1 is selected"); + is(completeNode.value, prefix + "item1", "completeNode.value holds item1"); + + popup._panel.addEventListener("popuphidden", function() { + popup._panel.removeEventListener("popuphidden", arguments.callee, false); + + ok(!popup.isOpen, "popup is not open after VK_RETURN"); + + is(inputNode.value, "window.foobarBug585991.item1", + "completion was successful after VK_RETURN"); + + ok(!completeNode.value, "completeNode is empty"); + + executeSoon(finishTest); + }, false); + + EventUtils.synthesizeKey("VK_RETURN", {}); + }, false); + + executeSoon(function() { + jsterm.setInputValue("window.foobarBug58599"); + EventUtils.synthesizeKey("1", {}); + EventUtils.synthesizeKey(".", {}); + }); +} diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585991_autocomplete_popup.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585991_autocomplete_popup.js new file mode 100644 index 000000000000..d89af7ee9912 --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585991_autocomplete_popup.js @@ -0,0 +1,129 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Web Console test suite. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mihai Sucan + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const TEST_URI = "data:text/html,

bug 585991 - autocomplete popup test"; + +function test() { + addTab(TEST_URI); + browser.addEventListener("load", tabLoaded, true); +} + +function tabLoaded() { + browser.removeEventListener("load", tabLoaded, true); + openConsole(); + + let items = [ + {label: "item0", value: "value0"}, + {label: "item1", value: "value1"}, + {label: "item2", value: "value2"}, + ]; + + let hudId = HUDService.getHudIdByWindow(content); + let HUD = HUDService.hudReferences[hudId]; + let popup = HUD.jsterm.autocompletePopup; + + ok(!popup.isOpen, "popup is not open"); + + popup._panel.addEventListener("popupshown", function() { + popup._panel.removeEventListener("popupshown", arguments.callee, false); + + ok(popup.isOpen, "popup is open"); + + is(popup.itemCount, 0, "no items"); + + popup.setItems(items); + + is(popup.itemCount, items.length, "items added"); + + let sameItems = popup.getItems(); + is(sameItems.every(function(aItem, aIndex) { + return aItem === items[aIndex]; + }), true, "getItems returns back the same items"); + + is(popup.selectedIndex, -1, "no index is selected"); + ok(!popup.selectedItem, "no item is selected"); + + popup.selectedIndex = 1; + + is(popup.selectedIndex, 1, "index 1 is selected"); + is(popup.selectedItem, items[1], "item1 is selected"); + + popup.selectedItem = items[2]; + + is(popup.selectedIndex, 2, "index 2 is selected"); + is(popup.selectedItem, items[2], "item2 is selected"); + + is(popup.selectPreviousItem(), items[1], "selectPreviousItem() works"); + + is(popup.selectedIndex, 1, "index 1 is selected"); + is(popup.selectedItem, items[1], "item1 is selected"); + + is(popup.selectNextItem(), items[2], "selectPreviousItem() works"); + + is(popup.selectedIndex, 2, "index 2 is selected"); + is(popup.selectedItem, items[2], "item2 is selected"); + + ok(!popup.selectNextItem(), "selectPreviousItem() works"); + + is(popup.selectedIndex, -1, "no index is selected"); + ok(!popup.selectedItem, "no item is selected"); + + items.push({label: "label3", value: "value3"}); + popup.appendItem(items[3]); + + is(popup.itemCount, items.length, "item3 appended"); + + popup.selectedIndex = 3; + is(popup.selectedItem, items[3], "item3 is selected"); + + popup.removeItem(items[2]); + + is(popup.selectedIndex, 2, "index2 is selected"); + is(popup.selectedItem, items[3], "item3 is still selected"); + is(popup.itemCount, items.length - 1, "item2 removed"); + + popup.clearItems(); + is(popup.itemCount, 0, "items cleared"); + + popup.hidePopup(); + finishTest(); + }, false); + + popup.openPopup(); +} + diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642615_autocomplete.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642615_autocomplete.js index f625c80b3e2e..89371c209058 100644 --- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642615_autocomplete.js +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642615_autocomplete.js @@ -20,7 +20,7 @@ function tabLoad(aEvent) { jsterm.clearOutput(); - ok(!jsterm.completionValue, "no completionValue"); + ok(!jsterm.completeNode.value, "no completeNode.value"); jsterm.setInputValue("doc"); @@ -28,28 +28,28 @@ function tabLoad(aEvent) { jsterm.inputNode.addEventListener("keyup", function() { jsterm.inputNode.removeEventListener("keyup", arguments.callee, false); - let completionValue = jsterm.completionValue; - ok(completionValue, "we have a completionValue"); + let completionValue = jsterm.completeNode.value; + ok(completionValue, "we have a completeNode.value"); // wait for paste jsterm.inputNode.addEventListener("input", function() { jsterm.inputNode.removeEventListener("input", arguments.callee, false); - ok(!jsterm.completionValue, "no completionValue after clipboard paste"); + ok(!jsterm.completeNode.value, "no completeNode.value after clipboard paste"); // wait for undo jsterm.inputNode.addEventListener("input", function() { jsterm.inputNode.removeEventListener("input", arguments.callee, false); - is(jsterm.completionValue, completionValue, - "same completionValue after undo"); + is(jsterm.completeNode.value, completionValue, + "same completeNode.value after undo"); // wait for paste (via keyboard event) jsterm.inputNode.addEventListener("keyup", function() { jsterm.inputNode.removeEventListener("keyup", arguments.callee, false); - ok(!jsterm.completionValue, - "no completionValue after clipboard paste (via keyboard event)"); + ok(!jsterm.completeNode.value, + "no completeNode.value after clipboard paste (via keyboard event)"); executeSoon(finishTest); }, false); diff --git a/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties b/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties index 22adcba3b687..fd7e1557ab00 100644 --- a/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties +++ b/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties @@ -139,6 +139,10 @@ webConsolePositionWindow=Window # title. webConsoleOwnWindowTitle=Web Console +# LOCALIZATION NOTE (Autocomplete.label): +# The autocomplete popup panel label/title. +Autocomplete.label=Autocomplete popup + # LOCALIZATION NOTE (stacktrace.anonymousFunction): # This string is used to display JavaScript functions that have no given name - # they are said to be anonymous. See stacktrace.outputMessage. From 9083ce4ea06bd741091eace28ff614610a8c7250 Mon Sep 17 00:00:00 2001 From: Mihai Sucan Date: Wed, 18 May 2011 19:10:28 +0300 Subject: [PATCH 005/145] Bug 585991 - Show a popup listing possible completions; r=rcampbell,dtownsend sr=neil --- .../components/console/hudservice/AutocompletePopup.jsm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/toolkit/components/console/hudservice/AutocompletePopup.jsm b/toolkit/components/console/hudservice/AutocompletePopup.jsm index 7267c82c0fca..d472fe71d49d 100644 --- a/toolkit/components/console/hudservice/AutocompletePopup.jsm +++ b/toolkit/components/console/hudservice/AutocompletePopup.jsm @@ -223,7 +223,15 @@ AutocompletePopup.prototype = { while (this._list.hasChildNodes()) { this._list.removeChild(this._list.firstChild); } + + // Reset the panel and list dimensions. New dimensions are calculated when a + // new set of items is added to the autocomplete popup. this._list.width = ""; + this._list.height = ""; + this._panel.width = ""; + this._panel.height = ""; + this._panel.top = ""; + this._panel.left = ""; }, /** From 32817a8148013647b4b410e541380a50617232b2 Mon Sep 17 00:00:00 2001 From: Rob Campbell Date: Wed, 18 May 2011 14:29:20 -0300 Subject: [PATCH 006/145] Bug 653528 - Strip out Style and DOM panels and support code from Inspector; r=gavin.sharp --- browser/base/Makefile.in | 1 - browser/base/content/browser.xul | 35 -- browser/base/content/inspector.js | 392 +++--------------- browser/base/content/stylePanel.jsm | 315 -------------- browser/base/content/test/Makefile.in | 2 - .../test/browser_inspector_domPanel.js | 171 -------- .../test/browser_inspector_highlighter.js | 1 + .../test/browser_inspector_initialization.js | 4 - .../test/browser_inspector_stylePanel.js | 124 ------ .../test/browser_inspector_tab_switch.js | 17 +- .../locales/en-US/chrome/browser/browser.dtd | 13 - .../en-US/chrome/browser/inspector.properties | 16 - browser/locales/jar.mn | 1 - 13 files changed, 69 insertions(+), 1023 deletions(-) delete mode 100644 browser/base/content/stylePanel.jsm delete mode 100644 browser/base/content/test/browser_inspector_domPanel.js delete mode 100644 browser/base/content/test/browser_inspector_stylePanel.js delete mode 100644 browser/locales/en-US/chrome/browser/inspector.properties diff --git a/browser/base/Makefile.in b/browser/base/Makefile.in index 3a894429b065..446fbb752bef 100644 --- a/browser/base/Makefile.in +++ b/browser/base/Makefile.in @@ -57,7 +57,6 @@ EXTRA_JS_MODULES = \ content/openLocationLastURL.jsm \ content/NetworkPrioritizer.jsm \ content/domplate.jsm \ - content/stylePanel.jsm \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index a7189d0c9bc8..a4915d2a012a 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -249,26 +249,6 @@ accesskey="&inspectButton.accesskey;" class="toolbarbutton-text" command="Inspector:Inspect"/> - - - - @@ -276,21 +256,6 @@ - - diff --git a/browser/base/content/inspector.js b/browser/base/content/inspector.js index 7fe792ae67e1..593948fe3dff 100644 --- a/browser/base/content/inspector.js +++ b/browser/base/content/inspector.js @@ -366,37 +366,6 @@ var InspectorUI = { } }, - /** - * Toggle the style panel. Invoked from the toolbar's Style button. - */ - toggleStylePanel: function IUI_toggleStylePanel() - { - if (this.isStylePanelOpen) { - this.stylePanel.hidePopup(); - } else { - this.openStylePanel(); - if (this.selection) { - this.updateStylePanel(this.selection); - } - } - }, - - /** - * Toggle the DOM panel. Invoked from the toolbar's DOM button. - */ - toggleDOMPanel: function IUI_toggleDOMPanel() - { - if (this.isDOMPanelOpen) { - this.domPanel.hidePopup(); - } else { - this.clearDOMPanel(); - this.openDOMPanel(); - if (this.selection) { - this.updateDOMPanel(this.selection); - } - } - }, - /** * Is the tree panel open? * @@ -407,26 +376,6 @@ var InspectorUI = { return this.treePanel && this.treePanel.state == "open"; }, - /** - * Is the style panel open? - * - * @returns boolean - */ - get isStylePanelOpen() - { - return this.stylePanel && this.stylePanel.state == "open"; - }, - - /** - * Is the DOM panel open? - * - * @returns boolean - */ - get isDOMPanelOpen() - { - return this.domPanel && this.domPanel.state == "open"; - }, - /** * Return the default selection element for the inspected document. */ @@ -445,10 +394,17 @@ var InspectorUI = { this.ioBox = new InsideOutBox(this, this.treePanelDiv); this.ioBox.createObjectBox(this.win.document.documentElement); this.treeLoaded = true; - if (this.isTreePanelOpen && this.isStylePanelOpen && - this.isDOMPanelOpen && this.treeLoaded) { - this.notifyReady(); - } + + // setup highlighter and start inspecting + this.initializeHighlighter(); + + // Setup the InspectorStore or restore state + this.initializeStore(); + + if (InspectorStore.getValue(this.winID, "inspecting")) + this.startInspecting(); + + this.notifyReady(); }, /** @@ -471,26 +427,33 @@ var InspectorUI = { this.treeIFrame.setAttribute("onclick", "InspectorUI.onTreeClick(event)"); this.treeIFrame = this.treePanel.insertBefore(this.treeIFrame, resizerBox); } - + + let self = this; + this.treePanel.addEventListener("popupshown", function treePanelShown() { + InspectorUI.treePanel.removeEventListener("popupshown", + treePanelShown, false); + + let src = InspectorUI.treeIFrame.getAttribute("src"); + if (src != "chrome://browser/content/inspector.html") { + InspectorUI.treeIFrame.addEventListener("load", + function loadedInitializeTreePanel() { + InspectorUI.treeIFrame.removeEventListener("load", + loadedInitializeTreePanel, true); + InspectorUI.initializeTreePanel(); + }, true); + InspectorUI.treeIFrame.setAttribute("src", + "chrome://browser/content/inspector.html"); + } else { + InspectorUI.initializeTreePanel(); + } + }, false); + const panelWidthRatio = 7 / 8; const panelHeightRatio = 1 / 5; this.treePanel.openPopup(this.browser, "overlap", 80, this.win.innerHeight, false, false); this.treePanel.sizeTo(this.win.outerWidth * panelWidthRatio, this.win.outerHeight * panelHeightRatio); - - let src = this.treeIFrame.getAttribute("src"); - if (src != "chrome://browser/content/inspector.html") { - let self = this; - this.treeIFrame.addEventListener("DOMContentLoaded", function() { - self.treeIFrame.removeEventListener("DOMContentLoaded", arguments.callee, true); - self.initializeTreePanel(); - }, true); - - this.treeIFrame.setAttribute("src", "chrome://browser/content/inspector.html"); - } else { - this.initializeTreePanel(); - } }, createObjectBox: function IUI_createObjectBox(object, isRoot) @@ -600,55 +563,8 @@ var InspectorUI = { }, /** - * Open the style panel if not already onscreen. - */ - openStylePanel: function IUI_openStylePanel() - { - if (!this.stylePanel) - this.stylePanel = document.getElementById("inspector-style-panel"); - if (!this.isStylePanelOpen) { - this.stylePanel.hidden = false; - // open at top right of browser panel, offset by 20px from top. - this.stylePanel.openPopup(this.browser, "end_before", 0, 20, false, false); - // size panel to 200px wide by half browser height - 60. - this.stylePanel.sizeTo(200, this.win.outerHeight / 2 - 60); - } - }, - - /** - * Open the DOM panel if not already onscreen. - */ - openDOMPanel: function IUI_openDOMPanel() - { - if (!this.isDOMPanelOpen) { - this.domPanel.hidden = false; - // open at middle right of browser panel, offset by 20px from middle. - this.domPanel.openPopup(this.browser, "end_before", 0, - this.win.outerHeight / 2 - 20, false, false); - // size panel to 200px wide by half browser height - 60. - this.domPanel.sizeTo(200, this.win.outerHeight / 2 - 60); - } - }, - - /** - * Toggle the dimmed (semi-transparent) state for a panel by setting or - * removing a dimmed attribute. - * - * @param aDim - * The panel to be dimmed. - */ - toggleDimForPanel: function IUI_toggleDimForPanel(aDim) - { - if (aDim.hasAttribute("dimmed")) { - aDim.removeAttribute("dimmed"); - } else { - aDim.setAttribute("dimmed", "true"); - } - }, - - /** - * Open inspector UI. tree, style and DOM panels if enabled. Add listeners for - * document scrolling, resize, tabContainer.TabSelect and others. + * Open inspector UI. tree. Add listeners for document scrolling, + * resize, tabContainer.TabSelect and others. */ openInspectorUI: function IUI_openInspectorUI() { @@ -661,44 +577,12 @@ var InspectorUI = { this.domplateUtils.setDOM(window); } - // DOM panel initialization and loading (via PropertyPanel.jsm) - let objectPanelTitle = this.strings. - GetStringFromName("object.objectPanelTitle"); - let parent = document.getElementById("inspector-style-panel").parentNode; - this.propertyPanel = new (this.PropertyPanel)(parent, document, - objectPanelTitle, {}); - - // additional DOM panel setup needed for unittest identification and use - this.domPanel = this.propertyPanel.panel; - this.domPanel.setAttribute("id", "inspector-dom-panel"); - this.domBox = this.propertyPanel.tree; - this.domTreeView = this.propertyPanel.treeView; - // open inspector UI this.openTreePanel(); - // style panel setup and activation - this.styleBox = document.getElementById("inspector-style-listbox"); - this.clearStylePanel(); - this.openStylePanel(); - - // DOM panel setup and activation - this.clearDOMPanel(); - this.openDOMPanel(); - - // setup highlighter and start inspecting - this.initializeHighlighter(); - - // Setup the InspectorStore or restore state - this.initializeStore(); - - if (InspectorStore.getValue(this.winID, "inspecting")) - this.startInspecting(); - this.win.document.addEventListener("scroll", this, false); this.win.addEventListener("resize", this, false); this.inspectCmd.setAttribute("checked", true); - document.addEventListener("popupshown", this, false); }, /** @@ -774,8 +658,6 @@ var InspectorUI = { this.highlighter.unhighlight(); } - if (this.isTreePanelOpen) - this.treePanel.hidePopup(); if (this.treePanelDiv) { this.treePanelDiv.ownerPanel = null; let parent = this.treePanelDiv.parentNode; @@ -795,19 +677,12 @@ var InspectorUI = { delete this.domplateUtils; } - if (this.isStylePanelOpen) { - this.stylePanel.hidePopup(); - } - if (this.domPanel) { - this.domPanel.hidePopup(); - this.domBox = null; - this.domTreeView = null; - } this.inspectCmd.setAttribute("checked", false); this.browser = this.win = null; // null out references to browser and window this.winID = null; this.selection = null; this.treeLoaded = false; + this.treePanel.hidePopup(); this.closing = false; Services.obs.notifyObservers(null, "inspector-closed", null); }, @@ -820,8 +695,6 @@ var InspectorUI = { { this.attachPageListeners(); this.inspecting = true; - this.toggleDimForPanel(this.stylePanel); - this.toggleDimForPanel(this.domPanel); }, /** @@ -834,8 +707,6 @@ var InspectorUI = { return; this.detachPageListeners(); this.inspecting = false; - this.toggleDimForPanel(this.stylePanel); - this.toggleDimForPanel(this.domPanel); if (this.highlighter.node) { this.select(this.highlighter.node, true, true); } @@ -860,148 +731,16 @@ var InspectorUI = { let box = this.ioBox.createObjectBox(this.selection); if (!this.inspecting) { this.highlighter.highlightNode(this.selection); - this.updateStylePanel(this.selection); - this.updateDOMPanel(this.selection); } this.ioBox.select(aNode, true, true, aScroll); } }, - ///////////////////////////////////////////////////////////////////////// - //// Model Creation Methods - - /** - * Add a new item to the style panel listbox. - * - * @param aLabel - * A bit of text to put in the listitem's label attribute. - * @param aType - * The type of item. - * @param content - * Text content or value of the listitem. - */ - addStyleItem: function IUI_addStyleItem(aLabel, aType, aContent) - { - let itemLabelString = this.strings.GetStringFromName("style.styleItemLabel"); - let item = document.createElement("listitem"); - - // Do not localize these strings - let label = aLabel; - item.className = "style-" + aType; - if (aContent) { - label = itemLabelString.replace("#1", aLabel); - label = label.replace("#2", aContent); - } - item.setAttribute("label", label); - - this.styleBox.appendChild(item); - }, - - /** - * Create items for each rule included in the given array. - * - * @param aRules - * an array of rule objects - */ - createStyleRuleItems: function IUI_createStyleRuleItems(aRules) - { - let selectorLabel = this.strings.GetStringFromName("style.selectorLabel"); - - aRules.forEach(function(rule) { - this.addStyleItem(selectorLabel, "selector", rule.id); - rule.properties.forEach(function(property) { - if (property.overridden) - return; // property marked overridden elsewhere - // Do not localize the strings below this line - let important = ""; - if (property.important) - important += " !important"; - this.addStyleItem(property.name, "property", property.value + important); - }, this); - }, this); - }, - - /** - * Create rule items for each section as well as the element's style rules, - * if any. - * - * @param aRules - * Array of rules corresponding to the element's style object. - * @param aSections - * Array of sections encapsulating the inherited rules for selectors - * and elements. - */ - createStyleItems: function IUI_createStyleItems(aRules, aSections) - { - this.createStyleRuleItems(aRules); - let inheritedString = - this.strings.GetStringFromName("style.inheritedFrom"); - aSections.forEach(function(section) { - let sectionTitle = section.element.tagName; - if (section.element.id) - sectionTitle += "#" + section.element.id; - let replacedString = inheritedString.replace("#1", sectionTitle); - this.addStyleItem(replacedString, "section"); - this.createStyleRuleItems(section.rules); - }, this); - }, - - /** - * Remove all items from the Style Panel's listbox. - */ - clearStylePanel: function IUI_clearStylePanel() - { - for (let i = this.styleBox.childElementCount; i >= 0; --i) - this.styleBox.removeItemAt(i); - }, - - /** - * Remove all items from the DOM Panel's listbox. - */ - clearDOMPanel: function IUI_clearStylePanel() - { - this.domTreeView.data = {}; - }, - - /** - * Update the contents of the style panel with styles for the currently - * inspected node. - * - * @param aNode - * The highlighted node to get styles for. - */ - updateStylePanel: function IUI_updateStylePanel(aNode) - { - if (this.inspecting || !this.isStylePanelOpen) { - return; - } - - let rules = [], styleSections = [], usedProperties = {}; - this.style.getInheritedRules(aNode, styleSections, usedProperties); - this.style.getElementRules(aNode, rules, usedProperties); - this.clearStylePanel(); - this.createStyleItems(rules, styleSections); - }, - - /** - * Update the contents of the DOM panel with name/value pairs for the - * currently-inspected node. - */ - updateDOMPanel: function IUI_updateDOMPanel(aNode) - { - if (this.inspecting || !this.isDOMPanelOpen) { - return; - } - - this.domTreeView.data = aNode; - }, - ///////////////////////////////////////////////////////////////////////// //// Event Handling notifyReady: function IUI_notifyReady() { - document.removeEventListener("popupshowing", this, false); Services.obs.notifyObservers(null, "inspector-opened", null); }, @@ -1018,15 +757,6 @@ var InspectorUI = { let inspectorClosed = false; switch (event.type) { - case "popupshown": - if (event.target.id == "inspector-tree-panel" || - event.target.id == "inspector-style-panel" || - event.target.id == "inspector-dom-panel") - if (this.isTreePanelOpen && this.isStylePanelOpen && - this.isDOMPanelOpen && this.treeLoaded) { - this.notifyReady(); - } - break; case "TabSelect": winID = this.getWindowID(gBrowser.selectedBrowser.contentWindow); if (this.isTreePanelOpen && winID != this.winID) { @@ -1036,13 +766,17 @@ var InspectorUI = { if (winID && InspectorStore.hasID(winID)) { if (inspectorClosed && this.closing) { - Services.obs.addObserver(function () { + Services.obs.addObserver(function reopenInspectorForTab() { + Services.obs.removeObserver(reopenInspectorForTab, + "inspector-closed", false); InspectorUI.openInspectorUI(); }, "inspector-closed", false); } else { this.openInspectorUI(); } - } else if (InspectorStore.isEmpty()) { + } + + if (InspectorStore.isEmpty()) { gBrowser.tabContainer.removeEventListener("TabSelect", this, false); } break; @@ -1151,8 +885,6 @@ var InspectorUI = { this.selectEventsSuppressed = true; this.select(aNode, true, true); this.selectEventsSuppressed = false; - this.updateStylePanel(aNode); - this.updateDOMPanel(aNode); }, /** @@ -1284,6 +1016,25 @@ var InspectorUI = { { Services.console.logStringMessage(msg); }, + + /** + * Debugging function. + * @param msg + * text to show with the stack trace. + */ + _trace: function TRACE(msg) + { + this._log("TRACE: " + msg); + let frame = Components.stack.caller; + while (frame = frame.caller) { + if (frame.language == Ci.nsIProgrammingLanguage.JAVASCRIPT || + frame.language == Ci.nsIProgrammingLanguage.JAVASCRIPT2) { + this._log("filename: " + frame.filename + " lineNumber: " + frame.lineNumber + + " functionName: " + frame.name); + } + } + this._log("END TRACE"); + }, } /** @@ -1420,26 +1171,3 @@ XPCOMUtils.defineLazyGetter(InspectorUI, "inspectCmd", function () { return document.getElementById("Tools:Inspect"); }); -XPCOMUtils.defineLazyGetter(InspectorUI, "strings", function () { - return Services.strings.createBundle("chrome://browser/locale/inspector.properties"); -}); - -XPCOMUtils.defineLazyGetter(InspectorUI, "PropertyTreeView", function () { - var obj = {}; - Cu.import("resource:///modules/PropertyPanel.jsm", obj); - return obj.PropertyTreeView; -}); - -XPCOMUtils.defineLazyGetter(InspectorUI, "PropertyPanel", function () { - var obj = {}; - Cu.import("resource:///modules/PropertyPanel.jsm", obj); - return obj.PropertyPanel; -}); - -XPCOMUtils.defineLazyGetter(InspectorUI, "style", function () { - var obj = {}; - Cu.import("resource:///modules/stylePanel.jsm", obj); - obj.style.initialize(); - return obj.style; -}); - diff --git a/browser/base/content/stylePanel.jsm b/browser/base/content/stylePanel.jsm deleted file mode 100644 index 21d8ceb1a1d8..000000000000 --- a/browser/base/content/stylePanel.jsm +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2007, Parakey Inc. - * All rights reserved. - * - * Redistribution and use of this software in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * * 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. - * - * * Neither the name of Parakey Inc. nor the names of its - * contributors may be used to endorse or promote products - * derived from this software without specific prior - * written permission of Parakey Inc. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. - */ - -/* - * Creator: - * Joe Hewitt - * Contributors - * John J. Barton (IBM Almaden) - * Jan Odvarko (Mozilla Corp.) - * Max Stepanov (Aptana Inc.) - * Rob Campbell (Mozilla Corp.) - * Hans Hillen (Paciello Group, Mozilla) - * Curtis Bartley (Mozilla Corp.) - * Mike Collins (IBM Almaden) - * Kevin Decker - * Mike Ratcliffe (Comartis AG) - * Hernan Rodríguez Colmeiro - * Austin Andrews - * Christoph Dorn - * Steven Roussey (AppCenter Inc, Network54) - */ - -var EXPORTED_SYMBOLS = ["style"]; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/Services.jsm"); - -var style = { - - /** - * initialize domUtils - */ - initialize: function CSS_initialize() - { - this.domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]. - getService(Ci["inIDOMUtils"]); - }, - - /** - * Is the given property sheet a system (user agent) stylesheet? - * - * @param aSheet - * a stylesheet - */ - isSystemStyleSheet: function CSS_isSystemStyleSheet(aSheet) - { - if (!aSheet) - return true; - - let url = aSheet.href; - - if (!url) - return false; - if (url.length == 0) - return true; - if (url[0] == 'h') - return false; - if (url.substr(0, 9) == "resource:") - return true; - if (url.substr(0, 7) == "chrome:") - return true; - if (url == "XPCSafeJSObjectWrapper.cpp") - return true; - if (url.substr(0, 6) == "about:") - return true; - - return false; - }, - - /** - * Parse properties from a given style object. - * Borrowed from Firebug's css.js. - * - * @param aStyle - * a style object - */ - parseCSSProperties: function CSS_parseCSSProps(aStyle) - { - let properties = []; - let lines = aStyle.cssText.match(/(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g); - let propRE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(! important)?;?$/; - let line, i = 0; - while(line = lines[i++]) { - let match = propRE.exec(line); - if (!match) - continue; - let name = match[1]; - let value = match[2]; - let important = !!match[3]; // true if match[3] is non-empty - properties.unshift({name: name, value: value, important: important}); - } - - return properties; - }, - - /** - * Mark properties overridden further up the hierarchy. - * - * @param aProps - * Array of properties. - * @param aUsedProps - * Object of arrays keyed by property name. - * @param aInherit - * Boolean of whether or not we are in inherited mode. - */ - markOverriddenProperties: function CSS_markOverriddenProperties(aProps, aUsedProps, aInherit) - { - for (let i = 0; i < aProps.length; ++i) { - let prop = aProps[i]; - if (aUsedProps.hasOwnProperty(prop.name)) { - // all previous occurrences of this property - let deadProps = aUsedProps[prop.name]; - for (let j = 0; j < deadProps.length; ++j) { - let deadProp = deadProps[j]; - if (!deadProp.disabled && !deadProp.wasInherited && - deadProp.important && !prop.important) { - prop.overridden = true; // new occurrence overridden - } else if (!prop.disabled) { - deadProp.overridden = true; // previous occurrences overridden - } else { - aUsedProps[prop.name] = []; - } - - prop.wasInherited = aInherit ? true : false; - // all occurrences of a property seen so far, by name - aUsedProps[prop.name].push(prop); - } - } - } - }, - - /** - * Sort given properties in lexical order by name. - * - * @param properties - * An array of properties. - * @returns sorted array. - */ - sortProperties: function CSS_sortProperties(properties) - { - properties.sort(function(a, b) - { - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - }); - }, - - /** - * Get properties for a given element and push them to the rules array. - * - * @param aNode - * a DOM node - * @param rules - * An array of rules to add properties to. - * @param usedProps - * Object of arrays keyed by property name. - * @param inherit - * boolean determining whether or not we're in inherit mode - */ - getStyleProperties: function CSS_getStyleProperties(aNode, aRules, aUsedProps, aInherit) - { - let properties = this.parseCSSProperties(aNode.style, aInherit); - - this.sortProperties(properties); - this.markOverriddenProperties(properties, aUsedProps, aInherit); - - if (properties.length) { - aRules.push({rule: aNode, selector: "element.style", - properties: properties, inherited: aInherit}); - } - }, - - /** - * Get properties for a given rule. - * - * @param aRule - * A Rule from a stylesheet. - */ - getRuleProperties: function CSS_getRuleProperties(aRule) - { - let style = aRule.style; - return this.parseCSSProperties(style); - }, - - /** - * Recursively get rules for an element's parents and add them to the - * sections array. - * - * @param aNode - * an element in a DOM tree. - * @param sections - * an array of sections - * @param usedProps - * Object of arrays keyed by property name. - */ - getInheritedRules: function CSS_getInheritedRules(aNode, aSections, aUsedProps) - { - let parent = aNode.parentNode; - if (parent && parent.nodeType == 1) { - this.getInheritedRules(parent, aSections, aUsedProps); - - let rules = []; - this.getElementRules(parent, rules, aUsedProps, true); - - if (rules.length) { - aSections.unshift({element: parent, rules: rules}); - } - } - }, - - /** - * Get the CSS style rules for a given node in the DOM and append them to the - * rules array. - * - * @param aNode - * an element in the DOM tree. - * @param aRules - * an array of rules. - * @param aUsedProps - * Object of arrays keyed by property name. - * @param aInherit - * boolean indicating whether we are in an inherited mode or not - */ - getElementRules: function CSS_getElementRules(aNode, aRules, aUsedProps, aInherit) - { - let inspectedRules; - - try { - inspectedRules = this.domUtils.getCSSStyleRules(aNode); - } catch (ex) { - Services.console.logStringMessage(ex); - } - - if (!inspectedRules) - return; - - for (let i = 0; i < inspectedRules.Count(); ++i) { - let rule = inspectedRules.GetElementAt(i); - let href = rule.parentStyleSheet.href; - - if (!href) { - // Null href means inline style. - href = aNode.ownerDocument.location.href; - } - - let isSystemSheet = this.isSystemStyleSheet(rule.parentStyleSheet); - - if (isSystemSheet) - continue; - - let properties = this.getRuleProperties(rule, aInherit); - if (aInherit && !properties.length) - continue; - - let line = this.domUtils.getRuleLine(rule); - let ruleId = rule.selectorText + " " + href + " (" + line + ")"; - - let sourceLink = "view-source:" + href + "#" + line; - - this.markOverriddenProperties(properties, aUsedProps, aInherit); - - aRules.unshift( - {rule: rule, - id: ruleId, - selector: rule.selectorText, - properties: properties, - inherited: aInherit, - sourceLink: sourceLink, - isSystemSheet: isSystemSheet}); - } - - if (aNode.style) { - this.getStyleProperties(aNode, aRules, aUsedProps, aInherit); - } - }, -}; - diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index e8bc6f32657d..38db5cd0c832 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -183,8 +183,6 @@ _BROWSER_FILES = \ browser_inspector_initialization.js \ browser_inspector_treeSelection.js \ browser_inspector_highlighter.js \ - browser_inspector_stylePanel.js \ - browser_inspector_domPanel.js \ browser_inspector_iframeTest.js \ browser_inspector_scrolling.js \ browser_inspector_store.js \ diff --git a/browser/base/content/test/browser_inspector_domPanel.js b/browser/base/content/test/browser_inspector_domPanel.js deleted file mode 100644 index 4d3f80fcd7c2..000000000000 --- a/browser/base/content/test/browser_inspector_domPanel.js +++ /dev/null @@ -1,171 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Inspector DOM Panel Tests. - * - * The Initial Developer of the Original Code is - * The Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Rob Campbell - * Mihai Șucan - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -let doc; -let testGen; -let newProperty; - -function createDocument() -{ - doc.body.innerHTML = '

\n' + - '

Some header text

\n' + - '

hi.

\n' + - '

I am a test-case. This text exists ' + - 'solely to provide some things to ' + - 'highlight and count ' + - 'DOM list-items in the box at right. If you are reading this, ' + - 'you should go do something else instead. Maybe read a book. Or better ' + - 'yet, write some test-cases for another bit of code. ' + - 'Maybe more inspector test-cases!

\n' + - '

end transmission

\n' + - '
'; - doc.title = "Inspector DOM Test"; - Services.obs.addObserver(runDOMTests, "inspector-opened", false); - InspectorUI.openInspectorUI(); -} - -function nodeGenerator() -{ - let body = doc.body; - newProperty = "rand" + Date.now(); - body[newProperty] = Math.round(Math.random() * 100); - InspectorUI.inspectNode(body); - yield; - - let h1 = doc.querySelector("h1"); - newProperty = "rand2" + Date.now(); - h1[newProperty] = "test" + Math.random(); - InspectorUI.inspectNode(h1); - yield; - - let first = doc.getElementById("first"); - newProperty = "rand3" + Date.now(); - first[newProperty] = null; - InspectorUI.inspectNode(first); - yield; - - let closing = doc.getElementById("closing"); - newProperty = "bazbaz" + Date.now(); - closing[newProperty] = false; - InspectorUI.inspectNode(closing); - yield; -} - -function runDOMTests() -{ - InspectorUI._log("runDOMtests"); - Services.obs.removeObserver(runDOMTests, "inspector-opened", false); - document.addEventListener("popupshown", performTestComparisons, false); - InspectorUI.stopInspecting(); - testGen = nodeGenerator(); - testGen.next(); -} - -function findInDOMPanel(aString) -{ - let treeView = InspectorUI.domTreeView; - let row; - - for (let i = 0, n = treeView.rowCount; i < n; i++) { - row = treeView.getCellText(i, 0); - if (row && row.indexOf(aString) != -1) { - return true; - } - } - - return false; -} - -function performTestComparisons(evt) -{ - InspectorUI._log("performTestComparisons"); - if (evt.target.id != "highlighter-panel") - return true; - - let selection = InspectorUI.selection; - - ok(selection, "selection"); - ok(InspectorUI.isDOMPanelOpen, "DOM panel is open?"); - ok(InspectorUI.highlighter.isHighlighting, "panel is highlighting"); - - let value = selection[newProperty]; - if (typeof value == "string") { - value = '"' + value + '"'; - } - - ok(findInDOMPanel(newProperty + ': ' + value), - "domPanel shows the correct value for " + newProperty); - - ok(findInDOMPanel('tagName: "' + selection.tagName + '"'), - "domPanel shows the correct tagName"); - - if (selection.id) { - ok(findInDOMPanel('id: "' + selection.id + '"'), - "domPanel shows the correct id"); - } - - try { - testGen.next(); - } catch(StopIteration) { - document.removeEventListener("popupshown", performTestComparisons, false); - finishUp(); - } -} - -function finishUp() { - InspectorUI.closeInspectorUI(); - gBrowser.removeCurrentTab(); - finish(); -} - -function test() -{ - waitForExplicitFinish(); - gBrowser.selectedTab = gBrowser.addTab(); - gBrowser.selectedBrowser.addEventListener("load", function() { - gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); - doc = content.document; - waitForFocus(createDocument, content); - }, true); - - content.location = "data:text/html,basic tests for inspector"; -} - diff --git a/browser/base/content/test/browser_inspector_highlighter.js b/browser/base/content/test/browser_inspector_highlighter.js index 82b2cab9fac5..08bd1f624ac9 100644 --- a/browser/base/content/test/browser_inspector_highlighter.js +++ b/browser/base/content/test/browser_inspector_highlighter.js @@ -102,6 +102,7 @@ function performTestComparisons(evt) function finishUp() { InspectorUI.closeInspectorUI(); + ok(!InspectorUI.highlighter.isHighlighting, "panel is not highlighting"); gBrowser.removeCurrentTab(); finish(); } diff --git a/browser/base/content/test/browser_inspector_initialization.js b/browser/base/content/test/browser_inspector_initialization.js index b56dcba65240..b439c71ccb5a 100644 --- a/browser/base/content/test/browser_inspector_initialization.js +++ b/browser/base/content/test/browser_inspector_initialization.js @@ -54,16 +54,12 @@ function runInspectorTests() is(InspectorUI.treeIFrame, iframe, "Inspector IFrame matches"); ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); - ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); - ok(InspectorUI.isDOMPanelOpen, "Inspector DOM Panel is open"); InspectorUI.closeInspectorUI(); } function finishInspectorTests() { Services.obs.removeObserver(finishInspectorTests, "inspector-closed", false); - ok(!InspectorUI.isDOMPanelOpen, "Inspector DOM Panel is closed"); - ok(!InspectorUI.isStylePanelOpen, "Inspector Style Panel is closed"); ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed"); ok(!InspectorUI.inspecting, "Inspector is not highlighting"); gBrowser.removeCurrentTab(); diff --git a/browser/base/content/test/browser_inspector_stylePanel.js b/browser/base/content/test/browser_inspector_stylePanel.js deleted file mode 100644 index d4d2e7d165f2..000000000000 --- a/browser/base/content/test/browser_inspector_stylePanel.js +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Inspector Style Panel Tests. - * - * The Initial Developer of the Original Code is - * The Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Rob Campbell (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -let doc; -let spans; -let testGen; - -function createDocument() -{ - doc.body.innerHTML = '
\n' + - '

Some header text

\n' + - '

hi.

\n' + - '

I am a test-case. This text exists ' + - 'solely to provide some things to ' + - 'highlight and count ' + - 'style list-items in the box at right. If you are reading this, ' + - 'you should go do something else instead. Maybe read a book. Or better ' + - 'yet, write some test-cases for another bit of code. ' + - 'Maybe more inspector test-cases!

\n' + - '

end transmission

\n' + - '
'; - doc.title = "Inspector Style Test"; - setupStyleTests(); -} - -function setupStyleTests() -{ - spans = doc.querySelectorAll("span"); - ok(spans, "captain, we have the spans"); - Services.obs.addObserver(runStyleTests, "inspector-opened", false); - InspectorUI.openInspectorUI(); -} - -function spanGenerator() -{ - for (var i = 0; i < spans.length; ++i) { - InspectorUI.inspectNode(spans[i]); - yield; - } -} - -function runStyleTests() -{ - Services.obs.removeObserver(runStyleTests, "inspector-opened", false); - document.addEventListener("popupshown", performTestComparisons, false); - InspectorUI.stopInspecting(); - testGen = spanGenerator(); - testGen.next(); -} - -function performTestComparisons(evt) -{ - if (evt.target.id != "highlighter-panel") - return true; - - ok(InspectorUI.selection, "selection"); - ok(InspectorUI.isStylePanelOpen, "style panel is open?"); - ok(InspectorUI.highlighter.isHighlighting, "panel is highlighting"); - ok(InspectorUI.styleBox.itemCount > 0, "styleBox has items"); - - try { - testGen.next(); - } catch(StopIteration) { - document.removeEventListener("popupshown", performTestComparisons, false); - finishUp(); - } -} - -function finishUp() { - InspectorUI.closeInspectorUI(); - gBrowser.removeCurrentTab(); - finish(); -} - -function test() -{ - waitForExplicitFinish(); - gBrowser.selectedTab = gBrowser.addTab(); - gBrowser.selectedBrowser.addEventListener("load", function() { - gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); - doc = content.document; - waitForFocus(createDocument, content); - }, true); - - content.location = "data:text/html,basic tests for inspector"; -} - diff --git a/browser/base/content/test/browser_inspector_tab_switch.js b/browser/base/content/test/browser_inspector_tab_switch.js index 7ec32249d39c..d9793a9ae8e8 100644 --- a/browser/base/content/test/browser_inspector_tab_switch.js +++ b/browser/base/content/test/browser_inspector_tab_switch.js @@ -60,7 +60,6 @@ function inspectorUIOpen1() // Make sure the inspector is open. ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); - ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); ok(!InspectorStore.isEmpty(), "InspectorStore is not empty"); is(InspectorStore.length, 1, "InspectorStore.length = 1"); @@ -72,6 +71,7 @@ function inspectorUIOpen1() // Open the second tab. tab2 = gBrowser.addTab(); gBrowser.selectedTab = tab2; + gBrowser.selectedBrowser.addEventListener("load", function(evt) { gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true); @@ -86,12 +86,13 @@ function inspectorTabOpen2() // Make sure the inspector is closed. ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.isPanelOpen, "Inspector Tree Panel is closed"); - ok(!InspectorUI.isStylePanelOpen, "Inspector Style Panel is closed"); is(InspectorStore.length, 1, "InspectorStore.length = 1"); // Activate the inspector again. + executeSoon(function() { Services.obs.addObserver(inspectorUIOpen2, "inspector-opened", false); - InspectorUI.openInspectorUI(); + InspectorUI.openInspectorUI(); + }); } function inspectorUIOpen2() @@ -101,7 +102,6 @@ function inspectorUIOpen2() // Make sure the inspector is open. ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); - ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); is(InspectorStore.length, 2, "InspectorStore.length = 2"); // Disable highlighting. @@ -109,8 +109,10 @@ function inspectorUIOpen2() ok(!InspectorUI.inspecting, "Inspector is not highlighting"); // Switch back to tab 1. - Services.obs.addObserver(inspectorFocusTab1, "inspector-opened", false); - gBrowser.selectedTab = tab1; + executeSoon(function() { + Services.obs.addObserver(inspectorFocusTab1, "inspector-opened", false); + gBrowser.selectedTab = tab1; + }); } function inspectorFocusTab1() @@ -120,7 +122,6 @@ function inspectorFocusTab1() // Make sure the inspector is still open. ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); - ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); is(InspectorStore.length, 2, "InspectorStore.length = 2"); is(InspectorUI.selection, div, "selection matches the div element"); @@ -136,7 +137,6 @@ function inspectorFocusTab2() // Make sure the inspector is still open. ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); - ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); is(InspectorStore.length, 2, "InspectorStore.length = 2"); isnot(InspectorUI.selection, div, "selection does not match the div element"); @@ -154,7 +154,6 @@ function inspectorTabUnload1(evt) // Make sure the Inspector is still open and that the state is correct. ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); - ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); is(InspectorStore.length, 1, "InspectorStore.length = 1"); InspectorUI.closeInspectorUI(); diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd index bc4dd094377c..9e7ef52a99d6 100644 --- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -212,19 +212,6 @@ can reach it easily. --> - - - - - - - - - - diff --git a/browser/locales/en-US/chrome/browser/inspector.properties b/browser/locales/en-US/chrome/browser/inspector.properties deleted file mode 100644 index 70225d5efe82..000000000000 --- a/browser/locales/en-US/chrome/browser/inspector.properties +++ /dev/null @@ -1,16 +0,0 @@ -# LOCALIZATION NOTE (style.selectorLabel): Used in the Inspector style panel -# to label a CSS Selector. -style.selectorLabel=Selector - -# LOCALIZATION NOTE (style.inheritedFrom): used in Style panel in -# inspector. Describes which tagname[#id] the properties are inherited from. -style.inheritedFrom=Inherited from: #1 - -# LOCALIZATION NOTE (style.styleItemLabel): used in Style panel in inspector. -# Used for construction of list items, #1 = label, #2 = content. -style.styleItemLabel=#1: #2 - -# LOCALIZATION NOTE (object.objectPanelTitle): used in the Object Panel in the -# Inspector tool. There's also inspectObjectButton in browser.dtd for the -# toolbar button which allows users to open/close the Object panel. -object.objectPanelTitle=Object diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn index 97599b5d8a38..50ee15f61fac 100644 --- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -14,7 +14,6 @@ * locale/browser/browser.dtd (%chrome/browser/browser.dtd) locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd) locale/browser/browser.properties (%chrome/browser/browser.properties) - locale/browser/inspector.properties (%chrome/browser/inspector.properties) locale/browser/scratchpad.properties (%chrome/browser/scratchpad.properties) locale/browser/scratchpad.dtd (%chrome/browser/scratchpad.dtd) locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd) From 3b63b349330e15d8db09252c4ea9ffe776309bbd Mon Sep 17 00:00:00 2001 From: Rob Campbell Date: Wed, 18 May 2011 15:56:14 -0300 Subject: [PATCH 007/145] Bug 653528 - Strip out Style and DOM panels and support code from Inspector; Backed out changeset 6b0c16915edd a=orange --- browser/base/Makefile.in | 1 + browser/base/content/browser.xul | 35 ++ browser/base/content/inspector.js | 392 +++++++++++++++--- browser/base/content/stylePanel.jsm | 315 ++++++++++++++ browser/base/content/test/Makefile.in | 2 + .../test/browser_inspector_domPanel.js | 171 ++++++++ .../test/browser_inspector_highlighter.js | 1 - .../test/browser_inspector_initialization.js | 4 + .../test/browser_inspector_stylePanel.js | 124 ++++++ .../test/browser_inspector_tab_switch.js | 17 +- .../locales/en-US/chrome/browser/browser.dtd | 13 + .../en-US/chrome/browser/inspector.properties | 16 + browser/locales/jar.mn | 1 + 13 files changed, 1023 insertions(+), 69 deletions(-) create mode 100644 browser/base/content/stylePanel.jsm create mode 100644 browser/base/content/test/browser_inspector_domPanel.js create mode 100644 browser/base/content/test/browser_inspector_stylePanel.js create mode 100644 browser/locales/en-US/chrome/browser/inspector.properties diff --git a/browser/base/Makefile.in b/browser/base/Makefile.in index 446fbb752bef..3a894429b065 100644 --- a/browser/base/Makefile.in +++ b/browser/base/Makefile.in @@ -57,6 +57,7 @@ EXTRA_JS_MODULES = \ content/openLocationLastURL.jsm \ content/NetworkPrioritizer.jsm \ content/domplate.jsm \ + content/stylePanel.jsm \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index a4915d2a012a..a7189d0c9bc8 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -249,6 +249,26 @@ accesskey="&inspectButton.accesskey;" class="toolbarbutton-text" command="Inspector:Inspect"/> + + + + @@ -256,6 +276,21 @@ + + diff --git a/browser/base/content/inspector.js b/browser/base/content/inspector.js index 593948fe3dff..7fe792ae67e1 100644 --- a/browser/base/content/inspector.js +++ b/browser/base/content/inspector.js @@ -366,6 +366,37 @@ var InspectorUI = { } }, + /** + * Toggle the style panel. Invoked from the toolbar's Style button. + */ + toggleStylePanel: function IUI_toggleStylePanel() + { + if (this.isStylePanelOpen) { + this.stylePanel.hidePopup(); + } else { + this.openStylePanel(); + if (this.selection) { + this.updateStylePanel(this.selection); + } + } + }, + + /** + * Toggle the DOM panel. Invoked from the toolbar's DOM button. + */ + toggleDOMPanel: function IUI_toggleDOMPanel() + { + if (this.isDOMPanelOpen) { + this.domPanel.hidePopup(); + } else { + this.clearDOMPanel(); + this.openDOMPanel(); + if (this.selection) { + this.updateDOMPanel(this.selection); + } + } + }, + /** * Is the tree panel open? * @@ -376,6 +407,26 @@ var InspectorUI = { return this.treePanel && this.treePanel.state == "open"; }, + /** + * Is the style panel open? + * + * @returns boolean + */ + get isStylePanelOpen() + { + return this.stylePanel && this.stylePanel.state == "open"; + }, + + /** + * Is the DOM panel open? + * + * @returns boolean + */ + get isDOMPanelOpen() + { + return this.domPanel && this.domPanel.state == "open"; + }, + /** * Return the default selection element for the inspected document. */ @@ -394,17 +445,10 @@ var InspectorUI = { this.ioBox = new InsideOutBox(this, this.treePanelDiv); this.ioBox.createObjectBox(this.win.document.documentElement); this.treeLoaded = true; - - // setup highlighter and start inspecting - this.initializeHighlighter(); - - // Setup the InspectorStore or restore state - this.initializeStore(); - - if (InspectorStore.getValue(this.winID, "inspecting")) - this.startInspecting(); - - this.notifyReady(); + if (this.isTreePanelOpen && this.isStylePanelOpen && + this.isDOMPanelOpen && this.treeLoaded) { + this.notifyReady(); + } }, /** @@ -427,33 +471,26 @@ var InspectorUI = { this.treeIFrame.setAttribute("onclick", "InspectorUI.onTreeClick(event)"); this.treeIFrame = this.treePanel.insertBefore(this.treeIFrame, resizerBox); } - - let self = this; - this.treePanel.addEventListener("popupshown", function treePanelShown() { - InspectorUI.treePanel.removeEventListener("popupshown", - treePanelShown, false); - - let src = InspectorUI.treeIFrame.getAttribute("src"); - if (src != "chrome://browser/content/inspector.html") { - InspectorUI.treeIFrame.addEventListener("load", - function loadedInitializeTreePanel() { - InspectorUI.treeIFrame.removeEventListener("load", - loadedInitializeTreePanel, true); - InspectorUI.initializeTreePanel(); - }, true); - InspectorUI.treeIFrame.setAttribute("src", - "chrome://browser/content/inspector.html"); - } else { - InspectorUI.initializeTreePanel(); - } - }, false); - + const panelWidthRatio = 7 / 8; const panelHeightRatio = 1 / 5; this.treePanel.openPopup(this.browser, "overlap", 80, this.win.innerHeight, false, false); this.treePanel.sizeTo(this.win.outerWidth * panelWidthRatio, this.win.outerHeight * panelHeightRatio); + + let src = this.treeIFrame.getAttribute("src"); + if (src != "chrome://browser/content/inspector.html") { + let self = this; + this.treeIFrame.addEventListener("DOMContentLoaded", function() { + self.treeIFrame.removeEventListener("DOMContentLoaded", arguments.callee, true); + self.initializeTreePanel(); + }, true); + + this.treeIFrame.setAttribute("src", "chrome://browser/content/inspector.html"); + } else { + this.initializeTreePanel(); + } }, createObjectBox: function IUI_createObjectBox(object, isRoot) @@ -563,8 +600,55 @@ var InspectorUI = { }, /** - * Open inspector UI. tree. Add listeners for document scrolling, - * resize, tabContainer.TabSelect and others. + * Open the style panel if not already onscreen. + */ + openStylePanel: function IUI_openStylePanel() + { + if (!this.stylePanel) + this.stylePanel = document.getElementById("inspector-style-panel"); + if (!this.isStylePanelOpen) { + this.stylePanel.hidden = false; + // open at top right of browser panel, offset by 20px from top. + this.stylePanel.openPopup(this.browser, "end_before", 0, 20, false, false); + // size panel to 200px wide by half browser height - 60. + this.stylePanel.sizeTo(200, this.win.outerHeight / 2 - 60); + } + }, + + /** + * Open the DOM panel if not already onscreen. + */ + openDOMPanel: function IUI_openDOMPanel() + { + if (!this.isDOMPanelOpen) { + this.domPanel.hidden = false; + // open at middle right of browser panel, offset by 20px from middle. + this.domPanel.openPopup(this.browser, "end_before", 0, + this.win.outerHeight / 2 - 20, false, false); + // size panel to 200px wide by half browser height - 60. + this.domPanel.sizeTo(200, this.win.outerHeight / 2 - 60); + } + }, + + /** + * Toggle the dimmed (semi-transparent) state for a panel by setting or + * removing a dimmed attribute. + * + * @param aDim + * The panel to be dimmed. + */ + toggleDimForPanel: function IUI_toggleDimForPanel(aDim) + { + if (aDim.hasAttribute("dimmed")) { + aDim.removeAttribute("dimmed"); + } else { + aDim.setAttribute("dimmed", "true"); + } + }, + + /** + * Open inspector UI. tree, style and DOM panels if enabled. Add listeners for + * document scrolling, resize, tabContainer.TabSelect and others. */ openInspectorUI: function IUI_openInspectorUI() { @@ -577,12 +661,44 @@ var InspectorUI = { this.domplateUtils.setDOM(window); } + // DOM panel initialization and loading (via PropertyPanel.jsm) + let objectPanelTitle = this.strings. + GetStringFromName("object.objectPanelTitle"); + let parent = document.getElementById("inspector-style-panel").parentNode; + this.propertyPanel = new (this.PropertyPanel)(parent, document, + objectPanelTitle, {}); + + // additional DOM panel setup needed for unittest identification and use + this.domPanel = this.propertyPanel.panel; + this.domPanel.setAttribute("id", "inspector-dom-panel"); + this.domBox = this.propertyPanel.tree; + this.domTreeView = this.propertyPanel.treeView; + // open inspector UI this.openTreePanel(); + // style panel setup and activation + this.styleBox = document.getElementById("inspector-style-listbox"); + this.clearStylePanel(); + this.openStylePanel(); + + // DOM panel setup and activation + this.clearDOMPanel(); + this.openDOMPanel(); + + // setup highlighter and start inspecting + this.initializeHighlighter(); + + // Setup the InspectorStore or restore state + this.initializeStore(); + + if (InspectorStore.getValue(this.winID, "inspecting")) + this.startInspecting(); + this.win.document.addEventListener("scroll", this, false); this.win.addEventListener("resize", this, false); this.inspectCmd.setAttribute("checked", true); + document.addEventListener("popupshown", this, false); }, /** @@ -658,6 +774,8 @@ var InspectorUI = { this.highlighter.unhighlight(); } + if (this.isTreePanelOpen) + this.treePanel.hidePopup(); if (this.treePanelDiv) { this.treePanelDiv.ownerPanel = null; let parent = this.treePanelDiv.parentNode; @@ -677,12 +795,19 @@ var InspectorUI = { delete this.domplateUtils; } + if (this.isStylePanelOpen) { + this.stylePanel.hidePopup(); + } + if (this.domPanel) { + this.domPanel.hidePopup(); + this.domBox = null; + this.domTreeView = null; + } this.inspectCmd.setAttribute("checked", false); this.browser = this.win = null; // null out references to browser and window this.winID = null; this.selection = null; this.treeLoaded = false; - this.treePanel.hidePopup(); this.closing = false; Services.obs.notifyObservers(null, "inspector-closed", null); }, @@ -695,6 +820,8 @@ var InspectorUI = { { this.attachPageListeners(); this.inspecting = true; + this.toggleDimForPanel(this.stylePanel); + this.toggleDimForPanel(this.domPanel); }, /** @@ -707,6 +834,8 @@ var InspectorUI = { return; this.detachPageListeners(); this.inspecting = false; + this.toggleDimForPanel(this.stylePanel); + this.toggleDimForPanel(this.domPanel); if (this.highlighter.node) { this.select(this.highlighter.node, true, true); } @@ -731,16 +860,148 @@ var InspectorUI = { let box = this.ioBox.createObjectBox(this.selection); if (!this.inspecting) { this.highlighter.highlightNode(this.selection); + this.updateStylePanel(this.selection); + this.updateDOMPanel(this.selection); } this.ioBox.select(aNode, true, true, aScroll); } }, + ///////////////////////////////////////////////////////////////////////// + //// Model Creation Methods + + /** + * Add a new item to the style panel listbox. + * + * @param aLabel + * A bit of text to put in the listitem's label attribute. + * @param aType + * The type of item. + * @param content + * Text content or value of the listitem. + */ + addStyleItem: function IUI_addStyleItem(aLabel, aType, aContent) + { + let itemLabelString = this.strings.GetStringFromName("style.styleItemLabel"); + let item = document.createElement("listitem"); + + // Do not localize these strings + let label = aLabel; + item.className = "style-" + aType; + if (aContent) { + label = itemLabelString.replace("#1", aLabel); + label = label.replace("#2", aContent); + } + item.setAttribute("label", label); + + this.styleBox.appendChild(item); + }, + + /** + * Create items for each rule included in the given array. + * + * @param aRules + * an array of rule objects + */ + createStyleRuleItems: function IUI_createStyleRuleItems(aRules) + { + let selectorLabel = this.strings.GetStringFromName("style.selectorLabel"); + + aRules.forEach(function(rule) { + this.addStyleItem(selectorLabel, "selector", rule.id); + rule.properties.forEach(function(property) { + if (property.overridden) + return; // property marked overridden elsewhere + // Do not localize the strings below this line + let important = ""; + if (property.important) + important += " !important"; + this.addStyleItem(property.name, "property", property.value + important); + }, this); + }, this); + }, + + /** + * Create rule items for each section as well as the element's style rules, + * if any. + * + * @param aRules + * Array of rules corresponding to the element's style object. + * @param aSections + * Array of sections encapsulating the inherited rules for selectors + * and elements. + */ + createStyleItems: function IUI_createStyleItems(aRules, aSections) + { + this.createStyleRuleItems(aRules); + let inheritedString = + this.strings.GetStringFromName("style.inheritedFrom"); + aSections.forEach(function(section) { + let sectionTitle = section.element.tagName; + if (section.element.id) + sectionTitle += "#" + section.element.id; + let replacedString = inheritedString.replace("#1", sectionTitle); + this.addStyleItem(replacedString, "section"); + this.createStyleRuleItems(section.rules); + }, this); + }, + + /** + * Remove all items from the Style Panel's listbox. + */ + clearStylePanel: function IUI_clearStylePanel() + { + for (let i = this.styleBox.childElementCount; i >= 0; --i) + this.styleBox.removeItemAt(i); + }, + + /** + * Remove all items from the DOM Panel's listbox. + */ + clearDOMPanel: function IUI_clearStylePanel() + { + this.domTreeView.data = {}; + }, + + /** + * Update the contents of the style panel with styles for the currently + * inspected node. + * + * @param aNode + * The highlighted node to get styles for. + */ + updateStylePanel: function IUI_updateStylePanel(aNode) + { + if (this.inspecting || !this.isStylePanelOpen) { + return; + } + + let rules = [], styleSections = [], usedProperties = {}; + this.style.getInheritedRules(aNode, styleSections, usedProperties); + this.style.getElementRules(aNode, rules, usedProperties); + this.clearStylePanel(); + this.createStyleItems(rules, styleSections); + }, + + /** + * Update the contents of the DOM panel with name/value pairs for the + * currently-inspected node. + */ + updateDOMPanel: function IUI_updateDOMPanel(aNode) + { + if (this.inspecting || !this.isDOMPanelOpen) { + return; + } + + this.domTreeView.data = aNode; + }, + ///////////////////////////////////////////////////////////////////////// //// Event Handling notifyReady: function IUI_notifyReady() { + document.removeEventListener("popupshowing", this, false); Services.obs.notifyObservers(null, "inspector-opened", null); }, @@ -757,6 +1018,15 @@ var InspectorUI = { let inspectorClosed = false; switch (event.type) { + case "popupshown": + if (event.target.id == "inspector-tree-panel" || + event.target.id == "inspector-style-panel" || + event.target.id == "inspector-dom-panel") + if (this.isTreePanelOpen && this.isStylePanelOpen && + this.isDOMPanelOpen && this.treeLoaded) { + this.notifyReady(); + } + break; case "TabSelect": winID = this.getWindowID(gBrowser.selectedBrowser.contentWindow); if (this.isTreePanelOpen && winID != this.winID) { @@ -766,17 +1036,13 @@ var InspectorUI = { if (winID && InspectorStore.hasID(winID)) { if (inspectorClosed && this.closing) { - Services.obs.addObserver(function reopenInspectorForTab() { - Services.obs.removeObserver(reopenInspectorForTab, - "inspector-closed", false); + Services.obs.addObserver(function () { InspectorUI.openInspectorUI(); }, "inspector-closed", false); } else { this.openInspectorUI(); } - } - - if (InspectorStore.isEmpty()) { + } else if (InspectorStore.isEmpty()) { gBrowser.tabContainer.removeEventListener("TabSelect", this, false); } break; @@ -885,6 +1151,8 @@ var InspectorUI = { this.selectEventsSuppressed = true; this.select(aNode, true, true); this.selectEventsSuppressed = false; + this.updateStylePanel(aNode); + this.updateDOMPanel(aNode); }, /** @@ -1016,25 +1284,6 @@ var InspectorUI = { { Services.console.logStringMessage(msg); }, - - /** - * Debugging function. - * @param msg - * text to show with the stack trace. - */ - _trace: function TRACE(msg) - { - this._log("TRACE: " + msg); - let frame = Components.stack.caller; - while (frame = frame.caller) { - if (frame.language == Ci.nsIProgrammingLanguage.JAVASCRIPT || - frame.language == Ci.nsIProgrammingLanguage.JAVASCRIPT2) { - this._log("filename: " + frame.filename + " lineNumber: " + frame.lineNumber + - " functionName: " + frame.name); - } - } - this._log("END TRACE"); - }, } /** @@ -1171,3 +1420,26 @@ XPCOMUtils.defineLazyGetter(InspectorUI, "inspectCmd", function () { return document.getElementById("Tools:Inspect"); }); +XPCOMUtils.defineLazyGetter(InspectorUI, "strings", function () { + return Services.strings.createBundle("chrome://browser/locale/inspector.properties"); +}); + +XPCOMUtils.defineLazyGetter(InspectorUI, "PropertyTreeView", function () { + var obj = {}; + Cu.import("resource:///modules/PropertyPanel.jsm", obj); + return obj.PropertyTreeView; +}); + +XPCOMUtils.defineLazyGetter(InspectorUI, "PropertyPanel", function () { + var obj = {}; + Cu.import("resource:///modules/PropertyPanel.jsm", obj); + return obj.PropertyPanel; +}); + +XPCOMUtils.defineLazyGetter(InspectorUI, "style", function () { + var obj = {}; + Cu.import("resource:///modules/stylePanel.jsm", obj); + obj.style.initialize(); + return obj.style; +}); + diff --git a/browser/base/content/stylePanel.jsm b/browser/base/content/stylePanel.jsm new file mode 100644 index 000000000000..21d8ceb1a1d8 --- /dev/null +++ b/browser/base/content/stylePanel.jsm @@ -0,0 +1,315 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2007, Parakey Inc. + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * * 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. + * + * * Neither the name of Parakey Inc. nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior + * written permission of Parakey Inc. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. + */ + +/* + * Creator: + * Joe Hewitt + * Contributors + * John J. Barton (IBM Almaden) + * Jan Odvarko (Mozilla Corp.) + * Max Stepanov (Aptana Inc.) + * Rob Campbell (Mozilla Corp.) + * Hans Hillen (Paciello Group, Mozilla) + * Curtis Bartley (Mozilla Corp.) + * Mike Collins (IBM Almaden) + * Kevin Decker + * Mike Ratcliffe (Comartis AG) + * Hernan Rodríguez Colmeiro + * Austin Andrews + * Christoph Dorn + * Steven Roussey (AppCenter Inc, Network54) + */ + +var EXPORTED_SYMBOLS = ["style"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); + +var style = { + + /** + * initialize domUtils + */ + initialize: function CSS_initialize() + { + this.domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]. + getService(Ci["inIDOMUtils"]); + }, + + /** + * Is the given property sheet a system (user agent) stylesheet? + * + * @param aSheet + * a stylesheet + */ + isSystemStyleSheet: function CSS_isSystemStyleSheet(aSheet) + { + if (!aSheet) + return true; + + let url = aSheet.href; + + if (!url) + return false; + if (url.length == 0) + return true; + if (url[0] == 'h') + return false; + if (url.substr(0, 9) == "resource:") + return true; + if (url.substr(0, 7) == "chrome:") + return true; + if (url == "XPCSafeJSObjectWrapper.cpp") + return true; + if (url.substr(0, 6) == "about:") + return true; + + return false; + }, + + /** + * Parse properties from a given style object. + * Borrowed from Firebug's css.js. + * + * @param aStyle + * a style object + */ + parseCSSProperties: function CSS_parseCSSProps(aStyle) + { + let properties = []; + let lines = aStyle.cssText.match(/(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g); + let propRE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(! important)?;?$/; + let line, i = 0; + while(line = lines[i++]) { + let match = propRE.exec(line); + if (!match) + continue; + let name = match[1]; + let value = match[2]; + let important = !!match[3]; // true if match[3] is non-empty + properties.unshift({name: name, value: value, important: important}); + } + + return properties; + }, + + /** + * Mark properties overridden further up the hierarchy. + * + * @param aProps + * Array of properties. + * @param aUsedProps + * Object of arrays keyed by property name. + * @param aInherit + * Boolean of whether or not we are in inherited mode. + */ + markOverriddenProperties: function CSS_markOverriddenProperties(aProps, aUsedProps, aInherit) + { + for (let i = 0; i < aProps.length; ++i) { + let prop = aProps[i]; + if (aUsedProps.hasOwnProperty(prop.name)) { + // all previous occurrences of this property + let deadProps = aUsedProps[prop.name]; + for (let j = 0; j < deadProps.length; ++j) { + let deadProp = deadProps[j]; + if (!deadProp.disabled && !deadProp.wasInherited && + deadProp.important && !prop.important) { + prop.overridden = true; // new occurrence overridden + } else if (!prop.disabled) { + deadProp.overridden = true; // previous occurrences overridden + } else { + aUsedProps[prop.name] = []; + } + + prop.wasInherited = aInherit ? true : false; + // all occurrences of a property seen so far, by name + aUsedProps[prop.name].push(prop); + } + } + } + }, + + /** + * Sort given properties in lexical order by name. + * + * @param properties + * An array of properties. + * @returns sorted array. + */ + sortProperties: function CSS_sortProperties(properties) + { + properties.sort(function(a, b) + { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + }, + + /** + * Get properties for a given element and push them to the rules array. + * + * @param aNode + * a DOM node + * @param rules + * An array of rules to add properties to. + * @param usedProps + * Object of arrays keyed by property name. + * @param inherit + * boolean determining whether or not we're in inherit mode + */ + getStyleProperties: function CSS_getStyleProperties(aNode, aRules, aUsedProps, aInherit) + { + let properties = this.parseCSSProperties(aNode.style, aInherit); + + this.sortProperties(properties); + this.markOverriddenProperties(properties, aUsedProps, aInherit); + + if (properties.length) { + aRules.push({rule: aNode, selector: "element.style", + properties: properties, inherited: aInherit}); + } + }, + + /** + * Get properties for a given rule. + * + * @param aRule + * A Rule from a stylesheet. + */ + getRuleProperties: function CSS_getRuleProperties(aRule) + { + let style = aRule.style; + return this.parseCSSProperties(style); + }, + + /** + * Recursively get rules for an element's parents and add them to the + * sections array. + * + * @param aNode + * an element in a DOM tree. + * @param sections + * an array of sections + * @param usedProps + * Object of arrays keyed by property name. + */ + getInheritedRules: function CSS_getInheritedRules(aNode, aSections, aUsedProps) + { + let parent = aNode.parentNode; + if (parent && parent.nodeType == 1) { + this.getInheritedRules(parent, aSections, aUsedProps); + + let rules = []; + this.getElementRules(parent, rules, aUsedProps, true); + + if (rules.length) { + aSections.unshift({element: parent, rules: rules}); + } + } + }, + + /** + * Get the CSS style rules for a given node in the DOM and append them to the + * rules array. + * + * @param aNode + * an element in the DOM tree. + * @param aRules + * an array of rules. + * @param aUsedProps + * Object of arrays keyed by property name. + * @param aInherit + * boolean indicating whether we are in an inherited mode or not + */ + getElementRules: function CSS_getElementRules(aNode, aRules, aUsedProps, aInherit) + { + let inspectedRules; + + try { + inspectedRules = this.domUtils.getCSSStyleRules(aNode); + } catch (ex) { + Services.console.logStringMessage(ex); + } + + if (!inspectedRules) + return; + + for (let i = 0; i < inspectedRules.Count(); ++i) { + let rule = inspectedRules.GetElementAt(i); + let href = rule.parentStyleSheet.href; + + if (!href) { + // Null href means inline style. + href = aNode.ownerDocument.location.href; + } + + let isSystemSheet = this.isSystemStyleSheet(rule.parentStyleSheet); + + if (isSystemSheet) + continue; + + let properties = this.getRuleProperties(rule, aInherit); + if (aInherit && !properties.length) + continue; + + let line = this.domUtils.getRuleLine(rule); + let ruleId = rule.selectorText + " " + href + " (" + line + ")"; + + let sourceLink = "view-source:" + href + "#" + line; + + this.markOverriddenProperties(properties, aUsedProps, aInherit); + + aRules.unshift( + {rule: rule, + id: ruleId, + selector: rule.selectorText, + properties: properties, + inherited: aInherit, + sourceLink: sourceLink, + isSystemSheet: isSystemSheet}); + } + + if (aNode.style) { + this.getStyleProperties(aNode, aRules, aUsedProps, aInherit); + } + }, +}; + diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index 38db5cd0c832..e8bc6f32657d 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -183,6 +183,8 @@ _BROWSER_FILES = \ browser_inspector_initialization.js \ browser_inspector_treeSelection.js \ browser_inspector_highlighter.js \ + browser_inspector_stylePanel.js \ + browser_inspector_domPanel.js \ browser_inspector_iframeTest.js \ browser_inspector_scrolling.js \ browser_inspector_store.js \ diff --git a/browser/base/content/test/browser_inspector_domPanel.js b/browser/base/content/test/browser_inspector_domPanel.js new file mode 100644 index 000000000000..4d3f80fcd7c2 --- /dev/null +++ b/browser/base/content/test/browser_inspector_domPanel.js @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Inspector DOM Panel Tests. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rob Campbell + * Mihai Șucan + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +let doc; +let testGen; +let newProperty; + +function createDocument() +{ + doc.body.innerHTML = '
\n' + + '

Some header text

\n' + + '

hi.

\n' + + '

I am a test-case. This text exists ' + + 'solely to provide some things to ' + + 'highlight and count ' + + 'DOM list-items in the box at right. If you are reading this, ' + + 'you should go do something else instead. Maybe read a book. Or better ' + + 'yet, write some test-cases for another bit of code. ' + + 'Maybe more inspector test-cases!

\n' + + '

end transmission

\n' + + '
'; + doc.title = "Inspector DOM Test"; + Services.obs.addObserver(runDOMTests, "inspector-opened", false); + InspectorUI.openInspectorUI(); +} + +function nodeGenerator() +{ + let body = doc.body; + newProperty = "rand" + Date.now(); + body[newProperty] = Math.round(Math.random() * 100); + InspectorUI.inspectNode(body); + yield; + + let h1 = doc.querySelector("h1"); + newProperty = "rand2" + Date.now(); + h1[newProperty] = "test" + Math.random(); + InspectorUI.inspectNode(h1); + yield; + + let first = doc.getElementById("first"); + newProperty = "rand3" + Date.now(); + first[newProperty] = null; + InspectorUI.inspectNode(first); + yield; + + let closing = doc.getElementById("closing"); + newProperty = "bazbaz" + Date.now(); + closing[newProperty] = false; + InspectorUI.inspectNode(closing); + yield; +} + +function runDOMTests() +{ + InspectorUI._log("runDOMtests"); + Services.obs.removeObserver(runDOMTests, "inspector-opened", false); + document.addEventListener("popupshown", performTestComparisons, false); + InspectorUI.stopInspecting(); + testGen = nodeGenerator(); + testGen.next(); +} + +function findInDOMPanel(aString) +{ + let treeView = InspectorUI.domTreeView; + let row; + + for (let i = 0, n = treeView.rowCount; i < n; i++) { + row = treeView.getCellText(i, 0); + if (row && row.indexOf(aString) != -1) { + return true; + } + } + + return false; +} + +function performTestComparisons(evt) +{ + InspectorUI._log("performTestComparisons"); + if (evt.target.id != "highlighter-panel") + return true; + + let selection = InspectorUI.selection; + + ok(selection, "selection"); + ok(InspectorUI.isDOMPanelOpen, "DOM panel is open?"); + ok(InspectorUI.highlighter.isHighlighting, "panel is highlighting"); + + let value = selection[newProperty]; + if (typeof value == "string") { + value = '"' + value + '"'; + } + + ok(findInDOMPanel(newProperty + ': ' + value), + "domPanel shows the correct value for " + newProperty); + + ok(findInDOMPanel('tagName: "' + selection.tagName + '"'), + "domPanel shows the correct tagName"); + + if (selection.id) { + ok(findInDOMPanel('id: "' + selection.id + '"'), + "domPanel shows the correct id"); + } + + try { + testGen.next(); + } catch(StopIteration) { + document.removeEventListener("popupshown", performTestComparisons, false); + finishUp(); + } +} + +function finishUp() { + InspectorUI.closeInspectorUI(); + gBrowser.removeCurrentTab(); + finish(); +} + +function test() +{ + waitForExplicitFinish(); + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function() { + gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); + doc = content.document; + waitForFocus(createDocument, content); + }, true); + + content.location = "data:text/html,basic tests for inspector"; +} + diff --git a/browser/base/content/test/browser_inspector_highlighter.js b/browser/base/content/test/browser_inspector_highlighter.js index 08bd1f624ac9..82b2cab9fac5 100644 --- a/browser/base/content/test/browser_inspector_highlighter.js +++ b/browser/base/content/test/browser_inspector_highlighter.js @@ -102,7 +102,6 @@ function performTestComparisons(evt) function finishUp() { InspectorUI.closeInspectorUI(); - ok(!InspectorUI.highlighter.isHighlighting, "panel is not highlighting"); gBrowser.removeCurrentTab(); finish(); } diff --git a/browser/base/content/test/browser_inspector_initialization.js b/browser/base/content/test/browser_inspector_initialization.js index b439c71ccb5a..b56dcba65240 100644 --- a/browser/base/content/test/browser_inspector_initialization.js +++ b/browser/base/content/test/browser_inspector_initialization.js @@ -54,12 +54,16 @@ function runInspectorTests() is(InspectorUI.treeIFrame, iframe, "Inspector IFrame matches"); ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); + ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); + ok(InspectorUI.isDOMPanelOpen, "Inspector DOM Panel is open"); InspectorUI.closeInspectorUI(); } function finishInspectorTests() { Services.obs.removeObserver(finishInspectorTests, "inspector-closed", false); + ok(!InspectorUI.isDOMPanelOpen, "Inspector DOM Panel is closed"); + ok(!InspectorUI.isStylePanelOpen, "Inspector Style Panel is closed"); ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed"); ok(!InspectorUI.inspecting, "Inspector is not highlighting"); gBrowser.removeCurrentTab(); diff --git a/browser/base/content/test/browser_inspector_stylePanel.js b/browser/base/content/test/browser_inspector_stylePanel.js new file mode 100644 index 000000000000..d4d2e7d165f2 --- /dev/null +++ b/browser/base/content/test/browser_inspector_stylePanel.js @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Inspector Style Panel Tests. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rob Campbell (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +let doc; +let spans; +let testGen; + +function createDocument() +{ + doc.body.innerHTML = '
\n' + + '

Some header text

\n' + + '

hi.

\n' + + '

I am a test-case. This text exists ' + + 'solely to provide some things to ' + + 'highlight and count ' + + 'style list-items in the box at right. If you are reading this, ' + + 'you should go do something else instead. Maybe read a book. Or better ' + + 'yet, write some test-cases for another bit of code. ' + + 'Maybe more inspector test-cases!

\n' + + '

end transmission

\n' + + '
'; + doc.title = "Inspector Style Test"; + setupStyleTests(); +} + +function setupStyleTests() +{ + spans = doc.querySelectorAll("span"); + ok(spans, "captain, we have the spans"); + Services.obs.addObserver(runStyleTests, "inspector-opened", false); + InspectorUI.openInspectorUI(); +} + +function spanGenerator() +{ + for (var i = 0; i < spans.length; ++i) { + InspectorUI.inspectNode(spans[i]); + yield; + } +} + +function runStyleTests() +{ + Services.obs.removeObserver(runStyleTests, "inspector-opened", false); + document.addEventListener("popupshown", performTestComparisons, false); + InspectorUI.stopInspecting(); + testGen = spanGenerator(); + testGen.next(); +} + +function performTestComparisons(evt) +{ + if (evt.target.id != "highlighter-panel") + return true; + + ok(InspectorUI.selection, "selection"); + ok(InspectorUI.isStylePanelOpen, "style panel is open?"); + ok(InspectorUI.highlighter.isHighlighting, "panel is highlighting"); + ok(InspectorUI.styleBox.itemCount > 0, "styleBox has items"); + + try { + testGen.next(); + } catch(StopIteration) { + document.removeEventListener("popupshown", performTestComparisons, false); + finishUp(); + } +} + +function finishUp() { + InspectorUI.closeInspectorUI(); + gBrowser.removeCurrentTab(); + finish(); +} + +function test() +{ + waitForExplicitFinish(); + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function() { + gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); + doc = content.document; + waitForFocus(createDocument, content); + }, true); + + content.location = "data:text/html,basic tests for inspector"; +} + diff --git a/browser/base/content/test/browser_inspector_tab_switch.js b/browser/base/content/test/browser_inspector_tab_switch.js index d9793a9ae8e8..7ec32249d39c 100644 --- a/browser/base/content/test/browser_inspector_tab_switch.js +++ b/browser/base/content/test/browser_inspector_tab_switch.js @@ -60,6 +60,7 @@ function inspectorUIOpen1() // Make sure the inspector is open. ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); + ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); ok(!InspectorStore.isEmpty(), "InspectorStore is not empty"); is(InspectorStore.length, 1, "InspectorStore.length = 1"); @@ -71,7 +72,6 @@ function inspectorUIOpen1() // Open the second tab. tab2 = gBrowser.addTab(); gBrowser.selectedTab = tab2; - gBrowser.selectedBrowser.addEventListener("load", function(evt) { gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true); @@ -86,13 +86,12 @@ function inspectorTabOpen2() // Make sure the inspector is closed. ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.isPanelOpen, "Inspector Tree Panel is closed"); + ok(!InspectorUI.isStylePanelOpen, "Inspector Style Panel is closed"); is(InspectorStore.length, 1, "InspectorStore.length = 1"); // Activate the inspector again. - executeSoon(function() { Services.obs.addObserver(inspectorUIOpen2, "inspector-opened", false); - InspectorUI.openInspectorUI(); - }); + InspectorUI.openInspectorUI(); } function inspectorUIOpen2() @@ -102,6 +101,7 @@ function inspectorUIOpen2() // Make sure the inspector is open. ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); + ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); is(InspectorStore.length, 2, "InspectorStore.length = 2"); // Disable highlighting. @@ -109,10 +109,8 @@ function inspectorUIOpen2() ok(!InspectorUI.inspecting, "Inspector is not highlighting"); // Switch back to tab 1. - executeSoon(function() { - Services.obs.addObserver(inspectorFocusTab1, "inspector-opened", false); - gBrowser.selectedTab = tab1; - }); + Services.obs.addObserver(inspectorFocusTab1, "inspector-opened", false); + gBrowser.selectedTab = tab1; } function inspectorFocusTab1() @@ -122,6 +120,7 @@ function inspectorFocusTab1() // Make sure the inspector is still open. ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); + ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); is(InspectorStore.length, 2, "InspectorStore.length = 2"); is(InspectorUI.selection, div, "selection matches the div element"); @@ -137,6 +136,7 @@ function inspectorFocusTab2() // Make sure the inspector is still open. ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); + ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); is(InspectorStore.length, 2, "InspectorStore.length = 2"); isnot(InspectorUI.selection, div, "selection does not match the div element"); @@ -154,6 +154,7 @@ function inspectorTabUnload1(evt) // Make sure the Inspector is still open and that the state is correct. ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); + ok(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); is(InspectorStore.length, 1, "InspectorStore.length = 1"); InspectorUI.closeInspectorUI(); diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd index 9e7ef52a99d6..bc4dd094377c 100644 --- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -212,6 +212,19 @@ can reach it easily. --> + + + + + + + + + + diff --git a/browser/locales/en-US/chrome/browser/inspector.properties b/browser/locales/en-US/chrome/browser/inspector.properties new file mode 100644 index 000000000000..70225d5efe82 --- /dev/null +++ b/browser/locales/en-US/chrome/browser/inspector.properties @@ -0,0 +1,16 @@ +# LOCALIZATION NOTE (style.selectorLabel): Used in the Inspector style panel +# to label a CSS Selector. +style.selectorLabel=Selector + +# LOCALIZATION NOTE (style.inheritedFrom): used in Style panel in +# inspector. Describes which tagname[#id] the properties are inherited from. +style.inheritedFrom=Inherited from: #1 + +# LOCALIZATION NOTE (style.styleItemLabel): used in Style panel in inspector. +# Used for construction of list items, #1 = label, #2 = content. +style.styleItemLabel=#1: #2 + +# LOCALIZATION NOTE (object.objectPanelTitle): used in the Object Panel in the +# Inspector tool. There's also inspectObjectButton in browser.dtd for the +# toolbar button which allows users to open/close the Object panel. +object.objectPanelTitle=Object diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn index 50ee15f61fac..97599b5d8a38 100644 --- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -14,6 +14,7 @@ * locale/browser/browser.dtd (%chrome/browser/browser.dtd) locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd) locale/browser/browser.properties (%chrome/browser/browser.properties) + locale/browser/inspector.properties (%chrome/browser/inspector.properties) locale/browser/scratchpad.properties (%chrome/browser/scratchpad.properties) locale/browser/scratchpad.dtd (%chrome/browser/scratchpad.dtd) locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd) From fcf33de8c18119b2953514073e0ee0dce0d9313b Mon Sep 17 00:00:00 2001 From: Panos Astithas Date: Thu, 19 May 2011 17:15:36 -0300 Subject: [PATCH 008/145] Bug 644419 - Console should have user-settable log limits for each message category; f=rcampbell r=rcampbell,gavin.sharp --- browser/app/profile/firefox.js | 7 + .../console/hudservice/HUDService.jsm | 29 ++-- .../hudservice/tests/browser/Makefile.in | 2 + ...rowser_webconsole_bug_585237_line_limit.js | 10 +- ...wser_webconsole_bug_613642_prune_scroll.js | 10 +- ...browser_webconsole_bug_642108_pruneTest.js | 4 +- ...rowser_webconsole_bug_644419_log_limits.js | 154 ++++++++++++++++++ .../browser/test-bug-644419-log-limits.html | 20 +++ 8 files changed, 208 insertions(+), 28 deletions(-) create mode 100644 toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_644419_log_limits.js create mode 100644 toolkit/components/console/hudservice/tests/browser/test-bug-644419-log-limits.html diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 902ad847d3ba..0e27a6e4fc05 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1009,6 +1009,13 @@ pref("devtools.hud.height", 0); // window - in a separate window/popup panel. pref("devtools.webconsole.position", "above"); +// The number of lines that are displayed in the web console for the Net, +// CSS, JS and Web Developer categories. +pref("devtools.hud.loglimit.network", 200); +pref("devtools.hud.loglimit.cssparser", 200); +pref("devtools.hud.loglimit.exception", 200); +pref("devtools.hud.loglimit.console", 200); + // Whether the character encoding menu is under the main Firefox button. This // preference is a string so that localizers can alter it. pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties"); diff --git a/toolkit/components/console/hudservice/HUDService.jsm b/toolkit/components/console/hudservice/HUDService.jsm index e1cac1e0fd84..62026c38a311 100644 --- a/toolkit/components/console/hudservice/HUDService.jsm +++ b/toolkit/components/console/hudservice/HUDService.jsm @@ -128,9 +128,9 @@ const NEW_GROUP_DELAY = 5000; // search. const SEARCH_DELAY = 200; -// The number of lines that are displayed in the console output by default. -// The user can change this number by adjusting the hidden -// "devtools.hud.loglimit" preference. +// The number of lines that are displayed in the console output by default, for +// each category. The user can change this number by adjusting the hidden +// "devtools.hud.loglimit.{network,cssparser,exception,console}" preferences. const DEFAULT_LOG_LIMIT = 200; // The various categories of messages. We start numbering at zero so we can @@ -1193,22 +1193,24 @@ NetworkPanel.prototype = //// Private utility functions for the HUD service /** - * Destroys lines of output if more lines than the allowed log limit are - * present. + * Ensures that the number of message nodes of type aCategory don't exceed that + * category's line limit by removing old messages as needed. * * @param nsIDOMNode aConsoleNode * The DOM node (richlistbox aka outputNode) that holds the output of the * console. + * @param integer aCategory + * The category of message nodes to limit. * @return number * The current user-selected log limit. */ -function pruneConsoleOutputIfNecessary(aConsoleNode) +function pruneConsoleOutputIfNecessary(aConsoleNode, aCategory) { // Get the log limit, either from the pref or from the constant. let logLimit; try { - let prefBranch = Services.prefs.getBranch("devtools.hud."); - logLimit = prefBranch.getIntPref("loglimit"); + let prefName = CATEGORY_CLASS_FRAGMENTS[aCategory]; + logLimit = Services.prefs.getIntPref("devtools.hud.loglimit." + prefName); } catch (e) { logLimit = DEFAULT_LOG_LIMIT; } @@ -1219,7 +1221,8 @@ function pruneConsoleOutputIfNecessary(aConsoleNode) let hudRef = HUDService.getHudReferenceForOutputNode(aConsoleNode); // Prune the nodes. - let messageNodes = aConsoleNode.querySelectorAll(".hud-msg-node"); + let messageNodes = aConsoleNode.querySelectorAll(".webconsole-msg-" + + CATEGORY_CLASS_FRAGMENTS[aCategory]); let removeNodes = messageNodes.length - logLimit; for (let i = 0; i < removeNodes; i++) { if (messageNodes[i].classList.contains("webconsole-msg-cssparser")) { @@ -4183,7 +4186,7 @@ function JSPropertyProvider(aScope, aInputValue) for (let i = 0; i < properties.length; i++) { let prop = properties[i].trim(); - // If obj is undefined or null, then there is no change to run completion + // If obj is undefined or null, then there is no chance to run completion // on it. Exit here. if (typeof obj === "undefined" || obj === null) { return null; @@ -4201,7 +4204,7 @@ function JSPropertyProvider(aScope, aInputValue) matchProp = properties[0].trimLeft(); } - // If obj is undefined or null, then there is no change to run + // If obj is undefined or null, then there is no chance to run // completion on it. Exit here. if (typeof obj === "undefined" || obj === null) { return null; @@ -4515,8 +4518,6 @@ JSTerm.prototype = { get codeInputString() { - // TODO: filter the input for windows line breaks, conver to unix - // see bug 572812 return this.inputNode.value; }, @@ -5810,7 +5811,7 @@ ConsoleUtils = { HUDService.regroupOutput(outputNode); - if (pruneConsoleOutputIfNecessary(outputNode) == 0) { + if (pruneConsoleOutputIfNecessary(outputNode, aNode.category) == 0) { // We can't very well scroll to make the message node visible if the log // limit is zero and the node was destroyed in the first place. return; diff --git a/toolkit/components/console/hudservice/tests/browser/Makefile.in b/toolkit/components/console/hudservice/tests/browser/Makefile.in index b72b3799fd71..3e03cd95cb50 100644 --- a/toolkit/components/console/hudservice/tests/browser/Makefile.in +++ b/toolkit/components/console/hudservice/tests/browser/Makefile.in @@ -135,6 +135,7 @@ _BROWSER_TEST_FILES = \ browser_webconsole_bug_585956_console_trace.js \ browser_webconsole_bug_595223_file_uri.js \ browser_webconsole_bug_632275_getters_document_width.js \ + browser_webconsole_bug_644419_log_limits.js \ browser_webconsole_bug_646025_console_file_location.js \ browser_webconsole_position_ui.js \ browser_webconsole_bug_642615_autocomplete.js \ @@ -207,6 +208,7 @@ _BROWSER_TEST_PAGES = \ test-bug-621644-jsterm-dollar.html \ test-bug-632347-iterators-generators.html \ test-bug-585956-console-trace.html \ + test-bug-644419-log-limits.html \ test-bug-632275-getters.html \ test-bug-646025-console-file-location.html \ test-file-location.js \ diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585237_line_limit.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585237_line_limit.js index f2363ce88932..d2fa906d2e72 100644 --- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585237_line_limit.js +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_585237_line_limit.js @@ -28,8 +28,8 @@ function testLineLimit() { let console = browser.contentWindow.wrappedJSObject.console; hudBox = HUDService.getHeadsUpDisplay(hudId); - let prefBranch = Services.prefs.getBranch("devtools.hud."); - prefBranch.setIntPref("loglimit", 20); + let prefBranch = Services.prefs.getBranch("devtools.hud.loglimit."); + prefBranch.setIntPref("console", 20); for (let i = 0; i < 20; i++) { console.log("foo #" + i); // must change message to prevent repeats @@ -42,7 +42,7 @@ function testLineLimit() { is(countMessageNodes(), 20, "there are still 20 message nodes in the " + "output when adding one more"); - prefBranch.setIntPref("loglimit", 30); + prefBranch.setIntPref("console", 30); for (let i = 0; i < 20; i++) { console.log("boo #" + i); // must change message to prevent repeats } @@ -50,12 +50,12 @@ function testLineLimit() { is(countMessageNodes(), 30, "there are 30 message nodes in the output " + "when the log limit is set to 30"); - prefBranch.setIntPref("loglimit", 0); + prefBranch.setIntPref("console", 0); console.log("baz"); is(countMessageNodes(), 0, "there are no message nodes in the output when " + "the log limit is set to zero"); - prefBranch.clearUserPref("loglimit"); + prefBranch.clearUserPref("console"); prefBranch = console = null; finishTest(); } diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_613642_prune_scroll.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_613642_prune_scroll.js index 0e47d47dd2ac..f2964ee64a25 100644 --- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_613642_prune_scroll.js +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_613642_prune_scroll.js @@ -15,13 +15,9 @@ function tabLoad(aEvent) { let hudId = HUDService.getHudIdByWindow(content); let hud = HUDService.hudReferences[hudId]; let outputNode = hud.outputNode; - let oldPref = 200; - try { - oldPref = Services.prefs.getIntPref("devtools.hud.loglimit"); - } - catch (ex) { } + let oldPref = Services.prefs.getIntPref("devtools.hud.loglimit.console"); - Services.prefs.setIntPref("devtools.hud.loglimit", 140); + Services.prefs.setIntPref("devtools.hud.loglimit.console", 140); let scrollBoxElement = outputNode.scrollBoxObject.element; let boxObject = outputNode.scrollBoxObject; @@ -57,7 +53,7 @@ function tabLoad(aEvent) { isnot(outputNode.firstChild, firstNode, "first message removed"); - Services.prefs.setIntPref("devtools.hud.loglimit", oldPref); + Services.prefs.setIntPref("devtools.hud.loglimit.console", oldPref); finishTest(); } diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642108_pruneTest.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642108_pruneTest.js index ed4957b69489..568857f4b999 100644 --- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642108_pruneTest.js +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_642108_pruneTest.js @@ -44,8 +44,8 @@ function populateConsole(aHudRef) { } function testCSSPruning() { - let prefBranch = Services.prefs.getBranch("devtools.hud."); - prefBranch.setIntPref("loglimit", LOG_LIMIT); + let prefBranch = Services.prefs.getBranch("devtools.hud.loglimit."); + prefBranch.setIntPref("cssparser", LOG_LIMIT); browser.removeEventListener("DOMContentLoaded",testCSSPruning, false); diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_644419_log_limits.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_644419_log_limits.js new file mode 100644 index 000000000000..5dbdae3065d5 --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_644419_log_limits.js @@ -0,0 +1,154 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Tests that the Web Console limits the number of lines displayed according to +// the limit set for each category. + +const TEST_URI = "http://example.com/browser/toolkit/components/console/" + + "hudservice/tests/browser/test-bug-644419-log-limits.html"; + +var gOldPref, gHudId; + +function test() { + addTab("data:text/html,Web Console test for bug 644419: Console should " + + "have user-settable log limits for each message category"); + browser.addEventListener("load", onLoad, true); +} + +function onLoad(aEvent) { + browser.removeEventListener(aEvent.type, arguments.callee, true); + + openConsole(); + + gHudId = HUDService.getHudIdByWindow(content); + browser.addEventListener("load", testWebDevLimits, true); + content.location = TEST_URI; +} + +function testWebDevLimits(aEvent) { + browser.removeEventListener(aEvent.type, arguments.callee, true); + gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.console"); + Services.prefs.setIntPref("devtools.hud.loglimit.console", 10); + + let hud = HUDService.hudReferences[gHudId]; + outputNode = hud.outputNode; + + executeSoon(function() { + // Find the sentinel entry. + findLogEntry("bar is not defined"); + + // Fill the log with Web Developer errors. + for (let i = 0; i < 11; i++) { + hud.console.log("test message " + i); + } + testLogEntry(outputNode, "test message 0", "first message is pruned", false, true); + findLogEntry("test message 1"); + // Check if the sentinel entry is still there. + findLogEntry("bar is not defined"); + + Services.prefs.setIntPref("devtools.hud.loglimit.console", gOldPref); + testJsLimits(); + }); +} + +function testJsLimits(aEvent) { + HUDService.clearDisplay(gHudId); + gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.exception"); + Services.prefs.setIntPref("devtools.hud.loglimit.exception", 10); + + let hud = HUDService.hudReferences[gHudId]; + outputNode = hud.outputNode; + hud.console.log("testing JS limits"); + + // Find the sentinel entry. + findLogEntry("testing JS limits"); + // Fill the log with JS errors. + let head = content.document.getElementsByTagName("head")[0]; + for (let i = 0; i < 11; i++) { + var script = content.document.createElement("script"); + script.text = "fubar" + i + ".bogus(6);"; + head.insertBefore(script, head.firstChild); + } + + executeSoon(function() { + testLogEntry(outputNode, "fubar0 is not defined", "first message is pruned", false, true); + findLogEntry("fubar1 is not defined"); + // Check if the sentinel entry is still there. + findLogEntry("testing JS limits"); + + Services.prefs.setIntPref("devtools.hud.loglimit.exception", gOldPref); + testNetLimits(); + }); +} + +var gCounter, gImage; + +function testNetLimits(aEvent) { + HUDService.clearDisplay(gHudId); + gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.network"); + Services.prefs.setIntPref("devtools.hud.loglimit.network", 10); + + let hud = HUDService.hudReferences[gHudId]; + outputNode = hud.outputNode; + hud.console.log("testing Net limits"); + + // Find the sentinel entry. + findLogEntry("testing Net limits"); + // Fill the log with network messages. + gCounter = 0; + loadImage(); +} + +function loadImage() { + if (gCounter < 11) { + let body = content.document.getElementsByTagName("body")[0]; + gImage && gImage.removeEventListener("load", loadImage, true); + gImage = content.document.createElement("img"); + gImage.src = "test-image.png?_fubar=" + gCounter; + body.insertBefore(gImage, body.firstChild); + gImage.addEventListener("load", loadImage, true); + gCounter++; + return; + } + is(gCounter, 11, "loaded 11 files"); + testLogEntry(outputNode, "test-image.png?_fubar=0", "first message is pruned", false, true); + findLogEntry("test-image.png?_fubar=1"); + // Check if the sentinel entry is still there. + findLogEntry("testing Net limits"); + + Services.prefs.setIntPref("devtools.hud.loglimit.network", gOldPref); + testCssLimits(); +} + +function testCssLimits(aEvent) { + HUDService.clearDisplay(gHudId); + gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.cssparser"); + Services.prefs.setIntPref("devtools.hud.loglimit.cssparser", 10); + + let hud = HUDService.hudReferences[gHudId]; + outputNode = hud.outputNode; + hud.console.log("testing CSS limits"); + + // Find the sentinel entry. + findLogEntry("testing CSS limits"); + + // Fill the log with CSS errors. + let body = content.document.getElementsByTagName("body")[0]; + for (let i = 0; i < 11; i++) { + var div = content.document.createElement("div"); + div.setAttribute("style", "-moz-foobar" + i + ": 42;"); + body.insertBefore(div, body.firstChild); + } + executeSoon(function() { + testLogEntry(outputNode, "Unknown property '-moz-foobar0'", "first message is pruned", false, true); + findLogEntry("Unknown property '-moz-foobar1'"); + // Check if the sentinel entry is still there. + findLogEntry("testing CSS limits"); + + Services.prefs.setIntPref("devtools.hud.loglimit.cssparser", gOldPref); + finishTest(); + }); +} diff --git a/toolkit/components/console/hudservice/tests/browser/test-bug-644419-log-limits.html b/toolkit/components/console/hudservice/tests/browser/test-bug-644419-log-limits.html new file mode 100644 index 000000000000..7bff38329636 --- /dev/null +++ b/toolkit/components/console/hudservice/tests/browser/test-bug-644419-log-limits.html @@ -0,0 +1,20 @@ + + + + + Test for bug 644419: console log limits + + +

Test for bug 644419: Console should have user-settable log limits for + each message category

+ + + + + From 6820b80e95c4a2260485eddb8222667e81168939 Mon Sep 17 00:00:00 2001 From: Rob Campbell Date: Thu, 19 May 2011 18:10:41 -0300 Subject: [PATCH 009/145] Bug 657136 - Rename top-level Context menu to something less confusing in Scratchpad; r=mihai.sucan --- browser/base/content/scratchpad.js | 16 ++++++------- browser/base/content/scratchpad.xul | 18 +++++++------- ...ratchpad_bug_646070_chrome_context_pref.js | 4 ++-- .../test/browser_scratchpad_contexts.js | 8 +++---- .../test/browser_scratchpad_initialization.js | 4 ++-- .../content/test/browser_scratchpad_ui.js | 2 +- .../en-US/chrome/browser/scratchpad.dtd | 24 ++++++++++++++++++- 7 files changed, 49 insertions(+), 27 deletions(-) diff --git a/browser/base/content/scratchpad.js b/browser/base/content/scratchpad.js index 054317b00c0f..5facb97381ad 100644 --- a/browser/base/content/scratchpad.js +++ b/browser/base/content/scratchpad.js @@ -58,7 +58,7 @@ Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource:///modules/PropertyPanel.jsm"); const SCRATCHPAD_CONTEXT_CONTENT = 1; -const SCRATCHPAD_CONTEXT_CHROME = 2; +const SCRATCHPAD_CONTEXT_BROWSER = 2; const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/scratchpad.xul"; const SCRATCHPAD_L10N = "chrome://browser/locale/scratchpad.properties"; const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no"; @@ -75,7 +75,7 @@ var Scratchpad = { * Possible values: * - SCRATCHPAD_CONTEXT_CONTENT to execute code in the context of the current * tab content window object. - * - SCRATCHPAD_CONTEXT_CHROME to execute code in the context of the + * - SCRATCHPAD_CONTEXT_BROWSER to execute code in the context of the * currently active chrome window object. */ executionContext: SCRATCHPAD_CONTEXT_CONTENT, @@ -556,7 +556,7 @@ var Scratchpad = { setContentContext: function SP_setContentContext() { let content = document.getElementById("sp-menu-content"); - document.getElementById("sp-menu-chrome").removeAttribute("checked"); + document.getElementById("sp-menu-browser").removeAttribute("checked"); content.setAttribute("checked", true); this.statusbarStatus.label = content.getAttribute("label"); this.executionContext = SCRATCHPAD_CONTEXT_CONTENT; @@ -566,13 +566,13 @@ var Scratchpad = { /** * Set the current execution context to be the most recent chrome window. */ - setChromeContext: function SP_setChromeContext() + setBrowserContext: function SP_setBrowserContext() { - let chrome = document.getElementById("sp-menu-chrome"); + let chrome = document.getElementById("sp-menu-browser"); document.getElementById("sp-menu-content").removeAttribute("checked"); chrome.setAttribute("checked", true); this.statusbarStatus.label = chrome.getAttribute("label"); - this.executionContext = SCRATCHPAD_CONTEXT_CHROME; + this.executionContext = SCRATCHPAD_CONTEXT_BROWSER; this.resetContext(); }, @@ -604,10 +604,10 @@ var Scratchpad = { */ onLoad: function SP_onLoad() { - let chromeContextMenu = document.getElementById("sp-menu-chrome"); + let chromeContextMenu = document.getElementById("sp-menu-browser"); let errorConsoleMenu = document.getElementById("sp-menu-errorConsole"); let errorConsoleCommand = document.getElementById("sp-cmd-errorConsole"); - let chromeContextCommand = document.getElementById("sp-cmd-chromeContext"); + let chromeContextCommand = document.getElementById("sp-cmd-browserContext"); let chrome = Services.prefs.getBoolPref(DEVTOOLS_CHROME_ENABLED); if (chrome) { diff --git a/browser/base/content/scratchpad.xul b/browser/base/content/scratchpad.xul index 656954756e96..6ef1d46a42bc 100644 --- a/browser/base/content/scratchpad.xul +++ b/browser/base/content/scratchpad.xul @@ -74,7 +74,7 @@ - + @@ -256,20 +256,20 @@
- - + + - + + + + + - + @@ -306,21 +311,21 @@ - + - + diff --git a/browser/base/content/test/browser_scratchpad_contexts.js b/browser/base/content/test/browser_scratchpad_contexts.js index 79d4e7b1c994..3ca1103ddec4 100644 --- a/browser/base/content/test/browser_scratchpad_contexts.js +++ b/browser/base/content/test/browser_scratchpad_contexts.js @@ -54,7 +54,7 @@ function runTests() ok(!content.wrappedJSObject.foobarBug636725, "no content.foobarBug636725"); - sp.execute(); + sp.run(); is(content.wrappedJSObject.foobarBug636725, "aloha", "content.foobarBug636725 has been set"); @@ -77,37 +77,37 @@ function runTests() ok(!window.foobarBug636725, "no window.foobarBug636725"); - sp.execute(); + sp.run(); is(window.foobarBug636725, "aloha2", "window.foobarBug636725 has been set"); sp.textbox.value = "window.gBrowser"; - is(typeof sp.execute()[1].addTab, "function", + is(typeof sp.run()[1].addTab, "function", "chrome context has access to chrome objects"); // Check that the sandbox is cached. sp.textbox.value = "typeof foobarBug636725cache;"; - is(sp.execute()[1], "undefined", "global variable does not exist"); + is(sp.run()[1], "undefined", "global variable does not exist"); sp.textbox.value = "var foobarBug636725cache = 'foo';"; - sp.execute(); + sp.run(); sp.textbox.value = "typeof foobarBug636725cache;"; - is(sp.execute()[1], "string", + is(sp.run()[1], "string", "global variable exists across two different executions"); sp.resetContext(); - is(sp.execute()[1], "undefined", + is(sp.run()[1], "undefined", "global variable no longer exists after calling resetContext()"); sp.textbox.value = "var foobarBug636725cache2 = 'foo';"; - sp.execute(); + sp.run(); sp.textbox.value = "typeof foobarBug636725cache2;"; - is(sp.execute()[1], "string", + is(sp.run()[1], "string", "global variable exists across two different executions"); sp.setContentContext(); @@ -115,7 +115,7 @@ function runTests() is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CONTENT, "executionContext is content"); - is(sp.execute()[1], "undefined", + is(sp.run()[1], "undefined", "global variable no longer exists after changing the context"); gScratchpadWindow.close(); diff --git a/browser/base/content/test/browser_scratchpad_execute_print.js b/browser/base/content/test/browser_scratchpad_execute_print.js index 91aa8d1f23b9..d74b84758845 100644 --- a/browser/base/content/test/browser_scratchpad_execute_print.js +++ b/browser/base/content/test/browser_scratchpad_execute_print.js @@ -17,7 +17,7 @@ function test() gScratchpadWindow.addEventListener("load", runTests, false); }, true); - content.location = "data:text/html,

test execute() and print() in Scratchpad"; + content.location = "data:text/html,

test run() and display() in Scratchpad"; } function runTests() @@ -31,7 +31,7 @@ function runTests() ok(sp.textbox, "textbox exists"); sp.textbox.value = "++window.foobarBug636725"; - let exec = sp.execute(); + let exec = sp.run(); is(exec[0], sp.textbox.value, "execute()[0] is correct"); is(exec[1], content.wrappedJSObject.foobarBug636725, "execute()[1] is correct"); @@ -42,7 +42,7 @@ function runTests() is(content.wrappedJSObject.foobarBug636725, 2, "execute() updated window.foobarBug636725"); - sp.print(); + sp.display(); is(content.wrappedJSObject.foobarBug636725, 3, "print() updated window.foobarBug636725"); @@ -69,7 +69,7 @@ function runTests() is(sp.textbox.selectionStart, 0, "selectionStart is 0"); is(sp.textbox.selectionEnd, 29, "selectionEnd is 29"); - exec = sp.execute(); + exec = sp.run(); is(exec[0], "window.foobarBug636725 = 'a';", "execute()[0] is correct"); @@ -88,7 +88,7 @@ function runTests() sp.selectRange(0, 22); - sp.print(); + sp.display(); is(content.wrappedJSObject.foobarBug636725, "a", "print() worked for the selected range"); diff --git a/browser/base/content/test/browser_scratchpad_initialization.js b/browser/base/content/test/browser_scratchpad_initialization.js index 067d1973e25e..ce4c9b9c6d5d 100644 --- a/browser/base/content/test/browser_scratchpad_initialization.js +++ b/browser/base/content/test/browser_scratchpad_initialization.js @@ -28,9 +28,9 @@ function runTests() let sp = gScratchpadWindow.Scratchpad; ok(sp, "Scratchpad object exists in new window"); - is(typeof sp.execute, "function", "Scratchpad.execute() exists"); + is(typeof sp.run, "function", "Scratchpad.run() exists"); is(typeof sp.inspect, "function", "Scratchpad.inspect() exists"); - is(typeof sp.print, "function", "Scratchpad.print() exists"); + is(typeof sp.display, "function", "Scratchpad.display() exists"); let chromeContextMenu = gScratchpadWindow.document. getElementById("sp-menu-browser"); diff --git a/browser/base/content/test/browser_scratchpad_ui.js b/browser/base/content/test/browser_scratchpad_ui.js index 373163f54f1a..f4bdc213ec80 100644 --- a/browser/base/content/test/browser_scratchpad_ui.js +++ b/browser/base/content/test/browser_scratchpad_ui.js @@ -33,8 +33,9 @@ function runTests() "sp-menu-open": "openFile", "sp-menu-save": "saveFile", "sp-menu-saveas": "saveFileAs", - "sp-text-execute": "execute", + "sp-text-run": "run", "sp-text-inspect": "inspect", + "sp-text-display": "display", "sp-menu-content": "setContentContext", "sp-menu-browser": "setBrowserContext", "sp-menu-resetContext": "resetContext", diff --git a/browser/locales/en-US/chrome/browser/scratchpad.dtd b/browser/locales/en-US/chrome/browser/scratchpad.dtd index 00330251d754..a86a67328d19 100644 --- a/browser/locales/en-US/chrome/browser/scratchpad.dtd +++ b/browser/locales/en-US/chrome/browser/scratchpad.dtd @@ -61,17 +61,17 @@ - - - + + + - - - + + + + diff --git a/browser/locales/en-US/chrome/browser/scratchpad.properties b/browser/locales/en-US/chrome/browser/scratchpad.properties index 01e0bf4988e7..36f71bc23428 100644 --- a/browser/locales/en-US/chrome/browser/scratchpad.properties +++ b/browser/locales/en-US/chrome/browser/scratchpad.properties @@ -29,3 +29,7 @@ saveFileAs=Save File As # save fails. saveFile.failed=The file save operation failed. +# LOCALIZATION NOTE (scratchpadIntro): This is a multi-line comment explaining +# how to use the Scratchpad. Note that this should be a valid JavaScript +# comment inside /* and */. +scratchpadIntro=/*\n * This is a JavaScript Scratchpad.\n *\n * Enter some JavaScript, then Right Click or choose from the Execute Menu:\n * 1. Run to evaluate the selected text,\n * 2. Inspect to bring up an Object Inspector on the result, or,\n * 3. Display to insert the result in a comment after the selection.\n */\n\n From fbd90779a4112261af9fb82e1e1da8b87c11e088 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 21 May 2011 18:12:21 -0700 Subject: [PATCH 048/145] Bug 654797: Remove no-longer-relevant comment about ("classic") MacOS in documentation for nsIURI::Clone. r=bz --- netwerk/base/public/nsIURI.idl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/netwerk/base/public/nsIURI.idl b/netwerk/base/public/nsIURI.idl index 2a2b0bc5e72c..efb4131be75d 100644 --- a/netwerk/base/public/nsIURI.idl +++ b/netwerk/base/public/nsIURI.idl @@ -194,10 +194,7 @@ interface nsIURI : nsISupports boolean schemeIs(in string scheme); /** - * Clones the current URI. For some protocols, this is more than just an - * optimization. For example, under MacOS, the spec of a file URL does not - * necessarily uniquely identify a file since two volumes could share the - * same name. + * Clones the current URI. */ nsIURI clone(); From cbdf2a3c2f5172b9ab0d1aee6a01ba8ff7fa34f7 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 21 May 2011 18:12:45 -0700 Subject: [PATCH 049/145] Bug 308590 patch 1: Revamp test_URIs.js, including some tests for .ref (which will be supported on URIs after the rest of this bug's patches). r=bz --- netwerk/test/unit/test_URIs.js | 341 +++++++++++++++++++++++++++++++-- 1 file changed, 324 insertions(+), 17 deletions(-) diff --git a/netwerk/test/unit/test_URIs.js b/netwerk/test/unit/test_URIs.js index eb8ac2f39a37..f0e09a0a2b88 100644 --- a/netwerk/test/unit/test_URIs.js +++ b/netwerk/test/unit/test_URIs.js @@ -1,29 +1,336 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ Components.utils.import("resource://gre/modules/NetUtil.jsm"); +const Ci = Components.interfaces; +// TEST DATA +// --------- +var gTests = [ + { spec: "about:foobar", + scheme: "about", + prePath: "about:", + path: "foobar", + ref: "", + nsIURL: false, nsINestedURI: false, immutable: true }, + { spec: "chrome://foobar/somedir/somefile.xml", + scheme: "chrome", + prePath: "chrome://foobar", + path: "/somedir/somefile.xml", + ref: "", + nsIURL: true, nsINestedURI: false, immutable: true }, + { spec: "data:text/html;charset=utf-8,", + scheme: "data", + prePath: "data:", + path: "text/html;charset=utf-8,", + ref: "", + nsIURL: false, nsINestedURI: false }, + { spec: "data:text/plain,hello world", + scheme: "data", + prePath: "data:", + path: "text/plain,hello%20world", + ref: "", + nsIURL: false, nsINestedURI: false }, + { spec: "file://", + scheme: "file", + prePath: "file://", + path: "/", + ref: "", + nsIURL: true, nsINestedURI: false }, + { spec: "file:///", + scheme: "file", + prePath: "file://", + path: "/", + ref: "", + nsIURL: true, nsINestedURI: false }, + { spec: "file:///myFile.html", + scheme: "file", + prePath: "file://", + path: "/myFile.html", + ref: "", + nsIURL: true, nsINestedURI: false }, + { spec: "http://", + scheme: "http", + prePath: "http://", + path: "/", + ref: "", + nsIURL: true, nsINestedURI: false }, + { spec: "http:///", + scheme: "http", + prePath: "http://", + path: "/", + ref: "", + nsIURL: true, nsINestedURI: false }, + { spec: "http://www.example.com/", + scheme: "http", + prePath: "http://www.example.com", + path: "/", + ref: "", + nsIURL: true, nsINestedURI: false }, + { spec: "jar:resource://!/", + scheme: "jar", + prePath: "jar:", + path: "resource:///!/", + ref: "", + nsIURL: true, nsINestedURI: true }, + { spec: "jar:resource://gre/chrome.toolkit.jar!/", + scheme: "jar", + prePath: "jar:", + path: "resource://gre/chrome.toolkit.jar!/", + ref: "", + nsIURL: true, nsINestedURI: true }, + { spec: "resource://gre/", + scheme: "resource", + prePath: "resource://gre", + path: "/", + ref: "", + nsIURL: true, nsINestedURI: false }, + { spec: "resource://gre/components/", + scheme: "resource", + prePath: "resource://gre", + path: "/components/", + ref: "", + nsIURL: true, nsINestedURI: false }, + { spec: "view-source:about:blank", + scheme: "view-source", + prePath: "view-source:", + path: "about:blank", + ref: "", + nsIURL: false, nsINestedURI: true, immutable: true }, + { spec: "view-source:http://www.mozilla.org/", + scheme: "view-source", + prePath: "view-source:", + path: "http://www.mozilla.org/", + ref: "", + nsIURL: false, nsINestedURI: true, immutable: true }, + { spec: "x-external:", + scheme: "x-external", + prePath: "x-external:", + path: "", + ref: "", + nsIURL: false, nsINestedURI: false }, + { spec: "x-external:abc", + scheme: "x-external", + prePath: "x-external:", + path: "abc", + ref: "", + nsIURL: false, nsINestedURI: false }, +]; + +var gHashSuffixes = [ + "#", + "#myRef", + "#myRef?a=b", + "#myRef#", + "#myRef#x:yz" +]; + +// TEST HELPER FUNCTIONS +// --------------------- function do_info(text, stack) { if (!stack) stack = Components.stack.caller; - dump("TEST-INFO | " + stack.filename + " | [" + stack.name + " : " + + dump( "\n" + + "TEST-INFO | " + stack.filename + " | [" + stack.name + " : " + stack.lineNumber + "] " + text + "\n"); } -function run_test() -{ - var tests = [ - { spec: "x-external:", nsIURL: false, nsINestedURI: false }, - { spec: "http://www.example.com/", nsIURL: true, nsINestedURI: false }, - { spec: "view-source:about:blank", nsIURL: false, nsINestedURI: true }, - { spec: "jar:resource://gre/chrome.toolkit.jar!/", nsIURL: true, nsINestedURI: true } - ]; +// Checks that the given property on aURI matches the corresponding property +// in the test bundle (or matches some function of that corresponding property, +// if aTestFunctor is passed in). +function do_check_property(aTest, aURI, aPropertyName, aTestFunctor) { + var expectedVal = aTestFunctor ? + aTestFunctor(aTest[aPropertyName]) : + aTest[aPropertyName]; - tests.forEach(function(aTest) { - var URI = NetUtil.newURI(aTest.spec); - do_info("testing " + aTest.spec + " equals " + aTest.spec); - do_check_true(URI.equals(URI.clone())); - do_info("testing " + aTest.spec + " instanceof nsIURL"); - do_check_eq(URI instanceof Components.interfaces.nsIURL, aTest.nsIURL); - do_info("testing " + aTest.spec + " instanceof nsINestedURI"); - do_check_eq(URI instanceof Components.interfaces.nsINestedURI, aTest.nsINestedURI); + do_info("testing " + aPropertyName + " of " + + (aTestFunctor ? "modified '" : "'" ) + aTest.spec + + "' is '" + expectedVal + "'"); + do_check_eq(aURI[aPropertyName], expectedVal); +} + +// Test that a given URI parses correctly into its various components. +function do_test_uri_basic(aTest) { + var URI = NetUtil.newURI(aTest.spec); + + // Sanity-check + do_info("testing " + aTest.spec + " equals a clone of itself"); + do_check_true(URI.equals(URI.clone())); + do_info("testing " + aTest.spec + " instanceof nsIURL"); + do_check_eq(URI instanceof Ci.nsIURL, aTest.nsIURL); + do_info("testing " + aTest.spec + " instanceof nsINestedURI"); + do_check_eq(URI instanceof Ci.nsINestedURI, + aTest.nsINestedURI); + + // Check the various components + do_check_property(aTest, URI, "scheme"); + do_check_property(aTest, URI, "prePath"); + do_check_property(aTest, URI, "path"); + + // XXXdholbert Only URLs (not URIs) support 'ref', until bug 308590's fix + // lands, so the following only checks 'ref' on URLs. + if (aTest.nsIURL) { + var URL = URI.QueryInterface(Ci.nsIURL); + do_check_property(aTest, URL, "ref"); + } +} + +// Test that a given URI parses correctly when we add a given ref to the end +function do_test_uri_with_hash_suffix(aTest, aSuffix) { + do_info("making sure caller is using suffix that starts with '#'"); + do_check_eq(aSuffix[0], "#"); + + var testURI = NetUtil.newURI(aTest.spec + aSuffix); + + do_info("testing " + aTest.spec + + " doesn't equal self with '" + aSuffix + "' appended"); + + var origURI = NetUtil.newURI(aTest.spec); + if (aTest.spec == "file://") { + do_info("TODO: bug 656853"); + todo_check_false(origURI.equals(testURI)); + return; // bail out early since file:// doesn't handle hash refs at all + } + + do_check_false(origURI.equals(testURI)); + + do_check_property(aTest, testURI, "scheme"); + do_check_property(aTest, testURI, "prePath"); + do_check_property(aTest, testURI, "path", + function(aStr) { return aStr + aSuffix; }); + + // XXXdholbert Only URLs (not URIs) support 'ref', until bug 308590's fix + // lands, so the following only checks 'ref' on URLs. + if (aTest.nsIURL) { + var URL = testURI.QueryInterface(Ci.nsIURL); + do_check_property(aTest, URL, "ref", + function(aStr) { return aSuffix.substr(1); }); + } +} + +// Tests various ways of setting & clearing a ref on a URI. +function do_test_mutate_ref(aTest, aSuffix) { + do_info("making sure caller is using suffix that starts with '#'"); + do_check_eq(aSuffix[0], "#"); + + // XXXdholbert Only URLs (not URIs) support 'ref', until bug 308590's fix + // lands, so this function only works with URLs right now. + if (!aTest.nsIURL) { + return; + } + + var refURIWithSuffix = NetUtil.newURI(aTest.spec + aSuffix).QueryInterface(Ci.nsIURL); + var refURIWithoutSuffix = NetUtil.newURI(aTest.spec).QueryInterface(Ci.nsIURL); + + var testURI = NetUtil.newURI(aTest.spec).QueryInterface(Ci.nsIURL); + + if (aTest.spec == "file://") { + do_info("TODO: bug 656853"); + testURI.ref = aSuffix; + todo_check_true(testURI.equals(refURIWithSuffix)); + return; // bail out early since file:// doesn't handle hash refs at all + } + + // First: Try setting .ref to our suffix + do_info("testing that setting .ref on " + aTest.spec + + " to '" + aSuffix + "' does what we expect"); + testURI.ref = aSuffix; + do_check_true(testURI.equals(refURIWithSuffix)); + + // Now try setting .ref but leave off the initial hash (expect same result) + var suffixLackingHash = aSuffix.substr(1); + if (suffixLackingHash) { // (skip this our suffix was *just* a #) + do_info("testing that setting .ref on " + aTest.spec + + " to '" + suffixLackingHash + "' does what we expect"); + testURI.ref = suffixLackingHash; + do_check_true(testURI.equals(refURIWithSuffix)); + } + + // Now, clear .ref (should get us back the original spec) + do_info("testing that clearing .ref on " + testURI.spec + + " does what we expect"); + testURI.ref = ""; + do_check_true(testURI.equals(refURIWithoutSuffix)); + + // Now try setting .spec directly (including suffix) and then clearing .ref + var specWithSuffix = aTest.spec + aSuffix; + do_info("testing that setting spec to " + + specWithSuffix + " and then clearing ref does what we expect"); + testURI.spec = specWithSuffix + testURI.ref = ""; + if (aTest.spec == "http://" && aSuffix == "#") { + do_info("TODO: bug 657033"); + todo_check_true(testURI.equals(refURIWithoutSuffix)); + } else { + do_check_true(testURI.equals(refURIWithoutSuffix)); + } + + // XXX nsIJARURI throws an exception in SetPath(), so skip it for next part. + if (!(testURI instanceof Ci.nsIJARURI)) { + // Now try setting .path directly (including suffix) and then clearing .ref + // (same as above, but with now with .path instead of .spec) + testURI = NetUtil.newURI(aTest.spec).QueryInterface(Ci.nsIURL); + + var pathWithSuffix = aTest.path + aSuffix; + do_info("testing that setting path to " + + pathWithSuffix + " and then clearing ref does what we expect"); + testURI.path = pathWithSuffix; + testURI.ref = ""; + do_check_true(testURI.equals(refURIWithoutSuffix)); + + // Also: make sure that clearing .path also clears .ref + testURI.path = pathWithSuffix; + do_info("testing that clearing path from " + + pathWithSuffix + " also clears .ref"); + testURI.path = ""; + do_check_eq(testURI.ref, ""); + } +} + +// Tests that normally-mutable properties can't be modified on +// special URIs that are known to be immutable. +function do_test_immutable(aTest) { + do_check_true(aTest.immutable); + + var URI = NetUtil.newURI(aTest.spec); + // All the non-readonly attributes on nsIURI.idl: + var propertiesToCheck = ["spec", "scheme", "userPass", "username", "password", + "hostPort", "host", "port", "path", "ref"]; + + propertiesToCheck.forEach(function(aProperty) { + var threw = false; + try { + URI[aProperty] = "anothervalue"; + } catch(e) { + threw = true; + } + + do_info("testing that setting '" + aProperty + + "' on immutable URI '" + aTest.spec + "' will throw"); + do_check_true(threw); + }); +} + + +// TEST MAIN FUNCTION +// ------------------ +function run_test() +{ + gTests.forEach(function(aTest) { + // Check basic URI functionality + do_test_uri_basic(aTest); + + // Try adding various #-prefixed strings to the ends of the URIs + gHashSuffixes.forEach(function(aSuffix) { + do_test_uri_with_hash_suffix(aTest, aSuffix); + if (!aTest.immutable) { + do_test_mutate_ref(aTest, aSuffix); + } + }); + + // For URIs that we couldn't mutate above due to them being immutable: + // Now we check that they're actually immutable. + if (aTest.immutable) { + do_test_immutable(aTest); + } }); } From a8ca33ca0fd57aa1dcd87229dad218843d70e22c Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 21 May 2011 18:12:45 -0700 Subject: [PATCH 050/145] Bug 308590 patch 2: Move GetRef/SetRef from nsIURL to nsIURI. r=bz sr=biesi --- caps/src/nsNullPrincipalURI.cpp | 13 ++++++++ modules/libpr0n/decoders/icon/nsIconURI.cpp | 13 ++++++++ netwerk/base/public/nsIURI.idl | 34 ++++++++++++++------- netwerk/base/public/nsIURL.idl | 10 +----- netwerk/base/src/nsSimpleURI.cpp | 14 +++++++++ 5 files changed, 64 insertions(+), 20 deletions(-) diff --git a/caps/src/nsNullPrincipalURI.cpp b/caps/src/nsNullPrincipalURI.cpp index 8dcfcf7e9bef..61dc2de45e9b 100644 --- a/caps/src/nsNullPrincipalURI.cpp +++ b/caps/src/nsNullPrincipalURI.cpp @@ -150,6 +150,19 @@ nsNullPrincipalURI::SetPath(const nsACString &aPath) return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +nsNullPrincipalURI::GetRef(nsACString &_ref) +{ + _ref.Truncate(); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsNullPrincipalURI::SetRef(const nsACString &aRef) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP nsNullPrincipalURI::GetPrePath(nsACString &_prePath) { diff --git a/modules/libpr0n/decoders/icon/nsIconURI.cpp b/modules/libpr0n/decoders/icon/nsIconURI.cpp index a6b08a9a43ae..c21465bc0c6c 100644 --- a/modules/libpr0n/decoders/icon/nsIconURI.cpp +++ b/modules/libpr0n/decoders/icon/nsIconURI.cpp @@ -384,6 +384,19 @@ nsMozIconURI::SetPath(const nsACString &aPath) return NS_ERROR_FAILURE; } +NS_IMETHODIMP +nsMozIconURI::GetRef(nsACString &aRef) +{ + aRef.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsMozIconURI::SetRef(const nsACString &aRef) +{ + return NS_ERROR_FAILURE; +} + NS_IMETHODIMP nsMozIconURI::Equals(nsIURI *other, PRBool *result) { diff --git a/netwerk/base/public/nsIURI.idl b/netwerk/base/public/nsIURI.idl index efb4131be75d..e00ba6fc21f0 100644 --- a/netwerk/base/public/nsIURI.idl +++ b/netwerk/base/public/nsIURI.idl @@ -46,16 +46,16 @@ * * This interface follows Tim Berners-Lee's URI spec (RFC2396) [1], where the * basic URI components are defined as such: - *

 
- *      ftp://username:password@hostname:portnumber/pathname
- *      \ /   \               / \      / \        /\       /
- *       -     ---------------   ------   --------  -------
- *       |            |             |        |         |
- *       |            |             |        |        Path
- *       |            |             |       Port         
- *       |            |            Host      /
- *       |         UserPass                 /
- *     Scheme                              /
+ * 
+ *      ftp://username:password@hostname:portnumber/pathname#ref
+ *      \ /   \               / \      / \        /\         \ /
+ *       -     ---------------   ------   --------  |         -
+ *       |            |             |        |      |         |
+ *       |            |             |        |      |        Ref
+ *       |            |             |       Port    \        /
+ *       |            |            Host      /       --------
+ *       |         UserPass                 /	         |
+ *     Scheme                              /	        Path
  *       \                                /
  *        --------------------------------
  *                       |
@@ -64,6 +64,10 @@
  * The definition of the URI components has been extended to allow for
  * internationalized domain names [2] and the more generic IRI structure [3].
  *
+ * Note also that the RFC defines #-separated fragment identifiers as being
+ * "not part of the URI".  Despite this, we bundle them as part of the URI, for
+ * convenience.
+ *
  * [1] http://www.ietf.org/rfc/rfc2396.txt
  * [2] http://www.ietf.org/internet-drafts/draft-ietf-idn-idna-06.txt
  * [3] http://www.ietf.org/internet-drafts/draft-masinter-url-i18n-08.txt
@@ -91,7 +95,7 @@
  * The correct way to create an nsIURI from a string is via
  * nsIIOService.newURI.
  */
-[scriptable, uuid(07a22cc0-0ce5-11d3-9331-00104ba0fd40)]
+[scriptable, uuid(70d94a92-2b13-4e03-9f84-c1684aeea0f2)]
 interface nsIURI : nsISupports
 {
     /************************************************************************
@@ -174,6 +178,14 @@ interface nsIURI : nsISupports
      */
     attribute AUTF8String path;
 
+    /**
+     * Returns the reference portion (the part after the "#") of the URI.
+     * If there isn't one, an empty string is returned.
+     *
+     * Some characters may be escaped.
+     */
+    attribute AUTF8String ref;
+
 
     /************************************************************************
      * An URI supports the following methods:
diff --git a/netwerk/base/public/nsIURL.idl b/netwerk/base/public/nsIURL.idl
index cf221e31f4ea..15eba882d6fc 100644
--- a/netwerk/base/public/nsIURL.idl
+++ b/netwerk/base/public/nsIURL.idl
@@ -54,7 +54,7 @@
  *                            |
  *                        filePath
  */
-[scriptable, uuid(d6116970-8034-11d3-9399-00104ba0fd40)]
+[scriptable, uuid(d55f7915-6ff7-4b17-8795-d3b447bfe1f8)]
 interface nsIURL : nsIURI
 {
     /*************************************************************************
@@ -85,14 +85,6 @@ interface nsIURL : nsIURI
      */
     attribute AUTF8String query;
 
-    /**
-     * Returns the reference portion (the part after the "#") of the URL.
-     * If there isn't one, an empty string is returned.
-     *
-     * Some characters may be escaped.
-     */
-    attribute AUTF8String ref;
-
 
     /*************************************************************************
      * The URL filepath is broken down into the following sub-components:
diff --git a/netwerk/base/src/nsSimpleURI.cpp b/netwerk/base/src/nsSimpleURI.cpp
index f00ee926cfef..37774152e8de 100644
--- a/netwerk/base/src/nsSimpleURI.cpp
+++ b/netwerk/base/src/nsSimpleURI.cpp
@@ -327,6 +327,20 @@ nsSimpleURI::SetPath(const nsACString &path)
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSimpleURI::GetRef(nsACString &result)
+{
+    // XXXdholbert Implement this.
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsSimpleURI::SetRef(const nsACString &ref)
+{
+    // XXXdholbert Implement this.
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 NS_IMETHODIMP
 nsSimpleURI::Equals(nsIURI* other, PRBool *result)
 {

From f4110d2e96a03867e60b70d3d3c956ad48c4e01b Mon Sep 17 00:00:00 2001
From: Daniel Holbert 
Date: Sat, 21 May 2011 18:12:45 -0700
Subject: [PATCH 051/145] Bug 308590 patch 3: Add nsIURI::EqualsExceptRef
 interface & impls. r=bz sr=biesi

---
 caps/src/nsNullPrincipalURI.cpp               |  8 +++
 .../base/src/nsFileDataProtocolHandler.cpp    | 15 ++--
 modules/libjar/nsIJARURI.idl                  |  2 +-
 modules/libjar/nsJARURI.cpp                   | 24 +++++--
 modules/libjar/nsJARURI.h                     | 11 +++
 modules/libpr0n/decoders/icon/nsIIconURI.idl  |  2 +-
 modules/libpr0n/decoders/icon/nsIconURI.cpp   |  8 +++
 netwerk/base/public/nsIFileURL.idl            |  2 +-
 netwerk/base/public/nsIURI.idl                | 11 ++-
 netwerk/base/public/nsIURL.idl                |  2 +-
 netwerk/base/src/nsSimpleNestedURI.cpp        | 13 ++--
 netwerk/base/src/nsSimpleNestedURI.h          |  6 +-
 netwerk/base/src/nsSimpleURI.cpp              | 16 +++++
 netwerk/base/src/nsSimpleURI.h                | 12 ++++
 netwerk/base/src/nsStandardURL.cpp            | 21 +++++-
 netwerk/base/src/nsStandardURL.h              | 12 ++++
 netwerk/test/unit/test_URIs.js                | 70 ++++++++++++++++---
 17 files changed, 202 insertions(+), 33 deletions(-)

diff --git a/caps/src/nsNullPrincipalURI.cpp b/caps/src/nsNullPrincipalURI.cpp
index 61dc2de45e9b..a8ace180839d 100644
--- a/caps/src/nsNullPrincipalURI.cpp
+++ b/caps/src/nsNullPrincipalURI.cpp
@@ -256,6 +256,14 @@ nsNullPrincipalURI::Equals(nsIURI *aOther, PRBool *_equals)
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsNullPrincipalURI::EqualsExceptRef(nsIURI *aOther, PRBool *_equals)
+{
+  // GetRef/SetRef not supported by nsNullPrincipalURI, so
+  // EqualsExceptRef() is the same as Equals().
+  return Equals(aOther, _equals);
+}
+
 NS_IMETHODIMP
 nsNullPrincipalURI::Resolve(const nsACString &aRelativePath,
                             nsACString &_resolvedURI)
diff --git a/content/base/src/nsFileDataProtocolHandler.cpp b/content/base/src/nsFileDataProtocolHandler.cpp
index 0713f42d075e..416a0ea1138b 100644
--- a/content/base/src/nsFileDataProtocolHandler.cpp
+++ b/content/base/src/nsFileDataProtocolHandler.cpp
@@ -147,9 +147,11 @@ public:
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
 
-  // Override Clone() and Equals()
+  // Override Clone() and EqualsInternal()
   NS_IMETHOD Clone(nsIURI** aClone);
-  NS_IMETHOD Equals(nsIURI* aOther, PRBool *aResult);
+  virtual nsresult EqualsInternal(nsIURI* aOther,
+                                  RefHandlingEnum aRefHandlingMode,
+                                  PRBool* aResult);
 
   // Override StartClone to hand back a nsFileDataURI
   virtual nsSimpleURI* StartClone()
@@ -236,8 +238,10 @@ nsFileDataURI::Clone(nsIURI** aClone)
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsFileDataURI::Equals(nsIURI* aOther, PRBool *aResult)
+/* virtual */ nsresult
+nsFileDataURI::EqualsInternal(nsIURI* aOther,
+                              nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                              PRBool* aResult)
 {
   if (!aOther) {
     *aResult = PR_FALSE;
@@ -258,7 +262,8 @@ nsFileDataURI::Equals(nsIURI* aOther, PRBool *aResult)
     return NS_OK;
   }
 
-  return nsSimpleURI::Equals(otherFileDataUri, aResult);
+  return nsSimpleURI::EqualsInternal(otherFileDataUri, aRefHandlingMode,
+                                     aResult);
 }
 
 // nsIClassInfo methods:
diff --git a/modules/libjar/nsIJARURI.idl b/modules/libjar/nsIJARURI.idl
index 2685c8f25219..439decd0c4f3 100644
--- a/modules/libjar/nsIJARURI.idl
+++ b/modules/libjar/nsIJARURI.idl
@@ -47,7 +47,7 @@
  *
  * The nsIURL methods operate on the  part of the spec.
  */
-[scriptable, uuid(b0922a89-f87b-4cb5-8612-305a285fcca7)]
+[scriptable, uuid(ba32f809-5adf-4191-866a-1cddf60548f7)]
 interface nsIJARURI : nsIURL {
 
     /**
diff --git a/modules/libjar/nsJARURI.cpp b/modules/libjar/nsJARURI.cpp
index 064ef0a5bd1c..24c3ae25c899 100644
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -458,11 +458,24 @@ nsJARURI::GetOriginCharset(nsACString &aOriginCharset)
 NS_IMETHODIMP
 nsJARURI::Equals(nsIURI *other, PRBool *result)
 {
-    nsresult rv;
+    return EqualsInternal(other, eHonorRef, result);
+}
 
+NS_IMETHODIMP
+nsJARURI::EqualsExceptRef(nsIURI *other, PRBool *result)
+{
+    return EqualsInternal(other, eIgnoreRef, result);
+}
+
+// Helper method:
+/* virtual */ nsresult
+nsJARURI::EqualsInternal(nsIURI *other,
+                         nsJARURI::RefHandlingEnum refHandlingMode,
+                         PRBool *result)
+{
     *result = PR_FALSE;
 
-    if (other == nsnull)
+    if (!other)
         return NS_OK;	// not equal
 
     nsRefPtr otherJAR;
@@ -471,13 +484,14 @@ nsJARURI::Equals(nsIURI *other, PRBool *result)
         return NS_OK;   // not equal
 
     PRBool equal;
-    rv = mJARFile->Equals(otherJAR->mJARFile, &equal);
+    nsresult rv = mJARFile->Equals(otherJAR->mJARFile, &equal);
     if (NS_FAILED(rv) || !equal) {
         return rv;   // not equal
     }
 
-    rv = mJAREntry->Equals(otherJAR->mJAREntry, result);
-    return rv;
+    return refHandlingMode == eHonorRef ?
+        mJAREntry->Equals(otherJAR->mJAREntry, result) :
+        mJAREntry->EqualsExceptRef(otherJAR->mJAREntry, result);
 }
 
 NS_IMETHODIMP
diff --git a/modules/libjar/nsJARURI.h b/modules/libjar/nsJARURI.h
index 93c073046d42..ba44c11f4401 100644
--- a/modules/libjar/nsJARURI.h
+++ b/modules/libjar/nsJARURI.h
@@ -94,6 +94,17 @@ public:
     nsresult SetSpecWithBase(const nsACString& aSpec, nsIURI* aBaseURL);
 
 protected:
+    // enum used in a few places to specify how .ref attribute should be handled
+    enum RefHandlingEnum {
+        eIgnoreRef,
+        eHonorRef
+    };
+
+    // Helper to share code between Equals methods.
+    virtual nsresult EqualsInternal(nsIURI* other,
+                                    RefHandlingEnum refHandlingMode,
+                                    PRBool* result);
+
     nsCOMPtr mJARFile;
     // mJarEntry stored as a URL so that we can easily access things
     // like extensions, refs, etc.
diff --git a/modules/libpr0n/decoders/icon/nsIIconURI.idl b/modules/libpr0n/decoders/icon/nsIIconURI.idl
index 7908a08f4ae6..e8a9a4eb376b 100644
--- a/modules/libpr0n/decoders/icon/nsIIconURI.idl
+++ b/modules/libpr0n/decoders/icon/nsIIconURI.idl
@@ -73,7 +73,7 @@
    *   Description: The mime type we want an icon for. This is ignored by stock images.
    */
 
-[scriptable, uuid(E2D046D2-3729-440D-B0DB-F8D817BC2571)]
+[scriptable, uuid(5d8a4518-bebf-4e7e-bad0-3e6737b3d7f4)]
 interface nsIMozIconURI : nsIURI 
 {
   /**
diff --git a/modules/libpr0n/decoders/icon/nsIconURI.cpp b/modules/libpr0n/decoders/icon/nsIconURI.cpp
index c21465bc0c6c..3cc09b86d6b6 100644
--- a/modules/libpr0n/decoders/icon/nsIconURI.cpp
+++ b/modules/libpr0n/decoders/icon/nsIconURI.cpp
@@ -415,6 +415,14 @@ nsMozIconURI::Equals(nsIURI *other, PRBool *result)
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsMozIconURI::EqualsExceptRef(nsIURI *other, PRBool *result)
+{
+  // GetRef/SetRef not supported by nsMozIconURI, so
+  // EqualsExceptRef() is the same as Equals().
+  return Equals(other, result);
+}
+
 NS_IMETHODIMP
 nsMozIconURI::SchemeIs(const char *i_Scheme, PRBool *o_Equals)
 {
diff --git a/netwerk/base/public/nsIFileURL.idl b/netwerk/base/public/nsIFileURL.idl
index 47f0481a3e9a..d8094621c186 100644
--- a/netwerk/base/public/nsIFileURL.idl
+++ b/netwerk/base/public/nsIFileURL.idl
@@ -45,7 +45,7 @@ interface nsIFile;
  * an URL.  The URL scheme need not be file:, since other local protocols may
  * map URLs to files (e.g., resource:).
  */
-[scriptable, uuid(d26b2e2e-1dd1-11b2-88f3-8545a7ba7949)]
+[scriptable, uuid(e693cb4f-d835-4068-9e14-76de8bd9df1d)]
 interface nsIFileURL : nsIURL
 {
     /**
diff --git a/netwerk/base/public/nsIURI.idl b/netwerk/base/public/nsIURI.idl
index e00ba6fc21f0..63f3042919e5 100644
--- a/netwerk/base/public/nsIURI.idl
+++ b/netwerk/base/public/nsIURI.idl
@@ -95,7 +95,7 @@
  * The correct way to create an nsIURI from a string is via
  * nsIIOService.newURI.
  */
-[scriptable, uuid(70d94a92-2b13-4e03-9f84-c1684aeea0f2)]
+[scriptable, uuid(d6d04c36-0fa4-4db3-be05-4a18397103e2)]
 interface nsIURI : nsISupports
 {
     /************************************************************************
@@ -198,6 +198,15 @@ interface nsIURI : nsISupports
      */
     boolean equals(in nsIURI other);
 
+    /**
+     * URI equivalence test (not a strict string comparison), ignoring
+     * the value of the .ref member.
+     *
+     * eg. http://foo.com/# == http://foo.com/
+     *     http://foo.com/#aaa == http://foo.com/#bbb
+     */
+    boolean equalsExceptRef(in nsIURI other);
+
     /**
      * An optimization to do scheme checks without requiring the users of nsIURI
      * to GetScheme, thereby saving extra allocating and freeing. Returns true if
diff --git a/netwerk/base/public/nsIURL.idl b/netwerk/base/public/nsIURL.idl
index 15eba882d6fc..4acb36f98ed5 100644
--- a/netwerk/base/public/nsIURL.idl
+++ b/netwerk/base/public/nsIURL.idl
@@ -54,7 +54,7 @@
  *                            |
  *                        filePath
  */
-[scriptable, uuid(d55f7915-6ff7-4b17-8795-d3b447bfe1f8)]
+[scriptable, uuid(55e824ca-f1bb-4452-9e14-fcfa1ff091ce)]
 interface nsIURL : nsIURI
 {
     /*************************************************************************
diff --git a/netwerk/base/src/nsSimpleNestedURI.cpp b/netwerk/base/src/nsSimpleNestedURI.cpp
index 737c66703bdb..198d0353343a 100644
--- a/netwerk/base/src/nsSimpleNestedURI.cpp
+++ b/netwerk/base/src/nsSimpleNestedURI.cpp
@@ -130,10 +130,11 @@ nsSimpleNestedURI::GetInnermostURI(nsIURI** uri)
     return NS_ImplGetInnermostURI(this, uri);
 }
 
-// nsIURI overrides
-
-NS_IMETHODIMP
-nsSimpleNestedURI::Equals(nsIURI* other, PRBool *result)
+// nsSimpleURI overrides
+/* virtual */ nsresult
+nsSimpleNestedURI::EqualsInternal(nsIURI* other,
+                                  nsSimpleURI::RefHandlingEnum refHandlingMode,
+                                  PRBool* result)
 {
     *result = PR_FALSE;
     NS_ENSURE_TRUE(mInnerURI, NS_ERROR_NOT_INITIALIZED);
@@ -150,7 +151,9 @@ nsSimpleNestedURI::Equals(nsIURI* other, PRBool *result)
                 rv = nest->GetInnerURI(getter_AddRefs(otherInner));
                 NS_ENSURE_SUCCESS(rv, rv);
 
-                return otherInner->Equals(mInnerURI, result);
+                return (refHandlingMode == eHonorRef) ?
+                    otherInner->Equals(mInnerURI, result) :
+                    otherInner->EqualsExceptRef(mInnerURI, result);
             }
         }
     }
diff --git a/netwerk/base/src/nsSimpleNestedURI.h b/netwerk/base/src/nsSimpleNestedURI.h
index 454efa4d7c3d..dfe1b39178b0 100644
--- a/netwerk/base/src/nsSimpleNestedURI.h
+++ b/netwerk/base/src/nsSimpleNestedURI.h
@@ -73,8 +73,10 @@ public:
 
     // Overrides for various methods nsSimpleURI implements follow.
   
-    // nsIURI overrides
-    NS_IMETHOD Equals(nsIURI* other, PRBool *result);
+    // nsSimpleURI overrides
+    virtual nsresult EqualsInternal(nsIURI* other,
+                                    RefHandlingEnum refHandlingMode,
+                                    PRBool* result);
     virtual nsSimpleURI* StartClone();
 
     // nsISerializable overrides
diff --git a/netwerk/base/src/nsSimpleURI.cpp b/netwerk/base/src/nsSimpleURI.cpp
index 37774152e8de..121afdc062d6 100644
--- a/netwerk/base/src/nsSimpleURI.cpp
+++ b/netwerk/base/src/nsSimpleURI.cpp
@@ -344,6 +344,22 @@ nsSimpleURI::SetRef(const nsACString &ref)
 NS_IMETHODIMP
 nsSimpleURI::Equals(nsIURI* other, PRBool *result)
 {
+    return EqualsInternal(other, eHonorRef, result);
+}
+
+NS_IMETHODIMP
+nsSimpleURI::EqualsExceptRef(nsIURI* other, PRBool *result)
+{
+    return EqualsInternal(other, eIgnoreRef, result);
+}
+
+/* virtual */ nsresult
+nsSimpleURI::EqualsInternal(nsIURI* other,
+                            nsSimpleURI::RefHandlingEnum refHandlingMode,
+                            PRBool* result)
+{
+    // XXXdholbert Currently ignoring refHandlingMode.  I'll make use of it
+    // in next patch, when I add support for .ref to this class.
     PRBool eq = PR_FALSE;
     if (other) {
         nsSimpleURI* otherUrl;
diff --git a/netwerk/base/src/nsSimpleURI.h b/netwerk/base/src/nsSimpleURI.h
index 9e4de9df8d3d..ee6a1592c039 100644
--- a/netwerk/base/src/nsSimpleURI.h
+++ b/netwerk/base/src/nsSimpleURI.h
@@ -74,6 +74,18 @@ public:
     virtual ~nsSimpleURI();
 
 protected:
+    // enum used in a few places to specify how .ref attribute should be handled
+    enum RefHandlingEnum {
+        eIgnoreRef,
+        eHonorRef
+    };
+
+    // Helper to share code between Equals methods.  Subclasses can override
+    // for custom Equals behavior.
+    virtual nsresult EqualsInternal(nsIURI* other,
+                                    RefHandlingEnum refHandlingMode,
+                                    PRBool* result);
+
     virtual nsSimpleURI* StartClone();
 
     nsCString mScheme;
diff --git a/netwerk/base/src/nsStandardURL.cpp b/netwerk/base/src/nsStandardURL.cpp
index 859bdc1462b0..2db8224e83db 100644
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -1576,6 +1576,20 @@ nsStandardURL::SetPath(const nsACString &input)
 
 NS_IMETHODIMP
 nsStandardURL::Equals(nsIURI *unknownOther, PRBool *result)
+{
+    return EqualsInternal(unknownOther, eHonorRef, result);
+}
+
+NS_IMETHODIMP
+nsStandardURL::EqualsExceptRef(nsIURI *unknownOther, PRBool *result)
+{
+    return EqualsInternal(unknownOther, eIgnoreRef, result);
+}
+
+nsresult
+nsStandardURL::EqualsInternal(nsIURI *unknownOther,
+                              nsStandardURL::RefHandlingEnum refHandlingMode,
+                              PRBool *result)
 {
     NS_ENSURE_ARG_POINTER(unknownOther);
     NS_PRECONDITION(result, "null pointer");
@@ -1602,7 +1616,6 @@ nsStandardURL::Equals(nsIURI *unknownOther, PRBool *result)
         // ignore the host!
         !SegmentIs(mHost, other->mSpec.get(), other->mHost) ||
         !SegmentIs(mQuery, other->mSpec.get(), other->mQuery) ||
-        !SegmentIs(mRef, other->mSpec.get(), other->mRef) ||
         !SegmentIs(mUsername, other->mSpec.get(), other->mUsername) ||
         !SegmentIs(mPassword, other->mSpec.get(), other->mPassword) ||
         Port() != other->Port() ||
@@ -1612,6 +1625,12 @@ nsStandardURL::Equals(nsIURI *unknownOther, PRBool *result)
         *result = PR_FALSE;
         return NS_OK;
     }
+
+    if (refHandlingMode == eHonorRef &&
+        !SegmentIs(mRef, other->mSpec.get(), other->mRef)) {
+        *result = PR_FALSE;
+        return NS_OK;
+    }
     
     // Then check for exact identity of URIs.  If we have it, they're equal
     if (SegmentIs(mDirectory, other->mSpec.get(), other->mDirectory) &&
diff --git a/netwerk/base/src/nsStandardURL.h b/netwerk/base/src/nsStandardURL.h
index 622b2c1ce32c..a073894c0cf5 100644
--- a/netwerk/base/src/nsStandardURL.h
+++ b/netwerk/base/src/nsStandardURL.h
@@ -153,6 +153,18 @@ public: /* internal -- HPUX compiler can't handle this being private */
     friend class nsSegmentEncoder;
 
 protected:
+    // enum used in a few places to specify how .ref attribute should be handled
+    enum RefHandlingEnum {
+        eIgnoreRef,
+        eHonorRef
+    };
+
+    // Helper to share code between Equals and EqualsExceptRef
+    // NOTE: *not* virtual, because no one needs to override this so far...
+    nsresult EqualsInternal(nsIURI* unknownOther,
+                            RefHandlingEnum refHandlingMode,
+                            PRBool* result);
+
     virtual nsStandardURL* StartClone();
 
     // Helper for subclass implementation of GetFile().  Subclasses that map
diff --git a/netwerk/test/unit/test_URIs.js b/netwerk/test/unit/test_URIs.js
index f0e09a0a2b88..e0ac3a7be734 100644
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -134,6 +134,47 @@ function do_info(text, stack) {
        stack.lineNumber + "] " + text + "\n");
 }
 
+// Checks that the URIs satisfy equals(), in both possible orderings.
+// Also checks URI.equalsExceptRef(), because equal URIs should also be equal
+// when we ignore the ref.
+// 
+// The third argument is optional. If the client passes a third argument
+// (e.g. todo_check_true), we'll use that in lieu of do_check_true.
+function do_check_uri_eq(aURI1, aURI2, aCheckTrueFunc) {
+  if (!aCheckTrueFunc) {
+    aCheckTrueFunc = do_check_true;
+  }
+
+  do_info("(uri equals check: '" + aURI1.spec + "' == '" + aURI2.spec + "')");
+  aCheckTrueFunc(aURI1.equals(aURI2));
+  do_info("(uri equals check: '" + aURI2.spec + "' == '" + aURI1.spec + "')");
+  aCheckTrueFunc(aURI2.equals(aURI1));
+
+  // (Only take the extra step of testing 'equalsExceptRef' when we expect the
+  // URIs to really be equal.  In 'todo' cases, the URIs may or may not be
+  // equal when refs are ignored - there's no way of knowing in general.)
+  if (aCheckTrueFunc == do_check_true) {
+    do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc);
+  }
+}
+
+// Checks that the URIs satisfy equalsExceptRef(), in both possible orderings.
+//
+// The third argument is optional. If the client passes a third argument
+// (e.g. todo_check_true), we'll use that in lieu of do_check_true.
+function do_check_uri_eqExceptRef(aURI1, aURI2, aCheckTrueFunc) {
+  if (!aCheckTrueFunc) {
+    aCheckTrueFunc = do_check_true;
+  }
+
+  do_info("(uri equalsExceptRef check: '" +
+          aURI1.spec + "' == '" + aURI2.spec + "')");
+  aCheckTrueFunc(aURI1.equalsExceptRef(aURI2));
+  do_info("(uri equalsExceptRef check: '" +
+          aURI2.spec + "' == '" + aURI1.spec + "')");
+  aCheckTrueFunc(aURI2.equalsExceptRef(aURI1));
+}
+
 // Checks that the given property on aURI matches the corresponding property
 // in the test bundle (or matches some function of that corresponding property,
 // if aTestFunctor is passed in).
@@ -154,7 +195,7 @@ function do_test_uri_basic(aTest) {
 
   // Sanity-check
   do_info("testing " + aTest.spec + " equals a clone of itself");
-  do_check_true(URI.equals(URI.clone()));
+  do_check_uri_eq(URI, URI.clone());
   do_info("testing " + aTest.spec + " instanceof nsIURL");
   do_check_eq(URI instanceof Ci.nsIURL, aTest.nsIURL);
   do_info("testing " + aTest.spec + " instanceof nsINestedURI");
@@ -180,11 +221,10 @@ function do_test_uri_with_hash_suffix(aTest, aSuffix) {
   do_check_eq(aSuffix[0], "#");
 
   var testURI = NetUtil.newURI(aTest.spec + aSuffix);
+  var origURI = NetUtil.newURI(aTest.spec);
 
   do_info("testing " + aTest.spec +
           " doesn't equal self with '" + aSuffix + "' appended");
-
-  var origURI = NetUtil.newURI(aTest.spec);
   if (aTest.spec == "file://") {
     do_info("TODO: bug 656853");
     todo_check_false(origURI.equals(testURI));
@@ -204,6 +244,10 @@ function do_test_uri_with_hash_suffix(aTest, aSuffix) {
     var URL = testURI.QueryInterface(Ci.nsIURL);
     do_check_property(aTest, URL, "ref",
                       function(aStr) { return aSuffix.substr(1); });
+
+    do_info("testing " + aTest.spec +
+          " is equalExceptRef to self with '" + aSuffix + "' appended");
+    do_check_uri_eqExceptRef(origURI, testURI);
   }
 }
 
@@ -226,7 +270,7 @@ function do_test_mutate_ref(aTest, aSuffix) {
   if (aTest.spec == "file://") {
     do_info("TODO: bug 656853");
     testURI.ref = aSuffix;
-    todo_check_true(testURI.equals(refURIWithSuffix));
+    do_check_uri_eq(testURI, refURIWithSuffix, todo_check_true);
     return; // bail out early since file:// doesn't handle hash refs at all
   }
 
@@ -234,7 +278,8 @@ function do_test_mutate_ref(aTest, aSuffix) {
   do_info("testing that setting .ref on " + aTest.spec +
           " to '" + aSuffix + "' does what we expect");
   testURI.ref = aSuffix;
-  do_check_true(testURI.equals(refURIWithSuffix));
+  do_check_uri_eq(testURI, refURIWithSuffix);
+  do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
 
   // Now try setting .ref but leave off the initial hash (expect same result)
   var suffixLackingHash = aSuffix.substr(1);
@@ -242,14 +287,16 @@ function do_test_mutate_ref(aTest, aSuffix) {
     do_info("testing that setting .ref on " + aTest.spec +
             " to '" + suffixLackingHash + "' does what we expect");
     testURI.ref = suffixLackingHash;
-    do_check_true(testURI.equals(refURIWithSuffix));
+    do_check_uri_eq(testURI, refURIWithSuffix);
+    do_check_uri_eqExceptRef(testURI, refURIWithoutSuffix);
   }
 
   // Now, clear .ref (should get us back the original spec)
   do_info("testing that clearing .ref on " + testURI.spec +
           " does what we expect");
   testURI.ref = "";
-  do_check_true(testURI.equals(refURIWithoutSuffix));
+  do_check_uri_eq(testURI, refURIWithoutSuffix);
+  do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
 
   // Now try setting .spec directly (including suffix) and then clearing .ref
   var specWithSuffix = aTest.spec + aSuffix;
@@ -259,9 +306,11 @@ function do_test_mutate_ref(aTest, aSuffix) {
   testURI.ref = "";
   if (aTest.spec == "http://" && aSuffix == "#") {
     do_info("TODO: bug 657033");
-    todo_check_true(testURI.equals(refURIWithoutSuffix));
+    do_check_uri_eq(testURI, refURIWithoutSuffix, todo_check_true);
+    do_check_uri_eqExceptRef(testURI, refURIWithSuffix, todo_check_true);
   } else {
-    do_check_true(testURI.equals(refURIWithoutSuffix));
+    do_check_uri_eq(testURI, refURIWithoutSuffix);
+    do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
   }
 
   // XXX nsIJARURI throws an exception in SetPath(), so skip it for next part.
@@ -275,7 +324,8 @@ function do_test_mutate_ref(aTest, aSuffix) {
             pathWithSuffix + " and then clearing ref does what we expect");
     testURI.path = pathWithSuffix;
     testURI.ref = "";
-    do_check_true(testURI.equals(refURIWithoutSuffix));
+    do_check_uri_eq(testURI, refURIWithoutSuffix);
+    do_check_uri_eqExceptRef(testURI, refURIWithSuffix);
 
     // Also: make sure that clearing .path also clears .ref
     testURI.path = pathWithSuffix;

From 2ee75e0a933a3d4d6fcfe0b617dff2da21fe6461 Mon Sep 17 00:00:00 2001
From: Daniel Holbert 
Date: Sat, 21 May 2011 18:12:45 -0700
Subject: [PATCH 052/145] Bug 308590 patch 3.5: Add nsIURI::CloneIgnoringRef
 interface & impls. r=bz sr=biesi

---
 caps/src/nsNullPrincipalURI.cpp               |  9 +++-
 .../base/src/nsFileDataProtocolHandler.cpp    | 16 +++----
 modules/libjar/nsJARURI.cpp                   | 42 +++++++++++++------
 modules/libjar/nsJARURI.h                     |  4 ++
 modules/libpr0n/decoders/icon/nsIconURI.cpp   | 11 +++--
 netwerk/base/public/nsIURI.idl                |  5 +++
 netwerk/base/src/nsSimpleNestedURI.cpp        |  7 +++-
 netwerk/base/src/nsSimpleNestedURI.h          |  2 +-
 netwerk/base/src/nsSimpleURI.cpp              | 21 ++++++++--
 netwerk/base/src/nsSimpleURI.h                | 12 ++++--
 netwerk/base/src/nsStandardURL.cpp            | 23 +++++++++-
 netwerk/base/src/nsStandardURL.h              |  4 ++
 netwerk/test/unit/test_URIs.js                | 12 ++++++
 13 files changed, 134 insertions(+), 34 deletions(-)

diff --git a/caps/src/nsNullPrincipalURI.cpp b/caps/src/nsNullPrincipalURI.cpp
index a8ace180839d..46d8f4713724 100644
--- a/caps/src/nsNullPrincipalURI.cpp
+++ b/caps/src/nsNullPrincipalURI.cpp
@@ -237,11 +237,18 @@ nsNullPrincipalURI::Clone(nsIURI **_newURI)
 {
   nsCOMPtr uri =
     new nsNullPrincipalURI(mScheme + NS_LITERAL_CSTRING(":") + mPath);
-  NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
   uri.forget(_newURI);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsNullPrincipalURI::CloneIgnoringRef(nsIURI **_newURI)
+{
+  // GetRef/SetRef not supported by nsNullPrincipalURI, so
+  // CloneIgnoringRef() is the same as Clone().
+  return Clone(_newURI);
+}
+
 NS_IMETHODIMP
 nsNullPrincipalURI::Equals(nsIURI *aOther, PRBool *_equals)
 {
diff --git a/content/base/src/nsFileDataProtocolHandler.cpp b/content/base/src/nsFileDataProtocolHandler.cpp
index 416a0ea1138b..e4934d35b8b6 100644
--- a/content/base/src/nsFileDataProtocolHandler.cpp
+++ b/content/base/src/nsFileDataProtocolHandler.cpp
@@ -147,14 +147,15 @@ public:
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
 
-  // Override Clone() and EqualsInternal()
-  NS_IMETHOD Clone(nsIURI** aClone);
+  // Override CloneInternal() and EqualsInternal()
+  virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
+                                 nsIURI** aClone);
   virtual nsresult EqualsInternal(nsIURI* aOther,
                                   RefHandlingEnum aRefHandlingMode,
                                   PRBool* aResult);
 
   // Override StartClone to hand back a nsFileDataURI
-  virtual nsSimpleURI* StartClone()
+  virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
   { return new nsFileDataURI(); }
 
   nsCOMPtr mPrincipal;
@@ -215,12 +216,13 @@ nsFileDataURI::Write(nsIObjectOutputStream* aStream)
 }
 
 // nsIURI methods:
-
-NS_IMETHODIMP
-nsFileDataURI::Clone(nsIURI** aClone)
+nsresult
+nsFileDataURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                             nsIURI** aClone)
 {
   nsCOMPtr simpleClone;
-  nsresult rv = nsSimpleURI::Clone(getter_AddRefs(simpleClone));
+  nsresult rv =
+    nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
diff --git a/modules/libjar/nsJARURI.cpp b/modules/libjar/nsJARURI.cpp
index 24c3ae25c899..10f50bfa49e7 100644
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -514,7 +514,19 @@ nsJARURI::Clone(nsIURI **result)
     nsresult rv;
 
     nsCOMPtr uri;
-    rv = CloneWithJARFile(mJARFile, getter_AddRefs(uri));
+    rv = CloneWithJARFileInternal(mJARFile, eHonorRef, getter_AddRefs(uri));
+    if (NS_FAILED(rv)) return rv;
+
+    return CallQueryInterface(uri, result);
+}
+
+NS_IMETHODIMP
+nsJARURI::CloneIgnoringRef(nsIURI **result)
+{
+    nsresult rv;
+
+    nsCOMPtr uri;
+    rv = CloneWithJARFileInternal(mJARFile, eIgnoreRef, getter_AddRefs(uri));
     if (NS_FAILED(rv)) return rv;
 
     return CallQueryInterface(uri, result);
@@ -781,6 +793,14 @@ nsJARURI::SetJAREntry(const nsACString &entryPath)
 
 NS_IMETHODIMP
 nsJARURI::CloneWithJARFile(nsIURI *jarFile, nsIJARURI **result)
+{
+    return CloneWithJARFileInternal(jarFile, eHonorRef, result);
+}
+
+nsresult
+nsJARURI::CloneWithJARFileInternal(nsIURI *jarFile,
+                                   nsJARURI::RefHandlingEnum refHandlingMode,
+                                   nsIJARURI **result)
 {
     if (!jarFile) {
         return NS_ERROR_INVALID_ARG;
@@ -795,24 +815,22 @@ nsJARURI::CloneWithJARFile(nsIURI *jarFile, nsIJARURI **result)
     NS_TryToSetImmutable(newJARFile);
 
     nsCOMPtr newJAREntryURI;
-    rv = mJAREntry->Clone(getter_AddRefs(newJAREntryURI));
+    rv = refHandlingMode == eHonorRef ?
+        mJAREntry->Clone(getter_AddRefs(newJAREntryURI)) :
+        mJAREntry->CloneIgnoringRef(getter_AddRefs(newJAREntryURI));
+
     if (NS_FAILED(rv)) return rv;
 
     nsCOMPtr newJAREntry(do_QueryInterface(newJAREntryURI));
     NS_ASSERTION(newJAREntry, "This had better QI to nsIURL!");
     
     nsJARURI* uri = new nsJARURI();
-    if (uri) {
-        NS_ADDREF(uri);
-        uri->mJARFile = newJARFile;
-        uri->mJAREntry = newJAREntry;
-        *result = uri;
-        rv = NS_OK;
-    } else {
-        rv = NS_ERROR_OUT_OF_MEMORY;
-    }
+    NS_ADDREF(uri);
+    uri->mJARFile = newJARFile;
+    uri->mJAREntry = newJAREntry;
+    *result = uri;
 
-    return rv;
+    return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/modules/libjar/nsJARURI.h b/modules/libjar/nsJARURI.h
index ba44c11f4401..8fd2dd17fce9 100644
--- a/modules/libjar/nsJARURI.h
+++ b/modules/libjar/nsJARURI.h
@@ -105,6 +105,10 @@ protected:
                                     RefHandlingEnum refHandlingMode,
                                     PRBool* result);
 
+    // Helper to share code between Clone methods.
+    nsresult CloneWithJARFileInternal(nsIURI *jarFile,
+                                      RefHandlingEnum refHandlingMode,
+                                      nsIJARURI **result);
     nsCOMPtr mJARFile;
     // mJarEntry stored as a URL so that we can easily access things
     // like extensions, refs, etc.
diff --git a/modules/libpr0n/decoders/icon/nsIconURI.cpp b/modules/libpr0n/decoders/icon/nsIconURI.cpp
index 3cc09b86d6b6..d658c3875c03 100644
--- a/modules/libpr0n/decoders/icon/nsIconURI.cpp
+++ b/modules/libpr0n/decoders/icon/nsIconURI.cpp
@@ -449,9 +449,6 @@ nsMozIconURI::Clone(nsIURI **result)
   }
 
   nsMozIconURI *uri = new nsMozIconURI();
-  if (!uri)
-    return NS_ERROR_OUT_OF_MEMORY;
- 
   newIconURL.swap(uri->mIconURL);
   uri->mSize = mSize;
   uri->mContentType = mContentType;
@@ -464,6 +461,14 @@ nsMozIconURI::Clone(nsIURI **result)
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsMozIconURI::CloneIgnoringRef(nsIURI **result)
+{
+  // GetRef/SetRef not supported by nsMozIconURI, so
+  // CloneIgnoringRef() is the same as Clone().
+  return Clone(result);
+}
+
 NS_IMETHODIMP
 nsMozIconURI::Resolve(const nsACString &relativePath, nsACString &result)
 {
diff --git a/netwerk/base/public/nsIURI.idl b/netwerk/base/public/nsIURI.idl
index 63f3042919e5..4609f283156d 100644
--- a/netwerk/base/public/nsIURI.idl
+++ b/netwerk/base/public/nsIURI.idl
@@ -219,6 +219,11 @@ interface nsIURI : nsISupports
      */
     nsIURI clone();
 
+    /**
+     * Clones the current URI, clearing the 'ref' attribute in the clone.
+     */
+    nsIURI cloneIgnoringRef();
+
     /**
      * This method resolves a relative string into an absolute URI string,
      * using this URI as the base. 
diff --git a/netwerk/base/src/nsSimpleNestedURI.cpp b/netwerk/base/src/nsSimpleNestedURI.cpp
index 198d0353343a..2a56726a3c53 100644
--- a/netwerk/base/src/nsSimpleNestedURI.cpp
+++ b/netwerk/base/src/nsSimpleNestedURI.cpp
@@ -162,12 +162,15 @@ nsSimpleNestedURI::EqualsInternal(nsIURI* other,
 }
 
 /* virtual */ nsSimpleURI*
-nsSimpleNestedURI::StartClone()
+nsSimpleNestedURI::StartClone(nsSimpleURI::RefHandlingEnum refHandlingMode)
 {
     NS_ENSURE_TRUE(mInnerURI, nsnull);
     
     nsCOMPtr innerClone;
-    nsresult rv = mInnerURI->Clone(getter_AddRefs(innerClone));
+    nsresult rv = refHandlingMode == eHonorRef ?
+        mInnerURI->Clone(getter_AddRefs(innerClone)) :
+        mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
+
     if (NS_FAILED(rv)) {
         return nsnull;
     }
diff --git a/netwerk/base/src/nsSimpleNestedURI.h b/netwerk/base/src/nsSimpleNestedURI.h
index dfe1b39178b0..8ea27aec219d 100644
--- a/netwerk/base/src/nsSimpleNestedURI.h
+++ b/netwerk/base/src/nsSimpleNestedURI.h
@@ -77,7 +77,7 @@ public:
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     PRBool* result);
-    virtual nsSimpleURI* StartClone();
+    virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode);
 
     // nsISerializable overrides
     NS_IMETHOD Read(nsIObjectInputStream* aStream);
diff --git a/netwerk/base/src/nsSimpleURI.cpp b/netwerk/base/src/nsSimpleURI.cpp
index 121afdc062d6..af917fe25d95 100644
--- a/netwerk/base/src/nsSimpleURI.cpp
+++ b/netwerk/base/src/nsSimpleURI.cpp
@@ -395,15 +395,30 @@ nsSimpleURI::SchemeIs(const char *i_Scheme, PRBool *o_Equals)
 }
 
 /* virtual */ nsSimpleURI*
-nsSimpleURI::StartClone()
+nsSimpleURI::StartClone(nsSimpleURI::RefHandlingEnum /* ignored */)
 {
     return new nsSimpleURI();
 }
 
 NS_IMETHODIMP
-nsSimpleURI::Clone(nsIURI* *result)
+nsSimpleURI::Clone(nsIURI** result)
 {
-    nsSimpleURI* url = StartClone();
+    return CloneInternal(eHonorRef, result);
+}
+
+NS_IMETHODIMP
+nsSimpleURI::CloneIgnoringRef(nsIURI** result)
+{
+    return CloneInternal(eIgnoreRef, result);
+}
+
+nsresult
+nsSimpleURI::CloneInternal(nsSimpleURI::RefHandlingEnum refHandlingMode,
+                           nsIURI** result)
+{
+    // XXXdholbert Mostly ignoring refHandlingMode so far, but I'll make use
+    // of it in next patch, when I add support for .ref to this class.
+    nsSimpleURI* url = StartClone(refHandlingMode);
     if (url == nsnull)
         return NS_ERROR_OUT_OF_MEMORY;
 
diff --git a/netwerk/base/src/nsSimpleURI.h b/netwerk/base/src/nsSimpleURI.h
index ee6a1592c039..014c85f9935b 100644
--- a/netwerk/base/src/nsSimpleURI.h
+++ b/netwerk/base/src/nsSimpleURI.h
@@ -80,14 +80,20 @@ protected:
         eHonorRef
     };
 
-    // Helper to share code between Equals methods.  Subclasses can override
-    // for custom Equals behavior.
+    // Helper to share code between Equals methods.
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     PRBool* result);
 
-    virtual nsSimpleURI* StartClone();
+    // NOTE: This takes the refHandlingMode as an argument because
+    // nsSimpleNestedURI's specialized version needs to know how to clone
+    // its inner URI.
+    virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode);
 
+    // Helper to share code between Clone methods.
+    virtual nsresult CloneInternal(RefHandlingEnum refHandlingMode,
+                                   nsIURI** clone);
+    
     nsCString mScheme;
     nsCString mPath;
     PRBool mMutable;
diff --git a/netwerk/base/src/nsStandardURL.cpp b/netwerk/base/src/nsStandardURL.cpp
index 2db8224e83db..2f08b8af51cf 100644
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -1697,7 +1697,22 @@ nsStandardURL::StartClone()
 NS_IMETHODIMP
 nsStandardURL::Clone(nsIURI **result)
 {
-    nsStandardURL *clone = StartClone();
+    return CloneInternal(eHonorRef, result);
+}
+
+
+NS_IMETHODIMP
+nsStandardURL::CloneIgnoringRef(nsIURI **result)
+{
+    return CloneInternal(eIgnoreRef, result);
+}
+
+nsresult
+nsStandardURL::CloneInternal(nsStandardURL::RefHandlingEnum refHandlingMode,
+                             nsIURI **result)
+
+{
+    nsRefPtr clone = StartClone();
     if (!clone)
         return NS_ERROR_OUT_OF_MEMORY;
 
@@ -1727,7 +1742,11 @@ nsStandardURL::Clone(nsIURI **result)
     clone->mHostEncoding = mHostEncoding;
     clone->mSpecEncoding = mSpecEncoding;
 
-    NS_ADDREF(*result = clone);
+    if (refHandlingMode == eIgnoreRef) {
+        clone->SetRef(EmptyCString());
+    }
+
+    clone.forget(result);
     return NS_OK;
 }
 
diff --git a/netwerk/base/src/nsStandardURL.h b/netwerk/base/src/nsStandardURL.h
index a073894c0cf5..cc774a8161ed 100644
--- a/netwerk/base/src/nsStandardURL.h
+++ b/netwerk/base/src/nsStandardURL.h
@@ -167,6 +167,10 @@ protected:
 
     virtual nsStandardURL* StartClone();
 
+    // Helper to share code between Clone methods.
+    nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
+                           nsIURI** aClone);
+
     // Helper for subclass implementation of GetFile().  Subclasses that map
     // URIs to files in a special way should implement this method.  It should
     // ensure that our mFile is initialized, if it's possible.
diff --git a/netwerk/test/unit/test_URIs.js b/netwerk/test/unit/test_URIs.js
index e0ac3a7be734..18a30bc8b285 100644
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -196,6 +196,7 @@ function do_test_uri_basic(aTest) {
   // Sanity-check
   do_info("testing " + aTest.spec + " equals a clone of itself");
   do_check_uri_eq(URI, URI.clone());
+  do_check_uri_eq(URI, URI.cloneIgnoringRef());
   do_info("testing " + aTest.spec + " instanceof nsIURL");
   do_check_eq(URI instanceof Ci.nsIURL, aTest.nsIURL);
   do_info("testing " + aTest.spec + " instanceof nsINestedURI");
@@ -248,6 +249,17 @@ function do_test_uri_with_hash_suffix(aTest, aSuffix) {
     do_info("testing " + aTest.spec +
           " is equalExceptRef to self with '" + aSuffix + "' appended");
     do_check_uri_eqExceptRef(origURI, testURI);
+
+    do_info("testing cloneIgnoringRef on " + testURI.spec +
+            " is equal to no-ref version but not equal to ref version");
+    var cloneNoRef = testURI.cloneIgnoringRef();
+    if (aTest.spec == "http://" && aSuffix == "#") {
+      do_info("TODO: bug 657033");
+      do_check_uri_eq(cloneNoRef, origURI, todo_check_true);
+    } else {
+      do_check_uri_eq(cloneNoRef, origURI);
+    }
+    do_check_false(cloneNoRef.equals(testURI));
   }
 }
 

From 270f56506c73bef0e5d8c8dd4a1b5fef05e9fe35 Mon Sep 17 00:00:00 2001
From: Daniel Holbert 
Date: Sat, 21 May 2011 18:12:45 -0700
Subject: [PATCH 053/145] Bug 308590 patch 4: Add impl for .ref on nsSimpleURI.
 r=bz

---
 netwerk/base/src/nsSimpleURI.cpp | 164 ++++++++++++++++++++++---------
 netwerk/base/src/nsSimpleURI.h   |  16 +--
 netwerk/test/unit/test_URIs.js   |  62 +++++-------
 3 files changed, 151 insertions(+), 91 deletions(-)

diff --git a/netwerk/base/src/nsSimpleURI.cpp b/netwerk/base/src/nsSimpleURI.cpp
index af917fe25d95..1a7eb0a3b946 100644
--- a/netwerk/base/src/nsSimpleURI.cpp
+++ b/netwerk/base/src/nsSimpleURI.cpp
@@ -63,7 +63,8 @@ static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
 // nsSimpleURI methods:
 
 nsSimpleURI::nsSimpleURI()
-    : mMutable(PR_TRUE)
+    : mMutable(PR_TRUE),
+      mIsRefValid(PR_FALSE)
 {
 }
 
@@ -89,8 +90,14 @@ nsSimpleURI::Read(nsIObjectInputStream* aStream)
 {
     nsresult rv;
 
-    rv = aStream->ReadBoolean(&mMutable);
+    PRBool isMutable; // (because ReadBoolean doesn't support PRPackedBool*)
+    rv = aStream->ReadBoolean(&isMutable);
     if (NS_FAILED(rv)) return rv;
+    if (isMutable != PR_TRUE && isMutable != PR_FALSE) {
+        NS_WARNING("Unexpected boolean value");
+        return NS_ERROR_UNEXPECTED;
+    }
+    mMutable = isMutable;
 
     rv = aStream->ReadCString(mScheme);
     if (NS_FAILED(rv)) return rv;
@@ -98,6 +105,20 @@ nsSimpleURI::Read(nsIObjectInputStream* aStream)
     rv = aStream->ReadCString(mPath);
     if (NS_FAILED(rv)) return rv;
 
+    PRBool isRefValid;
+    rv = aStream->ReadBoolean(&isRefValid);
+    if (NS_FAILED(rv)) return rv;
+    if (isRefValid != PR_TRUE && isRefValid != PR_FALSE) {
+        NS_WARNING("Unexpected boolean value");
+        return NS_ERROR_UNEXPECTED;
+    }
+    mIsRefValid = isRefValid;
+
+    if (isRefValid) {
+      rv = aStream->ReadCString(mRef);
+      if (NS_FAILED(rv)) return rv;
+    }
+
     return NS_OK;
 }
 
@@ -115,6 +136,14 @@ nsSimpleURI::Write(nsIObjectOutputStream* aStream)
     rv = aStream->WriteStringZ(mPath.get());
     if (NS_FAILED(rv)) return rv;
 
+    rv = aStream->WriteBoolean(mIsRefValid);
+    if (NS_FAILED(rv)) return rv;
+
+    if (mIsRefValid) {
+        rv = aStream->WriteStringZ(mRef.get());
+        if (NS_FAILED(rv)) return rv;
+    }
+
     return NS_OK;
 }
 
@@ -124,13 +153,20 @@ nsSimpleURI::Write(nsIObjectOutputStream* aStream)
 PRBool
 nsSimpleURI::Read(const IPC::Message *aMsg, void **aIter)
 {
-    bool isMutable;
+    bool isMutable, isRefValid;
     if (!ReadParam(aMsg, aIter, &isMutable) ||
         !ReadParam(aMsg, aIter, &mScheme) ||
-        !ReadParam(aMsg, aIter, &mPath))
+        !ReadParam(aMsg, aIter, &mPath) ||
+        !ReadParam(aMsg, aIter, &isRefValid))
         return PR_FALSE;
 
     mMutable = isMutable;
+    mIsRefValid = isRefValid;
+
+    if (mIsRefValid) {
+        return ReadParam(aMsg, aIter, &mRef);
+    }
+
     return PR_TRUE;
 }
 
@@ -140,6 +176,10 @@ nsSimpleURI::Write(IPC::Message *aMsg)
     WriteParam(aMsg, bool(mMutable));
     WriteParam(aMsg, mScheme);
     WriteParam(aMsg, mPath);
+    WriteParam(aMsg, mIsRefValid);
+    if (mIsRefValid) {
+        WriteParam(aMsg, mRef);
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -149,6 +189,9 @@ NS_IMETHODIMP
 nsSimpleURI::GetSpec(nsACString &result)
 {
     result = mScheme + NS_LITERAL_CSTRING(":") + mPath;
+    if (mIsRefValid) {
+        result += NS_LITERAL_CSTRING("#") + mRef;
+    }
     return NS_OK;
 }
 
@@ -173,22 +216,17 @@ nsSimpleURI::SetSpec(const nsACString &aSpec)
     nsCAutoString spec;
     NS_EscapeURL(specPtr, specLen, esc_OnlyNonASCII|esc_AlwaysCopy, spec);
 
-    PRInt32 pos = spec.FindChar(':');
-    if (pos == -1 || !net_IsValidScheme(spec.get(), pos))
+    PRInt32 colonPos = spec.FindChar(':');
+    if (colonPos < 0 || !net_IsValidScheme(spec.get(), colonPos))
         return NS_ERROR_MALFORMED_URI;
 
     mScheme.Truncate();
-    mPath.Truncate();
-
-    PRInt32 n = spec.Left(mScheme, pos);
-    NS_ASSERTION(n == pos, "Left failed");
-
-    PRInt32 count = spec.Length() - pos - 1;
-    n = spec.Mid(mPath, pos + 1, count);
-    NS_ASSERTION(n == count, "Mid failed");
-
+    PRInt32 n = spec.Left(mScheme, colonPos);
+    NS_ASSERTION(n == colonPos, "Left failed");
     ToLowerCase(mScheme);
-    return NS_OK;
+
+    // This sets both mPath and mRef.
+    return SetPath(Substring(spec, colonPos + 1));
 }
 
 NS_IMETHODIMP
@@ -315,6 +353,10 @@ NS_IMETHODIMP
 nsSimpleURI::GetPath(nsACString &result)
 {
     result = mPath;
+    if (mIsRefValid) {
+        result += NS_LITERAL_CSTRING("#") + mRef;
+    }
+
     return NS_OK;
 }
 
@@ -323,22 +365,53 @@ nsSimpleURI::SetPath(const nsACString &path)
 {
     NS_ENSURE_STATE(mMutable);
     
-    mPath = path;
-    return NS_OK;
+    PRInt32 hashPos = path.FindChar('#');
+    if (hashPos < 0) {
+        mIsRefValid = PR_FALSE;
+        mPath = path;
+        return NS_OK;
+    }
+
+    mPath = StringHead(path, hashPos);
+    return SetRef(Substring(path, PRUint32(hashPos)));
 }
 
 NS_IMETHODIMP
 nsSimpleURI::GetRef(nsACString &result)
 {
-    // XXXdholbert Implement this.
-    return NS_ERROR_NOT_IMPLEMENTED;
+    if (!mIsRefValid) {
+      result.Truncate();
+    } else {
+      result = mRef;
+    }
+
+    return NS_OK;
 }
 
+// NOTE: SetRef("") removes our ref, whereas SetRef("#") sets it to the empty
+// string (and will result in .spec and .path having a terminal #).
 NS_IMETHODIMP
-nsSimpleURI::SetRef(const nsACString &ref)
+nsSimpleURI::SetRef(const nsACString &aRef)
 {
-    // XXXdholbert Implement this.
-    return NS_ERROR_NOT_IMPLEMENTED;
+    NS_ENSURE_STATE(mMutable);
+
+    if (aRef.IsEmpty()) {
+      // Empty string means to remove ref completely.
+      mIsRefValid = PR_FALSE;
+      mRef.Truncate();
+      return NS_OK;
+    }
+
+    mIsRefValid = PR_TRUE;
+
+    // Gracefully skip initial hash
+    if (aRef[0] == '#') {
+        mRef = Substring(aRef, 1);
+    } else {
+        mRef = aRef;
+    }
+
+    return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -358,21 +431,25 @@ nsSimpleURI::EqualsInternal(nsIURI* other,
                             nsSimpleURI::RefHandlingEnum refHandlingMode,
                             PRBool* result)
 {
-    // XXXdholbert Currently ignoring refHandlingMode.  I'll make use of it
-    // in next patch, when I add support for .ref to this class.
-    PRBool eq = PR_FALSE;
-    if (other) {
-        nsSimpleURI* otherUrl;
-        nsresult rv =
-            other->QueryInterface(kThisSimpleURIImplementationCID,
-                                  (void**)&otherUrl);
-        if (NS_SUCCEEDED(rv)) {
-            eq = PRBool((0 == strcmp(mScheme.get(), otherUrl->mScheme.get())) && 
-                        (0 == strcmp(mPath.get(), otherUrl->mPath.get())));
-            NS_RELEASE(otherUrl);
-        }
+    NS_ENSURE_ARG_POINTER(other);
+    NS_PRECONDITION(result, "null pointer");
+
+    nsRefPtr otherUri;
+    nsresult rv = other->QueryInterface(kThisSimpleURIImplementationCID,
+                                        getter_AddRefs(otherUri));
+    if (NS_FAILED(rv)) {
+        *result = PR_FALSE;
+        return NS_OK;
     }
-    *result = eq;
+
+    *result = (mScheme == otherUri->mScheme &&
+               mPath   == otherUri->mPath);
+
+    if (*result && refHandlingMode == eHonorRef) {
+        *result = (mIsRefValid == otherUri->mIsRefValid &&
+                   (!mIsRefValid || mRef == otherUri->mRef));
+    }
+
     return NS_OK;
 }
 
@@ -416,19 +493,19 @@ nsresult
 nsSimpleURI::CloneInternal(nsSimpleURI::RefHandlingEnum refHandlingMode,
                            nsIURI** result)
 {
-    // XXXdholbert Mostly ignoring refHandlingMode so far, but I'll make use
-    // of it in next patch, when I add support for .ref to this class.
-    nsSimpleURI* url = StartClone(refHandlingMode);
-    if (url == nsnull)
+    nsRefPtr url = StartClone(refHandlingMode);
+    if (!url)
         return NS_ERROR_OUT_OF_MEMORY;
 
     // Note: |url| may well have mMutable false at this point, so
     // don't call any setter methods.
     url->mScheme = mScheme;
     url->mPath = mPath;
+    if (refHandlingMode == eHonorRef) {
+        url->mRef = mRef;
+    }
 
-    *result = url;
-    NS_ADDREF(url);
+    url.forget(result);
     return NS_OK;
 }
 
@@ -548,4 +625,3 @@ nsSimpleURI::SetMutable(PRBool value)
     mMutable = value;
     return NS_OK;
 }
-
diff --git a/netwerk/base/src/nsSimpleURI.h b/netwerk/base/src/nsSimpleURI.h
index 014c85f9935b..1c9415ddfd66 100644
--- a/netwerk/base/src/nsSimpleURI.h
+++ b/netwerk/base/src/nsSimpleURI.h
@@ -47,11 +47,11 @@
 #include "nsIMutable.h"
 
 #define NS_THIS_SIMPLEURI_IMPLEMENTATION_CID         \
-{ /* 22b8f64a-2f7b-11d3-8cd0-0060b0fc14a3 */         \
-    0x22b8f64a,                                      \
-    0x2f7b,                                          \
-    0x11d3,                                          \
-    {0x8c, 0xd0, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
+{ /* 0b9bb0c2-fee6-470b-b9b9-9fd9462b5e19 */         \
+    0x0b9bb0c2,                                      \
+    0xfee6,                                          \
+    0x470b,                                          \
+    {0xb9, 0xb9, 0x9f, 0xd9, 0x46, 0x2b, 0x5e, 0x19} \
 }
 
 class nsSimpleURI : public nsIURI,
@@ -95,8 +95,10 @@ protected:
                                    nsIURI** clone);
     
     nsCString mScheme;
-    nsCString mPath;
-    PRBool mMutable;
+    nsCString mPath; // NOTE: mPath does not include ref, as an optimization
+    nsCString mRef;  // so that URIs with different refs can share string data.
+    PRPackedBool mMutable;
+    PRPackedBool mIsRefValid; // To distinguish between empty-ref and no-ref.
 };
 
 #endif // nsSimpleURI_h__
diff --git a/netwerk/test/unit/test_URIs.js b/netwerk/test/unit/test_URIs.js
index 18a30bc8b285..3db4031fb302 100644
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -207,13 +207,7 @@ function do_test_uri_basic(aTest) {
   do_check_property(aTest, URI, "scheme");
   do_check_property(aTest, URI, "prePath");
   do_check_property(aTest, URI, "path");
-
-  // XXXdholbert Only URLs (not URIs) support 'ref', until bug 308590's fix
-  // lands, so the following only checks 'ref' on URLs.
-  if (aTest.nsIURL) {
-    var URL = URI.QueryInterface(Ci.nsIURL);
-    do_check_property(aTest, URL, "ref");
-  }
+  do_check_property(aTest, URI, "ref");
 }
 
 // Test that a given URI parses correctly when we add a given ref to the end
@@ -234,33 +228,27 @@ function do_test_uri_with_hash_suffix(aTest, aSuffix) {
 
   do_check_false(origURI.equals(testURI));
 
+  do_info("testing " + aTest.spec +
+          " is equalExceptRef to self with '" + aSuffix + "' appended");
+  do_check_uri_eqExceptRef(origURI, testURI);
+
+  do_info("testing cloneIgnoringRef on " + testURI.spec +
+          " is equal to no-ref version but not equal to ref version");
+  var cloneNoRef = testURI.cloneIgnoringRef();
+  if (aTest.spec == "http://" && aSuffix == "#") {
+    do_info("TODO: bug 657033");
+    do_check_uri_eq(cloneNoRef, origURI, todo_check_true);
+  } else {
+    do_check_uri_eq(cloneNoRef, origURI);
+  }
+  do_check_false(cloneNoRef.equals(testURI));
+
   do_check_property(aTest, testURI, "scheme");
   do_check_property(aTest, testURI, "prePath");
   do_check_property(aTest, testURI, "path",
                     function(aStr) { return aStr + aSuffix; });
-
-  // XXXdholbert Only URLs (not URIs) support 'ref', until bug 308590's fix
-  // lands, so the following only checks 'ref' on URLs.
-  if (aTest.nsIURL) {
-    var URL = testURI.QueryInterface(Ci.nsIURL);
-    do_check_property(aTest, URL, "ref",
-                      function(aStr) { return aSuffix.substr(1); });
-
-    do_info("testing " + aTest.spec +
-          " is equalExceptRef to self with '" + aSuffix + "' appended");
-    do_check_uri_eqExceptRef(origURI, testURI);
-
-    do_info("testing cloneIgnoringRef on " + testURI.spec +
-            " is equal to no-ref version but not equal to ref version");
-    var cloneNoRef = testURI.cloneIgnoringRef();
-    if (aTest.spec == "http://" && aSuffix == "#") {
-      do_info("TODO: bug 657033");
-      do_check_uri_eq(cloneNoRef, origURI, todo_check_true);
-    } else {
-      do_check_uri_eq(cloneNoRef, origURI);
-    }
-    do_check_false(cloneNoRef.equals(testURI));
-  }
+  do_check_property(aTest, testURI, "ref",
+                    function(aStr) { return aSuffix.substr(1); });
 }
 
 // Tests various ways of setting & clearing a ref on a URI.
@@ -268,16 +256,10 @@ function do_test_mutate_ref(aTest, aSuffix) {
   do_info("making sure caller is using suffix that starts with '#'");
   do_check_eq(aSuffix[0], "#");
 
-  // XXXdholbert Only URLs (not URIs) support 'ref', until bug 308590's fix
-  // lands, so this function only works with URLs right now.
-  if (!aTest.nsIURL) {
-    return;
-  }
+  var refURIWithSuffix    = NetUtil.newURI(aTest.spec + aSuffix);
+  var refURIWithoutSuffix = NetUtil.newURI(aTest.spec);
 
-  var refURIWithSuffix    = NetUtil.newURI(aTest.spec + aSuffix).QueryInterface(Ci.nsIURL);
-  var refURIWithoutSuffix = NetUtil.newURI(aTest.spec).QueryInterface(Ci.nsIURL);
-
-  var testURI             = NetUtil.newURI(aTest.spec).QueryInterface(Ci.nsIURL);
+  var testURI             = NetUtil.newURI(aTest.spec);
 
   if (aTest.spec == "file://") {
     do_info("TODO: bug 656853");
@@ -329,7 +311,7 @@ function do_test_mutate_ref(aTest, aSuffix) {
   if (!(testURI instanceof Ci.nsIJARURI)) {
     // Now try setting .path directly (including suffix) and then clearing .ref
     // (same as above, but with now with .path instead of .spec)
-    testURI = NetUtil.newURI(aTest.spec).QueryInterface(Ci.nsIURL);
+    testURI = NetUtil.newURI(aTest.spec);
 
     var pathWithSuffix = aTest.path + aSuffix;
     do_info("testing that setting path to " +

From 7c96f3c728029f0d23739f44bc8931e2d228419b Mon Sep 17 00:00:00 2001
From: Daniel Holbert 
Date: Sat, 21 May 2011 18:12:46 -0700
Subject: [PATCH 054/145] Bug 308590 patch 5: Clean up QIs to nsIURL that are
 really checks for "Does this support GetRef/SetRef", now that nsIURI supports
 GetRef/SetRef too. r=bz

---
 content/base/src/Link.cpp                     | 12 ++-
 content/base/src/nsDocument.cpp               | 15 +---
 content/base/src/nsFrameLoader.cpp            | 24 +-----
 content/base/src/nsReferencedElement.cpp      | 56 ++++---------
 content/events/src/nsXMLEventsManager.cpp     | 15 ++--
 content/xbl/src/nsXBLPrototypeBinding.cpp     | 15 ++--
 content/xbl/src/nsXBLService.cpp              | 10 +--
 .../src/xslt/txMozillaStylesheetCompiler.cpp  | 11 +--
 .../xul/templates/src/nsXULContentUtils.cpp   | 61 +++++---------
 dom/base/nsLocation.cpp                       | 81 +++++++++----------
 netwerk/protocol/http/HttpBaseChannel.cpp     | 11 +--
 netwerk/protocol/http/nsHttpChannel.cpp       | 19 ++---
 uriloader/prefetch/nsOfflineCacheUpdate.cpp   | 18 +----
 13 files changed, 116 insertions(+), 232 deletions(-)

diff --git a/content/base/src/Link.cpp b/content/base/src/Link.cpp
index 67429bfa063b..be5436d62ad3 100644
--- a/content/base/src/Link.cpp
+++ b/content/base/src/Link.cpp
@@ -307,13 +307,12 @@ nsresult
 Link::SetHash(const nsAString &aHash)
 {
   nsCOMPtr uri(GetURIToMutate());
-  nsCOMPtr url(do_QueryInterface(uri));
-  if (!url) {
+  if (!uri) {
     // Ignore failures to be compatible with NS4.
     return NS_OK;
   }
 
-  (void)url->SetRef(NS_ConvertUTF16toUTF8(aHash));
+  (void)uri->SetRef(NS_ConvertUTF16toUTF8(aHash));
   SetHrefAttribute(uri);
   return NS_OK;
 }
@@ -444,15 +443,14 @@ Link::GetHash(nsAString &_hash)
   _hash.Truncate();
 
   nsCOMPtr uri(GetURI());
-  nsCOMPtr url(do_QueryInterface(uri));
-  if (!url) {
-    // Do not throw!  Not having a valid URI or URL should result in an empty
+  if (!uri) {
+    // Do not throw!  Not having a valid URI should result in an empty
     // string.
     return NS_OK;
   }
 
   nsCAutoString ref;
-  nsresult rv = url->GetRef(ref);
+  nsresult rv = uri->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     _hash.Assign(PRUnichar('#'));
diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp
index e34f40e60000..e895355d5363 100644
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -694,14 +694,10 @@ nsExternalResourceMap::RequestResource(nsIURI* aURI,
   
   // First, make sure we strip the ref from aURI.
   nsCOMPtr clone;
-  aURI->Clone(getter_AddRefs(clone));
-  if (!clone) {
+  nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(clone));
+  if (NS_FAILED(rv) || !clone) {
     return nsnull;
   }
-  nsCOMPtr url(do_QueryInterface(clone));
-  if (url) {
-    url->SetRef(EmptyCString());
-  }
   
   ExternalResource* resource;
   mMap.Get(clone, &resource);
@@ -712,14 +708,11 @@ nsExternalResourceMap::RequestResource(nsIURI* aURI,
   nsRefPtr load;
   mPendingLoads.Get(clone, getter_AddRefs(load));
   if (load) {
-    NS_ADDREF(*aPendingLoad = load);
+    load.forget(aPendingLoad);
     return nsnull;
   }
 
   load = new PendingLoad(aDisplayDocument);
-  if (!load) {
-    return nsnull;
-  }
 
   if (!mPendingLoads.Put(clone, load)) {
     return nsnull;
@@ -730,7 +723,7 @@ nsExternalResourceMap::RequestResource(nsIURI* aURI,
     // chances are it failed for good reasons (security check, etc).
     AddExternalResource(clone, nsnull, nsnull, aDisplayDocument);
   } else {
-    NS_ADDREF(*aPendingLoad = load);
+    load.forget(aPendingLoad);
   }
 
   return nsnull;
diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp
index 533784fcd12c..8515337552ba 100644
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1580,18 +1580,6 @@ nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
   }
   
   // Bug 136580: Check for recursive frame loading
-  // pre-grab these for speed
-  nsCOMPtr cloneURI;
-  rv = aURI->Clone(getter_AddRefs(cloneURI));
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  // Bug 98158/193011: We need to ignore data after the #
-  nsCOMPtr cloneURL(do_QueryInterface(cloneURI)); // QI can fail
-  if (cloneURL) {
-    rv = cloneURL->SetRef(EmptyCString());
-    NS_ENSURE_SUCCESS(rv,rv);
-  }
-
   PRInt32 matchCount = 0;
   treeItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
   while (parentAsItem) {
@@ -1602,17 +1590,9 @@ nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
       nsCOMPtr parentURI;
       parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
       if (parentURI) {
-        nsCOMPtr parentClone;
-        rv = parentURI->Clone(getter_AddRefs(parentClone));
-        NS_ENSURE_SUCCESS(rv, rv);
-        nsCOMPtr parentURL(do_QueryInterface(parentClone));
-        if (parentURL) {
-          rv = parentURL->SetRef(EmptyCString());
-          NS_ENSURE_SUCCESS(rv,rv);
-        }
-
+        // Bug 98158/193011: We need to ignore data after the #
         PRBool equal;
-        rv = cloneURI->Equals(parentClone, &equal);
+        rv = aURI->EqualsExceptRef(parentURI, &equal);
         NS_ENSURE_SUCCESS(rv, rv);
         
         if (equal) {
diff --git a/content/base/src/nsReferencedElement.cpp b/content/base/src/nsReferencedElement.cpp
index 6b5df36ecd68..585f7c06bf4d 100644
--- a/content/base/src/nsReferencedElement.cpp
+++ b/content/base/src/nsReferencedElement.cpp
@@ -40,7 +40,6 @@
 #include "nsContentUtils.h"
 #include "nsIURI.h"
 #include "nsBindingManager.h"
-#include "nsIURL.h"
 #include "nsEscape.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsIDOMNode.h"
@@ -48,50 +47,23 @@
 #include "nsIDOMElement.h"
 #include "nsCycleCollectionParticipant.h"
 
-static PRBool EqualExceptRef(nsIURL* aURL1, nsIURL* aURL2)
-{
-  nsCOMPtr u1;
-  nsCOMPtr u2;
-
-  nsresult rv = aURL1->Clone(getter_AddRefs(u1));
-  if (NS_SUCCEEDED(rv)) {
-    rv = aURL2->Clone(getter_AddRefs(u2));
-  }
-  if (NS_FAILED(rv))
-    return PR_FALSE;
-
-  nsCOMPtr url1 = do_QueryInterface(u1);
-  nsCOMPtr url2 = do_QueryInterface(u2);
-  if (!url1 || !url2) {
-    NS_WARNING("Cloning a URL produced a non-URL");
-    return PR_FALSE;
-  }
-  url1->SetRef(EmptyCString());
-  url2->SetRef(EmptyCString());
-
-  PRBool equal;
-  rv = url1->Equals(url2, &equal);
-  return NS_SUCCEEDED(rv) && equal;
-}
-
 void
 nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI,
                            PRBool aWatch, PRBool aReferenceImage)
 {
+  NS_ABORT_IF_FALSE(aFromContent, "Reset() expects non-null content pointer");
+  NS_ABORT_IF_FALSE(aURI, "Reset() expects non-null URI for referenced elem");
+
   Unlink();
 
-  nsCOMPtr url = do_QueryInterface(aURI);
-  if (!url)
-    return;
-
   nsCAutoString refPart;
-  url->GetRef(refPart);
+  aURI->GetRef(refPart);
   // Unescape %-escapes in the reference. The result will be in the
   // origin charset of the URL, hopefully...
   NS_UnescapeURL(refPart);
 
   nsCAutoString charset;
-  url->GetOriginCharset(charset);
+  aURI->GetOriginCharset(charset);
   nsAutoString ref;
   nsresult rv = nsContentUtils::ConvertStringFromCharset(charset, refPart, ref);
   if (NS_FAILED(rv)) {
@@ -109,9 +81,10 @@ nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI,
   if (bindingParent) {
     nsXBLBinding* binding = doc->BindingManager()->GetBinding(bindingParent);
     if (binding) {
-      nsCOMPtr bindingDocumentURL =
-        do_QueryInterface(binding->PrototypeBinding()->DocURI());
-      if (EqualExceptRef(url, bindingDocumentURL)) {
+      PRBool isEqualExceptRef;
+      rv = aURI->EqualsExceptRef(binding->PrototypeBinding()->DocURI(),
+                                 &isEqualExceptRef);
+      if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
         // XXX sXBL/XBL2 issue
         // Our content is an anonymous XBL element from a binding inside the
         // same document that the referenced URI points to. In order to avoid
@@ -139,13 +112,12 @@ nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI,
     }
   }
 
-  nsCOMPtr documentURL = do_QueryInterface(doc->GetDocumentURI());
-  // We've already checked that |url| is an nsIURL.  So if the document URI is
-  // not an nsIURL then |url| is certainly not going to be pointing to the same
-  // document as the document URI.
-  if (!documentURL || !EqualExceptRef(url, documentURL)) {
+  PRBool isEqualExceptRef;
+  rv = aURI->EqualsExceptRef(doc->GetDocumentURI(), &isEqualExceptRef);
+  if (NS_FAILED(rv) || !isEqualExceptRef) {
     nsRefPtr load;
-    doc = doc->RequestExternalResource(url, aFromContent, getter_AddRefs(load));
+    doc = doc->RequestExternalResource(aURI, aFromContent,
+                                       getter_AddRefs(load));
     if (!doc) {
       if (!load || !aWatch) {
         // Nothing will ever happen here
diff --git a/content/events/src/nsXMLEventsManager.cpp b/content/events/src/nsXMLEventsManager.cpp
index b1187b936ed9..683ab53d8c92 100644
--- a/content/events/src/nsXMLEventsManager.cpp
+++ b/content/events/src/nsXMLEventsManager.cpp
@@ -83,16 +83,11 @@ PRBool nsXMLEventsListener::InitXMLEventsListener(nsIDocument * aDocument,
     nsIURI *baseURI = aDocument->GetDocBaseURI();
     rv = NS_NewURI( getter_AddRefs(handlerURI), handlerURIStr, nsnull, baseURI);
     if (NS_SUCCEEDED(rv)) {
-      nsCOMPtr handlerURL(do_QueryInterface(handlerURI));
-      if (handlerURL) {
-        handlerURL->GetRef(handlerRef);
-        handlerURL->SetRef(EmptyCString());
-        //We support only XML Events Basic.
-        docURI->Equals(handlerURL, &equals);
-        if (equals) {
-          handler =
-            aDocument->GetElementById(NS_ConvertUTF8toUTF16(handlerRef));
-        }
+      handlerURI->GetRef(handlerRef);
+      // We support only XML Events Basic.
+      rv = docURI->EqualsExceptRef(handlerURI, &equals);
+      if (NS_SUCCEEDED(rv) && equals) {
+        handler = aDocument->GetElementById(NS_ConvertUTF8toUTF16(handlerRef));
       }
     }
   }
diff --git a/content/xbl/src/nsXBLPrototypeBinding.cpp b/content/xbl/src/nsXBLPrototypeBinding.cpp
index 98c034085830..fc4b640802e2 100644
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -305,16 +305,13 @@ nsXBLPrototypeBinding::Init(const nsACString& aID,
   nsresult rv = aInfo->DocumentURI()->Clone(getter_AddRefs(mBindingURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // The binding URI might not be a nsIURL (e.g. for data: URIs). In that case,
-  // we always use the first binding, so we don't need to keep track of the ID.
-  nsCOMPtr bindingURL = do_QueryInterface(mBindingURI);
-  if (bindingURL) {
-    if (aFirstBinding) {
-      rv = mBindingURI->Clone(getter_AddRefs(mAlternateBindingURI));
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    bindingURL->SetRef(aID);
+  // The binding URI might be an immutable URI (e.g. for about: URIs). In that case,
+  // we'll fail in SetRef below, but that doesn't matter much for now.
+  if (aFirstBinding) {
+    rv = mBindingURI->Clone(getter_AddRefs(mAlternateBindingURI));
+    NS_ENSURE_SUCCESS(rv, rv);
   }
+  mBindingURI->SetRef(aID);
 
   mXBLDocInfoWeak = aInfo;
 
diff --git a/content/xbl/src/nsXBLService.cpp b/content/xbl/src/nsXBLService.cpp
index 60d0a2956a24..38904b878f8c 100644
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -862,9 +862,7 @@ nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
     return NS_ERROR_FAILURE;
 
   nsCAutoString ref;
-  nsCOMPtr url(do_QueryInterface(aURI));
-  if (url)
-    url->GetRef(ref);
+  aURI->GetRef(ref);
 
   nsCOMPtr boundDocument = aBoundElement->GetOwnerDoc();
 
@@ -1129,12 +1127,8 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
   nsRefPtr info;
 
   nsCOMPtr documentURI;
-  rv = aBindingURI->Clone(getter_AddRefs(documentURI));
+  rv = aBindingURI->CloneIgnoringRef(getter_AddRefs(documentURI));
   NS_ENSURE_SUCCESS(rv, rv);
-  
-  nsCOMPtr documentURL(do_QueryInterface(documentURI));
-  if (documentURL)
-    documentURL->SetRef(EmptyCString());
 
 #ifdef MOZ_XUL
   // We've got a file.  Check our XBL document cache.
diff --git a/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp b/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
index 0bc91d99bd73..718c357900f7 100644
--- a/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
+++ b/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
@@ -743,15 +743,10 @@ TX_CompileStylesheet(nsINode* aNode, txMozillaXSLTProcessor* aProcessor,
     nsIURI* docUri = doc->GetDocumentURI();
     NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE);
 
-    docUri->Clone(getter_AddRefs(uri));
-    NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
-
-    // We need to remove the ref, a URL with a ref would mean that we have an
+    // We need to remove the ref, a URI with a ref would mean that we have an
     // embedded stylesheet.
-    nsCOMPtr url = do_QueryInterface(uri);
-    if (url) {
-        url->SetRef(EmptyCString());
-    }
+    docUri->CloneIgnoringRef(getter_AddRefs(uri));
+    NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
     uri->GetSpec(spec);
     NS_ConvertUTF8toUTF16 stylesheetURI(spec);
diff --git a/content/xul/templates/src/nsXULContentUtils.cpp b/content/xul/templates/src/nsXULContentUtils.cpp
index df7d367ad4c9..c64665474a7b 100644
--- a/content/xul/templates/src/nsXULContentUtils.cpp
+++ b/content/xul/templates/src/nsXULContentUtils.cpp
@@ -328,34 +328,29 @@ nsXULContentUtils::MakeElementURI(nsIDocument* aDocument,
     // Convert an element's ID to a URI that can be used to refer to
     // the element in the XUL graph.
 
-    nsIURI *docURL = aDocument->GetDocumentURI();
-    NS_ENSURE_TRUE(docURL, NS_ERROR_UNEXPECTED);
+    nsIURI *docURI = aDocument->GetDocumentURI();
+    NS_ENSURE_TRUE(docURI, NS_ERROR_UNEXPECTED);
 
-    nsCOMPtr docURIClone;
-    nsresult rv = docURL->Clone(getter_AddRefs(docURIClone));
+    nsRefPtr docURIClone;
+    nsresult rv = docURI->Clone(getter_AddRefs(docURIClone));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCOMPtr mutableURL(do_QueryInterface(docURIClone));
-    if (!mutableURL) {
-        nsCString uri;
-        rv = docURL->GetSpec(aURI);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        nsCAutoString ref;
-        NS_EscapeURL(NS_ConvertUTF16toUTF8(aElementID), esc_FilePath | esc_AlwaysCopy, ref);
-
-        aURI.Append('#');
-        aURI.Append(ref);
-
-        return NS_OK;
+    rv = docURIClone->SetRef(NS_ConvertUTF16toUTF8(aElementID));
+    if (NS_SUCCEEDED(rv)) {
+        return docURIClone->GetSpec(aURI);
     }
 
-    NS_ENSURE_TRUE(mutableURL, NS_ERROR_NOT_AVAILABLE);
-
-    rv = mutableURL->SetRef(NS_ConvertUTF16toUTF8(aElementID));
+    // docURIClone is apparently immutable. Fine - we can append ref manually.
+    rv = docURI->GetSpec(aURI);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    return mutableURL->GetSpec(aURI);
+    nsCAutoString ref;
+    NS_EscapeURL(NS_ConvertUTF16toUTF8(aElementID), esc_FilePath | esc_AlwaysCopy, ref);
+
+    aURI.Append('#');
+    aURI.Append(ref);
+
+    return NS_OK;
 }
 
 
@@ -390,27 +385,9 @@ nsXULContentUtils::MakeElementID(nsIDocument* aDocument,
                             aDocument->GetDocumentCharacterSet().get());
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCOMPtr url = do_QueryInterface(uri);
-    if (url) {
-        nsCAutoString ref;
-        url->GetRef(ref);
-        CopyUTF8toUTF16(ref, aElementID);
-    } else {
-        const char* start = aURI.BeginReading();
-        const char* end = aURI.EndReading();
-        const char* chr = end;
-
-        while (--chr >= start) {
-            if (*chr == '#') {
-                nsDependentCSubstring ref = Substring(chr + 1, end);
-                nsCAutoString unescaped;
-                CopyUTF8toUTF16(NS_UnescapeURL(ref, esc_FilePath, unescaped), aElementID);
-                return NS_OK;
-            }
-        }
-
-        aElementID.Truncate();
-    }
+    nsCAutoString ref;
+    uri->GetRef(ref);
+    CopyUTF8toUTF16(ref, aElementID);
 
     return NS_OK;
 }
diff --git a/dom/base/nsLocation.cpp b/dom/base/nsLocation.cpp
index b1b5560f60e0..52dbdccdb850 100644
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -374,46 +374,45 @@ nsLocation::GetHash(nsAString& aHash)
 
   nsCOMPtr uri;
   nsresult rv = GetURI(getter_AddRefs(uri));
+  if (NS_FAILED(rv) || !uri) {
+    return rv;
+  }
 
-  nsCOMPtr url(do_QueryInterface(uri));
+  nsCAutoString ref;
+  nsAutoString unicodeRef;
 
-  if (url) {
-    nsCAutoString ref;
-    nsAutoString unicodeRef;
+  rv = uri->GetRef(ref);
+  if (NS_SUCCEEDED(rv)) {
+    nsCOMPtr textToSubURI(
+        do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
 
-    rv = url->GetRef(ref);
     if (NS_SUCCEEDED(rv)) {
-      nsCOMPtr textToSubURI(
-          do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
-
-      if (NS_SUCCEEDED(rv)) {
-        nsCAutoString charset;
-        url->GetOriginCharset(charset);
+      nsCAutoString charset;
+      uri->GetOriginCharset(charset);
         
-        rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
-      }
+      rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
+    }
       
-      if (NS_FAILED(rv)) {
-        // Oh, well.  No intl here!
-        NS_UnescapeURL(ref);
-        CopyASCIItoUTF16(ref, unicodeRef);
-        rv = NS_OK;
-      }
+    if (NS_FAILED(rv)) {
+      // Oh, well.  No intl here!
+      NS_UnescapeURL(ref);
+      CopyASCIItoUTF16(ref, unicodeRef);
+      rv = NS_OK;
     }
+  }
 
-    if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
-      aHash.Assign(PRUnichar('#'));
-      aHash.Append(unicodeRef);
-    }
+  if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
+    aHash.Assign(PRUnichar('#'));
+    aHash.Append(unicodeRef);
+  }
 
-    if (aHash == mCachedHash) {
-      // Work around ShareThis stupidly polling location.hash every
-      // 5ms all the time by handing out the same exact string buffer
-      // we handed out last time.
-      aHash = mCachedHash;
-    } else {
-      mCachedHash = aHash;
-    }
+  if (aHash == mCachedHash) {
+    // Work around ShareThis stupidly polling location.hash every
+    // 5ms all the time by handing out the same exact string buffer
+    // we handed out last time.
+    aHash = mCachedHash;
+  } else {
+    mCachedHash = aHash;
   }
 
   return rv;
@@ -424,17 +423,17 @@ nsLocation::SetHash(const nsAString& aHash)
 {
   nsCOMPtr uri;
   nsresult rv = GetWritableURI(getter_AddRefs(uri));
+  if (NS_FAILED(rv) || !uri) {
+    return rv;
+  }
 
-  nsCOMPtr url(do_QueryInterface(uri));
-  if (url) {
-    NS_ConvertUTF16toUTF8 hash(aHash);
-    if (hash.IsEmpty() || hash.First() != PRUnichar('#')) {
-      hash.Insert(PRUnichar('#'), 0);
-    }
-    rv = url->SetRef(hash);
-    if (NS_SUCCEEDED(rv)) {
-      SetURI(url);
-    }
+  NS_ConvertUTF16toUTF8 hash(aHash);
+  if (hash.IsEmpty() || hash.First() != PRUnichar('#')) {
+    hash.Insert(PRUnichar('#'), 0);
+  }
+  rv = uri->SetRef(hash);
+  if (NS_SUCCEEDED(rv)) {
+    SetURI(uri);
   }
 
   return rv;
diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
index 556abc012538..6af98544f92a 100644
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -865,16 +865,13 @@ HttpBaseChannel::SetReferrer(nsIURI *referrer)
   //  (1) modify it
   //  (2) keep a reference to it after returning from this function
   //
-  rv = referrer->Clone(getter_AddRefs(clone));
+  // Use CloneIgnoringRef to strip away any fragment per RFC 2616 section 14.36
+  rv = referrer->CloneIgnoringRef(getter_AddRefs(clone));
   if (NS_FAILED(rv)) return rv;
 
   // strip away any userpass; we don't want to be giving out passwords ;-)
-  clone->SetUserPass(EmptyCString());
-
-  // strip away any fragment per RFC 2616 section 14.36
-  nsCOMPtr url = do_QueryInterface(clone);
-  if (url)
-    url->SetRef(EmptyCString());
+  rv = clone->SetUserPass(EmptyCString());
+  if (NS_FAILED(rv)) return rv;
 
   nsCAutoString spec;
   rv = clone->GetAsciiSpec(spec);
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
index 925e8e4aa8e0..bdd7dc568d70 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -3384,17 +3384,14 @@ nsHttpChannel::ContinueProcessRedirectionAfterFallback(nsresult rv)
 
     // move the reference of the old location to the new one if the new
     // one has none.
-    nsCOMPtr newURL = do_QueryInterface(mRedirectURI);
-    if (newURL) {
-        nsCAutoString ref;
-        rv = newURL->GetRef(ref);
-        if (NS_SUCCEEDED(rv) && ref.IsEmpty()) {
-            nsCOMPtr baseURL(do_QueryInterface(mURI));
-            if (baseURL) {
-                baseURL->GetRef(ref);
-                if (!ref.IsEmpty())
-                    newURL->SetRef(ref);
-            }
+    nsCAutoString ref;
+    rv = mRedirectURI->GetRef(ref);
+    if (NS_SUCCEEDED(rv) && ref.IsEmpty()) {
+        mURI->GetRef(ref);
+        if (!ref.IsEmpty()) {
+            // NOTE: SetRef will fail if mRedirectURI is immutable
+            // (e.g. an about: URI)... Oh well.
+            mRedirectURI->SetRef(ref);
         }
     }
 
diff --git a/uriloader/prefetch/nsOfflineCacheUpdate.cpp b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
index ecac02b2714d..cabb0ecc8168 100644
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -104,13 +104,9 @@ private:
 static nsresult
 DropReferenceFromURL(nsIURI * aURI)
 {
-    nsCOMPtr url = do_QueryInterface(aURI);
-    if (url) {
-        nsresult rv = url->SetRef(EmptyCString());
-        NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    return NS_OK;
+    // XXXdholbert If this SetRef fails, callers of this method probably
+    // want to call aURI->CloneIgnoringRef() and use the result of that.
+    return aURI->SetRef(EmptyCString());
 }
 
 //-----------------------------------------------------------------------------
@@ -1163,15 +1159,9 @@ nsOfflineCacheUpdate::GetCacheKey(nsIURI *aURI, nsACString &aKey)
     aKey.Truncate();
 
     nsCOMPtr newURI;
-    nsresult rv = aURI->Clone(getter_AddRefs(newURI));
+    nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(newURI));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCOMPtr newURL;
-    newURL = do_QueryInterface(newURI);
-    if (newURL) {
-        newURL->SetRef(EmptyCString());
-    }
-
     rv = newURI->GetAsciiSpec(aKey);
     NS_ENSURE_SUCCESS(rv, rv);
 

From 9b63119f9ae6c231a978be95cbf18a0e0d80866c Mon Sep 17 00:00:00 2001
From: Daniel Holbert 
Date: Sat, 21 May 2011 18:12:46 -0700
Subject: [PATCH 055/145] Bug 308590 patch 6: Fix nsDataHandler::NewURI to
 accept relative URI specifications like "#myRef". r=bz

---
 netwerk/protocol/data/nsDataHandler.cpp | 55 ++++++++++++++-----------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/netwerk/protocol/data/nsDataHandler.cpp b/netwerk/protocol/data/nsDataHandler.cpp
index f20f539c0b6e..688969472e32 100644
--- a/netwerk/protocol/data/nsDataHandler.cpp
+++ b/netwerk/protocol/data/nsDataHandler.cpp
@@ -101,34 +101,43 @@ nsDataHandler::NewURI(const nsACString &aSpec,
                       nsIURI *aBaseURI,
                       nsIURI **result) {
     nsresult rv;
+    nsRefPtr uri;
 
     nsCString spec(aSpec);
-    nsCAutoString contentType, contentCharset, dataBuffer;
-    PRBool base64;
-    rv = ParseURI(spec, contentType, contentCharset, base64, dataBuffer);
+
+    if (aBaseURI && !spec.IsEmpty() && spec[0] == '#') {
+        // Looks like a reference instead of a fully-specified URI.
+        // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
+        rv = aBaseURI->Clone(getter_AddRefs(uri));
+        if (NS_FAILED(rv))
+            return rv;
+        rv = uri->SetRef(spec);
+    } else {
+        // Otherwise, we'll assume |spec| is a fully-specified data URI
+        nsCAutoString contentType, contentCharset, dataBuffer;
+        PRBool base64;
+        rv = ParseURI(spec, contentType, contentCharset, base64, dataBuffer);
+        if (NS_FAILED(rv))
+            return rv;
+
+        // Strip whitespace unless this is text, where whitespace is important
+        // Don't strip escaped whitespace though (bug 391951)
+        if (base64 || (strncmp(contentType.get(),"text/",5) != 0 &&
+                       contentType.Find("xml") == kNotFound)) {
+            // it's ascii encoded binary, don't let any spaces in
+            spec.StripWhitespace();
+        }
+
+        uri = do_CreateInstance(kSimpleURICID, &rv);
+        if (NS_FAILED(rv))
+            return rv;
+        rv = uri->SetSpec(spec);
+    }
+
     if (NS_FAILED(rv))
         return rv;
 
-    // Strip whitespace unless this is text, where whitespace is important
-    // Don't strip escaped whitespace though (bug 391951)
-    if (base64 || (strncmp(contentType.get(),"text/",5) != 0 &&
-                   contentType.Find("xml") == kNotFound)) {
-        // it's ascii encoded binary, don't let any spaces in
-        spec.StripWhitespace();
-    }
- 
-
-    nsIURI* url;
-    rv = CallCreateInstance(kSimpleURICID, &url);
-    if (NS_FAILED(rv)) return rv;
-
-    rv = url->SetSpec(spec);
-    if (NS_FAILED(rv)) {
-        NS_RELEASE(url);
-        return rv;
-    }
-
-    *result = url;
+    uri.forget(result);
     return rv;
 }
 

From 6ce0ea820e848cc7d70bafb04511887982e8b6b5 Mon Sep 17 00:00:00 2001
From: Daniel Holbert 
Date: Sat, 21 May 2011 18:12:46 -0700
Subject: [PATCH 056/145] Bug 308590 patch 7: Reftest for SVG data URI
 including hash-reference to internal pattern. r=bz

---
 .../svg/data-uri-with-filter-01-ref.svg         | 13 +++++++++++++
 .../reftests/svg/data-uri-with-filter-01.xhtml  | 16 ++++++++++++++++
 .../svg/data-uri-with-gradient-01-ref.svg       |  9 +++++++++
 .../svg/data-uri-with-gradient-01.xhtml         | 16 ++++++++++++++++
 .../reftests/svg/data-uri-with-pattern-01.xhtml | 17 +++++++++++++++++
 layout/reftests/svg/reftest.list                |  3 +++
 6 files changed, 74 insertions(+)
 create mode 100644 layout/reftests/svg/data-uri-with-filter-01-ref.svg
 create mode 100644 layout/reftests/svg/data-uri-with-filter-01.xhtml
 create mode 100644 layout/reftests/svg/data-uri-with-gradient-01-ref.svg
 create mode 100644 layout/reftests/svg/data-uri-with-gradient-01.xhtml
 create mode 100644 layout/reftests/svg/data-uri-with-pattern-01.xhtml

diff --git a/layout/reftests/svg/data-uri-with-filter-01-ref.svg b/layout/reftests/svg/data-uri-with-filter-01-ref.svg
new file mode 100644
index 000000000000..d808930c34f7
--- /dev/null
+++ b/layout/reftests/svg/data-uri-with-filter-01-ref.svg
@@ -0,0 +1,13 @@
+
+  
+    
+      
+    
+  
+  
+    
+  
+
diff --git a/layout/reftests/svg/data-uri-with-filter-01.xhtml b/layout/reftests/svg/data-uri-with-filter-01.xhtml
new file mode 100644
index 000000000000..b8f21bd3948b
--- /dev/null
+++ b/layout/reftests/svg/data-uri-with-filter-01.xhtml
@@ -0,0 +1,16 @@
+
+
+
+
+  
+  Testcase for referencing a filter within a data URI
+
+
+  
+
+
diff --git a/layout/reftests/svg/data-uri-with-gradient-01-ref.svg b/layout/reftests/svg/data-uri-with-gradient-01-ref.svg
new file mode 100644
index 000000000000..3f842c69f6a4
--- /dev/null
+++ b/layout/reftests/svg/data-uri-with-gradient-01-ref.svg
@@ -0,0 +1,9 @@
+
+  
+    
+      
+      
+    
+  
+  
+
diff --git a/layout/reftests/svg/data-uri-with-gradient-01.xhtml b/layout/reftests/svg/data-uri-with-gradient-01.xhtml
new file mode 100644
index 000000000000..7da655ef1f98
--- /dev/null
+++ b/layout/reftests/svg/data-uri-with-gradient-01.xhtml
@@ -0,0 +1,16 @@
+
+
+
+
+  
+  Testcase for referencing a gradient within a data URI
+
+
+  
+
+
diff --git a/layout/reftests/svg/data-uri-with-pattern-01.xhtml b/layout/reftests/svg/data-uri-with-pattern-01.xhtml
new file mode 100644
index 000000000000..1587482f5801
--- /dev/null
+++ b/layout/reftests/svg/data-uri-with-pattern-01.xhtml
@@ -0,0 +1,17 @@
+
+
+
+
+  
+  Testcase for referencing a pattern within a data URI
+
+
+  
+
+
diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list
index 621dcd47f9fc..266e207ff42c 100644
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -41,6 +41,9 @@ fails-if(Android) == conditions-01.svg pass.svg # bug 652050
 == currentColor-01.svg pass.svg
 == currentColor-02.svg pass.svg
 == currentColor-03.svg pass.svg
+== data-uri-with-filter-01.xhtml data-uri-with-filter-01-ref.svg
+== data-uri-with-gradient-01.xhtml data-uri-with-gradient-01-ref.svg
+== data-uri-with-pattern-01.xhtml pass.svg
 == dynamic-attr-removal-1.svg pass.svg
 == dynamic-attr-removal-2.svg pass.svg
 == dynamic-attr-change-1.svg pass.svg

From 4ff34a416976106ce00a115cd0fa6b64f5d1e219 Mon Sep 17 00:00:00 2001
From: Patrick McManus 
Date: Sat, 21 May 2011 21:27:52 -0400
Subject: [PATCH 057/145] bug 640003 websockets - update incorporated
 pywebsockets to support -07 r=biesi

---
 testing/mochitest/Makefile.in                 |  15 +-
 testing/mochitest/pywebsocket/README          |  30 +-
 .../pywebsocket/mod_pywebsocket/__init__.py   |  83 ++-
 .../mod_pywebsocket/_stream_base.py           | 151 ++++++
 .../mod_pywebsocket/_stream_hixie75.py        | 218 ++++++++
 .../mod_pywebsocket/_stream_hybi06.py         | 510 ++++++++++++++++++
 .../pywebsocket/mod_pywebsocket/common.py     |  74 +++
 .../pywebsocket/mod_pywebsocket/dispatch.py   | 129 +++--
 .../mod_pywebsocket/handshake/__init__.py     |  61 ++-
 .../mod_pywebsocket/handshake/_base.py        |  77 ++-
 .../mod_pywebsocket/handshake/draft75.py      |  83 +--
 .../mod_pywebsocket/handshake/handshake.py    | 208 -------
 .../mod_pywebsocket/handshake/hybi00.py       | 232 ++++++++
 .../mod_pywebsocket/handshake/hybi06.py       | 250 +++++++++
 .../mod_pywebsocket/headerparserhandler.py    |  22 +-
 .../mod_pywebsocket/memorizingfile.py         |   2 +-
 .../pywebsocket/mod_pywebsocket/msgutil.py    | 146 +----
 .../pywebsocket/mod_pywebsocket/standalone.py | 476 ++++++++++++++++
 .../pywebsocket/mod_pywebsocket/stream.py     |  53 ++
 .../pywebsocket/mod_pywebsocket/util.py       | 216 +++++++-
 testing/mochitest/pywebsocket/standalone.py   |  60 ++-
 21 files changed, 2573 insertions(+), 523 deletions(-)
 create mode 100644 testing/mochitest/pywebsocket/mod_pywebsocket/_stream_base.py
 create mode 100644 testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hixie75.py
 create mode 100644 testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hybi06.py
 create mode 100644 testing/mochitest/pywebsocket/mod_pywebsocket/common.py
 delete mode 100644 testing/mochitest/pywebsocket/mod_pywebsocket/handshake/handshake.py
 create mode 100644 testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi00.py
 create mode 100755 testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi06.py
 create mode 100755 testing/mochitest/pywebsocket/mod_pywebsocket/standalone.py
 create mode 100644 testing/mochitest/pywebsocket/mod_pywebsocket/stream.py

diff --git a/testing/mochitest/Makefile.in b/testing/mochitest/Makefile.in
index 290eda6edfc4..ab5482f257cd 100644
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -108,18 +108,25 @@ _PYWEBSOCKET_FILES = \
 
 _MOD_PYWEBSOCKET_FILES = \
 		pywebsocket/mod_pywebsocket/__init__.py \
+		pywebsocket/mod_pywebsocket/common.py \
 		pywebsocket/mod_pywebsocket/dispatch.py \
-		pywebsocket/mod_pywebsocket/util.py \
-		pywebsocket/mod_pywebsocket/msgutil.py \
-		pywebsocket/mod_pywebsocket/memorizingfile.py \
 		pywebsocket/mod_pywebsocket/headerparserhandler.py \
+		pywebsocket/mod_pywebsocket/memorizingfile.py \
+		pywebsocket/mod_pywebsocket/util.py \
+		pywebsocket/mod_pywebsocket/stream.py \
+		pywebsocket/mod_pywebsocket/_stream_hixie75.py \
+		pywebsocket/mod_pywebsocket/msgutil.py \
+		pywebsocket/mod_pywebsocket/_stream_hybi06.py \
+		pywebsocket/mod_pywebsocket/standalone.py \
+		pywebsocket/mod_pywebsocket/_stream_base.py \
 		$(NULL)
 
 _HANDSHAKE_FILES = \
 		pywebsocket/mod_pywebsocket/handshake/__init__.py \
+		pywebsocket/mod_pywebsocket/handshake/hybi00.py \
 		pywebsocket/mod_pywebsocket/handshake/_base.py \
 		pywebsocket/mod_pywebsocket/handshake/draft75.py \
-		pywebsocket/mod_pywebsocket/handshake/handshake.py \
+		pywebsocket/mod_pywebsocket/handshake/hybi06.py \
 		$(NULL)
 
 _DEST_DIR = $(DEPTH)/_tests/$(relativesrcdir)
diff --git a/testing/mochitest/pywebsocket/README b/testing/mochitest/pywebsocket/README
index 6c93a907ee0b..b7d197338469 100644
--- a/testing/mochitest/pywebsocket/README
+++ b/testing/mochitest/pywebsocket/README
@@ -1 +1,29 @@
-This is mod_pywebsocket 0.5, from http://code.google.com/p/pywebsocket/
+mod_pywebsocket http://pywebsocket.googlecode.com/svn
+version 470
+supporting ietf-07
+
+includes the following minor patch::
+
+diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py b/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
+--- a/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
++++ b/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
+@@ -60,17 +60,18 @@ def _normalize_path(path):
+         path: the path to normalize.
+ 
+     Path is converted to the absolute path.
+     The input path can use either '\\' or '/' as the separator.
+     The normalized path always uses '/' regardless of the platform.
+     """
+ 
+     path = path.replace('\\', os.path.sep)
+-    path = os.path.realpath(path)
++    # do not normalize away symlinks in mochitest
++    # path = os.path.realpath(path)
+     path = path.replace('\\', '/')
+     return path
+ 
+ 
+ def _create_path_to_resource_converter(base_dir):
+     base_dir = _normalize_path(base_dir)
+ 
+     base_len = len(base_dir)
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/__init__.py b/testing/mochitest/pywebsocket/mod_pywebsocket/__init__.py
index d947128e9738..e33bc4cd91f4 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/__init__.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/__init__.py
@@ -28,11 +28,12 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-"""Web Socket extension for Apache HTTP Server.
+"""WebSocket extension for Apache HTTP Server.
 
-mod_pywebsocket is a Web Socket extension for Apache HTTP Server
+mod_pywebsocket is a WebSocket extension for Apache HTTP Server
 intended for testing or experimental purposes. mod_python is required.
 
+
 Installation:
 
 0. Prepare an Apache HTTP Server for which mod_python is enabled.
@@ -46,27 +47,26 @@ Installation:
        PythonPath "sys.path+['']"
 
    Always specify the following.  is the directory where
-   user-written Web Socket handlers are placed.
+   user-written WebSocket handlers are placed.
 
        PythonOption mod_pywebsocket.handler_root 
        PythonHeaderParserHandler mod_pywebsocket.headerparserhandler
 
-   To limit the search for Web Socket handlers to a directory 
+   To limit the search for WebSocket handlers to a directory 
    under , configure as follows:
 
        PythonOption mod_pywebsocket.handler_scan 
 
     is useful in saving scan time when 
-   contains many non-Web Socket handler files.
+   contains many non-WebSocket handler files.
 
    If you want to support old handshake based on
    draft-hixie-thewebsocketprotocol-75:
 
        PythonOption mod_pywebsocket.allow_draft75 On
 
-
    Example snippet of httpd.conf:
-   (mod_pywebsocket is in /websock_lib, Web Socket handlers are in
+   (mod_pywebsocket is in /websock_lib, WebSocket handlers are in
    /websock_handlers, port is 80 for ws, 443 for wss.)
 
        
@@ -75,9 +75,17 @@ Installation:
          PythonHeaderParserHandler mod_pywebsocket.headerparserhandler
        
 
-Writing Web Socket handlers:
+2. Tune Apache parameters for serving WebSocket. We'd like to note that at
+   least TimeOut directive from core features and RequestReadTimeout directive
+   from mod_reqtimeout should be modified not to kill connections in only a few
+   seconds of idle time.
 
-When a Web Socket request comes in, the resource name
+3. Verify installation. You can use example/console.html to poke the server.
+
+
+Writing WebSocket handlers:
+
+When a WebSocket request comes in, the resource name
 specified in the handshake is considered as if it is a file path under
  and the handler defined in
 /_wsh.py is invoked.
@@ -85,7 +93,7 @@ specified in the handshake is considered as if it is a file path under
 For example, if the resource name is /example/chat, the handler defined in
 /example/chat_wsh.py is invoked.
 
-A Web Socket handler is composed of the following two functions:
+A WebSocket handler is composed of the following two functions:
 
     web_socket_do_extra_handshake(request)
     web_socket_transfer_data(request)
@@ -94,16 +102,65 @@ where:
     request: mod_python request.
 
 web_socket_do_extra_handshake is called during the handshake after the
-headers are successfully parsed and Web Socket properties (ws_location,
-ws_origin, ws_protocol, and ws_resource) are added to request. A handler
+headers are successfully parsed and WebSocket properties (ws_location,
+ws_origin, and ws_resource) are added to request. A handler
 can reject the request by raising an exception.
 
+A request object has the following properties that you can use during the extra
+handshake (web_socket_do_extra_handshake):
+- ws_resource
+- ws_origin
+- ws_version
+- ws_location (Hixie 75 and HyBi 00 only)
+- ws_extensions (Hybi 06 and later)
+- ws_deflate (HyBi 06 and later)
+- ws_protocol
+- ws_requested_protocols (HyBi 06 and later)
+
+The last two are a bit tricky.
+
+For HyBi 06 and later, ws_protocol is always set to None when
+web_socket_do_extra_handshake is called. If ws_requested_protocols is not
+None, you must choose one subprotocol from this list and set it to ws_protocol.
+
+For Hixie 75 and HyBi 00, when web_socket_do_extra_handshake is called,
+ws_protocol is set to the value given by the client in Sec-WebSocket-Protocol
+(WebSocket-Protocol for Hixie 75) header or None if such header was not found
+in the opening handshake request. Finish extra handshake with ws_protocol
+untouched to accept the request subprotocol. Then, Sec-WebSocket-Protocol
+(or WebSocket-Protocol) header will be sent to the client in response with the
+same value as requested. Raise an exception in web_socket_do_extra_handshake to
+reject the requested subprotocol.
+
 web_socket_transfer_data is called after the handshake completed
 successfully. A handler can receive/send messages from/to the client
 using request. mod_pywebsocket.msgutil module provides utilities
 for data transfer.
 
-A Web Socket handler must be thread-safe if the server (Apache or
+You can receive a message by the following statement.
+
+    message = request.ws_stream.receive_message()
+
+This call blocks until any complete text frame arrives, and the payload data of
+the incoming frame will be stored into message. When you're using IETF HyBi 00
+or later protocol, receive_message() will return None on receiving
+client-initiated closing handshake. When any error occurs, receive_message()
+will raise some exception.
+
+You can send a message by the following statement.
+
+    request.ws_stream.send_message(message)
+
+Executing the following statement or just return-ing from
+web_socket_transfer_data cause connection close.
+
+    request.ws_stream.close_connection()
+
+When you're using IETF HyBi 00 or later protocol, close_connection will wait
+for closing handshake acknowledgement coming from the client. When it couldn't
+receive a valid acknowledgement, raises an exception.
+
+A WebSocket handler must be thread-safe if the server (Apache or
 standalone.py) is configured to use threads.
 """
 
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_base.py b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_base.py
new file mode 100644
index 000000000000..eb17d7f89bc9
--- /dev/null
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_base.py
@@ -0,0 +1,151 @@
+# Copyright 2011, Google 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:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 THE COPYRIGHT
+# OWNER 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.
+
+
+"""Base stream class.
+"""
+
+
+# Note: request.connection.write/read are used in this module, even though
+# mod_python document says that they should be used only in connection
+# handlers. Unfortunately, we have no other options. For example,
+# request.write/read are not suitable because they don't allow direct raw bytes
+# writing/reading.
+
+
+from mod_pywebsocket import util
+
+
+# Exceptions
+class ConnectionTerminatedException(Exception):
+    """This exception will be raised when a connection is terminated
+    unexpectedly.
+    """
+    pass
+
+
+class InvalidFrameException(ConnectionTerminatedException):
+    """This exception will be raised when we received an invalid frame we
+    cannot parse.
+    """
+    pass
+
+
+class BadOperationException(RuntimeError):
+    """This exception will be raised when send_message() is called on
+    server-terminated connection or receive_message() is called on
+    client-terminated connection.
+    """
+    pass
+
+
+class UnsupportedFrameException(RuntimeError):
+    """This exception will be raised when we receive a frame with flag, opcode
+    we cannot handle. Handlers can just catch and ignore this exception and
+    call receive_message() again to continue processing the next frame.
+    """
+    pass
+
+
+class StreamBase(object):
+    """Base stream class."""
+
+    def __init__(self, request):
+        """Construct an instance.
+
+        Args:
+            request: mod_python request.
+        """
+
+        self._logger = util.get_class_logger(self)
+
+        self._request = request
+
+    def _read(self, length):
+        """Reads length bytes from connection. In case we catch any exception,
+        prepends remote address to the exception message and raise again.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty string.
+        """
+
+        bytes = self._request.connection.read(length)
+        if not bytes:
+            raise ConnectionTerminatedException(
+                'Receiving %d byte failed. Peer (%r) closed connection' %
+                (length, (self._request.connection.remote_addr,)))
+        return bytes
+
+    def _write(self, bytes):
+        """Writes given bytes to connection. In case we catch any exception,
+        prepends remote address to the exception message and raise again.
+        """
+
+        try:
+            self._request.connection.write(bytes)
+        except Exception, e:
+            util.prepend_message_to_exception(
+                    'Failed to send message to %r: ' %
+                            (self._request.connection.remote_addr,),
+                    e)
+            raise
+
+    def receive_bytes(self, length):
+        """Receives multiple bytes. Retries read when we couldn't receive the
+        specified amount.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty string.
+        """
+
+        bytes = []
+        while length > 0:
+            new_bytes = self._read(length)
+            bytes.append(new_bytes)
+            length -= len(new_bytes)
+        return ''.join(bytes)
+
+    def _read_until(self, delim_char):
+        """Reads bytes until we encounter delim_char. The result will not
+        contain delim_char.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty string.
+        """
+
+        bytes = []
+        while True:
+            ch = self._read(1)
+            if ch == delim_char:
+                break
+            bytes.append(ch)
+        return ''.join(bytes)
+
+
+# vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hixie75.py b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hixie75.py
new file mode 100644
index 000000000000..429c899d8926
--- /dev/null
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hixie75.py
@@ -0,0 +1,218 @@
+# Copyright 2011, Google 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:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 THE COPYRIGHT
+# OWNER 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.
+
+
+"""Stream of WebSocket protocol with the framing used by IETF HyBi 00 and
+Hixie 75. For Hixie 75 this stream doesn't perform closing handshake.
+"""
+
+
+from mod_pywebsocket import common
+from mod_pywebsocket._stream_base import BadOperationException
+from mod_pywebsocket._stream_base import ConnectionTerminatedException
+from mod_pywebsocket._stream_base import InvalidFrameException
+from mod_pywebsocket._stream_base import StreamBase
+from mod_pywebsocket._stream_base import UnsupportedFrameException
+from mod_pywebsocket import util
+
+
+class StreamHixie75(StreamBase):
+    """Stream of WebSocket messages."""
+
+    def __init__(self, request, enable_closing_handshake=False):
+        """Construct an instance.
+
+        Args:
+            request: mod_python request.
+            enable_closing_handshake: to let StreamHixie75 perform closing
+                                      handshake as specified in HyBi 00, set
+                                      this option to True.
+        """
+
+        StreamBase.__init__(self, request)
+
+        self._logger = util.get_class_logger(self)
+
+        self._enable_closing_handshake = enable_closing_handshake
+
+        self._request.client_terminated = False
+        self._request.server_terminated = False
+
+    def send_message(self, message, end=True):
+        """Send message.
+
+        Args:
+            message: unicode string to send.
+
+        Raises:
+            BadOperationException: when called on a server-terminated
+                connection.
+        """
+
+        if not end:
+            raise BadOperationException(
+                'StreamHixie75 doesn\'t support send_message with end=False')
+
+        if self._request.server_terminated:
+            raise BadOperationException(
+                'Requested send_message after sending out a closing handshake')
+
+        self._write(''.join(['\x00', message.encode('utf-8'), '\xff']))
+
+    def _read_payload_length_hixie75(self):
+        """Reads a length header in a Hixie75 version frame with length.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty string.
+        """
+
+        length = 0
+        while True:
+            b_str = self._read(1)
+            b = ord(b_str)
+            length = length * 128 + (b & 0x7f)
+            if (b & 0x80) == 0:
+                break
+        return length
+
+    def receive_message(self):
+        """Receive a WebSocket frame and return its payload an unicode string.
+
+        Returns:
+            payload unicode string in a WebSocket frame.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty
+                string.
+            BadOperationException: when called on a client-terminated
+                connection.
+        """
+
+        if self._request.client_terminated:
+            raise BadOperationException(
+                'Requested receive_message after receiving a closing '
+                'handshake')
+
+        while True:
+            # Read 1 byte.
+            # mp_conn.read will block if no bytes are available.
+            # Timeout is controlled by TimeOut directive of Apache.
+            frame_type_str = self.receive_bytes(1)
+            frame_type = ord(frame_type_str)
+            if (frame_type & 0x80) == 0x80:
+                # The payload length is specified in the frame.
+                # Read and discard.
+                length = self._read_payload_length_hixie75()
+                if length > 0:
+                    _ = self.receive_bytes(length)
+                # 5.3 3. 12. if /type/ is 0xFF and /length/ is 0, then set the
+                # /client terminated/ flag and abort these steps.
+                if not self._enable_closing_handshake:
+                    continue
+
+                if frame_type == 0xFF and length == 0:
+                    self._request.client_terminated = True
+
+                    if self._request.server_terminated:
+                        self._logger.debug(
+                            'Received ack for server-initiated closing '
+                            'handshake')
+                        return None
+
+                    self._logger.debug(
+                        'Received client-initiated closing handshake')
+
+                    self._send_closing_handshake()
+                    self._logger.debug(
+                        'Sent ack for client-initiated closing handshake')
+                    return None
+            else:
+                # The payload is delimited with \xff.
+                bytes = self._read_until('\xff')
+                # The WebSocket protocol section 4.4 specifies that invalid
+                # characters must be replaced with U+fffd REPLACEMENT
+                # CHARACTER.
+                message = bytes.decode('utf-8', 'replace')
+                if frame_type == 0x00:
+                    return message
+                # Discard data of other types.
+
+    def _send_closing_handshake(self):
+        if not self._enable_closing_handshake:
+            raise BadOperationException(
+                'Closing handshake is not supported in Hixie 75 protocol')
+
+        self._request.server_terminated = True
+
+        # 5.3 the server may decide to terminate the WebSocket connection by
+        # running through the following steps:
+        # 1. send a 0xFF byte and a 0x00 byte to the client to indicate the
+        # start of the closing handshake.
+        self._write('\xff\x00')
+
+    def close_connection(self, unused_code='', unused_reason=''):
+        """Closes a WebSocket connection.
+
+        Raises:
+            ConnectionTerminatedException: when closing handshake was
+                not successfull.
+        """
+
+        if self._request.server_terminated:
+            self._logger.debug(
+                'Requested close_connection but server is already terminated')
+            return
+
+        if not self._enable_closing_handshake:
+            self._request.server_terminated = True
+            self._logger.debug('Connection closed')
+            return
+
+        self._send_closing_handshake()
+        self._logger.debug('Sent server-initiated closing handshake')
+
+        # TODO(ukai): 2. wait until the /client terminated/ flag has been set,
+        # or until a server-defined timeout expires.
+        #
+        # For now, we expect receiving closing handshake right after sending
+        # out closing handshake, and if we couldn't receive non-handshake
+        # frame, we take it as ConnectionTerminatedException.
+        message = self.receive_message()
+        if message is not None:
+            raise ConnectionTerminatedException(
+                'Didn\'t receive valid ack for closing handshake')
+        # TODO: 3. close the WebSocket connection.
+        # note: mod_python Connection (mp_conn) doesn't have close method.
+
+    def send_ping(self, body):
+        raise BadOperationException(
+            'StreamHixie75 doesn\'t support send_ping')
+
+
+# vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hybi06.py b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hybi06.py
new file mode 100644
index 000000000000..649556d2aaf7
--- /dev/null
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hybi06.py
@@ -0,0 +1,510 @@
+# Copyright 2011, Google 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:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 THE COPYRIGHT
+# OWNER 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.
+
+
+"""Stream class for IETF HyBi 07 WebSocket protocol.
+"""
+
+
+from collections import deque
+import os
+import struct
+
+from mod_pywebsocket import common
+from mod_pywebsocket import util
+from mod_pywebsocket._stream_base import BadOperationException
+from mod_pywebsocket._stream_base import ConnectionTerminatedException
+from mod_pywebsocket._stream_base import InvalidFrameException
+from mod_pywebsocket._stream_base import StreamBase
+from mod_pywebsocket._stream_base import UnsupportedFrameException
+
+
+def is_control_opcode(opcode):
+    return (opcode >> 3) == 1
+
+
+_NOOP_MASKER = util.NoopMasker()
+
+
+# Helper functions made public to be used for writing unittests for WebSocket
+# clients.
+def create_length_header(length, mask):
+    """Creates a length header.
+
+    Args:
+        length: Frame length. Must be less than 2^63.
+        mask: Mask bit. Must be boolean.
+
+    Raises:
+        ValueError: when bad data is given.
+    """
+
+    if mask:
+        mask_bit = 1 << 7
+    else:
+        mask_bit = 0
+
+    if length < 0:
+        raise ValueError('length must be non negative integer')
+    elif length <= 125:
+        return chr(mask_bit | length)
+    elif length < (1 << 16):
+        return chr(mask_bit | 126) + struct.pack('!H', length)
+    elif length < (1 << 63):
+        return chr(mask_bit | 127) + struct.pack('!Q', length)
+    else:
+        raise ValueError('Payload is too big for one frame')
+
+
+def create_header(opcode, payload_length, fin, rsv1, rsv2, rsv3, mask):
+    """Creates a frame header.
+
+    Raises:
+        Exception: when bad data is given.
+    """
+
+    if opcode < 0 or 0xf < opcode:
+        raise ValueError('Opcode out of range')
+
+    if payload_length < 0 or (1 << 63) <= payload_length:
+        raise ValueError('payload_length out of range')
+
+    if (fin | rsv1 | rsv2 | rsv3) & ~1:
+        raise ValueError('FIN bit and Reserved bit parameter must be 0 or 1')
+
+    header = ''
+
+    first_byte = ((fin << 7)
+                  | (rsv1 << 6) | (rsv2 << 5) | (rsv3 << 4)
+                  | opcode)
+    header += chr(first_byte)
+    header += create_length_header(payload_length, mask)
+
+    return header
+
+
+def _build_frame(header, body, mask):
+    if not mask:
+        return header + body
+
+    masking_nonce = os.urandom(4)
+    masker = util.RepeatedXorMasker(masking_nonce)
+
+    return header + masking_nonce + masker.mask(body)
+
+
+def create_text_frame(message, opcode=common.OPCODE_TEXT, fin=1, mask=False):
+    """Creates a simple text frame with no extension, reserved bit."""
+
+    encoded_message = message.encode('utf-8')
+    header = create_header(opcode, len(encoded_message), fin, 0, 0, 0, mask)
+    return _build_frame(header, encoded_message, mask)
+
+
+class FragmentedTextFrameBuilder(object):
+    """A stateful class to send a message as fragments."""
+
+    def __init__(self, mask):
+        """Constructs an instance."""
+
+        self._mask = mask
+
+        self._started = False
+
+    def build(self, message, end):
+        if self._started:
+            opcode = common.OPCODE_CONTINUATION
+        else:
+            opcode = common.OPCODE_TEXT
+
+        if end:
+            self._started = False
+            fin = 1
+        else:
+            self._started = True
+            fin = 0
+
+        return create_text_frame(message, opcode, fin, self._mask)
+
+
+def create_ping_frame(body, mask=False):
+    header = create_header(common.OPCODE_PING, len(body), 1, 0, 0, 0, mask)
+    return _build_frame(header, body, mask)
+
+
+def create_pong_frame(body, mask=False):
+    header = create_header(common.OPCODE_PONG, len(body), 1, 0, 0, 0, mask)
+    return _build_frame(header, body, mask)
+
+
+def create_close_frame(body, mask=False):
+    header = create_header(common.OPCODE_CLOSE, len(body), 1, 0, 0, 0, mask)
+    return _build_frame(header, body, mask)
+
+
+class StreamOptions(object):
+    def __init__(self):
+        self.deflate = False
+        self.mask_send = False
+        self.unmask_receive = True
+
+
+class Stream(StreamBase):
+    """Stream of WebSocket messages."""
+
+    def __init__(self, request, options):
+        """Constructs an instance.
+
+        Args:
+            request: mod_python request.
+        """
+
+        StreamBase.__init__(self, request)
+
+        self._logger = util.get_class_logger(self)
+
+        self._options = options
+
+        if self._options.deflate:
+            self._logger.debug('Deflated stream')
+            self._request = util.DeflateRequest(self._request)
+
+        self._request.client_terminated = False
+        self._request.server_terminated = False
+
+        # Holds body of received fragments.
+        self._received_fragments = []
+        # Holds the opcode of the first fragment.
+        self._original_opcode = None
+
+        self._writer = FragmentedTextFrameBuilder(self._options.mask_send)
+
+        self._ping_queue = deque()
+
+    def _receive_frame(self):
+        """Receives a frame and return data in the frame as a tuple containing
+        each header field and payload separately.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty
+                string.
+            InvalidFrameException: when the frame contains invalid data.
+        """
+
+        received = self.receive_bytes(2)
+
+        first_byte = ord(received[0])
+        fin = (first_byte >> 7) & 1
+        rsv1 = (first_byte >> 6) & 1
+        rsv2 = (first_byte >> 5) & 1
+        rsv3 = (first_byte >> 4) & 1
+        opcode = first_byte & 0xf
+
+        second_byte = ord(received[1])
+        mask = (second_byte >> 7) & 1
+        payload_length = second_byte & 0x7f
+
+        if (mask == 1) != self._options.unmask_receive:
+            raise InvalidFrameException(
+                'Mask bit on the received frame did\'nt match masking '
+                'configuration for received frames')
+
+        if payload_length == 127:
+            extended_payload_length = self.receive_bytes(8)
+            payload_length = struct.unpack(
+                '!Q', extended_payload_length)[0]
+            if payload_length > 0x7FFFFFFFFFFFFFFF:
+                raise InvalidFrameException(
+                    'Extended payload length >= 2^63')
+        elif payload_length == 126:
+            extended_payload_length = self.receive_bytes(2)
+            payload_length = struct.unpack(
+                '!H', extended_payload_length)[0]
+
+        if mask == 1:
+            masking_nonce = self.receive_bytes(4)
+            masker = util.RepeatedXorMasker(masking_nonce)
+        else:
+            masker = _NOOP_MASKER
+
+        bytes = masker.mask(self.receive_bytes(payload_length))
+
+        return opcode, bytes, fin, rsv1, rsv2, rsv3
+
+    def send_message(self, message, end=True):
+        """Send message.
+
+        Args:
+            message: unicode string to send.
+
+        Raises:
+            BadOperationException: when called on a server-terminated
+                connection.
+        """
+
+        if self._request.server_terminated:
+            raise BadOperationException(
+                'Requested send_message after sending out a closing handshake')
+
+        self._write(self._writer.build(message, end))
+
+    def receive_message(self):
+        """Receive a WebSocket frame and return its payload an unicode string.
+
+        Returns:
+            payload unicode string in a WebSocket frame. None iff received
+            closing handshake.
+        Raises:
+            BadOperationException: when called on a client-terminated
+                connection.
+            ConnectionTerminatedException: when read returns empty
+                string.
+            InvalidFrameException: when the frame contains invalid
+                data.
+            UnsupportedFrameException: when the received frame has
+                flags, opcode we cannot handle. You can ignore this exception
+                and continue receiving the next frame.
+        """
+
+        if self._request.client_terminated:
+            raise BadOperationException(
+                'Requested receive_message after receiving a closing handshake')
+
+        while True:
+            # mp_conn.read will block if no bytes are available.
+            # Timeout is controlled by TimeOut directive of Apache.
+
+            opcode, bytes, fin, rsv1, rsv2, rsv3 = self._receive_frame()
+            if rsv1 or rsv2 or rsv3:
+                raise UnsupportedFrameException(
+                    'Unsupported flag is set (rsv = %d%d%d)' %
+                    (rsv1, rsv2, rsv3))
+
+            if opcode == common.OPCODE_CONTINUATION:
+                if not self._received_fragments:
+                    if fin:
+                        raise InvalidFrameException(
+                            'Received a termination frame but fragmentation '
+                            'not started')
+                    else:
+                        raise InvalidFrameException(
+                            'Received an intermediate frame but '
+                            'fragmentation not started')
+
+                if fin:
+                    # End of fragmentation frame
+                    self._received_fragments.append(bytes)
+                    message = ''.join(self._received_fragments)
+                    self._received_fragments = []
+                else:
+                    # Intermediate frame
+                    self._received_fragments.append(bytes)
+                    continue
+            else:
+                if self._received_fragments:
+                    if fin:
+                        raise InvalidFrameException(
+                            'Received an unfragmented frame without '
+                            'terminating existing fragmentation')
+                    else:
+                        raise InvalidFrameException(
+                            'New fragmentation started without terminating '
+                            'existing fragmentation')
+
+                if fin:
+                    # Unfragmented frame
+                    self._original_opcode = opcode
+                    message = bytes
+
+                    if is_control_opcode(opcode) and len(message) > 125:
+                        raise InvalidFrameException(
+                            'Application data size of control frames must be '
+                            '125 bytes or less')
+                else:
+                    # Start of fragmentation frame
+
+                    if is_control_opcode(opcode):
+                        raise InvalidFrameException(
+                            'Control frames must not be fragmented')
+
+                    self._original_opcode = opcode
+                    self._received_fragments.append(bytes)
+                    continue
+
+            if self._original_opcode == common.OPCODE_TEXT:
+                # The WebSocket protocol section 4.4 specifies that invalid
+                # characters must be replaced with U+fffd REPLACEMENT
+                # CHARACTER.
+                return message.decode('utf-8', 'replace')
+            elif self._original_opcode == common.OPCODE_CLOSE:
+                self._request.client_terminated = True
+
+                # Status code is optional. We can have status reason only if we
+                # have status code. Status reason can be empty string. So,
+                # allowed cases are
+                # - no application data: no code no reason
+                # - 2 octet of application data: has code but no reason
+                # - 3 or more octet of application data: both code and reason
+                if len(message) == 1:
+                    raise InvalidFrameException(
+                        'If a close frame has status code, the length of '
+                        'status code must be 2 octet')
+                elif len(message) >= 2:
+                    self._request.ws_close_code = struct.unpack(
+                        '!H', message[0:2])[0]
+                    self._request.ws_close_reason = message[2:].decode(
+                        'utf-8', 'replace')
+
+                if self._request.server_terminated:
+                    self._logger.debug(
+                        'Received ack for server-initiated closing '
+                        'handshake')
+                    return None
+
+                self._logger.debug(
+                    'Received client-initiated closing handshake')
+
+                self._send_closing_handshake(common.STATUS_NORMAL, '')
+                self._logger.debug(
+                    'Sent ack for client-initiated closing handshake')
+                return None
+            elif self._original_opcode == common.OPCODE_PING:
+                try:
+                    handler = self._request.on_ping_handler
+                    if handler:
+                        handler(self._request, message)
+                        continue
+                except AttributeError, e:
+                    pass
+                self._send_pong(message)
+            elif self._original_opcode == common.OPCODE_PONG:
+                # TODO(tyoshino): Add ping timeout handling.
+
+                inflight_pings = deque()
+
+                while True:
+                    try:
+                        expected_body = self._ping_queue.popleft()
+                        if expected_body == message:
+                            # inflight_pings contains pings ignored by the
+                            # other peer. Just forget them.
+                            self._logger.debug(
+                                'Ping %r is acked (%d pings were ignored)' %
+                                (expected_body, len(inflight_pings)))
+                            break
+                        else:
+                            inflight_pings.append(expected_body)
+                    except IndexError, e:
+                        # The received pong was unsolicited pong. Keep the
+                        # ping queue as is.
+                        self._ping_queue = inflight_pings
+                        self._logger.debug('Received a unsolicited pong')
+                        break
+
+                try:
+                    handler = self._request.on_pong_handler
+                    if handler:
+                        handler(self._request, message)
+                        continue
+                except AttributeError, e:
+                    pass
+
+                continue
+            else:
+                raise UnsupportedFrameException(
+                    'Opcode %d is not supported' % self._original_opcode)
+
+    def _send_closing_handshake(self, code, reason):
+        if code >= (1 << 16) or code < 0:
+            raise BadOperationException('Status code is out of range')
+
+        encoded_reason = reason.encode('utf-8')
+        if len(encoded_reason) + 2 > 125:
+            raise BadOperationException(
+                'Application data size of close frames must be 125 bytes or '
+                'less')
+
+        frame = create_close_frame(
+            struct.pack('!H', code) + encoded_reason, self._options.mask_send)
+
+        self._request.server_terminated = True
+
+        self._write(frame)
+
+    def close_connection(self, code=common.STATUS_NORMAL, reason=''):
+        """Closes a WebSocket connection."""
+
+        if self._request.server_terminated:
+            self._logger.debug(
+                'Requested close_connection but server is already terminated')
+            return
+
+        self._send_closing_handshake(code, reason)
+        self._logger.debug('Sent server-initiated closing handshake')
+
+        if (code == common.STATUS_GOING_AWAY or
+            code == common.STATUS_PROTOCOL_ERROR):
+            # It doesn't make sense to wait for a close frame if the reason is
+            # protocol error or that the server is going away. For some of other
+            # reasons, it might not make sense to wait for a close frame, but
+            # it's not clear, yet.
+            return
+
+        # TODO(ukai): 2. wait until the /client terminated/ flag has been set,
+        # or until a server-defined timeout expires.
+        #
+        # For now, we expect receiving closing handshake right after sending
+        # out closing handshake.
+        message = self.receive_message()
+        if message is not None:
+            raise ConnectionTerminatedException(
+                'Didn\'t receive valid ack for closing handshake')
+        # TODO: 3. close the WebSocket connection.
+        # note: mod_python Connection (mp_conn) doesn't have close method.
+
+    def send_ping(self, body=''):
+        if len(body) > 125:
+            raise ValueError(
+                'Application data size of control frames must be 125 bytes or '
+                'less')
+        frame = create_ping_frame(body, self._options.mask_send)
+        self._write(frame)
+
+        self._ping_queue.append(body)
+
+    def _send_pong(self, body):
+        if len(body) > 125:
+            raise ValueError(
+                'Application data size of control frames must be 125 bytes or '
+                'less')
+        frame = create_pong_frame(body, self._options.mask_send)
+        self._write(frame)
+
+
+# vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/common.py b/testing/mochitest/pywebsocket/mod_pywebsocket/common.py
new file mode 100644
index 000000000000..e76b70ecac77
--- /dev/null
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/common.py
@@ -0,0 +1,74 @@
+# Copyright 2011, Google 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:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 THE COPYRIGHT
+# OWNER 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.
+
+
+# Constants indicating WebSocket protocol version.
+VERSION_HYBI07 = 7
+VERSION_HYBI00 = 0
+VERSION_HIXIE75 = -1
+
+# Port numbers
+DEFAULT_WEB_SOCKET_PORT = 80
+DEFAULT_WEB_SOCKET_SECURE_PORT = 443
+
+# Schemes
+WEB_SOCKET_SCHEME = 'ws'
+WEB_SOCKET_SECURE_SCHEME = 'wss'
+
+# Frame opcodes defined in the spec.
+OPCODE_CONTINUATION = 0x0
+OPCODE_TEXT = 0x1
+OPCODE_BINARY = 0x2
+OPCODE_CLOSE = 0x8
+OPCODE_PING = 0x9
+OPCODE_PONG = 0xa
+
+# UUIDs used by HyBi 07 opening handshake and frame masking.
+WEBSOCKET_ACCEPT_UUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
+
+# Opening handshake header names and expected values.
+UPGRADE_HEADER = 'Upgrade'
+WEBSOCKET_UPGRADE_TYPE = 'websocket'
+WEBSOCKET_UPGRADE_TYPE_HIXIE75 = 'WebSocket'
+CONNECTION_HEADER = 'Connection'
+UPGRADE_CONNECTION_TYPE = 'Upgrade'
+HOST_HEADER = 'Host'
+SEC_WEBSOCKET_ORIGIN_HEADER = 'Sec-WebSocket-Origin'
+SEC_WEBSOCKET_KEY_HEADER = 'Sec-WebSocket-Key'
+SEC_WEBSOCKET_ACCEPT_HEADER = 'Sec-WebSocket-Accept'
+SEC_WEBSOCKET_VERSION_HEADER = 'Sec-WebSocket-Version'
+SEC_WEBSOCKET_PROTOCOL_HEADER = 'Sec-WebSocket-Protocol'
+SEC_WEBSOCKET_EXTENSIONS_HEADER = 'Sec-WebSocket-Extensions'
+
+# Status codes
+STATUS_NORMAL = 1000
+STATUS_GOING_AWAY = 1001
+STATUS_PROTOCOL_ERROR = 1002
+STATUS_UNSUPPORTED = 1003
+STATUS_TOO_LARGE = 1004
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py b/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
index 42c48fd8dea8..4a13194853db 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
@@ -1,4 +1,4 @@
-# Copyright 2009, Google Inc.
+# Copyright 2011, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,13 +28,15 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-"""Dispatch Web Socket request.
+"""Dispatch WebSocket request.
 """
 
 
+import logging
 import os
 import re
 
+from mod_pywebsocket import common
 from mod_pywebsocket import msgutil
 from mod_pywebsocket import util
 
@@ -46,7 +48,7 @@ _TRANSFER_DATA_HANDLER_NAME = 'web_socket_transfer_data'
 
 
 class DispatchError(Exception):
-    """Exception in dispatching Web Socket request."""
+    """Exception in dispatching WebSocket request."""
 
     pass
 
@@ -63,15 +65,18 @@ def _normalize_path(path):
     """
 
     path = path.replace('\\', os.path.sep)
-    #path = os.path.realpath(path)
+    # do not normalize away symlinks in mochitest
+    # path = os.path.realpath(path)
     path = path.replace('\\', '/')
     return path
 
 
-def _path_to_resource_converter(base_dir):
+def _create_path_to_resource_converter(base_dir):
     base_dir = _normalize_path(base_dir)
+
     base_len = len(base_dir)
     suffix_len = len(_SOURCE_SUFFIX)
+
     def converter(path):
         if not path.endswith(_SOURCE_SUFFIX):
             return None
@@ -79,11 +84,14 @@ def _path_to_resource_converter(base_dir):
         if not path.startswith(base_dir):
             return None
         return path[base_len:-suffix_len]
+
     return converter
 
 
-def _source_file_paths(directory):
-    """Yield Web Socket Handler source file names in the given directory."""
+def _enumerate_handler_file_paths(directory):
+    """Returns a generator that enumerates WebSocket Handler source file names
+    in the given directory.
+    """
 
     for root, unused_dirs, files in os.walk(directory):
         for base in files:
@@ -92,20 +100,38 @@ def _source_file_paths(directory):
                 yield path
 
 
-def _source(source_str):
-    """Source a handler definition string."""
+class _HandlerSuite(object):
+    """A handler suite holder class."""
+
+    def __init__(self, do_extra_handshake, transfer_data):
+        self.do_extra_handshake = do_extra_handshake
+        self.transfer_data = transfer_data
+
+
+def _source_handler_file(handler_definition):
+    """Source a handler definition string.
+
+    Args:
+        handler_definition: a string containing Python statements that define
+                            handler functions.
+    """
 
     global_dic = {}
     try:
-        exec source_str in global_dic
+        exec handler_definition in global_dic
     except Exception:
         raise DispatchError('Error in sourcing handler:' +
                             util.get_stack_trace())
-    return (_extract_handler(global_dic, _DO_EXTRA_HANDSHAKE_HANDLER_NAME),
-            _extract_handler(global_dic, _TRANSFER_DATA_HANDLER_NAME))
+    return _HandlerSuite(
+        _extract_handler(global_dic, _DO_EXTRA_HANDSHAKE_HANDLER_NAME),
+        _extract_handler(global_dic, _TRANSFER_DATA_HANDLER_NAME))
 
 
 def _extract_handler(dic, name):
+    """Extracts a callable with the specified name from the given dictionary
+    dic.
+    """
+
     if name not in dic:
         raise DispatchError('%s is not defined.' % name)
     handler = dic[name]
@@ -115,7 +141,7 @@ def _extract_handler(dic, name):
 
 
 class Dispatcher(object):
-    """Dispatches Web Socket requests.
+    """Dispatches WebSocket requests.
 
     This class maintains a map from resource name to handlers.
     """
@@ -133,7 +159,9 @@ class Dispatcher(object):
                       scan time when root_dir contains many subdirectories.
         """
 
-        self._handlers = {}
+        self._logger = util.get_class_logger(self)
+
+        self._handler_suite_map = {}
         self._source_warnings = []
         if scan_dir is None:
             scan_dir = root_dir
@@ -141,7 +169,7 @@ class Dispatcher(object):
                 os.path.realpath(root_dir)):
             raise DispatchError('scan_dir:%s must be a directory under '
                                 'root_dir:%s.' % (scan_dir, root_dir))
-        self._source_files_in_dir(root_dir, scan_dir)
+        self._source_handler_files_in_dir(root_dir, scan_dir)
 
     def add_resource_path_alias(self,
                                 alias_resource_path, existing_resource_path):
@@ -155,8 +183,8 @@ class Dispatcher(object):
             existing_resource_path: existing resource path
         """
         try:
-            handler = self._handlers[existing_resource_path]
-            self._handlers[alias_resource_path] = handler
+            handler_suite = self._handler_suite_map[existing_resource_path]
+            self._handler_suite_map[alias_resource_path] = handler_suite
         except KeyError:
             raise DispatchError('No handler for: %r' % existing_resource_path)
 
@@ -166,7 +194,7 @@ class Dispatcher(object):
         return self._source_warnings
 
     def do_extra_handshake(self, request):
-        """Do extra checking in Web Socket handshake.
+        """Do extra checking in WebSocket handshake.
 
         Select a handler based on request.uri and call its
         web_socket_do_extra_handshake function.
@@ -175,7 +203,8 @@ class Dispatcher(object):
             request: mod_python request.
         """
 
-        do_extra_handshake_, unused_transfer_data = self._handler(request)
+        do_extra_handshake_ = self._get_handler_suite(
+            request).do_extra_handshake
         try:
             do_extra_handshake_(request)
         except Exception, e:
@@ -187,7 +216,7 @@ class Dispatcher(object):
             raise
 
     def transfer_data(self, request):
-        """Let a handler transfer_data with a Web Socket client.
+        """Let a handler transfer_data with a WebSocket client.
 
         Select a handler based on request.ws_resource and call its
         web_socket_transfer_data function.
@@ -196,50 +225,58 @@ class Dispatcher(object):
             request: mod_python request.
         """
 
-        unused_do_extra_handshake, transfer_data_ = self._handler(request)
+        transfer_data_ = self._get_handler_suite(request).transfer_data
+        # TODO(tyoshino): Terminate underlying TCP connection if possible.
         try:
-            try:
-                request.client_terminated = False
-                request.server_terminated = False
-                transfer_data_(request)
-            except msgutil.ConnectionTerminatedException, e:
-                util.prepend_message_to_exception(
-                    'client initiated closing handshake for %s: ' % (
-                    request.ws_resource),
-                    e)
-                raise
-            except Exception, e:
-                print 'exception: %s' % type(e)
-                util.prepend_message_to_exception(
-                    '%s raised exception for %s: ' % (
+            transfer_data_(request)
+            if not request.server_terminated:
+                request.ws_stream.close_connection()
+        # Catch non-critical exceptions the handler didn't handle.
+        except msgutil.BadOperationException, e:
+            self._logger.debug(str(e))
+            request.ws_stream.close_connection(common.STATUS_GOING_AWAY)
+        except msgutil.InvalidFrameException, e:
+            # InvalidFrameException must be caught before
+            # ConnectionTerminatedException that catches InvalidFrameException.
+            self._logger.debug(str(e))
+            request.ws_stream.close_connection(common.STATUS_PROTOCOL_ERROR)
+        except msgutil.UnsupportedFrameException, e:
+            self._logger.debug(str(e))
+            request.ws_stream.close_connection(common.STATUS_UNSUPPORTED)
+        except msgutil.ConnectionTerminatedException, e:
+            self._logger.debug(str(e))
+        except Exception, e:
+            util.prepend_message_to_exception(
+                '%s raised exception for %s: ' % (
                     _TRANSFER_DATA_HANDLER_NAME, request.ws_resource),
-                    e)
-                raise
-        finally:
-            msgutil.close_connection(request)
+                e)
+            raise
 
+    def _get_handler_suite(self, request):
+        """Retrieves two handlers (one for extra handshake processing, and one
+        for data transfer) for the given request as a HandlerSuite object.
+        """
 
-    def _handler(self, request):
         try:
             ws_resource_path = request.ws_resource.split('?', 1)[0]
-            return self._handlers[ws_resource_path]
+            return self._handler_suite_map[ws_resource_path]
         except KeyError:
             raise DispatchError('No handler for: %r' % request.ws_resource)
 
-    def _source_files_in_dir(self, root_dir, scan_dir):
+    def _source_handler_files_in_dir(self, root_dir, scan_dir):
         """Source all the handler source files in the scan_dir directory.
 
         The resource path is determined relative to root_dir.
         """
 
-        to_resource = _path_to_resource_converter(root_dir)
-        for path in _source_file_paths(scan_dir):
+        convert = _create_path_to_resource_converter(root_dir)
+        for path in _enumerate_handler_file_paths(scan_dir):
             try:
-                handlers = _source(open(path).read())
+                handler_suite = _source_handler_file(open(path).read())
             except DispatchError, e:
                 self._source_warnings.append('%s: %s' % (path, e))
                 continue
-            self._handlers[to_resource(path)] = handlers
+            self._handler_suite_map[convert(path)] = handler_suite
 
 
 # vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/__init__.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/__init__.py
index 237dbde6d886..2e6758ee5f76 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/__init__.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2010, Google Inc.
+# Copyright 2011, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,30 +28,23 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-"""Web Socket handshaking.
-
-Note: request.connection.write/read are used in this module, even though
-mod_python document says that they should be used only in connection handlers.
-Unfortunately, we have no other options. For example, request.write/read are
-not suitable because they don't allow direct raw bytes writing/reading.
+"""WebSocket opening handshake processor. This class try to apply available
+opening handshake processors for each protocol version until a connection is
+successfully established.
 """
 
 
 import logging
-import re
 
+from mod_pywebsocket import util
 from mod_pywebsocket.handshake import draft75
-from mod_pywebsocket.handshake import handshake
-from mod_pywebsocket.handshake._base import DEFAULT_WEB_SOCKET_PORT
-from mod_pywebsocket.handshake._base import DEFAULT_WEB_SOCKET_SECURE_PORT
-from mod_pywebsocket.handshake._base import WEB_SOCKET_SCHEME
-from mod_pywebsocket.handshake._base import WEB_SOCKET_SECURE_SCHEME
+from mod_pywebsocket.handshake import hybi00
+from mod_pywebsocket.handshake import hybi06
 from mod_pywebsocket.handshake._base import HandshakeError
-from mod_pywebsocket.handshake._base import validate_protocol
 
 
 class Handshaker(object):
-    """This class performs Web Socket handshake."""
+    """This class performs WebSocket handshake."""
 
     def __init__(self, request, dispatcher, allowDraft75=False, strict=False):
         """Construct an instance.
@@ -68,28 +61,38 @@ class Handshaker(object):
         handshake.
         """
 
-        self._logger = logging.getLogger("mod_pywebsocket.handshake")
+        self._logger = util.get_class_logger(self)
+
         self._request = request
         self._dispatcher = dispatcher
         self._strict = strict
-        self._handshaker = handshake.Handshaker(request, dispatcher)
-        self._fallbackHandshaker = None
+        self._hybi07Handshaker = hybi06.Handshaker(request, dispatcher)
+        self._hybi00Handshaker = hybi00.Handshaker(request, dispatcher)
+        self._hixie75Handshaker = None
         if allowDraft75:
-            self._fallbackHandshaker = draft75.Handshaker(
+            self._hixie75Handshaker = draft75.Handshaker(
                 request, dispatcher, strict)
 
     def do_handshake(self):
-        """Perform Web Socket Handshake."""
+        """Perform WebSocket Handshake."""
 
-        try:
-            self._handshaker.do_handshake()
-        except HandshakeError, e:
-            self._logger.error('Handshake error: %s' % e)
-            if self._fallbackHandshaker:
-                self._logger.warning('fallback to old protocol')
-                self._fallbackHandshaker.do_handshake()
-                return
-            raise e
+        self._logger.debug(
+            'Opening handshake headers: %s' % self._request.headers_in)
 
+        handshakers = [
+            ('HyBi 07', self._hybi07Handshaker),
+            ('HyBi 00', self._hybi00Handshaker),
+            ('Hixie 75', self._hixie75Handshaker)]
+        last_error = HandshakeError('No handshaker available')
+        for name, handshaker in handshakers:
+            if handshaker:
+                self._logger.info('Trying %s protocol' % name)
+                try:
+                    handshaker.do_handshake()
+                    return
+                except HandshakeError, e:
+                    self._logger.info('%s handshake failed: %s' % (name, e))
+                    last_error = e
+        raise last_error
 
 # vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/_base.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/_base.py
index 6232471de3ce..94104008604f 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/_base.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/_base.py
@@ -1,4 +1,4 @@
-# Copyright 2010, Google Inc.
+# Copyright 2011, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,48 +28,51 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-"""Web Socket handshaking.
-
-Note: request.connection.write/read are used in this module, even though
-mod_python document says that they should be used only in connection handlers.
-Unfortunately, we have no other options. For example, request.write/read are
-not suitable because they don't allow direct raw bytes writing/reading.
+"""Common functions and exceptions used by WebSocket opening handshake
+processors.
 """
 
 
-DEFAULT_WEB_SOCKET_PORT = 80
-DEFAULT_WEB_SOCKET_SECURE_PORT = 443
-WEB_SOCKET_SCHEME = 'ws'
-WEB_SOCKET_SECURE_SCHEME = 'wss'
+from mod_pywebsocket import common
 
 
 class HandshakeError(Exception):
-    """Exception in Web Socket Handshake."""
-
+    """This exception will be raised when an error occurred while processing
+    WebSocket initial handshake.
+    """
     pass
 
 
-def default_port(is_secure):
+def get_default_port(is_secure):
     if is_secure:
-        return DEFAULT_WEB_SOCKET_SECURE_PORT
+        return common.DEFAULT_WEB_SOCKET_SECURE_PORT
     else:
-        return DEFAULT_WEB_SOCKET_PORT
+        return common.DEFAULT_WEB_SOCKET_PORT
 
 
-def validate_protocol(protocol):
-    """Validate WebSocket-Protocol string."""
+# TODO(tyoshino): Have stricter validator for HyBi 07.
+def validate_subprotocol(subprotocol):
+    """Validate a value in subprotocol fields such as WebSocket-Protocol,
+    Sec-WebSocket-Protocol.
 
-    if not protocol:
-        raise HandshakeError('Invalid WebSocket-Protocol: empty')
-    for c in protocol:
+    See
+    - HyBi 06: Section 5.2.2.
+    - HyBi 00: Section 4.1. Opening handshake
+    - Hixie 75: Section 4.1. Handshake
+    """
+
+    if not subprotocol:
+        raise HandshakeError('Invalid subprotocol name: empty')
+    for c in subprotocol:
         if not 0x20 <= ord(c) <= 0x7e:
-            raise HandshakeError('Illegal character in protocol: %r' % c)
+            raise HandshakeError(
+                'Illegal character in subprotocol name: %r' % c)
 
 
 def parse_host_header(request):
     fields = request.headers_in['Host'].split(':', 1)
     if len(fields) == 1:
-        return fields[0], default_port(request.is_https())
+        return fields[0], get_default_port(request.is_https())
     try:
         return fields[0], int(fields[1])
     except ValueError, e:
@@ -80,9 +83,9 @@ def build_location(request):
     """Build WebSocket location for request."""
     location_parts = []
     if request.is_https():
-        location_parts.append(WEB_SOCKET_SECURE_SCHEME)
+        location_parts.append(common.WEB_SOCKET_SECURE_SCHEME)
     else:
-        location_parts.append(WEB_SOCKET_SCHEME)
+        location_parts.append(common.WEB_SOCKET_SCHEME)
     location_parts.append('://')
     host, port = parse_host_header(request)
     connection_port = request.connection.local_addr[1]
@@ -90,12 +93,34 @@ def build_location(request):
         raise HandshakeError('Header/connection port mismatch: %d/%d' %
                              (port, connection_port))
     location_parts.append(host)
-    if (port != default_port(request.is_https())):
+    if (port != get_default_port(request.is_https())):
         location_parts.append(':')
         location_parts.append(str(port))
     location_parts.append(request.uri)
     return ''.join(location_parts)
 
 
+def get_mandatory_header(request, key, expected_value=None):
+    value = request.headers_in.get(key)
+    if value is None:
+        raise HandshakeError('Header %s is not defined' % key)
+    if expected_value is not None and expected_value != value:
+        raise HandshakeError(
+            'Illegal value for header %s: %s (expected: %s)' %
+            (key, value, expected_value))
+    return value
+
+
+def check_header_lines(request, mandatory_headers):
+    # 5.1 1. The three character UTF-8 string "GET".
+    # 5.1 2. A UTF-8-encoded U+0020 SPACE character (0x20 byte).
+    if request.method != 'GET':
+        raise HandshakeError('Method is not GET')
+    # The expected field names, and the meaning of their corresponding
+    # values, are as follows.
+    #  |Upgrade| and |Connection|
+    for key, expected_value in mandatory_headers:
+        get_mandatory_header(request, key, expected_value)
+
 
 # vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/draft75.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/draft75.py
index b132dbb1c39a..e56def7f4683 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/draft75.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/draft75.py
@@ -1,4 +1,4 @@
-# Copyright 2010, Google Inc.
+# Copyright 2011, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,20 +28,24 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-"""Web Socket handshaking defined in draft-hixie-thewebsocketprotocol-75.
-
-Note: request.connection.write/read are used in this module, even though
-mod_python document says that they should be used only in connection handlers.
-Unfortunately, we have no other options. For example, request.write/read are
-not suitable because they don't allow direct raw bytes writing/reading.
-"""
+"""WebSocket handshaking defined in draft-hixie-thewebsocketprotocol-75."""
 
 
+# Note: request.connection.write is used in this module, even though mod_python
+# document says that it should be used only in connection handlers.
+# Unfortunately, we have no other options. For example, request.write is not
+# suitable because it doesn't allow direct raw bytes writing.
+
+
+import logging
 import re
 
+from mod_pywebsocket import common
+from mod_pywebsocket.stream import StreamHixie75
+from mod_pywebsocket import util
 from mod_pywebsocket.handshake._base import HandshakeError
 from mod_pywebsocket.handshake._base import build_location
-from mod_pywebsocket.handshake._base import validate_protocol
+from mod_pywebsocket.handshake._base import validate_subprotocol
 
 
 _MANDATORY_HEADERS = [
@@ -70,7 +74,7 @@ _SIXTH_AND_LATER = re.compile(
 
 
 class Handshaker(object):
-    """This class performs Web Socket handshake."""
+    """This class performs WebSocket handshake."""
 
     def __init__(self, request, dispatcher, strict=False):
         """Construct an instance.
@@ -86,18 +90,28 @@ class Handshaker(object):
         handshake.
         """
 
+        self._logger = util.get_class_logger(self)
+
         self._request = request
         self._dispatcher = dispatcher
         self._strict = strict
 
     def do_handshake(self):
-        """Perform Web Socket Handshake."""
+        """Perform WebSocket Handshake.
+
+        On _request, we set
+            ws_resource, ws_origin, ws_location, ws_protocol
+            ws_challenge_md5: WebSocket handshake information.
+            ws_stream: Frame generation/parsing class.
+            ws_version: Protocol version.
+        """
 
         self._check_header_lines()
         self._set_resource()
         self._set_origin()
         self._set_location()
-        self._set_protocol()
+        self._set_subprotocol()
+        self._set_protocol_version()
         self._dispatcher.do_extra_handshake(self._request)
         self._send_handshake()
 
@@ -110,28 +124,30 @@ class Handshaker(object):
     def _set_location(self):
         self._request.ws_location = build_location(self._request)
 
-    def _set_protocol(self):
-        protocol = self._request.headers_in.get('WebSocket-Protocol')
-        if protocol is not None:
-            validate_protocol(protocol)
-        self._request.ws_protocol = protocol
+    def _set_subprotocol(self):
+        subprotocol = self._request.headers_in.get('WebSocket-Protocol')
+        if subprotocol is not None:
+            validate_subprotocol(subprotocol)
+        self._request.ws_protocol = subprotocol
+
+    def _set_protocol_version(self):
+        self._logger.debug('IETF Hixie 75 protocol')
+        self._request.ws_version = common.VERSION_HIXIE75
+        self._request.ws_stream = StreamHixie75(self._request)
+
+    def _sendall(self, data):
+        self._request.connection.write(data)
 
     def _send_handshake(self):
-        self._request.connection.write(
-                'HTTP/1.1 101 Web Socket Protocol Handshake\r\n')
-        self._request.connection.write('Upgrade: WebSocket\r\n')
-        self._request.connection.write('Connection: Upgrade\r\n')
-        self._request.connection.write('WebSocket-Origin: ')
-        self._request.connection.write(self._request.ws_origin)
-        self._request.connection.write('\r\n')
-        self._request.connection.write('WebSocket-Location: ')
-        self._request.connection.write(self._request.ws_location)
-        self._request.connection.write('\r\n')
+        self._sendall('HTTP/1.1 101 Web Socket Protocol Handshake\r\n')
+        self._sendall('Upgrade: WebSocket\r\n')
+        self._sendall('Connection: Upgrade\r\n')
+        self._sendall('WebSocket-Origin: %s\r\n' % self._request.ws_origin)
+        self._sendall('WebSocket-Location: %s\r\n' % self._request.ws_location)
         if self._request.ws_protocol:
-            self._request.connection.write('WebSocket-Protocol: ')
-            self._request.connection.write(self._request.ws_protocol)
-            self._request.connection.write('\r\n')
-        self._request.connection.write('\r\n')
+            self._sendall(
+                'WebSocket-Protocol: %s\r\n' % self._request.ws_protocol)
+        self._sendall('\r\n')
 
     def _check_header_lines(self):
         for key, expected_value in _MANDATORY_HEADERS:
@@ -140,8 +156,9 @@ class Handshaker(object):
                 raise HandshakeError('Header %s is not defined' % key)
             if expected_value:
                 if actual_value != expected_value:
-                    raise HandshakeError('Illegal value for header %s: %s' %
-                                         (key, actual_value))
+                    raise HandshakeError(
+                        'Expected %r for header %s but found %r' %
+                        (expected_value, key, actual_value))
         if self._strict:
             try:
                 lines = self._request.connection.get_memorized_lines()
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/handshake.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/handshake.py
deleted file mode 100644
index 8348bcb30582..000000000000
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/handshake.py
+++ /dev/null
@@ -1,208 +0,0 @@
-# Copyright 2009, Google 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:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * 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.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "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 THE COPYRIGHT
-# OWNER 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.
-
-
-"""Web Socket handshaking.
-
-Note: request.connection.write/read are used in this module, even though
-mod_python document says that they should be used only in connection handlers.
-Unfortunately, we have no other options. For example, request.write/read are
-not suitable because they don't allow direct raw bytes writing/reading.
-"""
-
-
-import logging
-from md5 import md5
-import re
-import struct
-
-from mod_pywebsocket.handshake._base import HandshakeError
-from mod_pywebsocket.handshake._base import build_location
-from mod_pywebsocket.handshake._base import validate_protocol
-
-
-_MANDATORY_HEADERS = [
-    # key, expected value or None
-    ['Upgrade', 'WebSocket'],
-    ['Connection', 'Upgrade'],
-]
-
-def _hexify(s):
-    return re.sub('.', lambda x: '%02x ' % ord(x.group(0)), s)
-
-class Handshaker(object):
-    """This class performs Web Socket handshake."""
-
-    def __init__(self, request, dispatcher):
-        """Construct an instance.
-
-        Args:
-            request: mod_python request.
-            dispatcher: Dispatcher (dispatch.Dispatcher).
-
-        Handshaker will add attributes such as ws_resource in performing
-        handshake.
-        """
-
-        self._logger = logging.getLogger("mod_pywebsocket.handshake")
-        self._request = request
-        self._dispatcher = dispatcher
-
-    def do_handshake(self):
-        """Perform Web Socket Handshake."""
-
-        # 5.1 Reading the client's opening handshake.
-        # dispatcher sets it in self._request.
-        self._check_header_lines()
-        self._set_resource()
-        self._set_protocol()
-        self._set_location()
-        self._set_origin()
-        self._set_challenge_response()
-        self._dispatcher.do_extra_handshake(self._request)
-        self._send_handshake()
-
-    def _check_header_lines(self):
-        # 5.1 1. The three character UTF-8 string "GET".
-        # 5.1 2. A UTF-8-encoded U+0020 SPACE character (0x20 byte).
-        if self._request.method != 'GET':
-            raise HandshakeError('Method is not GET')
-        # The expected field names, and the meaning of their corresponding
-        # values, are as follows.
-        #  |Upgrade| and |Connection|
-        for key, expected_value in _MANDATORY_HEADERS:
-            actual_value = self._request.headers_in.get(key)
-            if not actual_value:
-                raise HandshakeError('Header %s is not defined' % key)
-            if expected_value:
-                if actual_value != expected_value:
-                    raise HandshakeError('Illegal value for header %s: %s' %
-                                         (key, actual_value))
-
-    def _set_resource(self):
-        self._request.ws_resource = self._request.uri
-
-    def _set_protocol(self):
-        # |Sec-WebSocket-Protocol|
-        protocol = self._request.headers_in.get('Sec-WebSocket-Protocol')
-        if protocol is not None:
-            validate_protocol(protocol)
-        self._request.ws_protocol = protocol
-
-    def _set_location(self):
-        # |Host|
-        host = self._request.headers_in.get('Host')
-        if host is not None:
-            self._request.ws_location = build_location(self._request)
-        # TODO(ukai): check host is this host.
-
-    def _set_origin(self):
-        # |Origin|
-        origin = self._request.headers_in['Origin']
-        if origin is not None:
-            self._request.ws_origin = origin
-
-    def _set_challenge_response(self):
-        # 5.2 4-8.
-        self._request.ws_challenge = self._get_challenge()
-        # 5.2 9. let /response/ be the MD5 finterprint of /challenge/
-        self._request.ws_challenge_md5 = md5(
-            self._request.ws_challenge).digest()
-        self._logger.debug("challenge: %s" % _hexify(
-            self._request.ws_challenge))
-        self._logger.debug("response:  %s" % _hexify(
-            self._request.ws_challenge_md5))
-
-    def _get_key_value(self, key_field):
-        key_value = self._request.headers_in.get(key_field)
-        if key_value is None:
-            self._logger.debug("no %s" % key_value)
-            return None
-        try:
-            # 5.2 4. let /key-number_n/ be the digits (characters in the range
-            # U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_n/,
-            # interpreted as a base ten integer, ignoring all other characters
-            # in /key_n/
-            key_number = int(re.sub("\\D", "", key_value))
-            # 5.2 5. let /spaces_n/ be the number of U+0020 SPACE characters
-            # in /key_n/.
-            spaces = re.subn(" ", "", key_value)[1]
-            # 5.2 6. if /key-number_n/ is not an integral multiple of /spaces_n/
-            # then abort the WebSocket connection.
-            if key_number % spaces != 0:
-                raise handshakeError('key_number %d is not an integral '
-                                     'multiple of spaces %d' % (key_number,
-                                                                spaces))
-            # 5.2 7. let /part_n/ be /key_number_n/ divided by /spaces_n/.
-            part = key_number / spaces
-            self._logger.debug("%s: %s => %d / %d => %d" % (
-                key_field, key_value, key_number, spaces, part))
-            return part
-        except:
-            return None
-
-    def _get_challenge(self):
-        # 5.2 4-7.
-        key1 = self._get_key_value('Sec-Websocket-Key1')
-        if not key1:
-            raise HandshakeError('Sec-WebSocket-Key1 not found')
-        key2 = self._get_key_value('Sec-Websocket-Key2')
-        if not key2:
-            raise HandshakeError('Sec-WebSocket-Key2 not found')
-        # 5.2 8. let /challenge/ be the concatenation of /part_1/,
-        challenge = ""
-        challenge += struct.pack("!I", key1)  # network byteorder int
-        challenge += struct.pack("!I", key2)  # network byteorder int
-        challenge += self._request.connection.read(8)
-        return challenge
-
-    def _send_handshake(self):
-        # 5.2 10. send the following line.
-        self._request.connection.write(
-                'HTTP/1.1 101 WebSocket Protocol Handshake\r\n')
-        # 5.2 11. send the following fields to the client.
-        self._request.connection.write('Upgrade: WebSocket\r\n')
-        self._request.connection.write('Connection: Upgrade\r\n')
-        self._request.connection.write('Sec-WebSocket-Location: ')
-        self._request.connection.write(self._request.ws_location)
-        self._request.connection.write('\r\n')
-        self._request.connection.write('Sec-WebSocket-Origin: ')
-        self._request.connection.write(self._request.ws_origin)
-        self._request.connection.write('\r\n')
-        if self._request.ws_protocol:
-            self._request.connection.write('Sec-WebSocket-Protocol: ')
-            self._request.connection.write(self._request.ws_protocol)
-            self._request.connection.write('\r\n')
-        # 5.2 12. send two bytes 0x0D 0x0A.
-        self._request.connection.write('\r\n')
-        # 5.2 13. send /response/
-        self._request.connection.write(self._request.ws_challenge_md5)
-
-
-# vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi00.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi00.py
new file mode 100644
index 000000000000..ca8f56cb8b04
--- /dev/null
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi00.py
@@ -0,0 +1,232 @@
+# Copyright 2011, Google 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:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 THE COPYRIGHT
+# OWNER 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.
+
+
+"""WebSocket initial handshake hander for HyBi 00 protocol."""
+
+
+# Note: request.connection.write/read are used in this module, even though
+# mod_python document says that they should be used only in connection
+# handlers. Unfortunately, we have no other options. For example,
+# request.write/read are not suitable because they don't allow direct raw bytes
+# writing/reading.
+
+
+import logging
+import re
+import struct
+
+from mod_pywebsocket import common
+from mod_pywebsocket.stream import StreamHixie75
+from mod_pywebsocket import util
+from mod_pywebsocket.handshake._base import HandshakeError
+from mod_pywebsocket.handshake._base import build_location
+from mod_pywebsocket.handshake._base import check_header_lines
+from mod_pywebsocket.handshake._base import get_mandatory_header
+from mod_pywebsocket.handshake._base import validate_subprotocol
+
+
+_MANDATORY_HEADERS = [
+    # key, expected value or None
+    [common.UPGRADE_HEADER, common.WEBSOCKET_UPGRADE_TYPE_HIXIE75],
+    [common.CONNECTION_HEADER, common.UPGRADE_CONNECTION_TYPE],
+]
+
+
+class Handshaker(object):
+    """This class performs WebSocket handshake."""
+
+    def __init__(self, request, dispatcher):
+        """Construct an instance.
+
+        Args:
+            request: mod_python request.
+            dispatcher: Dispatcher (dispatch.Dispatcher).
+
+        Handshaker will add attributes such as ws_resource in performing
+        handshake.
+        """
+
+        self._logger = util.get_class_logger(self)
+
+        self._request = request
+        self._dispatcher = dispatcher
+
+    def do_handshake(self):
+        """Perform WebSocket Handshake.
+
+        On _request, we set
+            ws_resource, ws_protocol, ws_location, ws_origin, ws_challenge,
+            ws_challenge_md5: WebSocket handshake information.
+            ws_stream: Frame generation/parsing class.
+            ws_version: Protocol version.
+        """
+
+        # 5.1 Reading the client's opening handshake.
+        # dispatcher sets it in self._request.
+        check_header_lines(self._request, _MANDATORY_HEADERS)
+        self._set_resource()
+        self._set_subprotocol()
+        self._set_location()
+        self._set_origin()
+        self._set_challenge_response()
+        self._set_protocol_version()
+        self._dispatcher.do_extra_handshake(self._request)
+        self._send_handshake()
+
+    def _set_resource(self):
+        self._request.ws_resource = self._request.uri
+
+    def _set_subprotocol(self):
+        # |Sec-WebSocket-Protocol|
+        subprotocol = self._request.headers_in.get(
+            common.SEC_WEBSOCKET_PROTOCOL_HEADER)
+        if subprotocol is not None:
+            validate_subprotocol(subprotocol)
+        self._request.ws_protocol = subprotocol
+
+    def _set_location(self):
+        # |Host|
+        host = self._request.headers_in.get(common.HOST_HEADER)
+        if host is not None:
+            self._request.ws_location = build_location(self._request)
+        # TODO(ukai): check host is this host.
+
+    def _set_origin(self):
+        # |Origin|
+        origin = self._request.headers_in['Origin']
+        if origin is not None:
+            self._request.ws_origin = origin
+
+    def _set_protocol_version(self):
+        # |Sec-WebSocket-Draft|
+        draft = self._request.headers_in.get('Sec-WebSocket-Draft')
+        if draft is not None:
+            try:
+                draft_int = int(draft)
+
+                # Draft value 2 is used by HyBi 02 and 03 which we no longer
+                # support. draft >= 3 and <= 1 are never defined in the spec.
+                # 0 might be used to mean HyBi 00 by somebody. 1 might be used
+                # to mean HyBi 01 by somebody but we no longer support it.
+
+                if draft_int == 1 or draft_int == 2:
+                    raise HandshakeError('HyBi 01-03 are not supported')
+                elif draft_int != 0:
+                    raise ValueError
+            except ValueError, e:
+                raise HandshakeError(
+                    'Illegal value for Sec-WebSocket-Draft: %s' % draft)
+
+        self._logger.debug('IETF HyBi 00 protocol')
+        self._request.ws_version = common.VERSION_HYBI00
+        self._request.ws_stream = StreamHixie75(self._request, True)
+
+    def _set_challenge_response(self):
+        # 5.2 4-8.
+        self._request.ws_challenge = self._get_challenge()
+        # 5.2 9. let /response/ be the MD5 finterprint of /challenge/
+        self._request.ws_challenge_md5 = util.md5_hash(
+            self._request.ws_challenge).digest()
+        self._logger.debug(
+            'Challenge: %r (%s)' %
+            (self._request.ws_challenge,
+             util.hexify(self._request.ws_challenge)))
+        self._logger.debug(
+            'Challenge response: %r (%s)' %
+            (self._request.ws_challenge_md5,
+             util.hexify(self._request.ws_challenge_md5)))
+
+    def _get_key_value(self, key_field):
+        key_value = get_mandatory_header(self._request, key_field)
+
+        # 5.2 4. let /key-number_n/ be the digits (characters in the range
+        # U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_n/,
+        # interpreted as a base ten integer, ignoring all other characters
+        # in /key_n/.
+        try:
+            key_number = int(re.sub("\\D", "", key_value))
+        except:
+            raise HandshakeError('%s field contains no digit' % key_field)
+        # 5.2 5. let /spaces_n/ be the number of U+0020 SPACE characters
+        # in /key_n/.
+        spaces = re.subn(" ", "", key_value)[1]
+        if spaces == 0:
+            raise HandshakeError('%s field contains no space' % key_field)
+        # 5.2 6. if /key-number_n/ is not an integral multiple of /spaces_n/
+        # then abort the WebSocket connection.
+        if key_number % spaces != 0:
+            raise HandshakeError('Key-number %d is not an integral '
+                                 'multiple of spaces %d' % (key_number,
+                                                            spaces))
+        # 5.2 7. let /part_n/ be /key-number_n/ divided by /spaces_n/.
+        part = key_number / spaces
+        self._logger.debug('%s: %s => %d / %d => %d' % (
+            key_field, key_value, key_number, spaces, part))
+        return part
+
+    def _get_challenge(self):
+        # 5.2 4-7.
+        key1 = self._get_key_value('Sec-WebSocket-Key1')
+        key2 = self._get_key_value('Sec-WebSocket-Key2')
+        # 5.2 8. let /challenge/ be the concatenation of /part_1/,
+        challenge = ''
+        challenge += struct.pack('!I', key1)  # network byteorder int
+        challenge += struct.pack('!I', key2)  # network byteorder int
+        challenge += self._request.connection.read(8)
+        return challenge
+
+    def _sendall(self, data):
+        self._request.connection.write(data)
+
+    def _send_header(self, name, value):
+        self._sendall('%s: %s\r\n' % (name, value))
+
+    def _send_handshake(self):
+        # 5.2 10. send the following line.
+        self._sendall('HTTP/1.1 101 WebSocket Protocol Handshake\r\n')
+        # 5.2 11. send the following fields to the client.
+        self._send_header(
+            common.UPGRADE_HEADER, common.WEBSOCKET_UPGRADE_TYPE_HIXIE75)
+        self._send_header(
+            common.CONNECTION_HEADER, common.UPGRADE_CONNECTION_TYPE)
+        self._send_header('Sec-WebSocket-Location', self._request.ws_location)
+        self._send_header(
+            common.SEC_WEBSOCKET_ORIGIN_HEADER, self._request.ws_origin)
+        if self._request.ws_protocol:
+            self._send_header(
+                common.SEC_WEBSOCKET_PROTOCOL_HEADER,
+                self._request.ws_protocol)
+        # 5.2 12. send two bytes 0x0D 0x0A.
+        self._sendall('\r\n')
+        # 5.2 13. send /response/
+        self._sendall(self._request.ws_challenge_md5)
+
+
+# vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi06.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi06.py
new file mode 100755
index 000000000000..449fcc79cd9a
--- /dev/null
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi06.py
@@ -0,0 +1,250 @@
+# Copyright 2011, Google 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:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 THE COPYRIGHT
+# OWNER 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.
+
+
+"""WebSocket HyBi 07 opening handshake processor."""
+
+
+# Note: request.connection.write is used in this module, even though mod_python
+# document says that it should be used only in connection handlers.
+# Unfortunately, we have no other options. For example, request.write is not
+# suitable because it doesn't allow direct raw bytes writing.
+
+
+import base64
+import logging
+import os
+import re
+
+from mod_pywebsocket import common
+from mod_pywebsocket.stream import Stream
+from mod_pywebsocket.stream import StreamOptions
+from mod_pywebsocket import util
+from mod_pywebsocket.handshake._base import HandshakeError
+from mod_pywebsocket.handshake._base import check_header_lines
+from mod_pywebsocket.handshake._base import get_mandatory_header
+
+
+_MANDATORY_HEADERS = [
+    # key, expected value or None
+    [common.UPGRADE_HEADER, common.WEBSOCKET_UPGRADE_TYPE],
+    [common.CONNECTION_HEADER, common.UPGRADE_CONNECTION_TYPE],
+]
+
+_BASE64_REGEX = re.compile('^[+/0-9A-Za-z]*=*$')
+
+
+def compute_accept(key):
+    """Computes value for the Sec-WebSocket-Accept header from value of the
+    Sec-WebSocket-Key header.
+    """
+
+    accept_binary = util.sha1_hash(
+        key + common.WEBSOCKET_ACCEPT_UUID).digest()
+    accept = base64.b64encode(accept_binary)
+
+    return (accept, accept_binary)
+
+
+class Handshaker(object):
+    """This class performs WebSocket handshake."""
+
+    def __init__(self, request, dispatcher):
+        """Construct an instance.
+
+        Args:
+            request: mod_python request.
+            dispatcher: Dispatcher (dispatch.Dispatcher).
+
+        Handshaker will add attributes such as ws_resource during handshake.
+        """
+
+        self._logger = util.get_class_logger(self)
+
+        self._request = request
+        self._dispatcher = dispatcher
+
+    def do_handshake(self):
+        check_header_lines(self._request, _MANDATORY_HEADERS)
+        self._request.ws_resource = self._request.uri
+
+        unused_host = get_mandatory_header(self._request, common.HOST_HEADER)
+
+        self._get_origin()
+        self._check_version()
+        self._set_protocol()
+        self._set_extensions()
+
+        key = self._get_key()
+        (accept, accept_binary) = compute_accept(key)
+        self._logger.debug('Sec-WebSocket-Accept: %r (%s)' %
+                           (accept, util.hexify(accept_binary)))
+
+        self._logger.debug('IETF HyBi 07 protocol')
+        self._request.ws_version = common.VERSION_HYBI07
+        stream_options = StreamOptions()
+        stream_options.deflate = self._request.ws_deflate
+        self._request.ws_stream = Stream(self._request, stream_options)
+
+        self._request.ws_close_code = None
+        self._request.ws_close_reason = None
+
+        self._dispatcher.do_extra_handshake(self._request)
+
+        if self._request.ws_requested_protocols is not None:
+            if self._request.ws_protocol is None:
+                raise HandshakeError(
+                    'do_extra_handshake must choose one subprotocol from '
+                    'ws_requested_protocols and set it to ws_protocol')
+
+            # TODO(tyoshino): Validate selected subprotocol value.
+
+            self._logger.debug(
+                'Subprotocol accepted: %r',
+                self._request.ws_protocol)
+        else:
+            if self._request.ws_protocol is not None:
+                raise HandshakeError(
+                    'ws_protocol must be None when the client didn\'t request '
+                    'any subprotocol')
+
+        self._send_handshake(accept)
+
+    def _get_origin(self):
+        origin = self._request.headers_in.get(
+            common.SEC_WEBSOCKET_ORIGIN_HEADER)
+        self._request.ws_origin = origin
+
+    def _check_version(self):
+        unused_value = get_mandatory_header(
+            self._request, common.SEC_WEBSOCKET_VERSION_HEADER, '7')
+
+    def _set_protocol(self):
+        self._request.ws_protocol = None
+
+        protocol_header = self._request.headers_in.get(
+            common.SEC_WEBSOCKET_PROTOCOL_HEADER)
+
+        if not protocol_header:
+            self._request.ws_requested_protocols = None
+            return
+
+        # TODO(tyoshino): Validate the header value.
+
+        requested_protocols = protocol_header.split(',')
+        self._request.ws_requested_protocols = [
+            s.strip() for s in requested_protocols]
+
+        self._logger.debug('Subprotocols requested: %r', requested_protocols)
+
+    def _set_extensions(self):
+        self._request.ws_deflate = False
+
+        extensions_header = self._request.headers_in.get(
+            common.SEC_WEBSOCKET_EXTENSIONS_HEADER)
+        if not extensions_header:
+            self._request.ws_extensions = None
+            return
+
+        self._request.ws_extensions = []
+
+        requested_extensions = extensions_header.split(',')
+        # TODO(tyoshino): Follow the ABNF in the spec.
+        requested_extensions = [s.strip() for s in requested_extensions]
+
+        for extension in requested_extensions:
+            # We now support only deflate-stream extension. Any other
+            # extension requests are just ignored for now.
+            if extension == 'deflate-stream':
+                self._request.ws_extensions.append(extension)
+                self._request.ws_deflate = True
+
+        self._logger.debug('Extensions requested: %r', requested_extensions)
+        self._logger.debug(
+            'Extensions accepted: %r', self._request.ws_extensions)
+
+    def _validate_key(self, key):
+        # Validate
+        key_is_valid = False
+        try:
+            # Validate key by quick regex match before parsing by base64
+            # module. Because base64 module skips invalid characters, we have
+            # to do this in advance to make this server strictly reject illegal
+            # keys.
+            if _BASE64_REGEX.match(key):
+                decoded_key = base64.b64decode(key)
+                if len(decoded_key) == 16:
+                    key_is_valid = True
+        except TypeError, e:
+            pass
+
+        if not key_is_valid:
+            raise HandshakeError(
+                'Illegal value for header %s: %r' %
+                (common.SEC_WEBSOCKET_KEY_HEADER, key))
+
+        return decoded_key
+
+    def _get_key(self):
+        key = get_mandatory_header(
+            self._request, common.SEC_WEBSOCKET_KEY_HEADER)
+
+        decoded_key = self._validate_key(key)
+
+        self._logger.debug('Sec-WebSocket-Key: %r (%s)' %
+                           (key, util.hexify(decoded_key)))
+
+        return key
+
+    def _sendall(self, data):
+        self._request.connection.write(data)
+
+    def _send_header(self, name, value):
+        self._sendall('%s: %s\r\n' % (name, value))
+
+    def _send_handshake(self, accept):
+        self._sendall('HTTP/1.1 101 Switching Protocols\r\n')
+        self._send_header(common.UPGRADE_HEADER, common.WEBSOCKET_UPGRADE_TYPE)
+        self._send_header(
+            common.CONNECTION_HEADER, common.UPGRADE_CONNECTION_TYPE)
+        self._send_header(common.SEC_WEBSOCKET_ACCEPT_HEADER, accept)
+        # TODO(tyoshino): Encode value of protocol and extensions if any
+        # special character that we have to encode by some manner.
+        if self._request.ws_protocol is not None:
+            self._send_header(
+                common.SEC_WEBSOCKET_PROTOCOL_HEADER,
+                self._request.ws_protocol)
+        if self._request.ws_extensions is not None:
+            self._send_header(
+                common.SEC_WEBSOCKET_EXTENSIONS_HEADER,
+                ', '.join(self._request.ws_extensions))
+        self._sendall('\r\n')
+
+
+# vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/headerparserhandler.py b/testing/mochitest/pywebsocket/mod_pywebsocket/headerparserhandler.py
index a62a448b4198..1b12869a6fc3 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/headerparserhandler.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/headerparserhandler.py
@@ -1,4 +1,4 @@
-# Copyright 2009, Google Inc.
+# Copyright 2011, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,9 +31,10 @@
 """PythonHeaderParserHandler for mod_pywebsocket.
 
 Apache HTTP Server and mod_python must be configured such that this
-function is called to handle Web Socket request.
+function is called to handle WebSocket request.
 """
 
+
 import logging
 
 from mod_python import apache
@@ -57,7 +58,8 @@ _PYOPT_ALLOW_DRAFT75 = 'mod_pywebsocket.allow_draft75'
 
 
 class ApacheLogHandler(logging.Handler):
-    """Wrapper logging.Handler to emit log message to apache's error.log"""
+    """Wrapper logging.Handler to emit log message to apache's error.log."""
+
     _LEVELS = {
         logging.DEBUG: apache.APLOG_DEBUG,
         logging.INFO: apache.APLOG_INFO,
@@ -65,11 +67,12 @@ class ApacheLogHandler(logging.Handler):
         logging.ERROR: apache.APLOG_ERR,
         logging.CRITICAL: apache.APLOG_CRIT,
         }
+
     def __init__(self, request=None):
         logging.Handler.__init__(self)
         self.log_error = apache.log_error
         if request is not None:
-             self.log_error = request.log_error
+            self.log_error = request.log_error
 
     def emit(self, record):
         apache_level = apache.APLOG_DEBUG
@@ -78,7 +81,7 @@ class ApacheLogHandler(logging.Handler):
         self.log_error(record.getMessage(), apache_level)
 
 
-logging.getLogger("mod_pywebsocket").addHandler(ApacheLogHandler())
+logging.getLogger('mod_pywebsocket').addHandler(ApacheLogHandler())
 
 
 def _create_dispatcher():
@@ -111,12 +114,13 @@ def headerparserhandler(request):
 
     try:
         allowDraft75 = apache.main_server.get_options().get(
-		_PYOPT_ALLOW_DRAFT75, None)
+            _PYOPT_ALLOW_DRAFT75, None)
         handshaker = handshake.Handshaker(request, _dispatcher,
                                           allowDraft75=allowDraft75)
         handshaker.do_handshake()
-        request.log_error('mod_pywebsocket: resource: %r' % request.ws_resource,
-                          apache.APLOG_DEBUG)
+        request.log_error(
+            'mod_pywebsocket: resource: %r' % request.ws_resource,
+            apache.APLOG_DEBUG)
         try:
             _dispatcher.transfer_data(request)
         except Exception, e:
@@ -132,6 +136,8 @@ def headerparserhandler(request):
     except dispatch.DispatchError, e:
         request.log_error('mod_pywebsocket: %s' % e, apache.APLOG_WARNING)
         return apache.DECLINED
+    # Set assbackwards to suppress response header generation by Apache.
+    request.assbackwards = 1
     return apache.DONE  # Return DONE such that no other handlers are invoked.
 
 
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/memorizingfile.py b/testing/mochitest/pywebsocket/mod_pywebsocket/memorizingfile.py
index 2f8a54e456d6..9c188a5c9d82 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/memorizingfile.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/memorizingfile.py
@@ -53,7 +53,7 @@ class MemorizingFile(object):
             file_: the file object to wrap.
             max_memorized_lines: the maximum number of lines to memorize.
                 Only the first max_memorized_lines are memorized.
-                Default: sys.maxint. 
+                Default: sys.maxint.
         """
         self._file = file_
         self._memorized_lines = []
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py b/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py
index 7aae2479e4ce..4ea1e94bc970 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py
@@ -1,4 +1,4 @@
-# Copyright 2009, Google Inc.
+# Copyright 2011, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -40,153 +40,52 @@ not suitable because they don't allow direct raw bytes writing/reading.
 import Queue
 import threading
 
-from mod_pywebsocket import util
-from time import time,sleep
+
+# Export Exception symbols from msgutil for backward compatibility
+from mod_pywebsocket._stream_base import ConnectionTerminatedException
+from mod_pywebsocket._stream_base import InvalidFrameException
+from mod_pywebsocket._stream_base import BadOperationException
+from mod_pywebsocket._stream_base import UnsupportedFrameException
 
 
-class MsgUtilException(Exception):
-    pass
-
-
-class ConnectionTerminatedException(MsgUtilException):
-    pass
-
-
-def _read(request, length):
-    bytes = request.connection.read(length)
-    if not bytes:
-        raise MsgUtilException(
-                'Failed to receive message from %r' %
-                        (request.connection.remote_addr,))
-    return bytes
-
-
-def _write(request, bytes):
-    try:
-        request.connection.write(bytes)
-    except Exception, e:
-        util.prepend_message_to_exception(
-                'Failed to send message to %r: ' %
-                        (request.connection.remote_addr,),
-                e)
-        raise
-
-
-def close_connection(request, abort=False):
+# An API for handler to send/receive WebSocket messages.
+def close_connection(request):
     """Close connection.
 
     Args:
         request: mod_python request.
     """
-    if request.server_terminated:
-        return
-    # 5.3 the server may decide to terminate the WebSocket connection by
-    # running through the following steps:
-    # 1. send a 0xFF byte and a 0x00 byte to the client to indicate the start
-    # of the closing handshake.
-    got_exception = False
-    if not abort:
-        _write(request, '\xff\x00')
-        # timeout of 20 seconds to get the client's close frame ack
-        initial_time = time()
-        end_time = initial_time + 20
-        while time() < end_time:
-            try:
-                receive_message(request)
-            except ConnectionTerminatedException, e:
-                got_exception = True
-                sleep(1)
-    request.server_terminated = True
-    if got_exception:
-        util.prepend_message_to_exception(
-            'client initiated closing handshake for %s: ' % (
-            request.ws_resource),
-            e)
-        raise ConnectionTerminatedException
-    # TODO: 3. close the WebSocket connection.
-    # note: mod_python Connection (mp_conn) doesn't have close method.
+    request.ws_stream.close_connection()
 
 
-def send_message(request, message):
+def send_message(request, message, end=True):
     """Send message.
 
     Args:
         request: mod_python request.
         message: unicode string to send.
+        end: False to send message as a fragment. All messages until the first
+             call with end=True (inclusive) will be delivered to the client
+             in separate frames but as one WebSocket message.
     Raises:
-        ConnectionTerminatedException: when server already terminated.
+        BadOperationException: when server already terminated.
     """
-    if request.server_terminated:
-        raise ConnectionTerminatedException
-    _write(request, '\x00' + message.encode('utf-8') + '\xff')
+    request.ws_stream.send_message(message, end)
 
 
 def receive_message(request):
-    """Receive a Web Socket frame and return its payload as unicode string.
+    """Receive a WebSocket frame and return its payload as unicode string.
 
     Args:
         request: mod_python request.
     Raises:
-        ConnectionTerminatedException: when client already terminated.
+        BadOperationException: when client already terminated.
     """
-
-    if request.client_terminated:
-        raise ConnectionTerminatedException
-    while True:
-        # Read 1 byte.
-        # mp_conn.read will block if no bytes are available.
-        # Timeout is controlled by TimeOut directive of Apache.
-        frame_type_str = _read(request, 1)
-        frame_type = ord(frame_type_str[0])
-        if (frame_type & 0x80) == 0x80:
-            # The payload length is specified in the frame.
-            # Read and discard.
-            length = _payload_length(request)
-            _receive_bytes(request, length)
-            # 5.3 3. 12. if /type/ is 0xFF and /length/ is 0, then set the
-            # /client terminated/ flag and abort these steps.
-            if frame_type == 0xFF and length == 0:
-                request.client_terminated = True
-                raise ConnectionTerminatedException
-        else:
-            # The payload is delimited with \xff.
-            bytes = _read_until(request, '\xff')
-            # The Web Socket protocol section 4.4 specifies that invalid
-            # characters must be replaced with U+fffd REPLACEMENT CHARACTER.
-            message = bytes.decode('utf-8', 'replace')
-            if frame_type == 0x00:
-                return message
-            # Discard data of other types.
+    return request.ws_stream.receive_message()
 
 
-def _payload_length(request):
-    length = 0
-    while True:
-        b_str = _read(request, 1)
-        b = ord(b_str[0])
-        length = length * 128 + (b & 0x7f)
-        if (b & 0x80) == 0:
-            break
-    return length
-
-
-def _receive_bytes(request, length):
-    bytes = []
-    while length > 0:
-        new_bytes = _read(request, length)
-        bytes.append(new_bytes)
-        length -= len(new_bytes)
-    return ''.join(bytes)
-
-
-def _read_until(request, delim_char):
-    bytes = []
-    while True:
-        ch = _read(request, 1)
-        if ch == delim_char:
-            break
-        bytes.append(ch)
-    return ''.join(bytes)
+def send_ping(request, body=''):
+    request.ws_stream.send_ping(body)
 
 
 class MessageReceiver(threading.Thread):
@@ -199,6 +98,7 @@ class MessageReceiver(threading.Thread):
     because pyOpenSSL used by the server raises a fatal error if the socket
     is accessed from multiple threads.
     """
+
     def __init__(self, request, onmessage=None):
         """Construct an instance.
 
@@ -210,6 +110,7 @@ class MessageReceiver(threading.Thread):
                        and MessageReceiver.receive_nowait are useless because
                        they will never return any messages.
         """
+
         threading.Thread.__init__(self)
         self._request = request
         self._queue = Queue.Queue()
@@ -269,6 +170,7 @@ class MessageSender(threading.Thread):
     because pyOpenSSL used by the server raises a fatal error if the socket
     is accessed from multiple threads.
     """
+
     def __init__(self, request):
         """Construct an instance.
 
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/standalone.py b/testing/mochitest/pywebsocket/mod_pywebsocket/standalone.py
new file mode 100755
index 000000000000..38dddf27be25
--- /dev/null
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/standalone.py
@@ -0,0 +1,476 @@
+#!/usr/bin/env python
+#
+# Copyright 2011, Google 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:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 THE COPYRIGHT
+# OWNER 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.
+
+
+"""Standalone WebSocket server.
+
+Use this server to run mod_pywebsocket without Apache HTTP Server.
+
+Usage:
+    python standalone.py [-p ] [-w ]
+                         [-s ]
+                         [-d ]
+                         [-m ]
+                         ... for other options, see _main below ...
+
+ is the port number to use for ws:// connection.
+
+ is the path to the root directory of HTML files.
+
+ is the path to the root directory of WebSocket handlers.
+See __init__.py for details of  and how to write WebSocket
+handlers. If this path is relative,  is used as the base.
+
+ is a path under the root directory. If specified, only the handlers
+under scan_dir are scanned. This is useful in saving scan time.
+
+Note:
+This server is derived from SocketServer.ThreadingMixIn. Hence a thread is
+used for each request.
+
+SECURITY WARNING: This uses CGIHTTPServer and CGIHTTPServer is not secure.
+It may execute arbitrary Python code or external programs. It should not be
+used outside a firewall.
+"""
+
+import BaseHTTPServer
+import CGIHTTPServer
+import SimpleHTTPServer
+import SocketServer
+import logging
+import logging.handlers
+import optparse
+import os
+import re
+import socket
+import sys
+
+_HAS_OPEN_SSL = False
+try:
+    import OpenSSL.SSL
+    _HAS_OPEN_SSL = True
+except ImportError:
+    pass
+
+from mod_pywebsocket import common
+from mod_pywebsocket import dispatch
+from mod_pywebsocket import handshake
+from mod_pywebsocket import memorizingfile
+from mod_pywebsocket import util
+
+
+_DEFAULT_LOG_MAX_BYTES = 1024 * 256
+_DEFAULT_LOG_BACKUP_COUNT = 5
+
+_DEFAULT_REQUEST_QUEUE_SIZE = 128
+
+# 1024 is practically large enough to contain WebSocket handshake lines.
+_MAX_MEMORIZED_LINES = 1024
+
+
+def _print_warnings_if_any(dispatcher):
+    warnings = dispatcher.source_warnings()
+    if warnings:
+        for warning in warnings:
+            logging.warning('mod_pywebsocket: %s' % warning)
+
+
+class _StandaloneConnection(object):
+    """Mimic mod_python mp_conn."""
+
+    def __init__(self, request_handler):
+        """Construct an instance.
+
+        Args:
+            request_handler: A WebSocketRequestHandler instance.
+        """
+        self._request_handler = request_handler
+
+    def get_local_addr(self):
+        """Getter to mimic mp_conn.local_addr."""
+        return (self._request_handler.server.server_name,
+                self._request_handler.server.server_port)
+    local_addr = property(get_local_addr)
+
+    def get_remote_addr(self):
+        """Getter to mimic mp_conn.remote_addr.
+
+        Setting the property in __init__ won't work because the request
+        handler is not initialized yet there."""
+        return self._request_handler.client_address
+    remote_addr = property(get_remote_addr)
+
+    def write(self, data):
+        """Mimic mp_conn.write()."""
+        return self._request_handler.wfile.write(data)
+
+    def read(self, length):
+        """Mimic mp_conn.read()."""
+        return self._request_handler.rfile.read(length)
+
+    def get_memorized_lines(self):
+        """Get memorized lines."""
+        return self._request_handler.rfile.get_memorized_lines()
+
+
+class _StandaloneRequest(object):
+    """Mimic mod_python request."""
+
+    def __init__(self, request_handler, use_tls):
+        """Construct an instance.
+
+        Args:
+            request_handler: A WebSocketRequestHandler instance.
+        """
+        self._request_handler = request_handler
+        self.connection = _StandaloneConnection(request_handler)
+        self._use_tls = use_tls
+
+    def get_uri(self):
+        """Getter to mimic request.uri."""
+        return self._request_handler.path
+    uri = property(get_uri)
+
+    def get_method(self):
+        """Getter to mimic request.method."""
+        return self._request_handler.command
+    method = property(get_method)
+
+    def get_headers_in(self):
+        """Getter to mimic request.headers_in."""
+        return self._request_handler.headers
+    headers_in = property(get_headers_in)
+
+    def is_https(self):
+        """Mimic request.is_https()."""
+        return self._use_tls
+
+
+class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
+    """HTTPServer specialized for WebSocket."""
+
+    SocketServer.ThreadingMixIn.daemon_threads = True
+    SocketServer.TCPServer.allow_reuse_address = True
+
+    def __init__(self, server_address, RequestHandlerClass):
+        """Override SocketServer.BaseServer.__init__."""
+
+        SocketServer.BaseServer.__init__(
+                self, server_address, RequestHandlerClass)
+        self.socket = self._create_socket()
+        self.server_bind()
+        self.server_activate()
+
+    def _create_socket(self):
+        socket_ = socket.socket(self.address_family, self.socket_type)
+        if WebSocketServer.options.use_tls:
+            ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
+            ctx.use_privatekey_file(WebSocketServer.options.private_key)
+            ctx.use_certificate_file(WebSocketServer.options.certificate)
+            socket_ = OpenSSL.SSL.Connection(ctx, socket_)
+        return socket_
+
+    def handle_error(self, rquest, client_address):
+        """Override SocketServer.handle_error."""
+
+        logging.error(
+            ('Exception in processing request from: %r' % (client_address,)) +
+            '\n' + util.get_stack_trace())
+        # Note: client_address is a tuple. To match it against %r, we need the
+        # trailing comma.
+
+
+class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
+    """CGIHTTPRequestHandler specialized for WebSocket."""
+
+    def setup(self):
+        """Override SocketServer.StreamRequestHandler.setup to wrap rfile with
+        MemorizingFile.
+        """
+
+        # Call superclass's setup to prepare rfile, wfile, etc. See setup
+        # definition on the root class SocketServer.StreamRequestHandler to
+        # understand what this does.
+        CGIHTTPServer.CGIHTTPRequestHandler.setup(self)
+
+        self.rfile = memorizingfile.MemorizingFile(
+            self.rfile,
+            max_memorized_lines=_MAX_MEMORIZED_LINES)
+
+    def __init__(self, *args, **keywords):
+        self._request = _StandaloneRequest(
+                self, WebSocketRequestHandler.options.use_tls)
+        self._dispatcher = WebSocketRequestHandler.options.dispatcher
+        self._print_warnings_if_any()
+        self._handshaker = handshake.Handshaker(
+                self._request, self._dispatcher,
+                allowDraft75=WebSocketRequestHandler.options.allow_draft75,
+                strict=WebSocketRequestHandler.options.strict)
+        CGIHTTPServer.CGIHTTPRequestHandler.__init__(
+                self, *args, **keywords)
+
+    def _print_warnings_if_any(self):
+        warnings = self._dispatcher.source_warnings()
+        if warnings:
+            for warning in warnings:
+                logging.warning('mod_pywebsocket: %s' % warning)
+
+    def parse_request(self):
+        """Override BaseHTTPServer.BaseHTTPRequestHandler.parse_request.
+
+        Return True to continue processing for HTTP(S), False otherwise.
+        """
+        result = CGIHTTPServer.CGIHTTPRequestHandler.parse_request(self)
+        if result:
+            try:
+                self._handshaker.do_handshake()
+                try:
+                    self._dispatcher.transfer_data(self._request)
+                except Exception, e:
+                    # Catch exception in transfer_data.
+                    # In this case, handshake has been successful, so just log
+                    # the exception and return False.
+                    logging.info('mod_pywebsocket: %s' % e)
+                    logging.info('mod_pywebsocket: %s' % util.get_stack_trace())
+                return False
+            except handshake.HandshakeError, e:
+                # Handshake for ws(s) failed. Assume http(s).
+                logging.info('mod_pywebsocket: %s' % e)
+                return True
+            except dispatch.DispatchError, e:
+                logging.warning('mod_pywebsocket: %s' % e)
+                return False
+            except Exception, e:
+                logging.warning('mod_pywebsocket: %s' % e)
+                logging.warning('mod_pywebsocket: %s' % util.get_stack_trace())
+                return False
+        return result
+
+    def log_request(self, code='-', size='-'):
+        """Override BaseHTTPServer.log_request."""
+
+        logging.info('"%s" %s %s',
+                     self.requestline, str(code), str(size))
+
+    def log_error(self, *args):
+        """Override BaseHTTPServer.log_error."""
+
+        # Despite the name, this method is for warnings than for errors.
+        # For example, HTTP status code is logged by this method.
+        logging.warn('%s - %s' % (self.address_string(), (args[0] % args[1:])))
+
+    def is_cgi(self):
+        """Test whether self.path corresponds to a CGI script.
+
+        Add extra check that self.path doesn't contains ..
+        Also check if the file is a executable file or not.
+        If the file is not executable, it is handled as static file or dir
+        rather than a CGI script.
+        """
+        if CGIHTTPServer.CGIHTTPRequestHandler.is_cgi(self):
+            if '..' in self.path:
+                return False
+            # strip query parameter from request path
+            resource_name = self.path.split('?', 2)[0]
+            # convert resource_name into real path name in filesystem.
+            scriptfile = self.translate_path(resource_name)
+            if not os.path.isfile(scriptfile):
+                return False
+            if not self.is_executable(scriptfile):
+                return False
+            return True
+        return False
+
+
+def _configure_logging(options):
+    logger = logging.getLogger()
+    logger.setLevel(logging.getLevelName(options.log_level.upper()))
+    if options.log_file:
+        handler = logging.handlers.RotatingFileHandler(
+                options.log_file, 'a', options.log_max, options.log_count)
+    else:
+        handler = logging.StreamHandler()
+    formatter = logging.Formatter(
+            '[%(asctime)s] [%(levelname)s] %(name)s: %(message)s')
+    handler.setFormatter(formatter)
+    logger.addHandler(handler)
+
+
+def _alias_handlers(dispatcher, websock_handlers_map_file):
+    """Set aliases specified in websock_handler_map_file in dispatcher.
+
+    Args:
+        dispatcher: dispatch.Dispatcher instance
+        websock_handler_map_file: alias map file
+    """
+    fp = open(websock_handlers_map_file)
+    try:
+        for line in fp:
+            if line[0] == '#' or line.isspace():
+                continue
+            m = re.match('(\S+)\s+(\S+)', line)
+            if not m:
+                logging.warning('Wrong format in map file:' + line)
+                continue
+            try:
+                dispatcher.add_resource_path_alias(
+                    m.group(1), m.group(2))
+            except dispatch.DispatchError, e:
+                logging.error(str(e))
+    finally:
+        fp.close()
+
+
+def _main():
+    parser = optparse.OptionParser()
+    parser.add_option('-H', '--server-host', '--server_host',
+                      dest='server_host',
+                      default='',
+                      help='server hostname to listen to')
+    parser.add_option('-p', '--port', dest='port', type='int',
+                      default=common.DEFAULT_WEB_SOCKET_PORT,
+                      help='port to listen to')
+    parser.add_option('-w', '--websock-handlers', '--websock_handlers',
+                      dest='websock_handlers',
+                      default='.',
+                      help='WebSocket handlers root directory.')
+    parser.add_option('-m', '--websock-handlers-map-file',
+                      '--websock_handlers_map_file',
+                      dest='websock_handlers_map_file',
+                      default=None,
+                      help=('WebSocket handlers map file. '
+                            'Each line consists of alias_resource_path and '
+                            'existing_resource_path, separated by spaces.'))
+    parser.add_option('-s', '--scan-dir', '--scan_dir', dest='scan_dir',
+                      default=None,
+                      help=('WebSocket handlers scan directory. '
+                            'Must be a directory under websock_handlers.'))
+    parser.add_option('-d', '--document-root', '--document_root',
+                      dest='document_root', default='.',
+                      help='Document root directory.')
+    parser.add_option('-x', '--cgi-paths', '--cgi_paths', dest='cgi_paths',
+                      default=None,
+                      help=('CGI paths relative to document_root.'
+                            'Comma-separated. (e.g -x /cgi,/htbin) '
+                            'Files under document_root/cgi_path are handled '
+                            'as CGI programs. Must be executable.'))
+    parser.add_option('-t', '--tls', dest='use_tls', action='store_true',
+                      default=False, help='use TLS (wss://)')
+    parser.add_option('-k', '--private-key', '--private_key',
+                      dest='private_key',
+                      default='', help='TLS private key file.')
+    parser.add_option('-c', '--certificate', dest='certificate',
+                      default='', help='TLS certificate file.')
+    parser.add_option('-l', '--log-file', '--log_file', dest='log_file',
+                      default='', help='Log file.')
+    parser.add_option('--log-level', '--log_level', type='choice',
+                      dest='log_level', default='warn',
+                      choices=['debug', 'info', 'warning', 'warn', 'error',
+                               'critical'],
+                      help='Log level.')
+    parser.add_option('--log-max', '--log_max', dest='log_max', type='int',
+                      default=_DEFAULT_LOG_MAX_BYTES,
+                      help='Log maximum bytes')
+    parser.add_option('--log-count', '--log_count', dest='log_count',
+                      type='int', default=_DEFAULT_LOG_BACKUP_COUNT,
+                      help='Log backup count')
+    parser.add_option('--allow-draft75', dest='allow_draft75',
+                      action='store_true', default=False,
+                      help='Allow draft 75 handshake')
+    parser.add_option('--strict', dest='strict', action='store_true',
+                      default=False, help='Strictly check handshake request')
+    parser.add_option('-q', '--queue', dest='request_queue_size', type='int',
+                      default=_DEFAULT_REQUEST_QUEUE_SIZE,
+                      help='request queue size')
+    options = parser.parse_args()[0]
+
+    os.chdir(options.document_root)
+
+    _configure_logging(options)
+
+    SocketServer.TCPServer.request_queue_size = options.request_queue_size
+    CGIHTTPServer.CGIHTTPRequestHandler.cgi_directories = []
+
+    if options.cgi_paths:
+        CGIHTTPServer.CGIHTTPRequestHandler.cgi_directories = \
+            options.cgi_paths.split(',')
+        if sys.platform in ('cygwin', 'win32'):
+            cygwin_path = None
+            # For Win32 Python, it is expected that CYGWIN_PATH
+            # is set to a directory of cygwin binaries.
+            # For example, websocket_server.py in Chromium sets CYGWIN_PATH to
+            # full path of third_party/cygwin/bin.
+            if 'CYGWIN_PATH' in os.environ:
+                cygwin_path = os.environ['CYGWIN_PATH']
+            util.wrap_popen3_for_win(cygwin_path)
+            def __check_script(scriptpath):
+                return util.get_script_interp(scriptpath, cygwin_path)
+            CGIHTTPServer.executable = __check_script
+
+    if options.use_tls:
+        if not _HAS_OPEN_SSL:
+            logging.critical('To use TLS, install pyOpenSSL.')
+            sys.exit(1)
+        if not options.private_key or not options.certificate:
+            logging.critical(
+                    'To use TLS, specify private_key and certificate.')
+            sys.exit(1)
+
+    if not options.scan_dir:
+        options.scan_dir = options.websock_handlers
+
+    try:
+        # Share a Dispatcher among request handlers to save time for
+        # instantiation.  Dispatcher can be shared because it is thread-safe.
+        options.dispatcher = dispatch.Dispatcher(options.websock_handlers,
+                                                 options.scan_dir)
+        if options.websock_handlers_map_file:
+            _alias_handlers(options.dispatcher,
+                            options.websock_handlers_map_file)
+        _print_warnings_if_any(options.dispatcher)
+
+        WebSocketRequestHandler.options = options
+        WebSocketServer.options = options
+
+        server = WebSocketServer((options.server_host, options.port),
+                                 WebSocketRequestHandler)
+        server.serve_forever()
+    except Exception, e:
+        logging.critical('mod_pywebsocket: %s' % e)
+        logging.critical('mod_pywebsocket: %s' % util.get_stack_trace())
+        sys.exit(1)
+
+
+if __name__ == '__main__':
+    _main()
+
+
+# vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/stream.py b/testing/mochitest/pywebsocket/mod_pywebsocket/stream.py
new file mode 100644
index 000000000000..93c4025ff971
--- /dev/null
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/stream.py
@@ -0,0 +1,53 @@
+# Copyright 2010, Google 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:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 THE COPYRIGHT
+# OWNER 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.
+
+
+"""This file exports public symbols.
+"""
+
+
+from mod_pywebsocket._stream_base import BadOperationException
+from mod_pywebsocket._stream_base import ConnectionTerminatedException
+from mod_pywebsocket._stream_base import InvalidFrameException
+from mod_pywebsocket._stream_base import UnsupportedFrameException
+from mod_pywebsocket._stream_hixie75 import StreamHixie75
+from mod_pywebsocket._stream_hybi06 import Stream
+from mod_pywebsocket._stream_hybi06 import StreamOptions
+
+# These methods are intended to be used by WebSocket client developers to have
+# their implementations receive broken data in tests.
+from mod_pywebsocket._stream_hybi06 import create_close_frame
+from mod_pywebsocket._stream_hybi06 import create_header
+from mod_pywebsocket._stream_hybi06 import create_length_header
+from mod_pywebsocket._stream_hybi06 import create_ping_frame
+from mod_pywebsocket._stream_hybi06 import create_pong_frame
+from mod_pywebsocket._stream_hybi06 import create_text_frame
+
+
+# vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/util.py b/testing/mochitest/pywebsocket/mod_pywebsocket/util.py
index 8ec9dca0ab45..6b3bed6db8ab 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/util.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/util.py
@@ -28,14 +28,31 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-"""Web Sockets utilities.
+"""WebSocket utilities.
 """
 
 
+import array
+
+# Import hash classes from a module available and recommended for each Python
+# version and re-export those symbol. Use sha and md5 module in Python 2.4, and
+# hashlib module in Python 2.6.
+try:
+    import hashlib
+    md5_hash = hashlib.md5
+    sha1_hash = hashlib.sha1
+except ImportError:
+    import md5
+    import sha
+    md5_hash = md5.md5
+    sha1_hash = sha.sha
+
 import StringIO
+import logging
 import os
 import re
 import traceback
+import zlib
 
 
 def get_stack_trace():
@@ -72,7 +89,7 @@ def __translate_interp(interp, cygwin_path):
     """
     if not cygwin_path:
         return interp
-    m = re.match("^[^ ]*/([^ ]+)( .*)?", interp)
+    m = re.match('^[^ ]*/([^ ]+)( .*)?', interp)
     if m:
         cmd = os.path.join(cygwin_path, m.group(1))
         return cmd + m.group(2)
@@ -96,7 +113,7 @@ def get_script_interp(script_path, cygwin_path=None):
     fp = open(script_path)
     line = fp.readline()
     fp.close()
-    m = re.match("^#!(.*)", line)
+    m = re.match('^#!(.*)', line)
     if m:
         return __translate_interp(m.group(1), cygwin_path)
     return None
@@ -113,9 +130,200 @@ def wrap_popen3_for_win(cygwin_path):
         cmdline = cmd.split(' ')
         interp = get_script_interp(cmdline[0], cygwin_path)
         if interp:
-            cmd = interp + " " + cmd
+            cmd = interp + ' ' + cmd
         return __orig_popen3(cmd, mode, bufsize)
     os.popen3 = __wrap_popen3
 
 
+def hexify(s):
+    return ' '.join(map(lambda x: '%02x' % ord(x), s))
+
+
+def get_class_logger(o):
+    return logging.getLogger(
+        '%s.%s' % (o.__class__.__module__, o.__class__.__name__))
+
+
+class NoopMasker(object):
+    def __init__(self):
+        pass
+
+    def mask(self, s):
+        return s
+
+
+class RepeatedXorMasker(object):
+    """A masking object that applies XOR on the string given to mask method
+    with the masking bytes given to the constructor repeatedly. This object
+    remembers the position in the masking bytes the last mask method call ended
+    and resumes from that point on the next mask method call.
+    """
+
+    def __init__(self, mask):
+        self._mask = map(ord, mask)
+        self._mask_size = len(self._mask)
+        self._count = 0
+
+    def mask(self, s):
+        result = array.array('B')
+        result.fromstring(s)
+        for i in xrange(len(result)):
+            result[i] ^= self._mask[self._count]
+            self._count = (self._count + 1) % self._mask_size
+        return result.tostring()
+
+
+class DeflateRequest(object):
+    """A wrapper class for request object to intercept send and recv to perform
+    deflate compression and decompression transparently.
+    """
+
+    def __init__(self, request):
+        self._request = request
+        self.connection = DeflateConnection(request.connection)
+
+    def __getattribute__(self, name):
+        if name in ('_request', 'connection'):
+            return object.__getattribute__(self, name)
+        return self._request.__getattribute__(name)
+
+    def __setattr__(self, name, value):
+        if name in ('_request', 'connection'):
+            return object.__setattr__(self, name, value)
+        return self._request.__setattr__(name, value)
+
+
+# By making wbits option negative, we can suppress CMF/FLG (2 octet) and
+# ADLER32 (4 octet) fields of zlib so that we can use zlib module just as
+# deflate library. DICTID won't be added as far as we don't set dictionary.
+# LZ77 window of 32K will be used for both compression and decompression.
+# For decompression, we can just use 32K to cover any windows size. For
+# compression, we use 32K so receivers must use 32K.
+#
+# Compression level is Z_DEFAULT_COMPRESSION. We don't have to match level
+# to decode.
+#
+# See zconf.h, deflate.cc, inflate.cc of zlib library, and zlibmodule.c of
+# Python. See also RFC1950 (ZLIB 3.3).
+class DeflateSocket(object):
+    """A wrapper class for socket object to intercept send and recv to perform
+    deflate compression and decompression transparently.
+    """
+
+    # Size of the buffer passed to recv to receive compressed data.
+    _RECV_SIZE = 4096
+
+    def __init__(self, socket):
+        self._socket = socket
+
+        self._logger = logging.getLogger(
+            'mod_pywebsocket.util.DeflateSocket')
+
+        self._compress = zlib.compressobj(
+            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
+        self._decompress = zlib.decompressobj(-zlib.MAX_WBITS)
+        self._unconsumed = ''
+
+    def recv(self, size):
+        # TODO(tyoshino): Allow call with size=0. It should block until any
+        # decompressed data is available.
+        if size <= 0:
+           raise Exception('Non-positive size passed')
+        data = ''
+        while True:
+            data += self._decompress.decompress(
+                self._unconsumed, size - len(data))
+            self._unconsumed = self._decompress.unconsumed_tail
+            if self._decompress.unused_data:
+                raise Exception('Non-decompressible data found: %r' %
+                                self._decompress.unused_data)
+            if len(data) != 0:
+                break
+
+            read_data = self._socket.recv(DeflateSocket._RECV_SIZE)
+            self._logger.debug('Received compressed: %r' % read_data)
+            if not read_data:
+                break
+            self._unconsumed += read_data
+        self._logger.debug('Received: %r' % data)
+        return data
+
+    def sendall(self, bytes):
+        self.send(bytes)
+
+    def send(self, bytes):
+        compressed_bytes = self._compress.compress(bytes)
+        compressed_bytes += self._compress.flush(zlib.Z_SYNC_FLUSH)
+        self._socket.sendall(compressed_bytes)
+        self._logger.debug('Wrote: %r' % bytes)
+        self._logger.debug('Wrote compressed: %r' % compressed_bytes)
+        return len(bytes)
+
+
+class DeflateConnection(object):
+    """A wrapper class for request object to intercept write and read to
+    perform deflate compression and decompression transparently.
+    """
+
+    # Size of the buffer passed to recv to receive compressed data.
+    _RECV_SIZE = 4096
+
+    def __init__(self, connection):
+        self._connection = connection
+
+        self._logger = logging.getLogger(
+            'mod_pywebsocket.util.DeflateConnection')
+
+        self._compress = zlib.compressobj(
+            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
+        self._decompress = zlib.decompressobj(-zlib.MAX_WBITS)
+        self._unconsumed = ''
+
+    def put_bytes(self, bytes):
+        self.write(bytes)
+
+    def read(self, size=-1):
+        # TODO(tyoshino): Allow call with size=0.
+        if size == 0 or size < -1:
+           raise Exception('size must be -1 or positive')
+
+        data = ''
+        while True:
+            if size < 0:
+                data += self._decompress.decompress(self._unconsumed)
+            else:
+                data += self._decompress.decompress(
+                    self._unconsumed, size - len(data))
+            self._unconsumed = self._decompress.unconsumed_tail
+            if self._decompress.unused_data:
+                raise Exception('Non-decompressible data found: %r' %
+                                self._decompress.unused_data)
+
+            if size >= 0 and len(data) != 0:
+                break
+
+            # TODO(tyoshino): Make this read efficient by some workaround.
+            #
+            # In 3.0.3 and prior of mod_python, read blocks until length bytes
+            # was read. We don't know the exact size to read while using
+            # deflate, so read byte-by-byte.
+            #
+            # _StandaloneRequest.read that ultimately performs
+            # socket._fileobject.read also blocks until length bytes was read
+            read_data = self._connection.read(1)
+            self._logger.debug('Read compressed: %r' % read_data)
+            if not read_data:
+                break
+            self._unconsumed += read_data
+        self._logger.debug('Read: %r' % data)
+        return data
+
+    def write(self, bytes):
+        compressed_bytes = self._compress.compress(bytes)
+        compressed_bytes += self._compress.flush(zlib.Z_SYNC_FLUSH)
+        self._logger.debug('Wrote compressed: %r' % compressed_bytes)
+        self._logger.debug('Wrote: %r' % bytes)
+        self._connection.write(compressed_bytes)
+
+
 # vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/standalone.py b/testing/mochitest/pywebsocket/standalone.py
index c3e68680197a..38dddf27be25 100644
--- a/testing/mochitest/pywebsocket/standalone.py
+++ b/testing/mochitest/pywebsocket/standalone.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2009, Google Inc.
+# Copyright 2011, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-"""Standalone Web Socket server.
+"""Standalone WebSocket server.
 
 Use this server to run mod_pywebsocket without Apache HTTP Server.
 
@@ -45,8 +45,8 @@ Usage:
 
  is the path to the root directory of HTML files.
 
- is the path to the root directory of Web Socket handlers.
-See __init__.py for details of  and how to write Web Socket
+ is the path to the root directory of WebSocket handlers.
+See __init__.py for details of  and how to write WebSocket
 handlers. If this path is relative,  is used as the base.
 
  is a path under the root directory. If specified, only the handlers
@@ -80,19 +80,13 @@ try:
 except ImportError:
     pass
 
+from mod_pywebsocket import common
 from mod_pywebsocket import dispatch
 from mod_pywebsocket import handshake
 from mod_pywebsocket import memorizingfile
 from mod_pywebsocket import util
 
 
-_LOG_LEVELS = {
-    'debug': logging.DEBUG,
-    'info': logging.INFO,
-    'warn': logging.WARN,
-    'error': logging.ERROR,
-    'critical': logging.CRITICAL};
-
 _DEFAULT_LOG_MAX_BYTES = 1024 * 256
 _DEFAULT_LOG_BACKUP_COUNT = 5
 
@@ -101,6 +95,7 @@ _DEFAULT_REQUEST_QUEUE_SIZE = 128
 # 1024 is practically large enough to contain WebSocket handshake lines.
 _MAX_MEMORIZED_LINES = 1024
 
+
 def _print_warnings_if_any(dispatcher):
     warnings = dispatcher.source_warnings()
     if warnings:
@@ -180,9 +175,10 @@ class _StandaloneRequest(object):
 
 
 class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
-    """HTTPServer specialized for Web Socket."""
+    """HTTPServer specialized for WebSocket."""
 
     SocketServer.ThreadingMixIn.daemon_threads = True
+    SocketServer.TCPServer.allow_reuse_address = True
 
     def __init__(self, server_address, RequestHandlerClass):
         """Override SocketServer.BaseServer.__init__."""
@@ -213,16 +209,21 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
 
 
 class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
-    """CGIHTTPRequestHandler specialized for Web Socket."""
+    """CGIHTTPRequestHandler specialized for WebSocket."""
 
     def setup(self):
-        """Override SocketServer.StreamRequestHandler.setup."""
+        """Override SocketServer.StreamRequestHandler.setup to wrap rfile with
+        MemorizingFile.
+        """
+
+        # Call superclass's setup to prepare rfile, wfile, etc. See setup
+        # definition on the root class SocketServer.StreamRequestHandler to
+        # understand what this does.
+        CGIHTTPServer.CGIHTTPRequestHandler.setup(self)
 
-        self.connection = self.request
         self.rfile = memorizingfile.MemorizingFile(
-                socket._fileobject(self.request, 'rb', self.rbufsize),
-                max_memorized_lines=_MAX_MEMORIZED_LINES)
-        self.wfile = socket._fileobject(self.request, 'wb', self.wbufsize)
+            self.rfile,
+            max_memorized_lines=_MAX_MEMORIZED_LINES)
 
     def __init__(self, *args, **keywords):
         self._request = _StandaloneRequest(
@@ -258,6 +259,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
                     # In this case, handshake has been successful, so just log
                     # the exception and return False.
                     logging.info('mod_pywebsocket: %s' % e)
+                    logging.info('mod_pywebsocket: %s' % util.get_stack_trace())
                 return False
             except handshake.HandshakeError, e:
                 # Handshake for ws(s) failed. Assume http(s).
@@ -268,7 +270,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
                 return False
             except Exception, e:
                 logging.warning('mod_pywebsocket: %s' % e)
-                logging.info('mod_pywebsocket: %s' % util.get_stack_trace())
+                logging.warning('mod_pywebsocket: %s' % util.get_stack_trace())
                 return False
         return result
 
@@ -310,17 +312,18 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
 
 def _configure_logging(options):
     logger = logging.getLogger()
-    logger.setLevel(_LOG_LEVELS[options.log_level])
+    logger.setLevel(logging.getLevelName(options.log_level.upper()))
     if options.log_file:
         handler = logging.handlers.RotatingFileHandler(
                 options.log_file, 'a', options.log_max, options.log_count)
     else:
         handler = logging.StreamHandler()
     formatter = logging.Formatter(
-            "[%(asctime)s] [%(levelname)s] %(name)s: %(message)s")
+            '[%(asctime)s] [%(levelname)s] %(name)s: %(message)s')
     handler.setFormatter(formatter)
     logger.addHandler(handler)
 
+
 def _alias_handlers(dispatcher, websock_handlers_map_file):
     """Set aliases specified in websock_handler_map_file in dispatcher.
 
@@ -346,7 +349,6 @@ def _alias_handlers(dispatcher, websock_handlers_map_file):
         fp.close()
 
 
-
 def _main():
     parser = optparse.OptionParser()
     parser.add_option('-H', '--server-host', '--server_host',
@@ -354,22 +356,22 @@ def _main():
                       default='',
                       help='server hostname to listen to')
     parser.add_option('-p', '--port', dest='port', type='int',
-                      default=handshake.DEFAULT_WEB_SOCKET_PORT,
+                      default=common.DEFAULT_WEB_SOCKET_PORT,
                       help='port to listen to')
     parser.add_option('-w', '--websock-handlers', '--websock_handlers',
                       dest='websock_handlers',
                       default='.',
-                      help='Web Socket handlers root directory.')
+                      help='WebSocket handlers root directory.')
     parser.add_option('-m', '--websock-handlers-map-file',
                       '--websock_handlers_map_file',
                       dest='websock_handlers_map_file',
                       default=None,
-                      help=('Web Socket handlers map file. '
+                      help=('WebSocket handlers map file. '
                             'Each line consists of alias_resource_path and '
                             'existing_resource_path, separated by spaces.'))
     parser.add_option('-s', '--scan-dir', '--scan_dir', dest='scan_dir',
                       default=None,
-                      help=('Web Socket handlers scan directory. '
+                      help=('WebSocket handlers scan directory. '
                             'Must be a directory under websock_handlers.'))
     parser.add_option('-d', '--document-root', '--document_root',
                       dest='document_root', default='.',
@@ -391,7 +393,8 @@ def _main():
                       default='', help='Log file.')
     parser.add_option('--log-level', '--log_level', type='choice',
                       dest='log_level', default='warn',
-                      choices=['debug', 'info', 'warn', 'error', 'critical'],
+                      choices=['debug', 'info', 'warning', 'warn', 'error',
+                               'critical'],
                       help='Log level.')
     parser.add_option('--log-max', '--log_max', dest='log_max', type='int',
                       default=_DEFAULT_LOG_MAX_BYTES,
@@ -461,7 +464,8 @@ def _main():
                                  WebSocketRequestHandler)
         server.serve_forever()
     except Exception, e:
-        logging.critical(str(e))
+        logging.critical('mod_pywebsocket: %s' % e)
+        logging.critical('mod_pywebsocket: %s' % util.get_stack_trace())
         sys.exit(1)
 
 

From 5fd56cb6b8d01551c775c25b920b0559fe061103 Mon Sep 17 00:00:00 2001
From: Patrick McManus 
Date: Sat, 21 May 2011 21:27:52 -0400
Subject: [PATCH 058/145] bug 640003 - websockets, fixup tests for new server
 r=smaug r=biesi

---
 build/automation.py.in                        |  7 +-
 content/base/test/file_websocket_wsh.py       |  9 +-
 content/base/test/file_ws_basic_tests_wsh.py  |  3 +
 content/base/test/test_websocket.html         | 90 ++++++++++++-------
 content/base/test/test_websocket_hello.html   | 20 +----
 content/base/test/test_ws_basic_tests.html    | 12 ---
 modules/libpref/src/init/all.js               |  5 --
 testing/mochitest/ssltunnel/ssltunnel.cpp     |  4 +-
 ...browser_webconsole_bug_603750_websocket.js |  5 +-
 9 files changed, 78 insertions(+), 77 deletions(-)

diff --git a/build/automation.py.in b/build/automation.py.in
index 24cf0051dcd1..bf9b4ae5f82b 100644
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -441,20 +441,23 @@ function FindProxyForURL(url, host)
   var isHttp = matches[1] == 'http';
   var isHttps = matches[1] == 'https';
   var isWebSocket = matches[1] == 'ws';
+  var isWebSocketSSL = matches[1] == 'wss';
   if (!matches[3])
   {
     if (isHttp | isWebSocket) matches[3] = '80';
-    if (isHttps) matches[3] = '443';
+    if (isHttps | isWebSocketSSL) matches[3] = '443';
   }
   if (isWebSocket)
     matches[1] = 'http';
+  if (isWebSocketSSL)
+    matches[1] = 'https';
 
   var origin = matches[1] + '://' + matches[2] + ':' + matches[3];
   if (origins.indexOf(origin) < 0)
     return 'DIRECT';
   if (isHttp)
     return 'PROXY %(remote)s:%(httpport)s';
-  if (isHttps || isWebSocket)
+  if (isHttps || isWebSocket || isWebSocketSSL)
     return 'PROXY %(remote)s:%(sslport)s';
   return 'DIRECT';
 }""" % { "origins": origins,
diff --git a/content/base/test/file_websocket_wsh.py b/content/base/test/file_websocket_wsh.py
index 1431d792b974..3746d9fb3681 100644
--- a/content/base/test/file_websocket_wsh.py
+++ b/content/base/test/file_websocket_wsh.py
@@ -6,6 +6,9 @@ import sys
 # see the list of tests in test_websocket.html
 
 def web_socket_do_extra_handshake(request):
+  # must set request.ws_protocol to the selected version from ws_requested_protocols
+  request.ws_protocol = request.ws_requested_protocols[0]
+
   if request.ws_protocol == "test 2.1":
     time.sleep(5)
     pass
@@ -42,6 +45,7 @@ def web_socket_transfer_data(request):
     if msgutil.receive_message(request) == "5":
       resp = "あいうえお"
     msgutil.send_message(request, resp.decode('utf-8'))
+    msgutil.close_connection(request)
   elif request.ws_protocol == "test 7":
     try:
       while not request.client_terminated:
@@ -62,6 +66,9 @@ def web_socket_transfer_data(request):
     if msgutil.receive_message(request) == "client data":
       resp = "server data"
     msgutil.send_message(request, resp.decode('utf-8'))
+    msgutil.close_connection(request)
+  elif request.ws_protocol == "test 12":
+    msgutil.close_connection(request)
   elif request.ws_protocol == "test 13":
     # first one binary message containing the byte 0x61 ('a')
     request.connection.write('\xff\x01\x61')
@@ -69,7 +76,7 @@ def web_socket_transfer_data(request):
     request.connection.write('\x01\x61\xff')
     msgutil.close_connection(request)
   elif request.ws_protocol == "test 14":
-    request.connection.write('\xff\x00')
+    msgutil.close_connection(request)
     msgutil.send_message(request, "server data")
   elif request.ws_protocol == "test 15":
     msgutil.close_connection(request, True)
diff --git a/content/base/test/file_ws_basic_tests_wsh.py b/content/base/test/file_ws_basic_tests_wsh.py
index dc3a6a942ca9..498e278435c8 100644
--- a/content/base/test/file_ws_basic_tests_wsh.py
+++ b/content/base/test/file_ws_basic_tests_wsh.py
@@ -1,6 +1,9 @@
 from mod_pywebsocket import msgutil
 
 def web_socket_do_extra_handshake(request):
+  # must set request.ws_protocol to the selected version from ws_requested_protocols
+  request.ws_protocol = request.ws_requested_protocols[0]
+
   if (request.ws_protocol == 'error'):
       raise ValueError('Error')
   pass
diff --git a/content/base/test/test_websocket.html b/content/base/test/test_websocket.html
index 61d96c576738..2adc21d64f93 100644
--- a/content/base/test/test_websocket.html
+++ b/content/base/test/test_websocket.html
@@ -51,7 +51,6 @@ var last_test = 22;
 var current_test = first_test;
 
 var timeoutToAbortTest = 60000;
-var timeoutToOpenWS = 25000;
 var all_ws = [];
 
 function shouldNotOpen(e)
@@ -264,7 +263,7 @@ function test6()
   ws.onmessage = function(e)
   {
     if (counter == 5) {
-      ok(e.data == "あいうえお");
+      ok(e.data == "あいうえお", "test 6 counter 5 data ok");
       ws.close();
       doTest(7);
     } else {
@@ -278,16 +277,25 @@ function test6()
 
 function test7()
 {
-  var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 7");
-  ws.onopen = function()
-  {
-    ws.close();
-  }
-  ws.onclose = function(e)
-  {
-    shouldCloseNotCleanly(e);
-    doTest(8);
-  };
+// with pywebsockets for -06 ths test no longer does anything useful
+// as the server handles the receipt of the close event directly, not
+// as part of the wsh - so we cannot fake the non-clean close which is
+// what we're trying to do here.
+
+  ok(true, "test disabled");
+  current_test++;
+  doTest(8);
+
+//  var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 7");
+//  ws.onopen = function()
+//  {
+//    ws.close();
+//  }
+//  ws.onclose = function(e)
+//  {
+//    shouldCloseNotCleanly(e);
+//    doTest(8);
+//  };
 }
 
 function test8()
@@ -338,21 +346,24 @@ function test10()
 function test11()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 11");
-  ok(ws.readyState == 0, "bad readyState in test 11!");
+  ok(ws.readyState == 0, "create bad readyState in test 11!");
   ws.onopen = function()
   {
-    ok(ws.readyState == 1, "bad readyState in test 11!");
+    ok(ws.readyState == 1, "open bad readyState in test 11!");
     ws.send("client data");
   }
   ws.onmessage = function(e)
   {
     ok(e.data == "server data", "bad received message in test 11!");
     ws.close();
-    ok(ws.readyState == 2, "bad readyState in test 11!");
+
+// this ok() is disabled due to a race condition - it state may have
+// advanced through 2 (closing) and into 3 (closed) before it is evald
+//    ok(ws.readyState == 2, "onmessage bad readyState in test 11!");
   }
   ws.onclose = function(e)
   {
-    ok(ws.readyState == 3, "bad readyState in test 11!");
+    ok(ws.readyState == 3, "onclose bad readyState in test 11!");
     shouldCloseCleanly(e);
     doTest(12);
   }
@@ -372,23 +383,34 @@ function test12()
       ok(true, "couldn't send an unpaired surrogate!");
     }
     ws.close();
+
+// there isnt really a server implementation of test 12, so just
+// ignore an error
+    ws.onerror = function()
+    {
+    }
+
     doTest(13);
   };
 }
 
 function test13()
 {
+    // previous versions of this test counted the number of protocol errors returned, but the 
+    // protocol stack typically closes down after reporting a protocol level error - trying
+    // to resync is too dangerous
+
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 13");
   ws._timesCalledOnError = 0;
   ws.onerror = function()
   {
     ws._timesCalledOnError++;
-    if (ws._timesCalledOnError == 2) {
-      ok(true, "test 13 succeeded");
-      doTest(14);
-    }
   }
-  ws.onclose = shouldCloseCleanly;
+  ws.onclose = function(e)
+  {
+    ok(ws._timesCalledOnError > 0, "no error events");
+    doTest(14);
+  }
 }
 
 function test14()
@@ -413,6 +435,12 @@ function test15()
     shouldCloseNotCleanly(e);
     doTest(16);
   };
+
+  // termination of the connection might cause an error event if it happens in OPEN
+  ws.onerror = function()
+  {
+  }
+
 }
 
 function test16()
@@ -428,7 +456,13 @@ function test16()
   {
     ok(false, "shouldn't send message after calling close()");
   }
-  ws.onclose = shouldCloseCleanly;
+
+  ws.onerror = function()
+  {
+  }
+  ws.onclose = function()
+  {
+  }
 }
 
 var status_test17 = "not started";
@@ -593,9 +627,6 @@ function test22()
   };
 }
 
-var domBranch;
-var oldPrefVal;
-
 function finishWSTest()
 {
   for (i = 0; i < all_ws.length; ++i) {
@@ -604,20 +635,11 @@ function finishWSTest()
       ok(false, "didn't called close on test " + all_ws[i]._testNumber + "!");
     }
   }
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  domBranch.setBoolPref("override-security-block", oldPrefVal);
   SimpleTest.finish();
 }
 
 function testWebSocket ()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefService =
-      Components.classes["@mozilla.org/preferences-service;1"]
-      .getService(Components.interfaces.nsIPrefService);
-  domBranch = prefService.getBranch("network.websocket.");
-  oldPrefVal = domBranch.getBoolPref("override-security-block");
-  domBranch.setBoolPref("override-security-block", true);
   doTest(first_test);
 }
 
diff --git a/content/base/test/test_websocket_hello.html b/content/base/test/test_websocket_hello.html
index d67c0df94ca4..2f6bd6e7c127 100644
--- a/content/base/test/test_websocket_hello.html
+++ b/content/base/test/test_websocket_hello.html
@@ -17,24 +17,8 @@
 
+
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-2-dyn.html b/layout/reftests/margin-collapsing/block-horizontal-2-dyn.html new file mode 100644 index 000000000000..fbcdda8e9e45 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-2-dyn.html @@ -0,0 +1,36 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-3-dyn.html b/layout/reftests/margin-collapsing/block-horizontal-3-dyn.html new file mode 100644 index 000000000000..8d0c6d2d5d6f --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-3-dyn.html @@ -0,0 +1,33 @@ + + + + + + + +
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-3-noref.html b/layout/reftests/margin-collapsing/block-horizontal-3-noref.html new file mode 100644 index 000000000000..b2f9e4e2ada7 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-3-noref.html @@ -0,0 +1,23 @@ + + + + + + +
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-3-ref.html b/layout/reftests/margin-collapsing/block-horizontal-3-ref.html new file mode 100644 index 000000000000..9b84cbeb52f5 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-3-ref.html @@ -0,0 +1,25 @@ + + + + + + +
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-3.html b/layout/reftests/margin-collapsing/block-horizontal-3.html new file mode 100644 index 000000000000..d10c1f13c6c7 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-3.html @@ -0,0 +1,23 @@ + + + + + + +
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-4-dyn.html b/layout/reftests/margin-collapsing/block-horizontal-4-dyn.html new file mode 100644 index 000000000000..f51ad16cf6ff --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-4-dyn.html @@ -0,0 +1,33 @@ + + + + + + + +
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-4-noref.html b/layout/reftests/margin-collapsing/block-horizontal-4-noref.html new file mode 100644 index 000000000000..5ed5bd06eaad --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-4-noref.html @@ -0,0 +1,23 @@ + + + + + + +
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-4-ref.html b/layout/reftests/margin-collapsing/block-horizontal-4-ref.html new file mode 100644 index 000000000000..263530d2f6b3 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-4-ref.html @@ -0,0 +1,25 @@ + + + + + + +
+ + diff --git a/layout/reftests/margin-collapsing/block-horizontal-4.html b/layout/reftests/margin-collapsing/block-horizontal-4.html new file mode 100644 index 000000000000..6a4e5c1e20ea --- /dev/null +++ b/layout/reftests/margin-collapsing/block-horizontal-4.html @@ -0,0 +1,23 @@ + + + + + + +
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-1-noref.html b/layout/reftests/margin-collapsing/block-sibling-1-noref.html new file mode 100644 index 000000000000..4b123d94750b --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-1-noref.html @@ -0,0 +1,20 @@ + + + + + + +
+
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-1-noref2.html b/layout/reftests/margin-collapsing/block-sibling-1-noref2.html new file mode 100644 index 000000000000..96a2f6b10584 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-1-noref2.html @@ -0,0 +1,20 @@ + + + + + + +
+
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-1a-dyn.html b/layout/reftests/margin-collapsing/block-sibling-1a-dyn.html new file mode 100644 index 000000000000..195d3a63ac8b --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-1a-dyn.html @@ -0,0 +1,29 @@ + + + + + + + +
+
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-1b-dyn.html b/layout/reftests/margin-collapsing/block-sibling-1b-dyn.html new file mode 100644 index 000000000000..4360cb6b80f2 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-1b-dyn.html @@ -0,0 +1,29 @@ + + + + + + + +
+
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-1c-dyn.html b/layout/reftests/margin-collapsing/block-sibling-1c-dyn.html new file mode 100644 index 000000000000..27f6159938dd --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-1c-dyn.html @@ -0,0 +1,29 @@ + + + + + + + +
+
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-2-dyn.html b/layout/reftests/margin-collapsing/block-sibling-2-dyn.html new file mode 100644 index 000000000000..0b710d964a74 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-2-dyn.html @@ -0,0 +1,40 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-2-noref.html b/layout/reftests/margin-collapsing/block-sibling-2-noref.html new file mode 100644 index 000000000000..5a687e9a5061 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-2-noref.html @@ -0,0 +1,26 @@ + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-3-dyn.html b/layout/reftests/margin-collapsing/block-sibling-3-dyn.html new file mode 100644 index 000000000000..4303a3445cbd --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-3-dyn.html @@ -0,0 +1,35 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/block-sibling-3.html b/layout/reftests/margin-collapsing/block-sibling-3.html new file mode 100644 index 000000000000..4156e6fe12b0 --- /dev/null +++ b/layout/reftests/margin-collapsing/block-sibling-3.html @@ -0,0 +1,29 @@ + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/caption-sibling-1-noref.html b/layout/reftests/margin-collapsing/caption-sibling-1-noref.html new file mode 100644 index 000000000000..796478cfaa74 --- /dev/null +++ b/layout/reftests/margin-collapsing/caption-sibling-1-noref.html @@ -0,0 +1,33 @@ + + + + + + + +
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/caption-sibling-1-noref2.html b/layout/reftests/margin-collapsing/caption-sibling-1-noref2.html new file mode 100644 index 000000000000..185eb860a7b2 --- /dev/null +++ b/layout/reftests/margin-collapsing/caption-sibling-1-noref2.html @@ -0,0 +1,33 @@ + + + + + + + +
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/caption-sibling-1a-dyn.html b/layout/reftests/margin-collapsing/caption-sibling-1a-dyn.html new file mode 100644 index 000000000000..305927fd9ffe --- /dev/null +++ b/layout/reftests/margin-collapsing/caption-sibling-1a-dyn.html @@ -0,0 +1,45 @@ + + + + + + + + +
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/caption-sibling-1b-dyn.html b/layout/reftests/margin-collapsing/caption-sibling-1b-dyn.html new file mode 100644 index 000000000000..b9b34f6ab8b0 --- /dev/null +++ b/layout/reftests/margin-collapsing/caption-sibling-1b-dyn.html @@ -0,0 +1,45 @@ + + + + + + + + +
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/caption-sibling-1c-dyn.html b/layout/reftests/margin-collapsing/caption-sibling-1c-dyn.html new file mode 100644 index 000000000000..9a24c2c6800d --- /dev/null +++ b/layout/reftests/margin-collapsing/caption-sibling-1c-dyn.html @@ -0,0 +1,45 @@ + + + + + + + + +
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/caption-sibling-2-dyn.html b/layout/reftests/margin-collapsing/caption-sibling-2-dyn.html new file mode 100644 index 000000000000..cf66b14f6491 --- /dev/null +++ b/layout/reftests/margin-collapsing/caption-sibling-2-dyn.html @@ -0,0 +1,46 @@ + + + + + + + + +
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/caption-sibling-2-noref.html b/layout/reftests/margin-collapsing/caption-sibling-2-noref.html new file mode 100644 index 000000000000..cfd34effb657 --- /dev/null +++ b/layout/reftests/margin-collapsing/caption-sibling-2-noref.html @@ -0,0 +1,31 @@ + + + + + + + +
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/caption-sibling-2-ref.html b/layout/reftests/margin-collapsing/caption-sibling-2-ref.html new file mode 100644 index 000000000000..a9c3f7e8f887 --- /dev/null +++ b/layout/reftests/margin-collapsing/caption-sibling-2-ref.html @@ -0,0 +1,31 @@ + + + + + + + +
+
+
+
+
+ + diff --git a/layout/reftests/margin-collapsing/inline-block-horizontal-1-dyn.html b/layout/reftests/margin-collapsing/inline-block-horizontal-1-dyn.html new file mode 100644 index 000000000000..36cd3125067c --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-block-horizontal-1-dyn.html @@ -0,0 +1,25 @@ + + + + + + + +
HelloKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-block-horizontal-2-dyn.html b/layout/reftests/margin-collapsing/inline-block-horizontal-2-dyn.html new file mode 100644 index 000000000000..b288f9b43988 --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-block-horizontal-2-dyn.html @@ -0,0 +1,30 @@ + + + + + + + +
HellomyKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-block-horizontal-2-noref.html b/layout/reftests/margin-collapsing/inline-block-horizontal-2-noref.html new file mode 100644 index 000000000000..ff9557497ff9 --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-block-horizontal-2-noref.html @@ -0,0 +1,17 @@ + + + + + + +
HellomyKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-block-horizontal-2-ref.html b/layout/reftests/margin-collapsing/inline-block-horizontal-2-ref.html new file mode 100644 index 000000000000..c34d70cd683f --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-block-horizontal-2-ref.html @@ -0,0 +1,17 @@ + + + + + + +
HellomyKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-block-horizontal-2.html b/layout/reftests/margin-collapsing/inline-block-horizontal-2.html new file mode 100644 index 000000000000..6bd9df1e60a8 --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-block-horizontal-2.html @@ -0,0 +1,23 @@ + + + + + + +
HellomyKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-horizontal-1-dyn.html b/layout/reftests/margin-collapsing/inline-horizontal-1-dyn.html new file mode 100644 index 000000000000..dd4a773897f1 --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-horizontal-1-dyn.html @@ -0,0 +1,24 @@ + + + + + + + +
HelloKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-horizontal-2-dyn.html b/layout/reftests/margin-collapsing/inline-horizontal-2-dyn.html new file mode 100644 index 000000000000..d7a8929da226 --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-horizontal-2-dyn.html @@ -0,0 +1,28 @@ + + + + + + + +
HellomyKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-horizontal-2-noref.html b/layout/reftests/margin-collapsing/inline-horizontal-2-noref.html new file mode 100644 index 000000000000..1004d1e26710 --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-horizontal-2-noref.html @@ -0,0 +1,14 @@ + + + + + + +
HellomyKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-horizontal-2-ref.html b/layout/reftests/margin-collapsing/inline-horizontal-2-ref.html new file mode 100644 index 000000000000..bc7d008b465a --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-horizontal-2-ref.html @@ -0,0 +1,14 @@ + + + + + + +
HellomyKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-horizontal-2.html b/layout/reftests/margin-collapsing/inline-horizontal-2.html new file mode 100644 index 000000000000..21e11d4363f0 --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-horizontal-2.html @@ -0,0 +1,20 @@ + + + + + + +
HellomyKitty
+ + diff --git a/layout/reftests/margin-collapsing/inline-table-horizontal-1-dyn.html b/layout/reftests/margin-collapsing/inline-table-horizontal-1-dyn.html new file mode 100644 index 000000000000..8bc92c38d09e --- /dev/null +++ b/layout/reftests/margin-collapsing/inline-table-horizontal-1-dyn.html @@ -0,0 +1,25 @@ + + + + + + + +
HelloKitty
+ + diff --git a/layout/reftests/margin-collapsing/reftest.list b/layout/reftests/margin-collapsing/reftest.list index e18a1c2d1f42..966ba2ac9c3d 100644 --- a/layout/reftests/margin-collapsing/reftest.list +++ b/layout/reftests/margin-collapsing/reftest.list @@ -1,21 +1,69 @@ == inline-horizontal-1.html inline-horizontal-1-ref.html != inline-horizontal-1.html inline-horizontal-1-noref.html +== inline-horizontal-2.html inline-horizontal-2-ref.html +!= inline-horizontal-2.html inline-horizontal-2-noref.html +== inline-horizontal-1-dyn.html inline-horizontal-1-ref.html +!= inline-horizontal-1-dyn.html inline-horizontal-1-noref.html +== inline-horizontal-2-dyn.html inline-horizontal-2-ref.html +!= inline-horizontal-2-dyn.html inline-horizontal-2-noref.html == block-horizontal-1.html block-horizontal-1-ref.html != block-horizontal-1.html block-horizontal-1-noref.html == block-horizontal-2.html block-horizontal-2-ref.html != block-horizontal-2.html block-horizontal-2-noref.html +== block-horizontal-3.html block-horizontal-3-ref.html +!= block-horizontal-3.html block-horizontal-3-noref.html +== block-horizontal-4.html block-horizontal-4-ref.html +!= block-horizontal-4.html block-horizontal-4-noref.html +== block-horizontal-1-dyn.html block-horizontal-1-ref.html +!= block-horizontal-1-dyn.html block-horizontal-1-noref.html +== block-horizontal-2-dyn.html block-horizontal-2-ref.html +!= block-horizontal-2-dyn.html block-horizontal-2-noref.html +== block-horizontal-3-dyn.html block-horizontal-3-ref.html +!= block-horizontal-3-dyn.html block-horizontal-3-noref.html +== block-horizontal-4-dyn.html block-horizontal-4-ref.html +!= block-horizontal-4-dyn.html block-horizontal-4-noref.html == inline-block-horizontal-1.html inline-block-horizontal-1-ref.html != inline-block-horizontal-1.html inline-block-horizontal-1-noref.html +== inline-block-horizontal-2.html inline-block-horizontal-2-ref.html +!= inline-block-horizontal-2.html inline-block-horizontal-2-noref.html +== inline-block-horizontal-1-dyn.html inline-block-horizontal-1-ref.html +!= inline-block-horizontal-1-dyn.html inline-block-horizontal-1-noref.html +== inline-block-horizontal-2-dyn.html inline-block-horizontal-2-ref.html +!= inline-block-horizontal-2-dyn.html inline-block-horizontal-2-noref.html == inline-table-horizontal-1.html inline-table-horizontal-1-ref.html != inline-table-horizontal-1.html inline-table-horizontal-1-noref.html +== inline-table-horizontal-1-dyn.html inline-table-horizontal-1-ref.html +!= inline-table-horizontal-1-dyn.html inline-table-horizontal-1-noref.html == block-sibling-1a.html block-sibling-1-ref.html == block-sibling-1a.html block-sibling-1-ref2.html +!= block-sibling-1a.html block-sibling-1-noref.html == block-sibling-1b.html block-sibling-1-ref.html == block-sibling-1b.html block-sibling-1-ref2.html +!= block-sibling-1b.html block-sibling-1-noref.html == block-sibling-1c.html block-sibling-1-ref.html == block-sibling-1c.html block-sibling-1-ref2.html +!= block-sibling-1c.html block-sibling-1-noref2.html == block-sibling-2.html block-sibling-2-ref.html == block-sibling-2.html block-sibling-2-ref2.html +!= block-sibling-2.html block-sibling-2-noref.html +== block-sibling-3.html block-sibling-1-ref.html +== block-sibling-3.html block-sibling-1-ref2.html +!= block-sibling-3.html block-sibling-1-noref.html +== block-sibling-1a-dyn.html block-sibling-1-ref.html +== block-sibling-1a-dyn.html block-sibling-1-ref2.html +!= block-sibling-1a-dyn.html block-sibling-1-noref.html +== block-sibling-1b-dyn.html block-sibling-1-ref.html +== block-sibling-1b-dyn.html block-sibling-1-ref2.html +!= block-sibling-1b-dyn.html block-sibling-1-noref.html +== block-sibling-1c-dyn.html block-sibling-1-ref.html +== block-sibling-1c-dyn.html block-sibling-1-ref2.html +!= block-sibling-1c-dyn.html block-sibling-1-noref2.html +== block-sibling-2-dyn.html block-sibling-2-ref.html +== block-sibling-2-dyn.html block-sibling-2-ref2.html +!= block-sibling-2-dyn.html block-sibling-2-noref.html +== block-sibling-3-dyn.html block-sibling-1-ref.html +== block-sibling-3-dyn.html block-sibling-1-ref2.html +!= block-sibling-3-dyn.html block-sibling-1-noref.html == block-negative-1a.html block-negative-1-ref.html == block-negative-1b.html block-negative-1-ref.html == block-negative-2a.html block-negative-2-ref.html @@ -90,12 +138,32 @@ == block-overflow-5c.html block-overflow-5c-ref2.html == block-overflow-5d.html block-overflow-5-ref.html == block-overflow-5d.html block-overflow-5-ref2.html -fails == table-sibling-1a.html table-sibling-1-ref.html # Bug 372303 -fails == table-sibling-1b.html table-sibling-1-ref.html # Bug 372303 -fails == table-sibling-1c.html table-sibling-1-ref.html # Bug 372303 +fails == table-sibling-1a.html table-sibling-1-ref.html # Bug 87277 +fails != table-sibling-1a.html table-sibling-1-noref.html # Bug 87277 +fails == table-sibling-1b.html table-sibling-1-ref.html # Bug 87277 +fails != table-sibling-1b.html table-sibling-1-noref.html # Bug 87277 +fails == table-sibling-1c.html table-sibling-1-ref.html # Bug 87277 +fails != table-sibling-1c.html table-sibling-1-noref2.html # Bug 87277 fails == table-sibling-2a.html table-sibling-2-ref.html # Bug 87277 +fails != table-sibling-2a.html table-sibling-2-noref.html # Bug 87277 fails == table-sibling-2b.html table-sibling-2-ref.html # Bug 87277 +fails != table-sibling-2b.html table-sibling-2-noref.html # Bug 87277 fails == table-sibling-2c.html table-sibling-2-ref.html # Bug 87277 +fails != table-sibling-2c.html table-sibling-2-noref2.html # Bug 87277 +fails == table-sibling-1a-dyn.html table-sibling-1-ref.html # Bug 87277 +fails != table-sibling-1a-dyn.html table-sibling-1-noref.html # Bug 87277 +fails == table-sibling-1b-dyn.html table-sibling-1-ref.html # Bug 87277 +fails != table-sibling-1b-dyn.html table-sibling-1-noref.html # Bug 87277 +fails == table-sibling-1c-dyn.html table-sibling-1-ref.html # Bug 87277 +fails != table-sibling-1c-dyn.html table-sibling-1-noref2.html # Bug 87277 +fails == table-sibling-2a-dyn.html table-sibling-2-ref.html # Bug 87277 +fails != table-sibling-2a-dyn.html table-sibling-2-noref.html # Bug 87277 +fails == table-sibling-2b-dyn.html table-sibling-2-ref.html # Bug 87277 +fails != table-sibling-2b-dyn.html table-sibling-2-noref.html # Bug 87277 +fails == table-sibling-2c-dyn.html table-sibling-2-ref.html # Bug 87277 +fails != table-sibling-2c-dyn.html table-sibling-2-noref2.html # Bug 87277 +fails == table-sibling-3-dyn.html table-sibling-3-ref.html # Bug 87277 +fails != table-sibling-3-dyn.html table-sibling-3-noref.html # Bug 87277 == table-caption-1a.html table-caption-1-ref.html == table-caption-1b.html table-caption-1-ref.html == table-caption-2a.html table-caption-2-ref.html @@ -106,8 +174,19 @@ fails == table-sibling-2c.html table-sibling-2-ref.html # Bug 87277 == table-caption-bottom-1.html table-caption-bottom-1-ref.html == table-caption-bottom-2.html table-caption-bottom-2-ref.html fails == caption-sibling-1a.html caption-sibling-1-ref.html # Bug 144517 +!= caption-sibling-1a.html caption-sibling-1-noref.html fails == caption-sibling-1b.html caption-sibling-1-ref.html # Bug 144517 +!= caption-sibling-1b.html caption-sibling-1-noref.html fails == caption-sibling-1c.html caption-sibling-1-ref.html # Bug 144517 +!= caption-sibling-1c.html caption-sibling-1-noref2.html +fails == caption-sibling-1a-dyn.html caption-sibling-1-ref.html # Bug 144517 +!= caption-sibling-1a-dyn.html caption-sibling-1-noref.html +fails == caption-sibling-1b-dyn.html caption-sibling-1-ref.html # Bug 144517 +!= caption-sibling-1b-dyn.html caption-sibling-1-noref.html +fails == caption-sibling-1c-dyn.html caption-sibling-1-ref.html # Bug 144517 +!= caption-sibling-1c-dyn.html caption-sibling-1-noref2.html +fails == caption-sibling-2-dyn.html caption-sibling-2-ref.html # Bug 144517 +!= caption-sibling-2-dyn.html caption-sibling-2-noref.html == fieldset-sibling-1a.html fieldset-sibling-1-ref.html == fieldset-sibling-1b.html fieldset-sibling-1-ref.html == fieldset-sibling-1c.html fieldset-sibling-1-ref.html @@ -244,4 +323,4 @@ fails == block-clear-7g-left.html block-clear-7efgh-left-ref2.html # Bug 493380 == block-zero-min-height-3c.html block-zero-min-height-3-ref.html == block-zero-min-height-3d.html block-zero-min-height-3-ref.html == block-percent-1.html block-percent-1-ref.html -== dynamic-add-text-1.html dynamic-add-text-1-ref.html +== dynamic-add-text-1.html dynamic-add-text-1-ref.html # Bug 467321 diff --git a/layout/reftests/margin-collapsing/table-sibling-1-noref.html b/layout/reftests/margin-collapsing/table-sibling-1-noref.html new file mode 100644 index 000000000000..c04fc069c2a4 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-1-noref.html @@ -0,0 +1,29 @@ + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-1-noref2.html b/layout/reftests/margin-collapsing/table-sibling-1-noref2.html new file mode 100644 index 000000000000..256cae9f0913 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-1-noref2.html @@ -0,0 +1,29 @@ + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-1a-dyn.html b/layout/reftests/margin-collapsing/table-sibling-1a-dyn.html new file mode 100644 index 000000000000..a558c31546c1 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-1a-dyn.html @@ -0,0 +1,38 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-1b-dyn.html b/layout/reftests/margin-collapsing/table-sibling-1b-dyn.html new file mode 100644 index 000000000000..580255986105 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-1b-dyn.html @@ -0,0 +1,38 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-1c-dyn.html b/layout/reftests/margin-collapsing/table-sibling-1c-dyn.html new file mode 100644 index 000000000000..a22cf00d992e --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-1c-dyn.html @@ -0,0 +1,38 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-2-noref.html b/layout/reftests/margin-collapsing/table-sibling-2-noref.html new file mode 100644 index 000000000000..f0ffec8230e9 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-2-noref.html @@ -0,0 +1,29 @@ + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-2-noref2.html b/layout/reftests/margin-collapsing/table-sibling-2-noref2.html new file mode 100644 index 000000000000..3d476c01de21 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-2-noref2.html @@ -0,0 +1,29 @@ + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-2a-dyn.html b/layout/reftests/margin-collapsing/table-sibling-2a-dyn.html new file mode 100644 index 000000000000..a09d118a8471 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-2a-dyn.html @@ -0,0 +1,38 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-2b-dyn.html b/layout/reftests/margin-collapsing/table-sibling-2b-dyn.html new file mode 100644 index 000000000000..f0c705106cff --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-2b-dyn.html @@ -0,0 +1,38 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-2c-dyn.html b/layout/reftests/margin-collapsing/table-sibling-2c-dyn.html new file mode 100644 index 000000000000..0a3047104097 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-2c-dyn.html @@ -0,0 +1,38 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-3-dyn.html b/layout/reftests/margin-collapsing/table-sibling-3-dyn.html new file mode 100644 index 000000000000..49878f45318d --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-3-dyn.html @@ -0,0 +1,38 @@ + + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-3-noref.html b/layout/reftests/margin-collapsing/table-sibling-3-noref.html new file mode 100644 index 000000000000..69952b90247a --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-3-noref.html @@ -0,0 +1,23 @@ + + + + + + +
+
+
+ + diff --git a/layout/reftests/margin-collapsing/table-sibling-3-ref.html b/layout/reftests/margin-collapsing/table-sibling-3-ref.html new file mode 100644 index 000000000000..9b1dc0724f96 --- /dev/null +++ b/layout/reftests/margin-collapsing/table-sibling-3-ref.html @@ -0,0 +1,23 @@ + + + + + + +
+
+
+ + From 77408a88a659ecb0699376fd000f87c0462c5156 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sat, 21 May 2011 22:06:24 +0200 Subject: [PATCH 073/145] Bug 658314 - UserToDevice uses the transform matrix. r=roc --HG-- extra : rebase_source : 642b8d2ec5c5a523c74d44c4285731810f28e7ba --- gfx/thebes/gfxContext.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h index 6ac8143ec750..9f6a7a97b8c2 100644 --- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -323,8 +323,8 @@ public: gfxRect DeviceToUser(const gfxRect& rect) const; /** - * Converts a point from user to device coordinates using the inverse - * transformation matrix. + * Converts a point from user to device coordinates using the transformation + * matrix. */ gfxPoint UserToDevice(const gfxPoint& point) const; From aa420b62096944136b5bc9fb35e17b7b0edd44b1 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Sat, 21 May 2011 22:06:38 +0200 Subject: [PATCH 074/145] Bug 658500 - Don't treat windows with window level kCGFloatingWindowLevel as transparent to mouse events. r=josh --HG-- extra : rebase_source : 4bba3149f835785fb1e28709b96dc41060cc8461 --- widget/src/cocoa/nsChildView.mm | 3 --- 1 file changed, 3 deletions(-) diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 663a23091b9a..56d37364289c 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -6330,7 +6330,6 @@ ChildViewMouseTracker::ViewForEvent(NSEvent* aEvent) static CGWindowLevel kDockWindowLevel = 0; static CGWindowLevel kPopupWindowLevel = 0; -static CGWindowLevel kFloatingWindowLevel = 0; static BOOL WindowNumberIsUnderPoint(NSInteger aWindowNumber, NSPoint aPoint) { NSWindow* window = [NSApp windowWithWindowNumber:aWindowNumber]; @@ -6345,14 +6344,12 @@ static BOOL WindowNumberIsUnderPoint(NSInteger aWindowNumber, NSPoint aPoint) { // These constants are in fact function calls, so cache them. kDockWindowLevel = kCGDockWindowLevel; kPopupWindowLevel = kCGPopUpMenuWindowLevel; - kFloatingWindowLevel = kCGFloatingWindowLevel; } // Some things put transparent windows on top of everything. Ignore them. CGWindowLevel level; if ((kCGErrorSuccess == CGSGetWindowLevel(cid, aWindowNumber, &level)) && (level == kDockWindowLevel || // Transparent layer, spanning the whole screen - level == kFloatingWindowLevel || // invisible Jing window level > kPopupWindowLevel)) // Snapz Pro X while recording a screencast return false; From 95946ba5813ac0a059915d4b8e5b12df048b44d7 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Sun, 22 May 2011 14:43:13 +0200 Subject: [PATCH 075/145] Bug 657210 - Outparamdel nsEditor::GetPresShell; r=ehsan --- editor/libeditor/base/nsEditor.cpp | 51 +++++++------------ editor/libeditor/base/nsEditor.h | 4 +- .../libeditor/base/nsEditorEventListener.cpp | 4 +- editor/libeditor/html/nsHTMLAbsPosition.cpp | 6 +-- .../libeditor/html/nsHTMLAnonymousUtils.cpp | 3 +- editor/libeditor/html/nsHTMLEditor.cpp | 21 +++----- .../html/nsHTMLInlineTableEditor.cpp | 3 +- editor/libeditor/html/nsHTMLObjectResizer.cpp | 3 +- editor/libeditor/html/nsTableEditor.cpp | 8 ++- editor/libeditor/text/nsPlaintextEditor.cpp | 11 ++-- editor/libeditor/text/nsTextEditRulesBidi.cpp | 6 +-- 11 files changed, 42 insertions(+), 78 deletions(-) diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 67881f836eb5..94564524c504 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -242,8 +242,7 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIContent *aRoot, nsISelectionController * mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller selCon = aSelCon; } else { - nsCOMPtr presShell; - GetPresShell(getter_AddRefs(presShell)); + nsCOMPtr presShell = GetPresShell(); selCon = do_QueryInterface(presShell); } NS_ASSERTION(selCon, "Selection controller should be available at this point"); @@ -315,8 +314,7 @@ nsEditor::PostCreate() // update nsTextStateManager and caret if we have focus nsCOMPtr focusedContent = GetFocusedContent(); if (focusedContent) { - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ASSERTION(ps, "no pres shell even though we have focus"); NS_ENSURE_TRUE(ps, NS_ERROR_UNEXPECTED); nsPresContext* pc = ps->GetPresContext(); @@ -396,12 +394,11 @@ nsEditor::GetDesiredSpellCheckState() return PR_FALSE; } - nsCOMPtr presShell; - rv = GetPresShell(getter_AddRefs(presShell)); - if (NS_SUCCEEDED(rv)) { + nsCOMPtr presShell = GetPresShell(); + if (presShell) { nsPresContext* context = presShell->GetPresContext(); if (context && !context->IsDynamic()) { - return PR_FALSE; + return PR_FALSE; } } @@ -528,19 +525,14 @@ nsEditor::GetDocument(nsIDOMDocument **aDoc) return NS_OK; } - -nsresult -nsEditor::GetPresShell(nsIPresShell **aPS) +already_AddRefed +nsEditor::GetPresShell() { - NS_ENSURE_TRUE(aPS, NS_ERROR_NULL_POINTER); - *aPS = nsnull; // init out param NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak"); nsCOMPtr doc = do_QueryReferent(mDocWeak); - NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED); - *aPS = doc->GetShell(); - NS_ENSURE_TRUE(*aPS, NS_ERROR_NOT_INITIALIZED); - NS_ADDREF(*aPS); - return NS_OK; + NS_ENSURE_TRUE(doc, NULL); + nsRefPtr ps = doc->GetShell(); + return ps.forget(); } @@ -569,8 +561,7 @@ nsEditor::GetSelectionController(nsISelectionController **aSel) if (mSelConWeak) { selCon = do_QueryReferent(mSelConWeak); } else { - nsCOMPtr presShell; - GetPresShell(getter_AddRefs(presShell)); + nsCOMPtr presShell = GetPresShell(); selCon = do_QueryInterface(presShell); } NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED); @@ -939,8 +930,7 @@ nsEditor::EndPlaceHolderTransaction() // Hide the caret here to avoid hiding it twice, once in EndUpdateViewBatch // and once in ScrollSelectionIntoView. nsRefPtr caret; - nsCOMPtr presShell; - GetPresShell(getter_AddRefs(presShell)); + nsCOMPtr presShell = GetPresShell(); if (presShell) caret = presShell->GetCaret(); @@ -2778,8 +2768,7 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, } } // handle selection - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); if (ps) ps->FlushPendingNotifications(Flush_Frames); @@ -3907,8 +3896,7 @@ nsEditor::IsPreformatted(nsIDOMNode *aNode, PRBool *aResult) NS_ENSURE_TRUE(aResult && content, NS_ERROR_NULL_POINTER); - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); // Look at the node (and its parent if it's not an element), and grab its style context @@ -4117,8 +4105,7 @@ nsresult nsEditor::BeginUpdateViewBatch() } // Turn off view updating. - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); if (ps) { nsCOMPtr viewManager = ps->GetViewManager(); if (viewManager) { @@ -4153,8 +4140,7 @@ nsresult nsEditor::EndUpdateViewBatch() // to draw at the correct position. nsRefPtr caret; - nsCOMPtr presShell; - GetPresShell(getter_AddRefs(presShell)); + nsCOMPtr presShell = GetPresShell(); if (presShell) caret = presShell->GetCaret(); @@ -5083,9 +5069,8 @@ nsEditor::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget) nsresult rv = GetSelection(getter_AddRefs(selection)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr presShell; - rv = GetPresShell(getter_AddRefs(presShell)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr presShell = GetPresShell(); + NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_INITIALIZED); nsCOMPtr selCon; rv = GetSelectionController(getter_AddRefs(selCon)); diff --git a/editor/libeditor/base/nsEditor.h b/editor/libeditor/base/nsEditor.h index 33a3cac70ac1..8fdbc0d9054f 100644 --- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -145,8 +145,8 @@ public: nsIEditor) /* ------------ utility methods -------------- */ - NS_IMETHOD GetPresShell(nsIPresShell **aPS); - void NotifyEditorObservers(void); + already_AddRefed GetPresShell(); + void NotifyEditorObservers(); /* ------------ nsIEditor methods -------------- */ NS_DECL_NSIEDITOR diff --git a/editor/libeditor/base/nsEditorEventListener.cpp b/editor/libeditor/base/nsEditorEventListener.cpp index 9d44d7a20bc6..d1b3a77a1e2c 100644 --- a/editor/libeditor/base/nsEditorEventListener.cpp +++ b/editor/libeditor/base/nsEditorEventListener.cpp @@ -257,9 +257,7 @@ nsEditorEventListener::GetPresShell() { NS_PRECONDITION(mEditor, "The caller must check whether this is connected to an editor"); - nsCOMPtr ps; - mEditor->GetPresShell(getter_AddRefs(ps)); - return ps.forget(); + return mEditor->GetPresShell(); } /** diff --git a/editor/libeditor/html/nsHTMLAbsPosition.cpp b/editor/libeditor/html/nsHTMLAbsPosition.cpp index 08836d8fb5fe..2f446838a4ba 100644 --- a/editor/libeditor/html/nsHTMLAbsPosition.cpp +++ b/editor/libeditor/html/nsHTMLAbsPosition.cpp @@ -311,8 +311,7 @@ nsHTMLEditor::HideGrabber() NS_ENSURE_TRUE(mGrabber, NS_ERROR_NULL_POINTER); // get the presshell's document observer interface. - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); // We allow the pres shell to be null; when it is, we presume there // are no document observers to notify, but we still want to // UnbindFromTree. @@ -428,8 +427,7 @@ nsresult nsHTMLEditor::EndMoving() { if (mPositioningShadow) { - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); nsCOMPtr parentNode; diff --git a/editor/libeditor/html/nsHTMLAnonymousUtils.cpp b/editor/libeditor/html/nsHTMLAnonymousUtils.cpp index b7aea69a67d4..8fa94cd5353a 100644 --- a/editor/libeditor/html/nsHTMLAnonymousUtils.cpp +++ b/editor/libeditor/html/nsHTMLAnonymousUtils.cpp @@ -156,8 +156,7 @@ nsHTMLEditor::CreateAnonymousElement(const nsAString & aTag, nsIDOMNode * aPare NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER); // Get the pres shell - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); // Create a new node through the element factory diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index aac342d92c1a..8c4138fb91f3 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -175,8 +175,7 @@ nsHTMLEditor::~nsHTMLEditor() if (mLinkHandler && mDocWeak) { - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); if (ps && ps->GetPresContext()) { @@ -305,8 +304,7 @@ nsHTMLEditor::Init(nsIDOMDocument *aDoc, mHTMLCSSUtils = new nsHTMLCSSUtils(this); // disable links - nsCOMPtr presShell; - GetPresShell(getter_AddRefs(presShell)); + nsCOMPtr presShell = GetPresShell(); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); nsPresContext *context = presShell->GetPresContext(); NS_ENSURE_TRUE(context, NS_ERROR_NULL_POINTER); @@ -3498,8 +3496,7 @@ nsHTMLEditor::ReplaceStyleSheet(const nsAString& aURL) // Make sure the pres shell doesn't disappear during the load. NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); nsCOMPtr uaURI; @@ -3543,8 +3540,7 @@ nsHTMLEditor::AddOverrideStyleSheet(const nsAString& aURL) return NS_OK; // Make sure the pres shell doesn't disappear during the load. - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); nsCOMPtr uaURI; @@ -3608,8 +3604,7 @@ nsHTMLEditor::RemoveOverrideStyleSheet(const nsAString &aURL) NS_ENSURE_TRUE(sheet, NS_OK); /// Don't fail if sheet not found NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); ps->RemoveOverrideStyleSheet(sheet); @@ -4202,8 +4197,7 @@ nsHTMLEditor::SelectAll() return selection->SelectAllChildren(mRootElement); } - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); nsIContent *rootContent = anchorContent->GetSelectionRootContent(ps); NS_ENSURE_TRUE(rootContent, NS_ERROR_UNEXPECTED); @@ -5596,8 +5590,7 @@ nsHTMLEditor::GetElementOrigin(nsIDOMElement * aElement, PRInt32 & aX, PRInt32 & aY = 0; NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); nsCOMPtr content = do_QueryInterface(aElement); diff --git a/editor/libeditor/html/nsHTMLInlineTableEditor.cpp b/editor/libeditor/html/nsHTMLInlineTableEditor.cpp index 170ccf7d32ce..b157a6502179 100644 --- a/editor/libeditor/html/nsHTMLInlineTableEditor.cpp +++ b/editor/libeditor/html/nsHTMLInlineTableEditor.cpp @@ -124,8 +124,7 @@ nsHTMLEditor::HideInlineTableEditingUI() RemoveMouseClickListener(mAddRowAfterButton); // get the presshell's document observer interface. - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); // We allow the pres shell to be null; when it is, we presume there // are no document observers to notify, but we still want to // UnbindFromTree. diff --git a/editor/libeditor/html/nsHTMLObjectResizer.cpp b/editor/libeditor/html/nsHTMLObjectResizer.cpp index 5c0eb0dcdeb4..88c8471c8026 100644 --- a/editor/libeditor/html/nsHTMLObjectResizer.cpp +++ b/editor/libeditor/html/nsHTMLObjectResizer.cpp @@ -432,8 +432,7 @@ nsHTMLEditor::HideResizers(void) NS_ENSURE_TRUE(mResizedObject, NS_OK); // get the presshell's document observer interface. - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); // We allow the pres shell to be null; when it is, we presume there // are no document observers to notify, but we still want to // UnbindFromTree. diff --git a/editor/libeditor/html/nsTableEditor.cpp b/editor/libeditor/html/nsTableEditor.cpp index 06b453ea9966..b3ece7429237 100644 --- a/editor/libeditor/html/nsTableEditor.cpp +++ b/editor/libeditor/html/nsTableEditor.cpp @@ -2643,8 +2643,7 @@ nsHTMLEditor::GetCellIndexes(nsIDOMElement *aCell, } NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); nsCOMPtr nodeAsContent( do_QueryInterface(aCell) ); @@ -2661,11 +2660,10 @@ nsHTMLEditor::GetCellIndexes(nsIDOMElement *aCell, NS_IMETHODIMP nsHTMLEditor::GetTableLayoutObject(nsIDOMElement* aTable, nsITableLayout **tableLayoutObject) { - *tableLayoutObject=nsnull; + *tableLayoutObject = nsnull; NS_ENSURE_TRUE(aTable, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED); - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); nsCOMPtr nodeAsContent( do_QueryInterface(aTable) ); diff --git a/editor/libeditor/text/nsPlaintextEditor.cpp b/editor/libeditor/text/nsPlaintextEditor.cpp index ad4e1dc1b0df..e413f0a4e3eb 100644 --- a/editor/libeditor/text/nsPlaintextEditor.cpp +++ b/editor/libeditor/text/nsPlaintextEditor.cpp @@ -853,9 +853,8 @@ NS_IMETHODIMP nsPlaintextEditor::InsertLineBreak() // Batching the selection and moving nodes out from under the caret causes // caret turds. Ask the shell to invalidate the caret now to avoid the turds. - nsCOMPtr shell; - res = GetPresShell(getter_AddRefs(shell)); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr shell = GetPresShell(); + NS_ENSURE_TRUE(shell, NS_ERROR_NOT_INITIALIZED); shell->MaybeInvalidateCaretPosition(); nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertBreak); @@ -948,8 +947,7 @@ nsPlaintextEditor::UpdateIMEComposition(const nsAString& aCompositionString, return NS_ERROR_NULL_POINTER; } - nsCOMPtr ps; - GetPresShell(getter_AddRefs(ps)); + nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); nsCOMPtr selection; @@ -1272,8 +1270,7 @@ nsPlaintextEditor::FireClipboardEvent(PRInt32 aType) if (aType == NS_PASTE) ForceCompositionEnd(); - nsCOMPtr presShell; - GetPresShell(getter_AddRefs(presShell)); + nsCOMPtr presShell = GetPresShell(); NS_ENSURE_TRUE(presShell, PR_FALSE); nsCOMPtr selection; diff --git a/editor/libeditor/text/nsTextEditRulesBidi.cpp b/editor/libeditor/text/nsTextEditRulesBidi.cpp index 2117f7edb104..839ea9fabce7 100644 --- a/editor/libeditor/text/nsTextEditRulesBidi.cpp +++ b/editor/libeditor/text/nsTextEditRulesBidi.cpp @@ -56,10 +56,8 @@ nsTextEditRules::CheckBidiLevelForDeletion(nsISelection *aSelection, NS_ENSURE_ARG_POINTER(aCancel); *aCancel = PR_FALSE; - nsCOMPtr shell; - nsresult res = mEditor->GetPresShell(getter_AddRefs(shell)); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_TRUE(shell, NS_ERROR_NULL_POINTER); + nsCOMPtr shell = mEditor->GetPresShell(); + NS_ENSURE_TRUE(shell, NS_ERROR_NOT_INITIALIZED); nsPresContext *context = shell->GetPresContext(); NS_ENSURE_TRUE(context, NS_ERROR_NULL_POINTER); From 14fb4cd9c3e5ae793b114536f8419751cd532936 Mon Sep 17 00:00:00 2001 From: Kenneth Barbalace Date: Sun, 22 May 2011 17:25:44 +0200 Subject: [PATCH 076/145] Bug 658729 - Override tab max-width set by extensions and themes using !important. r=dao --- browser/base/content/tabbrowser.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index c809ffdb1285..47381b3c28b2 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -2902,7 +2902,7 @@ tabWidth += "px"; for (let i = numPinned; i < tabs.length; i++) { let tab = tabs[i]; - tab.style.maxWidth = tabWidth; + tab.style.setProperty("max-width", tabWidth, "important"); if (!isEndTab) { // keep tabs the same width tab.style.MozTransition = "none"; tab.clientTop; // flush styles to skip animation; see bug 649247 From caed4c146a82974233756a8b5cfa3b1d3c3047b0 Mon Sep 17 00:00:00 2001 From: Ludovic Hirlimann Date: Sun, 22 May 2011 17:26:52 +0200 Subject: [PATCH 077/145] Bug 328090 - remove -fpascal-strings from mac build options. r=ted --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 7e77f63e7034..928e760e9990 100644 --- a/configure.in +++ b/configure.in @@ -2027,8 +2027,8 @@ case "$target" in MOZ_OPTIMIZE_FLAGS="-O3 -fno-omit-frame-pointer" fi _PEDANTIC= - CFLAGS="$CFLAGS -fpascal-strings -fno-common" - CXXFLAGS="$CXXFLAGS -fpascal-strings -fno-common" + CFLAGS="$CFLAGS -fno-common" + CXXFLAGS="$CXXFLAGS -fno-common" DLL_SUFFIX=".dylib" DSO_LDOPTS='' STRIP="$STRIP -x -S" From 650910705ea3418d10b71b5158a860a9486788bb Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sun, 22 May 2011 17:52:16 +0200 Subject: [PATCH 078/145] Backout bug 552864, bug 632404 and bug 657297 because of leak test bustage --- browser/app/Makefile.in | 87 ++++++++- browser/app/macbuild/Contents/Info.plist.in | 2 +- browser/app/nsBrowserApp.cpp | 153 ++------------- dom/plugins/ipc/PluginProcessChild.cpp | 1 - ipc/app/MozillaRuntimeMain.cpp | 1 - toolkit/xre/Makefile.in | 2 - toolkit/xre/nsAppRunner.cpp | 152 ++++++++++++++- toolkit/xre/nsWindowsDllBlocklist.cpp | 8 +- toolkit/xre/nsWindowsWMain.cpp | 1 - xpcom/base/Makefile.in | 1 + xpcom/base/Telemetry.cpp | 43 +---- xpcom/base/nsITelemetry.idl | 3 - xpcom/base/nsSetDllDirectory.h | 37 +--- xpcom/build/BinaryPath.h | 178 ------------------ xpcom/build/dlldeps.cpp | 1 + xpcom/build/nsXULAppAPI.h | 20 -- xpcom/glue/standalone/nsGlueLinking.h | 2 +- xpcom/glue/standalone/nsGlueLinkingDlopen.cpp | 71 +------ xpcom/glue/standalone/nsGlueLinkingOS2.cpp | 2 +- xpcom/glue/standalone/nsGlueLinkingOSX.cpp | 123 +----------- xpcom/glue/standalone/nsGlueLinkingWin.cpp | 25 +-- xpcom/glue/standalone/nsXPCOMGlue.cpp | 9 +- xpcom/glue/standalone/nsXPCOMGlue.h | 6 - xpinstall/packager/Packager.pm | 7 - 24 files changed, 265 insertions(+), 670 deletions(-) delete mode 100644 xpcom/build/BinaryPath.h diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in index c754c504f830..dd3a89ffa6e1 100644 --- a/browser/app/Makefile.in +++ b/browser/app/Makefile.in @@ -91,22 +91,62 @@ include $(topsrcdir)/config/rules.mk else # Build a binary bootstrapping with XRE_main +ifneq (,$(filter OS2 WINNT,$(OS_ARCH))) PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX) +else +PROGRAM = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX) +endif CPPSRCS = nsBrowserApp.cpp LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base -LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/build -DEFINES += -DXPCOM_GLUE -STL_FLAGS= +ifdef BUILD_STATIC_LIBS +ifdef _MSC_VER +STATIC_COMPONENTS_LINKER_PATH = -LIBPATH:$(DEPTH)/staticlib +else +STATIC_COMPONENTS_LINKER_PATH = -L$(DEPTH)/staticlib +endif +LIBS += $(DEPTH)/toolkit/xre/$(LIB_PREFIX)xulapp_s.$(LIB_SUFFIX) +else +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) +LIBS += $(DIST)/bin/XUL +else +EXTRA_DSO_LIBS += xul +endif +endif + +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) +TK_LIBS := $(TK_LIBS) +endif + +ifdef MOZ_ENABLE_LIBXUL +APP_XPCOM_LIBS = $(XPCOM_GLUE_LDOPTS) +else +MOZILLA_INTERNAL_API = 1 +APP_XPCOM_LIBS = $(XPCOM_LIBS) +endif LIBS += \ + $(STATIC_COMPONENTS_LINKER_PATH) \ $(EXTRA_DSO_LIBS) \ - $(XPCOM_STANDALONE_GLUE_LDOPTS) \ + $(APP_XPCOM_LIBS) \ + $(NSPR_LIBS) \ $(NULL) +ifdef BUILD_STATIC_LIBS +LIBS += \ + $(MOZ_JS_LIBS) \ + $(TK_LIBS) \ + $(NULL) + +# Add explicit X11 dependency when building against X11 toolkits +ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT))) +LIBS += $(XLDFLAGS) $(XLIBS) $(ZLIB_LIBS) +endif +endif + ifdef MOZ_JPROF LIBS += -ljprof endif @@ -131,6 +171,18 @@ ifdef _MSC_VER WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup endif +ifdef BUILD_STATIC_LIBS +include $(topsrcdir)/config/static-config.mk + +EXTRA_DEPS += \ + $(STATIC_EXTRA_DEPS) \ + $(NULL) +DEFINES += $(STATIC_DEFINES) +CPPSRCS += $(STATIC_CPPSRCS) +EXTRA_DSO_LIBS += $(STATIC_EXTRA_DSO_LIBS) +EXTRA_LIBS += $(STATIC_EXTRA_LIBS) +endif + ifeq ($(OS_ARCH),WINNT) OS_LIBS += $(call EXPAND_LIBNAME,comctl32 comdlg32 uuid shell32 ole32 oleaut32 version winspool) OS_LIBS += $(call EXPAND_LIBNAME,usp10 msimg32) @@ -143,6 +195,9 @@ RCFLAGS += -DMOZ_PHOENIX -I$(srcdir) else RCFLAGS += -DMOZ_PHOENIX --include-dir $(srcdir) endif +ifdef BUILD_STATIC_LIBS +RCFLAGS += -DMOZ_STATIC_BUILD +endif ifdef DEBUG RCFLAGS += -DDEBUG endif @@ -151,6 +206,9 @@ endif ifeq ($(OS_ARCH),OS2) RESFILE=splashos2.res RCFLAGS += -DMOZ_PHOENIX +ifdef BUILD_STATIC_LIBS +RCFLAGS += -DMOZ_STATIC_BUILD -i $(DIST)/include +endif ifdef DEBUG RCFLAGS += -DDEBUG endif @@ -159,6 +217,12 @@ endif include $(topsrcdir)/config/rules.mk +ifdef BUILD_STATIC_LIBS +include $(topsrcdir)/config/static-rules.mk + +DEFINES += -DIMPL_XREAPI +endif + ifeq ($(MOZ_WIDGET_TOOLKIT),photon) LIBS += -lphexlib endif @@ -185,9 +249,18 @@ endif ifneq (,$(filter-out OS2 WINNT,$(OS_ARCH))) -libs:: - cp -p $(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/bin/$(MOZ_APP_NAME)-bin$(BIN_SUFFIX) +$(MOZ_APP_NAME):: $(topsrcdir)/build/unix/mozilla.in $(GLOBAL_DEPS) + cat $< | sed -e "s|%MOZAPPDIR%|$(installdir)|" \ + -e "s|%MOZ_APP_DISPLAYNAME%|$(MOZ_APP_DISPLAYNAME)|" > $@ + chmod +x $@ +libs:: $(MOZ_APP_NAME) + $(INSTALL) $< $(DIST)/bin + +install:: $(MOZ_APP_NAME) + $(SYSINSTALL) $< $(DESTDIR)$(bindir) + +GARBAGE += $(MOZ_APP_NAME) GARBAGE += $(addprefix $(DIST)/bin/defaults/pref/, firefox.js) endif @@ -255,7 +328,7 @@ libs repackage:: $(PROGRAM) application.ini rsync -a $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/$(APPFILES) $(RM) $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/mangle $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/shlibsign ifdef LIBXUL_SDK - cp $(LIBXUL_DIST)/bin/$(XR_STUB_NAME) $(DIST)/$(APP_NAME).app/Contents/MacOS/firefox + cp $(LIBXUL_DIST)/bin/$(XR_STUB_NAME) $(DIST)/$(APP_NAME).app/Contents/MacOS/firefox-bin else $(RM) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM) rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS diff --git a/browser/app/macbuild/Contents/Info.plist.in b/browser/app/macbuild/Contents/Info.plist.in index 6909ea5a7a4b..f71f16301f2a 100644 --- a/browser/app/macbuild/Contents/Info.plist.in +++ b/browser/app/macbuild/Contents/Info.plist.in @@ -94,7 +94,7 @@ CFBundleExecutable - firefox + firefox-bin CFBundleGetInfoString %APP_NAME% %APP_VERSION% CFBundleIconFile diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp index fd95e9f9e96c..f8cbf7933824 100644 --- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -36,19 +36,14 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsXPCOMGlue.h" #include "nsXULAppAPI.h" -#if defined(XP_WIN) +#ifdef XP_WIN #include #include -#elif defined(XP_UNIX) -#include -#include #endif #include #include -#include #include "plstr.h" #include "prprf.h" @@ -59,14 +54,11 @@ #include "nsStringGlue.h" #ifdef XP_WIN +// we want to use the DLL blocklist if possible +#define XRE_WANT_DLL_BLOCKLIST // we want a wmain entry point #include "nsWindowsWMain.cpp" -#define snprintf _snprintf -#define strcasecmp _stricmp #endif -#include "BinaryPath.h" - -#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL static void Output(const char *fmt, ... ) { @@ -93,12 +85,12 @@ static PRBool IsArg(const char* arg, const char* s) { if (*++arg == '-') ++arg; - return !strcasecmp(arg, s); + return !PL_strcasecmp(arg, s); } #if defined(XP_WIN) || defined(XP_OS2) if (*arg == '/') - return !strcasecmp(++arg, s); + return !PL_strcasecmp(++arg, s); #endif return PR_FALSE; @@ -114,48 +106,22 @@ public: ~ScopedLogging() { NS_LogTerm(); } }; -XRE_GetFileFromPathType XRE_GetFileFromPath; -XRE_CreateAppDataType XRE_CreateAppData; -XRE_FreeAppDataType XRE_FreeAppData; -#ifdef XRE_HAS_DLL_BLOCKLIST -XRE_SetupDllBlocklistType XRE_SetupDllBlocklist; -#endif -XRE_TelemetryAddType XRE_TelemetryAdd; -XRE_mainType XRE_main; - -static const nsDynamicFunctionLoad kXULFuncs[] = { - { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, - { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, - { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, -#ifdef XRE_HAS_DLL_BLOCKLIST - { "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist }, -#endif - { "XRE_TelemetryAdd", (NSFuncPtr*) &XRE_TelemetryAdd }, - { "XRE_main", (NSFuncPtr*) &XRE_main }, - { nsnull, nsnull } -}; - -static int do_main(const char *exePath, int argc, char* argv[]) +int main(int argc, char* argv[]) { + ScopedLogging log; + nsCOMPtr appini; -#ifdef XP_WIN - // exePath comes from mozilla::BinaryPath::Get, which returns a UTF-8 - // encoded path, so it is safe to convert it - nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), PR_FALSE, - getter_AddRefs(appini)); -#else - nsresult rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_FALSE, - getter_AddRefs(appini)); -#endif + nsresult rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appini)); if (NS_FAILED(rv)) { + Output("Couldn't calculate the application directory."); return 255; } - appini->SetNativeLeafName(NS_LITERAL_CSTRING("application.ini")); // Allow firefox.exe to launch XULRunner apps via -app // Note that -app must be the *first* argument. - const char *appDataFile = getenv("XUL_APP_FILE"); + char *appEnv = nsnull; + const char *appDataFile = PR_GetEnv("XUL_APP_FILE"); if (appDataFile && *appDataFile) { rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini)); if (NS_FAILED(rv)) { @@ -175,12 +141,8 @@ static int do_main(const char *exePath, int argc, char* argv[]) return 255; } - char appEnv[MAXPATHLEN]; - snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]); - if (putenv(appEnv)) { - Output("Couldn't set %s.\n", appEnv); - return 255; - } + appEnv = PR_smprintf("XUL_APP_FILE=%s", argv[2]); + PR_SetEnv(appEnv); argv[2] = argv[0]; argv += 2; argc -= 2; @@ -195,90 +157,7 @@ static int do_main(const char *exePath, int argc, char* argv[]) int result = XRE_main(argc, argv, appData); XRE_FreeAppData(appData); - return result; -} - -int main(int argc, char* argv[]) -{ - char exePath[MAXPATHLEN]; - - nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath); - if (NS_FAILED(rv)) { - Output("Couldn't calculate the application directory.\n"); - return 255; - } - - char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); - if (!lastSlash || (lastSlash - exePath > MAXPATHLEN - sizeof(XPCOM_DLL) - 1)) - return 255; - - strcpy(++lastSlash, XPCOM_DLL); - - int gotCounters; -#if defined(XP_UNIX) - struct rusage initialRUsage; - gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); -#elif defined(XP_WIN) - // GetProcessIoCounters().ReadOperationCount seems to have little to - // do with actual read operations. It reports 0 or 1 at this stage - // in the program. Luckily 1 coincides with when prefetch is - // enabled. If Windows prefetch didn't happen we can do our own - // faster dll preloading. - IO_COUNTERS ioCounters; - gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); - if (gotCounters && !ioCounters.ReadOperationCount) -#endif - { - XPCOMGlueEnablePreload(); - } - - - rv = XPCOMGlueStartup(exePath); - if (NS_FAILED(rv)) { - Output("Couldn't load XPCOM.\n"); - return 255; - } - - rv = XPCOMGlueLoadXULFunctions(kXULFuncs); - if (NS_FAILED(rv)) { - Output("Couldn't load XRE functions.\n"); - return 255; - } - -#ifdef XRE_HAS_DLL_BLOCKLIST - XRE_SetupDllBlocklist(); -#endif - - if (gotCounters) { -#if defined(XP_WIN) - XRE_TelemetryAdd("Early.GlueStartup::ProcessIoCounters.ReadOperationCount", - int(ioCounters.ReadOperationCount), 1, 100, 12, HISTOGRAM_LINEAR); - XRE_TelemetryAdd("Early.GlueStartup::ProcessIoCounters.ReadTransferCount (KB)", - int(ioCounters.ReadTransferCount / 1024), 1, 50 * 1024, 12, HISTOGRAM_LINEAR); - IO_COUNTERS newIoCounters; - if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) { - XRE_TelemetryAdd("GlueStartup::ProcessIoCounters.ReadOperationCount", - int(newIoCounters.ReadOperationCount - ioCounters.ReadOperationCount), 1, 100, 12, HISTOGRAM_LINEAR); - XRE_TelemetryAdd("GlueStartup::ProcessIoCounters.ReadTransferCount (KB)", - int((newIoCounters.ReadTransferCount - ioCounters.ReadTransferCount) / 1024), 1, 50 * 1024, 12, HISTOGRAM_LINEAR); - } -#elif defined(XP_UNIX) - XRE_TelemetryAdd("Early.GlueStartup::HardFaults", - int(initialRUsage.ru_majflt), 1, 100, 12, HISTOGRAM_LINEAR); - struct rusage newRUsage; - if (!getrusage(RUSAGE_SELF, &newRUsage)) { - XRE_TelemetryAdd("GlueStartup::HardFaults", - int(newRUsage.ru_majflt - initialRUsage.ru_majflt), 1, 500, 12, HISTOGRAM_LINEAR); - } -#endif - } - - int result; - { - ScopedLogging log; - result = do_main(exePath, argc, argv); - } - - XPCOMGlueShutdown(); + if (appEnv) + PR_smprintf_free(appEnv); return result; } diff --git a/dom/plugins/ipc/PluginProcessChild.cpp b/dom/plugins/ipc/PluginProcessChild.cpp index 00df22f415d6..8151b10870e7 100644 --- a/dom/plugins/ipc/PluginProcessChild.cpp +++ b/dom/plugins/ipc/PluginProcessChild.cpp @@ -110,7 +110,6 @@ PluginProcessChild::Init() protectCurrentDirectory = false; } if (protectCurrentDirectory) { - SanitizeEnvironmentVariables(); NS_SetDllDirectory(L""); } diff --git a/ipc/app/MozillaRuntimeMain.cpp b/ipc/app/MozillaRuntimeMain.cpp index 12d1f885e7ed..094325c5d277 100644 --- a/ipc/app/MozillaRuntimeMain.cpp +++ b/ipc/app/MozillaRuntimeMain.cpp @@ -73,7 +73,6 @@ main(int argc, char* argv[]) // avoid it for unsupported plugins. See PluginProcessChild::Init for // the details. if (proctype != GeckoProcessType_Plugin) { - mozilla::SanitizeEnvironmentVariables(); mozilla::NS_SetDllDirectory(L""); } #endif diff --git a/toolkit/xre/Makefile.in b/toolkit/xre/Makefile.in index ba716573406d..7771a7ee048f 100644 --- a/toolkit/xre/Makefile.in +++ b/toolkit/xre/Makefile.in @@ -95,7 +95,6 @@ endif ifeq ($(MOZ_WIDGET_TOOLKIT),windows) CPPSRCS += nsNativeAppSupportWin.cpp -CPPSRCS += nsWindowsDllBlocklist.cpp DEFINES += -DWIN32_LEAN_AND_MEAN -DUNICODE -D_UNICODE EXPORTS = nsWindowsDllInterceptor.h else @@ -195,7 +194,6 @@ LOCAL_INCLUDES += \ -I$(topsrcdir)/dom/ipc \ -I$(topsrcdir)/toolkit/crashreporter \ -I$(topsrcdir)/dom/base \ - -I$(topsrcdir)/xpcom/build \ $(NULL) ifdef BUILD_STATIC_LIBS diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index f258c4b63093..5fae29c22ab4 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -251,7 +251,6 @@ static char **gQtOnlyArgv; #endif /* MOZ_X11 */ #include "nsGTKToolkit.h" #endif -#include "BinaryPath.h" // Save literal putenv string to environment variable. static void @@ -1446,10 +1445,141 @@ RemoteCommandLine(const char* aDesktopStartupID) } #endif // MOZ_ENABLE_XREMOTE +#ifdef XP_MACOSX +static char const *gBinaryPath; +#endif + nsresult XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult) { - return mozilla::BinaryPath::GetFile(argv0, aResult); + nsresult rv; + nsCOMPtr lf; + + // We need to use platform-specific hackery to find the + // path of this executable. This is copied, with some modifications, from + // nsGREDirServiceProvider.cpp + +#ifdef XP_WIN + PRUnichar exePath[MAXPATHLEN]; + + if (!::GetModuleFileNameW(0, exePath, MAXPATHLEN)) + return NS_ERROR_FAILURE; + + rv = NS_NewLocalFile(nsDependentString(exePath), PR_TRUE, + getter_AddRefs(lf)); + if (NS_FAILED(rv)) + return rv; + +#elif defined(XP_MACOSX) + if (gBinaryPath) + return NS_NewNativeLocalFile(nsDependentCString(gBinaryPath), PR_FALSE, + aResult); + + NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(lf)); + nsCOMPtr lfm (do_QueryInterface(lf)); + if (!lfm) + return NS_ERROR_FAILURE; + + // Works even if we're not bundled. + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (!appBundle) + return NS_ERROR_FAILURE; + + CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle); + if (!executableURL) + return NS_ERROR_FAILURE; + rv = lfm->InitWithCFURL(executableURL); + CFRelease(executableURL); + if (NS_FAILED(rv)) + return rv; + + // Callers expect a normalized path. + lfm->Normalize(); + +#elif defined(XP_UNIX) + struct stat fileStat; + char exePath[MAXPATHLEN]; + char tmpPath[MAXPATHLEN]; + + rv = NS_ERROR_FAILURE; + + // on unix, there is no official way to get the path of the current binary. + // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to + // multiple applications, we will try a series of techniques: + // + // 1) look for /proc//exe which is a symlink to the executable on newer + // Linux kernels + // 2) use realpath() on argv[0], which works unless we're loaded from the + // PATH + // 3) manually walk through the PATH and look for ourself + // 4) give up + +// #ifdef __linux__ +// Commented out because it used to not work because it used to not deal +// with readlink not null-terminating the buffer. +#if 0 + int r = readlink("/proc/self/exe", exePath, MAXPATHLEN); + + if (r > 0 && r < MAXPATHLEN) { + exePath[r] = '\0'; + if (stat(exePath, &fileStat) == 0) { + rv = NS_OK; + } + } + +#endif + if (NS_FAILED(rv) && + realpath(argv0, exePath) && stat(exePath, &fileStat) == 0) { + rv = NS_OK; + } + + if (NS_FAILED(rv)) { + const char *path = getenv("PATH"); + if (!path) + return NS_ERROR_FAILURE; + + char *pathdup = strdup(path); + if (!pathdup) + return NS_ERROR_OUT_OF_MEMORY; + + PRBool found = PR_FALSE; + char *newStr = pathdup; + char *token; + while ( (token = nsCRT::strtok(newStr, ":", &newStr)) ) { + sprintf(tmpPath, "%s/%s", token, argv0); + if (realpath(tmpPath, exePath) && stat(exePath, &fileStat) == 0) { + found = PR_TRUE; + break; + } + } + free(pathdup); + if (!found) + return NS_ERROR_FAILURE; + } + + rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE, + getter_AddRefs(lf)); + if (NS_FAILED(rv)) + return rv; + +#elif defined(XP_OS2) + PPIB ppib; + PTIB ptib; + char exePath[MAXPATHLEN]; + + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, exePath); + rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE, + getter_AddRefs(lf)); + if (NS_FAILED(rv)) + return rv; + +#else +#error Oops, you need platform-specific code here +#endif + + NS_ADDREF(*aResult = lf); + return NS_OK; } #define NS_ERROR_LAUNCHED_CHILD_PROCESS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_PROFILE, 200) @@ -2689,6 +2819,16 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) NS_ENSURE_TRUE(aAppData, 2); +#ifdef XP_MACOSX + // The xulrunner stub executable tricks CFBundleGetMainBundle on + // purpose into lying about the main bundle path. It will set + // XRE_BINARY_PATH to inform us of our real location. + gBinaryPath = getenv("XRE_BINARY_PATH"); + + if (gBinaryPath && !*gBinaryPath) + gBinaryPath = nsnull; +#endif + // Check for application.ini overrides const char* override = nsnull; ar = CheckArg("override", PR_TRUE, &override); @@ -3608,6 +3748,14 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", profLD); SaveWordToEnvIfUnset("XRE_PROFILE_NAME", profileName); +#ifdef XP_MACOSX + if (gBinaryPath) { + static char kEnvVar[MAXPATHLEN]; + sprintf(kEnvVar, "XRE_BINARY_PATH=%s", gBinaryPath); + PR_SetEnv(kEnvVar); + } +#endif + #ifdef MOZ_WIDGET_GTK2 MOZ_gdk_display_close(display); #endif diff --git a/toolkit/xre/nsWindowsDllBlocklist.cpp b/toolkit/xre/nsWindowsDllBlocklist.cpp index ceb906f21daf..5ea016c59b6a 100644 --- a/toolkit/xre/nsWindowsDllBlocklist.cpp +++ b/toolkit/xre/nsWindowsDllBlocklist.cpp @@ -40,12 +40,6 @@ #include -#ifdef XRE_WANT_DLL_BLOCKLIST -#define XRE_SetupDllBlocklist SetupDllBlocklist -#else -#include "nsXULAppAPI.h" -#endif - #include "nsAutoPtr.h" #include "prlog.h" @@ -214,7 +208,7 @@ continue_loading: WindowsDllInterceptor NtDllIntercept; void -XRE_SetupDllBlocklist() +SetupDllBlocklist() { NtDllIntercept.Init("ntdll.dll"); diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp index bdbf16aedabf..a1c0179a7977 100644 --- a/toolkit/xre/nsWindowsWMain.cpp +++ b/toolkit/xre/nsWindowsWMain.cpp @@ -76,7 +76,6 @@ FreeAllocStrings(int argc, char **argv) int wmain(int argc, WCHAR **argv) { #ifndef XRE_DONT_PROTECT_DLL_LOAD - mozilla::SanitizeEnvironmentVariables(); mozilla::NS_SetDllDirectory(L""); #endif diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in index cbd66f215c6e..a1aa1bc91d02 100644 --- a/xpcom/base/Makefile.in +++ b/xpcom/base/Makefile.in @@ -98,6 +98,7 @@ EXPORTS_mozilla = \ $(NULL) ifeq (windows,$(MOZ_WIDGET_TOOLKIT)) +CPPSRCS += nsSetDllDirectory.cpp CPPSRCS += nsCrashOnException.cpp endif diff --git a/xpcom/base/Telemetry.cpp b/xpcom/base/Telemetry.cpp index 1f1f4b858de3..eaf57d3a311f 100644 --- a/xpcom/base/Telemetry.cpp +++ b/xpcom/base/Telemetry.cpp @@ -47,7 +47,6 @@ #include "jsapi.h" #include "nsStringGlue.h" #include "nsITelemetry.h" -#include "nsXULAppAPI.h" namespace { @@ -150,10 +149,10 @@ WrapAndReturnHistogram(Histogram *h, JSContext *cx, jsval *ret) && JS_DefineFunction (cx, obj, "snapshot", JSHistogram_Snapshot, 1, 0)) ? NS_OK : NS_ERROR_FAILURE; } -static nsresult -HistogramGet(const char *name, PRUint32 min, PRUint32 max, PRUint32 bucket_count, - PRUint32 histogram_type, Histogram **aResult) +NS_IMETHODIMP +Telemetry::NewHistogram(const nsACString &name, PRUint32 min, PRUint32 max, PRUint32 bucket_count, PRUint32 histogram_type, JSContext *cx, jsval *ret) { + // Sanity checks on histogram parameters. if (min < 1) return NS_ERROR_ILLEGAL_VALUE; @@ -163,22 +162,12 @@ HistogramGet(const char *name, PRUint32 min, PRUint32 max, PRUint32 bucket_count if (bucket_count <= 2) return NS_ERROR_ILLEGAL_VALUE; - if (histogram_type == nsITelemetry::HISTOGRAM_EXPONENTIAL) { - *aResult = Histogram::FactoryGet(name, min, max, bucket_count, Histogram::kNoFlags); - } else { - *aResult = LinearHistogram::FactoryGet(name, min, max, bucket_count, Histogram::kNoFlags); - } - return NS_OK; -} - -NS_IMETHODIMP -Telemetry::NewHistogram(const nsACString &name, PRUint32 min, PRUint32 max, PRUint32 bucket_count, PRUint32 histogram_type, JSContext *cx, jsval *ret) -{ Histogram *h; - nsresult rv = HistogramGet(name.BeginReading(), min, max, bucket_count, histogram_type, &h); - if (NS_FAILED(rv)) - return rv; - // Sanity checks on histogram parameters. + if (histogram_type == nsITelemetry::HISTOGRAM_EXPONENTIAL) { + h = Histogram::FactoryGet(name.BeginReading(), min, max, bucket_count, Histogram::kNoFlags); + } else { + h = LinearHistogram::FactoryGet(name.BeginReading(), min, max, bucket_count, Histogram::kNoFlags); + } return WrapAndReturnHistogram(h, cx, ret); } @@ -253,19 +242,3 @@ const mozilla::Module kTelemetryModule = { } // anonymous namespace NSMODULE_DEFN(nsTelemetryModule) = &kTelemetryModule; - -/** - * The XRE_TelemetryAdd function is to be used by embedding applications - * that can't use histogram.h directly. - */ -nsresult -XRE_TelemetryAdd(const char *name, int sample, PRUint32 min, PRUint32 max, - PRUint32 bucket_count, HistogramTypes histogram_type) -{ - base::Histogram *h; - nsresult rv = HistogramGet(name, min, max, bucket_count, histogram_type, &h); - if (NS_FAILED(rv)) - return rv; - h->Add(sample); - return NS_OK; -} diff --git a/xpcom/base/nsITelemetry.idl b/xpcom/base/nsITelemetry.idl index 6ededf09ffc3..e9b7c0717ae4 100644 --- a/xpcom/base/nsITelemetry.idl +++ b/xpcom/base/nsITelemetry.idl @@ -45,9 +45,6 @@ interface nsITelemetry : nsISupports * Histogram types: * HISTOGRAM_EXPONENTIAL - buckets increase exponentially * HISTOGRAM_LINEAR - buckets increase linearly - * - * Please update the HistogramTypes enum in xpcom/build/nsXULAppAPI.h when - * adding/changing values. */ const unsigned long HISTOGRAM_EXPONENTIAL = 0; const unsigned long HISTOGRAM_LINEAR = 1; diff --git a/xpcom/base/nsSetDllDirectory.h b/xpcom/base/nsSetDllDirectory.h index b0e3b2a6e62b..f9d1fc975eff 100644 --- a/xpcom/base/nsSetDllDirectory.h +++ b/xpcom/base/nsSetDllDirectory.h @@ -43,48 +43,13 @@ #error This file only makes sense on Windows. #endif -#include #include -#include namespace mozilla { -static void SanitizeEnvironmentVariables() -{ - DWORD bufferSize = GetEnvironmentVariableW(L"PATH", NULL, 0); - if (bufferSize) { - wchar_t* originalPath = new wchar_t[bufferSize]; - if (bufferSize - 1 == GetEnvironmentVariableW(L"PATH", originalPath, bufferSize)) { - bufferSize = ExpandEnvironmentStringsW(originalPath, NULL, 0); - if (bufferSize) { - wchar_t* newPath = new wchar_t[bufferSize]; - if (ExpandEnvironmentStringsW(originalPath, - newPath, - bufferSize)) { - SetEnvironmentVariableW(L"PATH", newPath); - } - delete[] newPath; - } - } - delete[] originalPath; - } -} - // Sets the directory from which DLLs can be loaded if the SetDllDirectory OS // API is available. -// You must call SanitizeEnvironmentVariables before this function when calling -// it the first time. -static inline void NS_SetDllDirectory(const WCHAR *aDllDirectory) -{ - typedef BOOL - (WINAPI *pfnSetDllDirectory) (LPCWSTR); - pfnSetDllDirectory setDllDirectory = nsnull; - setDllDirectory = reinterpret_cast - (GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDllDirectoryW")); - if (setDllDirectory) { - setDllDirectory(aDllDirectory); - } -} +XPCOM_API(void) NS_SetDllDirectory(const WCHAR *aDllDirectory); } diff --git a/xpcom/build/BinaryPath.h b/xpcom/build/BinaryPath.h deleted file mode 100644 index ba1e58db9249..000000000000 --- a/xpcom/build/BinaryPath.h +++ /dev/null @@ -1,178 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code - * - * The Initial Developer of the Original Code is - * Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Mike Hommey - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef mozilla_BinaryPath_h -#define mozilla_BinaryPath_h - -#include "nsXPCOMPrivate.h" // for MAXPATHLEN -#include "prtypes.h" -#ifdef XP_WIN -#include -#elif defined(XP_MACOSX) -#include -#elif defined(XP_UNIX) -#include -#endif - -namespace mozilla { - -class BinaryPath { -public: -#ifdef XP_WIN - static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) - { - PRUnichar wide_path[MAXPATHLEN]; - nsresult rv = GetW(argv0, wide_path); - if (NS_FAILED(rv)) - return rv; - WideCharToMultiByte(CP_UTF8, 0, wide_path, -1, - aResult, MAXPATHLEN, NULL, NULL); - return NS_OK; - } - -private: - static nsresult GetW(const char *argv0, PRUnichar aResult[MAXPATHLEN]) - { - if (::GetModuleFileNameW(0, aResult, MAXPATHLEN)) - return NS_OK; - return NS_ERROR_FAILURE; - } - -#elif defined(XP_MACOSX) - static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) - { - // Works even if we're not bundled. - CFBundleRef appBundle = CFBundleGetMainBundle(); - if (!appBundle) - return NS_ERROR_FAILURE; - - CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle); - if (!executableURL) - return NS_ERROR_FAILURE; - - nsresult rv; - if (CFURLGetFileSystemRepresentation(executableURL, false, (UInt8 *)aResult, MAXPATHLEN)) - rv = NS_OK; - else - rv = NS_ERROR_FAILURE; - CFRelease(executableURL); - return rv; - } - -#elif defined(XP_UNIX) - static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) - { - struct stat fileStat; - // on unix, there is no official way to get the path of the current binary. - // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to - // multiple applications, we will try a series of techniques: - // - // 1) use realpath() on argv[0], which works unless we're loaded from the - // PATH - // 2) manually walk through the PATH and look for ourself - // 3) give up - if (realpath(argv0, aResult) && stat(aResult, &fileStat) == 0) - return NS_OK; - - const char *path = getenv("PATH"); - if (!path) - return NS_ERROR_FAILURE; - - char *pathdup = strdup(path); - if (!pathdup) - return NS_ERROR_OUT_OF_MEMORY; - - PRBool found = PR_FALSE; - char *token = strtok(pathdup, ":"); - while (token) { - char tmpPath[MAXPATHLEN]; - sprintf(tmpPath, "%s/%s", token, argv0); - if (realpath(tmpPath, aResult) && stat(aResult, &fileStat) == 0) { - found = PR_TRUE; - break; - } - token = strtok(NULL, ":"); - } - free(pathdup); - if (found) - return NS_OK; - return NS_ERROR_FAILURE; - } - -#elif defined(XP_OS2) - static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) - { - PPIB ppib; - PTIB ptib; - DosGetInfoBlocks( &ptib, &ppib); - DosQueryModuleName(ppib->pib_hmte, MAXPATHLEN, aResult); - } - -#else -#error Oops, you need platform-specific code here -#endif - -public: - static nsresult GetFile(const char *argv0, nsILocalFile* *aResult) - { - nsCOMPtr lf; -#ifdef XP_WIN - PRUnichar exePath[MAXPATHLEN]; - nsresult rv = GetW(argv0, exePath); -#else - char exePath[MAXPATHLEN]; - nsresult rv = Get(argv0, exePath); -#endif - if (NS_FAILED(rv)) - return rv; -#ifdef XP_WIN - rv = NS_NewLocalFile(nsDependentString(exePath), PR_TRUE, - getter_AddRefs(lf)); -#else - rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE, - getter_AddRefs(lf)); -#endif - if (NS_FAILED(rv)) - return rv; - NS_ADDREF(*aResult = lf); - return NS_OK; - } -}; - -} - -#endif /* mozilla_BinaryPath_h */ diff --git a/xpcom/build/dlldeps.cpp b/xpcom/build/dlldeps.cpp index 3a9ca50bc02b..b5c67b1f2a19 100644 --- a/xpcom/build/dlldeps.cpp +++ b/xpcom/build/dlldeps.cpp @@ -281,6 +281,7 @@ void XXXNeverCalled() sXPCOMHasLoadedNewDLLs = !sXPCOMHasLoadedNewDLLs; NS_SetHasLoadedNewDLLs(); NS_NewWindowsRegKey(nsnull); + NS_SetDllDirectory(nsnull); #if defined (DEBUG) PurePrintf(0); #endif diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h index 2041b7a29bbb..a59b04aae71c 100644 --- a/xpcom/build/nsXULAppAPI.h +++ b/xpcom/build/nsXULAppAPI.h @@ -562,24 +562,4 @@ XRE_API(bool, XRE_API(void, XRE_InstallX11ErrorHandler, ()) - -#if defined(_MSC_VER) && defined(_M_IX86) -#define XRE_HAS_DLL_BLOCKLIST -XRE_API(void, - XRE_SetupDllBlocklist, ()) -#endif - -enum HistogramTypes { - HISTOGRAM_EXPONENTIAL = 0, - HISTOGRAM_LINEAR = 1 -}; - -XRE_API(nsresult, - XRE_TelemetryAdd, (const char *name, - int sample, - PRUint32 min, - PRUint32 max, - PRUint32 bucket_count, - HistogramTypes histogram_type)) - #endif // _nsXULAppAPI_h__ diff --git a/xpcom/glue/standalone/nsGlueLinking.h b/xpcom/glue/standalone/nsGlueLinking.h index 86c909d9d099..39a19e33406d 100644 --- a/xpcom/glue/standalone/nsGlueLinking.h +++ b/xpcom/glue/standalone/nsGlueLinking.h @@ -48,7 +48,7 @@ XPCOMGlueLoad(const char *xpcomFile, GetFrozenFunctionsFunc *func NS_OUTPARAM); NS_HIDDEN_(void) XPCOMGlueUnload(); -typedef void (*DependentLibsCallback)(const char *aDependentLib, PRBool do_preload); +typedef void (*DependentLibsCallback)(const char *aDependentLib); NS_HIDDEN_(void) XPCOMGlueLoadDependentLibs(const char *xpcomDir, DependentLibsCallback cb); diff --git a/xpcom/glue/standalone/nsGlueLinkingDlopen.cpp b/xpcom/glue/standalone/nsGlueLinkingDlopen.cpp index 7d0bae626ab9..d16f0a81c04c 100644 --- a/xpcom/glue/standalone/nsGlueLinkingDlopen.cpp +++ b/xpcom/glue/standalone/nsGlueLinkingDlopen.cpp @@ -21,7 +21,6 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Mike Hommey * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -40,14 +39,6 @@ #include "nsGlueLinking.h" #include "nsXPCOMGlue.h" -#ifdef LINUX -#define _GNU_SOURCE -#include -#include -#include -#include -#endif - #include #include #include @@ -82,69 +73,9 @@ AppendDependentLib(void *libHandle) sTop = d; } -#ifdef LINUX -static const unsigned int bufsize = 4096; - -#ifdef HAVE_64BIT_OS -typedef Elf64_Ehdr Elf_Ehdr; -typedef Elf64_Phdr Elf_Phdr; -static const unsigned char ELFCLASS = ELFCLASS64; -typedef Elf64_Off Elf_Off; -#else -typedef Elf32_Ehdr Elf_Ehdr; -typedef Elf32_Phdr Elf_Phdr; -static const unsigned char ELFCLASS = ELFCLASS32; -typedef Elf32_Off Elf_Off; -#endif - static void -preload(const char *file) +ReadDependentCB(const char *aDependentLib) { - union { - char buf[bufsize]; - Elf_Ehdr ehdr; - } elf; - int fd = open(file, O_RDONLY); - if (fd < 0) - return; - // Read ELF header (ehdr) and program header table (phdr). - // We check that the ELF magic is found, that the ELF class matches - // our own, and that the program header table as defined in the ELF - // headers fits in the buffer we read. - if ((read(fd, elf.buf, bufsize) <= 0) || - (memcmp(elf.buf, ELFMAG, 4)) || - (elf.ehdr.e_ident[EI_CLASS] != ELFCLASS) || - (elf.ehdr.e_phoff + elf.ehdr.e_phentsize * elf.ehdr.e_phnum >= bufsize)) { - close(fd); - return; - } - // The program header table contains segment definitions. One such - // segment type is PT_LOAD, which describes how the dynamic loader - // is going to map the file in memory. We use that information to - // find the biggest offset from the library that will be mapped in - // memory. - Elf_Phdr *phdr = (Elf_Phdr *)&elf.buf[elf.ehdr.e_phoff]; - Elf_Off end = 0; - for (int phnum = elf.ehdr.e_phnum; phnum; phdr++, phnum--) - if ((phdr->p_type == PT_LOAD) && - (end < phdr->p_offset + phdr->p_filesz)) - end = phdr->p_offset + phdr->p_filesz; - // Let the kernel read ahead what the dynamic loader is going to - // map in memory soon after. - if (end > 0) { - readahead(fd, 0, end); - } - close(fd); -} -#endif - -static void -ReadDependentCB(const char *aDependentLib, PRBool do_preload) -{ -#ifdef LINUX - if (do_preload) - preload(aDependentLib); -#endif void *libHandle = dlopen(aDependentLib, RTLD_GLOBAL | RTLD_LAZY); if (!libHandle) return; diff --git a/xpcom/glue/standalone/nsGlueLinkingOS2.cpp b/xpcom/glue/standalone/nsGlueLinkingOS2.cpp index 68c371451ae0..6ee2e4c672d8 100644 --- a/xpcom/glue/standalone/nsGlueLinkingOS2.cpp +++ b/xpcom/glue/standalone/nsGlueLinkingOS2.cpp @@ -68,7 +68,7 @@ AppendDependentLib(HMODULE libHandle) } static void -ReadDependentCB(const char *aDependentLib, PRBool do_preload) +ReadDependentCB(const char *aDependentLib) { CHAR pszError[_MAX_PATH]; ULONG ulrc = NO_ERROR; diff --git a/xpcom/glue/standalone/nsGlueLinkingOSX.cpp b/xpcom/glue/standalone/nsGlueLinkingOSX.cpp index 24aa193c746a..34b10b64ce6d 100644 --- a/xpcom/glue/standalone/nsGlueLinkingOSX.cpp +++ b/xpcom/glue/standalone/nsGlueLinkingOSX.cpp @@ -21,7 +21,6 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Mike Hommey * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -46,131 +45,11 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__i386__) -static const uint32_t CPU_TYPE = CPU_TYPE_X86; -#elif defined(__x86_64__) -static const uint32_t CPU_TYPE = CPU_TYPE_X86_64; -#elif defined(__ppc__) -static const uint32_t CPU_TYPE = CPU_TYPE_POWERPC; -#elif defined(__ppc64__) -static const uint32_t CPU_TYPE = CPU_TYPE_POWERPC64; -#else -#error Unsupported CPU type -#endif - -#ifdef HAVE_64BIT_OS -#undef LC_SEGMENT -#define LC_SEGMENT LC_SEGMENT_64 -#undef MH_MAGIC -#define MH_MAGIC MH_MAGIC_64 -#define cpu_mach_header mach_header_64 -#define segment_command segment_command_64 -#else -#define cpu_mach_header mach_header -#endif - -class ScopedMMap -{ -public: - ScopedMMap(const char *file): buf(NULL) { - fd = open(file, O_RDONLY); - if (fd < 0) - return; - struct stat st; - if (fstat(fd, &st) < 0) - return; - size = st.st_size; - buf = (char *)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - } - ~ScopedMMap() { - if (buf) - munmap(buf, size); - if (fd >= 0) - close(fd); - } - operator char *() { return buf; } - int getFd() { return fd; } -private: - int fd; - char *buf; - size_t size; -}; - -static void -preload(const char *file) -{ - ScopedMMap buf(file); - char *base = buf; - if (!base) - return; - - // An OSX binary might either be a fat (universal) binary or a - // Mach-O binary. A fat binary actually embeds several Mach-O - // binaries. If we have a fat binary, find the offset where the - // Mach-O binary for our CPU type can be found. - struct fat_header *fh = (struct fat_header *)base; - - if (OSSwapBigToHostInt32(fh->magic) == FAT_MAGIC) { - uint32_t nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch); - struct fat_arch *arch = (struct fat_arch *)&buf[sizeof(struct fat_header)]; - for (; nfat_arch; arch++, nfat_arch--) { - if (OSSwapBigToHostInt32(arch->cputype) == CPU_TYPE) { - base += OSSwapBigToHostInt32(arch->offset); - break; - } - } - if (base == buf) - return; - } - - // Check Mach-O magic in the Mach header - struct cpu_mach_header *mh = (struct cpu_mach_header *)base; - if (mh->magic != MH_MAGIC) - return; - - // The Mach header is followed by a sequence of load commands. - // Each command has a header containing the command type and the - // command size. LD_SEGMENT commands describes how the dynamic - // loader is going to map the file in memory. We use that - // information to find the biggest offset from the library that - // will be mapped in memory. - char *cmd = &base[sizeof(struct cpu_mach_header)]; - off_t end = 0; - for (uint32_t ncmds = mh->ncmds; ncmds; ncmds--) { - struct segment_command *sh = (struct segment_command *)cmd; - if (sh->cmd != LC_SEGMENT) - continue; - if (end < sh->fileoff + sh->filesize) - end = sh->fileoff + sh->filesize; - cmd += sh->cmdsize; - } - // Let the kernel read ahead what the dynamic loader is going to - // map in memory soon after. The F_RDADVISE fcntl is equivalent - // to Linux' readahead() system call. - if (end > 0) { - struct radvisory ra; - ra.ra_offset = (base - buf); - ra.ra_count = end; - fcntl(buf.getFd(), F_RDADVISE, &ra); - } -} - static const mach_header* sXULLibImage; static void -ReadDependentCB(const char *aDependentLib, PRBool do_preload) +ReadDependentCB(const char *aDependentLib) { - if (do_preload) - preload(aDependentLib); (void) NSAddImage(aDependentLib, NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME); diff --git a/xpcom/glue/standalone/nsGlueLinkingWin.cpp b/xpcom/glue/standalone/nsGlueLinkingWin.cpp index adcb236a5d26..438b361abfbb 100644 --- a/xpcom/glue/standalone/nsGlueLinkingWin.cpp +++ b/xpcom/glue/standalone/nsGlueLinkingWin.cpp @@ -70,34 +70,11 @@ AppendDependentLib(HINSTANCE libHandle) } static void -preload(LPCWSTR dll) -{ - HANDLE fd = CreateFileW(dll, GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - char buf[64 * 1024]; - - if (fd == INVALID_HANDLE_VALUE) - return; - - DWORD dwBytesRead; - // Do dummy reads to trigger kernel-side readhead via FILE_FLAG_SEQUENTIAL_SCAN. - // Abort when underfilling because during testing the buffers are read fully - // A buffer that's not keeping up would imply that readahead isn't working right - while (ReadFile(fd, buf, sizeof(buf), &dwBytesRead, NULL) && dwBytesRead == sizeof(buf)) - /* Nothing */; - - CloseHandle(fd); -} - -static void -ReadDependentCB(const char *aDependentLib, PRBool do_preload) +ReadDependentCB(const char *aDependentLib) { wchar_t wideDependentLib[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, aDependentLib, -1, wideDependentLib, MAX_PATH); - if (do_preload) - preload(wideDependentLib); - HINSTANCE h = LoadLibraryExW(wideDependentLib, NULL, MOZ_LOADLIBRARY_FLAGS); diff --git a/xpcom/glue/standalone/nsXPCOMGlue.cpp b/xpcom/glue/standalone/nsXPCOMGlue.cpp index 2b9706a5e235..92263f0b6bbe 100644 --- a/xpcom/glue/standalone/nsXPCOMGlue.cpp +++ b/xpcom/glue/standalone/nsXPCOMGlue.cpp @@ -55,13 +55,6 @@ #endif static XPCOMFunctions xpcomFunctions; -static PRBool do_preload = PR_FALSE; - -extern "C" -void XPCOMGlueEnablePreload() -{ - do_preload = PR_TRUE; -} extern "C" nsresult XPCOMGlueStartup(const char* xpcomFile) @@ -135,7 +128,7 @@ XPCOMGlueLoadDependentLibs(const char *xpcomDir, DependentLibsCallback cb) snprintf(buffer2, sizeof(buffer2), "%s" XPCOM_FILE_PATH_SEPARATOR "%s", xpcomDir, buffer); - cb(buffer2, do_preload); + cb(buffer2); } fclose(flist); diff --git a/xpcom/glue/standalone/nsXPCOMGlue.h b/xpcom/glue/standalone/nsXPCOMGlue.h index 2d382ac567c5..e7232203e7a8 100644 --- a/xpcom/glue/standalone/nsXPCOMGlue.h +++ b/xpcom/glue/standalone/nsXPCOMGlue.h @@ -47,12 +47,6 @@ * The following functions are only available in the standalone glue. */ -/** - * Enabled preloading of dynamically loaded libraries - */ -extern "C" NS_HIDDEN_(void) -XPCOMGlueEnablePreload(); - /** * Initialize the XPCOM glue by dynamically linking against the XPCOM * shared library indicated by xpcomFile. diff --git a/xpinstall/packager/Packager.pm b/xpinstall/packager/Packager.pm index 1443610e8a3e..82ed35833426 100644 --- a/xpinstall/packager/Packager.pm +++ b/xpinstall/packager/Packager.pm @@ -317,13 +317,6 @@ sub do_copyfile } } unlink("$destpath$destname$destsuffix") if ( -e "$destpath$destname$destsuffix"); - # If source is a symbolic link pointing in the same directory, create a - # symbolic link - if ((-l "$srcpath$srcname$srcsuffix") && (readlink("$srcpath$srcname$srcsuffix") !~ /\//)) { - symlink(readlink("$srcpath$srcname$srcsuffix"), "$destpath$destname$destsuffix") || - die "Error: copy of symbolic link $srcpath$srcname$srcsuffix failed ($package, $component, $lineno): $!. Exiting...\n"; - return; - } copy ("$srcpath$srcname$srcsuffix", "$destpath$destname$destsuffix") || die "Error: copy of file $srcpath$srcname$srcsuffix failed ($package, $component, $lineno): $!. Exiting...\n"; From d8f57ea03cc78bd8e19bd8becbc0ca88a13ea37d Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sun, 22 May 2011 18:09:55 +0200 Subject: [PATCH 079/145] Add missing file after backout aa83abd4fd01 --- xpcom/base/nsSetDllDirectory.cpp | 91 ++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 xpcom/base/nsSetDllDirectory.cpp diff --git a/xpcom/base/nsSetDllDirectory.cpp b/xpcom/base/nsSetDllDirectory.cpp new file mode 100644 index 000000000000..c1a04f9c90dd --- /dev/null +++ b/xpcom/base/nsSetDllDirectory.cpp @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ehsan Akhgari (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef XP_WIN +#error This file only makes sense on Windows. +#endif + +#include +#include +#include "nsSetDllDirectory.h" + +void +SanitizeEnvironmentVariables() +{ + DWORD bufferSize = GetEnvironmentVariableW(L"PATH", NULL, 0); + if (bufferSize) { + wchar_t* originalPath = new wchar_t[bufferSize]; + if (bufferSize - 1 == GetEnvironmentVariableW(L"PATH", originalPath, bufferSize)) { + bufferSize = ExpandEnvironmentStringsW(originalPath, NULL, 0); + if (bufferSize) { + wchar_t* newPath = new wchar_t[bufferSize]; + if (ExpandEnvironmentStringsW(originalPath, + newPath, + bufferSize)) { + SetEnvironmentVariableW(L"PATH", newPath); + } + delete[] newPath; + } + } + delete[] originalPath; + } +} + +namespace mozilla { + +XPCOM_API(void) +NS_SetDllDirectory(const WCHAR *aDllDirectory) +{ + typedef BOOL + (WINAPI *pfnSetDllDirectory) (LPCWSTR); + static pfnSetDllDirectory setDllDirectory = nsnull; + if (!setDllDirectory) { + setDllDirectory = reinterpret_cast + (GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDllDirectoryW")); + + // If it's the first time we're running this function, sanitize the + // environment variables too. + SanitizeEnvironmentVariables(); + } + if (setDllDirectory) { + setDllDirectory(aDllDirectory); + } +} + +} + From d97ccb10219476a233e1affc8c99d2e9fada3023 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Fri, 20 May 2011 12:22:00 -0400 Subject: [PATCH 080/145] Bug 616999 - switch to a manifest format for xpcshell instead of walking directories. r=jhammel, a=test-only --- testing/xpcshell/xpcshell.ini | 3 +++ toolkit/crashreporter/client/maemo-unit/xpcshell.ini | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 toolkit/crashreporter/client/maemo-unit/xpcshell.ini diff --git a/testing/xpcshell/xpcshell.ini b/testing/xpcshell/xpcshell.ini index 0607b5f2bf23..716ef91249e9 100644 --- a/testing/xpcshell/xpcshell.ini +++ b/testing/xpcshell/xpcshell.ini @@ -81,6 +81,9 @@ run-if.toolkit = cocoa skip-if.os = linux run-if.config = mozcrashreporter +[include:toolkit/crashreporter/client/maemo-unit/xpcshell.ini] +run-if.os = maemo + [include:intl/locale/src/unix/tests/unit/xpcshell.ini] skip-if.toolkit = windows cocoa os2 diff --git a/toolkit/crashreporter/client/maemo-unit/xpcshell.ini b/toolkit/crashreporter/client/maemo-unit/xpcshell.ini new file mode 100644 index 000000000000..7abf38d402d2 --- /dev/null +++ b/toolkit/crashreporter/client/maemo-unit/xpcshell.ini @@ -0,0 +1,6 @@ +[DEFAULT] +head = +tail = + +[test_maemo_certs.js] + From 71e8152319bdb81995fe7af79b86a59168124a8d Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Sun, 22 May 2011 09:38:02 -0700 Subject: [PATCH 081/145] Bug 658093 - BuildFileList can potentially try to read a signature beyond the end of the zip file, r=taras --- modules/libjar/nsZipArchive.cpp | 9 +++---- .../libjar/test/unit/data/test_bug658093.zip | Bin 0 -> 4096 bytes modules/libjar/test/unit/test_bug658093.js | 23 ++++++++++++++++++ modules/libjar/test/unit/xpcshell.ini | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 modules/libjar/test/unit/data/test_bug658093.zip create mode 100644 modules/libjar/test/unit/test_bug658093.js diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index 2d3b22be3275..93c5ad75aede 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -618,10 +618,9 @@ MOZ_WIN_MEM_TRY_BEGIN //-- Read the central directory headers buf = startp + centralOffset; - if (endp - buf < PRInt32(sizeof(PRUint32))) - return NS_ERROR_FILE_CORRUPTED; - PRUint32 sig = xtolong(buf); - while (sig == CENTRALSIG) { + PRUint32 sig = 0; + while (buf + PRInt32(sizeof(PRUint32)) <= endp && + (sig = xtolong(buf)) == CENTRALSIG) { // Make sure there is enough data available. if (endp - buf < ZIPCENTRAL_SIZE) return NS_ERROR_FILE_CORRUPTED; @@ -654,7 +653,7 @@ MOZ_WIN_MEM_TRY_BEGIN item->next = mFiles[hash]; mFiles[hash] = item; - sig = xtolong(buf); + sig = 0; } /* while reading central directory records */ if (sig != ENDSIG) diff --git a/modules/libjar/test/unit/data/test_bug658093.zip b/modules/libjar/test/unit/data/test_bug658093.zip new file mode 100644 index 0000000000000000000000000000000000000000..d32180101aeb47b86a14e7f56d61811bae55a68e GIT binary patch literal 4096 zcmeIwF$#b%5CzdyavY1;d51JPj>k8JFf6gLOEGEu1OoDyh=|^{eSAJonQm*nPG3wc z<3cM`tOSd^tOO4$!6Gj!!NW?h$jeIbuo5itvJyP31dF_^1P?30A}=e!V}(i%e&=2H HkJH-&u>gm5 literal 0 HcmV?d00001 diff --git a/modules/libjar/test/unit/test_bug658093.js b/modules/libjar/test/unit/test_bug658093.js new file mode 100644 index 000000000000..66a3c6f69499 --- /dev/null +++ b/modules/libjar/test/unit/test_bug658093.js @@ -0,0 +1,23 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const Cc = Components.classes; +const Ci = Components.interfaces; + +// Check that we don't crash on reading a directory entry signature +var ios = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + +function run_test() { + var file = do_get_file("data/test_bug658093.zip"); + var spec = "jar:" + ios.newFileURI(file).spec + "!/0000"; + var channel = ios.newChannel(spec, null, null); + var failed = false; + try { + var stream = channel.open(); + } catch (e) { + failed = true; + } + do_check_true(failed); +} diff --git a/modules/libjar/test/unit/xpcshell.ini b/modules/libjar/test/unit/xpcshell.ini index e2587507eeb7..bc053912916a 100644 --- a/modules/libjar/test/unit/xpcshell.ini +++ b/modules/libjar/test/unit/xpcshell.ini @@ -12,6 +12,7 @@ tail = [test_bug458158.js] [test_bug597702.js] [test_bug637286.js] +[test_bug658093.js] [test_corrupt_536911.js] [test_corrupt_541828.js] [test_dirjar_bug525755.js] From 493bddf3daa41db692b2aef7f43958f801edec75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Sun, 22 May 2011 19:07:23 +0200 Subject: [PATCH 082/145] Bug 658852 - When a page is loading, the status panel should appear immediately rather than being faded in (affects page load time). r=gavin --- browser/base/content/browser.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index bda8505d3265..b661aa228b47 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -462,7 +462,6 @@ statuspanel { margin-top: -3em; left: 0; max-width: 50%; - -moz-transition: opacity 100ms ease-out; } statuspanel:-moz-locale-dir(ltr)[mirror], @@ -482,6 +481,7 @@ statuspanel[type=status] { } statuspanel[type=overLink] { + -moz-transition: opacity 100ms ease-out; direction: ltr; } From 06e7bea554bf037f680165e3f8c821e45b76e855 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 19 May 2011 11:56:14 +1200 Subject: [PATCH 083/145] b=657041 initialize with NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY for when InheritAutomaticData does not get called r=fred --HG-- extra : transplant_source : %E3%07S3%ABv%EC%B67%5C%25%29CH%12%99%8C%B43P --- layout/mathml/crashtests/crashtests.list | 2 +- layout/mathml/nsMathMLmfencedFrame.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/layout/mathml/crashtests/crashtests.list b/layout/mathml/crashtests/crashtests.list index 80dd564a3467..7c41a8162841 100644 --- a/layout/mathml/crashtests/crashtests.list +++ b/layout/mathml/crashtests/crashtests.list @@ -32,7 +32,7 @@ load 375562-1.xhtml load 377824-1.xhtml load 379418-1.xhtml load 385226-1.xhtml -asserts(2-3) load 393760-1.xhtml # Bug 541620 +load 393760-1.xhtml load 397518-1.xhtml load 400475-1.xhtml load 402400-1.xhtml diff --git a/layout/mathml/nsMathMLmfencedFrame.cpp b/layout/mathml/nsMathMLmfencedFrame.cpp index 887a782aa73e..4cb730fca643 100644 --- a/layout/mathml/nsMathMLmfencedFrame.cpp +++ b/layout/mathml/nsMathMLmfencedFrame.cpp @@ -88,6 +88,10 @@ nsMathMLmfencedFrame::SetInitialChildList(nsIAtom* aListName, nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListName, aChildList); if (NS_FAILED(rv)) return rv; + // InheritAutomaticData will not get called if our parent is not a mathml + // frame, so initialize NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY for + // GetPreferredStretchSize() from Reflow(). + mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY; // No need to track the style contexts given to our MathML chars. // The Style System will use Get/SetAdditionalStyleContext() to keep them // up-to-date if dynamic changes arise. @@ -310,8 +314,6 @@ nsMathMLmfencedFrame::Reflow(nsPresContext* aPresContext, nsBoundingMetrics containerSize; nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL; - nsPresentationData presentationData; - GetPresentationData(presentationData); GetPreferredStretchSize(*aReflowState.rendContext, 0, /* i.e., without embellishments */ stretchDir, containerSize); From 7d1750ae3429007a361ca32c941769a6d64b881b Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Tue, 17 May 2011 14:57:31 +1200 Subject: [PATCH 084/145] normal line height test b=657864 --HG-- extra : transplant_source : w%E7B%EF%D1%A7%8C%9A%98%C2%0Ce%C1N%BB%08nrC2 --- layout/reftests/fonts/mark-generate.py | 31 +++++++++++++++++- .../reftests/fonts/markA-lineheight1500.ttf | Bin 0 -> 1768 bytes .../text/lineheight-metrics-1-ref.html | 17 ++++++++++ .../reftests/text/lineheight-metrics-1.html | 31 ++++++++++++++++++ layout/reftests/text/reftest.list | 1 + 5 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 layout/reftests/fonts/markA-lineheight1500.ttf create mode 100644 layout/reftests/text/lineheight-metrics-1-ref.html create mode 100644 layout/reftests/text/lineheight-metrics-1.html diff --git a/layout/reftests/fonts/mark-generate.py b/layout/reftests/fonts/mark-generate.py index 9acac173d654..2ee01fd95d59 100755 --- a/layout/reftests/fonts/mark-generate.py +++ b/layout/reftests/fonts/mark-generate.py @@ -89,7 +89,9 @@ for codepoint in range(ord("A"), ord("A") + 1): f.generate("mark" + mark + charname + "-" + uposname + "underline.ttf") - + +# font with a ligature involving a space + f = fontforge.font() n = "MarkAB-spaceliga" f.fontname = n @@ -113,3 +115,30 @@ g.importOutlines("mark2-glyph.svg") g.width = 1800 f.generate("markAB-spaceliga.otf") + +# font with a known line-height (which is greater than winascent + windescent). + +f = fontforge.font() +lineheight = 1500 +n = "MarkA-lineheight" + str(lineheight) +f.fontname = n +f.familyname = n +f.fullname = n +f.copyright = "Copyright (c) 2008-2011 Mozilla Corporation" + +g = f.createChar(ord(" "), "space") +g.width = 1000 +g = f.createChar(ord("A"), "A") +g.importOutlines("mark-glyph.svg") +g.width = 1500 + +f.os2_typoascent_add = False +f.os2_typoascent = 800 +f.os2_typodescent_add = False +f.os2_typodescent = -200 +f.os2_use_typo_metrics = True +f.os2_typolinegap = lineheight - (f.os2_typoascent - f.os2_typodescent) +# glyph height is 800 (hhea ascender - descender) +f.hhea_linegap = lineheight - 800 + +f.generate("markA-lineheight" + str(lineheight) + ".ttf") diff --git a/layout/reftests/fonts/markA-lineheight1500.ttf b/layout/reftests/fonts/markA-lineheight1500.ttf new file mode 100644 index 0000000000000000000000000000000000000000..52bbd00862ecf0d4074e8347910a96d46bfc407b GIT binary patch literal 1768 zcmdT^&1(}u6#va`c3ZVpixCtGZm??oXxxoPf>f|nau9;zNAV(dN!KKpX2UjUt0;nc zP{gy8{sn?UOAj7;kXERIM~@!-I`mQyNul7!`kTobwTK9woMAG*_nY_LzW3&3AONhz zb?7*r&7R7gy)xJim@mk79y_@=wej?ZZGbpKc`!fhR&mLkrOb12G=H&XA)$={`X-*o z3hqcX4Cx8xQ_8J{^4R&-Jw^xUE42m3b@zv4PjB(eIVagDy>l)H+!Hsn6%u^)6wJzCZ@gmzOKeJrPbAquLDRR%nvtpp7;YPG~cRj1$JF@+9H+VJOBx zo6MF&S_;J-Mp7}c*jrJD!J|9M``yMaUc(X8)?hX)rLv6k*YN}v`gAMIh&ru@co^v@ zUlxQYBOy&hj@dISMk=+WPq{iH{Uem5WhY{gcVKcC{5ZYyrqI~Kci~*5PfD20k3mM- ztO}tT^!Fq5@8pU-wnF~@MAg^W70oQGkYHVQY2!@31<6T)y}eT{F)XGgP2*MXl&%qC zQkS$L>8Tb|eD0lM2^UlQIuac__H}Gch*b;o^V;~A^9hY@s$(eXKIwA}{ihQfo2xGB zUykTEKTR8PQGfRA>&wPcrEJHe=8f%U$Ma4&1maCzLp$C?ybfEOh;R&X@i4*$){FNM zHWAmh$Zm#)Gc$ml%;(@5AxTgb%}`o-+sS37L*Fbn$?}(X{BsC z)046t$IAJaOXad__4`5958PVGr*e*#0WP4AUn1s)^unh`ljt4NS@gA08<Ek*M;Ps+7ZbPTrl&3Ikp+!a7^F?Idm6Ci9O4Z@xO=4R*%w c247ZouEtL5l8CQa;|-?p{I>5%lb_%DZ|T1d00000 literal 0 HcmV?d00001 diff --git a/layout/reftests/text/lineheight-metrics-1-ref.html b/layout/reftests/text/lineheight-metrics-1-ref.html new file mode 100644 index 000000000000..756b705329bb --- /dev/null +++ b/layout/reftests/text/lineheight-metrics-1-ref.html @@ -0,0 +1,17 @@ +Reference, bug 643781 + + +
+ diff --git a/layout/reftests/text/lineheight-metrics-1.html b/layout/reftests/text/lineheight-metrics-1.html new file mode 100644 index 000000000000..76f448241248 --- /dev/null +++ b/layout/reftests/text/lineheight-metrics-1.html @@ -0,0 +1,31 @@ +Testcase, bug 643781 + + +
A
+ diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index de97a3f4deff..f2553d497a1f 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -21,6 +21,7 @@ load ligature-with-space-1.html == line-editing-1c.html line-editing-1-ref.html == line-editing-1d.html line-editing-1-ref.html == line-editing-1e.html line-editing-1-ref.html +fails-if(cocoaWidget||winWidget) HTTP(..) == lineheight-metrics-1.html lineheight-metrics-1-ref.html # bug 657864 == long-1.html long-ref.html == pre-line-1.html pre-line-1-ref.html == pre-line-2.html pre-line-2-ref.html From 80eeae35bf126ef64d5f7fc08aa73ccb4cbdaad9 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Wed, 18 May 2011 11:45:27 -0700 Subject: [PATCH 085/145] Bug 657665 - Add documentation comments to ArgumentsObject detailing its structure, and add ArgumentsObject::getElement{,s} to abstract attempting to speedily get the value of one or more elements. r=bhackett --- js/src/jsapi-tests/Makefile.in | 1 + js/src/jsapi-tests/testArgumentsObject.cpp | 109 +++++++++++++++++++ js/src/jsarray.cpp | 48 +-------- js/src/vm/ArgumentsObject.h | 78 ++++++++++++-- js/src/vm/Stack-inl.h | 117 ++++++++++++++++++--- js/src/vm/Stack.h | 3 +- 6 files changed, 290 insertions(+), 66 deletions(-) create mode 100644 js/src/jsapi-tests/testArgumentsObject.cpp diff --git a/js/src/jsapi-tests/Makefile.in b/js/src/jsapi-tests/Makefile.in index fba0f72056f2..05071a5fd344 100644 --- a/js/src/jsapi-tests/Makefile.in +++ b/js/src/jsapi-tests/Makefile.in @@ -49,6 +49,7 @@ PROGRAM = jsapi-tests$(BIN_SUFFIX) CPPSRCS = \ tests.cpp \ selfTest.cpp \ + testArgumentsObject.cpp \ testBug604087.cpp \ testClassGetter.cpp \ testCloneScript.cpp \ diff --git a/js/src/jsapi-tests/testArgumentsObject.cpp b/js/src/jsapi-tests/testArgumentsObject.cpp new file mode 100644 index 000000000000..39f54b642614 --- /dev/null +++ b/js/src/jsapi-tests/testArgumentsObject.cpp @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +#include "jscntxt.h" +#include "jstracer.h" +#include "vm/Stack-inl.h" + +using namespace js; + +static const char NORMAL_ZERO[] = + "function f() { return arguments; }"; +static const char NORMAL_ONE[] = + "function f(a) { return arguments; }"; +static const char NORMAL_TWO[] = + "function f(a, b) { return arguments; }"; +static const char NORMAL_THREE[] = + "function f(a, b, c) { return arguments; }"; + +static const char STRICT_ZERO[] = + "function f() { 'use strict'; return arguments; }"; +static const char STRICT_ONE[] = + "function f() { 'use strict'; return arguments; }"; +static const char STRICT_TWO[] = + "function f() { 'use strict'; return arguments; }"; +static const char STRICT_THREE[] = + "function f() { 'use strict'; return arguments; }"; + +static const char *CALL_CODES[] = + { "f()", "f(0)", "f(0, 1)", "f(0, 1, 2)", "f(0, 1, 2, 3)", "f(0, 1, 2, 3, 4)" }; + +static const size_t MAX_ELEMS = 6; + +static void +ClearElements(Value elems[MAX_ELEMS]) +{ + for (size_t i = 0; i < MAX_ELEMS - 1; i++) + elems[i] = NullValue(); + elems[MAX_ELEMS - 1] = Int32Value(42); +} + +BEGIN_TEST(testArgumentsObject) +{ + return ExhaustiveTest<0>(NORMAL_ZERO) && + ExhaustiveTest<1>(NORMAL_ZERO) && + ExhaustiveTest<2>(NORMAL_ZERO) && + ExhaustiveTest<0>(NORMAL_ONE) && + ExhaustiveTest<1>(NORMAL_ONE) && + ExhaustiveTest<2>(NORMAL_ONE) && + ExhaustiveTest<3>(NORMAL_ONE) && + ExhaustiveTest<0>(NORMAL_TWO) && + ExhaustiveTest<1>(NORMAL_TWO) && + ExhaustiveTest<2>(NORMAL_TWO) && + ExhaustiveTest<3>(NORMAL_TWO) && + ExhaustiveTest<4>(NORMAL_TWO) && + ExhaustiveTest<0>(NORMAL_THREE) && + ExhaustiveTest<1>(NORMAL_THREE) && + ExhaustiveTest<2>(NORMAL_THREE) && + ExhaustiveTest<3>(NORMAL_THREE) && + ExhaustiveTest<4>(NORMAL_THREE) && + ExhaustiveTest<5>(NORMAL_THREE) && + ExhaustiveTest<0>(STRICT_ZERO) && + ExhaustiveTest<1>(STRICT_ZERO) && + ExhaustiveTest<2>(STRICT_ZERO) && + ExhaustiveTest<0>(STRICT_ONE) && + ExhaustiveTest<1>(STRICT_ONE) && + ExhaustiveTest<2>(STRICT_ONE) && + ExhaustiveTest<3>(STRICT_ONE) && + ExhaustiveTest<0>(STRICT_TWO) && + ExhaustiveTest<1>(STRICT_TWO) && + ExhaustiveTest<2>(STRICT_TWO) && + ExhaustiveTest<3>(STRICT_TWO) && + ExhaustiveTest<4>(STRICT_TWO) && + ExhaustiveTest<0>(STRICT_THREE) && + ExhaustiveTest<1>(STRICT_THREE) && + ExhaustiveTest<2>(STRICT_THREE) && + ExhaustiveTest<3>(STRICT_THREE) && + ExhaustiveTest<4>(STRICT_THREE) && + ExhaustiveTest<5>(STRICT_THREE); +} + +template bool +ExhaustiveTest(const char funcode[]) +{ + jsval v; + EVAL(funcode, &v); + + EVAL(CALL_CODES[ArgCount], &v); + ArgumentsObject *argsobj = JSVAL_TO_OBJECT(v)->asArguments(); + + Value elems[MAX_ELEMS]; + + for (size_t i = 0; i <= ArgCount; i++) { + for (size_t j = 0; j <= ArgCount - i; j++) { + ClearElements(elems); + CHECK(argsobj->getElements(i, j, elems)); + for (size_t k = 0; k < j; k++) + CHECK_SAME(Jsvalify(elems[k]), INT_TO_JSVAL(i + k)); + for (size_t k = j; k < MAX_ELEMS - 1; k++) + CHECK_SAME(Jsvalify(elems[k]), JSVAL_NULL); + CHECK_SAME(Jsvalify(elems[MAX_ELEMS - 1]), INT_TO_JSVAL(42)); + } + } + + return true; +} +END_TEST(testArgumentsObject) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 34f861f6f12f..bde955377d19 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -357,16 +357,9 @@ GetElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, Value *vp return JS_TRUE; } if (obj->isArguments()) { - ArgumentsObject *argsobj = obj->asArguments(); - if (index < argsobj->initialLength() && - !(*vp = argsobj->element(uint32(index))).isMagic(JS_ARGS_HOLE)) { + if (obj->asArguments()->getElement(uint32(index), vp)) { *hole = JS_FALSE; - StackFrame *fp = reinterpret_cast(argsobj->getPrivate()); - if (fp != JS_ARGUMENTS_OBJECT_ON_TRACE) { - if (fp) - *vp = fp->canonicalActualArg(index); - return JS_TRUE; - } + return true; } } @@ -397,19 +390,6 @@ GetElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, Value *vp namespace js { -struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo -{ - CopyNonHoleArgsTo(ArgumentsObject *argsobj, Value *dst) : argsobj(argsobj), dst(dst) {} - ArgumentsObject *argsobj; - Value *dst; - bool operator()(uintN argi, Value *src) { - if (argsobj->element(argi).isMagic(JS_ARGS_HOLE)) - return false; - *dst++ = *src; - return true; - } -}; - static bool GetElementsSlow(JSContext *cx, JSObject *aobj, uint32 length, Value *vp) { @@ -436,29 +416,9 @@ GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp) if (aobj->isArguments()) { ArgumentsObject *argsobj = aobj->asArguments(); - if (!argsobj->hasOverriddenLength() && !js_PrototypeHasIndexedProperties(cx, argsobj)) { - /* - * If the argsobj is for an active call, then the elements are the - * live args on the stack. Otherwise, the elements are the args that - * were copied into the argsobj by PutActivationObjects when the - * function returned. In both cases, it is necessary to fall off the - * fast path for deleted properties (MagicValue(JS_ARGS_HOLE) since - * this requires general-purpose property lookup. - */ - if (StackFrame *fp = reinterpret_cast(argsobj->getPrivate())) { - JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX); - if (fp->forEachCanonicalActualArg(CopyNonHoleArgsTo(argsobj, vp))) - return true; - } else { - Value *srcbeg = argsobj->elements(); - Value *srcend = srcbeg + length; - for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src) { - if (src->isMagic(JS_ARGS_HOLE)) - return GetElementsSlow(cx, argsobj, length, vp); - *dst = *src; - } + if (!argsobj->hasOverriddenLength()) { + if (argsobj->getElements(0, length, vp)) return true; - } } } diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index bc6256e7b113..2c61037c1301 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -80,6 +80,13 @@ class Writer; struct EmptyShape; +/* + * ArgumentsData stores the initial indexed arguments provided to the + * corresponding and that function itself. It is used to store arguments[i] + * and arguments.callee -- up until the corresponding property is modified, + * when the relevant value is overwritten with MagicValue(JS_ARGS_HOLE) to + * memorialize the modification. + */ struct ArgumentsData { /* @@ -95,16 +102,52 @@ struct ArgumentsData js::Value slots[1]; }; +/* + * ArgumentsObject instances represent |arguments| objects created to store + * function arguments when a function is called. It's expensive to create such + * objects if they're never used, so they're only created lazily. (See + * js::StackFrame::setArgsObj and friends.) + * + * Arguments objects are complicated because, for non-strict mode code, they + * must alias any named arguments which were provided to the function. Gnarly + * example: + * + * function f(a, b, c, d) + * { + * arguments[0] = "seta"; + * assertEq(a, "seta"); + * b = "setb"; + * assertEq(arguments[1], "setb"); + * c = "setc"; + * assertEq(arguments[2], undefined); + * arguments[3] = "setd"; + * assertEq(d, undefined); + * } + * f("arga", "argb"); + * + * ES5's strict mode behaves more sanely, and named arguments don't alias + * elements of an arguments object. + * + * ArgumentsObject instances use the following reserved slots: + * + * INITIAL_LENGTH_SLOT + * Stores the initial value of arguments.length, plus a bit indicating + * whether arguments.length has been modified. Use initialLength() and + * hasOverriddenLength() to access these values. If arguments.length has + * been modified, then the current value of arguments.length is stored in + * another slot associated with a new property. + * DATA_SLOT + * Stores an ArgumentsData* storing argument values and the callee, or + * sentinels for any of these if the corresponding property is modified. + * Use callee() to access the callee/sentinel, and use + * element/addressOfElement/setElement to access the values stored in + * the ArgumentsData. If you're simply looking to get arguments[i], + * however, use getElement or getElements to avoid spreading arguments + * object implementation details around too much. + */ class ArgumentsObject : public ::JSObject { - /* - * Stores the initial arguments length, plus a flag indicating whether - * arguments.length has been overwritten. Use initialLength() to access the - * initial arguments length. - */ static const uint32 INITIAL_LENGTH_SLOT = 0; - - /* Stores an ArgumentsData for these arguments; access with data(). */ static const uint32 DATA_SLOT = 1; protected: @@ -158,6 +201,27 @@ class ArgumentsObject : public ::JSObject inline bool hasOverriddenLength() const; inline void markLengthOverridden(); + /* + * Attempt to speedily and efficiently access the i-th element of this + * arguments object. Return true if the element was speedily returned. + * Return false if the element must be looked up more slowly using + * getProperty or some similar method. + * + * NB: Returning false does not indicate error! + */ + inline bool getElement(uint32 i, js::Value *vp); + + /* + * Attempt to speedily and efficiently get elements [start, start + count) + * of this arguments object into the locations starting at |vp|. Return + * true if all elements were copied. Return false if the elements must be + * gotten more slowly, perhaps using a getProperty or some similar method + * in a loop. + * + * NB: Returning false does not indicate error! + */ + inline bool getElements(uint32 start, uint32 count, js::Value *vp); + inline js::ArgumentsData *data() const; inline const js::Value &element(uint32 i) const; diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 01dc26abd451..774876f3d361 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -516,29 +516,35 @@ StackFrame::canonicalActualArg(uintN i) const template inline bool -StackFrame::forEachCanonicalActualArg(Op op) +StackFrame::forEachCanonicalActualArg(Op op, uintN start /* = 0 */, uintN count /* = uintN(-1) */) { uintN nformal = fun()->nargs; + JS_ASSERT(start <= nformal); + Value *formals = formalArgsEnd() - nformal; uintN nactual = numActualArgs(); - if (nactual <= nformal) { - uintN i = 0; - Value *actualsEnd = formals + nactual; - for (Value *p = formals; p != actualsEnd; ++p, ++i) { - if (!op(i, p)) + if (count == uintN(-1)) + count = nactual - start; + + uintN end = start + count; + JS_ASSERT(end >= start); + JS_ASSERT(end <= nactual); + + if (end <= nformal) { + Value *p = formals + start; + for (; start < end; ++p, ++start) { + if (!op(start, p)) return false; } } else { - uintN i = 0; - Value *formalsEnd = formalArgsEnd(); - for (Value *p = formals; p != formalsEnd; ++p, ++i) { - if (!op(i, p)) + for (Value *p = formals + start; start < nformal; ++p, ++start) { + if (!op(start, p)) return false; } - Value *actuals = formalsEnd - (nactual + 2); - Value *actualsEnd = formals - 2; - for (Value *p = actuals; p != actualsEnd; ++p, ++i) { - if (!op(i, p)) + JS_ASSERT(start >= nformal); + Value *actuals = formals - (nactual + 2) + start; + for (Value *p = actuals; start < end; ++p, ++start) { + if (!op(start, p)) return false; } } @@ -1080,6 +1086,89 @@ FrameRegsIter::operator++() return *this; } +namespace detail { + +struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo +{ + CopyNonHoleArgsTo(ArgumentsObject *argsobj, Value *dst) : argsobj(*argsobj), dst(dst) {} + ArgumentsObject &argsobj; + Value *dst; + bool operator()(uint32 argi, Value *src) { + if (argsobj.element(argi).isMagic(JS_ARGS_HOLE)) + return false; + *dst++ = *src; + return true; + } +}; + +} /* namespace detail */ + +inline bool +ArgumentsObject::getElement(uint32 i, Value *vp) +{ + if (i >= initialLength()) + return false; + + *vp = element(i); + + /* + * If the argument was overwritten, it could be in any object slot, so we + * can't optimize. + */ + if (vp->isMagic(JS_ARGS_HOLE)) + return false; + + /* + * If this arguments object was created on trace the actual argument value + * could be in a register or something, so we can't optimize. + */ + StackFrame *fp = reinterpret_cast(getPrivate()); + if (fp == JS_ARGUMENTS_OBJECT_ON_TRACE) + return false; + + /* + * If this arguments object has an associated stack frame, that contains + * the canonical argument value. Note that strict arguments objects do not + * alias named arguments and never have a stack frame. + */ + JS_ASSERT_IF(isStrictArguments(), !fp); + if (fp) + *vp = fp->canonicalActualArg(i); + return true; +} + +inline bool +ArgumentsObject::getElements(uint32 start, uint32 count, Value *vp) +{ + JS_ASSERT(start + count >= start); + + uint32 length = initialLength(); + if (start > length || start + count > length) + return false; + + StackFrame *fp = reinterpret_cast(getPrivate()); + + /* If there's no stack frame for this, argument values are in elements(). */ + if (!fp) { + Value *srcbeg = elements() + start; + Value *srcend = srcbeg + count; + for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src) { + if (src->isMagic(JS_ARGS_HOLE)) + return false; + *dst = *src; + } + return true; + } + + /* If we're on trace, there's no canonical location for elements: fail. */ + if (fp == JS_ARGUMENTS_OBJECT_ON_TRACE) + return false; + + /* Otherwise, element values are on the stack. */ + JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX); + return fp->forEachCanonicalActualArg(detail::CopyNonHoleArgsTo(this, vp), start, count); +} + } /* namespace js */ #endif /* Stack_inl_h__ */ diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 05d2df12e2fa..9bc750fe308e 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -540,7 +540,8 @@ class StackFrame inline js::Value *actualArgsEnd() const; inline js::Value &canonicalActualArg(uintN i) const; - template inline bool forEachCanonicalActualArg(Op op); + template + inline bool forEachCanonicalActualArg(Op op, uintN start = 0, uintN count = uintN(-1)); template inline bool forEachFormalArg(Op op); inline void clearMissingArgs(); From d9c40bb751847eb80ec692beb90fed0539eac4c4 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Mon, 23 May 2011 11:04:22 +1200 Subject: [PATCH 086/145] Bug 606855 - Re-enable checking of GLX extensions. r=bjacob --- gfx/thebes/GLContextProviderGLX.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfx/thebes/GLContextProviderGLX.cpp b/gfx/thebes/GLContextProviderGLX.cpp index f56cbda77cf7..8ecc337899b2 100644 --- a/gfx/thebes/GLContextProviderGLX.cpp +++ b/gfx/thebes/GLContextProviderGLX.cpp @@ -199,6 +199,8 @@ GLXLibrary::EnsureInitialized() // Not possible to query for extensions. return PR_FALSE; + extensionsStr = xQueryExtensionsString(display, screen); + LibrarySymbolLoader::SymLoadStruct *sym13; if (!GLXVersionCheck(1, 3)) { // Even if we don't have 1.3, we might have equivalent extensions From 39175f5e4f9630b5a5a6c35bbcb46aa59bbc8ef7 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Mon, 23 May 2011 11:05:25 +1200 Subject: [PATCH 087/145] Bug 594876 - Turn on OpenGL layer by default for linux. r=joe --- widget/src/xpwidgets/nsBaseWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index 395c658bd8fa..288630c8e7df 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -782,7 +782,7 @@ nsBaseWidget::GetShouldAccelerate() PRBool disableAcceleration = PR_FALSE; PRBool forceAcceleration = PR_FALSE; -#if defined(XP_WIN) || defined(ANDROID) || (MOZ_PLATFORM_MAEMO > 5) +#if defined(XP_WIN) || defined(ANDROID) || (MOZ_PLATFORM_MAEMO > 5) || (!defined(MOZ_PLATFORM_MAEMO) && defined(MOZ_X11)) PRBool accelerateByDefault = PR_TRUE; #elif defined(XP_MACOSX) /* quickdraw plugins don't work with OpenGL so we need to avoid OpenGL when we want to support From 9a85c0e88f073c9d0c8e925e8c47b9407b465df9 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Mon, 23 May 2011 12:18:46 +1200 Subject: [PATCH 088/145] Backed out changeset f9a070327df8. r=orange --- widget/src/xpwidgets/nsBaseWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index 288630c8e7df..395c658bd8fa 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -782,7 +782,7 @@ nsBaseWidget::GetShouldAccelerate() PRBool disableAcceleration = PR_FALSE; PRBool forceAcceleration = PR_FALSE; -#if defined(XP_WIN) || defined(ANDROID) || (MOZ_PLATFORM_MAEMO > 5) || (!defined(MOZ_PLATFORM_MAEMO) && defined(MOZ_X11)) +#if defined(XP_WIN) || defined(ANDROID) || (MOZ_PLATFORM_MAEMO > 5) PRBool accelerateByDefault = PR_TRUE; #elif defined(XP_MACOSX) /* quickdraw plugins don't work with OpenGL so we need to avoid OpenGL when we want to support From b4cb13cbef3b4c46401334a44474486e1b3531d1 Mon Sep 17 00:00:00 2001 From: Justin Dolske Date: Sun, 22 May 2011 18:46:33 -0700 Subject: [PATCH 089/145] Bug 545070 - plugin-problem UI shouldn't say "click here". r=gavin --- browser/base/content/browser.js | 82 +++++++++++-------- .../test/browser_pluginnotification.js | 7 +- browser/base/content/test/plugin_test.html | 2 +- .../en-US/chrome/mozapps/plugins/plugins.dtd | 10 ++- .../chrome/mozapps/plugins/plugins.properties | 2 - .../mozapps/plugins/content/pluginProblem.xml | 13 ++- .../plugins/content/pluginProblemContent.css | 9 +- toolkit/themes/pinstripe/mozapps/jar.mn | 1 + .../mozapps/plugins/pluginProblem.css | 3 + toolkit/themes/winstripe/mozapps/jar.mn | 2 + .../mozapps/plugins/pluginProblem.css | 3 + 11 files changed, 85 insertions(+), 49 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 9281c70d70d0..5d71bf8170ee 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1385,7 +1385,7 @@ function prepareForStartup() { gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true); #ifdef XP_MACOSX gBrowser.addEventListener("npapi-carbon-event-model-failure", gPluginHandler, true); -#endif +#endif Services.obs.addObserver(gPluginHandler.pluginCrashed, "plugin-crashed", false); @@ -6698,12 +6698,15 @@ var gPluginHandler = { handleEvent : function(event) { let self = gPluginHandler; let plugin = event.target; - let hideBarPrefName; + let doc = plugin.ownerDocument; // We're expecting the target to be a plugin. if (!(plugin instanceof Ci.nsIObjectLoadingContent)) return; + // Force a style flush, so that we ensure our binding is attached. + plugin.clientTop; + switch (event.type) { case "PluginCrashed": self.pluginInstanceCrashed(plugin, event); @@ -6713,32 +6716,38 @@ var gPluginHandler = { // For non-object plugin tags, register a click handler to install the // plugin. Object tags can, and often do, deal with that themselves, // so don't stomp on the page developers toes. - if (!(plugin instanceof HTMLObjectElement)) - self.addLinkClickCallback(plugin, "installSinglePlugin"); + if (!(plugin instanceof HTMLObjectElement)) { + // We don't yet check to see if there's actually an installer available. + let installStatus = doc.getAnonymousElementByAttribute(plugin, "class", "installStatus"); + installStatus.setAttribute("status", "ready"); + let iconStatus = doc.getAnonymousElementByAttribute(plugin, "class", "icon"); + iconStatus.setAttribute("status", "ready"); + + let installLink = doc.getAnonymousElementByAttribute(plugin, "class", "installPluginLink"); + self.addLinkClickCallback(installLink, "installSinglePlugin", plugin); + } /* FALLTHRU */ + case "PluginBlocklisted": case "PluginOutdated": - hideBarPrefName = event.type == "PluginOutdated" ? - "plugins.hide_infobar_for_outdated_plugin" : - "plugins.hide_infobar_for_missing_plugin"; - if (gPrefService.getBoolPref(hideBarPrefName)) - return; - - self.pluginUnavailable(plugin, event.type); - break; #ifdef XP_MACOSX case "npapi-carbon-event-model-failure": - hideBarPrefName = "plugins.hide_infobar_for_carbon_failure_plugin"; - if (gPrefService.getBoolPref(hideBarPrefName)) - return; - +#endif self.pluginUnavailable(plugin, event.type); break; -#endif + case "PluginDisabled": - self.addLinkClickCallback(plugin, "managePlugins"); + let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink"); + self.addLinkClickCallback(manageLink, "managePlugins"); break; } + + // Hide the in-content UI if it's too big. The crashed plugin handler already did this. + if (event.type != "PluginCrashed") { + let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); + if (self.isTooSmall(plugin, overlay)) + overlay.style.visibility = "hidden"; + } }, newPluginInstalled : function(event) { @@ -6757,10 +6766,10 @@ var gPluginHandler = { }, // Callback for user clicking on a missing (unsupported) plugin. - installSinglePlugin: function (aEvent) { + installSinglePlugin: function (plugin) { var missingPluginsArray = {}; - var pluginInfo = getPluginInfo(aEvent.target); + var pluginInfo = getPluginInfo(plugin); missingPluginsArray[pluginInfo.mimetype] = pluginInfo; openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", @@ -6810,9 +6819,6 @@ var gPluginHandler = { let blockedNotification = notificationBox.getNotificationWithValue("blocked-plugins"); let missingNotification = notificationBox.getNotificationWithValue("missing-plugins"); - // If there is already an outdated plugin notification then do nothing - if (outdatedNotification) - return; function showBlocklistInfo() { var url = formatURL("extensions.blocklist.detailsURL", true); @@ -6844,7 +6850,7 @@ var gPluginHandler = { let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]. createInstance(Ci.nsISupportsPRBool); Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null); - + // Something aborted the quit process. if (cancelQuit.data) return; @@ -6908,10 +6914,17 @@ var gPluginHandler = { } #endif }; + + // If there is already an outdated plugin notification then do nothing + if (outdatedNotification) + return; + #ifdef XP_MACOSX if (eventType == "npapi-carbon-event-model-failure") { + if (gPrefService.getBoolPref("plugins.hide_infobar_for_carbon_failure_plugin")) + return; - let carbonFailureNotification = + let carbonFailureNotification = notificationBox.getNotificationWithValue("carbon-failure-plugins"); if (carbonFailureNotification) @@ -6923,11 +6936,18 @@ var gPluginHandler = { eventType = "PluginNotFound"; } #endif + if (eventType == "PluginBlocklisted") { + if (gPrefService.getBoolPref("plugins.hide_infobar_for_missing_plugin")) // XXX add a new pref? + return; + if (blockedNotification || missingNotification) return; } else if (eventType == "PluginOutdated") { + if (gPrefService.getBoolPref("plugins.hide_infobar_for_outdated_plugin")) + return; + // Cancel any notification about blocklisting/missing plugins if (blockedNotification) blockedNotification.close(); @@ -6935,6 +6955,9 @@ var gPluginHandler = { missingNotification.close(); } else if (eventType == "PluginNotFound") { + if (gPrefService.getBoolPref("plugins.hide_infobar_for_missing_plugin")) + return; + if (missingNotification) return; @@ -6990,9 +7013,6 @@ var gPluginHandler = { // Remap the plugin name to a more user-presentable form. pluginName = this.makeNicePluginName(pluginName, pluginFilename); - // Force a style flush, so that we ensure our binding is attached. - plugin.clientTop; - let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]); // @@ -7000,12 +7020,6 @@ var gPluginHandler = { // let doc = plugin.ownerDocument; let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); - - // The binding has role="link" here, since missing/disabled/blocked - // plugin UI has a onclick handler on the whole thing. This isn't needed - // for the plugin-crashed UI, because we use actual HTML links in the text. - overlay.removeAttribute("role"); - let statusDiv = doc.getAnonymousElementByAttribute(plugin, "class", "submitStatus"); #ifdef MOZ_CRASHREPORTER let status; diff --git a/browser/base/content/test/browser_pluginnotification.js b/browser/base/content/test/browser_pluginnotification.js index 6ba6a3bc97a0..d22a221e8155 100644 --- a/browser/base/content/test/browser_pluginnotification.js +++ b/browser/base/content/test/browser_pluginnotification.js @@ -127,7 +127,12 @@ function test3() { new TabOpenListener("about:addons", test4, prepareTest5); - EventUtils.synthesizeMouse(gTestBrowser.contentDocument.getElementById("test"), + var pluginNode = gTestBrowser.contentDocument.getElementById("test"); + ok(pluginNode, "Test 3, Found plugin in page"); + var manageLink = gTestBrowser.contentDocument.getAnonymousElementByAttribute(pluginNode, "class", "managePluginsLink"); + ok(manageLink, "Test 3, found 'manage' link in plugin-problem binding"); + + EventUtils.synthesizeMouse(manageLink, 5, 5, {}, gTestBrowser.contentWindow); } diff --git a/browser/base/content/test/plugin_test.html b/browser/base/content/test/plugin_test.html index 1a7a185eaf6f..204a79854aab 100644 --- a/browser/base/content/test/plugin_test.html +++ b/browser/base/content/test/plugin_test.html @@ -1,5 +1,5 @@ - + diff --git a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd index e86c18e60f98..5290fe815709 100644 --- a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd +++ b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd @@ -19,10 +19,14 @@ - - - + + + + + + + diff --git a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.properties b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.properties index deb7265898dc..764ff44d7154 100644 --- a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.properties +++ b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.properties @@ -24,5 +24,3 @@ pluginInstallation.restart.label=Restart %S pluginInstallation.restart.accesskey=R pluginInstallation.close.label=Close pluginInstallation.close.accesskey=C - -missingPlugin.label=Click here to download plugin. diff --git a/toolkit/mozapps/plugins/content/pluginProblem.xml b/toolkit/mozapps/plugins/content/pluginProblem.xml index 51123681b343..c54f895a8ced 100644 --- a/toolkit/mozapps/plugins/content/pluginProblem.xml +++ b/toolkit/mozapps/plugins/content/pluginProblem.xml @@ -54,15 +54,20 @@ - + - &missingPlugin.label; - &disabledPlugin.label; + &missingPlugin; + &disabledPlugin; &blockedPlugin.label; + + + &installPlugin; + + &managePlugins; - + &report.please; &report.submitting; &report.submitted; diff --git a/toolkit/mozapps/plugins/content/pluginProblemContent.css b/toolkit/mozapps/plugins/content/pluginProblemContent.css index b1b1d6e460f8..66d1cfb6e69f 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemContent.css +++ b/toolkit/mozapps/plugins/content/pluginProblemContent.css @@ -12,10 +12,6 @@ html|applet:not([height]), html|applet[height=""] { height: 200px; } -:-moz-type-unsupported .mainBox { - cursor: pointer; -} - :-moz-type-unsupported .mainBox, :-moz-handler-disabled .mainBox, :-moz-handler-blocked .mainBox { @@ -45,11 +41,16 @@ html|applet:not([height]), html|applet[height=""] { :-moz-type-unsupported .msgUnsupported, :-moz-handler-disabled .msgDisabled, +:-moz-handler-disabled .msgManagePlugins, :-moz-handler-blocked .msgBlocked, :-moz-handler-crashed .msgCrashed { display: block; } +.installStatus[status="ready"] .msgInstallPlugin { + display: block; +} + .submitStatus[status="noReport"] .msgNoCrashReport, .submitStatus[status="please"] .msgPleaseSubmit, .submitStatus[status="noSubmit"] .msgNotSubmitted, diff --git a/toolkit/themes/pinstripe/mozapps/jar.mn b/toolkit/themes/pinstripe/mozapps/jar.mn index 0d8155d2a9b5..e9117c36a364 100644 --- a/toolkit/themes/pinstripe/mozapps/jar.mn +++ b/toolkit/themes/pinstripe/mozapps/jar.mn @@ -50,6 +50,7 @@ toolkit.jar: skin/classic/mozapps/plugins/contentPluginCrashed.png (plugins/contentPluginCrashed.png) skin/classic/mozapps/plugins/contentPluginDisabled.png (plugins/contentPluginDisabled.png) skin/classic/mozapps/plugins/contentPluginDownload.png (plugins/contentPluginDownload.png) + skin/classic/mozapps/plugins/contentPluginMissing.png (plugins/contentPluginMissing.png) skin/classic/mozapps/plugins/notifyPluginBlocked.png (plugins/notifyPluginGeneric.png) skin/classic/mozapps/plugins/notifyPluginCrashed.png (plugins/notifyPluginGeneric.png) skin/classic/mozapps/plugins/notifyPluginGeneric.png (plugins/notifyPluginGeneric.png) diff --git a/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css b/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css index 735bb061c877..4b3855d2fd35 100644 --- a/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css +++ b/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css @@ -29,6 +29,9 @@ html|a { background-repeat: no-repeat; } :-moz-type-unsupported .icon { + background-image: url(chrome://mozapps/skin/plugins/contentPluginMissing.png); +} +:-moz-type-unsupported .icon[status="ready"] { background-image: url(chrome://mozapps/skin/plugins/contentPluginDownload.png); } :-moz-handler-disabled .icon { diff --git a/toolkit/themes/winstripe/mozapps/jar.mn b/toolkit/themes/winstripe/mozapps/jar.mn index 2baeb285dfce..3b089acfdea9 100644 --- a/toolkit/themes/winstripe/mozapps/jar.mn +++ b/toolkit/themes/winstripe/mozapps/jar.mn @@ -55,6 +55,7 @@ toolkit.jar: skin/classic/mozapps/plugins/contentPluginCrashed.png (plugins/contentPluginCrashed.png) skin/classic/mozapps/plugins/contentPluginDisabled.png (plugins/contentPluginDisabled.png) skin/classic/mozapps/plugins/contentPluginDownload.png (plugins/contentPluginDownload.png) + skin/classic/mozapps/plugins/contentPluginMissing.png (plugins/contentPluginMissing.png) skin/classic/mozapps/plugins/notifyPluginBlocked.png (plugins/pluginBlocked-16.png) skin/classic/mozapps/plugins/notifyPluginCrashed.png (plugins/pluginGeneric-16.png) skin/classic/mozapps/plugins/notifyPluginGeneric.png (plugins/pluginGeneric-16.png) @@ -130,6 +131,7 @@ toolkit.jar: skin/classic/aero/mozapps/plugins/contentPluginCrashed.png (plugins/contentPluginCrashed.png) skin/classic/aero/mozapps/plugins/contentPluginDisabled.png (plugins/contentPluginDisabled.png) skin/classic/aero/mozapps/plugins/contentPluginDownload.png (plugins/contentPluginDownload.png) + skin/classic/aero/mozapps/plugins/contentPluginMissing.png (plugins/contentPluginMissing.png) skin/classic/aero/mozapps/plugins/notifyPluginBlocked.png (plugins/pluginBlocked-16-aero.png) skin/classic/aero/mozapps/plugins/notifyPluginCrashed.png (plugins/pluginGeneric-16-aero.png) skin/classic/aero/mozapps/plugins/notifyPluginGeneric.png (plugins/pluginGeneric-16-aero.png) diff --git a/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css b/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css index 735bb061c877..4b3855d2fd35 100644 --- a/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css +++ b/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css @@ -29,6 +29,9 @@ html|a { background-repeat: no-repeat; } :-moz-type-unsupported .icon { + background-image: url(chrome://mozapps/skin/plugins/contentPluginMissing.png); +} +:-moz-type-unsupported .icon[status="ready"] { background-image: url(chrome://mozapps/skin/plugins/contentPluginDownload.png); } :-moz-handler-disabled .icon { From d9307f3ae9fc9074acddb13f1402c8f3691b1a5e Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sun, 22 May 2011 18:50:12 -0700 Subject: [PATCH 090/145] =?UTF-8?q?Fix=20--disable-tracejit=20bustage,=20m?= =?UTF-8?q?ake=20some=20headers=20#include=20some=20files=20they=20need,?= =?UTF-8?q?=20add=20a=20forward=20declaration=20to=20produce=20the=20same?= =?UTF-8?q?=20effect=20in=20another.=20=20r=3D=C2=ACt-redness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/src/jsapi-tests/testArgumentsObject.cpp | 2 -- js/src/vm/Stack-inl.h | 5 +++++ js/src/vm/Stack.h | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/js/src/jsapi-tests/testArgumentsObject.cpp b/js/src/jsapi-tests/testArgumentsObject.cpp index 39f54b642614..46a13bc45756 100644 --- a/js/src/jsapi-tests/testArgumentsObject.cpp +++ b/js/src/jsapi-tests/testArgumentsObject.cpp @@ -4,8 +4,6 @@ #include "tests.h" -#include "jscntxt.h" -#include "jstracer.h" #include "vm/Stack-inl.h" using namespace js; diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 774876f3d361..740aacb99339 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -41,6 +41,9 @@ #ifndef Stack_inl_h__ #define Stack_inl_h__ +#include "jscntxt.h" +#include "jstracer.h" + #include "Stack.h" #include "ArgumentsObject-inl.h" @@ -738,6 +741,7 @@ StackSpace::activeFirstUnused() const return max; } +#ifdef JS_TRACER JS_ALWAYS_INLINE bool StackSpace::ensureEnoughSpaceToEnterTrace() { @@ -749,6 +753,7 @@ StackSpace::ensureEnoughSpaceToEnterTrace() return end_ - firstUnused() > needed; #endif } +#endif STATIC_POSTCONDITION(!return || ubound(from) >= nvals) JS_ALWAYS_INLINE bool diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 9bc750fe308e..cb08b78a42f9 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -43,6 +43,8 @@ #include "jsfun.h" +struct JSContext; + namespace js { class StackFrame; @@ -1082,6 +1084,7 @@ class StackSpace */ JSObject &varObjForFrame(const StackFrame *fp); +#ifdef JS_TRACER /* * LeaveTree requires stack allocation to rebuild the stack. There is no * good way to handle an OOM for these allocations, so this function checks @@ -1089,6 +1092,7 @@ class StackSpace * conservative upper bound. */ inline bool ensureEnoughSpaceToEnterTrace(); +#endif /* * If we let infinite recursion go until it hit the end of the contiguous From 1f12055bcae72755282881c5a1a62feceb31b86e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 22 May 2011 19:48:31 -0700 Subject: [PATCH 091/145] Bug 656520 - Make sure the gc-heap memory reporter is in the right place. r=gwagner. --- js/src/xpconnect/src/xpcjsruntime.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index 848de7064e80..0818a7211b39 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -1279,7 +1279,11 @@ protected: static XPConnectGCChunkAllocator gXPCJSChunkAllocator; NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap, +#ifdef MOZ_MEMORY "heap-used/js/gc-heap", +#else + "mapped/js/gc-heap", +#endif "Memory used by the garbage-collected JavaScript " "heap.", XPConnectGCChunkAllocator::GetGCChunkBytesInUse, From e942f8f50a2eff949cfc2325557104015728880d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 22 May 2011 19:49:56 -0700 Subject: [PATCH 092/145] Bug 657327 - about:memory: merge the "mapped" and "heap used" trees, and make the resulting tree flatter. r=sdwilsh,Jesse, sr=roc. --- .../canvas/src/nsCanvasRenderingContext2D.cpp | 17 +- dom/ipc/ContentChild.cpp | 3 + dom/ipc/ContentParent.cpp | 2 + dom/ipc/PMemoryReportRequest.ipdl | 1 + gfx/thebes/gfxASurface.cpp | 57 ++-- gfx/thebes/gfxWindowsPlatform.cpp | 10 + ipc/glue/SharedMemory.cpp | 21 +- js/src/xpconnect/src/xpcjsruntime.cpp | 69 ++-- layout/base/nsPresShell.cpp | 19 +- modules/libpr0n/src/imgLoader.cpp | 22 +- storage/src/mozStorageConnection.cpp | 11 +- storage/src/mozStorageService.cpp | 9 +- .../aboutmemory/content/aboutMemory.css | 5 + .../aboutmemory/content/aboutMemory.js | 309 ++++++++++++------ .../tests/chrome/test_aboutmemory.xul | 251 +++++++------- xpcom/base/nsIMemoryReporter.idl | 62 ++-- xpcom/base/nsMemoryReporterManager.cpp | 175 +++++----- xpcom/base/nsMemoryReporterManager.h | 2 + 18 files changed, 608 insertions(+), 437 deletions(-) diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp index 47503f98ebf7..245d51d934c1 100644 --- a/content/canvas/src/nsCanvasRenderingContext2D.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp @@ -172,15 +172,16 @@ static PRInt64 GetCanvasMemoryUsed(void *) { return gCanvasMemoryUsed; } -// This isn't "heap-used/content/canvas/2d-pixel-bytes" because the pixels of a -// canvas may not be stored on the heap. And if they are, they will be tracked -// by the underlying surface implementations. See bug 655638 for details. +// This is MR_OTHER because it's not always clear where in memory the pixels of +// a canvas are stored. Furthermore, this memory will be tracked by the +// underlying surface implementations. See bug 655638 for details. NS_MEMORY_REPORTER_IMPLEMENT(CanvasMemory, - "canvas-2d-pixel-bytes", - "Memory used by 2D canvases. Each canvas " - "requires (width * height * 4) bytes.", - GetCanvasMemoryUsed, - NULL) + "canvas-2d-pixel-bytes", + MR_OTHER, + "Memory used by 2D canvases. Each canvas requires (width * height * 4) " + "bytes.", + GetCanvasMemoryUsed, + NULL) static void CopyContext(gfxContext* dest, gfxContext* src) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 23808b809604..ba61c2ec47e3 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -313,9 +313,11 @@ ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* chi r->GetNext(getter_AddRefs(report)); nsCString path; + PRInt32 kind; nsCString desc; PRInt64 memoryUsed; report->GetPath(getter_Copies(path)); + report->GetKind(&kind); report->GetDescription(getter_Copies(desc)); report->GetMemoryUsed(&memoryUsed); @@ -323,6 +325,7 @@ ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* chi MemoryReport memreport(nsPrintfCString(maxLength, "Content (%d)", getpid()), path, + kind, desc, memoryUsed); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 0281012a00eb..2eab028f7a68 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -692,11 +692,13 @@ ContentParent::SetChildMemoryReporters(const InfallibleTArray& rep nsCString prefix = report[i].prefix(); nsCString path = report[i].path(); + PRInt32 kind = report[i].kind(); nsCString desc = report[i].desc(); PRInt64 memoryUsed = report[i].memoryUsed(); nsRefPtr r = new nsMemoryReporter(prefix, path, + kind, desc, memoryUsed); mMemoryReporters.AppendObject(r); diff --git a/dom/ipc/PMemoryReportRequest.ipdl b/dom/ipc/PMemoryReportRequest.ipdl index e4da42612f51..935b452b5570 100644 --- a/dom/ipc/PMemoryReportRequest.ipdl +++ b/dom/ipc/PMemoryReportRequest.ipdl @@ -44,6 +44,7 @@ namespace dom { struct MemoryReport { nsCString prefix; nsCString path; + PRInt32 kind; nsCString desc; PRInt64 memoryUsed; }; diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index fe169e64e35e..2f3d5bbfce18 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -543,30 +543,30 @@ gfxASurface::MovePixels(const nsIntRect& aSourceRect, /** Memory reporting **/ static const char *sSurfaceNamesForSurfaceType[] = { - "heap-used/gfx/surface/image", - "heap-used/gfx/surface/pdf", - "heap-used/gfx/surface/ps", - "heap-used/gfx/surface/xlib", - "heap-used/gfx/surface/xcb", - "heap-used/gfx/surface/glitz", - "heap-used/gfx/surface/quartz", - "heap-used/gfx/surface/win32", - "heap-used/gfx/surface/beos", - "heap-used/gfx/surface/directfb", - "heap-used/gfx/surface/svg", - "heap-used/gfx/surface/os2", - "heap-used/gfx/surface/win32printing", - "heap-used/gfx/surface/quartzimage", - "heap-used/gfx/surface/script", - "heap-used/gfx/surface/qpainter", - "heap-used/gfx/surface/recording", - "heap-used/gfx/surface/vg", - "heap-used/gfx/surface/gl", - "heap-used/gfx/surface/drm", - "heap-used/gfx/surface/tee", - "heap-used/gfx/surface/xml", - "heap-used/gfx/surface/skia", - "heap-used/gfx/surface/d2d" + "explicit/gfx/surface/image", + "explicit/gfx/surface/pdf", + "explicit/gfx/surface/ps", + "explicit/gfx/surface/xlib", + "explicit/gfx/surface/xcb", + "explicit/gfx/surface/glitz", + "explicit/gfx/surface/quartz", + "explicit/gfx/surface/win32", + "explicit/gfx/surface/beos", + "explicit/gfx/surface/directfb", + "explicit/gfx/surface/svg", + "explicit/gfx/surface/os2", + "explicit/gfx/surface/win32printing", + "explicit/gfx/surface/quartzimage", + "explicit/gfx/surface/script", + "explicit/gfx/surface/qpainter", + "explicit/gfx/surface/recording", + "explicit/gfx/surface/vg", + "explicit/gfx/surface/gl", + "explicit/gfx/surface/drm", + "explicit/gfx/surface/tee", + "explicit/gfx/surface/xml", + "explicit/gfx/surface/skia", + "explicit/gfx/surface/d2d" }; PR_STATIC_ASSERT(NS_ARRAY_LENGTH(sSurfaceNamesForSurfaceType) == gfxASurface::SurfaceTypeMax); @@ -580,7 +580,7 @@ SurfaceMemoryReporterPathForType(gfxASurface::gfxSurfaceType aType) { if (aType < 0 || aType >= gfxASurface::SurfaceTypeMax) - return "heap-used/gfx/surface/unknown"; + return "explicit/gfx/surface/unknown"; return sSurfaceNamesForSurfaceType[aType]; } @@ -604,8 +604,13 @@ public: return NS_OK; } + NS_IMETHOD GetKind(PRInt32 *kind) { + *kind = MR_HEAP; + return NS_OK; + } + NS_IMETHOD GetDescription(char **desc) { - *desc = strdup("Memory used by gfx surface of given type."); + *desc = strdup("Memory used by gfx surface of the given type."); return NS_OK; } diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index c898fd332fca..476eafc3b58e 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -100,6 +100,11 @@ public: return NS_OK; } + NS_IMETHOD GetKind(PRInt32 *kind) { + *kind = MR_OTHER; + return NS_OK; + } + NS_IMETHOD GetDescription(char **desc) { *desc = strdup("Memory used by the Direct2D internal surface cache."); return NS_OK; @@ -127,6 +132,11 @@ public: return NS_OK; } + NS_IMETHOD GetKind(PRInt32 *kind) { + *kind = MR_OTHER; + return NS_OK; + } + NS_IMETHOD GetDescription(char **desc) { *desc = strdup("Video memory used by D2D surfaces"); return NS_OK; diff --git a/ipc/glue/SharedMemory.cpp b/ipc/glue/SharedMemory.cpp index a28520b1eb28..70cc10fd0dd3 100644 --- a/ipc/glue/SharedMemory.cpp +++ b/ipc/glue/SharedMemory.cpp @@ -52,17 +52,18 @@ static PRInt64 GetShmemAllocated(void*) { return gShmemAllocated; } static PRInt64 GetShmemMapped(void*) { return gShmemMapped; } NS_MEMORY_REPORTER_IMPLEMENT(ShmemAllocated, - "shmem-allocated", - "Memory shared with other processes that is " - "accessible (but not necessarily mapped).", - GetShmemAllocated, - nsnull) + "shmem-allocated", + MR_OTHER, + "Memory shared with other processes that is accessible (but not " + "necessarily mapped).", + GetShmemAllocated, + nsnull) NS_MEMORY_REPORTER_IMPLEMENT(ShmemMapped, - "shmem-mapped", - "Memory shared with other processes that is " - "mapped into the address space.", - GetShmemMapped, - nsnull) + "shmem-mapped", + MR_OTHER, + "Memory shared with other processes that is mapped into the address space.", + GetShmemMapped, + nsnull) SharedMemory::SharedMemory() : mAllocSize(0) diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index 0818a7211b39..ff271a68dbf6 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -1278,16 +1278,18 @@ protected: static XPConnectGCChunkAllocator gXPCJSChunkAllocator; -NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap, #ifdef MOZ_MEMORY - "heap-used/js/gc-heap", +#define JS_GC_HEAP_KIND MR_HEAP #else - "mapped/js/gc-heap", +#define JS_GC_HEAP_KIND MR_MAPPED #endif - "Memory used by the garbage-collected JavaScript " - "heap.", - XPConnectGCChunkAllocator::GetGCChunkBytesInUse, - &gXPCJSChunkAllocator) + +NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap, + "explicit/js/gc-heap", + JS_GC_HEAP_KIND, + "Memory used by the garbage-collected JavaScript heap.", + XPConnectGCChunkAllocator::GetGCChunkBytesInUse, + &gXPCJSChunkAllocator) static PRInt64 GetPerCompartmentSize(PRInt64 (*f)(JSCompartment *c)) @@ -1322,19 +1324,19 @@ GetJSMJitData(void *data) } NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSMjitCode, - "mapped/js/mjit-code", - "Memory mapped by the method JIT to hold " - "generated code.", - GetJSMjitCode, - NULL) + "explicit/js/mjit-code", + MR_MAPPED, + "Memory used by the method JIT to hold generated code.", + GetJSMjitCode, + NULL) NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSMjitData, - "heap-used/js/mjit-data", - "Memory allocated by the method JIT for the " - "following data: JITScripts, native maps, and " - "inline cache structs.", - GetJSMJitData, - NULL) + "explicit/js/mjit-data", + MR_HEAP, + "Memory used by the method JIT for the following data: " + "JITScripts, native maps, and inline cache structs.", + GetJSMJitData, + NULL) #endif // JS_METHODJIT #ifdef JS_TRACER @@ -1384,25 +1386,26 @@ GetJSTjitDataAllocatorsReserve(void *data) } NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSTjitCode, - "mapped/js/tjit-code", - "Memory mapped by the trace JIT to hold " - "generated code.", - GetJSTjitCode, - NULL) + "explicit/js/tjit-code", + MR_MAPPED, + "Memory used by the trace JIT to hold generated code.", + GetJSTjitCode, + NULL) NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSTjitDataAllocatorsMain, - "heap-used/js/tjit-data/allocators/main", - "Memory allocated by the trace JIT's " - "VMAllocators.", - GetJSTjitDataAllocatorsMain, - NULL) + "explicit/js/tjit-data/allocators-main", + MR_HEAP, + "Memory used by the trace JIT's VMAllocators.", + GetJSTjitDataAllocatorsMain, + NULL) NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSTjitDataAllocatorsReserve, - "heap-used/js/tjit-data/allocators/reserve", - "Memory allocated by the trace JIT and held in " - "reserve for VMAllocators in case of OOM.", - GetJSTjitDataAllocatorsReserve, - NULL) + "explicit/js/tjit-data/allocators-reserve", + MR_HEAP, + "Memory used by the trace JIT and held in reserve for VMAllocators " + "in case of OOM.", + GetJSTjitDataAllocatorsReserve, + NULL) #endif // JS_TRACER XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index cf5f1c835c51..0d2421c3772c 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1676,17 +1676,18 @@ NS_NewPresShell(nsIPresShell** aInstancePtrResult) nsTHashtable *nsIPresShell::sLiveShells = 0; NS_MEMORY_REPORTER_IMPLEMENT(LayoutPresShell, - "heap-used/layout/all", - "Memory used by layout PresShell, PresContext, " - "and other related areas.", - PresShell::SizeOfLayoutMemoryReporter, - nsnull) + "explicit/layout/all", + MR_HEAP, + "Memory used by layout PresShell, PresContext, and other related areas.", + PresShell::SizeOfLayoutMemoryReporter, + nsnull) NS_MEMORY_REPORTER_IMPLEMENT(LayoutBidi, - "heap-used/layout/bidi", - "Memory used by layout Bidi processor.", - PresShell::SizeOfBidiMemoryReporter, - nsnull) + "explicit/layout/bidi", + MR_HEAP, + "Memory used by layout Bidi processor.", + PresShell::SizeOfBidiMemoryReporter, + nsnull) PresShell::PresShell() : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) diff --git a/modules/libpr0n/src/imgLoader.cpp b/modules/libpr0n/src/imgLoader.cpp index 6e0f7fc33368..eb0fe39a0ca4 100644 --- a/modules/libpr0n/src/imgLoader.cpp +++ b/modules/libpr0n/src/imgLoader.cpp @@ -160,25 +160,31 @@ public: NS_IMETHOD GetPath(char **memoryPath) { if (mType == ChromeUsedRaw) { - *memoryPath = strdup("heap-used/images/chrome/used/raw"); + *memoryPath = strdup("explicit/images/chrome/used/raw"); } else if (mType == ChromeUsedUncompressed) { - *memoryPath = strdup("heap-used/images/chrome/used/uncompressed"); + *memoryPath = strdup("explicit/images/chrome/used/uncompressed"); } else if (mType == ChromeUnusedRaw) { - *memoryPath = strdup("heap-used/images/chrome/unused/raw"); + *memoryPath = strdup("explicit/images/chrome/unused/raw"); } else if (mType == ChromeUnusedUncompressed) { - *memoryPath = strdup("heap-used/images/chrome/unused/uncompressed"); + *memoryPath = strdup("explicit/images/chrome/unused/uncompressed"); } else if (mType == ContentUsedRaw) { - *memoryPath = strdup("heap-used/images/content/used/raw"); + *memoryPath = strdup("explicit/images/content/used/raw"); } else if (mType == ContentUsedUncompressed) { - *memoryPath = strdup("heap-used/images/content/used/uncompressed"); + *memoryPath = strdup("explicit/images/content/used/uncompressed"); } else if (mType == ContentUnusedRaw) { - *memoryPath = strdup("heap-used/images/content/unused/raw"); + *memoryPath = strdup("explicit/images/content/unused/raw"); } else if (mType == ContentUnusedUncompressed) { - *memoryPath = strdup("heap-used/images/content/unused/uncompressed"); + *memoryPath = strdup("explicit/images/content/unused/uncompressed"); } return NS_OK; } + NS_IMETHOD GetKind(PRInt32 *kind) + { + *kind = MR_HEAP; + return NS_OK; + } + NS_IMETHOD GetDescription(char **desc) { if (mType == ChromeUsedRaw) { diff --git a/storage/src/mozStorageConnection.cpp b/storage/src/mozStorageConnection.cpp index 95a72a612f1f..d846989f263c 100644 --- a/storage/src/mozStorageConnection.cpp +++ b/storage/src/mozStorageConnection.cpp @@ -353,7 +353,7 @@ public: { nsCString path; - path.AppendLiteral("heap-used/storage/sqlite/"); + path.AppendLiteral("explicit/storage/sqlite/"); path.Append(mDBConn.getFilename()); if (mType == LookAside_Used) { @@ -373,6 +373,12 @@ public: return NS_OK; } + NS_IMETHOD GetKind(PRInt32 *kind) + { + *kind = MR_HEAP; + return NS_OK; + } + NS_IMETHOD GetDescription(char **desc) { if (mType == LookAside_Used) { @@ -382,7 +388,8 @@ public: *desc = ::strdup("Memory (approximate) used by all pager caches."); } else if (mType == Schema_Used) { - *desc = ::strdup("Memory (approximate) used to store the schema for all databases associated with the connection"); + *desc = ::strdup("Memory (approximate) used to store the schema " + "for all databases associated with the connection"); } else if (mType == Stmt_Used) { *desc = ::strdup("Memory (approximate) used by all prepared statements"); diff --git a/storage/src/mozStorageService.cpp b/storage/src/mozStorageService.cpp index 1ff0d72e6ca0..73b0a922266e 100644 --- a/storage/src/mozStorageService.cpp +++ b/storage/src/mozStorageService.cpp @@ -139,10 +139,11 @@ GetStorageSQLiteMemoryUsed(void *) } NS_MEMORY_REPORTER_IMPLEMENT(StorageSQLiteMemoryUsed, - "heap-used/storage/sqlite", - "Memory used by SQLite.", - GetStorageSQLiteMemoryUsed, - nsnull) + "explicit/storage/sqlite", + MR_HEAP, + "Memory used by SQLite.", + GetStorageSQLiteMemoryUsed, + nsnull) //////////////////////////////////////////////////////////////////////////////// //// Helpers diff --git a/toolkit/components/aboutmemory/content/aboutMemory.css b/toolkit/components/aboutmemory/content/aboutMemory.css index be4668187a36..99950ce9c8d7 100644 --- a/toolkit/components/aboutmemory/content/aboutMemory.css +++ b/toolkit/components/aboutmemory/content/aboutMemory.css @@ -48,6 +48,11 @@ color: #004; } +.mrStar { + font-style: italic; + color: #604; +} + .treeLine { color: #888; } diff --git a/toolkit/components/aboutmemory/content/aboutMemory.js b/toolkit/components/aboutmemory/content/aboutMemory.js index ebc197e93bad..8285ad659fde 100644 --- a/toolkit/components/aboutmemory/content/aboutMemory.js +++ b/toolkit/components/aboutmemory/content/aboutMemory.js @@ -48,6 +48,12 @@ var gVerbose = (location.href.split(/[\?,]/).indexOf("verbose") !== -1); var gAddedObserver = false; +const MR_MAPPED = Ci.nsIMemoryReporter.MR_MAPPED; +const MR_HEAP = Ci.nsIMemoryReporter.MR_HEAP; +const MR_OTHER = Ci.nsIMemoryReporter.MR_OTHER; + +const kUnknown = -1; // used for _memoryUsed if a memory reporter failed + function onLoad() { var os = Cc["@mozilla.org/observer-service;1"]. @@ -145,8 +151,9 @@ function update() // // interface Tmr { // _tpath: string; + // _kind: number; // _description: string; - // _memoryUsed: number; + // _memoryUsed: number; // } // // - The .path property is renamed ._tpath ("truncated path") in the copy @@ -170,6 +177,7 @@ function update() process = mr.path.slice(0, i); tmr._tpath = mr.path.slice(i + 1); } + tmr._kind = mr.kind; tmr._description = mr.description; tmr._memoryUsed = mr.memoryUsed; @@ -201,10 +209,11 @@ function update() const CCDesc = "Do a global garbage collection followed by a cycle " + "collection. (It currently is not possible to do a cycle " + "collection on its own, see bug 625302.)"; - const MPDesc = "Send three \"heap-minimize\" notifications in a row. Each " + - "notification triggers a global garbage collection followed " + - "by a cycle collection, and causes the process to reduce " + - "memory usage in other ways, e.g. by flushing various caches."; + const MPDesc = "Send three \"heap-minimize\" notifications in a " + + "row. Each notification triggers a global garbage " + + "collection followed by a cycle collection, and causes the " + + "process to reduce memory usage in other ways, e.g. by " + + "flushing various caches."; text += "
" + "" + @@ -222,6 +231,11 @@ function update() content.appendChild(div); } +function cmpTmrs(a, b) +{ + return b._memoryUsed - a._memoryUsed +}; + /** * Generates the text for a single process. * @@ -233,35 +247,26 @@ function update() */ function genProcessText(aProcess, aTmrs) { - // First, duplicate the "mapped/heap/used" reporter as "heap-used"; this - // value shows up in both the "mapped" and the "heap-used" trees. - var mappedHeapUsedTmr = aTmrs["mapped/heap/used"]; - aTmrs["heap-used"] = { - _tpath: "heap-used", - _description: mappedHeapUsedTmr._description, - _memoryUsed: mappedHeapUsedTmr._memoryUsed - }; - /** * From a list of memory reporters, builds a tree that mirrors the tree * structure that will be shown as output. * - * @param aTreeName - * The name of the tree; either "mapped" or "heap-used" - * @param aOmitThresholdPerc - * The threshold percentage; entries that account for less than - * this fraction are aggregated * @return The built tree. The tree nodes have this structure: * interface Node { * _name: string; + * _kind: number; * _description: string; - * _memoryUsed: number; - * _kids: [Node]; - * _hasReporter: boolean; (might not be defined) + * _memoryUsed: number; (non-negative or 'kUnknown') + * _kids: [Node]; + * _hasReporter: boolean; (only defined if 'true') + * _hasProblem: boolean; (only defined if 'true') * } */ - function buildTree(aTreeName, aOmitThresholdPerc) + function buildTree() { + const treeName = "explicit"; + const omitThresholdPerc = 0.5; /* percent */ + function findKid(aName, aKids) { for (var i = 0; i < aKids.length; i++) { @@ -272,13 +277,17 @@ function genProcessText(aProcess, aTmrs) return undefined; } - // We want to process all reporters that begin with 'aTreeName'. - // First we build the tree but only filling in '_name', '_kids' and - // maybe '._hasReporter'. This is done top-down from the reporters. - var t = { _name: "falseRoot", _kids: [] }; + // We want to process all reporters that begin with 'treeName'. + // First we build the tree but only filling in '_name', '_kind', '_kids' + // and maybe '._hasReporter'. This is done top-down from the reporters. + var t = { + _name: "falseRoot", + _kind: MR_OTHER, + _kids: [] + }; for (var tpath in aTmrs) { var tmr = aTmrs[tpath]; - if (tmr._tpath.slice(0, aTreeName.length) === aTreeName) { + if (tmr._tpath.slice(0, treeName.length) === treeName) { var names = tmr._tpath.split('/'); var u = t; for (var i = 0; i < names.length; i++) { @@ -287,66 +296,126 @@ function genProcessText(aProcess, aTmrs) if (uMatch) { u = uMatch; } else { - var v = { _name: name, _kids: [] }; + var v = { + _name: name, + _kind: MR_OTHER, + _kids: [] + }; u._kids.push(v); u = v; } } + u._kind = tmr._kind; u._hasReporter = true; } } // Using falseRoot makes the above code simpler. Now discard it, leaving - // aTreeName at the root. + // treeName at the root. t = t._kids[0]; - // Next, fill in '_description' and '_memoryUsed' for each node. This is - // done bottom-up because for most non-leaf nodes '_memoryUsed' and - // '_description' are determined from the child nodes. + // Next, fill in '_description' and '_memoryUsed', and maybe '_hasProblem' + // for each node. This is done bottom-up because for most non-leaf nodes + // '_memoryUsed' and '_description' are determined from the child nodes. function fillInTree(aT, aPretpath) { var tpath = aPretpath ? aPretpath + '/' + aT._name : aT._name; if (aT._kids.length === 0) { // Leaf node. Must have a reporter. - aT._memoryUsed = getBytes(aTmrs, tpath); aT._description = getDescription(aTmrs, tpath); + var memoryUsed = getBytes(aTmrs, tpath); + if (memoryUsed !== kUnknown) { + aT._memoryUsed = memoryUsed; + } else { + aT._memoryUsed = 0; + aT._hasProblem = true; + } } else { // Non-leaf node. Get the size of the children. var childrenBytes = 0; for (var i = 0; i < aT._kids.length; i++) { - // Allow for -1 (ie. "unknown"), treat it like 0. + // Allow for kUnknown, treat it like 0. var b = fillInTree(aT._kids[i], tpath); - childrenBytes += (b === -1 ? 0 : b); + childrenBytes += (b === kUnknown ? 0 : b); } if (aT._hasReporter === true) { - // Non-leaf node with its own reporter. Use the reporter and add an - // "other" child node (unless the byte count is -1, ie. unknown). - aT._memoryUsed = getBytes(aTmrs, tpath); aT._description = getDescription(aTmrs, tpath); - if (aT._memoryUsed !== -1) { + var memoryUsed = getBytes(aTmrs, tpath); + if (memoryUsed !== kUnknown) { + // Non-leaf node with its own reporter. Use the reporter and add + // an "other" child node. + aT._memoryUsed = memoryUsed; var other = { _name: "other", + _kind: MR_OTHER, _description: "All unclassified " + aT._name + " memory.", _memoryUsed: aT._memoryUsed - childrenBytes, _kids: [] }; aT._kids.push(other); + } else { + // Non-leaf node with a reporter that returns kUnknown. + // Use the sum of the children and mark it as problematic. + aT._memoryUsed = childrenBytes; + aT._hasProblem = true; } } else { // Non-leaf node without its own reporter. Derive its size and // description entirely from its children. aT._memoryUsed = childrenBytes; - aT._description = "The sum of all entries below " + aT._name + "."; + aT._description = "The sum of all entries below '" + aT._name + "'."; } } return aT._memoryUsed; } fillInTree(t, ""); + // Determine how many bytes are reported by heap reporters. Be careful + // with non-leaf reporters; if we count a non-leaf reporter we don't want + // to count any of its child reporters. + var s = ""; + function getKnownHeapUsedBytes(aT) + { + if (aT._kind === MR_HEAP) { + return aT._memoryUsed; + } else { + var n = 0; + for (var i = 0; i < aT._kids.length; i++) { + n += getKnownHeapUsedBytes(aT._kids[i]); + } + return n; + } + } + + // A special case: compute the derived "heap-unclassified" value. Don't + // mark "heap-used" when we get its size because we want it to appear in + // the "Other Measurements" list. + var heapUsedBytes = getBytes(aTmrs, "heap-used", true); + var unknownHeapUsedBytes = 0; + var hasProblem = true; + if (heapUsedBytes !== kUnknown) { + unknownHeapUsedBytes = heapUsedBytes - getKnownHeapUsedBytes(t); + hasProblem = false; + } + var heapUnclassified = { + _name: "heap-unclassified", + _kind: MR_HEAP, + _description: + "Memory not classified by a more specific reporter. This includes " + + "memory allocated by the heap allocator in excess of that requested " + + "by the application; this can happen when the heap allocator rounds " + + "up request sizes.", + _memoryUsed: unknownHeapUsedBytes, + _hasProblem: hasProblem, + _kids: [] + } + t._kids.push(heapUnclassified); + t._memoryUsed += unknownHeapUsedBytes; + function shouldOmit(aBytes) { return !gVerbose && - t._memoryUsed !== -1 && - (100 * aBytes / t._memoryUsed) < aOmitThresholdPerc; + t._memoryUsed !== kUnknown && + (100 * aBytes / t._memoryUsed) < omitThresholdPerc; } /** @@ -358,7 +427,6 @@ function genProcessText(aProcess, aTmrs) */ function filterTree(aT) { - var cmpTmrs = function(a, b) { return b._memoryUsed - a._memoryUsed }; aT._kids.sort(cmpTmrs); for (var i = 0; i < aT._kids.length; i++) { @@ -377,6 +445,7 @@ function genProcessText(aProcess, aTmrs) var n = i - i0; var tmrSub = { _name: "(" + n + " omitted)", + _kind: MR_OTHER, _description: "Omitted sub-trees: " + aggNames.join(", ") + ".", _memoryUsed: aggBytes, _kids: [] @@ -392,17 +461,10 @@ function genProcessText(aProcess, aTmrs) return t; } - // The threshold used for the "mapped" tree is lower than the one for the - // "heap-used" tree, because the "mapped" total size is dominated (especially - // on Mac) by memory usage that isn't covered by more specific reporters. - var mappedTree = buildTree("mapped", 0.01); - var heapUsedTree = buildTree("heap-used", 0.1); - // Nb: the newlines give nice spacing if we cut+paste into a text buffer. var text = ""; text += "

" + aProcess + " Process

\n\n"; - text += genTreeText(mappedTree, "Mapped Memory"); - text += genTreeText(heapUsedTree, "Used Heap Memory"); + text += genTreeText(buildTree()); text += genOtherText(aTmrs); text += "
"; return text; @@ -419,10 +481,6 @@ function formatBytes(aBytes) { var unit = gVerbose ? "B" : "MB"; - if (aBytes === -1) { - return "??? " + unit; - } - function formatInt(aN) { var neg = false; @@ -483,26 +541,30 @@ function pad(aS, aN, aC) } /** - * Gets the byte count for a particular memory reporter. + * Gets the byte count for a particular memory reporter and sets its _done + * property. * * @param aTmrs * Table of Tmrs for this process * @param aTpath * The tpath of the memory reporter + * @param aDoNotMark + * If set, the _done property is not set. * @return The byte count */ -function getBytes(aTmrs, aTpath) +function getBytes(aTmrs, aTpath, aDoNotMark) { var tmr = aTmrs[aTpath]; if (tmr) { var bytes = tmr._memoryUsed; - tmr.done = true; + if (!aDoNotMark) { + tmr._done = true; + } return bytes; } - // Nb: this should never occur; "mapped" and "mapped/heap/used" should - // always be registered, and all other tpaths have been extracted from - // aTmrs and so the lookup will succeed. Return an obviously wrong - // number that will likely be noticed. + // Nb: this should never occur; all tpaths have been extracted from aTmrs and + // so the lookup will succeed. Return an obviously wrong number that will + // likely be noticed. return -2 * 1024 * 1024; } @@ -526,22 +588,44 @@ function genMrValueText(aValue) return "" + aValue + ""; } -function genMrNameText(aDesc, aName) +function kindToString(aKind) { - return "-- " + - aName + "\n"; + switch (aKind) { + case MR_MAPPED: return "(Mapped) "; + case MR_HEAP: return "(Heap) "; + case MR_OTHER: return ""; + default: return "(???) "; + } +} + +function escapeQuotes(aStr) +{ + return aStr.replace(/'/g, '''); +} + +function genMrNameText(aKind, aDesc, aName, aHasProblem) +{ + const problemDesc = + "Warning: this memory reporter was unable to compute a useful value. " + + "The reported value is the sum of all entries below '" + aName + "', " + + "which is probably less than the true value."; + var text = "-- " + aName + ""; + text += aHasProblem + ? " [*]\n" + : "\n"; + return text; } /** - * Generates the text for a particular tree, including its heading. + * Generates the text for the tree, including its heading. * * @param aT * The tree - * @param aTreeName - * The tree's name * @return The generated text */ -function genTreeText(aT, aTreeName) +function genTreeText(aT) { var treeBytes = aT._memoryUsed; var treeBytesLength = formatBytes(treeBytes).length; @@ -605,20 +689,17 @@ function genTreeText(aT, aTreeName) // Generate the percentage. var perc = ""; - if (treeBytes !== -1) { - if (aT._memoryUsed === -1) { - perc = "??.??"; - } else if (aT._memoryUsed === treeBytes) { - perc = "100.0"; - } else { - perc = (100 * aT._memoryUsed / treeBytes).toFixed(2); - perc = pad(perc, 5, '0'); - } - perc = "(" + perc + "%) "; + if (aT._memoryUsed === treeBytes) { + perc = "100.0"; + } else { + perc = (100 * aT._memoryUsed / treeBytes).toFixed(2); + perc = pad(perc, 5, '0'); } + perc = "(" + perc + "%) "; var text = indent + genMrValueText(tMemoryUsedStr) + " " + perc + - genMrNameText(aT._description, aT._name); + genMrNameText(aT._kind, aT._description, aT._name, + aT._hasProblem); for (var i = 0; i < aT._kids.length; i++) { // 3 is the standard depth, the callee adjusts it if necessary. @@ -631,7 +712,21 @@ function genTreeText(aT, aTreeName) var text = genTreeText2(aT, [], treeBytesLength); // Nb: the newlines give nice spacing if we cut+paste into a text buffer. - return "

" + aTreeName + "

\n
" + text + "
\n"; + const desc = + "This tree covers explicit memory allocations by the application, " + + "both at the operating system level (via calls to functions such as " + + "VirtualAlloc, vm_allocate, and mmap), and at the heap allocation level " + + "(via functions such as malloc, calloc, realloc, memalign, operator " + + "new, and operator new[]). It excludes memory that is mapped implicitly " + + "such as code and data segments, and thread stacks. It also excludes " + + "heap memory that has been freed by the application but is still being " + + "held onto by the heap allocator. It is not guaranteed to cover every " + + "explicit allocation, but it does cover most (including the entire " + + "heap), and therefore it is the single best number to focus on when " + + "trying to reduce memory usage."; + + return "

Explicit Allocations

\n" + "
" + text + "
\n"; } /** @@ -643,30 +738,48 @@ function genTreeText(aT, aTreeName) */ function genOtherText(aTmrs) { - // Get the biggest not-yet-printed value, to determine the field width - // for all these entries. These should all be "other" values, assuming - // all paths are well-formed. - var maxBytes = 0; + // Generate an array of tmr-like elements, stripping out all the tmrs that + // have already been handled. Also find the width of the widest element, so + // we can format things nicely. + var maxBytesLength = 0; + var tmrArray = []; for (var tpath in aTmrs) { var tmr = aTmrs[tpath]; - if (!tmr.done && tmr._memoryUsed > maxBytes) { - maxBytes = tmr._memoryUsed; + if (!tmr._done) { + var hasProblem = false; + if (tmr._memoryUsed === kUnknown) { + hasProblem = true; + } + var elem = { + _tpath: tmr._tpath, + _kind: tmr._kind, + _description: tmr._description, + _memoryUsed: hasProblem ? 0 : tmr._memoryUsed, + _hasProblem: hasProblem + }; + tmrArray.push(elem); + var thisBytesLength = formatBytes(elem._memoryUsed).length; + if (thisBytesLength > maxBytesLength) { + maxBytesLength = thisBytesLength; + } } } + tmrArray.sort(cmpTmrs); - // Generate text for the not-yet-yet-printed values. - var maxBytesLength = formatBytes(maxBytes).length; + // Generate text for the not-yet-printed values. var text = ""; - for (var tpath in aTmrs) { - var tmr = aTmrs[tpath]; - if (!tmr.done) { - text += genMrValueText( - pad(formatBytes(tmr._memoryUsed), maxBytesLength, ' ')) + " "; - text += genMrNameText(tmr._description, tmr._tpath); - } + for (var i = 0; i < tmrArray.length; i++) { + var elem = tmrArray[i]; + text += genMrValueText( + pad(formatBytes(elem._memoryUsed), maxBytesLength, ' ')) + " "; + text += genMrNameText(elem._kind, elem._description, elem._tpath, + elem._hasProblem); } // Nb: the newlines give nice spacing if we cut+paste into a text buffer. - return "

Other Measurements

\n
" + text + "
\n"; + const desc = "This list contains other memory measurements that cross-cut " + + "the requested memory measurements above." + return "

Other Measurements

\n" + + "
" + text + "
\n"; } diff --git a/toolkit/components/aboutmemory/tests/chrome/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/chrome/test_aboutmemory.xul index ae540a69f6f6..f29a7e596e0f 100644 --- a/toolkit/components/aboutmemory/tests/chrome/test_aboutmemory.xul +++ b/toolkit/components/aboutmemory/tests/chrome/test_aboutmemory.xul @@ -30,41 +30,49 @@ // Setup various fake-but-deterministic reporters. const KB = 1024; const MB = KB * KB; + const kUnknown = -1; + const MAPPED = Ci.nsIMemoryReporter.MR_MAPPED; + const HEAP = Ci.nsIMemoryReporter.MR_HEAP; + const OTHER = Ci.nsIMemoryReporter.MR_OTHER; + fakeReporters = [ - { path: "mapped", memoryUsed: 1000 * MB }, - { path: "mapped/heap/used", memoryUsed: 500 * MB }, - { path: "mapped/heap/unused", memoryUsed: 100 * MB }, - { path: "mapped/a", memoryUsed: 222 * MB }, - { path: "heap-used/a", memoryUsed: 99 * MB }, - { path: "heap-used/b/a", memoryUsed: 80 * MB }, - { path: "heap-used/b/b", memoryUsed: 75 * MB }, - { path: "heap-used/b/c/a", memoryUsed: 44 * MB }, - { path: "heap-used/b/c/b", memoryUsed: 33 * MB }, // aggregated - { path: "heap-used/c", memoryUsed: 123 * MB }, - { path: "heap-used/d", memoryUsed: 499 * KB }, // aggregated - { path: "heap-used/e", memoryUsed: 100 * KB }, // aggregated - { path: "heap-used/f/g/h/i", memoryUsed: 20 * MB }, - { path: "heap-used/g", memoryUsed: 15 * MB }, // internal - { path: "heap-used/g/a", memoryUsed: 6 * MB }, - { path: "heap-used/g/b", memoryUsed: 5 * MB }, - { path: "other1", memoryUsed: 111 * MB }, - { path: "other2", memoryUsed: 222 * MB }, + { path: "heap-used", kind: OTHER, memoryUsed: 500 * MB }, + { path: "heap-unused", kind: OTHER, memoryUsed: 100 * MB }, + { path: "explicit/a", kind: HEAP, memoryUsed: 222 * MB }, + { path: "explicit/b/a", kind: HEAP, memoryUsed: 85 * MB }, + { path: "explicit/b/b", kind: HEAP, memoryUsed: 75 * MB }, + { path: "explicit/b/c/a", kind: HEAP, memoryUsed: 70 * MB }, + { path: "explicit/b/c/b", kind: HEAP, memoryUsed: 2 * MB }, // omitted + { path: "explicit/c", kind: MAPPED,memoryUsed: 123 * MB }, + { path: "explicit/d", kind: MAPPED,memoryUsed: 499 * KB }, // omitted + { path: "explicit/e", kind: MAPPED,memoryUsed: 100 * KB }, // omitted + { path: "explicit/f/g/h/i", kind: HEAP, memoryUsed: 20 * MB }, + { path: "explicit/g", kind: HEAP, memoryUsed: 14 * MB }, // internal + { path: "explicit/g", kind: HEAP, memoryUsed: 1 * MB }, // internal, dup: merge + { path: "explicit/g/a", kind: HEAP, memoryUsed: 6 * MB }, + { path: "explicit/g/b", kind: HEAP, memoryUsed: 5 * MB }, + { path: "other1", kind: OTHER, memoryUsed: 111 * MB }, + { path: "other2", kind: OTHER, memoryUsed: 222 * MB }, - { path: "2nd:mapped", memoryUsed: 1000 * MB }, - { path: "2nd:mapped/heap/used", memoryUsed: 500 * MB }, - { path: "2nd:mapped/a/b/c", memoryUsed: 499 * MB }, - { path: "2nd:heap-used/a", memoryUsed: 400 * MB }, - { path: "2nd:other1", memoryUsed: 777 * MB }, + { path: "2nd:heap-used", kind: OTHER, memoryUsed: 1000 * MB }, + { path: "2nd:heap-unused", kind: OTHER, memoryUsed: 100 * MB }, + { path: "2nd:explicit/a/b/c",kind: HEAP, memoryUsed: 498 * MB }, + { path: "2nd:explicit/a/b/c",kind: HEAP, memoryUsed: 1 * MB }, // dup: merge + { path: "2nd:explicit/b", kind: HEAP, memoryUsed: 400 * MB }, + { path: "2nd:other1", kind: OTHER, memoryUsed: 777 * MB }, - // -1 means "don't know"; this should be handled gracefully for - // "mapped" and "mapped/heap/used". - { path: "3rd:mapped", memoryUsed: -1 }, - { path: "3rd:mapped/heap/used", memoryUsed: -1 }, - { path: "3rd:mapped/a/b", memoryUsed: 333 * MB }, - { path: "3rd:heap-used/a/b", memoryUsed: 444 * MB }, - { path: "3rd:other1", memoryUsed: 555 * MB } + // kUnknown should be handled gracefully for "heap-used", non-leaf + // reporters, leaf-reporters, and "other" reporters. + { path: "3rd:heap-used", kind: OTHER, memoryUsed: kUnknown }, + { path: "3rd:explicit/a", kind: HEAP, memoryUsed: kUnknown }, + { path: "3rd:explicit/a/b", kind: HEAP, memoryUsed: 333 * MB }, + { path: "3rd:explicit/a/c", kind: HEAP, memoryUsed: 444 * MB }, + { path: "3rd:explicit/a/d", kind: HEAP, memoryUsed: kUnknown }, + { path: "3rd:explicit/b", kind: MAPPED,memoryUsed: kUnknown }, + { path: "3rd:other1", kind: OTHER, memoryUsed: kUnknown } ]; for (var i = 0; i < fakeReporters.length; i++) { + fakeReporters[i].description = "(description)"; mgr.registerReporter(fakeReporters[i]); } ]]> @@ -79,74 +87,61 @@ "\ Main Process\n\ \n\ -Mapped Memory\n\ -1,000.00 MB (100.0%) -- mapped\n\ -├────600.00 MB (60.00%) -- heap\n\ -│ ├──500.00 MB (50.00%) -- used\n\ -│ └──100.00 MB (10.00%) -- unused\n\ -├────222.00 MB (22.20%) -- a\n\ -└────178.00 MB (17.80%) -- other\n\ -\n\ -Used Heap Memory\n\ -500.00 MB (100.0%) -- heap-used\n\ -├──232.00 MB (46.40%) -- b\n\ -│ ├───80.00 MB (16.00%) -- a\n\ -│ ├───77.00 MB (15.40%) -- c\n\ -│ │ ├──44.00 MB (08.80%) -- a\n\ -│ │ └──33.00 MB (06.60%) -- b\n\ -│ └───75.00 MB (15.00%) -- b\n\ -├──123.00 MB (24.60%) -- c\n\ -├───99.00 MB (19.80%) -- a\n\ -├───20.00 MB (04.00%) -- f\n\ -│ └──20.00 MB (04.00%) -- g\n\ -│ └──20.00 MB (04.00%) -- h\n\ -│ └──20.00 MB (04.00%) -- i\n\ -├───15.00 MB (03.00%) -- g\n\ -│ ├───6.00 MB (01.20%) -- a\n\ -│ ├───5.00 MB (01.00%) -- b\n\ -│ └───4.00 MB (00.80%) -- other\n\ -├───10.42 MB (02.08%) -- other\n\ -└────0.58 MB (00.12%) -- (2 omitted)\n\ +Explicit Allocations\n\ +623.58 MB (100.0%) -- explicit\n\ +├──232.00 MB (37.20%) -- b\n\ +│ ├───85.00 MB (13.63%) -- a\n\ +│ ├───75.00 MB (12.03%) -- b\n\ +│ └───72.00 MB (11.55%) -- c\n\ +│ ├──70.00 MB (11.23%) -- a\n\ +│ └───2.00 MB (00.32%) -- (1 omitted)\n\ +├──222.00 MB (35.60%) -- a\n\ +├──123.00 MB (19.72%) -- c\n\ +├───20.00 MB (03.21%) -- f\n\ +│ └──20.00 MB (03.21%) -- g\n\ +│ └──20.00 MB (03.21%) -- h\n\ +│ └──20.00 MB (03.21%) -- i\n\ +├───15.00 MB (02.41%) -- g\n\ +│ ├───6.00 MB (00.96%) -- a\n\ +│ ├───5.00 MB (00.80%) -- b\n\ +│ └───4.00 MB (00.64%) -- other\n\ +├───11.00 MB (01.76%) -- heap-unclassified\n\ +└────0.58 MB (00.09%) -- (2 omitted)\n\ \n\ Other Measurements\n\ -111.00 MB -- other1\n\ +500.00 MB -- heap-used\n\ 222.00 MB -- other2\n\ +111.00 MB -- other1\n\ +100.00 MB -- heap-unused\n\ \n\ 2nd Process\n\ \n\ -Mapped Memory\n\ -1,000.00 MB (100.0%) -- mapped\n\ -├────500.00 MB (50.00%) -- heap\n\ -│ └──500.00 MB (50.00%) -- used\n\ +Explicit Allocations\n\ +1,000.00 MB (100.0%) -- explicit\n\ ├────499.00 MB (49.90%) -- a\n\ │ └──499.00 MB (49.90%) -- b\n\ │ └──499.00 MB (49.90%) -- c\n\ -└──────1.00 MB (00.10%) -- other\n\ -\n\ -Used Heap Memory\n\ -500.00 MB (100.0%) -- heap-used\n\ -├──400.00 MB (80.00%) -- a\n\ -└──100.00 MB (20.00%) -- other\n\ +├────400.00 MB (40.00%) -- b\n\ +└────101.00 MB (10.10%) -- heap-unclassified\n\ \n\ Other Measurements\n\ -777.00 MB -- other1\n\ +1,000.00 MB -- heap-used\n\ + 777.00 MB -- other1\n\ + 100.00 MB -- heap-unused\n\ \n\ 3rd Process\n\ \n\ -Mapped Memory\n\ -??? MB -- mapped\n\ -├──333.00 MB -- a\n\ -│ └──333.00 MB -- b\n\ -└──0.00 MB -- heap\n\ - └───??? MB -- used\n\ -\n\ -Used Heap Memory\n\ -??? MB -- heap-used\n\ -└──444.00 MB -- a\n\ - └──444.00 MB -- b\n\ +Explicit Allocations\n\ +777.00 MB (100.0%) -- explicit\n\ +├──777.00 MB (100.0%) -- a [*]\n\ +│ ├──444.00 MB (57.14%) -- c\n\ +│ ├──333.00 MB (42.86%) -- b\n\ +│ └────0.00 MB (00.00%) -- (1 omitted)\n\ +└────0.00 MB (00.00%) -- (2 omitted)\n\ \n\ Other Measurements\n\ -555.00 MB -- other1\n\ +0.00 MB -- heap-used [*]\n\ +0.00 MB -- other1 [*]\n\ \n\ "; @@ -154,75 +149,63 @@ Other Measurements\n\ "\ Main Process\n\ \n\ -Mapped Memory\n\ -1,048,576,000 B (100.0%) -- mapped\n\ -├────629,145,600 B (60.00%) -- heap\n\ -│ ├──524,288,000 B (50.00%) -- used\n\ -│ └──104,857,600 B (10.00%) -- unused\n\ -├────232,783,872 B (22.20%) -- a\n\ -└────186,646,528 B (17.80%) -- other\n\ -\n\ -Used Heap Memory\n\ -524,288,000 B (100.0%) -- heap-used\n\ -├──243,269,632 B (46.40%) -- b\n\ -│ ├───83,886,080 B (16.00%) -- a\n\ -│ ├───80,740,352 B (15.40%) -- c\n\ -│ │ ├──46,137,344 B (08.80%) -- a\n\ -│ │ └──34,603,008 B (06.60%) -- b\n\ -│ └───78,643,200 B (15.00%) -- b\n\ -├──128,974,848 B (24.60%) -- c\n\ -├──103,809,024 B (19.80%) -- a\n\ -├───20,971,520 B (04.00%) -- f\n\ -│ └──20,971,520 B (04.00%) -- g\n\ -│ └──20,971,520 B (04.00%) -- h\n\ -│ └──20,971,520 B (04.00%) -- i\n\ -├───15,728,640 B (03.00%) -- g\n\ -│ ├───6,291,456 B (01.20%) -- a\n\ -│ ├───5,242,880 B (01.00%) -- b\n\ -│ └───4,194,304 B (00.80%) -- other\n\ -├───10,920,960 B (02.08%) -- other\n\ -├──────510,976 B (00.10%) -- d\n\ +Explicit Allocations\n\ +653,876,224 B (100.0%) -- explicit\n\ +├──243,269,632 B (37.20%) -- b\n\ +│ ├───89,128,960 B (13.63%) -- a\n\ +│ ├───78,643,200 B (12.03%) -- b\n\ +│ └───75,497,472 B (11.55%) -- c\n\ +│ ├──73,400,320 B (11.23%) -- a\n\ +│ └───2,097,152 B (00.32%) -- b\n\ +├──232,783,872 B (35.60%) -- a\n\ +├──128,974,848 B (19.72%) -- c\n\ +├───20,971,520 B (03.21%) -- f\n\ +│ └──20,971,520 B (03.21%) -- g\n\ +│ └──20,971,520 B (03.21%) -- h\n\ +│ └──20,971,520 B (03.21%) -- i\n\ +├───15,728,640 B (02.41%) -- g\n\ +│ ├───6,291,456 B (00.96%) -- a\n\ +│ ├───5,242,880 B (00.80%) -- b\n\ +│ └───4,194,304 B (00.64%) -- other\n\ +├───11,534,336 B (01.76%) -- heap-unclassified\n\ +├──────510,976 B (00.08%) -- d\n\ └──────102,400 B (00.02%) -- e\n\ \n\ Other Measurements\n\ -116,391,936 B -- other1\n\ +524,288,000 B -- heap-used\n\ 232,783,872 B -- other2\n\ +116,391,936 B -- other1\n\ +104,857,600 B -- heap-unused\n\ \n\ 2nd Process\n\ \n\ -Mapped Memory\n\ -1,048,576,000 B (100.0%) -- mapped\n\ -├────524,288,000 B (50.00%) -- heap\n\ -│ └──524,288,000 B (50.00%) -- used\n\ +Explicit Allocations\n\ +1,048,576,000 B (100.0%) -- explicit\n\ ├────523,239,424 B (49.90%) -- a\n\ │ └──523,239,424 B (49.90%) -- b\n\ │ └──523,239,424 B (49.90%) -- c\n\ -└──────1,048,576 B (00.10%) -- other\n\ -\n\ -Used Heap Memory\n\ -524,288,000 B (100.0%) -- heap-used\n\ -├──419,430,400 B (80.00%) -- a\n\ -└──104,857,600 B (20.00%) -- other\n\ +├────419,430,400 B (40.00%) -- b\n\ +└────105,906,176 B (10.10%) -- heap-unclassified\n\ \n\ Other Measurements\n\ -814,743,552 B -- other1\n\ +1,048,576,000 B -- heap-used\n\ + 814,743,552 B -- other1\n\ + 104,857,600 B -- heap-unused\n\ \n\ 3rd Process\n\ \n\ -Mapped Memory\n\ -??? B -- mapped\n\ -├──349,175,808 B -- a\n\ -│ └──349,175,808 B -- b\n\ -└────0 B -- heap\n\ - └──??? B -- used\n\ -\n\ -Used Heap Memory\n\ -??? B -- heap-used\n\ -└──465,567,744 B -- a\n\ - └──465,567,744 B -- b\n\ +Explicit Allocations\n\ +814,743,552 B (100.0%) -- explicit\n\ +├──814,743,552 B (100.0%) -- a [*]\n\ +│ ├──465,567,744 B (57.14%) -- c\n\ +│ ├──349,175,808 B (42.86%) -- b\n\ +│ └────────────0 B (00.00%) -- d [*]\n\ +├────────────0 B (00.00%) -- b [*]\n\ +└────────────0 B (00.00%) -- heap-unclassified [*]\n\ \n\ Other Measurements\n\ -581,959,680 B -- other1\n\ +0 B -- heap-used [*]\n\ +0 B -- other1 [*]\n\ \n\ " diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 2cfa0b7d6c32..1712e58459ca 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -47,39 +47,52 @@ interface nsIMemoryReporter : nsISupports * The path that this memory usage should be reported under. Paths can * begin with a process name plus a colon, eg "Content:", but this is not * necessary for the main process. After the process name, paths are - * '/'-delimited, eg. "a/b/c". There are three categories of paths. + * '/'-delimited, eg. "a/b/c". There are two categories of paths. * - * - Paths starting with "mapped" represent non-overlapping regions of mapped - * memory. Each one can be viewed as representing a path in a tree from - * the root node ("mapped") to a node lower in the tree; this lower node - * may be a non-leaf or a leaf node. So, for example, "mapped", - * "mapped/heap/used", "mapped/heap/unused", "mapped/js/mjit-code", - * and "mapped/js/tjit-code" define this tree: + * - Paths starting with "explicit" represent non-overlapping regions of + * memory that have been explicitly allocated with an OS-level allocation + * (eg. mmap/VirtualAlloc/vm_allocate) or a heap-level allocation (eg. + * malloc/calloc/operator new). Each one can be viewed as representing a + * path in a tree from the root node ("explicit") to a node lower in the + * tree; this lower node does not have to be a leaf node. * - * mapped [*] - * |--heap - * | |--used [*] - * | \--unused [*] - * \--js - * |--mjit-code [*] - * \--tjit-code [*] + * So, for example, "explicit/a/b", "explicit/a/c", "explicit/d", + * "explicit/d/e", and "explicit/d/f" define this tree: + * + * explicit + * |--a + * | |--b [*] + * | \--c [*] + * \--d [*] + * |--e [*] + * \--f [*] * * Nodes marked with a [*] have a reporter. * - * - Paths starting with "heap-used" represent non-overlapping regions of - * used heap memory. The "mapped" rules above apply equally here. These - * paths are actually sub-paths of "mapped/heap/used", but that reporter - * is duplicated under the name "heap-used" to make the processing for - * about:memory simpler. - * * - All other paths represent cross-cuttings memory regions, ie. ones that - * may overlap arbitrarily with regions in the "mapped" and "heap-used" - * trees. + * may overlap arbitrarily with regions in the "explicit" tree. */ readonly attribute string path; /* - * A human-readable description of this memory usage report + * Allocation kinds. "MAPPED" means it is allocated directly by the OS, eg. + * by calling mmap, VirtualAlloc, vm_allocate, etc. "HEAP" means it is + * allocated by the heap allocator, eg. by calling malloc, calloc, realloc, + * memalign, operator new, operator new[], etc. "OTHER" means it doesn't fit + * into either of these categories; such reporters should have a path that + * does *not* start with "explicit". + */ + const PRInt32 MR_MAPPED = 0; + const PRInt32 MR_HEAP = 1; + const PRInt32 MR_OTHER = 2; + + /* + * The memory kind, see MR_* above. + */ + readonly attribute PRInt32 kind; + + /* + * A human-readable description of this memory usage report. */ readonly attribute string description; @@ -119,11 +132,12 @@ interface nsIMemoryReporterManager : nsISupports %{C++ -#define NS_MEMORY_REPORTER_IMPLEMENT(_classname,_path,_desc,_usageFunction,_dataptr) \ +#define NS_MEMORY_REPORTER_IMPLEMENT(_classname,_path,_kind,_desc,_usageFunction,_dataptr) \ class MemoryReporter_##_classname : public nsIMemoryReporter { \ public: \ NS_DECL_ISUPPORTS \ NS_IMETHOD GetPath(char **memoryPath) { *memoryPath = strdup(_path); return NS_OK; } \ + NS_IMETHOD GetKind(int *kind) { *kind = _kind; return NS_OK; } \ NS_IMETHOD GetDescription(char **desc) { *desc = strdup(_desc); return NS_OK; } \ NS_IMETHOD GetMemoryUsed(PRInt64 *memoryUsed) { *memoryUsed = _usageFunction(_dataptr); return NS_OK; } \ }; \ diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index d02159549b4a..ef2b3ff3b927 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -60,7 +60,7 @@ static PRInt64 GetProcSelfStatmField(int n) return (PRInt64) -1; } -static PRInt64 GetMapped(void *) +static PRInt64 GetVsize(void *) { return GetProcSelfStatmField(0); } @@ -83,11 +83,10 @@ static bool GetTaskBasicInfo(struct task_basic_info *ti) return kr == KERN_SUCCESS; } -// Getting a sensible "mapped" number on Mac is difficult. The following is -// easy and (I think) corresponds to the VSIZE figure reported by 'top' and -// 'ps', but that includes shared memory and so is always absurdly high. This -// doesn't really matter as the "mapped" figure is never that useful. -static PRInt64 GetMapped(void *) +// The VSIZE figure on Mac includes huge amounts of shared memory and is always +// absurdly high, eg. 2GB+ even at start-up. But both 'top' and 'ps' report +// it, so we might as well too. +static PRInt64 GetVsize(void *) { task_basic_info ti; return (PRInt64) (GetTaskBasicInfo(&ti) ? ti.virtual_size : -1); @@ -104,22 +103,29 @@ static PRInt64 GetResident(void *) #include #include -static PRInt64 GetMapped(void *) -{ #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN - PROCESS_MEMORY_COUNTERS_EX pmcex; - pmcex.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX); +static PRInt64 GetPrivate(void *) +{ + PROCESS_MEMORY_COUNTERS_EX pmcex; + pmcex.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX); - if (!GetProcessMemoryInfo(GetCurrentProcess(), - (PPROCESS_MEMORY_COUNTERS) &pmcex, sizeof(pmcex))) - return (PRInt64) -1; + if (!GetProcessMemoryInfo(GetCurrentProcess(), + (PPROCESS_MEMORY_COUNTERS) &pmcex, sizeof(pmcex))) + return (PRInt64) -1; - return pmcex.PrivateUsage; -#else - return (PRInt64) -1; -#endif + return pmcex.PrivateUsage; } +NS_MEMORY_REPORTER_IMPLEMENT(Private, + "private", + MR_OTHER, + "Memory that cannot be shared with other processes, including memory that " + "is committed and marked MEM_PRIVATE, data that is not mapped, and " + "executable pages that have been written to.", + GetPrivate, + NULL) +#endif + static PRInt64 GetResident(void *) { PROCESS_MEMORY_COUNTERS pmc; @@ -133,11 +139,6 @@ static PRInt64 GetResident(void *) #else -static PRInt64 GetMapped(void *) -{ - return (PRInt64) -1; -} - static PRInt64 GetResident(void *) { return (PRInt64) -1; @@ -145,25 +146,25 @@ static PRInt64 GetResident(void *) #endif -// aboutMemory.js requires that this reporter always be registered, even if the -// byte count returned is always -1. -NS_MEMORY_REPORTER_IMPLEMENT(Mapped, - "mapped", - "Memory mapped by the process, including the heap, code and data segments, " - "thread stacks, and memory explicitly mapped by the process via " - "mmap, VirtualAlloc and similar operations. " - "Note that 'resident' is a better measure of memory resources used by the " - "process. " - "On Windows (XP SP2 or later only) this is the private usage and does not " - "include memory shared with other processes. " - "On Mac and Linux this is the vsize figure as reported by 'top' or 'ps' " - "and includes memory shared with other processes; on Mac the amount of " - "shared memory can be very high and so this figure is of limited use.", - GetMapped, +#if defined(XP_LINUX) || defined(XP_MACOSX) +NS_MEMORY_REPORTER_IMPLEMENT(Vsize, + "vsize", + MR_OTHER, + "Memory mapped by the process, including code and data segments, the " + "heap, thread stacks, memory explicitly mapped by the process via mmap " + "and similar operations, and memory shared with other processes. " + "(Note that 'resident' is a better measure of the memory resources used " + "by the process.) " + "This is the vsize figure as reported by 'top' or 'ps'; on Mac the amount " + "of memory shared with other processes is very high and so this figure is " + "of limited use.", + GetVsize, NULL) +#endif NS_MEMORY_REPORTER_IMPLEMENT(Resident, "resident", + MR_OTHER, "Memory mapped by the process that is present in physical memory, " "also known as the resident set size (RSS). This is the best single " "figure to use when considering the memory resources used by the process, " @@ -199,14 +200,14 @@ extern void jemalloc_stats(jemalloc_stats_t* stats) #if HAVE_JEMALLOC_STATS -static PRInt64 GetMappedHeapUsed(void *) +static PRInt64 GetHeapUsed(void *) { jemalloc_stats_t stats; jemalloc_stats(&stats); return (PRInt64) stats.allocated; } -static PRInt64 GetMappedHeapUnused(void *) +static PRInt64 GetHeapUnused(void *) { jemalloc_stats_t stats; jemalloc_stats(&stats); @@ -228,30 +229,30 @@ static PRInt64 GetHeapDirty(void *) } NS_MEMORY_REPORTER_IMPLEMENT(HeapCommitted, - "heap-committed", - "Memory mapped by the heap allocator that is " - "committed, i.e. in physical memory or paged to " - "disk.", - GetHeapCommitted, - NULL) + "heap-committed", + MR_OTHER, + "Memory mapped by the heap allocator that is committed, i.e. in physical " + "memory or paged to disk.", + GetHeapCommitted, + NULL) NS_MEMORY_REPORTER_IMPLEMENT(HeapDirty, - "heap-dirty", - "Memory mapped by the heap allocator that is " - "committed but unused.", - GetHeapDirty, - NULL) + "heap-dirty", + MR_OTHER, + "Memory mapped by the heap allocator that is committed but unused.", + GetHeapDirty, + NULL) #elif defined(XP_MACOSX) && !defined(MOZ_MEMORY) #include -static PRInt64 GetMappedHeapUsed(void *) +static PRInt64 GetHeapUsed(void *) { struct mstats stats = mstats(); return (PRInt64) stats.bytes_used; } -static PRInt64 GetMappedHeapUnused(void *) +static PRInt64 GetHeapUnused(void *) { struct mstats stats = mstats(); return (PRInt64) (stats.bytes_total - stats.bytes_used); @@ -272,52 +273,51 @@ static PRInt64 GetHeapZone0Used(void *) } NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Committed, - "heap-zone0-committed", - "Memory mapped by the heap allocator that is " - "committed in the default zone.", - GetHeapZone0Committed, - NULL) + "heap-zone0-committed", + MR_OTHER, + "Memory mapped by the heap allocator that is committed in the default " + "zone.", + GetHeapZone0Committed, + NULL) NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Used, - "heap-zone0-used", - "Memory mapped by the heap allocator in the " - "default zone that is available for use by the " - "application.", - GetHeapZone0Used, - NULL) + "heap-zone0-used", + MR_OTHER, + "Memory mapped by the heap allocator in the default zone that is " + "available for use by the application.", + GetHeapZone0Used, + NULL) #else -static PRInt64 GetMappedHeapUsed(void *) +static PRInt64 GetHeapUsed(void *) { return (PRInt64) -1; } -static PRInt64 GetMappedHeapUnused(void *) +static PRInt64 GetHeapUnused(void *) { return (PRInt64) -1; } #endif -// aboutMemory.js requires that this reporter always be registered, even if the -// byte count returned is always -1. -NS_MEMORY_REPORTER_IMPLEMENT(MappedHeapUsed, - "mapped/heap/used", +NS_MEMORY_REPORTER_IMPLEMENT(HeapUsed, + "heap-used", + MR_OTHER, "Memory mapped by the heap allocator that is available for use by the " "application. This may exceed the amount of memory requested by the " - "application due to the allocator rounding up request sizes. " - "(The exact amount requested is not measured.) " - "This is usually the best figure for developers to focus on when trying " - "to reduce memory consumption.", - GetMappedHeapUsed, + "application due to the allocator rounding up request sizes. " + "(The exact amount requested is not measured.) ", + GetHeapUsed, NULL) -NS_MEMORY_REPORTER_IMPLEMENT(MappedHeapUnused, - "mapped/heap/unused", +NS_MEMORY_REPORTER_IMPLEMENT(HeapUnused, + "heap-unused", + MR_OTHER, "Memory mapped by the heap allocator and not available for use by the " "application. This can grow large if the heap allocator is holding onto " "memory that the application has freed.", - GetMappedHeapUnused, + GetHeapUnused, NULL) /** @@ -336,11 +336,16 @@ nsMemoryReporterManager::Init() #define REGISTER(_x) RegisterReporter(new NS_MEMORY_REPORTER_NAME(_x)) - REGISTER(Mapped); - REGISTER(MappedHeapUsed); - REGISTER(MappedHeapUnused); + REGISTER(HeapUsed); + REGISTER(HeapUnused); REGISTER(Resident); +#if defined(XP_LINUX) || defined(XP_MACOSX) + REGISTER(Vsize); +#elif defined(XP_WIN) && MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN + REGISTER(Private); +#endif + #if defined(HAVE_JEMALLOC_STATS) REGISTER(HeapCommitted); REGISTER(HeapDirty); @@ -395,9 +400,11 @@ NS_IMPL_ISUPPORTS1(nsMemoryReporter, nsIMemoryReporter) nsMemoryReporter::nsMemoryReporter(nsCString& prefix, nsCString& path, + PRInt32 kind, nsCString& desc, PRInt64 memoryUsed) -: mDesc(desc) +: mKind(kind) +, mDesc(desc) , mMemoryUsed(memoryUsed) { if (!prefix.IsEmpty()) { @@ -417,6 +424,12 @@ NS_IMETHODIMP nsMemoryReporter::GetPath(char **aPath) return NS_OK; } +NS_IMETHODIMP nsMemoryReporter::GetKind(PRInt32 *aKind) +{ + *aKind = mKind; + return NS_OK; +} + NS_IMETHODIMP nsMemoryReporter::GetDescription(char **aDescription) { *aDescription = strdup(mDesc.get()); diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 274195812c37..951399e7b244 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -13,6 +13,7 @@ public: nsMemoryReporter(nsCString& prefix, nsCString& path, + PRInt32 kind, nsCString& desc, PRInt64 memoryUsed); @@ -20,6 +21,7 @@ public: protected: nsCString mPath, mDesc; + PRInt32 mKind; PRInt64 mMemoryUsed; }; From 13f17c61efca76a2f0465870190f0ad29b724ef1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 22 May 2011 19:49:59 -0700 Subject: [PATCH 093/145] Bug 656545 - Make about:memory tool-tips more discoverable. r=sdwilsh. --- .../components/aboutmemory/content/aboutMemory.css | 12 ++++++++++-- .../components/aboutmemory/content/aboutMemory.js | 14 +++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/toolkit/components/aboutmemory/content/aboutMemory.css b/toolkit/components/aboutmemory/content/aboutMemory.css index 99950ce9c8d7..6cdee2d90b66 100644 --- a/toolkit/components/aboutmemory/content/aboutMemory.css +++ b/toolkit/components/aboutmemory/content/aboutMemory.css @@ -44,12 +44,14 @@ } .mrName { - font-style: italic; color: #004; } +.hasDesc:hover { + text-decoration: underline; +} + .mrStar { - font-style: italic; color: #604; } @@ -61,3 +63,9 @@ font-size: 80%; -moz-user-select: none; /* no need to include this when cutting+pasting */ } + +.legend { + font-size: 80%; + -moz-user-select: none; /* no need to include this when cutting+pasting */ +} + diff --git a/toolkit/components/aboutmemory/content/aboutMemory.js b/toolkit/components/aboutmemory/content/aboutMemory.js index 8285ad659fde..ed61f9f8c883 100644 --- a/toolkit/components/aboutmemory/content/aboutMemory.js +++ b/toolkit/components/aboutmemory/content/aboutMemory.js @@ -222,9 +222,17 @@ function update() "
"; // Generate verbosity option link at the bottom. + text += "
"; text += gVerbose ? "Less verbose" : "More verbose"; + text += "
"; + + text += "
" + + "Hover the pointer over the name of a memory " + + "reporter to see a detailed description of what it measures." + "
"; + var div = document.createElement("div"); div.innerHTML = text; @@ -609,7 +617,7 @@ function genMrNameText(aKind, aDesc, aName, aHasProblem) "Warning: this memory reporter was unable to compute a useful value. " + "The reported value is the sum of all entries below '" + aName + "', " + "which is probably less than the true value."; - var text = "-- " + aName + ""; text += aHasProblem @@ -725,7 +733,7 @@ function genTreeText(aT) "heap), and therefore it is the single best number to focus on when " + "trying to reduce memory usage."; - return "

Explicit Allocations

\n" + "
" + text + "
\n"; } @@ -779,7 +787,7 @@ function genOtherText(aTmrs) // Nb: the newlines give nice spacing if we cut+paste into a text buffer. const desc = "This list contains other memory measurements that cross-cut " + "the requested memory measurements above." - return "

Other Measurements

\n" + + return "

Other Measurements

\n" + "
" + text + "
\n"; } From 0f28436b065fed2b4f0c235d6424c2a655365357 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sun, 22 May 2011 19:50:09 -0700 Subject: [PATCH 094/145] Fix Windows bustage. r=hate-windows.h-macros --- js/src/vm/Stack-inl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 740aacb99339..e28efcb71846 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -42,7 +42,7 @@ #define Stack_inl_h__ #include "jscntxt.h" -#include "jstracer.h" +#include "jscompartment.h" #include "Stack.h" From 9d540ee86fee97b2965275797c1a24585b5c31dd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 22 May 2011 19:50:14 -0700 Subject: [PATCH 095/145] Bug 649867 - Remove the heap-used/storage/lookaside-used memory reporter. r=sdwilsh. --- storage/src/mozStorageConnection.cpp | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/storage/src/mozStorageConnection.cpp b/storage/src/mozStorageConnection.cpp index d846989f263c..2b581deef9b4 100644 --- a/storage/src/mozStorageConnection.cpp +++ b/storage/src/mozStorageConnection.cpp @@ -335,7 +335,6 @@ public: NS_DECL_ISUPPORTS enum ReporterType { - LookAside_Used, Cache_Used, Schema_Used, Stmt_Used @@ -356,10 +355,7 @@ public: path.AppendLiteral("explicit/storage/sqlite/"); path.Append(mDBConn.getFilename()); - if (mType == LookAside_Used) { - path.AppendLiteral("/lookaside-used"); - } - else if (mType == Cache_Used) { + if (mType == Cache_Used) { path.AppendLiteral("/cache-used"); } else if (mType == Schema_Used) { @@ -381,10 +377,7 @@ public: NS_IMETHOD GetDescription(char **desc) { - if (mType == LookAside_Used) { - *desc = ::strdup("Number of lookaside memory slots currently checked out."); - } - else if (mType == Cache_Used) { + if (mType == Cache_Used) { *desc = ::strdup("Memory (approximate) used by all pager caches."); } else if (mType == Schema_Used) { @@ -400,10 +393,7 @@ public: NS_IMETHOD GetMemoryUsed(PRInt64 *memoryUsed) { int type = 0; - if (mType == LookAside_Used) { - type = SQLITE_DBSTATUS_LOOKASIDE_USED; - } - else if (mType == Cache_Used) { + if (mType == Cache_Used) { type = SQLITE_DBSTATUS_CACHE_USED; } else if (mType == Schema_Used) { @@ -583,12 +573,6 @@ Connection::initialize(nsIFile *aDatabaseFile, } nsRefPtr reporter; -#if 0 - // FIXME: Bug 649867 explains why this is disabled. - reporter = - new StorageMemoryReporter(*this, StorageMemoryReporter::LookAside_Used); - mMemoryReporters.AppendElement(reporter); -#endif reporter = new StorageMemoryReporter(*this, StorageMemoryReporter::Cache_Used); From 92d71c95f27875994cfbf30bbf19c9057cb74522 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sun, 22 May 2011 19:50:47 -0700 Subject: [PATCH 096/145] Silence mega-spammy build warning on Windows. r=class-to-struct --- js/src/jsgc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 92a00a643388..090412c99a98 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -130,7 +130,7 @@ struct ArenaHeader { FreeCell *freeList; unsigned thingKind; - friend class FreeLists; + friend struct FreeLists; public: inline uintptr_t address() const; From 3ca701af546198e0854b11005e2fab99ba4eba32 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Mon, 23 May 2011 09:38:21 -0700 Subject: [PATCH 097/145] Add test, bug 614688. r=Waldo --- js/src/jit-test/tests/basic/bug614688.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 js/src/jit-test/tests/basic/bug614688.js diff --git a/js/src/jit-test/tests/basic/bug614688.js b/js/src/jit-test/tests/basic/bug614688.js new file mode 100644 index 000000000000..c075cadab8f6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug614688.js @@ -0,0 +1,7 @@ +function Foo() { + u = 0; +} + +var x = new Foo(); +assertEq(Object.getPrototypeOf(x) === Foo.prototype, true); +assertEq(Object.getPrototypeOf(x) === Object.prototype, false); From 341d22ca2226c3de884e02f561286a4b47e27404 Mon Sep 17 00:00:00 2001 From: Chris Leary Date: Mon, 23 May 2011 13:04:47 -0700 Subject: [PATCH 098/145] Remove accidental file addition. (r=khuey) --- jsgc-study.js | 316 -------------------------------------------------- 1 file changed, 316 deletions(-) delete mode 100644 jsgc-study.js diff --git a/jsgc-study.js b/jsgc-study.js deleted file mode 100644 index 3eda1bfaaaff..000000000000 --- a/jsgc-study.js +++ /dev/null @@ -1,316 +0,0 @@ -// chrome://testpilot/content/debug.html - -/* - * JS GC study: a TestPilot study to monitor GC frequency and duration. - * This will work on any operating system where ctypes can find the symbols it - * requires in the shared objects/DLLs. - * - * The JS runtime has a gcInfoEnabled value that is initialized to false when - * the runtime is initialized (i.e. on browser startup). Installing the - * GCObserver enables it, and uninstalling disables it. In the event of a - * crash, the next startup will proceed in the usual fashion: if this study - * gets loaded and the GCObserver gets installed, then the value will be set to - * true and data will start being collected. - */ - -BaseClasses = require("study_base_classes.js"); - -// experimentInfo is an obect providing metadata about the study. -exports.experimentInfo = { - - testName: "JavaScript memory usage", - testId: 1717, - testInfoUrl: "https://", // URL of page explaining your study - summary: "This study aims to explore how well JavaScript manages memory over time. " + - "It will periodically collect data on the browser's JavaScript memory " + - "reclamation performance.", - thumbnail: "http://", // URL of image representing your study - // (will be displayed at 90px by 90px) - versionNumber: 1, // update this when changing your study - // so you can identify results submitted from different versions - - duration: 1, // a number of days - fractions OK. - minTPVersion: "1.0", // Test Pilot versions older than this - // will not run the study. - minFXVersion: "4.0b1", // Firefox versions older than this will - // not run the study. - - // For studies that automatically recur: - recursAutomatically: false, - recurrenceInterval: 60, // also in days - - // When the study starts: - startDate: null, // null means "start immediately". - optInRequired: false // opt-in studies not yet implemented -}; - -var GCInfoStructFields = [ - {name: 'appTime', kind: 'double', desc: 'Elapsed application time'}, - {name: 'gcTime', kind: 'double', desc: 'Total time to perform garbage collection'}, - {name: 'waitTime', kind: 'double', desc: 'GC start wait time'}, - {name: 'markTime', kind: 'double', desc: 'JS entity traversal time'}, - {name: 'sweepTime', kind: 'double', desc: 'JS entity destruction time'}, - {name: 'sweepObjTime', kind: 'double', desc: 'JS object destruction time'}, - {name: 'sweepStringTime', kind: 'double', desc: 'JS string destruction time'}, - {name: 'sweepShapeTime', kind: 'double', desc: 'JS shape destruction time'}, - {name: 'destroyTime', kind: 'double', desc: 'Heap arena destruction time'}, - {name: 'endTime', kind: 'double', desc: 'GC end wait time'}, - {name: 'isCompartmental', kind: 'bool', desc: 'GC is compartmental'}, -]; - -const GCInfoStructFieldNames = [field.name for each (field in GCInfoStructFields)] - -function makeCTypeProps(ctypes, fields) { - const kindToCType = { - double: ctypes.float64_t, - bool: ctypes.bool, - }; - let attrs = []; - for each (field in fields) { - let record = {}; - record[field.name] = kindToCType[field.kind]; - attrs.push(record); - } - return attrs; -} - -function makeColumns(fields) { - const kindToType = { - double: BaseClasses.TYPE_DOUBLE, - bool: BaseClasses.TYPE_INT_32, - }; - let columns = []; - for each (field in fields) - columns.push({property: field.name, type: kindToType[field.kind], displayName: field.desc}); - return columns; -} - -function zipObj(names, values) { - let o = {}; - for (let i in names) - o[names[i]] = values[i]; - return o; -} - -exports.dataStoreInfo = { - fileName: "testpilot_jsgc_results.sqlite", - tableName: "jsgc_info", - columns: makeColumns(GCInfoStructFields), -}; - -function GCGlobalObserver() { - GCGlobalObserver.baseConstructor.call(this); -} - -BaseClasses.extend(GCGlobalObserver, BaseClasses.GenericGlobalObserver); - -GCGlobalObserver.prototype.onExperimentStartup = function(store) { - GCGlobalObserver.superClass.onExperimentStartup.call(this, store); - - dump('Installing GC observer\n'); - try { - this.gcObserver = GCObserver.install(store); - } catch (e) { - this.console.debug('Exception during install: ' + e); - } - dump('Done installing GC observer\n'); -}; - -GCGlobalObserver.prototype.getStudyMetadata = function() { - return [{droppedGCInfoCount: this.gcObserver.dropCount}]; -}; - -GCGlobalObserver.prototype.onExperimentShutdown = function(store) { - GCGlobalObserver.superClass.onExperimentShutdown.call(this, store); - if (this.gcObserver) - this.gcObserver.uninstall(); -}; - -// Called when the study is over or has been cancelled. -GCGlobalObserver.prototype.doExperimentCleanup = function() { - // Nothing to do. -}; - -// Instantiate and export the global observer (required!) -exports.handlers = new GCGlobalObserver(); - -// Defines what will show up on the study detail view page. -function JSGCWebContent() { - JSGCWebContent.baseConstructor.call(this, exports.experimentInfo); -} - -BaseClasses.extend(JSGCWebContent, BaseClasses.GenericWebContent); - -JSGCWebContent.prototype.__defineGetter__("dataCanvas", - function() { - return '

View Your Data:

' + - this.dataViewExplanation + - this.rawDataLink + - '
' + - this.saveButtons + '
'; - }); - -JSGCWebContent.prototype.__defineGetter__("dataViewExplanation", - function() { - return "This plot shows the garbage collection duration during the course of the application's lifetime."; - }); - -// This function is called when the experiment page load is done -JSGCWebContent.prototype.onPageLoad = function(experiment, - document, - graphUtils) { - experiment.getDataStoreAsJSON(function(rawData) { - - let compartmental = []; - let full = []; - for each (row in rawData) { - let series = row.isCompartmental ? compartmental : full; - series.push([row.appTime, row.gcTime]); - } - let div = document.getElementById('data-plot-div'); - graphUtils.plot(div, - [ - {label: 'Compartmental GCs (ms)', - data: compartmental, - points: {show: true}}, - {label: 'Full GCs (ms)', - data: full, - points: {show: true}}, - ] - ); - }); -}; - -// Instantiate and export the web content (required!) -exports.webContent = new JSGCWebContent(); - -const GCINFO_READ_INTERVAL_SECONDS = 30; - -var GCObserver = { - alreadyInstalled : false, - selfPingInterval: GCINFO_READ_INTERVAL_SECONDS * 1000, - ctypes: null, - libxul: null, - runtime: null, - GCInfoStruct: null, - getGCInfo: null, - droppedGCInfo: null, - setGCInfoEnabled: null, - wasGCInfoEnabled: null, - store: null, - dropCount: 0, - - install: function GCObserver__install(store) { - this.debug('Installing GCObserver'); - if (this.alreadyInstalled) - return; - this.debug('Adding GCObserver'); - try { - this.createCTypes(); - } catch (e) { - this.debug('Failed to create ctypes: ' + e); - return; - } - this.store = store; - this.wasGCInfoEnabled = this.getGCInfoEnabled(this.runtime); - this.setGCInfoEnabled(this.runtime, true); - if (!this.getGCInfoEnabled(this.runtime)) { - throw new Error('GC info could not be enabled'); - } - /* Once GC info has been successfully enabled, we are able to uninstall. */ - this.debug('Successfully enabled'); - this.alreadyInstalled = true; - this.debug('Initiating self-ping'); - this.selfPingTimer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer); - this.pingSelf(); - this.debug('Finished installing'); - }, - - uninstall: function GCObserver__uninstall() { - if (!this.alreadyInstalled) - return; - if (this.selfPingTimer) - this.selfPingTimer.cancel(); - this.selfPingTimer = null; - this.setGCInfoEnabled(this.wasGCInfoEnabled); - this.alreadyInstalled = false; - }, - - debug: function GCObserver__debug(msg) { - dump('//// ' + msg + '\n'); - }, - - recordGCInfo: function GCObserver__alwaysRecord(fieldContents) { - this.debug('Fields: ' + fieldContents.join(' ')); - this.store.storeEvent(zipObj(GCInfoStructFieldNames, fieldContents)); - }, - - tryFindLibXUL: function GCObserver__tryFindLibXUL(ctypes) { - try { return ctypes.open(ctypes.libraryName('xul')); } catch (e) {} - try { return ctypes.open(ctypes.libraryName('mozjs')); } catch (e) {} - throw new Error('could not find SpiderMonkey dll'); - }, - - createCTypes: function GCObserver__createCTypes() { - Components.utils.import('resource://gre/modules/ctypes.jsm'); - this.ctypes = ctypes; - let libxul = this.tryFindLibXUL(ctypes); - this.libxul = libxul; - this.runtime = ctypes.getRuntime(ctypes.voidptr_t); - let GCInfo = this.createGCInfoStruct(); - this.getGCInfo = libxul.declare('JS_GCInfoFront', ctypes.default_abi, GCInfo.ptr, ctypes.voidptr_t); - this.popGCInfo = libxul.declare('JS_GCInfoPopFront', ctypes.default_abi, ctypes.bool, ctypes.voidptr_t); - this.setGCInfoEnabled = libxul.declare('JS_SetGCInfoEnabled', ctypes.default_abi, ctypes.void_t, ctypes.voidptr_t, ctypes.bool); - this.getGCInfoEnabled = libxul.declare('JS_GetGCInfoEnabled', ctypes.default_abi, ctypes.bool, ctypes.voidptr_t); - }, - - createGCInfoStruct: function GCObserver__createGCInfoStruct() { - let ctypes = this.ctypes; - let GCInfoStruct = this.GCInfoStruct = new ctypes.StructType('GCInfo', makeCTypeProps(ctypes, GCInfoStructFields)); - GCInfoStruct.ptr = new ctypes.PointerType(GCInfoStruct); - return GCInfoStruct; - }, - - pingSelf: function GCObserver__pingSelf() { - let self = this; - const TYPE_ONE_SHOT = 0; - const TYPE_REPEATING_SLACK = 1; - this.selfPingTimer.initWithCallback(function dumpAndRepeat() { - self.dumpGCInfos(); - self.pingSelf(); - }, this.selfPingInterval, TYPE_ONE_SHOT); - }, - - dumpGCInfos: function GCObserver__dumpGCInfos() { - let self = this; - let debug = this.debug; - - let rt = this.runtime; - - debug('Dumping GC infos'); - for (var i = 0;; i++) { - debug('Getting GCInfo'); - let info = this.getGCInfo(rt); - debug('GCInfo: ' + info); - - if (info.isNull()) { - debug('Breaking due to null'); - break; - } - - /* Copy info contents into a temporary object so we can pop the info as quickly as possible. */ - let c = info.contents; - let data = [c[name] for each (name in GCInfoStructFieldNames)] - - let dropped = this.popGCInfo(rt); - if (dropped) { - debug('Dropped!'); - ++this.dropCount; - break; - } - - self.recordGCInfo(data); - } - debug ('Saw ' + i + ' entries'); - } -}; From 4e66bd9998f5d6a74aa206d3194a60671f5cd39c Mon Sep 17 00:00:00 2001 From: David Mandelin Date: Thu, 12 May 2011 18:39:47 -0700 Subject: [PATCH 099/145] Bug 625600: Update Yarr import to WebKit rev 83339, r=cdleary,dvander --- js/src/Makefile.in | 37 +- .../assembler/AbstractMacroAssembler.h | 63 +- js/src/assembler/assembler/MacroAssembler.h | 12 +- .../assembler/assembler/MacroAssemblerARM.cpp | 2 +- .../assembler/assembler/MacroAssemblerARM.h | 50 +- .../assembler/assembler/MacroAssemblerARMv7.h | 44 +- .../assembler/MacroAssemblerCodeRef.h | 17 +- .../assembler/assembler/MacroAssemblerSparc.h | 48 +- .../assembler/assembler/MacroAssemblerX86.h | 14 +- .../assembler/MacroAssemblerX86Common.h | 44 +- .../assembler/MacroAssemblerX86_64.h | 16 +- js/src/assembler/jit/ExecutableAllocator.h | 20 +- .../assembler/jit/ExecutableAllocatorOS2.cpp | 2 +- .../jit/ExecutableAllocatorPosix.cpp | 4 +- .../jit/ExecutableAllocatorSymbian.cpp | 2 +- .../assembler/jit/ExecutableAllocatorWin.cpp | 2 +- js/src/assembler/wtf/Platform.h | 981 ++++-- .../jit-test/tests/basic/bug632964-regexp.js | 3 - js/src/jscompartment.cpp | 11 +- js/src/jscompartment.h | 10 +- js/src/jsregexp.cpp | 46 +- js/src/jsregexpinlines.h | 119 +- js/src/jsutil.h | 10 + js/src/jsvector.h | 22 +- js/src/methodjit/Compiler.cpp | 10 +- js/src/methodjit/MethodJIT.cpp | 7 +- js/src/methodjit/TrampolineCompiler.cpp | 2 +- js/src/yarr/{wtf => }/ASCIICType.h | 33 +- js/src/yarr/BumpPointerAllocator.h | 254 ++ js/src/yarr/Makefile | 5 - js/src/yarr/OSAllocator.h | 103 + js/src/yarr/OSAllocatorPosix.cpp | 129 + js/src/yarr/OSAllocatorWin.cpp | 89 + js/src/yarr/PageAllocation.h | 131 + js/src/yarr/PageBlock.cpp | 88 + js/src/yarr/PageBlock.h | 91 + js/src/yarr/{yarr => }/RegExpJitTables.h | 0 js/src/yarr/VMTags.h | 90 + js/src/yarr/Yarr.h | 72 + js/src/yarr/YarrInterpreter.cpp | 1914 +++++++++++ js/src/yarr/YarrInterpreter.h | 380 +++ js/src/yarr/YarrJIT.cpp | 2405 +++++++++++++ js/src/yarr/YarrJIT.h | 93 + .../yarr/{yarr/RegexParser.h => YarrParser.h} | 262 +- .../RegexCompiler.cpp => YarrPattern.cpp} | 572 +++- .../{yarr/RegexPattern.h => YarrPattern.h} | 218 +- .../RegexCommon.h => YarrSyntaxChecker.cpp} | 56 +- .../RegexCompiler.h => YarrSyntaxChecker.h} | 25 +- js/src/yarr/jswtfbridge.h | 61 - js/src/yarr/pcre/AUTHORS | 12 - js/src/yarr/pcre/COPYING | 35 - js/src/yarr/pcre/chartables.c | 96 - js/src/yarr/pcre/dftables | 273 -- js/src/yarr/pcre/pcre.h | 68 - js/src/yarr/pcre/pcre.pri | 12 - js/src/yarr/pcre/pcre_compile.cpp | 2702 --------------- js/src/yarr/pcre/pcre_exec.cpp | 2193 ------------ js/src/yarr/pcre/pcre_internal.h | 434 --- js/src/yarr/pcre/pcre_tables.cpp | 71 - js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp | 98 - js/src/yarr/pcre/pcre_xclass.cpp | 114 - js/src/yarr/pcre/ucpinternal.h | 126 - js/src/yarr/pcre/ucptable.cpp | 2968 ----------------- js/src/yarr/wtfbridge.h | 321 ++ js/src/yarr/yarr/RegexJIT.cpp | 1589 --------- js/src/yarr/yarr/RegexJIT.h | 112 - toolkit/content/license.html | 2 +- 67 files changed, 7872 insertions(+), 12023 deletions(-) rename js/src/yarr/{wtf => }/ASCIICType.h (81%) create mode 100644 js/src/yarr/BumpPointerAllocator.h delete mode 100644 js/src/yarr/Makefile create mode 100644 js/src/yarr/OSAllocator.h create mode 100644 js/src/yarr/OSAllocatorPosix.cpp create mode 100644 js/src/yarr/OSAllocatorWin.cpp create mode 100644 js/src/yarr/PageAllocation.h create mode 100644 js/src/yarr/PageBlock.cpp create mode 100644 js/src/yarr/PageBlock.h rename js/src/yarr/{yarr => }/RegExpJitTables.h (100%) create mode 100644 js/src/yarr/VMTags.h create mode 100644 js/src/yarr/Yarr.h create mode 100644 js/src/yarr/YarrInterpreter.cpp create mode 100644 js/src/yarr/YarrInterpreter.h create mode 100644 js/src/yarr/YarrJIT.cpp create mode 100644 js/src/yarr/YarrJIT.h rename js/src/yarr/{yarr/RegexParser.h => YarrParser.h} (81%) rename js/src/yarr/{yarr/RegexCompiler.cpp => YarrPattern.cpp} (52%) rename js/src/yarr/{yarr/RegexPattern.h => YarrPattern.h} (70%) rename js/src/yarr/{yarr/RegexCommon.h => YarrSyntaxChecker.cpp} (52%) rename js/src/yarr/{yarr/RegexCompiler.h => YarrSyntaxChecker.h} (74%) delete mode 100644 js/src/yarr/jswtfbridge.h delete mode 100644 js/src/yarr/pcre/AUTHORS delete mode 100644 js/src/yarr/pcre/COPYING delete mode 100644 js/src/yarr/pcre/chartables.c delete mode 100644 js/src/yarr/pcre/dftables delete mode 100644 js/src/yarr/pcre/pcre.h delete mode 100644 js/src/yarr/pcre/pcre.pri delete mode 100644 js/src/yarr/pcre/pcre_compile.cpp delete mode 100644 js/src/yarr/pcre/pcre_exec.cpp delete mode 100644 js/src/yarr/pcre/pcre_internal.h delete mode 100644 js/src/yarr/pcre/pcre_tables.cpp delete mode 100644 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp delete mode 100644 js/src/yarr/pcre/pcre_xclass.cpp delete mode 100644 js/src/yarr/pcre/ucpinternal.h delete mode 100644 js/src/yarr/pcre/ucptable.cpp create mode 100644 js/src/yarr/wtfbridge.h delete mode 100644 js/src/yarr/yarr/RegexJIT.cpp delete mode 100644 js/src/yarr/yarr/RegexJIT.h diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 8023b1750b05..71f35a53d881 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -362,7 +362,6 @@ CPPSRCS += MethodJIT.cpp \ Retcon.cpp \ TrampolineCompiler.cpp \ $(NULL) -# PICStubCompiler.cpp \ ifeq (86, $(findstring 86,$(TARGET_CPU))) ifeq (x86_64, $(TARGET_CPU)) @@ -420,14 +419,17 @@ ifeq (,$(filter arm% sparc %86 x86_64,$(TARGET_CPU))) VPATH += $(srcdir)/assembler \ $(srcdir)/assembler/wtf \ - $(srcdir)/yarr/pcre \ + $(srcdir)/yarr\ $(NULL) -CPPSRCS += pcre_compile.cpp \ - pcre_exec.cpp \ - pcre_tables.cpp \ - pcre_xclass.cpp \ - pcre_ucp_searchfuncs.cpp \ +CPPSRCS += \ + Assertions.cpp \ + OSAllocatorPosix.cpp \ + OSAllocatorWin.cpp \ + PageBlock.cpp \ + YarrInterpreter.cpp \ + YarrPattern.cpp \ + YarrSyntaxChecker.cpp \ $(NULL) else @@ -440,9 +442,6 @@ VPATH += $(srcdir)/assembler \ $(srcdir)/assembler/assembler \ $(srcdir)/methodjit \ $(srcdir)/yarr \ - $(srcdir)/yarr/yarr \ - $(srcdir)/yarr/pcre \ - $(srcdir)/yarr/wtf \ $(NONE) CPPSRCS += Assertions.cpp \ @@ -451,16 +450,16 @@ CPPSRCS += Assertions.cpp \ ExecutableAllocatorOS2.cpp \ ExecutableAllocator.cpp \ ARMAssembler.cpp \ - Logging.cpp \ + Logging.cpp \ MacroAssemblerARM.cpp \ MacroAssemblerX86Common.cpp \ - RegexCompiler.cpp \ - RegexJIT.cpp \ - pcre_compile.cpp \ - pcre_exec.cpp \ - pcre_tables.cpp \ - pcre_xclass.cpp \ - pcre_ucp_searchfuncs.cpp \ + OSAllocatorPosix.cpp \ + OSAllocatorWin.cpp \ + PageBlock.cpp \ + YarrInterpreter.cpp \ + YarrJIT.cpp \ + YarrPattern.cpp \ + YarrSyntaxChecker.cpp \ $(NONE) ifeq (86, $(findstring 86,$(TARGET_CPU))) @@ -653,7 +652,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL # We desire these numbers to go down, not up. See "User guide to memory # management within SpiderMonkey" in jsutil.h. - $(srcdir)/config/check_source_count.py OffTheBooks:: 52 \ + $(srcdir)/config/check_source_count.py OffTheBooks:: 54 \ "in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^ # This should go to zero, if possible. $(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \ diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h index 260380acd307..3c14c80bd4b0 100644 --- a/js/src/assembler/assembler/AbstractMacroAssembler.h +++ b/js/src/assembler/assembler/AbstractMacroAssembler.h @@ -166,13 +166,13 @@ public: void* m_ptr; }; - // ImmPtr: + // TrustedImmPtr: // // A pointer sized immediate operand to an instruction - this is wrapped // in a class requiring explicit construction in order to differentiate // from pointers used as absolute addresses to memory operations - struct ImmPtr { - explicit ImmPtr(const void* value) + struct TrustedImmPtr { + explicit TrustedImmPtr(const void* value) : m_value(value) { } @@ -185,14 +185,21 @@ public: const void* m_value; }; - // Imm32: + struct ImmPtr : public TrustedImmPtr { + explicit ImmPtr(const void* value) + : TrustedImmPtr(value) + { + } + }; + + // TrustedImm32: // // A 32bit immediate operand to an instruction - this is wrapped in a // class requiring explicit construction in order to prevent RegisterIDs // (which are implemented as an enum) from accidentally being passed as // immediate values. - struct Imm32 { - explicit Imm32(int32_t value) + struct TrustedImm32 { + explicit TrustedImm32(int32_t value) : m_value(value) #if WTF_CPU_ARM || WTF_CPU_MIPS , m_isPointer(false) @@ -201,7 +208,7 @@ public: } #if !WTF_CPU_X86_64 - explicit Imm32(ImmPtr ptr) + explicit TrustedImm32(TrustedImmPtr ptr) : m_value(ptr.asIntptr()) #if WTF_CPU_ARM || WTF_CPU_MIPS , m_isPointer(true) @@ -223,6 +230,20 @@ public: #endif }; + + struct Imm32 : public TrustedImm32 { + explicit Imm32(int32_t value) + : TrustedImm32(value) + { + } +#if !WTF_CPU_X86_64 + explicit Imm32(TrustedImmPtr ptr) + : TrustedImm32(ptr) + { + } +#endif + }; + struct ImmDouble { union { struct { @@ -241,7 +262,6 @@ public: } }; - // Section 2: MacroAssembler code buffer handles // // The following types are used to reference items in the code buffer @@ -273,7 +293,7 @@ public: bool isUsed() const { return m_label.isUsed(); } void used() { m_label.used(); } - bool isValid() const { return m_label.isValid(); } + bool isSet() const { return m_label.isValid(); } private: JmpDst m_label; }; @@ -296,6 +316,8 @@ public: { } + bool isSet() const { return m_label.isValid(); } + private: JmpDst m_label; }; @@ -411,6 +433,20 @@ public: public: typedef js::Vector JumpVector; + JumpList() {} + + JumpList(const JumpList &other) + { + m_jumps.append(other.m_jumps); + } + + JumpList &operator=(const JumpList &other) + { + m_jumps.clear(); + m_jumps.append(other.m_jumps); + return *this; + } + void link(AbstractMacroAssembler* masm) { size_t size = m_jumps.length(); @@ -432,17 +468,22 @@ public: m_jumps.append(jump); } - void append(JumpList& other) + void append(const JumpList& other) { m_jumps.append(other.m_jumps.begin(), other.m_jumps.length()); } + void clear() + { + m_jumps.clear(); + } + bool empty() { return !m_jumps.length(); } - const JumpVector& jumps() { return m_jumps; } + const JumpVector& jumps() const { return m_jumps; } private: JumpVector m_jumps; diff --git a/js/src/assembler/assembler/MacroAssembler.h b/js/src/assembler/assembler/MacroAssembler.h index 73bda22a8ee2..38d5a31a2590 100644 --- a/js/src/assembler/assembler/MacroAssembler.h +++ b/js/src/assembler/assembler/MacroAssembler.h @@ -95,12 +95,12 @@ public: storePtr(src, Address(stackPointerRegister, (index * sizeof(void*)))); } - void poke(Imm32 value, int index = 0) + void poke(TrustedImm32 value, int index = 0) { store32(value, Address(stackPointerRegister, (index * sizeof(void*)))); } - void poke(ImmPtr imm, int index = 0) + void poke(TrustedImmPtr imm, int index = 0) { storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*)))); } @@ -117,7 +117,7 @@ public: branch32(cond, op1, op2).linkTo(target, this); } - void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target) + void branch32(Condition cond, RegisterID op1, TrustedImm32 imm, Label target) { branch32(cond, op1, imm).linkTo(target, this); } @@ -288,17 +288,17 @@ public: store32(src, address); } - void storePtr(ImmPtr imm, ImplicitAddress address) + void storePtr(TrustedImmPtr imm, ImplicitAddress address) { store32(Imm32(imm), address); } - void storePtr(ImmPtr imm, BaseIndex address) + void storePtr(TrustedImmPtr imm, BaseIndex address) { store32(Imm32(imm), address); } - void storePtr(ImmPtr imm, void* address) + void storePtr(TrustedImmPtr imm, void* address) { store32(Imm32(imm), address); } diff --git a/js/src/assembler/assembler/MacroAssemblerARM.cpp b/js/src/assembler/assembler/MacroAssemblerARM.cpp index 14b4166b7ea9..065c98197395 100644 --- a/js/src/assembler/assembler/MacroAssemblerARM.cpp +++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp @@ -34,7 +34,7 @@ #include "MacroAssemblerARM.h" -#if WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID +#if WTF_OS_LINUX || WTF_OS_ANDROID #include #include #include diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h index 7413411f4500..2630bce7a909 100644 --- a/js/src/assembler/assembler/MacroAssemblerARM.h +++ b/js/src/assembler/assembler/MacroAssemblerARM.h @@ -91,14 +91,14 @@ public: m_assembler.adds_r(dest, dest, src); } - void add32(Imm32 imm, Address address) + void add32(TrustedImm32 imm, Address address) { load32(address, ARMRegisters::S1); add32(imm, ARMRegisters::S1); store32(ARMRegisters::S1, address); } - void add32(Imm32 imm, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID dest) { m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } @@ -173,7 +173,7 @@ public: m_assembler.orrs_r(dest, dest, src); } - void or32(Imm32 imm, RegisterID dest) + void or32(TrustedImm32 imm, RegisterID dest) { m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } @@ -211,12 +211,12 @@ public: m_assembler.subs_r(dest, dest, src); } - void sub32(Imm32 imm, RegisterID dest) + void sub32(TrustedImm32 imm, RegisterID dest) { m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } - void sub32(Imm32 imm, Address address) + void sub32(TrustedImm32 imm, Address address) { load32(address, ARMRegisters::S1); sub32(imm, ARMRegisters::S1); @@ -240,7 +240,7 @@ public: m_assembler.eors_r(dest, dest, src); } - void xor32(Imm32 imm, RegisterID dest) + void xor32(TrustedImm32 imm, RegisterID dest) { m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } @@ -380,7 +380,7 @@ public: m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset); } - void store32(Imm32 imm, BaseIndex address) + void store32(TrustedImm32 imm, BaseIndex address) { if (imm.m_isPointer) m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); @@ -389,7 +389,7 @@ public: store32(ARMRegisters::S1, address); } - void store32(Imm32 imm, ImplicitAddress address) + void store32(TrustedImm32 imm, ImplicitAddress address) { if (imm.m_isPointer) m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); @@ -404,7 +404,7 @@ public: m_assembler.dtr_u(false, src, ARMRegisters::S0, 0); } - void store32(Imm32 imm, void* address) + void store32(TrustedImm32 imm, void* address) { m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); if (imm.m_isPointer) @@ -436,7 +436,7 @@ public: push(ARMRegisters::S0); } - void move(Imm32 imm, RegisterID dest) + void move(TrustedImm32 imm, RegisterID dest) { if (imm.m_isPointer) m_assembler.ldr_un_imm(dest, imm.m_value); @@ -449,7 +449,7 @@ public: m_assembler.mov_r(dest, src); } - void move(ImmPtr imm, RegisterID dest) + void move(TrustedImmPtr imm, RegisterID dest) { move(Imm32(imm), dest); } @@ -485,7 +485,7 @@ public: return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); } - Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0) + Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0) { ASSERT(left != ARMRegisters::S0); if (right.m_isPointer) { @@ -500,21 +500,21 @@ public: // number of instructions emitted is constant, regardless of the argument // values. For ARM, this is identical to branch32WithPatch, except that it // does not generate a DataLabel32. - Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right) + Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right) { m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value); return branch32(cond, left, ARMRegisters::S1, true); } // As branch32_force32, but allow the value ('right') to be patched. - Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel) + Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel) { ASSERT(left != ARMRegisters::S1); dataLabel = moveWithPatch(right, ARMRegisters::S1); return branch32(cond, left, ARMRegisters::S1, true); } - Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel) + Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel) { ASSERT(left.base != ARMRegisters::S1); load32(left, ARMRegisters::S1); @@ -534,19 +534,19 @@ public: return branch32(cond, ARMRegisters::S1, right); } - Jump branch32(Condition cond, Address left, Imm32 right) + Jump branch32(Condition cond, Address left, TrustedImm32 right) { load32(left, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); } - Jump branch32(Condition cond, BaseIndex left, Imm32 right) + Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) { load32(left, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); } - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) { load32WithUnalignedHalfWords(left, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); @@ -828,7 +828,7 @@ public: setTest32(cond, address, mask, dest); } - void add32(Imm32 imm, RegisterID src, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } @@ -850,7 +850,7 @@ public: move(ARMRegisters::S1, dest); } - void add32(Imm32 imm, AbsoluteAddress address) + void add32(TrustedImm32 imm, AbsoluteAddress address) { m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr)); m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); @@ -859,7 +859,7 @@ public: m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); } - void sub32(Imm32 imm, AbsoluteAddress address) + void sub32(TrustedImm32 imm, AbsoluteAddress address) { m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr)); m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); @@ -880,7 +880,7 @@ public: return branch32(cond, ARMRegisters::S1, right); } - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) + Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) { load32(left.m_ptr, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); @@ -908,14 +908,14 @@ public: return Call::fromTailJump(oldJump); } - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) + DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) { DataLabelPtr dataLabel(this); m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value)); return dataLabel; } - DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest) + DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest) { DataLabel32 dataLabel(this); m_assembler.ldr_un_imm(dest, initialValue.m_value); @@ -937,7 +937,7 @@ public: return jump; } - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) { DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1); store32(ARMRegisters::S1, address); diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h index 5492f8246a06..c23e9ea6655f 100644 --- a/js/src/assembler/assembler/MacroAssemblerARMv7.h +++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h @@ -131,12 +131,12 @@ public: m_assembler.add(dest, dest, src); } - void add32(Imm32 imm, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID dest) { add32(imm, dest, dest); } - void add32(Imm32 imm, RegisterID src, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); if (armImm.isValid()) @@ -147,7 +147,7 @@ public: } } - void add32(Imm32 imm, Address address) + void add32(TrustedImm32 imm, Address address) { load32(address, dataTempRegister); @@ -170,7 +170,7 @@ public: add32(dataTempRegister, dest); } - void add32(Imm32 imm, AbsoluteAddress address) + void add32(TrustedImm32 imm, AbsoluteAddress address) { load32(address.m_ptr, dataTempRegister); @@ -239,7 +239,7 @@ public: m_assembler.orr(dest, dest, src); } - void or32(Imm32 imm, RegisterID dest) + void or32(TrustedImm32 imm, RegisterID dest) { ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); if (armImm.isValid()) @@ -285,7 +285,7 @@ public: m_assembler.sub(dest, dest, src); } - void sub32(Imm32 imm, RegisterID dest) + void sub32(TrustedImm32 imm, RegisterID dest) { ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); if (armImm.isValid()) @@ -296,7 +296,7 @@ public: } } - void sub32(Imm32 imm, Address address) + void sub32(TrustedImm32 imm, Address address) { load32(address, dataTempRegister); @@ -319,7 +319,7 @@ public: sub32(dataTempRegister, dest); } - void sub32(Imm32 imm, AbsoluteAddress address) + void sub32(TrustedImm32 imm, AbsoluteAddress address) { load32(address.m_ptr, dataTempRegister); @@ -341,7 +341,7 @@ public: m_assembler.eor(dest, dest, src); } - void xor32(Imm32 imm, RegisterID dest) + void xor32(TrustedImm32 imm, RegisterID dest) { ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); if (armImm.isValid()) @@ -486,7 +486,7 @@ public: store32(src, setupArmAddress(address)); } - void store32(Imm32 imm, ImplicitAddress address) + void store32(TrustedImm32 imm, ImplicitAddress address) { move(imm, dataTempRegister); store32(dataTempRegister, setupArmAddress(address)); @@ -498,7 +498,7 @@ public: m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); } - void store32(Imm32 imm, void* address) + void store32(TrustedImm32 imm, void* address) { move(imm, dataTempRegister); store32(dataTempRegister, address); @@ -667,7 +667,7 @@ public: // // Move values in registers. - void move(Imm32 imm, RegisterID dest) + void move(TrustedImm32 imm, RegisterID dest) { uint32_t value = imm.m_value; @@ -693,7 +693,7 @@ public: m_assembler.mov(dest, src); } - void move(ImmPtr imm, RegisterID dest) + void move(TrustedImmPtr imm, RegisterID dest) { move(Imm32(imm), dest); } @@ -780,7 +780,7 @@ public: return Jump(makeBranch(cond)); } - Jump branch32(Condition cond, RegisterID left, Imm32 right) + Jump branch32(Condition cond, RegisterID left, TrustedImm32 right) { compare32(left, right); return Jump(makeBranch(cond)); @@ -798,21 +798,21 @@ public: return branch32(cond, dataTempRegister, right); } - Jump branch32(Condition cond, Address left, Imm32 right) + Jump branch32(Condition cond, Address left, TrustedImm32 right) { // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ load32(left, addressTempRegister); return branch32(cond, addressTempRegister, right); } - Jump branch32(Condition cond, BaseIndex left, Imm32 right) + Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) { // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ load32(left, addressTempRegister); return branch32(cond, addressTempRegister, right); } - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) { // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ load32WithUnalignedHalfWords(left, addressTempRegister); @@ -825,7 +825,7 @@ public: return branch32(cond, dataTempRegister, right); } - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) + Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) { // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ load32(left.m_ptr, addressTempRegister); @@ -1065,13 +1065,13 @@ public: m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); } - DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst) + DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst) { moveFixedWidthEncoding(imm, dst); return DataLabel32(this); } - DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst) + DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst) { moveFixedWidthEncoding(Imm32(imm), dst); return DataLabelPtr(this); @@ -1090,7 +1090,7 @@ public: return branch32(cond, addressTempRegister, dataTempRegister); } - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) { DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister); store32(dataTempRegister, address); @@ -1179,7 +1179,7 @@ protected: return addressTempRegister; } - void moveFixedWidthEncoding(Imm32 imm, RegisterID dst) + void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst) { uint32_t value = imm.m_value; m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff)); diff --git a/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/js/src/assembler/assembler/MacroAssemblerCodeRef.h index 841fa9647128..6acdfd67a74d 100644 --- a/js/src/assembler/assembler/MacroAssemblerCodeRef.h +++ b/js/src/assembler/assembler/MacroAssemblerCodeRef.h @@ -180,7 +180,8 @@ private: class MacroAssemblerCodeRef { public: MacroAssemblerCodeRef() - : m_size(0) + : m_executablePool(NULL), + m_size(0) { } @@ -191,6 +192,20 @@ public: { } + // Release the code memory in this code ref. + void release() + { + if (!m_executablePool) + return; + +#if defined DEBUG && (defined WTF_CPU_X86 || defined WTF_CPU_X86_64) + void *addr = m_code.executableAddress(); + memset(addr, 0xcc, m_size); +#endif + m_executablePool->release(); + m_executablePool = NULL; + } + MacroAssemblerCodePtr m_code; ExecutablePool* m_executablePool; size_t m_size; diff --git a/js/src/assembler/assembler/MacroAssemblerSparc.h b/js/src/assembler/assembler/MacroAssemblerSparc.h index 3bdd2d871b1b..91a8f0e16163 100644 --- a/js/src/assembler/assembler/MacroAssemblerSparc.h +++ b/js/src/assembler/assembler/MacroAssemblerSparc.h @@ -97,14 +97,14 @@ namespace JSC { m_assembler.addcc_r(dest, src, dest); } - void add32(Imm32 imm, Address address) + void add32(TrustedImm32 imm, Address address) { load32(address, SparcRegisters::g2); add32(imm, SparcRegisters::g2); store32(SparcRegisters::g2, address); } - void add32(Imm32 imm, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID dest) { if (m_assembler.isimm13(imm.m_value)) m_assembler.addcc_imm(dest, imm.m_value, dest); @@ -126,7 +126,7 @@ namespace JSC { m_assembler.andcc_r(dest, SparcRegisters::g2, dest); } - void add32(Imm32 imm, RegisterID src, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { if (m_assembler.isimm13(imm.m_value)) m_assembler.addcc_imm(src, imm.m_value, dest); @@ -194,7 +194,7 @@ namespace JSC { m_assembler.orcc_r(dest, src, dest); } - void or32(Imm32 imm, RegisterID dest) + void or32(TrustedImm32 imm, RegisterID dest) { if (m_assembler.isimm13(imm.m_value)) m_assembler.orcc_imm(dest, imm.m_value, dest); @@ -240,7 +240,7 @@ namespace JSC { m_assembler.subcc_r(dest, src, dest); } - void sub32(Imm32 imm, RegisterID dest) + void sub32(TrustedImm32 imm, RegisterID dest) { if (m_assembler.isimm13(imm.m_value)) m_assembler.subcc_imm(dest, imm.m_value, dest); @@ -250,7 +250,7 @@ namespace JSC { } } - void sub32(Imm32 imm, Address address) + void sub32(TrustedImm32 imm, Address address) { load32(address, SparcRegisters::g2); sub32(imm, SparcRegisters::g2); @@ -268,7 +268,7 @@ namespace JSC { m_assembler.xorcc_r(src, dest, dest); } - void xor32(Imm32 imm, RegisterID dest) + void xor32(TrustedImm32 imm, RegisterID dest) { if (m_assembler.isimm13(imm.m_value)) m_assembler.xorcc_imm(dest, imm.m_value, dest); @@ -548,7 +548,7 @@ namespace JSC { m_assembler.stw_r(src, address.base, SparcRegisters::g2); } - void store32(Imm32 imm, BaseIndex address) + void store32(TrustedImm32 imm, BaseIndex address) { m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2); add32(Imm32(address.offset), SparcRegisters::g2); @@ -556,7 +556,7 @@ namespace JSC { m_assembler.stw_r(SparcRegisters::g3, SparcRegisters::g2, address.base); } - void store32(Imm32 imm, ImplicitAddress address) + void store32(TrustedImm32 imm, ImplicitAddress address) { m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2); store32(SparcRegisters::g2, address); @@ -568,7 +568,7 @@ namespace JSC { m_assembler.stw_r(src, SparcRegisters::g0, SparcRegisters::g3); } - void store32(Imm32 imm, void* address) + void store32(TrustedImm32 imm, void* address) { move(imm, SparcRegisters::g2); store32(SparcRegisters::g2, address); @@ -598,7 +598,7 @@ namespace JSC { push(SparcRegisters::g2); } - void move(Imm32 imm, RegisterID dest) + void move(TrustedImm32 imm, RegisterID dest) { if (m_assembler.isimm13(imm.m_value)) m_assembler.or_imm(SparcRegisters::g0, imm.m_value, dest); @@ -611,7 +611,7 @@ namespace JSC { m_assembler.or_r(src, SparcRegisters::g0, dest); } - void move(ImmPtr imm, RegisterID dest) + void move(TrustedImmPtr imm, RegisterID dest) { move(Imm32(imm), dest); } @@ -641,20 +641,20 @@ namespace JSC { return branch32(cond, SparcRegisters::g2, right); } - Jump branch32_force32(Condition cond, RegisterID left, Imm32 right) + Jump branch32_force32(Condition cond, RegisterID left, TrustedImm32 right) { m_assembler.move_nocheck(right.m_value, SparcRegisters::g3); m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0); return Jump(m_assembler.branch(SparcCondition(cond))); } - Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right) + Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right) { m_assembler.move_nocheck(right.m_value, SparcRegisters::g2); return branch32(cond, left, SparcRegisters::g2); } - Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel) + Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel) { // Always use move_nocheck, since the value is to be patched. dataLabel = DataLabel32(this); @@ -669,7 +669,7 @@ namespace JSC { return Jump(m_assembler.branch(SparcCondition(cond))); } - Jump branch32(Condition cond, RegisterID left, Imm32 right) + Jump branch32(Condition cond, RegisterID left, TrustedImm32 right) { if (m_assembler.isimm13(right.m_value)) m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0); @@ -692,20 +692,20 @@ namespace JSC { return branch32(cond, SparcRegisters::g2, right); } - Jump branch32(Condition cond, Address left, Imm32 right) + Jump branch32(Condition cond, Address left, TrustedImm32 right) { load32(left, SparcRegisters::g2); return branch32(cond, SparcRegisters::g2, right); } - Jump branch32(Condition cond, BaseIndex left, Imm32 right) + Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) { load32(left, SparcRegisters::g2); return branch32(cond, SparcRegisters::g2, right); } - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) { load32WithUnalignedHalfWords(left, SparcRegisters::g4); return branch32(cond, SparcRegisters::g4, right); @@ -1052,7 +1052,7 @@ namespace JSC { store32(SparcRegisters::g2, address.m_ptr); } - void sub32(Imm32 imm, AbsoluteAddress address) + void sub32(TrustedImm32 imm, AbsoluteAddress address) { load32(address.m_ptr, SparcRegisters::g2); sub32(imm, SparcRegisters::g2); @@ -1071,7 +1071,7 @@ namespace JSC { return branch32(cond, SparcRegisters::g2, right); } - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) + Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) { load32(left.m_ptr, SparcRegisters::g2); return branch32(cond, SparcRegisters::g2, right); @@ -1099,7 +1099,7 @@ namespace JSC { return Call::fromTailJump(oldJump); } - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) + DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) { DataLabelPtr dataLabel(this); Imm32 imm = Imm32(initialValue); @@ -1107,7 +1107,7 @@ namespace JSC { return dataLabel; } - DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest) + DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest) { DataLabel32 dataLabel(this); m_assembler.move_nocheck(initialValue.m_value, dest); @@ -1129,7 +1129,7 @@ namespace JSC { return jump; } - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) { DataLabelPtr dataLabel = moveWithPatch(initialValue, SparcRegisters::g2); store32(SparcRegisters::g2, address); diff --git a/js/src/assembler/assembler/MacroAssemblerX86.h b/js/src/assembler/assembler/MacroAssemblerX86.h index ee61b895a8fe..c6ab40f587fa 100644 --- a/js/src/assembler/assembler/MacroAssemblerX86.h +++ b/js/src/assembler/assembler/MacroAssemblerX86.h @@ -60,7 +60,7 @@ public: using MacroAssemblerX86Common::storeDouble; using MacroAssemblerX86Common::convertInt32ToDouble; - void add32(Imm32 imm, RegisterID src, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { m_assembler.leal_mr(imm.m_value, src, dest); } @@ -90,12 +90,12 @@ public: m_assembler.andl_im(imm.m_value, address.m_ptr); } - void or32(Imm32 imm, AbsoluteAddress address) + void or32(TrustedImm32 imm, AbsoluteAddress address) { m_assembler.orl_im(imm.m_value, address.m_ptr); } - void sub32(Imm32 imm, AbsoluteAddress address) + void sub32(TrustedImm32 imm, AbsoluteAddress address) { m_assembler.subl_im(imm.m_value, address.m_ptr); } @@ -148,7 +148,7 @@ public: addDouble(Address(srcDest), dest); } - void store32(Imm32 imm, void* address) + void store32(TrustedImm32 imm, void* address) { m_assembler.movl_i32m(imm.m_value, address); } @@ -164,7 +164,7 @@ public: return Jump(m_assembler.jCC(x86Condition(cond))); } - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) + Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right) { m_assembler.cmpl_im(right.m_value, left.m_ptr); return Jump(m_assembler.jCC(x86Condition(cond))); @@ -186,7 +186,7 @@ public: } - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) + DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) { m_assembler.movl_i32r(initialValue.asIntptr(), dest); return DataLabelPtr(this); @@ -206,7 +206,7 @@ public: return Jump(m_assembler.jCC(x86Condition(cond))); } - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) { m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base); return DataLabelPtr(this); diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h index 1ead9665f4e2..fa1b7ba8cb10 100644 --- a/js/src/assembler/assembler/MacroAssemblerX86Common.h +++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h @@ -116,12 +116,12 @@ public: m_assembler.addl_rr(src, dest); } - void add32(Imm32 imm, Address address) + void add32(TrustedImm32 imm, Address address) { m_assembler.addl_im(imm.m_value, address.offset, address.base); } - void add32(Imm32 imm, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID dest) { m_assembler.addl_ir(imm.m_value, dest); } @@ -234,7 +234,7 @@ public: m_assembler.orl_rr(src, dest); } - void or32(Imm32 imm, RegisterID dest) + void or32(TrustedImm32 imm, RegisterID dest) { m_assembler.orl_ir(imm.m_value, dest); } @@ -249,7 +249,7 @@ public: m_assembler.orl_mr(src.offset, src.base, dest); } - void or32(Imm32 imm, Address address) + void or32(TrustedImm32 imm, Address address) { m_assembler.orl_im(imm.m_value, address.offset, address.base); } @@ -313,12 +313,12 @@ public: m_assembler.subl_rr(src, dest); } - void sub32(Imm32 imm, RegisterID dest) + void sub32(TrustedImm32 imm, RegisterID dest) { m_assembler.subl_ir(imm.m_value, dest); } - void sub32(Imm32 imm, Address address) + void sub32(TrustedImm32 imm, Address address) { m_assembler.subl_im(imm.m_value, address.offset, address.base); } @@ -339,12 +339,12 @@ public: m_assembler.xorl_rr(src, dest); } - void xor32(Imm32 imm, Address dest) + void xor32(TrustedImm32 imm, Address dest) { m_assembler.xorl_im(imm.m_value, dest.offset, dest.base); } - void xor32(Imm32 imm, RegisterID dest) + void xor32(TrustedImm32 imm, RegisterID dest) { m_assembler.xorl_ir(imm.m_value, dest); } @@ -468,7 +468,7 @@ public: m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale); } - void store32(Imm32 imm, BaseIndex address) + void store32(TrustedImm32 imm, BaseIndex address) { m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale); } @@ -483,7 +483,7 @@ public: m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale); } - void store32(Imm32 imm, ImplicitAddress address) + void store32(TrustedImm32 imm, ImplicitAddress address) { m_assembler.movl_i32m(imm.m_value, address.offset, address.base); } @@ -748,7 +748,7 @@ public: // // Move values in registers. - void move(Imm32 imm, RegisterID dest) + void move(TrustedImm32 imm, RegisterID dest) { // Note: on 64-bit the Imm32 value is zero extended into the register, it // may be useful to have a separate version that sign extends the value? @@ -767,7 +767,7 @@ public: m_assembler.movq_rr(src, dest); } - void move(ImmPtr imm, RegisterID dest) + void move(TrustedImmPtr imm, RegisterID dest) { m_assembler.movq_i64r(imm.asIntptr(), dest); } @@ -798,7 +798,7 @@ public: m_assembler.movl_rr(src, dest); } - void move(ImmPtr imm, RegisterID dest) + void move(TrustedImmPtr imm, RegisterID dest) { m_assembler.movl_i32r(imm.asIntptr(), dest); } @@ -852,7 +852,7 @@ public: return Jump(m_assembler.jCC(x86Condition(cond))); } - Jump branch32(Condition cond, RegisterID left, Imm32 right) + Jump branch32(Condition cond, RegisterID left, TrustedImm32 right) { if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) m_assembler.testl_rr(left, left); @@ -864,14 +864,14 @@ public: // Branch based on a 32-bit comparison, forcing the size of the // immediate operand to 32 bits in the native code stream to ensure that // the length of code emitted by this instruction is consistent. - Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right) + Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right) { m_assembler.cmpl_ir_force32(right.m_value, left); return Jump(m_assembler.jCC(x86Condition(cond))); } // Branch and record a label after the comparison. - Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel) + Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel) { // Always use cmpl, since the value is to be patched. m_assembler.cmpl_ir_force32(right.m_value, left); @@ -879,7 +879,7 @@ public: return Jump(m_assembler.jCC(x86Condition(cond))); } - Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel) + Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel) { m_assembler.cmpl_im_force32(right.m_value, left.offset, left.base); dataLabel = DataLabel32(this); @@ -898,19 +898,19 @@ public: return Jump(m_assembler.jCC(x86Condition(cond))); } - Jump branch32(Condition cond, Address left, Imm32 right) + Jump branch32(Condition cond, Address left, TrustedImm32 right) { m_assembler.cmpl_im(right.m_value, left.offset, left.base); return Jump(m_assembler.jCC(x86Condition(cond))); } - Jump branch32(Condition cond, BaseIndex left, Imm32 right) + Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right) { m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale); return Jump(m_assembler.jCC(x86Condition(cond))); } - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right) { return branch32(cond, left, right); } @@ -1369,7 +1369,7 @@ private: } #if WTF_CPU_X86 -#if WTF_PLATFORM_MAC +#if WTF_OS_MAC_OS_X // All X86 Macs are guaranteed to support at least SSE2 static bool isSSEPresent() @@ -1382,7 +1382,7 @@ private: return true; } -#else // PLATFORM(MAC) +#else // OS(MAC_OS_X) static bool isSSEPresent() { diff --git a/js/src/assembler/assembler/MacroAssemblerX86_64.h b/js/src/assembler/assembler/MacroAssemblerX86_64.h index 7dadc6bcaf2e..a5038a930e56 100644 --- a/js/src/assembler/assembler/MacroAssemblerX86_64.h +++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h @@ -60,7 +60,7 @@ public: using MacroAssemblerX86Common::storeDouble; using MacroAssemblerX86Common::convertInt32ToDouble; - void add32(Imm32 imm, AbsoluteAddress address) + void add32(TrustedImm32 imm, AbsoluteAddress address) { move(ImmPtr(address.m_ptr), scratchRegister); add32(imm, Address(scratchRegister)); @@ -72,13 +72,13 @@ public: and32(imm, Address(scratchRegister)); } - void or32(Imm32 imm, AbsoluteAddress address) + void or32(TrustedImm32 imm, AbsoluteAddress address) { move(ImmPtr(address.m_ptr), scratchRegister); or32(imm, Address(scratchRegister)); } - void sub32(Imm32 imm, AbsoluteAddress address) + void sub32(TrustedImm32 imm, AbsoluteAddress address) { move(ImmPtr(address.m_ptr), scratchRegister); sub32(imm, Address(scratchRegister)); @@ -114,7 +114,7 @@ public: m_assembler.cvtsq2sd_rr(srcDest, dest); } - void store32(Imm32 imm, void* address) + void store32(TrustedImm32 imm, void* address) { move(X86Registers::eax, scratchRegister); move(imm, X86Registers::eax); @@ -311,7 +311,7 @@ public: m_assembler.movq_rm(src, address.offset, address.base); } - void storePtr(ImmPtr imm, BaseIndex address) + void storePtr(TrustedImmPtr imm, BaseIndex address) { intptr_t value = intptr_t(imm.m_value); @@ -341,7 +341,7 @@ public: } } - void storePtr(ImmPtr imm, ImplicitAddress address) + void storePtr(TrustedImmPtr imm, ImplicitAddress address) { intptr_t value = intptr_t(imm.m_value); @@ -487,7 +487,7 @@ public: return Jump(m_assembler.jCC(x86Condition(cond))); } - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) + DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) { m_assembler.movq_i64r(initialValue.asIntptr(), dest); return DataLabelPtr(this); @@ -505,7 +505,7 @@ public: return branchPtr(cond, left, scratchRegister); } - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) { DataLabelPtr label = moveWithPatch(initialValue, scratchRegister); storePtr(scratchRegister, address); diff --git a/js/src/assembler/jit/ExecutableAllocator.h b/js/src/assembler/jit/ExecutableAllocator.h index a54a4dab143b..9cca26f48c99 100644 --- a/js/src/assembler/jit/ExecutableAllocator.h +++ b/js/src/assembler/jit/ExecutableAllocator.h @@ -52,16 +52,16 @@ extern "C" void sync_instruction_memory(caddr_t v, u_int len); #endif #endif -#if WTF_PLATFORM_IPHONE +#if WTF_OS_IOS #include #include #endif -#if WTF_PLATFORM_SYMBIAN +#if WTF_OS_SYMBIAN #include #endif -#if WTF_CPU_MIPS && WTF_PLATFORM_LINUX +#if WTF_CPU_MIPS && WTF_OS_LINUX #include #endif @@ -90,7 +90,7 @@ private: struct Allocation { char* pages; size_t size; -#if WTF_PLATFORM_SYMBIAN +#if WTF_OS_SYMBIAN RChunk* chunk; #endif }; @@ -269,6 +269,7 @@ private: return pool; } +public: ExecutablePool* poolForSize(size_t n) { #ifndef DEBUG_STRESS_JSC_ALLOCATOR @@ -327,7 +328,6 @@ private: return pool; } -public: #if ENABLE_ASSEMBLER_WX_EXCLUSIVE static void makeWritable(void* start, size_t size) { @@ -374,13 +374,13 @@ public: _flush_cache(reinterpret_cast(code), size, BCACHE); #endif } -#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE +#elif WTF_CPU_ARM_THUMB2 && WTF_OS_IOS static void cacheFlush(void* code, size_t size) { sys_dcache_flush(code, size); sys_icache_invalidate(code, size); } -#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_LINUX +#elif WTF_CPU_ARM_THUMB2 && WTF_IOS static void cacheFlush(void* code, size_t size) { asm volatile ( @@ -396,14 +396,14 @@ public: : "r" (code), "r" (reinterpret_cast(code) + size) : "r0", "r1", "r2"); } -#elif WTF_PLATFORM_SYMBIAN +#elif WTF_OS_SYMBIAN static void cacheFlush(void* code, size_t size) { User::IMB_Range(code, static_cast(code) + size); } -#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT +#elif WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT static __asm void cacheFlush(void* code, size_t size); -#elif WTF_CPU_ARM_TRADITIONAL && (WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID) && WTF_COMPILER_GCC +#elif WTF_CPU_ARM_TRADITIONAL && (WTF_OS_LINUX || WTF_OS_ANDROID) && WTF_COMPILER_GCC static void cacheFlush(void* code, size_t size) { asm volatile ( diff --git a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp index ef9e27d92b47..675b604ae914 100644 --- a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp +++ b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp @@ -26,7 +26,7 @@ #include "ExecutableAllocator.h" -#if ENABLE_ASSEMBLER && WTF_PLATFORM_OS2 +#if ENABLE_ASSEMBLER && WTF_OS_OS2 #define INCL_DOS #include diff --git a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp index 50efd932e02a..e334626ccc2f 100644 --- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp +++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp @@ -25,7 +25,7 @@ #include "ExecutableAllocator.h" -#if ENABLE_ASSEMBLER && WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN +#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN #include #include @@ -74,7 +74,7 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe } #endif -#if WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT +#if WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT __asm void ExecutableAllocator::cacheFlush(void* code, size_t size) { ARM diff --git a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp index c66fa80fff12..f51c0d507877 100644 --- a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp +++ b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp @@ -22,7 +22,7 @@ #include "ExecutableAllocator.h" -#if ENABLE_ASSEMBLER && WTF_PLATFORM_SYMBIAN +#if ENABLE_ASSEMBLER && WTF_OS_SYMBIAN #include #include diff --git a/js/src/assembler/jit/ExecutableAllocatorWin.cpp b/js/src/assembler/jit/ExecutableAllocatorWin.cpp index f5775608f36f..da6e756cfa66 100644 --- a/js/src/assembler/jit/ExecutableAllocatorWin.cpp +++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp @@ -26,7 +26,7 @@ #include "ExecutableAllocator.h" -#if ENABLE_ASSEMBLER && WTF_PLATFORM_WIN_OS +#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS #include "jswin.h" diff --git a/js/src/assembler/wtf/Platform.h b/js/src/assembler/wtf/Platform.h index 68713cd4c810..217c9b8a1eec 100644 --- a/js/src/assembler/wtf/Platform.h +++ b/js/src/assembler/wtf/Platform.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,206 +28,267 @@ #ifndef WTF_Platform_h #define WTF_Platform_h -/* Either XX(YY) --> WTF_XX_YY or XX(YY) --> XX_YY, depending on XX - - PLATFORM(YY) --> WTF_PLATFORM_YY - COMPILER(YY) --> WTF_COMPILER_YY - CPU(YY) --> WTF_CPU_YY - OS(YY) --> WTF_OS_YY - USE(YY) --> WTF_USE_YY - - HAVE(YY) --> HAVE_YY - ENABLE(YY) --> ENABLE_YY -*/ - /* ==== PLATFORM handles OS, operating environment, graphics API, and CPU. This macro will be phased out in favor of platform adaptation macros, policy decision macros, and top-level port definitions. ==== */ -//#define PLATFORM(WTF_FEATURE) (defined(WTF_PLATFORM_##WTF_FEATURE) && WTF_PLATFORM_##WTF_FEATURE) +#define PLATFORM(WTF_FEATURE) (defined WTF_PLATFORM_##WTF_FEATURE && WTF_PLATFORM_##WTF_FEATURE) /* ==== Platform adaptation macros: these describe properties of the target environment. ==== */ /* COMPILER() - the compiler being used to build the project */ -//#define COMPILER(WTF_FEATURE) (defined(WTF_COMPILER_##WTF_FEATURE) && WTF_COMPILER_##WTF_FEATURE) +#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE && WTF_COMPILER_##WTF_FEATURE) /* CPU() - the target CPU architecture */ -//#define CPU(WTF_FEATURE) (defined(WTF_CPU_##WTF_FEATURE) && WTF_CPU_##WTF_FEATURE) +#define CPU(WTF_FEATURE) (defined WTF_CPU_##WTF_FEATURE && WTF_CPU_##WTF_FEATURE) /* HAVE() - specific system features (headers, functions or similar) that are present or not */ -//#define HAVE(WTF_FEATURE) (defined(HAVE_##WTF_FEATURE) && HAVE_##WTF_FEATURE) +#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE && HAVE_##WTF_FEATURE) /* OS() - underlying operating system; only to be used for mandated low-level services like virtual memory, not to choose a GUI toolkit */ -//#define OS(WTF_FEATURE) (defined(WTF_OS_##WTF_FEATURE) && WTF_OS_##WTF_FEATURE) +#define OS(WTF_FEATURE) (defined WTF_OS_##WTF_FEATURE && WTF_OS_##WTF_FEATURE) /* ==== Policy decision macros: these define policy choices for a particular port. ==== */ /* USE() - use a particular third-party library or optional OS service */ -//#define USE(WTF_FEATURE) (defined(WTF_USE_##WTF_FEATURE) && WTF_USE_##WTF_FEATURE) +#define USE(WTF_FEATURE) (defined WTF_USE_##WTF_FEATURE && WTF_USE_##WTF_FEATURE) /* ENABLE() - turn on a specific feature of WebKit */ -//#define ENABLE(WTF_FEATURE) (defined(ENABLE_##WTF_FEATURE) && ENABLE_##WTF_FEATURE) +#define ENABLE(WTF_FEATURE) (defined ENABLE_##WTF_FEATURE && ENABLE_##WTF_FEATURE) /* ==== COMPILER() - the compiler being used to build the project ==== */ -/* COMPILER(MSVC) Microsoft Visual C++ */ -/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/ +/* WTF_COMPILER_MSVC Microsoft Visual C++ */ +/* WTF_COMPILER_MSVC7_OR_LOWER Microsoft Visual C++ 2003 or lower*/ +/* WTF_COMPILER_MSVC9_OR_LOWER Microsoft Visual C++ 2008 or lower*/ #if defined(_MSC_VER) #define WTF_COMPILER_MSVC 1 #if _MSC_VER < 1400 -#define WTF_COMPILER_MSVC7 1 +#define WTF_COMPILER_MSVC7_OR_LOWER 1 +#elif _MSC_VER < 1600 +#define WTF_COMPILER_MSVC9_OR_LOWER 1 #endif #endif -/* COMPILER(RVCT) - ARM RealView Compilation Tools */ +/* WTF_COMPILER_RVCT - ARM RealView Compilation Tools */ +/* WTF_COMPILER_RVCT4_OR_GREATER - ARM RealView Compilation Tools 4.0 or greater */ #if defined(__CC_ARM) || defined(__ARMCC__) #define WTF_COMPILER_RVCT 1 +#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) (__ARMCC_VERSION >= (major * 100000 + minor * 10000 + patch * 1000 + build)) +#else +/* Define this for !RVCT compilers, just so we can write things like RVCT_VERSION_AT_LEAST(3, 0, 0, 0). */ +#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) 0 #endif -/* COMPILER(GCC) - GNU Compiler Collection */ +/* WTF_COMPILER_GCC - GNU Compiler Collection */ /* --gnu option of the RVCT compiler also defines __GNUC__ */ #if defined(__GNUC__) && !WTF_COMPILER_RVCT #define WTF_COMPILER_GCC 1 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch)) +#else +/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */ +#define GCC_VERSION_AT_LEAST(major, minor, patch) 0 #endif -/* COMPILER(MINGW) - MinGW GCC */ -#if defined(MINGW) || defined(__MINGW32__) +/* WTF_COMPILER_MINGW - MinGW GCC */ +/* WTF_COMPILER_MINGW64 - mingw-w64 GCC - only used as additional check to exclude mingw.org specific functions */ +#if defined(__MINGW32__) #define WTF_COMPILER_MINGW 1 -#endif +#include <_mingw.h> /* private MinGW header */ + #if defined(__MINGW64_VERSION_MAJOR) /* best way to check for mingw-w64 vs mingw.org */ + #define WTF_COMPILER_MINGW64 1 + #endif /* __MINGW64_VERSION_MAJOR */ +#endif /* __MINGW32__ */ -/* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */ +/* WTF_COMPILER_WINSCW - CodeWarrior for Symbian emulator */ #if defined(__WINSCW__) #define WTF_COMPILER_WINSCW 1 +/* cross-compiling, it is not really windows */ +#undef WIN32 +#undef _WIN32 #endif -/* COMPILER(SUNPRO) - Sun Studio for Solaris */ -#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -#define WTF_COMPILER_SUNPRO 1 +/* WTF_COMPILER_INTEL - Intel C++ Compiler */ +#if defined(__INTEL_COMPILER) +#define WTF_COMPILER_INTEL 1 #endif +/* WTF_COMPILER_SUNCC */ +#if defined(__SUNPRO_CC) || defined(__SUNPRO_C) +#define WTF_COMPILER_SUNCC 1 +#endif /* ==== CPU() - the target CPU architecture ==== */ -/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */ +/* This also defines WTF_CPU_BIG_ENDIAN or WTF_CPU_MIDDLE_ENDIAN or neither, as appropriate. */ - -/* CPU(ALPHA) - DEC Alpha */ +/* WTF_CPU_ALPHA - DEC Alpha */ #if defined(__alpha__) #define WTF_CPU_ALPHA 1 #endif -/* CPU(IA64) - Itanium / IA-64 */ +/* WTF_CPU_IA64 - Itanium / IA-64 */ #if defined(__ia64__) #define WTF_CPU_IA64 1 +/* 32-bit mode on Itanium */ +#if !defined(__LP64__) +#define WTF_CPU_IA64_32 1 +#endif #endif -/* CPU(PPC) - PowerPC 32-bit */ +/* WTF_CPU_MIPS - MIPS 32-bit */ +/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now. */ +#if (defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_)) \ + && defined(_ABIO32) +#define WTF_CPU_MIPS 1 +#if defined(__MIPSEB__) +#define WTF_CPU_BIG_ENDIAN 1 +#endif +#define WTF_MIPS_PIC (defined __PIC__) +#define WTF_MIPS_ARCH __mips +#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v) +#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v) +#define WTF_MIPS_ARCH_REV __mips_isa_rev +#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v) +#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float) +#define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64) +/* MIPS requires allocators to use aligned memory */ +#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1 +#endif /* MIPS */ + +/* WTF_CPU_PPC - PowerPC 32-bit */ #if defined(__ppc__) \ - || defined(__PPC__) \ - || defined(__powerpc__) \ - || defined(__powerpc) \ - || defined(__POWERPC__) \ - || defined(_M_PPC) \ - || defined(__PPC) + || defined(__PPC__) \ + || defined(__powerpc__) \ + || defined(__powerpc) \ + || defined(__POWERPC__) \ + || defined(_M_PPC) \ + || defined(__PPC) #define WTF_CPU_PPC 1 #define WTF_CPU_BIG_ENDIAN 1 #endif -/* CPU(PPC64) - PowerPC 64-bit */ +/* WTF_CPU_PPC64 - PowerPC 64-bit */ #if defined(__ppc64__) \ - || defined(__PPC64__) + || defined(__PPC64__) #define WTF_CPU_PPC64 1 #define WTF_CPU_BIG_ENDIAN 1 #endif -/* CPU(SH4) - SuperH SH-4 */ +/* WTF_CPU_SH4 - SuperH SH-4 */ #if defined(__SH4__) #define WTF_CPU_SH4 1 #endif -/* CPU(SPARC32) - SPARC 32-bit */ +/* WTF_CPU_SPARC32 - SPARC 32-bit */ #if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8) #define WTF_CPU_SPARC32 1 #define WTF_CPU_BIG_ENDIAN 1 #endif -/* CPU(SPARC64) - SPARC 64-bit */ +/* WTF_CPU_SPARC64 - SPARC 64-bit */ #if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9) #define WTF_CPU_SPARC64 1 #define WTF_CPU_BIG_ENDIAN 1 #endif -/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */ +/* WTF_CPU_SPARC - any SPARC, true for WTF_CPU_SPARC32 and WTF_CPU_SPARC64 */ #if WTF_CPU_SPARC32 || WTF_CPU_SPARC64 #define WTF_CPU_SPARC 1 #endif -/* CPU(X86) - i386 / x86 32-bit */ +/* WTF_CPU_S390X - S390 64-bit */ +#if defined(__s390x__) +#define WTF_CPU_S390X 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + +/* WTF_CPU_S390 - S390 32-bit */ +#if defined(__s390__) +#define WTF_CPU_S390 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + +/* WTF_CPU_X86 - i386 / x86 32-bit */ #if defined(__i386__) \ - || defined(i386) \ - || defined(_M_IX86) \ - || defined(_X86_) \ - || defined(__THW_INTEL) + || defined(i386) \ + || defined(_M_IX86) \ + || defined(_X86_) \ + || defined(__THW_INTEL) #define WTF_CPU_X86 1 #endif -/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */ +/* WTF_CPU_X86_64 - AMD64 / Intel64 / x86_64 64-bit */ #if defined(__x86_64__) \ - || defined(_M_X64) + || defined(_M_X64) #define WTF_CPU_X86_64 1 #endif -/* CPU(ARM) - ARM, any version*/ +/* WTF_CPU_ARM - ARM, any version*/ #if defined(arm) \ - || defined(__arm__) + || defined(__arm__) \ + || defined(ARM) \ + || defined(_ARM_) #define WTF_CPU_ARM 1 -#if defined(__ARMEB__) +#if defined(__ARMEB__) || (WTF_COMPILER_RVCT && defined(__BIG_ENDIAN)) #define WTF_CPU_BIG_ENDIAN 1 #elif !defined(__ARM_EABI__) \ - && !defined(__EABI__) \ - && !defined(__VFP_FP__) \ - && !defined(ANDROID) + && !defined(__EABI__) \ + && !defined(__VFP_FP__) \ + && !defined(_WIN32_WCE) \ + && !defined(ANDROID) #define WTF_CPU_MIDDLE_ENDIAN 1 #endif -#define WTF_ARM_ARCH_AT_LEAST(N) (WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= N) +#define WTF_ARM_ARCH_AT_LEAST(N) (CPU(ARM) && WTF_ARM_ARCH_VERSION >= N) /* Set WTF_ARM_ARCH_VERSION */ #if defined(__ARM_ARCH_4__) \ - || defined(__ARM_ARCH_4T__) \ - || defined(__MARM_ARMV4__) \ - || defined(_ARMV4I_) + || defined(__ARM_ARCH_4T__) \ + || defined(__MARM_ARMV4__) \ + || defined(_ARMV4I_) #define WTF_ARM_ARCH_VERSION 4 #elif defined(__ARM_ARCH_5__) \ - || defined(__ARM_ARCH_5T__) \ - || defined(__ARM_ARCH_5E__) \ - || defined(__ARM_ARCH_5TE__) \ - || defined(__ARM_ARCH_5TEJ__) \ - || defined(__MARM_ARMV5__) + || defined(__ARM_ARCH_5T__) \ + || defined(__MARM_ARMV5__) #define WTF_ARM_ARCH_VERSION 5 +#elif defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +#define WTF_ARM_ARCH_VERSION 5 +/*ARMv5TE requires allocators to use aligned memory*/ +#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1 + #elif defined(__ARM_ARCH_6__) \ - || defined(__ARM_ARCH_6J__) \ - || defined(__ARM_ARCH_6K__) \ - || defined(__ARM_ARCH_6Z__) \ - || defined(__ARM_ARCH_6ZK__) \ - || defined(__ARM_ARCH_6T2__) \ - || defined(__ARMV6__) + || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6T2__) \ + || defined(__ARMV6__) #define WTF_ARM_ARCH_VERSION 6 #elif defined(__ARM_ARCH_7A__) \ - || defined(__ARM_ARCH_7R__) + || defined(__ARM_ARCH_7R__) #define WTF_ARM_ARCH_VERSION 7 /* RVCT sets _TARGET_ARCH_ARM */ #elif defined(__TARGET_ARCH_ARM) #define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM +#if defined(__TARGET_ARCH_5E) \ + || defined(__TARGET_ARCH_5TE) \ + || defined(__TARGET_ARCH_5TEJ) +/*ARMv5TE requires allocators to use aligned memory*/ +#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1 +#endif + #else #define WTF_ARM_ARCH_VERSION 0 @@ -237,22 +299,22 @@ #define WTF_THUMB_ARCH_VERSION 1 #elif defined(__ARM_ARCH_5T__) \ - || defined(__ARM_ARCH_5TE__) \ - || defined(__ARM_ARCH_5TEJ__) + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) #define WTF_THUMB_ARCH_VERSION 2 #elif defined(__ARM_ARCH_6J__) \ - || defined(__ARM_ARCH_6K__) \ - || defined(__ARM_ARCH_6Z__) \ - || defined(__ARM_ARCH_6ZK__) \ - || defined(__ARM_ARCH_6M__) + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6M__) #define WTF_THUMB_ARCH_VERSION 3 #elif defined(__ARM_ARCH_6T2__) \ - || defined(__ARM_ARCH_7__) \ - || defined(__ARM_ARCH_7A__) \ - || defined(__ARM_ARCH_7R__) \ - || defined(__ARM_ARCH_7M__) + || defined(__ARM_ARCH_7__) \ + || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) \ + || defined(__ARM_ARCH_7M__) #define WTF_THUMB_ARCH_VERSION 4 /* RVCT sets __TARGET_ARCH_THUMB */ @@ -264,22 +326,22 @@ #endif -/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */ +/* WTF_CPU_ARMV5_OR_LOWER - ARM instruction set v5 or earlier */ /* On ARMv5 and below the natural alignment is required. And there are some other differences for v5 or earlier. */ -#if !defined(ARMV5_OR_LOWER) /* && !CPU_ARM_ARCH_AT_LEAST(6) */ +#if !defined(ARMV5_OR_LOWER) && !WTF_ARM_ARCH_AT_LEAST(6) #define WTF_CPU_ARMV5_OR_LOWER 1 #endif -/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */ -/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */ +/* WTF_CPU_ARM_TRADITIONAL - Thumb2 is not available, only traditional ARM (v4 or greater) */ +/* WTF_CPU_ARM_THUMB2 - Thumb2 instruction set is available */ /* Only one of these will be defined. */ #if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) # if defined(thumb2) || defined(__thumb2__) \ - || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4) -# define WTF_CPU_ARM_TRADITIONAL 1 -# define WTF_CPU_ARM_THUMB2 0 + || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4) +# define WTF_CPU_ARM_TRADITIONAL 0 +# define WTF_CPU_ARM_THUMB2 1 # elif WTF_ARM_ARCH_AT_LEAST(4) # define WTF_CPU_ARM_TRADITIONAL 1 # define WTF_CPU_ARM_THUMB2 0 @@ -288,19 +350,36 @@ # endif #elif WTF_CPU_ARM_TRADITIONAL && WTF_CPU_ARM_THUMB2 /* Sanity Check */ # error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms" -#endif // !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) +#endif /* !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) */ + +#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON) +#define WTF_CPU_ARM_NEON 1 +#endif #endif /* ARM */ +#if WTF_CPU_ARM || WTF_CPU_MIPS +#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1 +#endif +/* ==== OS() - underlying operating system; only to be used for mandated low-level services like + virtual memory, not to choose a GUI toolkit ==== */ -/* Operating systems - low-level dependencies */ +/* WTF_OS_ANDROID - Android */ +#ifdef ANDROID +#define WTF_OS_ANDROID 1 +#endif -/* PLATFORM(DARWIN) */ -/* Operating system level dependencies for Mac OS X / Darwin that should */ -/* be used regardless of operating environment */ +/* WTF_OS_AIX - AIX */ +#ifdef _AIX +#define WTF_OS_AIX 1 +#endif + +/* WTF_OS_DARWIN - Any Darwin-based OS, including Mac OS X and iPhone OS */ #ifdef __APPLE__ -#define WTF_PLATFORM_DARWIN 1 +#define WTF_OS_DARWIN 1 + +/* FIXME: BUILDING_ON_.., and TARGETING... macros should be folded into the OS() system */ #include #if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 #define BUILDING_ON_TIGER 1 @@ -317,98 +396,97 @@ #define TARGETING_SNOW_LEOPARD 1 #endif #include + #endif -/* PLATFORM(WIN_OS) */ -/* Operating system level dependencies for Windows that should be used */ -/* regardless of operating environment */ -#if defined(WIN32) || defined(_WIN32) -#define WTF_PLATFORM_WIN_OS 1 +/* WTF_OS_IOS - iOS */ +/* WTF_OS_MAC_OS_X - Mac OS X (not including iOS) */ +#if WTF_OS_DARWIN && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) \ + || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) \ + || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR)) +#define WTF_OS_IOS 1 +#elif WTF_OS_DARWIN && defined(TARGET_OS_MAC) && TARGET_OS_MAC +#define WTF_OS_MAC_OS_X 1 #endif -/* PLATFORM(LINUX) */ -/* Operating system level dependencies for Linux-like systems that */ -/* should be used regardless of operating environment */ +/* WTF_OS_FREEBSD - FreeBSD */ +#if defined(__FreeBSD__) || defined(__DragonFly__) +#define WTF_OS_FREEBSD 1 +#endif + +/* WTF_OS_HAIKU - Haiku */ +#ifdef __HAIKU__ +#define WTF_OS_HAIKU 1 +#endif + +/* WTF_OS_LINUX - Linux */ #ifdef __linux__ -#define WTF_PLATFORM_LINUX 1 +#define WTF_OS_LINUX 1 #endif -/* PLATFORM(FREEBSD) */ -/* Operating system level dependencies for FreeBSD-like systems that */ -/* should be used regardless of operating environment */ -#ifdef __FreeBSD__ -#define WTF_PLATFORM_FREEBSD 1 -#endif - -/* PLATFORM(OPENBSD) */ -/* Operating system level dependencies for OpenBSD systems that */ -/* should be used regardless of operating environment */ -#ifdef __OpenBSD__ -#define WTF_PLATFORM_OPENBSD 1 -#endif - -/* PLATFORM(SOLARIS) */ -/* Operating system level dependencies for Solaris that should be used */ -/* regardless of operating environment */ -#if defined(sun) || defined(__sun) -#define WTF_PLATFORM_SOLARIS 1 -#endif - -/* PLATFORM(OS2) */ -/* Operating system level dependencies for OS/2 that should be used */ -/* regardless of operating environment */ -#if defined(OS2) || defined(__OS2__) -#define WTF_PLATFORM_OS2 1 -#endif - -#if defined (__SYMBIAN32__) -/* we are cross-compiling, it is not really windows */ -#undef WTF_PLATFORM_WIN_OS -#undef WTF_PLATFORM_WIN -#define WTF_PLATFORM_SYMBIAN 1 -#endif - - -/* PLATFORM(NETBSD) */ -/* Operating system level dependencies for NetBSD that should be used */ -/* regardless of operating environment */ +/* WTF_OS_NETBSD - NetBSD */ #if defined(__NetBSD__) -#define WTF_PLATFORM_NETBSD 1 +#define WTF_OS_NETBSD 1 #endif -/* PLATFORM(QNX) */ -/* Operating system level dependencies for QNX that should be used */ -/* regardless of operating environment */ +/* WTF_OS_OPENBSD - OpenBSD */ +#ifdef __OpenBSD__ +#define WTF_OS_OPENBSD 1 +#endif + +/* WTF_OS_QNX - QNX */ #if defined(__QNXNTO__) -#define WTF_PLATFORM_QNX 1 +#define WTF_OS_QNX 1 #endif -/* PLATFORM(UNIX) */ -/* Operating system level dependencies for Unix-like systems that */ -/* should be used regardless of operating environment */ -#if WTF_PLATFORM_DARWIN \ - || WTF_PLATFORM_FREEBSD \ - || WTF_PLATFORM_SYMBIAN \ - || WTF_PLATFORM_NETBSD \ - || defined(unix) \ - || defined(__unix) \ - || defined(__unix__) \ - || defined(_AIX) \ - || defined(__HAIKU__) \ - || defined(__QNXNTO__) \ - || defined(ANDROID) -#define WTF_PLATFORM_UNIX 1 +/* WTF_OS_SOLARIS - Solaris */ +#if defined(sun) || defined(__sun) +#define WTF_OS_SOLARIS 1 +#endif + +/* WTF_OS_WINCE - Windows CE; note that for this platform WTF_OS_WINDOWS is also defined */ +#if defined(_WIN32_WCE) +#define WTF_OS_WINCE 1 +#endif + +/* WTF_OS_WINDOWS - Any version of Windows */ +#if defined(WIN32) || defined(_WIN32) +#define WTF_OS_WINDOWS 1 +#endif + +/* WTF_OS_SYMBIAN - Symbian */ +#if defined (__SYMBIAN32__) +#define WTF_OS_SYMBIAN 1 +#endif + +/* WTF_OS_UNIX - Any Unix-like system */ +#if WTF_OS_AIX \ + || WTF_OS_ANDROID \ + || WTF_OS_DARWIN \ + || WTF_OS_FREEBSD \ + || WTF_OS_HAIKU \ + || WTF_OS_LINUX \ + || WTF_OS_NETBSD \ + || WTF_OS_OPENBSD \ + || WTF_OS_QNX \ + || WTF_OS_SOLARIS \ + || WTF_OS_SYMBIAN \ + || defined(unix) \ + || defined(__unix) \ + || defined(__unix__) +#define WTF_OS_UNIX 1 #endif /* Operating environments */ -/* PLATFORM(CHROMIUM) */ -/* PLATFORM(QT) */ -/* PLATFORM(WX) */ -/* PLATFORM(GTK) */ -/* PLATFORM(HAIKU) */ -/* PLATFORM(MAC) */ -/* PLATFORM(WIN) */ +/* FIXME: these are all mixes of OS, operating environment and policy choices. */ +/* WTF_PLATFORM_CHROMIUM */ +/* WTF_PLATFORM_QT */ +/* WTF_PLATFORM_WX */ +/* WTF_PLATFORM_GTK */ +/* WTF_PLATFORM_HAIKU */ +/* WTF_PLATFORM_MAC */ +/* WTF_PLATFORM_WIN */ #if defined(BUILDING_CHROMIUM__) #define WTF_PLATFORM_CHROMIUM 1 #elif defined(BUILDING_QT__) @@ -419,142 +497,229 @@ #define WTF_PLATFORM_GTK 1 #elif defined(BUILDING_HAIKU__) #define WTF_PLATFORM_HAIKU 1 -#elif WTF_PLATFORM_DARWIN +#elif defined(BUILDING_BREWMP__) +#define WTF_PLATFORM_BREWMP 1 +#if defined(AEE_SIMULATOR) +#define WTF_PLATFORM_BREWMP_SIMULATOR 1 +#else +#define WTF_PLATFORM_BREWMP_SIMULATOR 0 +#endif +#undef WTF_OS_WINDOWS +#undef WTF_PLATFORM_WIN +#elif WTF_OS_DARWIN #define WTF_PLATFORM_MAC 1 -#elif WTF_PLATFORM_WIN_OS +#elif WTF_OS_WINDOWS #define WTF_PLATFORM_WIN 1 #endif -/* PLATFORM(IPHONE) */ +/* WTF_PLATFORM_IOS */ +/* FIXME: this is sometimes used as an OS switch and sometimes for higher-level things */ #if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) -#define WTF_PLATFORM_IPHONE 1 +#define WTF_PLATFORM_IOS 1 #endif -/* PLATFORM(IPHONE_SIMULATOR) */ +/* WTF_PLATFORM_IOS_SIMULATOR */ #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR -#define WTF_PLATFORM_IPHONE 1 -#define WTF_PLATFORM_IPHONE_SIMULATOR 1 +#define WTF_PLATFORM_IOS 1 +#define WTF_PLATFORM_IOS_SIMULATOR 1 #else -#define WTF_PLATFORM_IPHONE_SIMULATOR 0 +#define WTF_PLATFORM_IOS_SIMULATOR 0 #endif -#if !defined(WTF_PLATFORM_IPHONE) -#define WTF_PLATFORM_IPHONE 0 +#if !defined(WTF_PLATFORM_IOS) +#define WTF_PLATFORM_IOS 0 #endif -/* PLATFORM(ANDROID) */ +/* WTF_PLATFORM_ANDROID */ +/* FIXME: this is sometimes used as an OS() switch, and other times to drive + policy choices */ #if defined(ANDROID) #define WTF_PLATFORM_ANDROID 1 #endif /* Graphics engines */ -/* PLATFORM(CG) and PLATFORM(CI) */ -#if WTF_PLATFORM_MAC || WTF_PLATFORM_IPHONE -#define WTF_PLATFORM_CG 1 +/* WTF_USE_CG and WTF_PLATFORM_CI */ +#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS +#define WTF_USE_CG 1 #endif -#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE -#define WTF_PLATFORM_CI 1 +#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS || (WTF_PLATFORM_WIN && WTF_USE_CG) +#define WTF_USE_CA 1 #endif -/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */ +/* WTF_USE_SKIA for Win/Linux, CG for Mac */ #if WTF_PLATFORM_CHROMIUM -#if WTF_PLATFORM_DARWIN -#define WTF_PLATFORM_CG 1 -#define WTF_PLATFORM_CI 1 +#if WTF_OS_DARWIN +#define WTF_USE_CG 1 #define WTF_USE_ATSUI 1 #define WTF_USE_CORE_TEXT 1 +#define WTF_USE_ICCJPEG 1 #else -#define WTF_PLATFORM_SKIA 1 +#define WTF_USE_SKIA 1 +#define WTF_USE_CHROMIUM_NET 1 #endif #endif +#if WTF_PLATFORM_BREWMP +#define WTF_USE_SKIA 1 +#endif + #if WTF_PLATFORM_GTK -#define WTF_PLATFORM_CAIRO 1 +#define WTF_USE_CAIRO 1 #endif -#if (WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_OS2 || (WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS) +#if WTF_OS_WINCE +#include +#define WTF_USE_MERSENNE_TWISTER_19937 1 +#endif + +#if WTF_PLATFORM_QT && WTF_OS_UNIX && !WTF_OS_SYMBIAN && !WTF_OS_DARWIN +#define WTF_USE_PTHREAD_BASED_QT 1 +#endif + +#if (WTF_PLATFORM_GTK || WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || (WTF_PLATFORM_QT && (WTF_OS_DARWIN || WTF_USE_PTHREAD_BASED_QT) && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS) #define ENABLE_JSC_MULTIPLE_THREADS 1 #endif +#if ENABLE_JSC_MULTIPLE_THREADS +#define ENABLE_WTF_MULTIPLE_THREADS 1 +#endif + /* On Windows, use QueryPerformanceCounter by default */ -#if WTF_PLATFORM_WIN_OS +#if WTF_OS_WINDOWS #define WTF_USE_QUERY_PERFORMANCE_COUNTER 1 #endif +#if WTF_OS_WINCE && !WTF_PLATFORM_QT +#define NOMINMAX /* Windows min and max conflict with standard macros */ +#define NOSHLWAPI /* shlwapi.h not available on WinCe */ + +/* MSDN documentation says these functions are provided with uspce.lib. But we cannot find this file. */ +#define __usp10__ /* disable "usp10.h" */ + +#define _INC_ASSERT /* disable "assert.h" */ +#define assert(x) + +#endif /* WTF_OS_WINCE && !WTF_PLATFORM_QT */ + #if WTF_PLATFORM_QT #define WTF_USE_QT4_UNICODE 1 +#elif WTF_OS_WINCE +#define WTF_USE_WINCE_UNICODE 1 +#elif WTF_PLATFORM_BREWMP +#define WTF_USE_BREWMP_UNICODE 1 #elif WTF_PLATFORM_GTK /* The GTK+ Unicode backend is configurable */ #else #define WTF_USE_ICU_UNICODE 1 #endif -#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE -#define WTF_PLATFORM_CF 1 -#define WTF_USE_PTHREADS 1 -#define HAVE_PTHREAD_RWLOCK 1 +#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && WTF_CPU_X86_64 #define WTF_USE_PLUGIN_HOST_PROCESS 1 #endif -#if !defined(ENABLE_MAC_JAVA_BRIDGE) -#define ENABLE_MAC_JAVA_BRIDGE 1 +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +#define ENABLE_GESTURE_EVENTS 1 +#define ENABLE_RUBBER_BANDING 1 +#define WTF_USE_WK_SCROLLBAR_PAINTER 1 +#endif +#if !defined(ENABLE_JAVA_BRIDGE) +#define ENABLE_JAVA_BRIDGE 1 #endif #if !defined(ENABLE_DASHBOARD_SUPPORT) #define ENABLE_DASHBOARD_SUPPORT 1 #endif +#define WTF_USE_CF 1 +#define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 #define HAVE_READLINE 1 #define HAVE_RUNLOOP_TIMER 1 -#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */ +#define ENABLE_FULLSCREEN_API 1 +#define ENABLE_SMOOTH_SCROLLING 1 +#define ENABLE_WEB_ARCHIVE 1 +#endif /* WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS */ -#if WTF_PLATFORM_CHROMIUM && WTF_PLATFORM_DARWIN -#define WTF_PLATFORM_CF 1 +#if WTF_PLATFORM_CHROMIUM && WTF_OS_DARWIN +#define WTF_USE_CF 1 #define WTF_USE_PTHREADS 1 #define HAVE_PTHREAD_RWLOCK 1 #endif -#if WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN -#define WTF_PLATFORM_CF 1 +#if WTF_PLATFORM_BREWMP +#define ENABLE_SINGLE_THREADED 1 #endif -#if WTF_PLATFORM_IPHONE +#if WTF_PLATFORM_QT && WTF_OS_DARWIN +#define WTF_USE_CF 1 +#endif + +#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER) && !WTF_PLATFORM_GTK && !WTF_PLATFORM_QT +#define ENABLE_PURGEABLE_MEMORY 1 +#endif + +#if WTF_PLATFORM_IOS #define ENABLE_CONTEXT_MENUS 0 #define ENABLE_DRAG_SUPPORT 0 +#define ENABLE_DATA_TRANSFER_ITEMS 0 #define ENABLE_FTPDIR 1 #define ENABLE_GEOLOCATION 1 #define ENABLE_ICONDATABASE 0 #define ENABLE_INSPECTOR 0 -#define ENABLE_MAC_JAVA_BRIDGE 0 +#define ENABLE_JAVA_BRIDGE 0 #define ENABLE_NETSCAPE_PLUGIN_API 0 #define ENABLE_ORIENTATION_EVENTS 1 #define ENABLE_REPAINT_THROTTLING 1 #define HAVE_READLINE 1 -#define WTF_PLATFORM_CF 1 +#define WTF_USE_CF 1 #define WTF_USE_PTHREADS 1 #define HAVE_PTHREAD_RWLOCK 1 +#define ENABLE_WEB_ARCHIVE 1 #endif #if WTF_PLATFORM_ANDROID #define WTF_USE_PTHREADS 1 -#define WTF_PLATFORM_SGL 1 #define USE_SYSTEM_MALLOC 1 -#define ENABLE_MAC_JAVA_BRIDGE 1 +#define ENABLE_JAVA_BRIDGE 1 #define LOG_DISABLED 1 -// Prevents Webkit from drawing the caret in textfields and textareas -// This prevents unnecessary invals. +/* Prevents Webkit from drawing the caret in textfields and textareas + This prevents unnecessary invals. */ #define ENABLE_TEXT_CARET 1 #define ENABLE_JAVASCRIPT_DEBUGGER 0 +#if !defined(ENABLE_JIT) && !ENABLE_ANDROID_JSC_JIT +#define ENABLE_JIT 0 +#endif #endif -#if WTF_PLATFORM_WIN -#define WTF_USE_WININET 1 +#if WTF_PLATFORM_WIN && !WTF_OS_WINCE +#define WTF_USE_CF 1 +#define WTF_USE_PTHREADS 0 +#endif + +#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !defined(WIN_CAIRO) +#define WTF_USE_CFNETWORK 1 +#endif + +#if WTF_USE_CFNETWORK || WTF_PLATFORM_MAC +#define WTF_USE_CFURLCACHE 1 +#define WTF_USE_CFURLSTORAGESESSIONS 1 +#endif + +#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !WTF_PLATFORM_QT +#define ENABLE_WEB_ARCHIVE 1 #endif #if WTF_PLATFORM_WX #define ENABLE_ASSEMBLER 1 -#if WTF_PLATFORM_DARWIN -#define WTF_PLATFORM_CF 1 +#define ENABLE_GLOBAL_FASTMALLOC_NEW 0 +#if WTF_OS_DARWIN +#define WTF_USE_CF 1 +#ifndef BUILDING_ON_TIGER +#define WTF_USE_CORE_TEXT 1 +#define ENABLE_WEB_ARCHIVE 1 +#else +#define WTF_USE_ATSUI 1 +#endif #endif #endif @@ -574,25 +739,39 @@ #define ENABLE_NETSCAPE_PLUGIN_API 0 #endif +#if WTF_PLATFORM_BREWMP +#define USE_SYSTEM_MALLOC 1 +#endif + +#if WTF_PLATFORM_BREWMP_SIMULATOR +#define ENABLE_JIT 0 +#endif + #if !defined(HAVE_ACCESSIBILITY) -#if WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM +#if WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM #define HAVE_ACCESSIBILITY 1 #endif #endif /* !defined(HAVE_ACCESSIBILITY) */ -#if WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN +#if WTF_OS_UNIX && !WTF_OS_SYMBIAN #define HAVE_SIGNAL_H 1 #endif -#if !WTF_PLATFORM_WIN_OS && !WTF_PLATFORM_SOLARIS && !WTF_PLATFORM_QNX \ - && !WTF_PLATFORM_SYMBIAN && !WTF_PLATFORM_HAIKU && !WTF_COMPILER_RVCT \ - && !WTF_PLATFORM_ANDROID && !WTF_PLATFORM_OS2 +#if !defined(HAVE_STRNSTR) +#if WTF_OS_DARWIN || WTF_OS_FREEBSD +#define HAVE_STRNSTR 1 +#endif +#endif + +#if !WTF_OS_WINDOWS && !WTF_OS_SOLARIS && !WTF_OS_QNX \ + && !WTF_OS_SYMBIAN && !WTF_OS_HAIKU && !WTF_OS_RVCT \ + && !WTF_OS_ANDROID && !WTF_PLATFORM_BREWMP #define HAVE_TM_GMTOFF 1 #define HAVE_TM_ZONE 1 #define HAVE_TIMEGM 1 -#endif +#endif -#if WTF_PLATFORM_DARWIN +#if WTF_OS_DARWIN #define HAVE_ERRNO_H 1 #define HAVE_LANGINFO_H 1 @@ -603,23 +782,37 @@ #define HAVE_SYS_PARAM_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TIMEB_H 1 +#define WTF_USE_ACCELERATE 1 -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !WTF_PLATFORM_IPHONE && !WTF_PLATFORM_QT +#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD) + +#define HAVE_DISPATCH_H 1 +#define HAVE_HOSTED_CORE_ANIMATION 1 + +#if !WTF_PLATFORM_IOS #define HAVE_MADV_FREE_REUSE 1 #define HAVE_MADV_FREE 1 #define HAVE_PTHREAD_SETNAME_NP 1 #endif -#if WTF_PLATFORM_IPHONE +#endif + +#if WTF_PLATFORM_IOS #define HAVE_MADV_FREE 1 #endif -#elif WTF_PLATFORM_WIN_OS +#elif WTF_OS_WINDOWS +#if WTF_OS_WINCE +#define HAVE_ERRNO_H 0 +#else #define HAVE_SYS_TIMEB_H 1 +#define HAVE_ALIGNED_MALLOC 1 +#define HAVE_ISDEBUGGERPRESENT 1 +#endif #define HAVE_VIRTUALALLOC 1 -#elif WTF_PLATFORM_SYMBIAN +#elif WTF_OS_SYMBIAN #define HAVE_ERRNO_H 1 #define HAVE_MMAP 0 @@ -632,7 +825,11 @@ #define HAVE_SYS_PARAM_H 1 #endif -#elif WTF_PLATFORM_QNX +#elif WTF_PLATFORM_BREWMP + +#define HAVE_ERRNO_H 1 + +#elif WTF_OS_QNX #define HAVE_ERRNO_H 1 #define HAVE_MMAP 1 @@ -641,7 +838,7 @@ #define HAVE_SYS_PARAM_H 1 #define HAVE_SYS_TIME_H 1 -#elif WTF_PLATFORM_ANDROID +#elif WTF_OS_ANDROID #define HAVE_ERRNO_H 1 #define HAVE_LANGINFO_H 0 @@ -651,23 +848,13 @@ #define HAVE_SYS_PARAM_H 1 #define HAVE_SYS_TIME_H 1 -#elif WTF_PLATFORM_OS2 - -#define HAVE_MMAP 1 -#define ENABLE_ASSEMBLER 1 -#define HAVE_ERRNO_H 1 -#define HAVE_STRINGS_H 1 -#define HAVE_SYS_PARAM_H 1 -#define HAVE_SYS_TIME_H 1 -#define HAVE_SYS_TIMEB_H 1 - #else /* FIXME: is this actually used or do other platforms generate their own config.h? */ #define HAVE_ERRNO_H 1 /* As long as Haiku doesn't have a complete support of locale this will be disabled. */ -#if !WTF_PLATFORM_HAIKU +#if !WTF_OS_HAIKU #define HAVE_LANGINFO_H 1 #endif #define HAVE_MMAP 1 @@ -680,6 +867,14 @@ /* ENABLE macro defaults */ +#if WTF_PLATFORM_QT +/* We must not customize the global operator new and delete for the Qt port. */ +#define ENABLE_GLOBAL_FASTMALLOC_NEW 0 +#if !WTF_OS_UNIX || WTF_OS_SYMBIAN +#define USE_SYSTEM_MALLOC 1 +#endif +#endif + /* fastMalloc match validation allows for runtime verification that new is matched by delete, fastMalloc is matched by fastFree, etc. */ #if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION) @@ -710,6 +905,10 @@ #define ENABLE_DRAG_SUPPORT 1 #endif +#if !defined(ENABLE_DATA_TRANSFER_ITEMS) +#define ENABLE_DATA_TRANSFER_ITEMS 0 +#endif + #if !defined(ENABLE_DASHBOARD_SUPPORT) #define ENABLE_DASHBOARD_SUPPORT 0 #endif @@ -718,14 +917,22 @@ #define ENABLE_INSPECTOR 1 #endif -#if !defined(ENABLE_MAC_JAVA_BRIDGE) -#define ENABLE_MAC_JAVA_BRIDGE 0 +#if !defined(ENABLE_JAVA_BRIDGE) +#define ENABLE_JAVA_BRIDGE 0 #endif #if !defined(ENABLE_NETSCAPE_PLUGIN_API) #define ENABLE_NETSCAPE_PLUGIN_API 1 #endif +#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE) +#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0 +#endif + +#if !defined(ENABLE_PURGEABLE_MEMORY) +#define ENABLE_PURGEABLE_MEMORY 0 +#endif + #if !defined(WTF_USE_PLUGIN_HOST_PROCESS) #define WTF_USE_PLUGIN_HOST_PROCESS 0 #endif @@ -738,6 +945,11 @@ #define ENABLE_OPCODE_STATS 0 #endif +#if !defined(ENABLE_GLOBAL_FASTMALLOC_NEW) +#define ENABLE_GLOBAL_FASTMALLOC_NEW 1 +#endif + +#define ENABLE_DEBUG_WITH_BREAKPOINT 0 #define ENABLE_SAMPLING_COUNTERS 0 #define ENABLE_SAMPLING_FLAGS 0 #define ENABLE_OPCODE_SAMPLING 0 @@ -753,10 +965,18 @@ #define ENABLE_GEOLOCATION 0 #endif +#if !defined(ENABLE_GESTURE_RECOGNIZER) +#define ENABLE_GESTURE_RECOGNIZER 0 +#endif + #if !defined(ENABLE_NOTIFICATIONS) #define ENABLE_NOTIFICATIONS 0 #endif +#if WTF_PLATFORM_IOS +#define ENABLE_TEXT_CARET 0 +#endif + #if !defined(ENABLE_TEXT_CARET) #define ENABLE_TEXT_CARET 1 #endif @@ -765,80 +985,88 @@ #define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0 #endif -#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) -#if (WTF_CPU_X86_64 && (WTF_PLATFORM_UNIX || WTF_PLATFORM_WIN_OS)) || WTF_CPU_IA64 || WTF_CPU_ALPHA +#if !defined(ENABLE_FULLSCREEN_API) +#define ENABLE_FULLSCREEN_API 0 +#endif + +#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) +#if (WTF_CPU_X86_64 && (WTF_OS_UNIX || WTF_OS_WINDOWS)) \ + || (WTF_CPU_IA64 && !WTF_CPU_IA64_32) \ + || WTF_CPU_ALPHA \ + || WTF_CPU_SPARC64 \ + || WTF_CPU_S390X \ + || WTF_CPU_PPC64 #define WTF_USE_JSVALUE64 1 -#elif WTF_CPU_ARM || WTF_CPU_PPC64 -#define WTF_USE_JSVALUE32 1 -#elif WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW -/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg -on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ -#define WTF_USE_JSVALUE32 1 #else #define WTF_USE_JSVALUE32_64 1 #endif -#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */ +#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */ #if !defined(ENABLE_REPAINT_THROTTLING) #define ENABLE_REPAINT_THROTTLING 0 #endif -#if !defined(ENABLE_JIT) - -/* The JIT is tested & working on x86_64 Mac */ -#if WTF_CPU_X86_64 && WTF_PLATFORM_MAC - #define ENABLE_JIT 1 -/* The JIT is tested & working on x86 Mac */ -#elif WTF_CPU_X86 && WTF_PLATFORM_MAC - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE - #define ENABLE_JIT 1 -/* The JIT is tested & working on x86 OS/2 */ -#elif WTF_CPU_X86 && WTF_PLATFORM_OS2 - #define ENABLE_JIT 1 -/* The JIT is tested & working on x86 Windows */ -#elif WTF_CPU_X86 && WTF_PLATFORM_WIN - #define ENABLE_JIT 1 -#elif WTF_CPU_SPARC - #define ENABLE_JIT 1 +/* Disable the JIT on versions of GCC prior to 4.1 */ +#if !defined(ENABLE_JIT) && WTF_COMPILER_GCC && !GCC_VERSION_AT_LEAST(4, 1, 0) +#define ENABLE_JIT 0 #endif -#if WTF_PLATFORM_QT -#if WTF_CPU_X86_64 && WTF_PLATFORM_DARWIN - #define ENABLE_JIT 1 -#elif WTF_CPU_X86 && WTF_PLATFORM_DARWIN - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100 - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1 -#elif WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100 - #define ENABLE_JIT 1 - #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX - #define ENABLE_JIT 1 +/* JIT is not implemented for 64 bit on MSVC */ +#if !defined(ENABLE_JIT) && WTF_COMPILER_MSVC && WTF_CPU_X86_64 +#define ENABLE_JIT 0 #endif -#endif /* PLATFORM(QT) */ -#endif /* !defined(ENABLE_JIT) */ +/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */ +#if !defined(ENABLE_JIT) \ + && (WTF_CPU_X86 || WTF_CPU_X86_64 || WTF_CPU_ARM || WTF_CPU_MIPS) \ + && (WTF_OS_DARWIN || !WTF_COMPILER_GCC || GCC_VERSION_AT_LEAST(4, 1, 0)) \ + && !WTF_OS_WINCE +#define ENABLE_JIT 1 +#endif +/* Currently only implemented for JSVALUE64, only tested on WTF_PLATFORM_MAC */ +#if ENABLE_JIT && WTF_USE_JSVALUE64 && WTF_PLATFORM_MAC +#define ENABLE_DFG_JIT 1 +/* Enabled with restrictions to circumvent known performance regressions. */ +#define ENABLE_DFG_JIT_RESTRICTIONS 1 +#endif + +/* Ensure that either the JIT or the interpreter has been enabled. */ +#if !defined(ENABLE_INTERPRETER) && !ENABLE_JIT +#define ENABLE_INTERPRETER 1 +#endif +#if !(ENABLE_JIT || ENABLE_INTERPRETER) +#error You have to have at least one execution model enabled to build JSC +#endif + +#if WTF_CPU_SH4 && WTF_PLATFORM_QT +#define ENABLE_JIT 1 +#define ENABLE_YARR 1 +#define ENABLE_YARR_JIT 1 +#define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1 +#define ENABLE_ASSEMBLER 1 +#endif + +/* Configure the JIT */ #if ENABLE_JIT -#ifndef ENABLE_JIT_OPTIMIZE_CALL -#define ENABLE_JIT_OPTIMIZE_CALL 1 -#endif -#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL -#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1 -#endif -#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS -#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1 -#endif -#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS -#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1 -#endif + #if WTF_CPU_ARM + #if !defined(ENABLE_JIT_USE_SOFT_MODULO) && WTF_ARM_ARCH_AT_LEAST(5) + #define ENABLE_JIT_USE_SOFT_MODULO 1 + #endif + #endif + + #ifndef ENABLE_JIT_OPTIMIZE_CALL + #define ENABLE_JIT_OPTIMIZE_CALL 1 + #endif + #ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL + #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1 + #endif + #ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS + #define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1 + #endif + #ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS + #define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1 + #endif #endif #if WTF_CPU_X86 && WTF_COMPILER_MSVC @@ -849,80 +1077,89 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define JSC_HOST_CALL #endif -#if WTF_COMPILER_GCC && !ENABLE_JIT +/* Configure the interpreter */ +#if WTF_COMPILER_GCC || (RVCT_VERSION_AT_LEAST(4, 0, 0, 0) && defined(__GNUC__)) #define HAVE_COMPUTED_GOTO 1 #endif - -#if ENABLE_JIT && defined(COVERAGE) - #define WTF_USE_INTERPRETER 0 -#else - #define WTF_USE_INTERPRETER 1 +#if HAVE_COMPUTED_GOTO && ENABLE_INTERPRETER +#define ENABLE_COMPUTED_GOTO_INTERPRETER 1 #endif -/* Yet Another Regex Runtime. */ -#if !defined(ENABLE_YARR_JIT) +/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc. Results dumped at exit */ +#define ENABLE_REGEXP_TRACING 0 -/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */ -#if (WTF_CPU_X86 \ - || WTF_CPU_X86_64 \ - || WTF_CPU_SPARC \ - || WTF_CPU_ARM_TRADITIONAL \ - || WTF_CPU_ARM_THUMB2 \ - || WTF_CPU_X86) -#define ENABLE_YARR_JIT 1 -#else +/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */ +#if WTF_PLATFORM_CHROMIUM #define ENABLE_YARR_JIT 0 + +#elif ENABLE_JIT && !defined(ENABLE_YARR_JIT) +#define ENABLE_YARR_JIT 1 + +/* Setting this flag compares JIT results with interpreter results. */ +#define ENABLE_YARR_JIT_DEBUG 0 #endif -#endif /* !defined(ENABLE_YARR_JIT) */ - -#if (ENABLE_JIT || ENABLE_YARR_JIT) +#if ENABLE_JIT || ENABLE_YARR_JIT #define ENABLE_ASSEMBLER 1 #endif /* Setting this flag prevents the assembler from using RWX memory; this may improve security but currectly comes at a significant performance cost. */ -#if WTF_PLATFORM_IPHONE +#if WTF_PLATFORM_IOS #define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1 -#else -#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0 #endif -#if !defined(ENABLE_PAN_SCROLLING) && WTF_PLATFORM_WIN_OS +/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in. + On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */ +#if ENABLE_ASSEMBLER +#if WTF_CPU_X86_64 +#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1 +#else +#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1 +#endif +#endif + +#if !defined(ENABLE_PAN_SCROLLING) && WTF_OS_WINDOWS #define ENABLE_PAN_SCROLLING 1 #endif -/* Use the QXmlStreamReader implementation for XMLTokenizer */ +#if !defined(ENABLE_SMOOTH_SCROLLING) +#define ENABLE_SMOOTH_SCROLLING 0 +#endif + +#if !defined(ENABLE_WEB_ARCHIVE) +#define ENABLE_WEB_ARCHIVE 0 +#endif + +/* Use the QXmlStreamReader implementation for XMLDocumentParser */ /* Use the QXmlQuery implementation for XSLTProcessor */ #if WTF_PLATFORM_QT #define WTF_USE_QXMLSTREAM 1 #define WTF_USE_QXMLQUERY 1 #endif -#if !WTF_PLATFORM_QT -#define WTF_USE_FONT_FAST_PATH 1 +#if WTF_PLATFORM_MAC +/* Complex text framework */ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#define WTF_USE_ATSUI 0 +#define WTF_USE_CORE_TEXT 1 +#else +#define WTF_USE_ATSUI 1 +#define WTF_USE_CORE_TEXT 0 +#endif #endif /* Accelerated compositing */ -#if WTF_PLATFORM_MAC -#if !defined(BUILDING_ON_TIGER) -#define WTF_USE_ACCELERATED_COMPOSITING 1 -#endif -#endif - -#if WTF_PLATFORM_IPHONE +#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER)) || WTF_PLATFORM_IOS || WTF_PLATFORM_QT || (WTF_PLATFORM_WIN && !WTF_OS_WINCE &&!defined(WIN_CAIRO)) #define WTF_USE_ACCELERATED_COMPOSITING 1 #endif -/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with - with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and - off in one place. */ -//#if WTF_PLATFORM_WIN -//#include "QuartzCorePresent.h" -//#if QUARTZCORE_PRESENT -//#define WTF_USE_ACCELERATED_COMPOSITING 1 -//#define ENABLE_3D_RENDERING 1 -//#endif -//#endif +#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || WTF_PLATFORM_IOS +#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1 +#endif + +#if WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) +#define WTF_USE_AVFOUNDATION 1 +#endif #if WTF_COMPILER_GCC #define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result)) @@ -930,7 +1167,7 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define WARN_UNUSED_RETURN #endif -#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_PLATFORM_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK)) +#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 @@ -939,4 +1176,46 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define ENABLE_JSC_ZOMBIES 0 +/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */ +#if WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_QT +#define WTF_USE_PLATFORM_STRATEGIES 1 +#endif + +#if WTF_PLATFORM_WIN +#define WTF_USE_CROSS_PLATFORM_CONTEXT_MENUS 1 +#endif + +/* Geolocation request policy. pre-emptive policy is to acquire user permission before acquiring location. + Client based implementations will have option to choose between pre-emptive and nonpre-emptive permission policy. + pre-emptive permission policy is enabled by default for all client-based implementations. */ +#if ENABLE_CLIENT_BASED_GEOLOCATION +#define WTF_USE_PREEMPT_GEOLOCATION_PERMISSION 1 +#endif + +#if WTF_CPU_ARM_THUMB2 +#define ENABLE_BRANCH_COMPACTION 1 +#endif + +#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP) +#define ENABLE_THREADING_OPENMP 1 +#endif + +#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE_SINGLE_THREADED && (ENABLE_THREADING_GENERIC || ENABLE_THREADING_LIBDISPATCH || ENABLE_THREADING_OPENMP) +#define ENABLE_PARALLEL_JOBS 1 +#endif + +#if ENABLE_GLIB_SUPPORT +#include "GTypedefs.h" +#endif + +/* FIXME: This define won't be needed once #27551 is fully landed. However, + since most ports try to support sub-project independence, adding new headers + to WTF causes many ports to break, and so this way we can address the build + breakages one port at a time. */ +#define WTF_USE_EXPORT_MACROS 0 + +#if WTF_PLATFORM_QT || WTF_PLATFORM_GTK +#define WTF_USE_UNIX_DOMAIN_SOCKETS 1 +#endif + #endif /* WTF_Platform_h */ diff --git a/js/src/jit-test/tests/basic/bug632964-regexp.js b/js/src/jit-test/tests/basic/bug632964-regexp.js index 7151d3713647..75612dbc735d 100644 --- a/js/src/jit-test/tests/basic/bug632964-regexp.js +++ b/js/src/jit-test/tests/basic/bug632964-regexp.js @@ -1,5 +1,3 @@ -// |jit-test| error: InternalError: regular expression too complex - var sText = "s"; for (var i = 0; i < 250000; ++i) @@ -12,6 +10,5 @@ var match = sText.match(/s(\s|.)*?e/gi); //var match = sText.match(/s([\s\S]*?)e/gi); //var match = sText.match(/s(?:[\s\S]*?)e/gi); var end = new Date(); -print(end - start); assertEq(match.length, 1); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index ecc336cdc4c3..c88fae9fdaf0 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -48,6 +48,7 @@ #include "jstracer.h" #include "jswrapper.h" #include "assembler/wtf/Platform.h" +#include "yarr/BumpPointerAllocator.h" #include "methodjit/MethodJIT.h" #include "methodjit/PolyIC.h" #include "methodjit/MonoIC.h" @@ -73,6 +74,9 @@ JSCompartment::JSCompartment(JSRuntime *rt) active(false), #ifdef JS_METHODJIT jaegerCompartment(NULL), +#endif +#if ENABLE_YARR_JIT + regExpAllocator(NULL), #endif propertyTree(thisForCtor()), emptyArgumentsShape(NULL), @@ -84,9 +88,6 @@ JSCompartment::JSCompartment(JSRuntime *rt) initialRegExpShape(NULL), initialStringShape(NULL), debugMode(rt->debugMode), -#if ENABLE_YARR_JIT - regExpAllocator(NULL), -#endif mathCache(NULL) { JS_INIT_CLIST(&scripts); @@ -135,11 +136,9 @@ JSCompartment::init() return false; #endif -#if ENABLE_YARR_JIT - regExpAllocator = rt->new_(); + regExpAllocator = rt->new_(); if (!regExpAllocator) return false; -#endif if (!backEdgeTable.init()) return false; diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 5b3f16643050..8827a275f796 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -54,11 +54,8 @@ #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */ #endif -namespace JSC { - -class ExecutableAllocator; - -} +namespace JSC { class ExecutableAllocator; } +namespace WTF { class BumpPointerAllocator; } namespace js { @@ -420,6 +417,7 @@ struct JS_FRIEND_API(JSCompartment) { */ size_t getMjitCodeSize() const; #endif + WTF::BumpPointerAllocator *regExpAllocator; /* * Shared scope property tree, and arena-pool for allocating its nodes. @@ -466,8 +464,6 @@ struct JS_FRIEND_API(JSCompartment) { bool debugMode; // true iff debug mode on JSCList scripts; // scripts in this compartment - JSC::ExecutableAllocator *regExpAllocator; - js::NativeIterCache nativeIterCache; typedef js::Maybe LazyToSourceCache; diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 0df8ae536a47..3d9f09f56559 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -59,8 +59,6 @@ #include "jsobjinlines.h" #include "jsregexpinlines.h" -#include "yarr/RegexParser.h" - #ifdef JS_TRACER #include "jstracer.h" using namespace nanojit; @@ -193,11 +191,11 @@ js_ObjectIsRegExp(JSObject *obj) */ void -RegExp::handleYarrError(JSContext *cx, int error) +RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error) { switch (error) { case JSC::Yarr::NoError: - JS_NOT_REACHED("Precondition violation: an error must have occurred."); + JS_NOT_REACHED("Called reportYarrError with value for no error"); return; #define COMPILE_EMSG(__code, __msg) \ case JSC::Yarr::__code: \ @@ -210,49 +208,16 @@ RegExp::handleYarrError(JSContext *cx, int error) COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN); COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */ COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE); + COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE); COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE); - COMPILE_EMSG(CharacterClassRangeSingleChar, JSMSG_BAD_CLASS_RANGE); - COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH); COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER); - COMPILE_EMSG(HitRecursionLimit, JSMSG_REGEXP_TOO_COMPLEX); + COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH); #undef COMPILE_EMSG default: - JS_NOT_REACHED("Precondition violation: unknown Yarr error code."); + JS_NOT_REACHED("Unknown Yarr error code"); } } -void -RegExp::handlePCREError(JSContext *cx, int error) -{ -#define REPORT(msg_) \ - JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \ - return - switch (error) { - case -2: REPORT(JSMSG_REGEXP_TOO_COMPLEX); - case 0: JS_NOT_REACHED("Precondition violation: an error must have occurred."); - case 1: REPORT(JSMSG_TRAILING_SLASH); - case 2: REPORT(JSMSG_TRAILING_SLASH); - case 3: REPORT(JSMSG_REGEXP_TOO_COMPLEX); - case 4: REPORT(JSMSG_BAD_QUANTIFIER); - case 5: REPORT(JSMSG_BAD_QUANTIFIER); - case 6: REPORT(JSMSG_BAD_CLASS_RANGE); - case 7: REPORT(JSMSG_REGEXP_TOO_COMPLEX); - case 8: REPORT(JSMSG_BAD_CLASS_RANGE); - case 9: REPORT(JSMSG_BAD_QUANTIFIER); - case 10: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN); - case 11: REPORT(JSMSG_REGEXP_TOO_COMPLEX); - case 12: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN); - case 13: REPORT(JSMSG_REGEXP_TOO_COMPLEX); - case 14: REPORT(JSMSG_MISSING_PAREN); - case 15: REPORT(JSMSG_BAD_BACKREF); - case 16: REPORT(JSMSG_REGEXP_TOO_COMPLEX); - case 17: REPORT(JSMSG_REGEXP_TOO_COMPLEX); - default: - JS_NOT_REACHED("Precondition violation: unknown PCRE error code."); - } -#undef REPORT -} - bool RegExp::parseFlags(JSContext *cx, JSString *flagStr, uintN *flagsOut) { @@ -929,3 +894,4 @@ js_InitRegExpClass(JSContext *cx, JSObject *global) return proto; } + diff --git a/js/src/jsregexpinlines.h b/js/src/jsregexpinlines.h index 70db45413e1d..305cf1590462 100644 --- a/js/src/jsregexpinlines.h +++ b/js/src/jsregexpinlines.h @@ -48,12 +48,13 @@ #include "jsobjinlines.h" #include "jsstrinlines.h" +#include "methodjit/MethodJIT.h" #include "assembler/wtf/Platform.h" +#include "yarr/BumpPointerAllocator.h" +#include "yarr/Yarr.h" #if ENABLE_YARR_JIT -#include "yarr/yarr/RegexJIT.h" -#else -#include "yarr/pcre/pcre.h" +#include "yarr/YarrJIT.h" #endif namespace js { @@ -95,10 +96,10 @@ regexp_statics_construct(JSContext *cx, GlobalObject *parent) class RegExp { #if ENABLE_YARR_JIT - JSC::Yarr::RegexCodeBlock compiled; -#else - JSRegExp *compiled; + /* native code is valid only if codeBlock.isFallBack() == false */ + JSC::Yarr::YarrCodeBlock codeBlock; #endif + JSC::Yarr::BytecodePattern *byteCode; JSLinearString *source; size_t refCount; unsigned parenCount; /* Must be |unsigned| to interface with YARR. */ @@ -111,7 +112,11 @@ class RegExp #endif RegExp(JSLinearString *source, uint32 flags, JSCompartment *compartment) - : compiled(), source(source), refCount(1), parenCount(0), flags(flags) + : +#if ENABLE_YARR_JIT + codeBlock(), +#endif + byteCode(NULL), source(source), refCount(1), parenCount(0), flags(flags) #ifdef DEBUG , compartment(compartment) #endif @@ -120,17 +125,18 @@ class RegExp JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; ~RegExp() { -#if !ENABLE_YARR_JIT - if (compiled) - jsRegExpFree(compiled); +#if ENABLE_YARR_JIT + codeBlock.release(); #endif + // YYY + if (byteCode) + delete byteCode; } bool compileHelper(JSContext *cx, JSLinearString &pattern); bool compile(JSContext *cx); static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY; - void handlePCREError(JSContext *cx, int error); - void handleYarrError(JSContext *cx, int error); + void reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error); static inline bool initArena(JSContext *cx); static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount); static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount); @@ -318,9 +324,6 @@ inline bool RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr, size_t *lastIndex, bool test, Value *rval) { -#if !ENABLE_YARR_JIT - JS_ASSERT(compiled); -#endif const size_t pairCount = parenCount + 1; const size_t bufCount = pairCount * 3; /* Should be x2, but PCRE has... needs. */ const size_t matchItemCount = pairCount * 2; @@ -360,27 +363,20 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr, inputOffset = *lastIndex; } + int result; #if ENABLE_YARR_JIT - int result = JSC::Yarr::executeRegex(cx, compiled, chars, *lastIndex - inputOffset, len, buf, - bufCount); + if (!codeBlock.isFallBack()) + result = JSC::Yarr::execute(codeBlock, chars, *lastIndex - inputOffset, len, buf); + else + result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf); #else - int result = jsRegExpExecute(cx, compiled, chars, len, *lastIndex - inputOffset, buf, - bufCount); + result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf); #endif if (result == -1) { *rval = NullValue(); return true; } - if (result < 0) { -#if ENABLE_YARR_JIT - handleYarrError(cx, result); -#else - handlePCREError(cx, result); -#endif - return false; - } - /* * Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so * just do another pass. @@ -460,53 +456,44 @@ RegExp::createObjectNoStatics(JSContext *cx, const jschar *chars, size_t length, return obj; } -#ifdef ANDROID -static bool -YarrJITIsBroken(JSContext *cx) +/* + * This function should be deleted once we can. See bug 604774. + */ +static inline bool +EnableYarrJIT(JSContext *cx) { -#if defined(JS_TRACER) && defined(JS_METHODJIT) - /* FIXME/bug 604774: dead code walking. - * - * If both JITs are disabled, assume they were disabled because - * we're running on a blacklisted device. - */ - return !cx->traceJitEnabled && !cx->methodJitEnabled; +#if defined ANDROID && defined(JS_TRACER) && defined(JS_METHODJIT) + return cx->traceJitEnabled || cx->methodJitEnabled; #else - return false; + return true; #endif } -#endif /* ANDROID */ inline bool RegExp::compileHelper(JSContext *cx, JSLinearString &pattern) { -#if ENABLE_YARR_JIT - bool fellBack = false; - int error = 0; - jitCompileRegex(*cx->compartment->regExpAllocator, compiled, pattern, parenCount, error, fellBack, ignoreCase(), multiline() -#ifdef ANDROID - /* Temporary gross hack to work around buggy kernels. */ - , YarrJITIsBroken(cx) -#endif -); - if (!error) - return true; - if (fellBack) - handlePCREError(cx, error); - else - handleYarrError(cx, error); - return false; -#else - int error = 0; - compiled = jsRegExpCompile(pattern.chars(), pattern.length(), - ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase, - multiline() ? JSRegExpMultiline : JSRegExpSingleLine, - &parenCount, &error); - if (!error) - return true; - handlePCREError(cx, error); - return false; + JSC::Yarr::ErrorCode yarrError; + JSC::Yarr::YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError); + if (yarrError) { + reportYarrError(cx, yarrError); + return false; + } + parenCount = yarrPattern.m_numSubpatterns; + +#if ENABLE_YARR_JIT && defined(JS_METHODJIT) + if (EnableYarrJIT(cx) && !yarrPattern.m_containsBackreferences) { + JSC::Yarr::JSGlobalData globalData(cx->compartment->jaegerCompartment->execAlloc()); + JSC::Yarr::jitCompile(yarrPattern, &globalData, codeBlock); + if (!codeBlock.isFallBack()) + return true; + } else { + codeBlock.setFallBack(true); + } #endif + + byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get(); + + return true; } inline bool diff --git a/js/src/jsutil.h b/js/src/jsutil.h index 1b249c1874a7..37b44d137b2e 100644 --- a/js/src/jsutil.h +++ b/js/src/jsutil.h @@ -374,11 +374,21 @@ JS_END_EXTERN_C QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3) {\ JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\ }\ +\ + template \ + QUALIFIERS T *new_(P1 &p1, const P2 &p2, const P3 &p3) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\ + }\ \ template \ QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4) {\ JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\ }\ +\ + template \ + QUALIFIERS T *new_(const P1 &p1, const P2 &p2, P3 &p3, const P4 &p4) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\ + }\ \ template \ QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {\ diff --git a/js/src/jsvector.h b/js/src/jsvector.h index 3d413c1f64b6..4eaf58b6a4e7 100644 --- a/js/src/jsvector.h +++ b/js/src/jsvector.h @@ -208,12 +208,30 @@ class Vector : private AllocPolicy /* compute constants */ + /* + * Consider element size to be 1 for buffer sizing if there are + * 0 inline elements. This allows us to compile when the definition + * of the element type is not visible here. + * + * Explicit specialization is only allowed at namespace scope, so + * in order to keep everything here, we use a dummy template + * parameter with partial specialization. + */ + template + struct ElemSize { + static const size_t result = sizeof(T); + }; + template + struct ElemSize<0, Dummy> { + static const size_t result = 1; + }; + static const size_t sInlineCapacity = - tl::Min::result; + tl::Min::result>::result; /* Calculate inline buffer size; avoid 0-sized array. */ static const size_t sInlineBytes = - tl::Max<1, sInlineCapacity * sizeof(T)>::result; + tl::Max<1, sInlineCapacity * ElemSize::result>::result; /* member data */ diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 603d76a59c88..b03c6afa0990 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -503,7 +503,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp) analyze::Bytecode *opinfo = analysis->maybeCode(i); if (opinfo && opinfo->safePoint) { Label L = jumpMap[i]; - JS_ASSERT(L.isValid()); + JS_ASSERT(L.isSet()); jitNmap[ix].bcOff = i; jitNmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L)); ix++; @@ -625,7 +625,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp) cursor += sizeof(ic::EqualityICInfo) * jit->nEqualityICs; for (size_t i = 0; i < jit->nEqualityICs; i++) { uint32 offs = uint32(equalityICs[i].jumpTarget - script->code); - JS_ASSERT(jumpMap[offs].isValid()); + JS_ASSERT(jumpMap[offs].isSet()); jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]); jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry); jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall); @@ -650,7 +650,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp) continue; uint32 offs = uint32(traceICs[i].jumpTarget - script->code); - JS_ASSERT(jumpMap[offs].isValid()); + JS_ASSERT(jumpMap[offs].isSet()); jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint); jitTraceICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]); jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry); @@ -800,7 +800,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp) for (size_t i = 0; i < jumpTableOffsets.length(); i++) { uint32 offset = jumpTableOffsets[i]; - JS_ASSERT(jumpMap[offset].isValid()); + JS_ASSERT(jumpMap[offset].isSet()); jumpVec[i] = (void *)(result + masm.distanceOf(jumpMap[offset])); } @@ -2089,7 +2089,7 @@ JSC::MacroAssembler::Label mjit::Compiler::labelOf(jsbytecode *pc) { uint32 offs = uint32(pc - script->code); - JS_ASSERT(jumpMap[offs].isValid()); + JS_ASSERT(jumpMap[offs].isSet()); return jumpMap[offs]; } diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp index bd738b92ba2b..b55b0dba48a5 100644 --- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -846,12 +846,7 @@ static inline void Destroy(T &t) mjit::JITScript::~JITScript() { -#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) - void *addr = code.m_code.executableAddress(); - memset(addr, 0xcc, code.m_size); -#endif - - code.m_executablePool->release(); + code.release(); #if defined JS_POLYIC ic::GetElementIC *getElems_ = getElems(); diff --git a/js/src/methodjit/TrampolineCompiler.cpp b/js/src/methodjit/TrampolineCompiler.cpp index a6ac9d709f0e..77bb148ba311 100644 --- a/js/src/methodjit/TrampolineCompiler.cpp +++ b/js/src/methodjit/TrampolineCompiler.cpp @@ -93,7 +93,7 @@ TrampolineCompiler::compileTrampoline(Trampolines::TrampolinePtr *where, Label entry = masm.label(); CHECK_RESULT(generator(masm)); - JS_ASSERT(entry.isValid()); + JS_ASSERT(entry.isSet()); bool ok; JSC::LinkBuffer buffer(&masm, execAlloc, poolp, &ok); diff --git a/js/src/yarr/wtf/ASCIICType.h b/js/src/yarr/ASCIICType.h similarity index 81% rename from js/src/yarr/wtf/ASCIICType.h rename to js/src/yarr/ASCIICType.h index cf53d9ac0c87..a3ae9f4455e2 100644 --- a/js/src/yarr/wtf/ASCIICType.h +++ b/js/src/yarr/ASCIICType.h @@ -1,4 +1,7 @@ -/* +/* -*- 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) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,12 +27,13 @@ * 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. - */ + * + * ***** END LICENSE BLOCK ***** */ #ifndef WTF_ASCIICType_h #define WTF_ASCIICType_h -#include "yarr/jswtfbridge.h" +#include "assembler/wtf/Assertions.h" // The behavior of many of the functions in the header is dependent // on the current locale. But in the WebKit project, all uses of those functions @@ -49,6 +53,7 @@ namespace WTF { inline bool isASCII(wchar_t c) { return !(c & ~0x7F); } #endif inline bool isASCII(int c) { return !(c & ~0x7F); } + inline bool isASCII(unsigned c) { return !(c & ~0x7F); } inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } @@ -56,6 +61,7 @@ namespace WTF { inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } #endif inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } + inline bool isASCIIAlpha(unsigned c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } @@ -63,6 +69,7 @@ namespace WTF { inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } #endif inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } + inline bool isASCIIAlphanumeric(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); } inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); } @@ -70,6 +77,7 @@ namespace WTF { inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); } #endif inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); } + inline bool isASCIIDigit(unsigned c) { return (c >= '0') & (c <= '9'); } inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } @@ -77,6 +85,7 @@ namespace WTF { inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } #endif inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } + inline bool isASCIIHexDigit(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); } inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); } @@ -84,6 +93,7 @@ namespace WTF { inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); } #endif inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); } + inline bool isASCIIOctalDigit(unsigned c) { return (c >= '0') & (c <= '7'); } inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; } inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; } @@ -91,6 +101,7 @@ namespace WTF { inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; } #endif inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; } + inline bool isASCIILower(unsigned c) { return c >= 'a' && c <= 'z'; } inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; } inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; } @@ -98,6 +109,7 @@ namespace WTF { inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; } #endif inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; } + inline bool isASCIIUpper(unsigned c) { return c >= 'A' && c <= 'Z'; } /* Statistics from a run of Apple's page load test for callers of isASCIISpace: @@ -118,6 +130,7 @@ namespace WTF { inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } #endif inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } + inline bool isASCIISpace(unsigned c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); } inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); } @@ -125,20 +138,24 @@ namespace WTF { inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); } #endif inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); } + inline unsigned toASCIILower(unsigned c) { return c | ((c >= 'A' && c <= 'Z') << 5); } + // FIXME: Why do these need static_cast? inline char toASCIIUpper(char c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } inline unsigned short toASCIIUpper(unsigned short c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) inline wchar_t toASCIIUpper(wchar_t c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } #endif inline int toASCIIUpper(int c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } + inline unsigned toASCIIUpper(unsigned c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline int toASCIIHexValue(char c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned short c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline int toASCIIHexValue(wchar_t c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } #endif - inline int toASCIIHexValue(int c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(unsigned c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; } inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; } @@ -146,7 +163,7 @@ namespace WTF { inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; } #endif inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; } - + inline bool isASCIIPrintable(unsigned c) { return c >= ' ' && c <= '~'; } } using WTF::isASCII; diff --git a/js/src/yarr/BumpPointerAllocator.h b/js/src/yarr/BumpPointerAllocator.h new file mode 100644 index 000000000000..8ef5a780f9d8 --- /dev/null +++ b/js/src/yarr/BumpPointerAllocator.h @@ -0,0 +1,254 @@ +/* -*- 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) 2010 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. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef BumpPointerAllocator_h +#define BumpPointerAllocator_h + +#include "PageAllocation.h" + +namespace WTF { + +#define MINIMUM_BUMP_POOL_SIZE 0x1000 + +class BumpPointerPool { +public: + // ensureCapacity will check whether the current pool has capacity to + // allocate 'size' bytes of memory If it does not, it will attempt to + // allocate a new pool (which will be added to this one in a chain). + // + // If allocation fails (out of memory) this method will return null. + // If the return value is non-null, then callers should update any + // references they have to this current (possibly full) BumpPointerPool + // to instead point to the newly returned BumpPointerPool. + BumpPointerPool* ensureCapacity(size_t size) + { + void* allocationEnd = static_cast(m_current) + size; + ASSERT(allocationEnd > m_current); // check for overflow + if (allocationEnd <= static_cast(this)) + return this; + return ensureCapacityCrossPool(this, size); + } + + // alloc should only be called after calling ensureCapacity; as such + // alloc will never fail. + void* alloc(size_t size) + { + void* current = m_current; + void* allocationEnd = static_cast(current) + size; + ASSERT(allocationEnd > current); // check for overflow + ASSERT(allocationEnd <= static_cast(this)); + m_current = allocationEnd; + return current; + } + + // The dealloc method releases memory allocated using alloc. Memory + // must be released in a LIFO fashion, e.g. if the client calls alloc + // four times, returning pointer A, B, C, D, then the only valid order + // in which these may be deallocaed is D, C, B, A. + // + // The client may optionally skip some deallocations. In the example + // above, it would be valid to only explicitly dealloc C, A (D being + // dealloced along with C, B along with A). + // + // If pointer was not allocated from this pool (or pools) then dealloc + // will CRASH(). Callers should update any references they have to + // this current BumpPointerPool to instead point to the returned + // BumpPointerPool. + BumpPointerPool* dealloc(void* position) + { + if ((position >= m_start) && (position <= static_cast(this))) { + ASSERT(position <= m_current); + m_current = position; + return this; + } + return deallocCrossPool(this, position); + } + +private: + // Placement operator new, returns the last 'size' bytes of allocation for use as this. + void* operator new(size_t size, const PageAllocation& allocation) + { + ASSERT(size < allocation.size()); + return reinterpret_cast(reinterpret_cast(allocation.base()) + allocation.size()) - size; + } + + BumpPointerPool(const PageAllocation& allocation) + : m_current(allocation.base()) + , m_start(allocation.base()) + , m_next(0) + , m_previous(0) + , m_allocation(allocation) + { + } + + static BumpPointerPool* create(size_t minimumCapacity = 0) + { + // Add size of BumpPointerPool object, check for overflow. + minimumCapacity += sizeof(BumpPointerPool); + if (minimumCapacity < sizeof(BumpPointerPool)) + return 0; + + size_t poolSize = MINIMUM_BUMP_POOL_SIZE; + while (poolSize < minimumCapacity) { + poolSize <<= 1; + // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2! + ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1))); + if (!poolSize) + return 0; + } + + PageAllocation allocation = PageAllocation::allocate(poolSize); + if (!!allocation) + return new(allocation) BumpPointerPool(allocation); + return 0; + } + + void shrink() + { + ASSERT(!m_previous); + m_current = m_start; + while (m_next) { + BumpPointerPool* nextNext = m_next->m_next; + m_next->destroy(); + m_next = nextNext; + } + } + + void destroy() + { + m_allocation.deallocate(); + } + + static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size) + { + // The pool passed should not have capacity, so we'll start with the next one. + ASSERT(previousPool); + ASSERT((static_cast(previousPool->m_current) + size) > previousPool->m_current); // check for overflow + ASSERT((static_cast(previousPool->m_current) + size) > static_cast(previousPool)); + BumpPointerPool* pool = previousPool->m_next; + + while (true) { + if (!pool) { + // We've run to the end; allocate a new pool. + pool = BumpPointerPool::create(size); + previousPool->m_next = pool; + pool->m_previous = previousPool; + return pool; + } + + // + void* current = pool->m_current; + void* allocationEnd = static_cast(current) + size; + ASSERT(allocationEnd > current); // check for overflow + if (allocationEnd <= static_cast(pool)) + return pool; + } + } + + static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position) + { + // Should only be called if position is not in the current pool. + ASSERT((position < pool->m_start) || (position > static_cast(pool))); + + while (true) { + // Unwind the current pool to the start, move back in the chain to the previous pool. + pool->m_current = pool->m_start; + pool = pool->m_previous; + + // position was nowhere in the chain! + if (!pool) + CRASH(); + + if ((position >= pool->m_start) && (position <= static_cast(pool))) { + ASSERT(position <= pool->m_current); + pool->m_current = position; + return pool; + } + } + } + + void* m_current; + void* m_start; + BumpPointerPool* m_next; + BumpPointerPool* m_previous; + PageAllocation m_allocation; + + friend class BumpPointerAllocator; +}; + +// A BumpPointerAllocator manages a set of BumpPointerPool objects, which +// can be used for LIFO (stack like) allocation. +// +// To begin allocating using this class call startAllocator(). The result +// of this method will be null if the initial pool allocation fails, or a +// pointer to a BumpPointerPool object that can be used to perform +// allocations. Whilst running no memory will be released until +// stopAllocator() is called. At this point all allocations made through +// this allocator will be reaped, and underlying memory may be freed. +// +// (In practice we will still hold on to the initial pool to allow allocation +// to be quickly restared, but aditional pools will be freed). +// +// This allocator is non-renetrant, it is encumbant on the clients to ensure +// startAllocator() is not called again until stopAllocator() has been called. +class BumpPointerAllocator { +public: + BumpPointerAllocator() + : m_head(0) + { + } + + ~BumpPointerAllocator() + { + if (m_head) + m_head->destroy(); + } + + BumpPointerPool* startAllocator() + { + if (!m_head) + m_head = BumpPointerPool::create(); + return m_head; + } + + void stopAllocator() + { + if (m_head) + m_head->shrink(); + } + +private: + BumpPointerPool* m_head; +}; + +} + +using WTF::BumpPointerAllocator; + +#endif // BumpPointerAllocator_h diff --git a/js/src/yarr/Makefile b/js/src/yarr/Makefile deleted file mode 100644 index c824cdb96b6c..000000000000 --- a/js/src/yarr/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -INCLUDES := -I. -Iyarr -Iwtf -I../assembler/assembler -I../assembler - -all: - $(CXX) -g3 -c $(INCLUDES) yarr/*.cpp - $(CXX) -g3 $(INCLUDES) TestMain.cpp *.o diff --git a/js/src/yarr/OSAllocator.h b/js/src/yarr/OSAllocator.h new file mode 100644 index 000000000000..ecfdc3b042ec --- /dev/null +++ b/js/src/yarr/OSAllocator.h @@ -0,0 +1,103 @@ +/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef OSAllocator_h +#define OSAllocator_h + +#include +#include "wtfbridge.h" +#include "assembler/wtf/VMTags.h" +#include "assembler/wtf/Assertions.h" + +namespace WTF { + +class OSAllocator { +public: + enum Usage { + UnknownUsage = -1, + FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY, + JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY, + JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY, + JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY + }; + + // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state, + // releaseDecommitted should be called on a region of VM allocated by a single reservation, + // the memory must all currently be in a decommitted state. + static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false); + static void releaseDecommitted(void*, size_t); + + // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should + // never be accessed, since the OS may not have attached physical memory for these regions). + // Clients should only call commit on uncommitted regions and decommit on committed regions. + static void commit(void*, size_t, bool writable, bool executable); + static void decommit(void*, size_t); + + // These methods are symmetric; reserveAndCommit allocates VM in an committed state, + // decommitAndRelease should be called on a region of VM allocated by a single reservation, + // the memory must all currently be in a committed state. + static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false); + static void decommitAndRelease(void* base, size_t size); + + // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than + // committing/decommitting the entire region additional parameters allow a subregion to be + // specified. + static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false); + static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize); +}; + +inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable) +{ + void* base = reserveUncommitted(reserveSize, usage, writable, executable); + commit(base, commitSize, writable, executable); + return base; +} + +inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize) +{ + ASSERT(decommitBase >= releaseBase && (static_cast(decommitBase) + decommitSize) <= (static_cast(releaseBase) + releaseSize)); +#if WTF_OS_WINCE || WTF_OS_SYMBIAN + // On most platforms we can actually skip this final decommit; releasing the VM will + // implicitly decommit any physical memory in the region. This is not true on WINCE. + // On Symbian, this makes implementation simpler and better aligned with the RChunk API + decommit(decommitBase, decommitSize); +#endif + releaseDecommitted(releaseBase, releaseSize); +} + +inline void OSAllocator::decommitAndRelease(void* base, size_t size) +{ + decommitAndRelease(base, size, base, size); +} + +} // namespace WTF + +using WTF::OSAllocator; + +#endif // OSAllocator_h diff --git a/js/src/yarr/OSAllocatorPosix.cpp b/js/src/yarr/OSAllocatorPosix.cpp new file mode 100644 index 000000000000..57c240b22fe5 --- /dev/null +++ b/js/src/yarr/OSAllocatorPosix.cpp @@ -0,0 +1,129 @@ +/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN + +#include "OSAllocator.h" + +#include +#include +#include "wtf/Assertions.h" + +namespace WTF { + +void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable) +{ + void* result = reserveAndCommit(bytes, usage, writable, executable); +#if HAVE_MADV_FREE_REUSE + // To support the "reserve then commit" model, we have to initially decommit. + while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } +#endif + return result; +} + +void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable) +{ + // All POSIX reservations start out logically committed. + int protection = PROT_READ; + if (writable) + protection |= PROT_WRITE; + if (executable) + protection |= PROT_EXEC; + + int flags = MAP_PRIVATE | MAP_ANON; + +#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER) + int fd = usage; +#else + int fd = -1; +#endif + + void* result = 0; +#if (WTF_OS_DARWIN && WTF_CPU_X86_64) + if (executable) { + // Cook up an address to allocate at, using the following recipe: + // 17 bits of zero, stay in userspace kids. + // 26 bits of randomness for ASLR. + // 21 bits of zero, at least stay aligned within one level of the pagetables. + // + // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854), + // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus + // 2^24, which should put up somewhere in the middle of userspace (in the address range + // 0x200000000000 .. 0x5fffffffffff). + intptr_t randomLocation = 0; + randomLocation = arc4random() & ((1 << 25) - 1); + randomLocation += (1 << 24); + randomLocation <<= 21; + result = reinterpret_cast(randomLocation); + } +#endif + + result = mmap(result, bytes, protection, flags, fd, 0); + if (result == MAP_FAILED) + CRASH(); + return result; +} + +void OSAllocator::commit(void* address, size_t bytes, bool, bool) +{ +#if HAVE_MADV_FREE_REUSE + while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { } +#else + // Non-MADV_FREE_REUSE reservations automatically commit on demand. + UNUSED_PARAM(address); + UNUSED_PARAM(bytes); +#endif +} + +void OSAllocator::decommit(void* address, size_t bytes) +{ +#if HAVE_MADV_FREE_REUSE + while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } +#elif HAVE_MADV_FREE + while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { } +#elif HAVE_MADV_DONTNEED + while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { } +#else + UNUSED_PARAM(address); + UNUSED_PARAM(bytes); +#endif +} + +void OSAllocator::releaseDecommitted(void* address, size_t bytes) +{ + int result = munmap(address, bytes); + if (result == -1) + CRASH(); +} + +} // namespace WTF + +#endif diff --git a/js/src/yarr/OSAllocatorWin.cpp b/js/src/yarr/OSAllocatorWin.cpp new file mode 100644 index 000000000000..08df9e98aefb --- /dev/null +++ b/js/src/yarr/OSAllocatorWin.cpp @@ -0,0 +1,89 @@ +/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS + +#include "windows.h" +#include "wtf/Assertions.h" + +#include "OSAllocator.h" + +namespace WTF { + +static inline DWORD protection(bool writable, bool executable) +{ + return executable ? + (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) : + (writable ? PAGE_READWRITE : PAGE_READONLY); +} + +void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable) +{ + void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable)); + if (!result) + CRASH(); + return result; +} + +void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable) +{ + void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable)); + if (!result) + CRASH(); + return result; +} + +void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable) +{ + void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable)); + if (!result) + CRASH(); +} + +void OSAllocator::decommit(void* address, size_t bytes) +{ + bool result = VirtualFree(address, bytes, MEM_DECOMMIT); + if (!result) + CRASH(); +} + +void OSAllocator::releaseDecommitted(void* address, size_t bytes) +{ + // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx, + // dwSize must be 0 if dwFreeType is MEM_RELEASE. + bool result = VirtualFree(address, 0, MEM_RELEASE); + if (!result) + CRASH(); +} + +} // namespace WTF + +#endif diff --git a/js/src/yarr/PageAllocation.h b/js/src/yarr/PageAllocation.h new file mode 100644 index 000000000000..a86f37116e50 --- /dev/null +++ b/js/src/yarr/PageAllocation.h @@ -0,0 +1,131 @@ +/* -*- 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) 2010 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. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef PageAllocation_h +#define PageAllocation_h + +#include "wtfbridge.h" +#include "OSAllocator.h" +#include "PageBlock.h" +#include "assembler/wtf/VMTags.h" + +#if WTF_OS_DARWIN +#include +#include +#endif + +#if WTF_OS_HAIKU +#include +#endif + +#if WTF_OS_WINDOWS +#include +#include +#endif + +#if WTF_OS_SYMBIAN +#include +#include +#endif + +#if WTF_HAVE_ERRNO_H +#include +#endif + +#if WTF_HAVE_MMAP +#include +#include +#endif + +namespace WTF { + +/* + PageAllocation + + The PageAllocation class provides a cross-platform memory allocation interface + with similar capabilities to posix mmap/munmap. Memory is allocated by calling + PageAllocation::allocate, and deallocated by calling deallocate on the + PageAllocation object. The PageAllocation holds the allocation's base pointer + and size. + + The allocate method is passed the size required (which must be a multiple of + the system page size, which can be accessed using PageAllocation::pageSize). + Callers may also optinally provide a flag indicating the usage (for use by + system memory usage tracking tools, where implemented), and boolean values + specifying the required protection (defaulting to writable, non-executable). +*/ + +class PageAllocation : private PageBlock { +public: + PageAllocation() + { + } + + using PageBlock::size; + using PageBlock::base; + +#ifndef __clang__ + using PageBlock::operator bool; +#else + // FIXME: This is a workaround for , wherein Clang incorrectly emits an access + // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool". + operator bool() const { return PageBlock::operator bool(); } +#endif + + static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false) + { + ASSERT(isPageAligned(size)); + return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size); + } + + void deallocate() + { + // Clear base & size before calling release; if this is *inside* allocation + // then we won't be able to clear then after deallocating the memory. + PageAllocation tmp; + JSC::std::swap(tmp, *this); + + ASSERT(tmp); + ASSERT(!*this); + + OSAllocator::decommitAndRelease(tmp.base(), tmp.size()); + } + +private: + PageAllocation(void* base, size_t size) + : PageBlock(base, size) + { + } +}; + +} // namespace WTF + +using WTF::PageAllocation; + +#endif // PageAllocation_h diff --git a/js/src/yarr/PageBlock.cpp b/js/src/yarr/PageBlock.cpp new file mode 100644 index 000000000000..0f435b772860 --- /dev/null +++ b/js/src/yarr/PageBlock.cpp @@ -0,0 +1,88 @@ +/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "PageBlock.h" +#include "wtf/Assertions.h" + +#if WTF_OS_UNIX && !WTF_OS_SYMBIAN +#include +#endif + +#if WTF_OS_WINDOWS +#include +#include +#endif + +#if WTF_OS_SYMBIAN +#include +#include +#endif + +namespace WTF { + +static size_t s_pageSize; + +#if WTF_OS_UNIX && !WTF_OS_SYMBIAN + +inline size_t systemPageSize() +{ + return getpagesize(); +} + +#elif WTF_OS_WINDOWS + +inline size_t systemPageSize() +{ + static size_t size = 0; + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + size = system_info.dwPageSize; + return size; +} + +#elif WTF_OS_SYMBIAN + +inline size_t systemPageSize() +{ + static TInt page_size = 0; + UserHal::PageSizeInBytes(page_size); + return page_size; +} + +#endif + +size_t pageSize() +{ + if (!s_pageSize) + s_pageSize = systemPageSize(); + ASSERT(isPowerOfTwo(s_pageSize)); + return s_pageSize; +} + +} // namespace WTF diff --git a/js/src/yarr/PageBlock.h b/js/src/yarr/PageBlock.h new file mode 100644 index 000000000000..33751315e049 --- /dev/null +++ b/js/src/yarr/PageBlock.h @@ -0,0 +1,91 @@ +/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef PageBlock_h +#define PageBlock_h + +#include +#include "jsstdint.h" +#include "assembler/wtf/Platform.h" + +namespace WTF { + +size_t pageSize(); +inline bool isPageAligned(void* address) { return !(reinterpret_cast(address) & (pageSize() - 1)); } +inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); } +inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); } + +class PageBlock { +public: + PageBlock(); + PageBlock(const PageBlock&); + PageBlock(void*, size_t); + + void* base() const { return m_base; } + size_t size() const { return m_size; } + + operator bool() const { return !!m_base; } + + bool contains(void* containedBase, size_t containedSize) + { + return containedBase >= m_base + && (static_cast(containedBase) + containedSize) <= (static_cast(m_base) + m_size); + } + +private: + void* m_base; + size_t m_size; +}; + +inline PageBlock::PageBlock() + : m_base(0) + , m_size(0) +{ +} + +inline PageBlock::PageBlock(const PageBlock& other) + : m_base(other.m_base) + , m_size(other.m_size) +{ +} + +inline PageBlock::PageBlock(void* base, size_t size) + : m_base(base) + , m_size(size) +{ +} + +} // namespace WTF + +using WTF::pageSize; +using WTF::isPageAligned; +using WTF::isPageAligned; +using WTF::isPowerOfTwo; + +#endif // PageBlock_h diff --git a/js/src/yarr/yarr/RegExpJitTables.h b/js/src/yarr/RegExpJitTables.h similarity index 100% rename from js/src/yarr/yarr/RegExpJitTables.h rename to js/src/yarr/RegExpJitTables.h diff --git a/js/src/yarr/VMTags.h b/js/src/yarr/VMTags.h new file mode 100644 index 000000000000..fe6a006d3601 --- /dev/null +++ b/js/src/yarr/VMTags.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2009 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 VMTags_h +#define VMTags_h + +// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map +// in order to aid tools that inspect system memory use. +#if WTF_OS_DARWIN + +#include + +#if !defined(TARGETING_TIGER) + +#if defined(VM_MEMORY_TCMALLOC) +#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC) +#else +#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53) +#endif // defined(VM_MEMORY_TCMALLOC) + +#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) +#else +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64) +#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) + +#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) +#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) +#else +#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65) +#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) + +#else // !defined(TARGETING_TIGER) + +// mmap on Tiger fails with tags that work on Leopard, so fall +// back to Tiger-compatible tags (that also work on Leopard) +// when targeting Tiger. +#define VM_TAG_FOR_TCMALLOC_MEMORY -1 +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1 +#define VM_TAG_FOR_REGISTERFILE_MEMORY -1 + +#endif // !defined(TARGETING_TIGER) + +// Tags for vm_map and vm_allocate work on both Tiger and Leopard. + +#if defined(VM_MEMORY_JAVASCRIPT_CORE) +#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE) +#else +#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63) +#endif // defined(VM_MEMORY_JAVASCRIPT_CORE) + +#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) +#else +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69) +#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) + +#else // OS(DARWIN) + +#define VM_TAG_FOR_TCMALLOC_MEMORY -1 +#define VM_TAG_FOR_COLLECTOR_MEMORY -1 +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1 +#define VM_TAG_FOR_REGISTERFILE_MEMORY -1 +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1 + +#endif // OS(DARWIN) + +#endif // VMTags_h diff --git a/js/src/yarr/Yarr.h b/js/src/yarr/Yarr.h new file mode 100644 index 000000000000..40ebcca096af --- /dev/null +++ b/js/src/yarr/Yarr.h @@ -0,0 +1,72 @@ +/* -*- 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. + * + * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef Yarr_h +#define Yarr_h + +#include + +#include "YarrInterpreter.h" +#include "YarrPattern.h" + +namespace JSC { namespace Yarr { + +#define YarrStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers. +#define YarrStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers. +#define YarrStackSpaceForBackTrackInfoBackReference 2 +#define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative. +#define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1 +#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers. +#define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1 +#define YarrStackSpaceForBackTrackInfoParentheses 2 + +static const unsigned quantifyInfinite = UINT_MAX; + +// The below limit restricts the number of "recursive" match calls in order to +// avoid spending exponential time on complex regular expressions. +static const unsigned matchLimit = 1000000; + +enum JSRegExpResult { + JSRegExpMatch = 1, + JSRegExpNoMatch = 0, + JSRegExpErrorNoMatch = -1, + JSRegExpErrorHitLimit = -2, + JSRegExpErrorNoMemory = -3, + JSRegExpErrorInternal = -4 +}; + +PassOwnPtr byteCompile(YarrPattern&, BumpPointerAllocator*); +int interpret(BytecodePattern*, const UChar* input, unsigned start, unsigned length, int* output); + +} } // namespace JSC::Yarr + +#endif // Yarr_h + diff --git a/js/src/yarr/YarrInterpreter.cpp b/js/src/yarr/YarrInterpreter.cpp new file mode 100644 index 000000000000..2be8240efe60 --- /dev/null +++ b/js/src/yarr/YarrInterpreter.cpp @@ -0,0 +1,1914 @@ +/* -*- 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 + * + * 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "YarrInterpreter.h" + +#include "Yarr.h" +#include "BumpPointerAllocator.h" + +#ifndef NDEBUG +#include +#endif + +using namespace WTF; + +namespace JSC { namespace Yarr { + +class Interpreter { +public: + struct ParenthesesDisjunctionContext; + + struct BackTrackInfoPatternCharacter { + uintptr_t matchAmount; + }; + struct BackTrackInfoCharacterClass { + uintptr_t matchAmount; + }; + struct BackTrackInfoBackReference { + uintptr_t begin; // Not really needed for greedy quantifiers. + uintptr_t matchAmount; // Not really needed for fixed quantifiers. + }; + struct BackTrackInfoAlternative { + uintptr_t offset; + }; + struct BackTrackInfoParentheticalAssertion { + uintptr_t begin; + }; + struct BackTrackInfoParenthesesOnce { + uintptr_t begin; + }; + struct BackTrackInfoParenthesesTerminal { + uintptr_t begin; + }; + struct BackTrackInfoParentheses { + uintptr_t matchAmount; + ParenthesesDisjunctionContext* lastContext; + }; + + static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context) + { + context->next = backTrack->lastContext; + backTrack->lastContext = context; + ++backTrack->matchAmount; + } + + static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack) + { + ASSERT(backTrack->matchAmount); + ASSERT(backTrack->lastContext); + backTrack->lastContext = backTrack->lastContext->next; + --backTrack->matchAmount; + } + + struct DisjunctionContext + { + DisjunctionContext() + : term(0) + { + } + + void* operator new(size_t, void* where) + { + return where; + } + + int term; + unsigned matchBegin; + unsigned matchEnd; + uintptr_t frame[1]; + }; + + DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction) + { + size_t size = sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t); + allocatorPool = allocatorPool->ensureCapacity(size); + if (!allocatorPool) + CRASH(); + return new(allocatorPool->alloc(size)) DisjunctionContext(); + } + + void freeDisjunctionContext(DisjunctionContext* context) + { + allocatorPool = allocatorPool->dealloc(context); + } + + struct ParenthesesDisjunctionContext + { + ParenthesesDisjunctionContext(int* output, ByteTerm& term) + : next(0) + { + unsigned firstSubpatternId = term.atom.subpatternId; + unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns; + + for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) { + subpatternBackup[i] = output[(firstSubpatternId << 1) + i]; + output[(firstSubpatternId << 1) + i] = -1; + } + + new(getDisjunctionContext(term)) DisjunctionContext(); + } + + void* operator new(size_t, void* where) + { + return where; + } + + void restoreOutput(int* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns) + { + for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) + output[(firstSubpatternId << 1) + i] = subpatternBackup[i]; + } + + DisjunctionContext* getDisjunctionContext(ByteTerm& term) + { + return reinterpret_cast(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1])); + } + + ParenthesesDisjunctionContext* next; + int subpatternBackup[1]; + }; + + ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, int* output, ByteTerm& term) + { + size_t size = sizeof(ParenthesesDisjunctionContext) - sizeof(int) + (term.atom.parenthesesDisjunction->m_numSubpatterns << 1) * sizeof(int) + sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t); + allocatorPool = allocatorPool->ensureCapacity(size); + if (!allocatorPool) + CRASH(); + return new(allocatorPool->alloc(size)) ParenthesesDisjunctionContext(output, term); + } + + void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context) + { + allocatorPool = allocatorPool->dealloc(context); + } + + class InputStream { + public: + InputStream(const UChar* input, unsigned start, unsigned length) + : input(input) + , pos(start) + , length(length) + { + } + + void next() + { + ++pos; + } + + void rewind(unsigned amount) + { + ASSERT(pos >= amount); + pos -= amount; + } + + int read() + { + ASSERT(pos < length); + if (pos < length) + return input[pos]; + return -1; + } + + int readPair() + { + ASSERT(pos + 1 < length); + return input[pos] | input[pos + 1] << 16; + } + + int readChecked(int position) + { + ASSERT(position < 0); + ASSERT(static_cast(-position) <= pos); + unsigned p = pos + position; + ASSERT(p < length); + return input[p]; + } + + int reread(unsigned from) + { + ASSERT(from < length); + return input[from]; + } + + int prev() + { + ASSERT(!(pos > length)); + if (pos && length) + return input[pos - 1]; + return -1; + } + + unsigned getPos() + { + return pos; + } + + void setPos(unsigned p) + { + pos = p; + } + + bool atStart() + { + return pos == 0; + } + + bool atEnd() + { + return pos == length; + } + + bool checkInput(int count) + { + if ((pos + count) <= length) { + pos += count; + return true; + } + return false; + } + + void uncheckInput(int count) + { + pos -= count; + } + + bool atStart(int position) + { + return (pos + position) == 0; + } + + bool atEnd(int position) + { + return (pos + position) == length; + } + + bool isNotAvailableInput(int position) + { + return (pos + position) > length; + } + + private: + const UChar* input; + unsigned pos; + unsigned length; + }; + + bool testCharacterClass(CharacterClass* characterClass, int ch) + { + if (ch & 0xFF80) { + for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i) + if (ch == characterClass->m_matchesUnicode[i]) + return true; + for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i) + if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end)) + return true; + } else { + for (unsigned i = 0; i < characterClass->m_matches.size(); ++i) + if (ch == characterClass->m_matches[i]) + return true; + for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i) + if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end)) + return true; + } + + return false; + } + + bool checkCharacter(int testChar, int inputPosition) + { + return testChar == input.readChecked(inputPosition); + } + + bool checkCasedCharacter(int loChar, int hiChar, int inputPosition) + { + int ch = input.readChecked(inputPosition); + return (loChar == ch) || (hiChar == ch); + } + + bool checkCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition) + { + bool match = testCharacterClass(characterClass, input.readChecked(inputPosition)); + return invert ? !match : match; + } + + bool tryConsumeBackReference(int matchBegin, int matchEnd, int inputOffset) + { + int matchSize = matchEnd - matchBegin; + + if (!input.checkInput(matchSize)) + return false; + + if (pattern->m_ignoreCase) { + for (int i = 0; i < matchSize; ++i) { + int ch = input.reread(matchBegin + i); + + int lo = Unicode::toLower(ch); + int hi = Unicode::toUpper(ch); + + if ((lo != hi) ? (!checkCasedCharacter(lo, hi, inputOffset - matchSize + i)) : (!checkCharacter(ch, inputOffset - matchSize + i))) { + input.uncheckInput(matchSize); + return false; + } + } + } else { + for (int i = 0; i < matchSize; ++i) { + if (!checkCharacter(input.reread(matchBegin + i), inputOffset - matchSize + i)) { + input.uncheckInput(matchSize); + return false; + } + } + } + + return true; + } + + bool matchAssertionBOL(ByteTerm& term) + { + return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition - 1))); + } + + bool matchAssertionEOL(ByteTerm& term) + { + if (term.inputPosition) + return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition))); + + return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read())); + } + + bool matchAssertionWordBoundary(ByteTerm& term) + { + bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition - 1)); + bool readIsWordchar; + if (term.inputPosition) + readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition)); + else + readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read()); + + bool wordBoundary = prevIsWordchar != readIsWordchar; + return term.invert() ? !wordBoundary : wordBoundary; + } + + bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context) + { + BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + switch (term.atom.quantityType) { + case QuantifierFixedCount: + break; + + case QuantifierGreedy: + if (backTrack->matchAmount) { + --backTrack->matchAmount; + input.uncheckInput(1); + return true; + } + break; + + case QuantifierNonGreedy: + if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) { + ++backTrack->matchAmount; + if (checkCharacter(term.atom.patternCharacter, term.inputPosition - 1)) + return true; + } + input.uncheckInput(backTrack->matchAmount); + break; + } + + return false; + } + + bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context) + { + BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + switch (term.atom.quantityType) { + case QuantifierFixedCount: + break; + + case QuantifierGreedy: + if (backTrack->matchAmount) { + --backTrack->matchAmount; + input.uncheckInput(1); + return true; + } + break; + + case QuantifierNonGreedy: + if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) { + ++backTrack->matchAmount; + if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition - 1)) + return true; + } + input.uncheckInput(backTrack->matchAmount); + break; + } + + return false; + } + + bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeCharacterClass); + BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + switch (term.atom.quantityType) { + case QuantifierFixedCount: { + for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) { + if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + matchAmount)) + return false; + } + return true; + } + + case QuantifierGreedy: { + unsigned matchAmount = 0; + while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) { + if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) { + input.uncheckInput(1); + break; + } + ++matchAmount; + } + backTrack->matchAmount = matchAmount; + + return true; + } + + case QuantifierNonGreedy: + backTrack->matchAmount = 0; + return true; + } + + ASSERT_NOT_REACHED(); + return false; + } + + bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeCharacterClass); + BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + switch (term.atom.quantityType) { + case QuantifierFixedCount: + break; + + case QuantifierGreedy: + if (backTrack->matchAmount) { + --backTrack->matchAmount; + input.uncheckInput(1); + return true; + } + break; + + case QuantifierNonGreedy: + if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) { + ++backTrack->matchAmount; + if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) + return true; + } + input.uncheckInput(backTrack->matchAmount); + break; + } + + return false; + } + + bool matchBackReference(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeBackReference); + BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + int matchBegin = output[(term.atom.subpatternId << 1)]; + int matchEnd = output[(term.atom.subpatternId << 1) + 1]; + + // If the end position of the referenced match hasn't set yet then the backreference in the same parentheses where it references to that. + // In this case the result of match is empty string like when it references to a parentheses with zero-width match. + // Eg.: /(a\1)/ + if (matchEnd == -1) + return true; + + ASSERT((matchBegin == -1) || (matchBegin <= matchEnd)); + + if (matchBegin == matchEnd) + return true; + + switch (term.atom.quantityType) { + case QuantifierFixedCount: { + backTrack->begin = input.getPos(); + for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) { + if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) { + input.setPos(backTrack->begin); + return false; + } + } + return true; + } + + case QuantifierGreedy: { + unsigned matchAmount = 0; + while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) + ++matchAmount; + backTrack->matchAmount = matchAmount; + return true; + } + + case QuantifierNonGreedy: + backTrack->begin = input.getPos(); + backTrack->matchAmount = 0; + return true; + } + + ASSERT_NOT_REACHED(); + return false; + } + + bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeBackReference); + BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + int matchBegin = output[(term.atom.subpatternId << 1)]; + int matchEnd = output[(term.atom.subpatternId << 1) + 1]; + ASSERT((matchBegin == -1) || (matchBegin <= matchEnd)); + + if (matchBegin == matchEnd) + return false; + + switch (term.atom.quantityType) { + case QuantifierFixedCount: + // for quantityCount == 1, could rewind. + input.setPos(backTrack->begin); + break; + + case QuantifierGreedy: + if (backTrack->matchAmount) { + --backTrack->matchAmount; + input.rewind(matchEnd - matchBegin); + return true; + } + break; + + case QuantifierNonGreedy: + if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) { + ++backTrack->matchAmount; + return true; + } + input.setPos(backTrack->begin); + break; + } + + return false; + } + + void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context) + { + if (term.capture()) { + unsigned subpatternId = term.atom.subpatternId; + output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition; + output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition; + } + } + void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context) + { + unsigned firstSubpatternId = term.atom.subpatternId; + unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns; + context->restoreOutput(output, firstSubpatternId, count); + } + JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack) + { + while (backTrack->matchAmount) { + ParenthesesDisjunctionContext* context = backTrack->lastContext; + + JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true); + if (result == JSRegExpMatch) + return JSRegExpMatch; + + resetMatches(term, context); + popParenthesesDisjunctionContext(backTrack); + freeParenthesesDisjunctionContext(context); + + if (result != JSRegExpNoMatch) + return result; + } + + return JSRegExpNoMatch; + } + + bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin); + ASSERT(term.atom.quantityCount == 1); + + BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + switch (term.atom.quantityType) { + case QuantifierGreedy: { + // set this speculatively; if we get to the parens end this will be true. + backTrack->begin = input.getPos(); + break; + } + case QuantifierNonGreedy: { + backTrack->begin = notFound; + context->term += term.atom.parenthesesWidth; + return true; + } + case QuantifierFixedCount: + break; + } + + if (term.capture()) { + unsigned subpatternId = term.atom.subpatternId; + output[(subpatternId << 1)] = input.getPos() + term.inputPosition; + } + + return true; + } + + bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd); + ASSERT(term.atom.quantityCount == 1); + + if (term.capture()) { + unsigned subpatternId = term.atom.subpatternId; + output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition; + } + + if (term.atom.quantityType == QuantifierFixedCount) + return true; + + BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation); + return backTrack->begin != input.getPos(); + } + + bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin); + ASSERT(term.atom.quantityCount == 1); + + BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + if (term.capture()) { + unsigned subpatternId = term.atom.subpatternId; + output[(subpatternId << 1)] = -1; + output[(subpatternId << 1) + 1] = -1; + } + + switch (term.atom.quantityType) { + case QuantifierGreedy: + // if we backtrack to this point, there is another chance - try matching nothing. + ASSERT(backTrack->begin != notFound); + backTrack->begin = notFound; + context->term += term.atom.parenthesesWidth; + return true; + case QuantifierNonGreedy: + ASSERT(backTrack->begin != notFound); + case QuantifierFixedCount: + break; + } + + return false; + } + + bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd); + ASSERT(term.atom.quantityCount == 1); + + BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + switch (term.atom.quantityType) { + case QuantifierGreedy: + if (backTrack->begin == notFound) { + context->term -= term.atom.parenthesesWidth; + return false; + } + case QuantifierNonGreedy: + if (backTrack->begin == notFound) { + backTrack->begin = input.getPos(); + if (term.capture()) { + // Technically this access to inputPosition should be accessing the begin term's + // inputPosition, but for repeats other than fixed these values should be + // the same anyway! (We don't pre-check for greedy or non-greedy matches.) + ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin); + ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition); + unsigned subpatternId = term.atom.subpatternId; + output[subpatternId << 1] = input.getPos() + term.inputPosition; + } + context->term -= term.atom.parenthesesWidth; + return true; + } + case QuantifierFixedCount: + break; + } + + return false; + } + + bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin); + ASSERT(term.atom.quantityType == QuantifierGreedy); + ASSERT(term.atom.quantityCount == quantifyInfinite); + ASSERT(!term.capture()); + + BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation); + backTrack->begin = input.getPos(); + return true; + } + + bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd); + + BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation); + // Empty match is a failed match. + if (backTrack->begin == input.getPos()) + return false; + + // Successful match! Okay, what's next? - loop around and try to match moar! + context->term -= (term.atom.parenthesesWidth + 1); + return true; + } + + bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin); + ASSERT(term.atom.quantityType == QuantifierGreedy); + ASSERT(term.atom.quantityCount == quantifyInfinite); + ASSERT(!term.capture()); + + // If we backtrack to this point, we have failed to match this iteration of the parens. + // Since this is greedy / zero minimum a failed is also accepted as a match! + context->term += term.atom.parenthesesWidth; + return true; + } + + bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*) + { + // 'Terminal' parentheses are at the end of the regex, and as such a match past end + // should always be returned as a successful match - we should never backtrack to here. + ASSERT_NOT_REACHED(); + return false; + } + + bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin); + ASSERT(term.atom.quantityCount == 1); + + BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + backTrack->begin = input.getPos(); + return true; + } + + bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd); + ASSERT(term.atom.quantityCount == 1); + + BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + input.setPos(backTrack->begin); + + // We've reached the end of the parens; if they are inverted, this is failure. + if (term.invert()) { + context->term -= term.atom.parenthesesWidth; + return false; + } + + return true; + } + + bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin); + ASSERT(term.atom.quantityCount == 1); + + // We've failed to match parens; if they are inverted, this is win! + if (term.invert()) { + context->term += term.atom.parenthesesWidth; + return true; + } + + return false; + } + + bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd); + ASSERT(term.atom.quantityCount == 1); + + BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation); + + input.setPos(backTrack->begin); + + context->term -= term.atom.parenthesesWidth; + return false; + } + + JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern); + + BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation); + ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction; + + backTrack->matchAmount = 0; + backTrack->lastContext = 0; + + switch (term.atom.quantityType) { + case QuantifierFixedCount: { + // While we haven't yet reached our fixed limit, + while (backTrack->matchAmount < term.atom.quantityCount) { + // Try to do a match, and it it succeeds, add it to the list. + ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); + JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + if (result == JSRegExpMatch) + appendParenthesesDisjunctionContext(backTrack, context); + else { + // The match failed; try to find an alternate point to carry on from. + resetMatches(term, context); + freeParenthesesDisjunctionContext(context); + + if (result == JSRegExpNoMatch) { + JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack); + if (backtrackResult != JSRegExpMatch) + return backtrackResult; + } else + return result; + } + } + + ASSERT(backTrack->matchAmount == term.atom.quantityCount); + ParenthesesDisjunctionContext* context = backTrack->lastContext; + recordParenthesesMatch(term, context); + return JSRegExpMatch; + } + + case QuantifierGreedy: { + while (backTrack->matchAmount < term.atom.quantityCount) { + ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); + JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + if (result == JSRegExpMatch) + appendParenthesesDisjunctionContext(backTrack, context); + else { + resetMatches(term, context); + freeParenthesesDisjunctionContext(context); + + if (result != JSRegExpNoMatch) + return result; + + break; + } + } + + if (backTrack->matchAmount) { + ParenthesesDisjunctionContext* context = backTrack->lastContext; + recordParenthesesMatch(term, context); + } + return JSRegExpMatch; + } + + case QuantifierNonGreedy: + return JSRegExpMatch; + } + + ASSERT_NOT_REACHED(); + return JSRegExpErrorNoMatch; + } + + // Rules for backtracking differ depending on whether this is greedy or non-greedy. + // + // Greedy matches never should try just adding more - you should already have done + // the 'more' cases. Always backtrack, at least a leetle bit. However cases where + // you backtrack an item off the list needs checking, since we'll never have matched + // the one less case. Tracking forwards, still add as much as possible. + // + // Non-greedy, we've already done the one less case, so don't match on popping. + // We haven't done the one more case, so always try to add that. + // + JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context) + { + ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern); + + BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation); + ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction; + + switch (term.atom.quantityType) { + case QuantifierFixedCount: { + ASSERT(backTrack->matchAmount == term.atom.quantityCount); + + ParenthesesDisjunctionContext* context = 0; + JSRegExpResult result = parenthesesDoBacktrack(term, backTrack); + + if (result != JSRegExpMatch) + return result; + + // While we haven't yet reached our fixed limit, + while (backTrack->matchAmount < term.atom.quantityCount) { + // Try to do a match, and it it succeeds, add it to the list. + context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); + result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + + if (result == JSRegExpMatch) + appendParenthesesDisjunctionContext(backTrack, context); + else { + // The match failed; try to find an alternate point to carry on from. + resetMatches(term, context); + freeParenthesesDisjunctionContext(context); + + if (result == JSRegExpNoMatch) { + JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack); + if (backtrackResult != JSRegExpMatch) + return backtrackResult; + } else + return result; + } + } + + ASSERT(backTrack->matchAmount == term.atom.quantityCount); + context = backTrack->lastContext; + recordParenthesesMatch(term, context); + return JSRegExpMatch; + } + + case QuantifierGreedy: { + if (!backTrack->matchAmount) + return JSRegExpNoMatch; + + ParenthesesDisjunctionContext* context = backTrack->lastContext; + JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true); + if (result == JSRegExpMatch) { + while (backTrack->matchAmount < term.atom.quantityCount) { + ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); + JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + if (parenthesesResult == JSRegExpMatch) + appendParenthesesDisjunctionContext(backTrack, context); + else { + resetMatches(term, context); + freeParenthesesDisjunctionContext(context); + + if (parenthesesResult != JSRegExpNoMatch) + return parenthesesResult; + + break; + } + } + } else { + resetMatches(term, context); + popParenthesesDisjunctionContext(backTrack); + freeParenthesesDisjunctionContext(context); + + if (result != JSRegExpNoMatch) + return result; + } + + if (backTrack->matchAmount) { + ParenthesesDisjunctionContext* context = backTrack->lastContext; + recordParenthesesMatch(term, context); + } + return JSRegExpMatch; + } + + case QuantifierNonGreedy: { + // If we've not reached the limit, try to add one more match. + if (backTrack->matchAmount < term.atom.quantityCount) { + ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term); + JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term)); + if (result == JSRegExpMatch) { + appendParenthesesDisjunctionContext(backTrack, context); + recordParenthesesMatch(term, context); + return JSRegExpMatch; + } + + resetMatches(term, context); + freeParenthesesDisjunctionContext(context); + + if (result != JSRegExpNoMatch) + return result; + } + + // Nope - okay backtrack looking for an alternative. + while (backTrack->matchAmount) { + ParenthesesDisjunctionContext* context = backTrack->lastContext; + JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true); + if (result == JSRegExpMatch) { + // successful backtrack! we're back in the game! + if (backTrack->matchAmount) { + context = backTrack->lastContext; + recordParenthesesMatch(term, context); + } + return JSRegExpMatch; + } + + // pop a match off the stack + resetMatches(term, context); + popParenthesesDisjunctionContext(backTrack); + freeParenthesesDisjunctionContext(context); + + return result; + } + + return JSRegExpNoMatch; + } + } + + ASSERT_NOT_REACHED(); + return JSRegExpErrorNoMatch; + } + + void lookupForBeginChars() + { + int character; + bool firstSingleCharFound; + + while (true) { + if (input.isNotAvailableInput(2)) + return; + + firstSingleCharFound = false; + + character = input.readPair(); + + for (unsigned i = 0; i < pattern->m_beginChars.size(); ++i) { + BeginChar bc = pattern->m_beginChars[i]; + + if (!firstSingleCharFound && bc.value <= 0xFFFF) { + firstSingleCharFound = true; + character &= 0xFFFF; + } + + if ((character | bc.mask) == bc.value) + return; + } + + input.next(); + } + } + +#define MATCH_NEXT() { ++context->term; goto matchAgain; } +#define BACKTRACK() { --context->term; goto backtrack; } +#define currentTerm() (disjunction->terms[context->term]) + JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false, bool isBody = false) + { + if (!--remainingMatchCount) + return JSRegExpErrorHitLimit; + + if (btrack) + BACKTRACK(); + + if (pattern->m_containsBeginChars && isBody) + lookupForBeginChars(); + + context->matchBegin = input.getPos(); + context->term = 0; + + matchAgain: + ASSERT(context->term < static_cast(disjunction->terms.size())); + + switch (currentTerm().type) { + case ByteTerm::TypeSubpatternBegin: + MATCH_NEXT(); + case ByteTerm::TypeSubpatternEnd: + context->matchEnd = input.getPos(); + return JSRegExpMatch; + + case ByteTerm::TypeBodyAlternativeBegin: + MATCH_NEXT(); + case ByteTerm::TypeBodyAlternativeDisjunction: + case ByteTerm::TypeBodyAlternativeEnd: + context->matchEnd = input.getPos(); + return JSRegExpMatch; + + case ByteTerm::TypeAlternativeBegin: + MATCH_NEXT(); + case ByteTerm::TypeAlternativeDisjunction: + case ByteTerm::TypeAlternativeEnd: { + int offset = currentTerm().alternative.end; + BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); + backTrack->offset = offset; + context->term += offset; + MATCH_NEXT(); + } + + case ByteTerm::TypeAssertionBOL: + if (matchAssertionBOL(currentTerm())) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeAssertionEOL: + if (matchAssertionEOL(currentTerm())) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeAssertionWordBoundary: + if (matchAssertionWordBoundary(currentTerm())) + MATCH_NEXT(); + BACKTRACK(); + + case ByteTerm::TypePatternCharacterOnce: + case ByteTerm::TypePatternCharacterFixed: { + for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) { + if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + matchAmount)) + BACKTRACK(); + } + MATCH_NEXT(); + } + case ByteTerm::TypePatternCharacterGreedy: { + BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); + unsigned matchAmount = 0; + while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) { + if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 1)) { + input.uncheckInput(1); + break; + } + ++matchAmount; + } + backTrack->matchAmount = matchAmount; + + MATCH_NEXT(); + } + case ByteTerm::TypePatternCharacterNonGreedy: { + BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); + backTrack->matchAmount = 0; + MATCH_NEXT(); + } + + case ByteTerm::TypePatternCasedCharacterOnce: + case ByteTerm::TypePatternCasedCharacterFixed: { + for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) { + if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + matchAmount)) + BACKTRACK(); + } + MATCH_NEXT(); + } + case ByteTerm::TypePatternCasedCharacterGreedy: { + BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); + unsigned matchAmount = 0; + while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) { + if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - 1)) { + input.uncheckInput(1); + break; + } + ++matchAmount; + } + backTrack->matchAmount = matchAmount; + + MATCH_NEXT(); + } + case ByteTerm::TypePatternCasedCharacterNonGreedy: { + BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); + backTrack->matchAmount = 0; + MATCH_NEXT(); + } + + case ByteTerm::TypeCharacterClass: + if (matchCharacterClass(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeBackReference: + if (matchBackReference(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParenthesesSubpattern: { + JSRegExpResult result = matchParentheses(currentTerm(), context); + + if (result == JSRegExpMatch) { + MATCH_NEXT(); + } else if (result != JSRegExpNoMatch) + return result; + + BACKTRACK(); + } + case ByteTerm::TypeParenthesesSubpatternOnceBegin: + if (matchParenthesesOnceBegin(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParenthesesSubpatternOnceEnd: + if (matchParenthesesOnceEnd(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParenthesesSubpatternTerminalBegin: + if (matchParenthesesTerminalBegin(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParenthesesSubpatternTerminalEnd: + if (matchParenthesesTerminalEnd(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParentheticalAssertionBegin: + if (matchParentheticalAssertionBegin(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParentheticalAssertionEnd: + if (matchParentheticalAssertionEnd(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + + case ByteTerm::TypeCheckInput: + if (input.checkInput(currentTerm().checkInputCount)) + MATCH_NEXT(); + BACKTRACK(); + + case ByteTerm::TypeUncheckInput: + input.uncheckInput(currentTerm().checkInputCount); + MATCH_NEXT(); + } + + // We should never fall-through to here. + ASSERT_NOT_REACHED(); + + backtrack: + ASSERT(context->term < static_cast(disjunction->terms.size())); + + switch (currentTerm().type) { + case ByteTerm::TypeSubpatternBegin: + return JSRegExpNoMatch; + case ByteTerm::TypeSubpatternEnd: + ASSERT_NOT_REACHED(); + + case ByteTerm::TypeBodyAlternativeBegin: + case ByteTerm::TypeBodyAlternativeDisjunction: { + int offset = currentTerm().alternative.next; + context->term += offset; + if (offset > 0) + MATCH_NEXT(); + + if (input.atEnd()) + return JSRegExpNoMatch; + + input.next(); + + if (pattern->m_containsBeginChars && isBody) + lookupForBeginChars(); + + context->matchBegin = input.getPos(); + + if (currentTerm().alternative.onceThrough) + context->term += currentTerm().alternative.next; + + MATCH_NEXT(); + } + case ByteTerm::TypeBodyAlternativeEnd: + ASSERT_NOT_REACHED(); + + case ByteTerm::TypeAlternativeBegin: + case ByteTerm::TypeAlternativeDisjunction: { + int offset = currentTerm().alternative.next; + context->term += offset; + if (offset > 0) + MATCH_NEXT(); + BACKTRACK(); + } + case ByteTerm::TypeAlternativeEnd: { + // We should never backtrack back into an alternative of the main body of the regex. + BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation); + unsigned offset = backTrack->offset; + context->term -= offset; + BACKTRACK(); + } + + case ByteTerm::TypeAssertionBOL: + case ByteTerm::TypeAssertionEOL: + case ByteTerm::TypeAssertionWordBoundary: + BACKTRACK(); + + case ByteTerm::TypePatternCharacterOnce: + case ByteTerm::TypePatternCharacterFixed: + case ByteTerm::TypePatternCharacterGreedy: + case ByteTerm::TypePatternCharacterNonGreedy: + if (backtrackPatternCharacter(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypePatternCasedCharacterOnce: + case ByteTerm::TypePatternCasedCharacterFixed: + case ByteTerm::TypePatternCasedCharacterGreedy: + case ByteTerm::TypePatternCasedCharacterNonGreedy: + if (backtrackPatternCasedCharacter(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeCharacterClass: + if (backtrackCharacterClass(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeBackReference: + if (backtrackBackReference(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParenthesesSubpattern: { + JSRegExpResult result = backtrackParentheses(currentTerm(), context); + + if (result == JSRegExpMatch) { + MATCH_NEXT(); + } else if (result != JSRegExpNoMatch) + return result; + + BACKTRACK(); + } + case ByteTerm::TypeParenthesesSubpatternOnceBegin: + if (backtrackParenthesesOnceBegin(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParenthesesSubpatternOnceEnd: + if (backtrackParenthesesOnceEnd(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParenthesesSubpatternTerminalBegin: + if (backtrackParenthesesTerminalBegin(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParenthesesSubpatternTerminalEnd: + if (backtrackParenthesesTerminalEnd(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParentheticalAssertionBegin: + if (backtrackParentheticalAssertionBegin(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + case ByteTerm::TypeParentheticalAssertionEnd: + if (backtrackParentheticalAssertionEnd(currentTerm(), context)) + MATCH_NEXT(); + BACKTRACK(); + + case ByteTerm::TypeCheckInput: + input.uncheckInput(currentTerm().checkInputCount); + BACKTRACK(); + + case ByteTerm::TypeUncheckInput: + input.checkInput(currentTerm().checkInputCount); + BACKTRACK(); + } + + ASSERT_NOT_REACHED(); + return JSRegExpErrorNoMatch; + } + + JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false) + { + JSRegExpResult result = matchDisjunction(disjunction, context, btrack); + + if (result == JSRegExpMatch) { + while (context->matchBegin == context->matchEnd) { + result = matchDisjunction(disjunction, context, true); + if (result != JSRegExpMatch) + return result; + } + return JSRegExpMatch; + } + + return result; + } + + int interpret() + { + allocatorPool = pattern->m_allocator->startAllocator(); + if (!allocatorPool) + CRASH(); + + for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i) + output[i] = -1; + + DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get()); + + JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false, true); + if (result == JSRegExpMatch) { + output[0] = context->matchBegin; + output[1] = context->matchEnd; + } + + freeDisjunctionContext(context); + + pattern->m_allocator->stopAllocator(); + + // RegExp.cpp currently expects all error to be converted to -1. + ASSERT((result == JSRegExpMatch) == (output[0] != -1)); + return output[0]; + } + + Interpreter(BytecodePattern* pattern, int* output, const UChar* inputChar, unsigned start, unsigned length) + : pattern(pattern) + , output(output) + , input(inputChar, start, length) + , allocatorPool(0) + , remainingMatchCount(matchLimit) + { + } + +private: + BytecodePattern* pattern; + int* output; + InputStream input; + BumpPointerPool* allocatorPool; + unsigned remainingMatchCount; +}; + + + +class ByteCompiler { + struct ParenthesesStackEntry { + unsigned beginTerm; + unsigned savedAlternativeIndex; + // For js::Vector. Does not create a valid object. + ParenthesesStackEntry() {} + ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/) + : beginTerm(beginTerm) + , savedAlternativeIndex(savedAlternativeIndex) + { + } + }; + +public: + ByteCompiler(YarrPattern& pattern) + : m_pattern(pattern) + { + m_currentAlternativeIndex = 0; + } + + PassOwnPtr compile(BumpPointerAllocator* allocator) + { + regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough()); + emitDisjunction(m_pattern.m_body); + regexEnd(); + + return adoptPtr(js::OffTheBooks::new_(m_bodyDisjunction.release(), m_allParenthesesInfo, m_pattern, allocator)); + } + + void checkInput(unsigned count) + { + m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count)); + } + + void uncheckInput(unsigned count) + { + m_bodyDisjunction->terms.append(ByteTerm::UncheckInput(count)); + } + + void assertionBOL(int inputPosition) + { + m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition)); + } + + void assertionEOL(int inputPosition) + { + m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition)); + } + + void assertionWordBoundary(bool invert, int inputPosition) + { + m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition)); + } + + void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) + { + if (m_pattern.m_ignoreCase) { + UChar lo = Unicode::toLower(ch); + UChar hi = Unicode::toUpper(ch); + + if (lo != hi) { + m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType)); + return; + } + } + + m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType)); + } + + void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) + { + m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition)); + + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + } + + void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) + { + ASSERT(subpatternId); + + m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition)); + + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + } + + void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation) + { + int beginTerm = m_bodyDisjunction->terms.size(); + + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition)); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; + + m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); + m_currentAlternativeIndex = beginTerm + 1; + } + + void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation) + { + int beginTerm = m_bodyDisjunction->terms.size(); + + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, false, inputPosition)); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; + + m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); + m_currentAlternativeIndex = beginTerm + 1; + } + + void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation) + { + // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin, + // then fix this up at the end! - simplifying this should make it much clearer. + // https://bugs.webkit.org/show_bug.cgi?id=50136 + + int beginTerm = m_bodyDisjunction->terms.size(); + + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition)); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; + + m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); + m_currentAlternativeIndex = beginTerm + 1; + } + + void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation) + { + int beginTerm = m_bodyDisjunction->terms.size(); + + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, false, invert, 0)); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; + + m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); + m_currentAlternativeIndex = beginTerm + 1; + } + + void atomParentheticalAssertionEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) + { + unsigned beginTerm = popParenthesesStack(); + closeAlternative(beginTerm + 1); + unsigned endTerm = m_bodyDisjunction->terms.size(); + + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin); + + bool invert = m_bodyDisjunction->terms[beginTerm].invert(); + unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId; + + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, false, invert, inputPosition)); + m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm; + m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm; + m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation; + + m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; + m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType; + } + + unsigned popParenthesesStack() + { + ASSERT(m_parenthesesStack.size()); + int stackEnd = m_parenthesesStack.size() - 1; + unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm; + m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex; + m_parenthesesStack.shrink(stackEnd); + + ASSERT(beginTerm < m_bodyDisjunction->terms.size()); + ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size()); + + return beginTerm; + } + +#ifndef NDEBUG + void dumpDisjunction(ByteDisjunction* disjunction) + { + printf("ByteDisjunction(%p):\n\t", disjunction); + for (unsigned i = 0; i < disjunction->terms.size(); ++i) + printf("{ %d } ", disjunction->terms[i].type); + printf("\n"); + } +#endif + + void closeAlternative(int beginTerm) + { + int origBeginTerm = beginTerm; + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin); + int endIndex = m_bodyDisjunction->terms.size(); + + unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation; + + if (!m_bodyDisjunction->terms[beginTerm].alternative.next) + m_bodyDisjunction->terms.remove(beginTerm); + else { + while (m_bodyDisjunction->terms[beginTerm].alternative.next) { + beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next; + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction); + m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm; + m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; + } + + m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm; + + m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd()); + m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation; + } + } + + void closeBodyAlternative() + { + int beginTerm = 0; + int origBeginTerm = 0; + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin); + int endIndex = m_bodyDisjunction->terms.size(); + + unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation; + + while (m_bodyDisjunction->terms[beginTerm].alternative.next) { + beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next; + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction); + m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm; + m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; + } + + m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm; + + m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd()); + m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation; + } + + void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0) + { + unsigned beginTerm = popParenthesesStack(); + closeAlternative(beginTerm + 1); + unsigned endTerm = m_bodyDisjunction->terms.size(); + + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin); + + ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm]; + + bool capture = parenthesesBegin.capture(); + unsigned subpatternId = parenthesesBegin.atom.subpatternId; + + unsigned numSubpatterns = lastSubpatternId - subpatternId + 1; + ByteDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(numSubpatterns, callFrameSize); + + parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin()); + for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses) + parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]); + parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd()); + + m_bodyDisjunction->terms.shrink(beginTerm); + + m_allParenthesesInfo.append(parenthesesDisjunction); + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, inputPosition)); + + m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; + m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; + } + + void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) + { + unsigned beginTerm = popParenthesesStack(); + closeAlternative(beginTerm + 1); + unsigned endTerm = m_bodyDisjunction->terms.size(); + + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin); + + bool capture = m_bodyDisjunction->terms[beginTerm].capture(); + unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId; + + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, capture, false, inputPosition)); + m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm; + m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm; + m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation; + + m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; + m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType; + } + + void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) + { + unsigned beginTerm = popParenthesesStack(); + closeAlternative(beginTerm + 1); + unsigned endTerm = m_bodyDisjunction->terms.size(); + + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin); + + bool capture = m_bodyDisjunction->terms[beginTerm].capture(); + unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId; + + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, capture, false, inputPosition)); + m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm; + m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm; + m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation; + + m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; + m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType; + } + + void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough) + { + m_bodyDisjunction = adoptPtr(js::OffTheBooks::new_(numSubpatterns, callFrameSize)); + m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough)); + m_bodyDisjunction->terms[0].frameLocation = 0; + m_currentAlternativeIndex = 0; + } + + void regexEnd() + { + closeBodyAlternative(); + } + + void alternativeBodyDisjunction(bool onceThrough) + { + int newAlternativeIndex = m_bodyDisjunction->terms.size(); + m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex; + m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough)); + + m_currentAlternativeIndex = newAlternativeIndex; + } + + void alternativeDisjunction() + { + int newAlternativeIndex = m_bodyDisjunction->terms.size(); + m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex; + m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction()); + + m_currentAlternativeIndex = newAlternativeIndex; + } + + void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0) + { + for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + unsigned currentCountAlreadyChecked = inputCountAlreadyChecked; + + PatternAlternative* alternative = disjunction->m_alternatives[alt]; + + if (alt) { + if (disjunction == m_pattern.m_body) + alternativeBodyDisjunction(alternative->onceThrough()); + else + alternativeDisjunction(); + } + + unsigned minimumSize = alternative->m_minimumSize; + int countToCheck = minimumSize - parenthesesInputCountAlreadyChecked; + + ASSERT(countToCheck >= 0); + if (countToCheck) { + checkInput(countToCheck); + currentCountAlreadyChecked += countToCheck; + } + + for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { + PatternTerm& term = alternative->m_terms[i]; + + switch (term.type) { + case PatternTerm::TypeAssertionBOL: + assertionBOL(term.inputPosition - currentCountAlreadyChecked); + break; + + case PatternTerm::TypeAssertionEOL: + assertionEOL(term.inputPosition - currentCountAlreadyChecked); + break; + + case PatternTerm::TypeAssertionWordBoundary: + assertionWordBoundary(term.invert(), term.inputPosition - currentCountAlreadyChecked); + break; + + case PatternTerm::TypePatternCharacter: + atomPatternCharacter(term.patternCharacter, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType); + break; + + case PatternTerm::TypeCharacterClass: + atomCharacterClass(term.characterClass, term.invert(), term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType); + break; + + case PatternTerm::TypeBackReference: + atomBackReference(term.backReferenceSubpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType); + break; + + case PatternTerm::TypeForwardReference: + break; + + case PatternTerm::TypeParenthesesSubpattern: { + unsigned disjunctionAlreadyCheckedCount = 0; + if (term.quantityCount == 1 && !term.parentheses.isCopy) { + unsigned alternativeFrameLocation = term.frameLocation; + // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame. + if (term.quantityType == QuantifierFixedCount) + disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize; + else + alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; + unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked; + atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, alternativeFrameLocation); + emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount); + atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType); + } else if (term.parentheses.isTerminal) { + unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked; + atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce); + emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount); + atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType); + } else { + unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked; + atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0); + emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0); + atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize); + } + break; + } + + case PatternTerm::TypeParentheticalAssertion: { + unsigned alternativeFrameLocation = term.frameLocation + YarrStackSpaceForBackTrackInfoParentheticalAssertion; + + ASSERT(currentCountAlreadyChecked >= static_cast(term.inputPosition)); + int positiveInputOffset = currentCountAlreadyChecked - term.inputPosition; + int uncheckAmount = positiveInputOffset - term.parentheses.disjunction->m_minimumSize; + + if (uncheckAmount > 0) { + uncheckInput(uncheckAmount); + currentCountAlreadyChecked -= uncheckAmount; + } else + uncheckAmount = 0; + + atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation); + emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount); + atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType); + if (uncheckAmount) { + checkInput(uncheckAmount); + currentCountAlreadyChecked += uncheckAmount; + } + break; + } + } + } + } + } + +private: + YarrPattern& m_pattern; + OwnPtr m_bodyDisjunction; + unsigned m_currentAlternativeIndex; + Vector m_parenthesesStack; + Vector m_allParenthesesInfo; +}; + +PassOwnPtr byteCompile(YarrPattern& pattern, BumpPointerAllocator* allocator) +{ + return ByteCompiler(pattern).compile(allocator); +} + +int interpret(BytecodePattern* bytecode, const UChar* input, unsigned start, unsigned length, int* output) +{ + return Interpreter(bytecode, output, input, start, length).interpret(); +} + +COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoPatternCharacter); +COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoCharacterClass); +COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoBackReference); +COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative); +COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion); +COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce); +COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses); + + +} } diff --git a/js/src/yarr/YarrInterpreter.h b/js/src/yarr/YarrInterpreter.h new file mode 100644 index 000000000000..32b72858cad1 --- /dev/null +++ b/js/src/yarr/YarrInterpreter.h @@ -0,0 +1,380 @@ +/* -*- 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, 2010 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. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef YarrInterpreter_h +#define YarrInterpreter_h + +#include "YarrPattern.h" + +namespace WTF { +class BumpPointerAllocator; +} +using WTF::BumpPointerAllocator; + +namespace JSC { namespace Yarr { + +class ByteDisjunction; + +struct ByteTerm { + enum Type { + TypeBodyAlternativeBegin, + TypeBodyAlternativeDisjunction, + TypeBodyAlternativeEnd, + TypeAlternativeBegin, + TypeAlternativeDisjunction, + TypeAlternativeEnd, + TypeSubpatternBegin, + TypeSubpatternEnd, + TypeAssertionBOL, + TypeAssertionEOL, + TypeAssertionWordBoundary, + TypePatternCharacterOnce, + TypePatternCharacterFixed, + TypePatternCharacterGreedy, + TypePatternCharacterNonGreedy, + TypePatternCasedCharacterOnce, + TypePatternCasedCharacterFixed, + TypePatternCasedCharacterGreedy, + TypePatternCasedCharacterNonGreedy, + TypeCharacterClass, + TypeBackReference, + TypeParenthesesSubpattern, + TypeParenthesesSubpatternOnceBegin, + TypeParenthesesSubpatternOnceEnd, + TypeParenthesesSubpatternTerminalBegin, + TypeParenthesesSubpatternTerminalEnd, + TypeParentheticalAssertionBegin, + TypeParentheticalAssertionEnd, + TypeCheckInput, + TypeUncheckInput + } type; + union { + struct { + union { + UChar patternCharacter; + struct { + UChar lo; + UChar hi; + } casedCharacter; + CharacterClass* characterClass; + unsigned subpatternId; + }; + union { + ByteDisjunction* parenthesesDisjunction; + unsigned parenthesesWidth; + }; + QuantifierType quantityType; + unsigned quantityCount; + } atom; + struct { + int next; + int end; + bool onceThrough; + } alternative; + unsigned checkInputCount; + }; + unsigned frameLocation; + bool m_capture : 1; + bool m_invert : 1; + int inputPosition; + + // For js::Vector. Does not create a valid object. + ByteTerm() + { + } + + ByteTerm(UChar ch, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) + : frameLocation(frameLocation) + , m_capture(false) + , m_invert(false) + { + switch (quantityType) { + case QuantifierFixedCount: + type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed; + break; + case QuantifierGreedy: + type = ByteTerm::TypePatternCharacterGreedy; + break; + case QuantifierNonGreedy: + type = ByteTerm::TypePatternCharacterNonGreedy; + break; + } + + atom.patternCharacter = ch; + atom.quantityType = quantityType; + atom.quantityCount = quantityCount; + inputPosition = inputPos; + } + + ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) + : frameLocation(frameLocation) + , m_capture(false) + , m_invert(false) + { + switch (quantityType) { + case QuantifierFixedCount: + type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed; + break; + case QuantifierGreedy: + type = ByteTerm::TypePatternCasedCharacterGreedy; + break; + case QuantifierNonGreedy: + type = ByteTerm::TypePatternCasedCharacterNonGreedy; + break; + } + + atom.casedCharacter.lo = lo; + atom.casedCharacter.hi = hi; + atom.quantityType = quantityType; + atom.quantityCount = quantityCount; + inputPosition = inputPos; + } + + ByteTerm(CharacterClass* characterClass, bool invert, int inputPos) + : type(ByteTerm::TypeCharacterClass) + , m_capture(false) + , m_invert(invert) + { + atom.characterClass = characterClass; + atom.quantityType = QuantifierFixedCount; + atom.quantityCount = 1; + inputPosition = inputPos; + } + + ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool capture, int inputPos) + : type(type) + , m_capture(capture) + , m_invert(false) + { + atom.subpatternId = subpatternId; + atom.parenthesesDisjunction = parenthesesInfo; + atom.quantityType = QuantifierFixedCount; + atom.quantityCount = 1; + inputPosition = inputPos; + } + + ByteTerm(Type type, bool invert = false) + : type(type) + , m_capture(false) + , m_invert(invert) + { + atom.quantityType = QuantifierFixedCount; + atom.quantityCount = 1; + } + + ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, int inputPos) + : type(type) + , m_capture(capture) + , m_invert(invert) + { + atom.subpatternId = subpatternId; + atom.quantityType = QuantifierFixedCount; + atom.quantityCount = 1; + inputPosition = inputPos; + } + + static ByteTerm BOL(int inputPos) + { + ByteTerm term(TypeAssertionBOL); + term.inputPosition = inputPos; + return term; + } + + static ByteTerm CheckInput(unsigned count) + { + ByteTerm term(TypeCheckInput); + term.checkInputCount = count; + return term; + } + + static ByteTerm UncheckInput(unsigned count) + { + ByteTerm term(TypeUncheckInput); + term.checkInputCount = count; + return term; + } + + static ByteTerm EOL(int inputPos) + { + ByteTerm term(TypeAssertionEOL); + term.inputPosition = inputPos; + return term; + } + + static ByteTerm WordBoundary(bool invert, int inputPos) + { + ByteTerm term(TypeAssertionWordBoundary, invert); + term.inputPosition = inputPos; + return term; + } + + static ByteTerm BackReference(unsigned subpatternId, int inputPos) + { + return ByteTerm(TypeBackReference, subpatternId, false, false, inputPos); + } + + static ByteTerm BodyAlternativeBegin(bool onceThrough) + { + ByteTerm term(TypeBodyAlternativeBegin); + term.alternative.next = 0; + term.alternative.end = 0; + term.alternative.onceThrough = onceThrough; + return term; + } + + static ByteTerm BodyAlternativeDisjunction(bool onceThrough) + { + ByteTerm term(TypeBodyAlternativeDisjunction); + term.alternative.next = 0; + term.alternative.end = 0; + term.alternative.onceThrough = onceThrough; + return term; + } + + static ByteTerm BodyAlternativeEnd() + { + ByteTerm term(TypeBodyAlternativeEnd); + term.alternative.next = 0; + term.alternative.end = 0; + term.alternative.onceThrough = false; + return term; + } + + static ByteTerm AlternativeBegin() + { + ByteTerm term(TypeAlternativeBegin); + term.alternative.next = 0; + term.alternative.end = 0; + term.alternative.onceThrough = false; + return term; + } + + static ByteTerm AlternativeDisjunction() + { + ByteTerm term(TypeAlternativeDisjunction); + term.alternative.next = 0; + term.alternative.end = 0; + term.alternative.onceThrough = false; + return term; + } + + static ByteTerm AlternativeEnd() + { + ByteTerm term(TypeAlternativeEnd); + term.alternative.next = 0; + term.alternative.end = 0; + term.alternative.onceThrough = false; + return term; + } + + static ByteTerm SubpatternBegin() + { + return ByteTerm(TypeSubpatternBegin); + } + + static ByteTerm SubpatternEnd() + { + return ByteTerm(TypeSubpatternEnd); + } + + bool invert() + { + return m_invert; + } + + bool capture() + { + return m_capture; + } +}; + +class ByteDisjunction { + WTF_MAKE_FAST_ALLOCATED +public: + ByteDisjunction(unsigned numSubpatterns, unsigned frameSize) + : m_numSubpatterns(numSubpatterns) + , m_frameSize(frameSize) + { + } + + Vector terms; + unsigned m_numSubpatterns; + unsigned m_frameSize; +}; + +struct BytecodePattern { + WTF_MAKE_FAST_ALLOCATED +public: + BytecodePattern(PassOwnPtr body, Vector allParenthesesInfo, YarrPattern& pattern, BumpPointerAllocator* allocator) + : m_body(body) + , m_ignoreCase(pattern.m_ignoreCase) + , m_multiline(pattern.m_multiline) + , m_containsBeginChars(pattern.m_containsBeginChars) + , m_allocator(allocator) + { + newlineCharacterClass = pattern.newlineCharacterClass(); + wordcharCharacterClass = pattern.wordcharCharacterClass(); + + m_allParenthesesInfo.append(allParenthesesInfo); + m_userCharacterClasses.append(pattern.m_userCharacterClasses); + // 'Steal' the YarrPattern's CharacterClasses! We clear its + // array, so that it won't delete them on destruction. We'll + // take responsibility for that. + pattern.m_userCharacterClasses.clear(); + + m_beginChars.append(pattern.m_beginChars); + } + + ~BytecodePattern() + { + deleteAllValues(m_allParenthesesInfo); + deleteAllValues(m_userCharacterClasses); + } + + OwnPtr m_body; + bool m_ignoreCase; + bool m_multiline; + bool m_containsBeginChars; + // Each BytecodePattern is associated with a RegExp, each RegExp is associated + // with a JSGlobalData. Cache a pointer to out JSGlobalData's m_regExpAllocator. + BumpPointerAllocator* m_allocator; + + CharacterClass* newlineCharacterClass; + CharacterClass* wordcharCharacterClass; + + Vector m_beginChars; + +private: + Vector m_allParenthesesInfo; + Vector m_userCharacterClasses; +}; + +} } // namespace JSC::Yarr + +#endif // YarrInterpreter_h diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp new file mode 100644 index 000000000000..c0187f240b6d --- /dev/null +++ b/js/src/yarr/YarrJIT.cpp @@ -0,0 +1,2405 @@ +/* -*- 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. + * + * 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "YarrJIT.h" + +#include "assembler/assembler/LinkBuffer.h" +#include "Yarr.h" + +#if ENABLE_YARR_JIT + +using namespace WTF; + +namespace JSC { namespace Yarr { + +class YarrGenerator : private MacroAssembler { + friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); + +#if WTF_CPU_ARM + static const RegisterID input = ARMRegisters::r0; + static const RegisterID index = ARMRegisters::r1; + static const RegisterID length = ARMRegisters::r2; + static const RegisterID output = ARMRegisters::r4; + + static const RegisterID regT0 = ARMRegisters::r5; + static const RegisterID regT1 = ARMRegisters::r6; + + static const RegisterID returnRegister = ARMRegisters::r0; +#elif WTF_CPU_MIPS + static const RegisterID input = MIPSRegisters::a0; + static const RegisterID index = MIPSRegisters::a1; + static const RegisterID length = MIPSRegisters::a2; + static const RegisterID output = MIPSRegisters::a3; + + static const RegisterID regT0 = MIPSRegisters::t4; + static const RegisterID regT1 = MIPSRegisters::t5; + + static const RegisterID returnRegister = MIPSRegisters::v0; +#elif WTF_CPU_SH4 + static const RegisterID input = SH4Registers::r4; + static const RegisterID index = SH4Registers::r5; + static const RegisterID length = SH4Registers::r6; + static const RegisterID output = SH4Registers::r7; + + static const RegisterID regT0 = SH4Registers::r0; + static const RegisterID regT1 = SH4Registers::r1; + + static const RegisterID returnRegister = SH4Registers::r0; +#elif WTF_CPU_X86 + static const RegisterID input = X86Registers::eax; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::ecx; + static const RegisterID output = X86Registers::edi; + + static const RegisterID regT0 = X86Registers::ebx; + static const RegisterID regT1 = X86Registers::esi; + + static const RegisterID returnRegister = X86Registers::eax; +#elif WTF_CPU_X86_64 + static const RegisterID input = X86Registers::edi; + static const RegisterID index = X86Registers::esi; + static const RegisterID length = X86Registers::edx; + static const RegisterID output = X86Registers::ecx; + + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::ebx; + + static const RegisterID returnRegister = X86Registers::eax; +#endif + + void optimizeAlternative(PatternAlternative* alternative) + { + if (!alternative->m_terms.size()) + return; + + for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) { + PatternTerm& term = alternative->m_terms[i]; + PatternTerm& nextTerm = alternative->m_terms[i + 1]; + + if ((term.type == PatternTerm::TypeCharacterClass) + && (term.quantityType == QuantifierFixedCount) + && (nextTerm.type == PatternTerm::TypePatternCharacter) + && (nextTerm.quantityType == QuantifierFixedCount)) { + PatternTerm termCopy = term; + alternative->m_terms[i] = nextTerm; + alternative->m_terms[i + 1] = termCopy; + } + } + } + + void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) + { + do { + // pick which range we're going to generate + int which = count >> 1; + char lo = ranges[which].begin; + char hi = ranges[which].end; + + // check if there are any ranges or matches below lo. If not, just jl to failure - + // if there is anything else to check, check that first, if it falls through jmp to failure. + if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { + Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); + + // generate code for all ranges before this one + if (which) + matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); + + while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { + matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex]))); + ++*matchIndex; + } + failures.append(jump()); + + loOrAbove.link(this); + } else if (which) { + Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); + + matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); + failures.append(jump()); + + loOrAbove.link(this); + } else + failures.append(branch32(LessThan, character, Imm32((unsigned short)lo))); + + while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) + ++*matchIndex; + + matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi))); + // fall through to here, the value is above hi. + + // shuffle along & loop around if there are any more matches to handle. + unsigned next = which + 1; + ranges += next; + count -= next; + } while (count); + } + + void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass) + { + if (charClass->m_table) { + ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table)); + matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry)); + return; + } + Jump unicodeFail; + if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) { + Jump isAscii = branch32(LessThanOrEqual, character, TrustedImm32(0x7f)); + + if (charClass->m_matchesUnicode.size()) { + for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) { + UChar ch = charClass->m_matchesUnicode[i]; + matchDest.append(branch32(Equal, character, Imm32(ch))); + } + } + + if (charClass->m_rangesUnicode.size()) { + for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) { + UChar lo = charClass->m_rangesUnicode[i].begin; + UChar hi = charClass->m_rangesUnicode[i].end; + + Jump below = branch32(LessThan, character, Imm32(lo)); + matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi))); + below.link(this); + } + } + + unicodeFail = jump(); + isAscii.link(this); + } + + if (charClass->m_ranges.size()) { + unsigned matchIndex = 0; + JumpList failures; + matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size()); + while (matchIndex < charClass->m_matches.size()) + matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++]))); + + failures.link(this); + } else if (charClass->m_matches.size()) { + // optimization: gather 'a','A' etc back together, can mask & test once. + Vector matchesAZaz; + + for (unsigned i = 0; i < charClass->m_matches.size(); ++i) { + char ch = charClass->m_matches[i]; + if (m_pattern.m_ignoreCase) { + if (isASCIILower(ch)) { + matchesAZaz.append(ch); + continue; + } + if (isASCIIUpper(ch)) + continue; + } + matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch))); + } + + if (unsigned countAZaz = matchesAZaz.size()) { + or32(TrustedImm32(32), character); + for (unsigned i = 0; i < countAZaz; ++i) + matchDest.append(branch32(Equal, character, TrustedImm32(matchesAZaz[i]))); + } + } + + if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) + unicodeFail.link(this); + } + + // Jumps if input not available; will have (incorrectly) incremented already! + Jump jumpIfNoAvailableInput(unsigned countToCheck = 0) + { + if (countToCheck) + add32(Imm32(countToCheck), index); + return branch32(Above, index, length); + } + + Jump jumpIfAvailableInput(unsigned countToCheck) + { + add32(Imm32(countToCheck), index); + return branch32(BelowOrEqual, index, length); + } + + Jump checkInput() + { + return branch32(BelowOrEqual, index, length); + } + + Jump atEndOfInput() + { + return branch32(Equal, index, length); + } + + Jump notAtEndOfInput() + { + return branch32(NotEqual, index, length); + } + + Jump jumpIfCharEquals(UChar ch, int inputPosition) + { + return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); + } + + Jump jumpIfCharNotEquals(UChar ch, int inputPosition) + { + return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); + } + + void readCharacter(int inputPosition, RegisterID reg) + { + load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg); + } + + void storeToFrame(RegisterID reg, unsigned frameLocation) + { + poke(reg, frameLocation); + } + + void storeToFrame(TrustedImm32 imm, unsigned frameLocation) + { + poke(imm, frameLocation); + } + + DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) + { + return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*))); + } + + void loadFromFrame(unsigned frameLocation, RegisterID reg) + { + peek(reg, frameLocation); + } + + void loadFromFrameAndJump(unsigned frameLocation) + { + jump(Address(stackPointerRegister, frameLocation * sizeof(void*))); + } + + enum YarrOpCode { + // These nodes wrap body alternatives - those in the main disjunction, + // rather than subpatterns or assertions. These are chained together in + // a doubly linked list, with a 'begin' node for the first alternative, + // a 'next' node for each subsequent alternative, and an 'end' node at + // the end. In the case of repeating alternatives, the 'end' node also + // has a reference back to 'begin'. + OpBodyAlternativeBegin, + OpBodyAlternativeNext, + OpBodyAlternativeEnd, + // Similar to the body alternatives, but used for subpatterns with two + // or more alternatives. + OpNestedAlternativeBegin, + OpNestedAlternativeNext, + OpNestedAlternativeEnd, + // Used for alternatives in subpatterns where there is only a single + // alternative (backtrackingis easier in these cases), or for alternatives + // which never need to be backtracked (those in parenthetical assertions, + // terminal subpatterns). + OpSimpleNestedAlternativeBegin, + OpSimpleNestedAlternativeNext, + OpSimpleNestedAlternativeEnd, + // Used to wrap 'Once' subpattern matches (quantityCount == 1). + OpParenthesesSubpatternOnceBegin, + OpParenthesesSubpatternOnceEnd, + // Used to wrap 'Terminal' subpattern matches (at the end of the regexp). + OpParenthesesSubpatternTerminalBegin, + OpParenthesesSubpatternTerminalEnd, + // Used to wrap parenthetical assertions. + OpParentheticalAssertionBegin, + OpParentheticalAssertionEnd, + // Wraps all simple terms (pattern characters, character classes). + OpTerm, + // Where an expression contains only 'once through' body alternatives + // and no repeating ones, this op is used to return match failure. + OpMatchFailed + }; + + // This structure is used to hold the compiled opcode information, + // including reference back to the original PatternTerm/PatternAlternatives, + // and JIT compilation data structures. + struct YarrOp { + explicit YarrOp(PatternTerm* term) + : m_op(OpTerm) + , m_term(term) + , m_isDeadCode(false) + { + } + + explicit YarrOp(YarrOpCode op) + : m_op(op) + , m_isDeadCode(false) + { + } + + // The operation, as a YarrOpCode, and also a reference to the PatternTerm. + YarrOpCode m_op; + PatternTerm* m_term; + + // For alternatives, this holds the PatternAlternative and doubly linked + // references to this alternative's siblings. In the case of the + // OpBodyAlternativeEnd node at the end of a section of repeating nodes, + // m_nextOp will reference the OpBodyAlternativeBegin node of the first + // repeating alternative. + PatternAlternative* m_alternative; + size_t m_previousOp; + size_t m_nextOp; + + // Used to record a set of Jumps out of the generated code, typically + // used for jumps out to backtracking code, and a single reentry back + // into the code for a node (likely where a backtrack will trigger + // rematching). + Label m_reentry; + JumpList m_jumps; + + // This flag is used to null out the second pattern character, when + // two are fused to match a pair together. + bool m_isDeadCode; + + // Currently used in the case of some of the more complex management of + // 'm_checked', to cache the offset used in this alternative, to avoid + // recalculating it. + int m_checkAdjust; + + // Used by OpNestedAlternativeNext/End to hold the pointer to the + // value that will be pushed into the pattern's frame to return to, + // upon backtracking back into the disjunction. + DataLabelPtr m_returnAddress; + }; + + // BacktrackingState + // This class encapsulates information about the state of code generation + // whilst generating the code for backtracking, when a term fails to match. + // Upon entry to code generation of the backtracking code for a given node, + // the Backtracking state will hold references to all control flow sources + // that are outputs in need of further backtracking from the prior node + // generated (which is the subsequent operation in the regular expression, + // and in the m_ops Vector, since we generated backtracking backwards). + // These references to control flow take the form of: + // - A jump list of jumps, to be linked to code that will backtrack them + // further. + // - A set of DataLabelPtr values, to be populated with values to be + // treated effectively as return addresses backtracking into complex + // subpatterns. + // - A flag indicating that the current sequence of generated code up to + // this point requires backtracking. + class BacktrackingState { + public: + BacktrackingState() + : m_pendingFallthrough(false) + { + } + + // Add a jump or jumps, a return address, or set the flag indicating + // that the current 'fallthrough' control flow requires backtracking. + void append(const Jump& jump) + { + m_laterFailures.append(jump); + } + void append(JumpList& jumpList) + { + m_laterFailures.append(jumpList); + } + void append(const DataLabelPtr& returnAddress) + { + m_pendingReturns.append(returnAddress); + } + void fallthrough() + { + ASSERT(!m_pendingFallthrough); + m_pendingFallthrough = true; + } + + // These methods clear the backtracking state, either linking to the + // current location, a provided label, or copying the backtracking out + // to a JumpList. All actions may require code generation to take place, + // and as such are passed a pointer to the assembler. + void link(MacroAssembler* assembler) + { + if (m_pendingReturns.size()) { + Label here(assembler); + for (unsigned i = 0; i < m_pendingReturns.size(); ++i) + m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here)); + m_pendingReturns.clear(); + } + m_laterFailures.link(assembler); + m_laterFailures.clear(); + m_pendingFallthrough = false; + } + void linkTo(Label label, MacroAssembler* assembler) + { + if (m_pendingReturns.size()) { + for (unsigned i = 0; i < m_pendingReturns.size(); ++i) + m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], label)); + m_pendingReturns.clear(); + } + if (m_pendingFallthrough) + assembler->jump(label); + m_laterFailures.linkTo(label, assembler); + m_laterFailures.clear(); + m_pendingFallthrough = false; + } + void takeBacktracksToJumpList(JumpList& jumpList, MacroAssembler* assembler) + { + if (m_pendingReturns.size()) { + Label here(assembler); + for (unsigned i = 0; i < m_pendingReturns.size(); ++i) + m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here)); + m_pendingReturns.clear(); + m_pendingFallthrough = true; + } + if (m_pendingFallthrough) + jumpList.append(assembler->jump()); + jumpList.append(m_laterFailures); + m_laterFailures.clear(); + m_pendingFallthrough = false; + } + + bool isEmpty() + { + return m_laterFailures.empty() && m_pendingReturns.isEmpty() && !m_pendingFallthrough; + } + + // Called at the end of code generation to link all return addresses. + void linkDataLabels(LinkBuffer& linkBuffer) + { + ASSERT(isEmpty()); + for (unsigned i = 0; i < m_backtrackRecords.size(); ++i) + linkBuffer.patch(m_backtrackRecords[i].m_dataLabel, linkBuffer.locationOf(m_backtrackRecords[i].m_backtrackLocation)); + } + + private: + struct ReturnAddressRecord { + ReturnAddressRecord(DataLabelPtr dataLabel, Label backtrackLocation) + : m_dataLabel(dataLabel) + , m_backtrackLocation(backtrackLocation) + { + } + + DataLabelPtr m_dataLabel; + Label m_backtrackLocation; + }; + + JumpList m_laterFailures; + bool m_pendingFallthrough; + Vector m_pendingReturns; + Vector m_backtrackRecords; + }; + + // Generation methods: + // =================== + + // This method provides a default implementation of backtracking common + // to many terms; terms commonly jump out of the forwards matching path + // on any failed conditions, and add these jumps to the m_jumps list. If + // no special handling is required we can often just backtrack to m_jumps. + void backtrackTermDefault(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + m_backtrackingState.append(op.m_jumps); + } + + void generateAssertionBOL(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + if (m_pattern.m_multiline) { + const RegisterID character = regT0; + + JumpList matchDest; + if (!term->inputPosition) + matchDest.append(branch32(Equal, index, Imm32(m_checked))); + + readCharacter((term->inputPosition - m_checked) - 1, character); + matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); + op.m_jumps.append(jump()); + + matchDest.link(this); + } else { + // Erk, really should poison out these alternatives early. :-/ + if (term->inputPosition) + op.m_jumps.append(jump()); + else + op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked))); + } + } + void backtrackAssertionBOL(size_t opIndex) + { + backtrackTermDefault(opIndex); + } + + void generateAssertionEOL(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + if (m_pattern.m_multiline) { + const RegisterID character = regT0; + + JumpList matchDest; + if (term->inputPosition == m_checked) + matchDest.append(atEndOfInput()); + + readCharacter((term->inputPosition - m_checked), character); + matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); + op.m_jumps.append(jump()); + + matchDest.link(this); + } else { + if (term->inputPosition == m_checked) + op.m_jumps.append(notAtEndOfInput()); + // Erk, really should poison out these alternatives early. :-/ + else + op.m_jumps.append(jump()); + } + } + void backtrackAssertionEOL(size_t opIndex) + { + backtrackTermDefault(opIndex); + } + + // Also falls though on nextIsNotWordChar. + void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID character = regT0; + + if (term->inputPosition == m_checked) + nextIsNotWordChar.append(atEndOfInput()); + + readCharacter((term->inputPosition - m_checked), character); + matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass()); + } + + void generateAssertionWordBoundary(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID character = regT0; + + Jump atBegin; + JumpList matchDest; + if (!term->inputPosition) + atBegin = branch32(Equal, index, Imm32(m_checked)); + readCharacter((term->inputPosition - m_checked) - 1, character); + matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass()); + if (!term->inputPosition) + atBegin.link(this); + + // We fall through to here if the last character was not a wordchar. + JumpList nonWordCharThenWordChar; + JumpList nonWordCharThenNonWordChar; + if (term->invert()) { + matchAssertionWordchar(opIndex, nonWordCharThenNonWordChar, nonWordCharThenWordChar); + nonWordCharThenWordChar.append(jump()); + } else { + matchAssertionWordchar(opIndex, nonWordCharThenWordChar, nonWordCharThenNonWordChar); + nonWordCharThenNonWordChar.append(jump()); + } + op.m_jumps.append(nonWordCharThenNonWordChar); + + // We jump here if the last character was a wordchar. + matchDest.link(this); + JumpList wordCharThenWordChar; + JumpList wordCharThenNonWordChar; + if (term->invert()) { + matchAssertionWordchar(opIndex, wordCharThenNonWordChar, wordCharThenWordChar); + wordCharThenWordChar.append(jump()); + } else { + matchAssertionWordchar(opIndex, wordCharThenWordChar, wordCharThenNonWordChar); + // This can fall-though! + } + + op.m_jumps.append(wordCharThenWordChar); + + nonWordCharThenWordChar.link(this); + wordCharThenNonWordChar.link(this); + } + void backtrackAssertionWordBoundary(size_t opIndex) + { + backtrackTermDefault(opIndex); + } + + void generatePatternCharacterOnce(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + + // m_ops always ends with a OpBodyAlternativeEnd or OpMatchFailed + // node, so there must always be at least one more node. + ASSERT(opIndex + 1 < m_ops.size()); + YarrOp& nextOp = m_ops[opIndex + 1]; + + if (op.m_isDeadCode) + return; + + PatternTerm* term = op.m_term; + UChar ch = term->patternCharacter; + + const RegisterID character = regT0; + + if (nextOp.m_op == OpTerm) { + PatternTerm* nextTerm = nextOp.m_term; + if (nextTerm->type == PatternTerm::TypePatternCharacter + && nextTerm->quantityType == QuantifierFixedCount + && nextTerm->quantityCount == 1 + && nextTerm->inputPosition == (term->inputPosition + 1)) { + + UChar ch2 = nextTerm->patternCharacter; + + int mask = 0; + int chPair = ch | (ch2 << 16); + + if (m_pattern.m_ignoreCase) { + if (isASCIIAlpha(ch)) + mask |= 32; + if (isASCIIAlpha(ch2)) + mask |= 32 << 16; + } + + BaseIndex address(input, index, TimesTwo, (term->inputPosition - m_checked) * sizeof(UChar)); + if (mask) { + load32WithUnalignedHalfWords(address, character); + or32(Imm32(mask), character); + op.m_jumps.append(branch32(NotEqual, character, Imm32(chPair | mask))); + } else + op.m_jumps.append(branch32WithUnalignedHalfWords(NotEqual, address, Imm32(chPair))); + + nextOp.m_isDeadCode = true; + return; + } + } + + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(term->inputPosition - m_checked, character); + or32(TrustedImm32(32), character); + op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + op.m_jumps.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked)); + } + } + void backtrackPatternCharacterOnce(size_t opIndex) + { + backtrackTermDefault(opIndex); + } + + void generatePatternCharacterFixed(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + UChar ch = term->patternCharacter; + + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + + move(index, countRegister); + sub32(Imm32(term->quantityCount), countRegister); + + Label loop(this); + BaseIndex address(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar)); + + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + load16(address, character); + or32(TrustedImm32(32), character); + op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + op.m_jumps.append(branch16(NotEqual, address, Imm32(ch))); + } + add32(TrustedImm32(1), countRegister); + branch32(NotEqual, countRegister, index).linkTo(loop, this); + } + void backtrackPatternCharacterFixed(size_t opIndex) + { + backtrackTermDefault(opIndex); + } + + void generatePatternCharacterGreedy(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + UChar ch = term->patternCharacter; + + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + + move(TrustedImm32(0), countRegister); + + JumpList failures; + Label loop(this); + failures.append(atEndOfInput()); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(term->inputPosition - m_checked, character); + or32(TrustedImm32(32), character); + failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked)); + } + + add32(TrustedImm32(1), countRegister); + add32(TrustedImm32(1), index); + if (term->quantityCount == quantifyInfinite) + jump(loop); + else + branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this); + + failures.link(this); + op.m_reentry = label(); + + storeToFrame(countRegister, term->frameLocation); + + } + void backtrackPatternCharacterGreedy(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID countRegister = regT1; + + m_backtrackingState.link(this); + + loadFromFrame(term->frameLocation, countRegister); + m_backtrackingState.append(branchTest32(Zero, countRegister)); + sub32(TrustedImm32(1), countRegister); + sub32(TrustedImm32(1), index); + jump(op.m_reentry); + } + + void generatePatternCharacterNonGreedy(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID countRegister = regT1; + + move(TrustedImm32(0), countRegister); + op.m_reentry = label(); + storeToFrame(countRegister, term->frameLocation); + } + void backtrackPatternCharacterNonGreedy(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + UChar ch = term->patternCharacter; + + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + + JumpList nonGreedyFailures; + + m_backtrackingState.link(this); + + loadFromFrame(term->frameLocation, countRegister); + + nonGreedyFailures.append(atEndOfInput()); + if (term->quantityCount != quantifyInfinite) + nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount))); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(term->inputPosition - m_checked, character); + or32(TrustedImm32(32), character); + nonGreedyFailures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked)); + } + + add32(TrustedImm32(1), countRegister); + add32(TrustedImm32(1), index); + + jump(op.m_reentry); + + nonGreedyFailures.link(this); + sub32(countRegister, index); + m_backtrackingState.fallthrough(); + } + + void generateCharacterClassOnce(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID character = regT0; + + JumpList matchDest; + readCharacter((term->inputPosition - m_checked), character); + matchCharacterClass(character, matchDest, term->characterClass); + + if (term->invert()) + op.m_jumps.append(matchDest); + else { + op.m_jumps.append(jump()); + matchDest.link(this); + } + } + void backtrackCharacterClassOnce(size_t opIndex) + { + backtrackTermDefault(opIndex); + } + + void generateCharacterClassFixed(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + + move(index, countRegister); + sub32(Imm32(term->quantityCount), countRegister); + + Label loop(this); + JumpList matchDest; + load16(BaseIndex(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar)), character); + matchCharacterClass(character, matchDest, term->characterClass); + + if (term->invert()) + op.m_jumps.append(matchDest); + else { + op.m_jumps.append(jump()); + matchDest.link(this); + } + + add32(TrustedImm32(1), countRegister); + branch32(NotEqual, countRegister, index).linkTo(loop, this); + } + void backtrackCharacterClassFixed(size_t opIndex) + { + backtrackTermDefault(opIndex); + } + + void generateCharacterClassGreedy(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + + move(TrustedImm32(0), countRegister); + + JumpList failures; + Label loop(this); + failures.append(atEndOfInput()); + + if (term->invert()) { + readCharacter(term->inputPosition - m_checked, character); + matchCharacterClass(character, failures, term->characterClass); + } else { + JumpList matchDest; + readCharacter(term->inputPosition - m_checked, character); + matchCharacterClass(character, matchDest, term->characterClass); + failures.append(jump()); + matchDest.link(this); + } + + add32(TrustedImm32(1), countRegister); + add32(TrustedImm32(1), index); + if (term->quantityCount != quantifyInfinite) { + branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this); + failures.append(jump()); + } else + jump(loop); + + failures.link(this); + op.m_reentry = label(); + + storeToFrame(countRegister, term->frameLocation); + } + void backtrackCharacterClassGreedy(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID countRegister = regT1; + + m_backtrackingState.link(this); + + loadFromFrame(term->frameLocation, countRegister); + m_backtrackingState.append(branchTest32(Zero, countRegister)); + sub32(TrustedImm32(1), countRegister); + sub32(TrustedImm32(1), index); + jump(op.m_reentry); + } + + void generateCharacterClassNonGreedy(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID countRegister = regT1; + + move(TrustedImm32(0), countRegister); + op.m_reentry = label(); + storeToFrame(countRegister, term->frameLocation); + } + void backtrackCharacterClassNonGreedy(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + + JumpList nonGreedyFailures; + + m_backtrackingState.link(this); + + Label backtrackBegin(this); + loadFromFrame(term->frameLocation, countRegister); + + nonGreedyFailures.append(atEndOfInput()); + nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount))); + + JumpList matchDest; + readCharacter(term->inputPosition - m_checked, character); + matchCharacterClass(character, matchDest, term->characterClass); + + if (term->invert()) + nonGreedyFailures.append(matchDest); + else { + nonGreedyFailures.append(jump()); + matchDest.link(this); + } + + add32(TrustedImm32(1), countRegister); + add32(TrustedImm32(1), index); + + jump(op.m_reentry); + + nonGreedyFailures.link(this); + sub32(countRegister, index); + m_backtrackingState.fallthrough(); + } + + // Code generation/backtracking for simple terms + // (pattern characters, character classes, and assertions). + // These methods farm out work to the set of functions above. + void generateTerm(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + switch (term->type) { + case PatternTerm::TypePatternCharacter: + switch (term->quantityType) { + case QuantifierFixedCount: + if (term->quantityCount == 1) + generatePatternCharacterOnce(opIndex); + else + generatePatternCharacterFixed(opIndex); + break; + case QuantifierGreedy: + generatePatternCharacterGreedy(opIndex); + break; + case QuantifierNonGreedy: + generatePatternCharacterNonGreedy(opIndex); + break; + } + break; + + case PatternTerm::TypeCharacterClass: + switch (term->quantityType) { + case QuantifierFixedCount: + if (term->quantityCount == 1) + generateCharacterClassOnce(opIndex); + else + generateCharacterClassFixed(opIndex); + break; + case QuantifierGreedy: + generateCharacterClassGreedy(opIndex); + break; + case QuantifierNonGreedy: + generateCharacterClassNonGreedy(opIndex); + break; + } + break; + + case PatternTerm::TypeAssertionBOL: + generateAssertionBOL(opIndex); + break; + + case PatternTerm::TypeAssertionEOL: + generateAssertionEOL(opIndex); + break; + + case PatternTerm::TypeAssertionWordBoundary: + generateAssertionWordBoundary(opIndex); + break; + + case PatternTerm::TypeForwardReference: + break; + + case PatternTerm::TypeParenthesesSubpattern: + case PatternTerm::TypeParentheticalAssertion: + ASSERT_NOT_REACHED(); + case PatternTerm::TypeBackReference: + m_shouldFallBack = true; + break; + } + } + void backtrackTerm(size_t opIndex) + { + YarrOp& op = m_ops[opIndex]; + PatternTerm* term = op.m_term; + + switch (term->type) { + case PatternTerm::TypePatternCharacter: + switch (term->quantityType) { + case QuantifierFixedCount: + if (term->quantityCount == 1) + backtrackPatternCharacterOnce(opIndex); + else + backtrackPatternCharacterFixed(opIndex); + break; + case QuantifierGreedy: + backtrackPatternCharacterGreedy(opIndex); + break; + case QuantifierNonGreedy: + backtrackPatternCharacterNonGreedy(opIndex); + break; + } + break; + + case PatternTerm::TypeCharacterClass: + switch (term->quantityType) { + case QuantifierFixedCount: + if (term->quantityCount == 1) + backtrackCharacterClassOnce(opIndex); + else + backtrackCharacterClassFixed(opIndex); + break; + case QuantifierGreedy: + backtrackCharacterClassGreedy(opIndex); + break; + case QuantifierNonGreedy: + backtrackCharacterClassNonGreedy(opIndex); + break; + } + break; + + case PatternTerm::TypeAssertionBOL: + backtrackAssertionBOL(opIndex); + break; + + case PatternTerm::TypeAssertionEOL: + backtrackAssertionEOL(opIndex); + break; + + case PatternTerm::TypeAssertionWordBoundary: + backtrackAssertionWordBoundary(opIndex); + break; + + case PatternTerm::TypeForwardReference: + break; + + case PatternTerm::TypeParenthesesSubpattern: + case PatternTerm::TypeParentheticalAssertion: + ASSERT_NOT_REACHED(); + case PatternTerm::TypeBackReference: + m_shouldFallBack = true; + break; + } + } + + void generate() + { + // Forwards generate the matching code. + ASSERT(m_ops.size()); + size_t opIndex = 0; + + do { + YarrOp& op = m_ops[opIndex]; + switch (op.m_op) { + + case OpTerm: + generateTerm(opIndex); + break; + + // OpBodyAlternativeBegin/Next/End + // + // These nodes wrap the set of alternatives in the body of the regular expression. + // There may be either one or two chains of OpBodyAlternative nodes, one representing + // the 'once through' sequence of alternatives (if any exist), and one representing + // the repeating alternatives (again, if any exist). + // + // Upon normal entry to the Begin alternative, we will check that input is available. + // Reentry to the Begin alternative will take place after the check has taken place, + // and will assume that the input position has already been progressed as appropriate. + // + // Entry to subsequent Next/End alternatives occurs when the prior alternative has + // successfully completed a match - return a success state from JIT code. + // + // Next alternatives allow for reentry optimized to suit backtracking from its + // preceding alternative. It expects the input position to still be set to a position + // appropriate to its predecessor, and it will only perform an input check if the + // predecessor had a minimum size less than its own. + // + // In the case 'once through' expressions, the End node will also have a reentry + // point to jump to when the last alternative fails. Again, this expects the input + // position to still reflect that expected by the prior alternative. + case OpBodyAlternativeBegin: { + PatternAlternative* alternative = op.m_alternative; + + // Upon entry at the head of the set of alternatives, check if input is available + // to run the first alternative. (This progresses the input position). + op.m_jumps.append(jumpIfNoAvailableInput(alternative->m_minimumSize)); + // We will reenter after the check, and assume the input position to have been + // set as appropriate to this alternative. + op.m_reentry = label(); + + m_checked += alternative->m_minimumSize; + break; + } + case OpBodyAlternativeNext: + case OpBodyAlternativeEnd: { + PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative; + PatternAlternative* alternative = op.m_alternative; + + // If we get here, the prior alternative matched - return success. + + // Adjust the stack pointer to remove the pattern's frame. + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + // Load appropriate values into the return register and the first output + // slot, and return. In the case of pattern with a fixed size, we will + // not have yet set the value in the first + ASSERT(index != returnRegister); + if (m_pattern.m_body->m_hasFixedSize) { + move(index, returnRegister); + if (priorAlternative->m_minimumSize) + sub32(Imm32(priorAlternative->m_minimumSize), returnRegister); + store32(returnRegister, output); + } else + load32(Address(output), returnRegister); + store32(index, Address(output, 4)); + generateReturn(); + + // This is the divide between the tail of the prior alternative, above, and + // the head of the subsequent alternative, below. + + if (op.m_op == OpBodyAlternativeNext) { + // This is the reentry point for the Next alternative. We expect any code + // that jumps here to do so with the input position matching that of the + // PRIOR alteranative, and we will only check input availability if we + // need to progress it forwards. + op.m_reentry = label(); + if (int delta = alternative->m_minimumSize - priorAlternative->m_minimumSize) { + add32(Imm32(delta), index); + if (delta > 0) + op.m_jumps.append(jumpIfNoAvailableInput()); + } + } else if (op.m_nextOp == notFound) { + // This is the reentry point for the End of 'once through' alternatives, + // jumped to when the las alternative fails to match. + op.m_reentry = label(); + sub32(Imm32(priorAlternative->m_minimumSize), index); + } + + if (op.m_op == OpBodyAlternativeNext) + m_checked += alternative->m_minimumSize; + m_checked -= priorAlternative->m_minimumSize; + break; + } + + // OpSimpleNestedAlternativeBegin/Next/End + // OpNestedAlternativeBegin/Next/End + // + // These nodes are used to handle sets of alternatives that are nested within + // subpatterns and parenthetical assertions. The 'simple' forms are used where + // we do not need to be able to backtrack back into any alternative other than + // the last, the normal forms allow backtracking into any alternative. + // + // Each Begin/Next node is responsible for planting an input check to ensure + // sufficient input is available on entry. Next nodes additionally need to + // jump to the end - Next nodes use the End node's m_jumps list to hold this + // set of jumps. + // + // In the non-simple forms, successful alternative matches must store a + // 'return address' using a DataLabelPtr, used to store the address to jump + // to when backtracking, to get to the code for the appropriate alternative. + case OpSimpleNestedAlternativeBegin: + case OpNestedAlternativeBegin: { + PatternTerm* term = op.m_term; + PatternAlternative* alternative = op.m_alternative; + PatternDisjunction* disjunction = term->parentheses.disjunction; + + // Calculate how much input we need to check for, and if non-zero check. + op.m_checkAdjust = alternative->m_minimumSize; + if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion)) + op.m_checkAdjust -= disjunction->m_minimumSize; + if (op.m_checkAdjust) + op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust)); + + m_checked += op.m_checkAdjust; + break; + } + case OpSimpleNestedAlternativeNext: + case OpNestedAlternativeNext: { + PatternTerm* term = op.m_term; + PatternAlternative* alternative = op.m_alternative; + PatternDisjunction* disjunction = term->parentheses.disjunction; + + // In the non-simple case, store a 'return address' so we can backtrack correctly. + if (op.m_op == OpNestedAlternativeNext) { + unsigned parenthesesFrameLocation = term->frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation; + if (term->quantityType != QuantifierFixedCount) + alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; + op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation); + } + + // If we reach here then the last alternative has matched - jump to the + // End node, to skip over any further alternatives. + // + // FIXME: this is logically O(N^2) (though N can be expected to be very + // small). We could avoid this either by adding an extra jump to the JIT + // data structures, or by making backtracking code that jumps to Next + // alternatives are responsible for checking that input is available (if + // we didn't need to plant the input checks, then m_jumps would be free). + YarrOp* endOp = &m_ops[op.m_nextOp]; + while (endOp->m_nextOp != notFound) { + ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext); + endOp = &m_ops[endOp->m_nextOp]; + } + ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd); + endOp->m_jumps.append(jump()); + + // This is the entry point for the next alternative. + op.m_reentry = label(); + + // Calculate how much input we need to check for, and if non-zero check. + op.m_checkAdjust = alternative->m_minimumSize; + if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion)) + op.m_checkAdjust -= disjunction->m_minimumSize; + if (op.m_checkAdjust) + op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust)); + + YarrOp& lastOp = m_ops[op.m_previousOp]; + m_checked -= lastOp.m_checkAdjust; + m_checked += op.m_checkAdjust; + break; + } + case OpSimpleNestedAlternativeEnd: + case OpNestedAlternativeEnd: { + PatternTerm* term = op.m_term; + + // In the non-simple case, store a 'return address' so we can backtrack correctly. + if (op.m_op == OpNestedAlternativeEnd) { + unsigned parenthesesFrameLocation = term->frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation; + if (term->quantityType != QuantifierFixedCount) + alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; + op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation); + } + + // If this set of alternatives contains more than one alternative, + // then the Next nodes will have planted jumps to the End, and added + // them to this node's m_jumps list. + op.m_jumps.link(this); + op.m_jumps.clear(); + + YarrOp& lastOp = m_ops[op.m_previousOp]; + m_checked -= lastOp.m_checkAdjust; + break; + } + + // OpParenthesesSubpatternOnceBegin/End + // + // These nodes support (optionally) capturing subpatterns, that have a + // quantity count of 1 (this covers fixed once, and ?/?? quantifiers). + case OpParenthesesSubpatternOnceBegin: { + PatternTerm* term = op.m_term; + unsigned parenthesesFrameLocation = term->frameLocation; + const RegisterID indexTemporary = regT0; + ASSERT(term->quantityCount == 1); + + // Upon entry to a Greedy quantified set of parenthese store the index. + // We'll use this for two purposes: + // - To indicate which iteration we are on of mathing the remainder of + // the expression after the parentheses - the first, including the + // match within the parentheses, or the second having skipped over them. + // - To check for empty matches, which must be rejected. + // + // At the head of a NonGreedy set of parentheses we'll immediately set the + // value on the stack to -1 (indicating a match skipping the subpattern), + // and plant a jump to the end. We'll also plant a label to backtrack to + // to reenter the subpattern later, with a store to set up index on the + // second iteration. + // + // FIXME: for capturing parens, could use the index in the capture array? + if (term->quantityType == QuantifierGreedy) + storeToFrame(index, parenthesesFrameLocation); + else if (term->quantityType == QuantifierNonGreedy) { + storeToFrame(TrustedImm32(-1), parenthesesFrameLocation); + op.m_jumps.append(jump()); + op.m_reentry = label(); + storeToFrame(index, parenthesesFrameLocation); + } + + // If the parenthese are capturing, store the starting index value to the + // captures array, offsetting as necessary. + // + // FIXME: could avoid offsetting this value in JIT code, apply + // offsets only afterwards, at the point the results array is + // being accessed. + if (term->capture()) { + int offsetId = term->parentheses.subpatternId << 1; + int inputOffset = term->inputPosition - m_checked; + if (term->quantityType == QuantifierFixedCount) + inputOffset -= term->parentheses.disjunction->m_minimumSize; + if (inputOffset) { + move(index, indexTemporary); + add32(Imm32(inputOffset), indexTemporary); + store32(indexTemporary, Address(output, offsetId * sizeof(int))); + } else + store32(index, Address(output, offsetId * sizeof(int))); + } + break; + } + case OpParenthesesSubpatternOnceEnd: { + PatternTerm* term = op.m_term; + unsigned parenthesesFrameLocation = term->frameLocation; + const RegisterID indexTemporary = regT0; + ASSERT(term->quantityCount == 1); + + // For Greedy/NonGreedy quantified parentheses, we must reject zero length + // matches. If the minimum size is know to be non-zero we need not check. + if (term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize) + op.m_jumps.append(branch32(Equal, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)))); + + // If the parenthese are capturing, store the ending index value to the + // captures array, offsetting as necessary. + // + // FIXME: could avoid offsetting this value in JIT code, apply + // offsets only afterwards, at the point the results array is + // being accessed. + if (term->capture()) { + int offsetId = (term->parentheses.subpatternId << 1) + 1; + int inputOffset = term->inputPosition - m_checked; + if (inputOffset) { + move(index, indexTemporary); + add32(Imm32(inputOffset), indexTemporary); + store32(indexTemporary, Address(output, offsetId * sizeof(int))); + } else + store32(index, Address(output, offsetId * sizeof(int))); + } + + // If the parentheses are quantified Greedy then add a label to jump back + // to if get a failed match from after the parentheses. For NonGreedy + // parentheses, link the jump from before the subpattern to here. + if (term->quantityType == QuantifierGreedy) + op.m_reentry = label(); + else if (term->quantityType == QuantifierNonGreedy) { + YarrOp& beginOp = m_ops[op.m_previousOp]; + beginOp.m_jumps.link(this); + } + break; + } + + // OpParenthesesSubpatternTerminalBegin/End + case OpParenthesesSubpatternTerminalBegin: { + PatternTerm* term = op.m_term; + ASSERT(term->quantityType == QuantifierGreedy); + ASSERT(term->quantityCount == quantifyInfinite); + ASSERT(!term->capture()); + + // Upon entry set a label to loop back to. + op.m_reentry = label(); + + // Store the start index of the current match; we need to reject zero + // length matches. + storeToFrame(index, term->frameLocation); + break; + } + case OpParenthesesSubpatternTerminalEnd: { + PatternTerm* term = op.m_term; + + // Check for zero length matches - if the match is non-zero, then we + // can accept it & loop back up to the head of the subpattern. + YarrOp& beginOp = m_ops[op.m_previousOp]; + branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*)), beginOp.m_reentry); + + // Reject the match - backtrack back into the subpattern. + op.m_jumps.append(jump()); + + // This is the entry point to jump to when we stop matching - we will + // do so once the subpattern cannot match any more. + op.m_reentry = label(); + break; + } + + // OpParentheticalAssertionBegin/End + case OpParentheticalAssertionBegin: { + PatternTerm* term = op.m_term; + + // Store the current index - assertions should not update index, so + // we will need to restore it upon a successful match. + unsigned parenthesesFrameLocation = term->frameLocation; + storeToFrame(index, parenthesesFrameLocation); + + // Check + op.m_checkAdjust = m_checked - term->inputPosition; + if (op.m_checkAdjust) + sub32(Imm32(op.m_checkAdjust), index); + + m_checked -= op.m_checkAdjust; + break; + } + case OpParentheticalAssertionEnd: { + PatternTerm* term = op.m_term; + + // Restore the input index value. + unsigned parenthesesFrameLocation = term->frameLocation; + loadFromFrame(parenthesesFrameLocation, index); + + // If inverted, a successful match of the assertion must be treated + // as a failure, so jump to backtracking. + if (term->invert()) { + op.m_jumps.append(jump()); + op.m_reentry = label(); + } + + YarrOp& lastOp = m_ops[op.m_previousOp]; + m_checked += lastOp.m_checkAdjust; + break; + } + + case OpMatchFailed: + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + move(TrustedImm32(-1), returnRegister); + generateReturn(); + break; + } + + ++opIndex; + } while (opIndex < m_ops.size()); + } + + void backtrack() + { + // Backwards generate the backtracking code. + size_t opIndex = m_ops.size(); + ASSERT(opIndex); + + do { + --opIndex; + YarrOp& op = m_ops[opIndex]; + switch (op.m_op) { + + case OpTerm: + backtrackTerm(opIndex); + break; + + // OpBodyAlternativeBegin/Next/End + // + // For each Begin/Next node representing an alternative, we need to decide what to do + // in two circumstances: + // - If we backtrack back into this node, from within the alternative. + // - If the input check at the head of the alternative fails (if this exists). + // + // We treat these two cases differently since in the former case we have slightly + // more information - since we are backtracking out of a prior alternative we know + // that at least enough input was available to run it. For example, given the regular + // expression /a|b/, if we backtrack out of the first alternative (a failed pattern + // character match of 'a'), then we need not perform an additional input availability + // check before running the second alternative. + // + // Backtracking required differs for the last alternative, which in the case of the + // repeating set of alternatives must loop. The code generated for the last alternative + // will also be used to handle all input check failures from any prior alternatives - + // these require similar functionality, in seeking the next available alternative for + // which there is sufficient input. + // + // Since backtracking of all other alternatives simply requires us to link backtracks + // to the reentry point for the subsequent alternative, we will only be generating any + // code when backtracking the last alternative. + case OpBodyAlternativeBegin: + case OpBodyAlternativeNext: { + PatternAlternative* alternative = op.m_alternative; + + if (op.m_op == OpBodyAlternativeNext) { + PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative; + m_checked += priorAlternative->m_minimumSize; + } + m_checked -= alternative->m_minimumSize; + + // Is this the last alternative? If not, then if we backtrack to this point we just + // need to jump to try to match the next alternative. + if (m_ops[op.m_nextOp].m_op != OpBodyAlternativeEnd) { + m_backtrackingState.linkTo(m_ops[op.m_nextOp].m_reentry, this); + break; + } + YarrOp& endOp = m_ops[op.m_nextOp]; + + YarrOp* beginOp = &op; + while (beginOp->m_op != OpBodyAlternativeBegin) { + ASSERT(beginOp->m_op == OpBodyAlternativeNext); + beginOp = &m_ops[beginOp->m_previousOp]; + } + + bool onceThrough = endOp.m_nextOp == notFound; + + // First, generate code to handle cases where we backtrack out of an attempted match + // of the last alternative. If this is a 'once through' set of alternatives then we + // have nothing to do - link this straight through to the End. + if (onceThrough) + m_backtrackingState.linkTo(endOp.m_reentry, this); + else { + // Okay, we're going to need to loop. Calculate the delta between where the input + // position was, and where we want it to be allowing for the fact that we need to + // increment by 1. E.g. for the regexp /a|x/ we need to increment the position by + // 1 between loop iterations, but for /abcd|xyz/ we need to increment by two when + // looping from the last alternative to the first, for /a|xyz/ we need to decrement + // by 1, and for /a|xy/ we don't need to move the input position at all. + int deltaLastAlternativeToFirstAlternativePlusOne = (beginOp->m_alternative->m_minimumSize - alternative->m_minimumSize) + 1; + + // If we don't need to move the input poistion, and the pattern has a fixed size + // (in which case we omit the store of the start index until the pattern has matched) + // then we can just link the backtrack out of the last alternative straight to the + // head of the first alternative. + if (!deltaLastAlternativeToFirstAlternativePlusOne && m_pattern.m_body->m_hasFixedSize) + m_backtrackingState.linkTo(beginOp->m_reentry, this); + else { + // We need to generate a trampoline of code to execute before looping back + // around to the first alternative. + m_backtrackingState.link(this); + + // If the pattern size is not fixed, then store the start index, for use if we match. + if (!m_pattern.m_body->m_hasFixedSize) { + if (alternative->m_minimumSize == 1) + store32(index, Address(output)); + else { + move(index, regT0); + if (alternative->m_minimumSize) + sub32(Imm32(alternative->m_minimumSize - 1), regT0); + else + add32(Imm32(1), regT0); + store32(regT0, Address(output)); + } + } + + if (deltaLastAlternativeToFirstAlternativePlusOne) + add32(Imm32(deltaLastAlternativeToFirstAlternativePlusOne), index); + + // Loop. Since this code is only reached when we backtrack out of the last + // alternative (and NOT linked to from the input check upon entry to the + // last alternative) we know that there must be at least enough input as + // required by the last alternative. As such, we only need to check if the + // first will require more to run - if the same or less is required we can + // unconditionally jump. + if (deltaLastAlternativeToFirstAlternativePlusOne > 0) + checkInput().linkTo(beginOp->m_reentry, this); + else + jump(beginOp->m_reentry); + } + } + + // We can reach this point in the code in two ways: + // - Fallthrough from the code above (a repeating alternative backtracked out of its + // last alternative, and did not have sufficent input to run the first). + // - We will loop back up to the following label when a releating alternative loops, + // following a failed input check. + // + // Either way, we have just failed the input check for the first alternative. + Label firstInputCheckFailed(this); + + // Generate code to handle input check failures from alternatives except the last. + // prevOp is the alternative we're handling a bail out from (initially Begin), and + // nextOp is the alternative we will be attempting to reenter into. + // + // We will link input check failures from the forwards matching path back to the code + // that can handle them. + YarrOp* prevOp = beginOp; + YarrOp* nextOp = &m_ops[beginOp->m_nextOp]; + while (nextOp->m_op != OpBodyAlternativeEnd) { + prevOp->m_jumps.link(this); + + int delta = nextOp->m_alternative->m_minimumSize - prevOp->m_alternative->m_minimumSize; + if (delta) + add32(Imm32(delta), index); + + // We only get here if an input check fails, it is only worth checking again + // if the next alternative has a minimum size less than the last. + if (delta < 0) { + // FIXME: if we added an extra label to YarrOp, we could avoid needing to + // subtract delta back out, and reduce this code. Should performance test + // the benefit of this. + Jump fail = jumpIfNoAvailableInput(); + sub32(Imm32(delta), index); + jump(nextOp->m_reentry); + fail.link(this); + } + prevOp = nextOp; + nextOp = &m_ops[nextOp->m_nextOp]; + } + + // We fall through to here if there is insufficient input to run the last alternative. + + // If there is insufficient input to run the last alternative, then for 'once through' + // alternatives we are done - just jump back up into the forwards matching path at the End. + if (onceThrough) { + op.m_jumps.linkTo(endOp.m_reentry, this); + jump(endOp.m_reentry); + break; + } + + // For repeating alternatives, link any input check failure from the last alternative to + // this point. + op.m_jumps.link(this); + + bool needsToUpdateMatchStart = !m_pattern.m_body->m_hasFixedSize; + + // Check for cases where input position is already incremented by 1 for the last + // alternative (this is particularly useful where the minimum size of the body + // disjunction is 0, e.g. /a*|b/). + if (needsToUpdateMatchStart && alternative->m_minimumSize == 1) { + // index is already incremented by 1, so just store it now! + store32(index, Address(output)); + needsToUpdateMatchStart = false; + } + + // Check whether there is sufficient input to loop. Increment the input position by + // one, and check. Also add in the minimum disjunction size before checking - there + // is no point in looping if we're just going to fail all the input checks around + // the next iteration. + int deltaLastAlternativeToBodyMinimumPlusOne = (m_pattern.m_body->m_minimumSize + 1) - alternative->m_minimumSize; + if (deltaLastAlternativeToBodyMinimumPlusOne) + add32(Imm32(deltaLastAlternativeToBodyMinimumPlusOne), index); + Jump matchFailed = jumpIfNoAvailableInput(); + + if (needsToUpdateMatchStart) { + if (!m_pattern.m_body->m_minimumSize) + store32(index, Address(output)); + else { + move(index, regT0); + sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0); + store32(regT0, Address(output)); + } + } + + // Calculate how much more input the first alternative requires than the minimum + // for the body as a whole. If no more is needed then we dont need an additional + // input check here - jump straight back up to the start of the first alternative. + int deltaBodyMinimumToFirstAlternative = beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize; + if (!deltaBodyMinimumToFirstAlternative) + jump(beginOp->m_reentry); + else { + add32(Imm32(deltaBodyMinimumToFirstAlternative), index); + checkInput().linkTo(beginOp->m_reentry, this); + jump(firstInputCheckFailed); + } + + // We jump to here if we iterate to the point that there is insufficient input to + // run any matches, and need to return a failure state from JIT code. + matchFailed.link(this); + + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + move(TrustedImm32(-1), returnRegister); + generateReturn(); + break; + } + case OpBodyAlternativeEnd: { + // We should never backtrack back into a body disjunction. + ASSERT(m_backtrackingState.isEmpty()); + + PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative; + m_checked += priorAlternative->m_minimumSize; + break; + } + + // OpSimpleNestedAlternativeBegin/Next/End + // OpNestedAlternativeBegin/Next/End + // + // Generate code for when we backtrack back out of an alternative into + // a Begin or Next node, or when the entry input count check fails. If + // there are more alternatives we need to jump to the next alternative, + // if not we backtrack back out of the current set of parentheses. + // + // In the case of non-simple nested assertions we need to also link the + // 'return address' appropriately to backtrack back out into the correct + // alternative. + case OpSimpleNestedAlternativeBegin: + case OpSimpleNestedAlternativeNext: + case OpNestedAlternativeBegin: + case OpNestedAlternativeNext: { + YarrOp& nextOp = m_ops[op.m_nextOp]; + bool isBegin = op.m_previousOp == notFound; + bool isLastAlternative = nextOp.m_nextOp == notFound; + ASSERT(isBegin == (op.m_op == OpSimpleNestedAlternativeBegin || op.m_op == OpNestedAlternativeBegin)); + ASSERT(isLastAlternative == (nextOp.m_op == OpSimpleNestedAlternativeEnd || nextOp.m_op == OpNestedAlternativeEnd)); + + // Treat an input check failure the same as a failed match. + m_backtrackingState.append(op.m_jumps); + + // Set the backtracks to jump to the appropriate place. We may need + // to link the backtracks in one of three different way depending on + // the type of alternative we are dealing with: + // - A single alternative, with no simplings. + // - The last alternative of a set of two or more. + // - An alternative other than the last of a set of two or more. + // + // In the case of a single alternative on its own, we don't need to + // jump anywhere - if the alternative fails to match we can just + // continue to backtrack out of the parentheses without jumping. + // + // In the case of the last alternative in a set of more than one, we + // need to jump to return back out to the beginning. We'll do so by + // adding a jump to the End node's m_jumps list, and linking this + // when we come to generate the Begin node. For alternatives other + // than the last, we need to jump to the next alternative. + // + // If the alternative had adjusted the input position we must link + // backtracking to here, correct, and then jump on. If not we can + // link the backtracks directly to their destination. + if (op.m_checkAdjust) { + // Handle the cases where we need to link the backtracks here. + m_backtrackingState.link(this); + sub32(Imm32(op.m_checkAdjust), index); + if (!isLastAlternative) { + // An alternative that is not the last should jump to its successor. + jump(nextOp.m_reentry); + } else if (!isBegin) { + // The last of more than one alternatives must jump back to the begnning. + nextOp.m_jumps.append(jump()); + } else { + // A single alternative on its own can fall through. + m_backtrackingState.fallthrough(); + } + } else { + // Handle the cases where we can link the backtracks directly to their destinations. + if (!isLastAlternative) { + // An alternative that is not the last should jump to its successor. + m_backtrackingState.linkTo(nextOp.m_reentry, this); + } else if (!isBegin) { + // The last of more than one alternatives must jump back to the begnning. + m_backtrackingState.takeBacktracksToJumpList(nextOp.m_jumps, this); + } + // In the case of a single alternative on its own do nothing - it can fall through. + } + + // At this point we've handled the backtracking back into this node. + // Now link any backtracks that need to jump to here. + + // For non-simple alternatives, link the alternative's 'return address' + // so that we backtrack back out into the previous alternative. + if (op.m_op == OpNestedAlternativeNext) + m_backtrackingState.append(op.m_returnAddress); + + // If there is more than one alternative, then the last alternative will + // have planted a jump to be linked to the end. This jump was added to the + // End node's m_jumps list. If we are back at the beginning, link it here. + if (isBegin) { + YarrOp* endOp = &m_ops[op.m_nextOp]; + while (endOp->m_nextOp != notFound) { + ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext); + endOp = &m_ops[endOp->m_nextOp]; + } + ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd); + m_backtrackingState.append(endOp->m_jumps); + } + + if (!isBegin) { + YarrOp& lastOp = m_ops[op.m_previousOp]; + m_checked += lastOp.m_checkAdjust; + } + m_checked -= op.m_checkAdjust; + break; + } + case OpSimpleNestedAlternativeEnd: + case OpNestedAlternativeEnd: { + PatternTerm* term = op.m_term; + + // If we backtrack into the end of a simple subpattern do nothing; + // just continue through into the last alternative. If we backtrack + // into the end of a non-simple set of alterntives we need to jump + // to the backtracking return address set up during generation. + if (op.m_op == OpNestedAlternativeEnd) { + m_backtrackingState.link(this); + + // Plant a jump to the return address. + unsigned parenthesesFrameLocation = term->frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation; + if (term->quantityType != QuantifierFixedCount) + alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce; + loadFromFrameAndJump(alternativeFrameLocation); + + // Link the DataLabelPtr associated with the end of the last + // alternative to this point. + m_backtrackingState.append(op.m_returnAddress); + } + + YarrOp& lastOp = m_ops[op.m_previousOp]; + m_checked += lastOp.m_checkAdjust; + break; + } + + // OpParenthesesSubpatternOnceBegin/End + // + // When we are backtracking back out of a capturing subpattern we need + // to clear the start index in the matches output array, to record that + // this subpattern has not been captured. + // + // When backtracking back out of a Greedy quantified subpattern we need + // to catch this, and try running the remainder of the alternative after + // the subpattern again, skipping the parentheses. + // + // Upon backtracking back into a quantified set of parentheses we need to + // check whether we were currently skipping the subpattern. If not, we + // can backtrack into them, if we were we need to either backtrack back + // out of the start of the parentheses, or jump back to the forwards + // matching start, depending of whether the match is Greedy or NonGreedy. + case OpParenthesesSubpatternOnceBegin: { + PatternTerm* term = op.m_term; + ASSERT(term->quantityCount == 1); + + // We only need to backtrack to thispoint if capturing or greedy. + if (term->capture() || term->quantityType == QuantifierGreedy) { + m_backtrackingState.link(this); + + // If capturing, clear the capture (we only need to reset start). + if (term->capture()) + store32(TrustedImm32(-1), Address(output, (term->parentheses.subpatternId << 1) * sizeof(int))); + + // If Greedy, jump to the end. + if (term->quantityType == QuantifierGreedy) { + // Clear the flag in the stackframe indicating we ran through the subpattern. + unsigned parenthesesFrameLocation = term->frameLocation; + storeToFrame(TrustedImm32(-1), parenthesesFrameLocation); + // Jump to after the parentheses, skipping the subpattern. + jump(m_ops[op.m_nextOp].m_reentry); + // A backtrack from after the parentheses, when skipping the subpattern, + // will jump back to here. + op.m_jumps.link(this); + } + + m_backtrackingState.fallthrough(); + } + break; + } + case OpParenthesesSubpatternOnceEnd: { + PatternTerm* term = op.m_term; + + if (term->quantityType != QuantifierFixedCount) { + m_backtrackingState.link(this); + + // Check whether we should backtrack back into the parentheses, or if we + // are currently in a state where we had skipped over the subpattern + // (in which case the flag value on the stack will be -1). + unsigned parenthesesFrameLocation = term->frameLocation; + Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1)); + + if (term->quantityType == QuantifierGreedy) { + // For Greedy parentheses, we skip after having already tried going + // through the subpattern, so if we get here we're done. + YarrOp& beginOp = m_ops[op.m_previousOp]; + beginOp.m_jumps.append(hadSkipped); + } else { + // For NonGreedy parentheses, we try skipping the subpattern first, + // so if we get here we need to try running through the subpattern + // next. Jump back to the start of the parentheses in the forwards + // matching path. + ASSERT(term->quantityType == QuantifierNonGreedy); + YarrOp& beginOp = m_ops[op.m_previousOp]; + hadSkipped.linkTo(beginOp.m_reentry, this); + } + + m_backtrackingState.fallthrough(); + } + + m_backtrackingState.append(op.m_jumps); + break; + } + + // OpParenthesesSubpatternTerminalBegin/End + // + // Terminal subpatterns will always match - there is nothing after them to + // force a backtrack, and they have a minimum count of 0, and as such will + // always produce an acceptable result. + case OpParenthesesSubpatternTerminalBegin: { + // We will backtrack to this point once the subpattern cannot match any + // more. Since no match is accepted as a successful match (we are Greedy + // quantified with a minimum of zero) jump back to the forwards matching + // path at the end. + YarrOp& endOp = m_ops[op.m_nextOp]; + m_backtrackingState.linkTo(endOp.m_reentry, this); + break; + } + case OpParenthesesSubpatternTerminalEnd: + // We should never be backtracking to here (hence the 'terminal' in the name). + ASSERT(m_backtrackingState.isEmpty()); + m_backtrackingState.append(op.m_jumps); + break; + + // OpParentheticalAssertionBegin/End + case OpParentheticalAssertionBegin: { + PatternTerm* term = op.m_term; + YarrOp& endOp = m_ops[op.m_nextOp]; + + // We need to handle the backtracks upon backtracking back out + // of a parenthetical assertion if either we need to correct + // the input index, or the assertion was inverted. + if (op.m_checkAdjust || term->invert()) { + m_backtrackingState.link(this); + + if (op.m_checkAdjust) + add32(Imm32(op.m_checkAdjust), index); + + // In an inverted assertion failure to match the subpattern + // is treated as a successful match - jump to the end of the + // subpattern. We already have adjusted the input position + // back to that before the assertion, which is correct. + if (term->invert()) + jump(endOp.m_reentry); + + m_backtrackingState.fallthrough(); + } + + // The End node's jump list will contain any backtracks into + // the end of the assertion. Also, if inverted, we will have + // added the failure caused by a successful match to this. + m_backtrackingState.append(endOp.m_jumps); + + m_checked += op.m_checkAdjust; + break; + } + case OpParentheticalAssertionEnd: { + // FIXME: We should really be clearing any nested subpattern + // matches on bailing out from after the pattern. Firefox has + // this bug too (presumably because they use YARR!) + + // Never backtrack into an assertion; later failures bail to before the begin. + m_backtrackingState.takeBacktracksToJumpList(op.m_jumps, this); + + YarrOp& lastOp = m_ops[op.m_previousOp]; + m_checked -= lastOp.m_checkAdjust; + break; + } + + case OpMatchFailed: + break; + } + + } while (opIndex); + } + + // Compilation methods: + // ==================== + + // opCompileParenthesesSubpattern + // Emits ops for a subpattern (set of parentheses). These consist + // of a set of alternatives wrapped in an outer set of nodes for + // the parentheses. + // Supported types of parentheses are 'Once' (quantityCount == 1) + // and 'Terminal' (non-capturing parentheses quantified as greedy + // and infinite). + // Alternatives will use the 'Simple' set of ops if either the + // subpattern is terminal (in which case we will never need to + // backtrack), or if the subpattern only contains one alternative. + void opCompileParenthesesSubpattern(PatternTerm* term) + { + YarrOpCode parenthesesBeginOpCode; + YarrOpCode parenthesesEndOpCode; + YarrOpCode alternativeBeginOpCode = OpSimpleNestedAlternativeBegin; + YarrOpCode alternativeNextOpCode = OpSimpleNestedAlternativeNext; + YarrOpCode alternativeEndOpCode = OpSimpleNestedAlternativeEnd; + + // We can currently only compile quantity 1 subpatterns that are + // not copies. We generate a copy in the case of a range quantifier, + // e.g. /(?:x){3,9}/, or /(?:x)+/ (These are effectively expanded to + // /(?:x){3,3}(?:x){0,6}/ and /(?:x)(?:x)*/ repectively). The problem + // comes where the subpattern is capturing, in which case we would + // need to restore the capture from the first subpattern upon a + // failure in the second. + if (term->quantityCount == 1 && !term->parentheses.isCopy) { + // Select the 'Once' nodes. + parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin; + parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd; + + // If there is more than one alternative we cannot use the 'simple' nodes. + if (term->parentheses.disjunction->m_alternatives.size() != 1) { + alternativeBeginOpCode = OpNestedAlternativeBegin; + alternativeNextOpCode = OpNestedAlternativeNext; + alternativeEndOpCode = OpNestedAlternativeEnd; + } + } else if (term->parentheses.isTerminal) { + // Select the 'Terminal' nodes. + parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin; + parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd; + } else { + // This subpattern is not supported by the JIT. + m_shouldFallBack = true; + return; + } + + size_t parenBegin = m_ops.size(); + m_ops.append(parenthesesBeginOpCode); + + m_ops.append(alternativeBeginOpCode); + m_ops.last().m_previousOp = notFound; + m_ops.last().m_term = term; + Vector& alternatives = term->parentheses.disjunction->m_alternatives; + for (unsigned i = 0; i < alternatives.size(); ++i) { + size_t lastOpIndex = m_ops.size() - 1; + + PatternAlternative* nestedAlternative = alternatives[i]; + opCompileAlternative(nestedAlternative); + + size_t thisOpIndex = m_ops.size(); + m_ops.append(YarrOp(alternativeNextOpCode)); + + YarrOp& lastOp = m_ops[lastOpIndex]; + YarrOp& thisOp = m_ops[thisOpIndex]; + + lastOp.m_alternative = nestedAlternative; + lastOp.m_nextOp = thisOpIndex; + thisOp.m_previousOp = lastOpIndex; + thisOp.m_term = term; + } + YarrOp& lastOp = m_ops.last(); + ASSERT(lastOp.m_op == alternativeNextOpCode); + lastOp.m_op = alternativeEndOpCode; + lastOp.m_alternative = 0; + lastOp.m_nextOp = notFound; + + size_t parenEnd = m_ops.size(); + m_ops.append(parenthesesEndOpCode); + + m_ops[parenBegin].m_term = term; + m_ops[parenBegin].m_previousOp = notFound; + m_ops[parenBegin].m_nextOp = parenEnd; + m_ops[parenEnd].m_term = term; + m_ops[parenEnd].m_previousOp = parenBegin; + m_ops[parenEnd].m_nextOp = notFound; + } + + // opCompileParentheticalAssertion + // Emits ops for a parenthetical assertion. These consist of an + // OpSimpleNestedAlternativeBegin/Next/End set of nodes wrapping + // the alternatives, with these wrapped by an outer pair of + // OpParentheticalAssertionBegin/End nodes. + // We can always use the OpSimpleNestedAlternative nodes in the + // case of parenthetical assertions since these only ever match + // once, and will never backtrack back into the assertion. + void opCompileParentheticalAssertion(PatternTerm* term) + { + size_t parenBegin = m_ops.size(); + m_ops.append(OpParentheticalAssertionBegin); + + m_ops.append(OpSimpleNestedAlternativeBegin); + m_ops.last().m_previousOp = notFound; + m_ops.last().m_term = term; + Vector& alternatives = term->parentheses.disjunction->m_alternatives; + for (unsigned i = 0; i < alternatives.size(); ++i) { + size_t lastOpIndex = m_ops.size() - 1; + + PatternAlternative* nestedAlternative = alternatives[i]; + opCompileAlternative(nestedAlternative); + + size_t thisOpIndex = m_ops.size(); + m_ops.append(YarrOp(OpSimpleNestedAlternativeNext)); + + YarrOp& lastOp = m_ops[lastOpIndex]; + YarrOp& thisOp = m_ops[thisOpIndex]; + + lastOp.m_alternative = nestedAlternative; + lastOp.m_nextOp = thisOpIndex; + thisOp.m_previousOp = lastOpIndex; + thisOp.m_term = term; + } + YarrOp& lastOp = m_ops.last(); + ASSERT(lastOp.m_op == OpSimpleNestedAlternativeNext); + lastOp.m_op = OpSimpleNestedAlternativeEnd; + lastOp.m_alternative = 0; + lastOp.m_nextOp = notFound; + + size_t parenEnd = m_ops.size(); + m_ops.append(OpParentheticalAssertionEnd); + + m_ops[parenBegin].m_term = term; + m_ops[parenBegin].m_previousOp = notFound; + m_ops[parenBegin].m_nextOp = parenEnd; + m_ops[parenEnd].m_term = term; + m_ops[parenEnd].m_previousOp = parenBegin; + m_ops[parenEnd].m_nextOp = notFound; + } + + // opCompileAlternative + // Called to emit nodes for all terms in an alternative. + void opCompileAlternative(PatternAlternative* alternative) + { + optimizeAlternative(alternative); + + for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { + PatternTerm* term = &alternative->m_terms[i]; + + switch (term->type) { + case PatternTerm::TypeParenthesesSubpattern: + opCompileParenthesesSubpattern(term); + break; + + case PatternTerm::TypeParentheticalAssertion: + opCompileParentheticalAssertion(term); + break; + + default: + m_ops.append(term); + } + } + } + + // opCompileBody + // This method compiles the body disjunction of the regular expression. + // The body consists of two sets of alternatives - zero or more 'once + // through' (BOL anchored) alternatives, followed by zero or more + // repeated alternatives. + // For each of these two sets of alteratives, if not empty they will be + // wrapped in a set of OpBodyAlternativeBegin/Next/End nodes (with the + // 'begin' node referencing the first alternative, and 'next' nodes + // referencing any further alternatives. The begin/next/end nodes are + // linked together in a doubly linked list. In the case of repeating + // alternatives, the end node is also linked back to the beginning. + // If no repeating alternatives exist, then a OpMatchFailed node exists + // to return the failing result. + void opCompileBody(PatternDisjunction* disjunction) + { + Vector& alternatives = disjunction->m_alternatives; + size_t currentAlternativeIndex = 0; + + // Emit the 'once through' alternatives. + if (alternatives.size() && alternatives[0]->onceThrough()) { + m_ops.append(YarrOp(OpBodyAlternativeBegin)); + m_ops.last().m_previousOp = notFound; + + do { + size_t lastOpIndex = m_ops.size() - 1; + PatternAlternative* alternative = alternatives[currentAlternativeIndex]; + opCompileAlternative(alternative); + + size_t thisOpIndex = m_ops.size(); + m_ops.append(YarrOp(OpBodyAlternativeNext)); + + YarrOp& lastOp = m_ops[lastOpIndex]; + YarrOp& thisOp = m_ops[thisOpIndex]; + + lastOp.m_alternative = alternative; + lastOp.m_nextOp = thisOpIndex; + thisOp.m_previousOp = lastOpIndex; + + ++currentAlternativeIndex; + } while (currentAlternativeIndex < alternatives.size() && alternatives[currentAlternativeIndex]->onceThrough()); + + YarrOp& lastOp = m_ops.last(); + + ASSERT(lastOp.m_op == OpBodyAlternativeNext); + lastOp.m_op = OpBodyAlternativeEnd; + lastOp.m_alternative = 0; + lastOp.m_nextOp = notFound; + } + + if (currentAlternativeIndex == alternatives.size()) { + m_ops.append(YarrOp(OpMatchFailed)); + return; + } + + // Emit the repeated alternatives. + size_t repeatLoop = m_ops.size(); + m_ops.append(YarrOp(OpBodyAlternativeBegin)); + m_ops.last().m_previousOp = notFound; + do { + size_t lastOpIndex = m_ops.size() - 1; + PatternAlternative* alternative = alternatives[currentAlternativeIndex]; + ASSERT(!alternative->onceThrough()); + opCompileAlternative(alternative); + + size_t thisOpIndex = m_ops.size(); + m_ops.append(YarrOp(OpBodyAlternativeNext)); + + YarrOp& lastOp = m_ops[lastOpIndex]; + YarrOp& thisOp = m_ops[thisOpIndex]; + + lastOp.m_alternative = alternative; + lastOp.m_nextOp = thisOpIndex; + thisOp.m_previousOp = lastOpIndex; + + ++currentAlternativeIndex; + } while (currentAlternativeIndex < alternatives.size()); + YarrOp& lastOp = m_ops.last(); + ASSERT(lastOp.m_op == OpBodyAlternativeNext); + lastOp.m_op = OpBodyAlternativeEnd; + lastOp.m_alternative = 0; + lastOp.m_nextOp = repeatLoop; + } + + void generateEnter() + { +#if WTF_CPU_X86_64 + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + push(X86Registers::ebx); +#elif WTF_CPU_X86 + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + // TODO: do we need spill registers to fill the output pointer if there are no sub captures? + push(X86Registers::ebx); + push(X86Registers::edi); + push(X86Registers::esi); + // load output into edi (2 = saved ebp + return address). + #if WTF_COMPILER_MSVC + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); + loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); + loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); + loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); + #else + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); + #endif +#elif WTF_CPU_ARM + push(ARMRegisters::r4); + push(ARMRegisters::r5); + push(ARMRegisters::r6); +#if WTF_CPU_ARM_TRADITIONAL + push(ARMRegisters::r8); // scratch register +#endif + move(ARMRegisters::r3, output); +#elif WTF_CPU_SH4 + push(SH4Registers::r11); + push(SH4Registers::r13); +#elif WTF_CPU_MIPS + // Do nothing. +#endif + } + + void generateReturn() + { +#if WTF_CPU_X86_64 + pop(X86Registers::ebx); + pop(X86Registers::ebp); +#elif WTF_CPU_X86 + pop(X86Registers::esi); + pop(X86Registers::edi); + pop(X86Registers::ebx); + pop(X86Registers::ebp); +#elif WTF_CPU_ARM +#if WTF_CPU_ARM_TRADITIONAL + pop(ARMRegisters::r8); // scratch register +#endif + pop(ARMRegisters::r6); + pop(ARMRegisters::r5); + pop(ARMRegisters::r4); +#elif WTF_CPU_SH4 + pop(SH4Registers::r13); + pop(SH4Registers::r11); +#elif WTF_CPU_MIPS + // Do nothing +#endif + ret(); + } + +public: + YarrGenerator(YarrPattern& pattern) + : m_pattern(pattern) + , m_shouldFallBack(false) + , m_checked(0) + { + } + + void compile(JSGlobalData* globalData, YarrCodeBlock& jitObject) + { + generateEnter(); + + if (!m_pattern.m_body->m_hasFixedSize) + store32(index, Address(output)); + + if (m_pattern.m_body->m_callFrameSize) + subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + // Compile the pattern to the internal 'YarrOp' representation. + opCompileBody(m_pattern.m_body); + + // If we encountered anything we can't handle in the JIT code + // (e.g. backreferences) then return early. + if (m_shouldFallBack) { + jitObject.setFallBack(true); + return; + } + + generate(); + backtrack(); + + // Link & finalize the code. + // XXX yarr-oom + ExecutablePool *pool; + bool ok; + LinkBuffer linkBuffer(this, globalData->regexAllocator, &pool, &ok); + m_backtrackingState.linkDataLabels(linkBuffer); + jitObject.set(linkBuffer.finalizeCode()); + jitObject.setFallBack(m_shouldFallBack); + } + +private: + YarrPattern& m_pattern; + + // Used to detect regular expression constructs that are not currently + // supported in the JIT; fall back to the interpreter when this is detected. + bool m_shouldFallBack; + + // The regular expression expressed as a linear sequence of operations. + Vector m_ops; + + // This records the current input offset being applied due to the current + // set of alternatives we are nested within. E.g. when matching the + // character 'b' within the regular expression /abc/, we will know that + // the minimum size for the alternative is 3, checked upon entry to the + // alternative, and that 'b' is at offset 1 from the start, and as such + // when matching 'b' we need to apply an offset of -2 to the load. + // + // FIXME: This should go away. Rather than tracking this value throughout + // code generation, we should gather this information up front & store it + // on the YarrOp structure. + int m_checked; + + // This class records state whilst generating the backtracking path of code. + BacktrackingState m_backtrackingState; +}; + +void jitCompile(YarrPattern& pattern, JSGlobalData* globalData, YarrCodeBlock& jitObject) +{ + YarrGenerator(pattern).compile(globalData, jitObject); +} + +int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output) +{ + return jitObject.execute(input, start, length, output); +} + +}} + +#endif diff --git a/js/src/yarr/YarrJIT.h b/js/src/yarr/YarrJIT.h new file mode 100644 index 000000000000..4f0f47f8c548 --- /dev/null +++ b/js/src/yarr/YarrJIT.h @@ -0,0 +1,93 @@ +/* -*- 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. + * + * 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. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef YarrJIT_h +#define YarrJIT_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_YARR_JIT + +#include "assembler/assembler/MacroAssembler.h" +#include "YarrPattern.h" + +#if WTF_CPU_X86 && !WTF_COMPILER_MSVC +#define YARR_CALL __attribute__ ((regparm (3))) +#else +#define YARR_CALL +#endif + +namespace JSC { + +class JSGlobalData; +class ExecutablePool; + +namespace Yarr { + +class YarrCodeBlock { + typedef int (*YarrJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; + +public: + YarrCodeBlock() + : m_needFallBack(false) + { + } + + ~YarrCodeBlock() + { + } + + void setFallBack(bool fallback) { m_needFallBack = fallback; } + bool isFallBack() { return m_needFallBack; } + void set(MacroAssembler::CodeRef ref) { m_ref = ref; } + + int execute(const UChar* input, unsigned start, unsigned length, int* output) + { + return JS_EXTENSION((reinterpret_cast(m_ref.m_code.executableAddress()))(input, start, length, output)); + } + +#if ENABLE_REGEXP_TRACING + void *getAddr() { return m_ref.m_code.executableAddress(); } +#endif + + void release() { m_ref.release(); } + +private: + MacroAssembler::CodeRef m_ref; + bool m_needFallBack; +}; + +void jitCompile(YarrPattern&, JSGlobalData*, YarrCodeBlock& jitObject); +int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output); + +} } // namespace JSC::Yarr + +#endif + +#endif // YarrJIT_h diff --git a/js/src/yarr/yarr/RegexParser.h b/js/src/yarr/YarrParser.h similarity index 81% rename from js/src/yarr/yarr/RegexParser.h rename to js/src/yarr/YarrParser.h index 1ae2c2fd049b..f2b50dd867e3 100644 --- a/js/src/yarr/yarr/RegexParser.h +++ b/js/src/yarr/YarrParser.h @@ -1,4 +1,7 @@ -/* +/* -*- 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. * * Redistribution and use in source and binary forms, with or without @@ -21,18 +24,18 @@ * 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 RegexParser_h -#define RegexParser_h +#ifndef YarrParser_h +#define YarrParser_h -#include -#include -#include "yarr/jswtfbridge.h" -#include "yarr/yarr/RegexCommon.h" +#include "Yarr.h" namespace JSC { namespace Yarr { +#define REGEXP_ERROR_PREFIX "Invalid regular expression: " + enum BuiltInCharacterClassID { DigitClassID, SpaceClassID, @@ -45,7 +48,7 @@ template class Parser { private: template - friend int parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit); + friend ErrorCode parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit); /* * CharacterClassParserDelegate: @@ -61,10 +64,8 @@ private: CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err) : m_delegate(delegate) , m_err(err) - , m_state(empty) -#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 5 /* quell GCC overwarning */ - , m_character(0xFFFF) -#endif + , m_state(Empty) + , m_character(0) { } @@ -79,56 +80,62 @@ private: } /* - * atomPatternCharacterUnescaped(): + * atomPatternCharacter(): * - * This method is called directly from parseCharacterClass(), to report a new - * pattern character token. This method differs from atomPatternCharacter(), - * which will be called from parseEscape(), since a hypen provided via this - * method may be indicating a character range, but a hyphen parsed by - * parseEscape() cannot be interpreted as doing so. + * This method is called either from parseCharacterClass() (for an unescaped + * character in a character class), or from parseEscape(). In the former case + * the value true will be passed for the argument 'hyphenIsRange', and in this + * mode we will allow a hypen to be treated as indicating a range (i.e. /[a-z]/ + * is different to /[a\-z]/). */ - void atomPatternCharacterUnescaped(UChar ch) + void atomPatternCharacter(UChar ch, bool hyphenIsRange = false) { switch (m_state) { - case empty: - m_character = ch; - m_state = cachedCharacter; - break; + case AfterCharacterClass: + // Following a builtin character class we need look out for a hyphen. + // We're looking for invalid ranges, such as /[\d-x]/ or /[\d-\d]/. + // If we see a hyphen following a charater class then unlike usual + // we'll report it to the delegate immediately, and put ourself into + // a poisoned state. Any following calls to add another character or + // character class will result in an error. (A hypen following a + // character-class is itself valid, but only at the end of a regex). + if (hyphenIsRange && ch == '-') { + m_delegate.atomCharacterClassAtom('-'); + m_state = AfterCharacterClassHyphen; + return; + } + // Otherwise just fall through - cached character so treat this as Empty. - case cachedCharacter: - if (ch == '-') - m_state = cachedCharacterHyphen; + case Empty: + m_character = ch; + m_state = CachedCharacter; + return; + + case CachedCharacter: + if (hyphenIsRange && ch == '-') + m_state = CachedCharacterHyphen; else { m_delegate.atomCharacterClassAtom(m_character); m_character = ch; } - break; + return; - case cachedCharacterHyphen: - if (ch >= m_character) - m_delegate.atomCharacterClassRange(m_character, ch); - else + case CachedCharacterHyphen: + if (ch < m_character) { m_err = CharacterClassOutOfOrder; - m_state = empty; + return; + } + m_delegate.atomCharacterClassRange(m_character, ch); + m_state = Empty; + return; + + case AfterCharacterClassHyphen: + m_delegate.atomCharacterClassAtom(ch); + m_state = Empty; + return; } } - /* - * atomPatternCharacter(): - * - * Adds a pattern character, called by parseEscape(), as such will not - * interpret a hyphen as indicating a character range. - */ - void atomPatternCharacter(UChar ch) - { - // Flush if a character is already pending to prevent the - // hyphen from begin interpreted as indicating a range. - if((ch == '-') && (m_state == cachedCharacter)) - flush(); - - atomPatternCharacterUnescaped(ch); - } - /* * atomBuiltInCharacterClass(): * @@ -136,17 +143,28 @@ private: */ void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert) { - if (m_state == cachedCharacterHyphen) { - // If the RHS of a range does not contain exacly one character then a SyntaxError - // must be thrown. SpiderMonkey only errors out in the [c-\s] case as an extension. - // (This assumes none of the built in character classes contain a single - // character.) - m_err = CharacterClassRangeSingleChar; - m_state = empty; + switch (m_state) { + case CachedCharacter: + // Flush the currently cached character, then fall through. + m_delegate.atomCharacterClassAtom(m_character); + + case Empty: + case AfterCharacterClass: + m_state = AfterCharacterClass; + m_delegate.atomCharacterClassBuiltIn(classID, invert); + return; + + case CachedCharacterHyphen: + // Error! We have a range that looks like [x-\d]. We require + // the end of the range to be a single character. + m_err = CharacterClassInvalidRange; + return; + + case AfterCharacterClassHyphen: + m_delegate.atomCharacterClassBuiltIn(classID, invert); + m_state = Empty; return; } - flush(); - m_delegate.atomCharacterClassBuiltIn(classID, invert); } /* @@ -156,31 +174,29 @@ private: */ void end() { - flush(); + if (m_state == CachedCharacter) + m_delegate.atomCharacterClassAtom(m_character); + else if (m_state == CachedCharacterHyphen) { + m_delegate.atomCharacterClassAtom(m_character); + m_delegate.atomCharacterClassAtom('-'); + } m_delegate.atomCharacterClassEnd(); } // parseEscape() should never call these delegate methods when // invoked with inCharacterClass set. - void assertionWordBoundary(bool) { JS_NOT_REACHED("parseEscape() should never call this"); } - void atomBackReference(unsigned) { JS_NOT_REACHED("parseEscape() should never call this"); } + void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); } + void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); } private: - void flush() - { - if (m_state != empty) // either cachedCharacter or cachedCharacterHyphen - m_delegate.atomCharacterClassAtom(m_character); - if (m_state == cachedCharacterHyphen) - m_delegate.atomCharacterClassAtom('-'); - m_state = empty; - } - Delegate& m_delegate; ErrorCode& m_err; enum CharacterClassConstructionState { - empty, - cachedCharacter, - cachedCharacterHyphen + Empty, + CachedCharacter, + CachedCharacterHyphen, + AfterCharacterClass, + AfterCharacterClassHyphen } m_state; UChar m_character; }; @@ -189,7 +205,7 @@ private: : m_delegate(delegate) , m_backReferenceLimit(backReferenceLimit) , m_err(NoError) - , m_data(const_cast(pattern).chars()) + , m_data(pattern.chars()) , m_size(pattern.length()) , m_index(0) , m_parenthesesNestingDepth(0) @@ -219,8 +235,8 @@ private: template bool parseEscape(EscapeDelegate& delegate) { - JS_ASSERT(!m_err); - JS_ASSERT(peek() == '\\'); + ASSERT(!m_err); + ASSERT(peek() == '\\'); consume(); if (atEndOfPattern()) { @@ -292,7 +308,7 @@ private: unsigned backReference; if (!consumeNumber(backReference)) - return false; + break; if (backReference <= m_backReferenceLimit) { delegate.atomBackReference(backReference); break; @@ -402,14 +418,14 @@ private: /* * parseCharacterClass(): * - * Helper for parseTokens(); calls directly and indirectly (via parseCharacterClassEscape) + * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape) * to an instance of CharacterClassParserDelegate, to describe the character class to the * delegate. */ void parseCharacterClass() { - JS_ASSERT(!m_err); - JS_ASSERT(peek() == '['); + ASSERT(!m_err); + ASSERT(peek() == '['); consume(); CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err); @@ -428,7 +444,7 @@ private: break; default: - characterClassConstructor.atomPatternCharacterUnescaped(consume()); + characterClassConstructor.atomPatternCharacter(consume(), true); } if (m_err) @@ -445,8 +461,8 @@ private: */ void parseParenthesesBegin() { - JS_ASSERT(!m_err); - JS_ASSERT(peek() == '('); + ASSERT(!m_err); + ASSERT(peek() == '('); consume(); if (tryConsume('?')) { @@ -484,8 +500,8 @@ private: */ void parseParenthesesEnd() { - JS_ASSERT(!m_err); - JS_ASSERT(peek() == ')'); + ASSERT(!m_err); + ASSERT(peek() == ')'); consume(); if (m_parenthesesNestingDepth > 0) @@ -503,8 +519,8 @@ private: */ void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max) { - JS_ASSERT(!m_err); - JS_ASSERT(min <= max); + ASSERT(!m_err); + ASSERT(min <= max); if (lastTokenWasAnAtom) m_delegate.quantifyAtom(min, max, !tryConsume('?')); @@ -572,13 +588,13 @@ private: case '*': consume(); - parseQuantifier(lastTokenWasAnAtom, 0, UINT_MAX); + parseQuantifier(lastTokenWasAnAtom, 0, quantifyInfinite); lastTokenWasAnAtom = false; break; case '+': consume(); - parseQuantifier(lastTokenWasAnAtom, 1, UINT_MAX); + parseQuantifier(lastTokenWasAnAtom, 1, quantifyInfinite); lastTokenWasAnAtom = false; break; @@ -603,7 +619,7 @@ private: if (!consumeNumber(max)) break; } else { - max = UINT_MAX; + max = quantifyInfinite; } } @@ -636,26 +652,18 @@ private: /* * parse(): * - * This method calls regexBegin(), calls parseTokens() to parse over the input - * patterns, calls regexEnd() or regexError() as appropriate, and converts any + * This method calls parseTokens() to parse over the input and converts any * error code to a const char* for a result. */ - int parse() + ErrorCode parse() { - m_delegate.regexBegin(); - if (m_size > MAX_PATTERN_SIZE) m_err = PatternTooLarge; else parseTokens(); - JS_ASSERT(atEndOfPattern() || m_err); + ASSERT(atEndOfPattern() || m_err); - if (m_err) - m_delegate.regexError(); - else - m_delegate.regexEnd(); - - return static_cast(m_err); + return m_err; } @@ -675,13 +683,13 @@ private: bool atEndOfPattern() { - JS_ASSERT(m_index <= m_size); + ASSERT(m_index <= m_size); return m_index == m_size; } int peek() { - JS_ASSERT(m_index < m_size); + ASSERT(m_index < m_size); return m_data[m_index]; } @@ -692,40 +700,40 @@ private: unsigned peekDigit() { - JS_ASSERT(peekIsDigit()); + ASSERT(peekIsDigit()); return peek() - '0'; } int consume() { - JS_ASSERT(m_index < m_size); + ASSERT(m_index < m_size); return m_data[m_index++]; } unsigned consumeDigit() { - JS_ASSERT(peekIsDigit()); + ASSERT(peekIsDigit()); return consume() - '0'; } - bool consumeNumber(unsigned &accum) - { - accum = consumeDigit(); - while (peekIsDigit()) { - unsigned newValue = accum * 10 + peekDigit(); - if (newValue < accum) { /* Overflow check. */ - m_err = QuantifierTooLarge; - return false; - } - accum = newValue; - consume(); - } - return true; + bool consumeNumber(unsigned &accum) + { + accum = consumeDigit(); + while (peekIsDigit()) { + unsigned newValue = accum * 10 + peekDigit(); + if (newValue < accum) { /* Overflow check. */ + m_err = QuantifierTooLarge; + return false; + } + accum = newValue; + consume(); + } + return true; } unsigned consumeOctal() { - JS_ASSERT(WTF::isASCIIOctalDigit(peek())); + ASSERT(WTF::isASCIIOctalDigit(peek())); unsigned n = consumeDigit(); while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek())) @@ -798,14 +806,6 @@ private: * * void disjunction(); * - * void regexBegin(); - * void regexEnd(); - * void regexError(); - * - * Before any call recording tokens are made, regexBegin() will be called on the - * delegate once. Once parsing is complete either regexEnd() or regexError() will - * be called, as appropriate. - * * The regular expression is described by a sequence of assertion*() and atom*() * callbacks to the delegate, describing the terms in the regular expression. * Following an atom a quantifyAtom() call may occur to indicate that the previous @@ -836,11 +836,11 @@ private: */ template -int parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = UINT_MAX) +ErrorCode parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = quantifyInfinite) { return Parser(delegate, pattern, backReferenceLimit).parse(); } } } // namespace JSC::Yarr -#endif // RegexParser_h +#endif // YarrParser_h diff --git a/js/src/yarr/yarr/RegexCompiler.cpp b/js/src/yarr/YarrPattern.cpp similarity index 52% rename from js/src/yarr/yarr/RegexCompiler.cpp rename to js/src/yarr/YarrPattern.cpp index 9b60cbd4a78b..10b7d8911987 100644 --- a/js/src/yarr/yarr/RegexCompiler.cpp +++ b/js/src/yarr/YarrPattern.cpp @@ -1,5 +1,9 @@ -/* +/* -*- 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 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -21,12 +25,13 @@ * 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 ***** */ -#include "jsinttypes.h" -#include "RegexCompiler.h" +#include "YarrPattern.h" -#include "RegexPattern.h" +#include "Yarr.h" +#include "YarrParser.h" using namespace WTF; @@ -34,12 +39,6 @@ namespace JSC { namespace Yarr { #include "RegExpJitTables.h" -#if WTF_CPU_SPARC -#define BASE_FRAME_SIZE 24 -#else -#define BASE_FRAME_SIZE 0 -#endif - class CharacterClassConstructor { public: CharacterClassConstructor(bool isCaseInsensitive = false) @@ -57,13 +56,13 @@ public: void append(const CharacterClass* other) { - for (size_t i = 0; i < other->m_matches.length(); ++i) + for (size_t i = 0; i < other->m_matches.size(); ++i) addSorted(m_matches, other->m_matches[i]); - for (size_t i = 0; i < other->m_ranges.length(); ++i) + for (size_t i = 0; i < other->m_ranges.size(); ++i) addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end); - for (size_t i = 0; i < other->m_matchesUnicode.length(); ++i) + for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i) addSorted(m_matchesUnicode, other->m_matchesUnicode[i]); - for (size_t i = 0; i < other->m_rangesUnicode.length(); ++i) + for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i) addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end); } @@ -101,18 +100,18 @@ public: { if (lo <= 0x7f) { char asciiLo = lo; - char asciiHi = JS_MIN(hi, (UChar)0x7f); + char asciiHi = std::min(hi, (UChar)0x7f); addSortedRange(m_ranges, lo, asciiHi); if (m_isCaseInsensitive) { if ((asciiLo <= 'Z') && (asciiHi >= 'A')) - addSortedRange(m_ranges, JS_MAX(asciiLo, 'A')+('a'-'A'), JS_MIN(asciiHi, 'Z')+('a'-'A')); + addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A')); if ((asciiLo <= 'z') && (asciiHi >= 'a')) - addSortedRange(m_ranges, JS_MAX(asciiLo, 'a')+('A'-'a'), JS_MIN(asciiHi, 'z')+('A'-'a')); + addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a')); } } if (hi >= 0x80) { - uint32 unicodeCurr = JS_MAX(lo, (UChar)0x80); + uint32_t unicodeCurr = std::max(lo, (UChar)0x80); addSortedRange(m_rangesUnicode, unicodeCurr, hi); if (m_isCaseInsensitive) { @@ -122,7 +121,7 @@ public: // (if so we won't re-enter the loop, since the loop condition above // will definitely fail) - but this does mean we cannot use a UChar // to represent unicodeCurr, we must use a 32-bit value instead. - JS_ASSERT(unicodeCurr <= 0xffff); + ASSERT(unicodeCurr <= 0xffff); if (isUnicodeUpper(unicodeCurr)) { UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr); @@ -145,8 +144,7 @@ public: CharacterClass* charClass() { - // FIXME: bug 574459 -- no NULL check - CharacterClass* characterClass = js::OffTheBooks::new_((CharacterClassTable*)NULL); + CharacterClass* characterClass = js::OffTheBooks::new_(PassRefPtr(0)); characterClass->m_matches.append(m_matches); characterClass->m_ranges.append(m_ranges); @@ -159,12 +157,10 @@ public: } private: - typedef js::Vector UChars; - typedef js::Vector CharacterRanges; - void addSorted(UChars& matches, UChar ch) + void addSorted(Vector& matches, UChar ch) { unsigned pos = 0; - unsigned range = matches.length(); + unsigned range = matches.size(); // binary chop, find position to insert char. while (range) { @@ -181,15 +177,15 @@ private: } } - if (pos == matches.length()) + if (pos == matches.size()) matches.append(ch); else - matches.insert(matches.begin() + pos, ch); + matches.insert(pos, ch); } - void addSortedRange(CharacterRanges& ranges, UChar lo, UChar hi) + void addSortedRange(Vector& ranges, UChar lo, UChar hi) { - unsigned end = ranges.length(); + unsigned end = ranges.size(); // Simple linear scan - I doubt there are that many ranges anyway... // feel free to fix this with something faster (eg binary chop). @@ -201,7 +197,7 @@ private: ranges[i].begin = lo; return; } - ranges.insert(ranges.begin() + i, CharacterRange(lo, hi)); + ranges.insert(i, CharacterRange(lo, hi)); return; } // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining @@ -209,17 +205,17 @@ private: // end of the last range they concatenate, which is just as good. if (lo <= (ranges[i].end + 1)) { // found an intersect! we'll replace this entry in the array. - ranges[i].begin = JS_MIN(ranges[i].begin, lo); - ranges[i].end = JS_MAX(ranges[i].end, hi); + ranges[i].begin = std::min(ranges[i].begin, lo); + ranges[i].end = std::max(ranges[i].end, hi); // now check if the new range can subsume any subsequent ranges. unsigned next = i+1; // each iteration of the loop we will either remove something from the list, or break the loop. - while (next < ranges.length()) { + while (next < ranges.size()) { if (ranges[next].begin <= (ranges[i].end + 1)) { // the next entry now overlaps / concatenates this one. - ranges[i].end = JS_MAX(ranges[i].end, ranges[next].end); - ranges.erase(ranges.begin() + next); + ranges[i].end = std::max(ranges[i].end, ranges[next].end); + ranges.remove(next); } else break; } @@ -234,21 +230,131 @@ private: bool m_isCaseInsensitive; - UChars m_matches; - CharacterRanges m_ranges; - UChars m_matchesUnicode; - CharacterRanges m_rangesUnicode; + Vector m_matches; + Vector m_ranges; + Vector m_matchesUnicode; + Vector m_rangesUnicode; }; -class RegexPatternConstructor { -public: - RegexPatternConstructor(RegexPattern& pattern) - : m_pattern(pattern) - , m_characterClassConstructor(pattern.m_ignoreCase) +struct BeginCharHelper { + BeginCharHelper(Vector* beginChars, bool isCaseInsensitive = false) + : m_beginChars(beginChars) + , m_isCaseInsensitive(isCaseInsensitive) + {} + + void addBeginChar(BeginChar beginChar, Vector* hotTerms, QuantifierType quantityType, unsigned quantityCount) { + if (quantityType == QuantifierFixedCount && quantityCount > 1) { + // We duplicate the first found character if the quantity of the term is more than one. eg.: /a{3}/ + beginChar.value |= beginChar.value << 16; + beginChar.mask |= beginChar.mask << 16; + addCharacter(beginChar); + } else if (quantityType == QuantifierFixedCount && quantityCount == 1 && hotTerms->size()) + // In case of characters with fixed quantifier we should check the next character as well. + linkHotTerms(beginChar, hotTerms); + else + // In case of greedy matching the next character checking is unnecessary therefore we just store + // the first character. + addCharacter(beginChar); } - ~RegexPatternConstructor() + // Merge two following BeginChars in the vector to reduce the number of character checks. + void merge(unsigned size) + { + for (unsigned i = 0; i < size; i++) { + BeginChar* curr = &m_beginChars->at(i); + BeginChar* next = &m_beginChars->at(i + 1); + + // If the current and the next size of value is different we should skip the merge process + // because the 16bit and 32bit values are unmergable. + if (curr->value <= 0xFFFF && next->value > 0xFFFF) + continue; + + unsigned diff = curr->value ^ next->value; + + curr->mask |= diff; + curr->value |= curr->mask; + + m_beginChars->remove(i + 1); + size--; + } + } + +private: + void addCharacter(BeginChar beginChar) + { + unsigned pos = 0; + unsigned range = m_beginChars->size(); + + // binary chop, find position to insert char. + while (range) { + unsigned index = range >> 1; + + int val = m_beginChars->at(pos+index).value - beginChar.value; + if (!val) + return; + if (val < 0) + range = index; + else { + pos += (index+1); + range -= (index+1); + } + } + + if (pos == m_beginChars->size()) + m_beginChars->append(beginChar); + else + m_beginChars->insert(pos, beginChar); + } + + // Create BeginChar objects by appending each terms from a hotTerms vector to an existing BeginChar object. + void linkHotTerms(BeginChar beginChar, Vector* hotTerms) + { + for (unsigned i = 0; i < hotTerms->size(); i++) { + PatternTerm hotTerm = hotTerms->at(i).term; + ASSERT(hotTerm.type == PatternTerm::TypePatternCharacter); + + UChar characterNext = hotTerm.patternCharacter; + + // Append a character to an existing BeginChar object. + if (characterNext <= 0x7f) { + unsigned mask = 0; + + if (m_isCaseInsensitive && isASCIIAlpha(characterNext)) { + mask = 32; + characterNext = toASCIILower(characterNext); + } + + addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask | (mask << 16))); + } else { + UChar upper, lower; + if (m_isCaseInsensitive && ((upper = Unicode::toUpper(characterNext)) != (lower = Unicode::toLower(characterNext)))) { + addCharacter(BeginChar(beginChar.value | (upper << 16), beginChar.mask)); + addCharacter(BeginChar(beginChar.value | (lower << 16), beginChar.mask)); + } else + addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask)); + } + } + } + + Vector* m_beginChars; + bool m_isCaseInsensitive; +}; + +class YarrPatternConstructor { +public: + YarrPatternConstructor(YarrPattern& pattern) + : m_pattern(pattern) + , m_characterClassConstructor(pattern.m_ignoreCase) + , m_beginCharHelper(&pattern.m_beginChars, pattern.m_ignoreCase) + , m_invertParentheticalAssertion(false) + { + m_pattern.m_body = js::OffTheBooks::new_(); + m_alternative = m_pattern.m_body->addNewAlternative(); + m_pattern.m_disjunctions.append(m_pattern.m_body); + } + + ~YarrPatternConstructor() { } @@ -256,10 +362,19 @@ public: { m_pattern.reset(); m_characterClassConstructor.reset(); + + m_pattern.m_body = js::OffTheBooks::new_(); + m_alternative = m_pattern.m_body->addNewAlternative(); + m_pattern.m_disjunctions.append(m_pattern.m_body); } void assertionBOL() { + if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) { + m_alternative->m_startsWithBOL = true; + m_alternative->m_containsBOL = true; + m_pattern.m_containsBOL = true; + } m_alternative->m_terms.append(PatternTerm::BOL()); } void assertionEOL() @@ -318,7 +433,7 @@ public: void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert) { - JS_ASSERT(classID != NewlineClassID); + ASSERT(classID != NewlineClassID); switch (classID) { case DigitClassID: @@ -334,7 +449,7 @@ public: break; default: - JS_NOT_REACHED("Invalid character class."); + ASSERT_NOT_REACHED(); } } @@ -351,36 +466,56 @@ public: if (capture) m_pattern.m_numSubpatterns++; - // FIXME: bug 574459 -- no NULL check PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative); m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture)); + m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, false)); m_alternative = parenthesesDisjunction->addNewAlternative(); } void atomParentheticalAssertionBegin(bool invert = false) { - // FIXME: bug 574459 -- no NULL check PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative); m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert)); + m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, false, invert)); m_alternative = parenthesesDisjunction->addNewAlternative(); + m_invertParentheticalAssertion = invert; } void atomParenthesesEnd() { - JS_ASSERT(m_alternative->m_parent); - JS_ASSERT(m_alternative->m_parent->m_parent); + ASSERT(m_alternative->m_parent); + ASSERT(m_alternative->m_parent->m_parent); + + PatternDisjunction* parenthesesDisjunction = m_alternative->m_parent; m_alternative = m_alternative->m_parent->m_parent; - - m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; + + PatternTerm& lastTerm = m_alternative->lastTerm(); + + unsigned numParenAlternatives = parenthesesDisjunction->m_alternatives.size(); + unsigned numBOLAnchoredAlts = 0; + + for (unsigned i = 0; i < numParenAlternatives; i++) { + // Bubble up BOL flags + if (parenthesesDisjunction->m_alternatives[i]->m_startsWithBOL) + numBOLAnchoredAlts++; + } + + if (numBOLAnchoredAlts) { + m_alternative->m_containsBOL = true; + // If all the alternatives in parens start with BOL, then so does this one + if (numBOLAnchoredAlts == numParenAlternatives) + m_alternative->m_startsWithBOL = true; + } + + lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; + m_invertParentheticalAssertion = false; } void atomBackReference(unsigned subpatternId) { - JS_ASSERT(subpatternId); + ASSERT(subpatternId); m_pattern.m_containsBackreferences = true; - m_pattern.m_maxBackReference = JS_MAX(m_pattern.m_maxBackReference, subpatternId); + m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId); if (subpatternId > m_pattern.m_numSubpatterns) { m_alternative->m_terms.append(PatternTerm::ForwardReference()); @@ -388,14 +523,14 @@ public: } PatternAlternative* currentAlternative = m_alternative; - JS_ASSERT(currentAlternative); + ASSERT(currentAlternative); // Note to self: if we waited until the AST was baked, we could also remove forwards refs while ((currentAlternative = currentAlternative->m_parent->m_parent)) { PatternTerm& term = currentAlternative->lastTerm(); - JS_ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); + ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); - if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) { + if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.capture() && (subpatternId == term.parentheses.subpatternId)) { m_alternative->m_terms.append(PatternTerm::ForwardReference()); return; } @@ -404,37 +539,43 @@ public: m_alternative->m_terms.append(PatternTerm(subpatternId)); } - PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction) + // deep copy the argument disjunction. If filterStartsWithBOL is true, + // skip alternatives with m_startsWithBOL set true. + PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false) { - // FIXME: bug 574459 -- no NULL check - PatternDisjunction* newDisjunction = js::OffTheBooks::new_(); - - newDisjunction->m_parent = disjunction->m_parent; - for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) { + PatternDisjunction* newDisjunction = 0; + for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { PatternAlternative* alternative = disjunction->m_alternatives[alt]; - PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); - for (unsigned i = 0; i < alternative->m_terms.length(); ++i) - newAlternative->m_terms.append(copyTerm(alternative->m_terms[i])); + if (!filterStartsWithBOL || !alternative->m_startsWithBOL) { + if (!newDisjunction) { + newDisjunction = new PatternDisjunction(); + newDisjunction->m_parent = disjunction->m_parent; + } + PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); + for (unsigned i = 0; i < alternative->m_terms.size(); ++i) + newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL)); + } } - - m_pattern.m_disjunctions.append(newDisjunction); + + if (newDisjunction) + m_pattern.m_disjunctions.append(newDisjunction); return newDisjunction; } - - PatternTerm copyTerm(PatternTerm& term) + + PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false) { if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion)) return PatternTerm(term); - + PatternTerm termCopy = term; - termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction); + termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL); return termCopy; } - + void quantifyAtom(unsigned min, unsigned max, bool greedy) { - JS_ASSERT(min <= max); - JS_ASSERT(m_alternative->m_terms.length()); + ASSERT(min <= max); + ASSERT(m_alternative->m_terms.size()); if (!max) { m_alternative->removeLastTerm(); @@ -442,8 +583,8 @@ public: } PatternTerm& term = m_alternative->lastTerm(); - JS_ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); - JS_ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); + ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); + ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); // For any assertion with a zero minimum, not matching is valid and has no effect, // remove it. Otherwise, we need to match as least once, but there is no point @@ -464,7 +605,7 @@ public: term.quantify(min, QuantifierFixedCount); m_alternative->m_terms.append(copyTerm(term)); // NOTE: this term is interesting from an analysis perspective, in that it can be ignored..... - m_alternative->lastTerm().quantify((max == UINT_MAX) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); + m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern) m_alternative->lastTerm().parentheses.isCopy = true; } @@ -475,26 +616,12 @@ public: m_alternative = m_alternative->m_parent->addNewAlternative(); } - void regexBegin() - { - // FIXME: bug 574459 -- no NULL check - m_pattern.m_body = js::OffTheBooks::new_(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); - } - void regexEnd() - { - } - void regexError() - { - } - unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition) { alternative->m_hasFixedSize = true; unsigned currentInputPosition = initialInputPosition; - for (unsigned i = 0; i < alternative->m_terms.length(); ++i) { + for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { PatternTerm& term = alternative->m_terms[i]; switch (term.type) { @@ -507,7 +634,7 @@ public: case PatternTerm::TypeBackReference: term.inputPosition = currentInputPosition; term.frameLocation = currentCallFrameSize; - currentCallFrameSize += RegexStackSpaceForBackTrackInfoBackReference; + currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference; alternative->m_hasFixedSize = false; break; @@ -518,7 +645,7 @@ public: term.inputPosition = currentInputPosition; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; - currentCallFrameSize += RegexStackSpaceForBackTrackInfoPatternCharacter; + currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter; alternative->m_hasFixedSize = false; } else currentInputPosition += term.quantityCount; @@ -528,7 +655,7 @@ public: term.inputPosition = currentInputPosition; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; - currentCallFrameSize += RegexStackSpaceForBackTrackInfoCharacterClass; + currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass; alternative->m_hasFixedSize = false; } else currentInputPosition += term.quantityCount; @@ -539,20 +666,20 @@ public: term.frameLocation = currentCallFrameSize; if (term.quantityCount == 1 && !term.parentheses.isCopy) { if (term.quantityType != QuantifierFixedCount) - currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesOnce; + currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce; currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition); // If quantity is fixed, then pre-check its minimum size. if (term.quantityType == QuantifierFixedCount) currentInputPosition += term.parentheses.disjunction->m_minimumSize; term.inputPosition = currentInputPosition; } else if (term.parentheses.isTerminal) { - currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesTerminal; + currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal; currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition); term.inputPosition = currentInputPosition; } else { term.inputPosition = currentInputPosition; setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition); - currentCallFrameSize += RegexStackSpaceForBackTrackInfoParentheses; + currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses; } // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length. alternative->m_hasFixedSize = false; @@ -561,7 +688,7 @@ public: case PatternTerm::TypeParentheticalAssertion: term.inputPosition = currentInputPosition; term.frameLocation = currentCallFrameSize; - currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + RegexStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition); + currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition); break; } } @@ -572,23 +699,23 @@ public: unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition) { - if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.length() > 1)) - initialCallFrameSize += RegexStackSpaceForBackTrackInfoAlternative; + if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1)) + initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative; unsigned minimumInputSize = UINT_MAX; unsigned maximumCallFrameSize = 0; bool hasFixedSize = true; - for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) { + for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { PatternAlternative* alternative = disjunction->m_alternatives[alt]; unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition); - minimumInputSize = JS_MIN(minimumInputSize, alternative->m_minimumSize); - maximumCallFrameSize = JS_MAX(maximumCallFrameSize, currentAlternativeCallFrameSize); + minimumInputSize = std::min(minimumInputSize, alternative->m_minimumSize); + maximumCallFrameSize = std::max(maximumCallFrameSize, currentAlternativeCallFrameSize); hasFixedSize &= alternative->m_hasFixedSize; } - JS_ASSERT(minimumInputSize != UINT_MAX); - JS_ASSERT(maximumCallFrameSize >= initialCallFrameSize); + ASSERT(minimumInputSize != UINT_MAX); + ASSERT(maximumCallFrameSize >= initialCallFrameSize); disjunction->m_hasFixedSize = hasFixedSize; disjunction->m_minimumSize = minimumInputSize; @@ -598,13 +725,14 @@ public: void setupOffsets() { - setupDisjunctionOffsets(m_pattern.m_body, BASE_FRAME_SIZE, 0); + setupDisjunctionOffsets(m_pattern.m_body, 0, 0); } // This optimization identifies sets of parentheses that we will never need to backtrack. // In these cases we do not need to store state from prior iterations. // We can presently avoid backtracking for: - // * a set of parens at the end of the regular expression (last term in any of the alternatives of the main body disjunction). + // * where the parens are at the end of the regular expression (last term in any of the + // alternatives of the main body disjunction). // * where the parens are non-capturing, and quantified unbounded greedy (*). // * where the parens do not contain any capturing subpatterns. void checkForTerminalParentheses() @@ -614,57 +742,239 @@ public: if (m_pattern.m_numSubpatterns) return; - js::Vector& alternatives = m_pattern.m_body->m_alternatives; - for (unsigned i =0; i < alternatives.length(); ++i) { - js::Vector& terms = alternatives[i]->m_terms; - if (terms.length()) { - PatternTerm& term = terms.back(); + Vector& alternatives = m_pattern.m_body->m_alternatives; + for (size_t i = 0; i < alternatives.size(); ++i) { + Vector& terms = alternatives[i]->m_terms; + if (terms.size()) { + PatternTerm& term = terms.last(); if (term.type == PatternTerm::TypeParenthesesSubpattern && term.quantityType == QuantifierGreedy - && term.quantityCount == UINT_MAX + && term.quantityCount == quantifyInfinite && !term.capture()) term.parentheses.isTerminal = true; } } } + void optimizeBOL() + { + // Look for expressions containing beginning of line (^) anchoring and unroll them. + // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops + // This code relies on the parsing code tagging alternatives with m_containsBOL and + // m_startsWithBOL and rolling those up to containing alternatives. + // At this point, this is only valid for non-multiline expressions. + PatternDisjunction* disjunction = m_pattern.m_body; + + if (!m_pattern.m_containsBOL || m_pattern.m_multiline) + return; + + PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true); + + // Set alternatives in disjunction to "onceThrough" + for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) + disjunction->m_alternatives[alt]->setOnceThrough(); + + if (loopDisjunction) { + // Move alternatives from loopDisjunction to disjunction + for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt) + disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]); + + loopDisjunction->m_alternatives.clear(); + } + } + + // This function collects the terms which are potentially matching the first number of depth characters in the result. + // If this function returns false then it found at least one term which makes the beginning character + // look-up optimization inefficient. + bool setupDisjunctionBeginTerms(PatternDisjunction* disjunction, Vector* beginTerms, unsigned depth) + { + for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + PatternAlternative* alternative = disjunction->m_alternatives[alt]; + + if (!setupAlternativeBeginTerms(alternative, beginTerms, 0, depth)) + return false; + } + + return true; + } + + bool setupAlternativeBeginTerms(PatternAlternative* alternative, Vector* beginTerms, unsigned termIndex, unsigned depth) + { + bool checkNext = true; + unsigned numTerms = alternative->m_terms.size(); + + while (checkNext && termIndex < numTerms) { + PatternTerm term = alternative->m_terms[termIndex]; + checkNext = false; + + switch (term.type) { + case PatternTerm::TypeAssertionBOL: + case PatternTerm::TypeAssertionEOL: + case PatternTerm::TypeAssertionWordBoundary: + return false; + + case PatternTerm::TypeBackReference: + case PatternTerm::TypeForwardReference: + return false; + + case PatternTerm::TypePatternCharacter: + if (termIndex != numTerms - 1) { + beginTerms->append(TermChain(term)); + termIndex++; + checkNext = true; + } else if (term.quantityType == QuantifierFixedCount) { + beginTerms->append(TermChain(term)); + if (depth < 2 && termIndex < numTerms - 1 && term.quantityCount == 1) + if (!setupAlternativeBeginTerms(alternative, &beginTerms->last().hotTerms, termIndex + 1, depth + 1)) + return false; + } + + break; + + case PatternTerm::TypeCharacterClass: + return false; + + case PatternTerm::TypeParentheticalAssertion: + if (term.invert()) + return false; + + case PatternTerm::TypeParenthesesSubpattern: + if (term.quantityType != QuantifierFixedCount) { + if (termIndex == numTerms - 1) + break; + + termIndex++; + checkNext = true; + } + + if (!setupDisjunctionBeginTerms(term.parentheses.disjunction, beginTerms, depth)) + return false; + + break; + } + } + + return true; + } + + void setupBeginChars() + { + Vector beginTerms; + bool containsFixedCharacter = false; + + if ((!m_pattern.m_body->m_hasFixedSize || m_pattern.m_body->m_alternatives.size() > 1) + && setupDisjunctionBeginTerms(m_pattern.m_body, &beginTerms, 0)) { + unsigned size = beginTerms.size(); + + // If we haven't collected any terms we should abort the preparation of beginning character look-up optimization. + if (!size) + return; + + m_pattern.m_containsBeginChars = true; + + for (unsigned i = 0; i < size; i++) { + PatternTerm term = beginTerms[i].term; + + // We have just collected PatternCharacter terms, other terms are not allowed. + ASSERT(term.type == PatternTerm::TypePatternCharacter); + + if (term.quantityType == QuantifierFixedCount) + containsFixedCharacter = true; + + UChar character = term.patternCharacter; + unsigned mask = 0; + + if (character <= 0x7f) { + if (m_pattern.m_ignoreCase && isASCIIAlpha(character)) { + mask = 32; + character = toASCIILower(character); + } + + m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); + } else { + UChar upper, lower; + if (m_pattern.m_ignoreCase && ((upper = Unicode::toUpper(character)) != (lower = Unicode::toLower(character)))) { + m_beginCharHelper.addBeginChar(BeginChar(upper, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); + m_beginCharHelper.addBeginChar(BeginChar(lower, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); + } else + m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); + } + } + + // If the pattern doesn't contain terms with fixed quantifiers then the beginning character look-up optimization is inefficient. + if (!containsFixedCharacter) { + m_pattern.m_containsBeginChars = false; + return; + } + + size = m_pattern.m_beginChars.size(); + + if (size > 2) + m_beginCharHelper.merge(size - 1); + else if (size <= 1) + m_pattern.m_containsBeginChars = false; + } + } + private: - RegexPattern& m_pattern; + YarrPattern& m_pattern; PatternAlternative* m_alternative; CharacterClassConstructor m_characterClassConstructor; + BeginCharHelper m_beginCharHelper; bool m_invertCharacterClass; + bool m_invertParentheticalAssertion; }; - -int compileRegex(const UString& patternString, RegexPattern& pattern) +ErrorCode YarrPattern::compile(const UString& patternString) { - RegexPatternConstructor constructor(pattern); + YarrPatternConstructor constructor(*this); - if (int error = parse(constructor, patternString)) + if (ErrorCode error = parse(constructor, patternString)) return error; // If the pattern contains illegal backreferences reset & reparse. // Quoting Netscape's "What's new in JavaScript 1.2", // "Note: if the number of left parentheses is less than the number specified // in \#, the \# is taken as an octal escape as described in the next row." - if (pattern.containsIllegalBackReference()) { - unsigned numSubpatterns = pattern.m_numSubpatterns; + if (containsIllegalBackReference()) { + unsigned numSubpatterns = m_numSubpatterns; constructor.reset(); -#ifdef DEBUG - int error = +#if !ASSERT_DISABLED + ErrorCode error = #endif parse(constructor, patternString, numSubpatterns); - JS_ASSERT(!error); - JS_ASSERT(numSubpatterns == pattern.m_numSubpatterns); + ASSERT(!error); + ASSERT(numSubpatterns == m_numSubpatterns); } constructor.checkForTerminalParentheses(); + constructor.optimizeBOL(); + constructor.setupOffsets(); + constructor.setupBeginChars(); - return 0; + return NoError; } +YarrPattern::YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error) + : m_ignoreCase(ignoreCase) + , m_multiline(multiline) + , m_containsBackreferences(false) + , m_containsBeginChars(false) + , m_containsBOL(false) + , m_numSubpatterns(0) + , m_maxBackReference(0) + , newlineCached(0) + , digitsCached(0) + , spacesCached(0) + , wordcharCached(0) + , nondigitsCached(0) + , nonspacesCached(0) + , nonwordcharCached(0) +{ + *error = compile(pattern); +} } } diff --git a/js/src/yarr/yarr/RegexPattern.h b/js/src/yarr/YarrPattern.h similarity index 70% rename from js/src/yarr/yarr/RegexPattern.h rename to js/src/yarr/YarrPattern.h index 9d9b286a653e..38ae10fcf289 100644 --- a/js/src/yarr/yarr/RegexPattern.h +++ b/js/src/yarr/YarrPattern.h @@ -1,5 +1,9 @@ -/* +/* -*- 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 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -21,26 +25,32 @@ * 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 RegexPattern_h -#define RegexPattern_h - -#include "jsvector.h" -#include "yarr/jswtfbridge.h" -#include "yarr/yarr/RegexCommon.h" +#ifndef YarrPattern_h +#define YarrPattern_h +#include "wtfbridge.h" +#include "ASCIICType.h" namespace JSC { namespace Yarr { -#define RegexStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers. -#define RegexStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers. -#define RegexStackSpaceForBackTrackInfoBackReference 2 -#define RegexStackSpaceForBackTrackInfoAlternative 1 // One per alternative. -#define RegexStackSpaceForBackTrackInfoParentheticalAssertion 1 -#define RegexStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers. -#define RegexStackSpaceForBackTrackInfoParenthesesTerminal 1 -#define RegexStackSpaceForBackTrackInfoParentheses 4 +enum ErrorCode { + NoError, + PatternTooLarge, + QuantifierOutOfOrder, + QuantifierWithoutAtom, + MissingParentheses, + ParenthesesUnmatched, + ParenthesesTypeInvalid, + CharacterClassUnmatched, + CharacterClassInvalidRange, + CharacterClassOutOfOrder, + EscapeUnterminated, + QuantifierTooLarge, + NumberOfErrorCodes +}; struct PatternDisjunction; @@ -55,60 +65,42 @@ struct CharacterRange { } }; -/* - * Wraps a table and indicates inversion. Can be efficiently borrowed - * between character classes, so it's refcounted. - */ -struct CharacterClassTable { - - JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; - +struct CharacterClassTable : RefCounted { + friend class js::OffTheBooks; const char* m_table; bool m_inverted; - jsrefcount m_refcount; - - /* Ownership transferred to caller. */ - static CharacterClassTable *create(const char* table, bool inverted) + static PassRefPtr create(const char* table, bool inverted) { - // FIXME: bug 574459 -- no NULL checks done by any of the callers, all - // of which are in RegExpJitTables.h. - return js::OffTheBooks::new_(table, inverted); + return adoptRef(js::OffTheBooks::new_(table, inverted)); } - void incref() { JS_ATOMIC_INCREMENT(&m_refcount); } - void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js::Foreground::delete_(this); } - private: CharacterClassTable(const char* table, bool inverted) : m_table(table) , m_inverted(inverted) - , m_refcount(0) { } }; struct CharacterClass { + WTF_MAKE_FAST_ALLOCATED +public: // All CharacterClass instances have to have the full set of matches and ranges, // they may have an optional table for faster lookups (which must match the // specified matches and ranges) - CharacterClass(CharacterClassTable *table) + CharacterClass(PassRefPtr table) : m_table(table) { - if (m_table) - m_table->incref(); } ~CharacterClass() { - if (m_table) - m_table->decref(); + js::Foreground::delete_(m_table.get()); } - typedef js::Vector UChars; - typedef js::Vector CharacterRanges; - UChars m_matches; - CharacterRanges m_ranges; - UChars m_matchesUnicode; - CharacterRanges m_rangesUnicode; - CharacterClassTable *m_table; + Vector m_matches; + Vector m_ranges; + Vector m_matchesUnicode; + Vector m_rangesUnicode; + RefPtr m_table; }; enum QuantifierType { @@ -129,11 +121,12 @@ struct PatternTerm { TypeParenthesesSubpattern, TypeParentheticalAssertion } type; - bool invertOrCapture; + bool m_capture :1; + bool m_invert :1; union { UChar patternCharacter; CharacterClass* characterClass; - unsigned subpatternId; + unsigned backReferenceSubpatternId; struct { PatternDisjunction* disjunction; unsigned subpatternId; @@ -147,8 +140,21 @@ struct PatternTerm { int inputPosition; unsigned frameLocation; + // No-argument constructor for js::Vector. + PatternTerm() + : type(PatternTerm::TypePatternCharacter) + , m_capture(false) + , m_invert(false) + { + patternCharacter = 0; + quantityType = QuantifierFixedCount; + quantityCount = 1; + } + PatternTerm(UChar ch) : type(PatternTerm::TypePatternCharacter) + , m_capture(false) + , m_invert(false) { patternCharacter = ch; quantityType = QuantifierFixedCount; @@ -157,16 +163,18 @@ struct PatternTerm { PatternTerm(CharacterClass* charClass, bool invert) : type(PatternTerm::TypeCharacterClass) - , invertOrCapture(invert) + , m_capture(false) + , m_invert(invert) { characterClass = charClass; quantityType = QuantifierFixedCount; quantityCount = 1; } - PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool invertOrCapture) + PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false) : type(type) - , invertOrCapture(invertOrCapture) + , m_capture(capture) + , m_invert(invert) { parentheses.disjunction = disjunction; parentheses.subpatternId = subpatternId; @@ -178,7 +186,8 @@ struct PatternTerm { PatternTerm(Type type, bool invert = false) : type(type) - , invertOrCapture(invert) + , m_capture(false) + , m_invert(invert) { quantityType = QuantifierFixedCount; quantityCount = 1; @@ -186,9 +195,10 @@ struct PatternTerm { PatternTerm(unsigned spatternId) : type(TypeBackReference) - , invertOrCapture(false) + , m_capture(false) + , m_invert(false) { - subpatternId = spatternId; + backReferenceSubpatternId = spatternId; quantityType = QuantifierFixedCount; quantityCount = 1; } @@ -215,12 +225,12 @@ struct PatternTerm { bool invert() { - return invertOrCapture; + return m_invert; } bool capture() { - return invertOrCapture; + return m_capture; } void quantify(unsigned count, QuantifierType type) @@ -231,9 +241,8 @@ struct PatternTerm { }; struct PatternAlternative { - - JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; - + WTF_MAKE_FAST_ALLOCATED +public: PatternAlternative(PatternDisjunction* disjunction) : m_parent(disjunction) , m_onceThrough(false) @@ -245,14 +254,14 @@ struct PatternAlternative { PatternTerm& lastTerm() { - JS_ASSERT(m_terms.length()); - return m_terms[m_terms.length() - 1]; + ASSERT(m_terms.size()); + return m_terms[m_terms.size() - 1]; } void removeLastTerm() { - JS_ASSERT(m_terms.length()); - m_terms.popBack(); + ASSERT(m_terms.size()); + m_terms.shrink(m_terms.size() - 1); } void setOnceThrough() @@ -265,7 +274,7 @@ struct PatternAlternative { return m_onceThrough; } - js::Vector m_terms; + Vector m_terms; PatternDisjunction* m_parent; unsigned m_minimumSize; bool m_onceThrough : 1; @@ -274,18 +283,9 @@ struct PatternAlternative { bool m_containsBOL : 1; }; -template -static inline void -deleteAllValues(js::Vector &vector) -{ - for (T** t = vector.begin(); t < vector.end(); ++t) - js::Foreground::delete_(*t); -} - struct PatternDisjunction { - - JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; - + WTF_MAKE_FAST_ALLOCATED +public: PatternDisjunction(PatternAlternative* parent = 0) : m_parent(parent) , m_hasFixedSize(false) @@ -299,13 +299,12 @@ struct PatternDisjunction { PatternAlternative* addNewAlternative() { - // FIXME: bug 574459 -- no NULL check PatternAlternative* alternative = js::OffTheBooks::new_(this); m_alternatives.append(alternative); return alternative; } - js::Vector m_alternatives; + Vector m_alternatives; PatternAlternative* m_parent; unsigned m_minimumSize; unsigned m_callFrameSize; @@ -314,7 +313,7 @@ struct PatternDisjunction { // You probably don't want to be calling these functions directly // (please to be calling newlineCharacterClass() et al on your -// friendly neighborhood RegexPattern instance to get nicely +// friendly neighborhood YarrPattern instance to get nicely // cached copies). CharacterClass* newlineCreate(); CharacterClass* digitsCreate(); @@ -324,25 +323,34 @@ CharacterClass* nondigitsCreate(); CharacterClass* nonspacesCreate(); CharacterClass* nonwordcharCreate(); -struct RegexPattern { - RegexPattern(bool ignoreCase, bool multiline) - : m_ignoreCase(ignoreCase) - , m_multiline(multiline) - , m_containsBackreferences(false) - , m_containsBOL(false) - , m_numSubpatterns(0) - , m_maxBackReference(0) - , newlineCached(0) - , digitsCached(0) - , spacesCached(0) - , wordcharCached(0) - , nondigitsCached(0) - , nonspacesCached(0) - , nonwordcharCached(0) - { - } +struct TermChain { + TermChain(PatternTerm term) + : term(term) + {} - ~RegexPattern() + PatternTerm term; + Vector hotTerms; +}; + +struct BeginChar { + BeginChar() + : value(0) + , mask(0) + {} + + BeginChar(unsigned value, unsigned mask) + : value(value) + , mask(mask) + {} + + unsigned value; + unsigned mask; +}; + +struct YarrPattern { + YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error); + + ~YarrPattern() { deleteAllValues(m_disjunctions); deleteAllValues(m_userCharacterClasses); @@ -354,6 +362,7 @@ struct RegexPattern { m_maxBackReference = 0; m_containsBackreferences = false; + m_containsBeginChars = false; m_containsBOL = false; newlineCached = 0; @@ -368,6 +377,7 @@ struct RegexPattern { m_disjunctions.clear(); deleteAllValues(m_userCharacterClasses); m_userCharacterClasses.clear(); + m_beginChars.clear(); } bool containsIllegalBackReference() @@ -418,19 +428,21 @@ struct RegexPattern { return nonwordcharCached; } - typedef js::Vector PatternDisjunctions; - typedef js::Vector CharacterClasses; bool m_ignoreCase : 1; bool m_multiline : 1; bool m_containsBackreferences : 1; + bool m_containsBeginChars : 1; bool m_containsBOL : 1; unsigned m_numSubpatterns; unsigned m_maxBackReference; - PatternDisjunction *m_body; - PatternDisjunctions m_disjunctions; - CharacterClasses m_userCharacterClasses; + PatternDisjunction* m_body; + Vector m_disjunctions; + Vector m_userCharacterClasses; + Vector m_beginChars; private: + ErrorCode compile(const UString& patternString); + CharacterClass* newlineCached; CharacterClass* digitsCached; CharacterClass* spacesCached; @@ -442,4 +454,4 @@ private: } } // namespace JSC::Yarr -#endif // RegexPattern_h +#endif // YarrPattern_h diff --git a/js/src/yarr/yarr/RegexCommon.h b/js/src/yarr/YarrSyntaxChecker.cpp similarity index 52% rename from js/src/yarr/yarr/RegexCommon.h rename to js/src/yarr/YarrSyntaxChecker.cpp index 3ae337ea62cc..f36ac5a3f5bc 100644 --- a/js/src/yarr/yarr/RegexCommon.h +++ b/js/src/yarr/YarrSyntaxChecker.cpp @@ -1,5 +1,8 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. +/* -*- 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) 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 @@ -21,30 +24,39 @@ * 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 RegexCommon_h -#define RegexCommon_h +#include "YarrSyntaxChecker.h" + +#include "YarrParser.h" namespace JSC { namespace Yarr { -enum ErrorCode { - HitRecursionLimit = -2, - NoError = 0, - PatternTooLarge, - QuantifierOutOfOrder, - QuantifierWithoutAtom, - MissingParentheses, - ParenthesesUnmatched, - ParenthesesTypeInvalid, - CharacterClassUnmatched, - CharacterClassOutOfOrder, - CharacterClassRangeSingleChar, - EscapeUnterminated, - QuantifierTooLarge, - NumberOfErrorCodes +class SyntaxChecker { +public: + void assertionBOL() {} + void assertionEOL() {} + void assertionWordBoundary(bool) {} + void atomPatternCharacter(UChar) {} + void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) {} + void atomCharacterClassBegin(bool = false) {} + void atomCharacterClassAtom(UChar) {} + void atomCharacterClassRange(UChar, UChar) {} + void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) {} + void atomCharacterClassEnd() {} + void atomParenthesesSubpatternBegin(bool = true) {} + void atomParentheticalAssertionBegin(bool = false) {} + void atomParenthesesEnd() {} + void atomBackReference(unsigned) {} + void quantifyAtom(unsigned, unsigned, bool) {} + void disjunction() {} }; -}} +ErrorCode checkSyntax(const UString& pattern) +{ + SyntaxChecker syntaxChecker; + return parse(syntaxChecker, pattern); +} -#endif +}} // JSC::YARR diff --git a/js/src/yarr/yarr/RegexCompiler.h b/js/src/yarr/YarrSyntaxChecker.h similarity index 74% rename from js/src/yarr/yarr/RegexCompiler.h rename to js/src/yarr/YarrSyntaxChecker.h index 307c15866e59..87f2ed5093b0 100644 --- a/js/src/yarr/yarr/RegexCompiler.h +++ b/js/src/yarr/YarrSyntaxChecker.h @@ -1,5 +1,8 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. +/* -*- 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) 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 @@ -21,18 +24,20 @@ * 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 RegexCompiler_h -#define RegexCompiler_h +#ifndef YarrSyntaxChecker_h +#define YarrSyntaxChecker_h -#include "RegexParser.h" -#include "RegexPattern.h" +#include "wtfbridge.h" +#include "YarrParser.h" namespace JSC { namespace Yarr { -int compileRegex(const UString& patternString, RegexPattern& pattern); +ErrorCode checkSyntax(const UString& pattern); -} } // namespace JSC::Yarr +}} // JSC::YARR + +#endif // YarrSyntaxChecker_h -#endif // RegexCompiler_h diff --git a/js/src/yarr/jswtfbridge.h b/js/src/yarr/jswtfbridge.h deleted file mode 100644 index b38f76ead5a8..000000000000 --- a/js/src/yarr/jswtfbridge.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- 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 ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released - * June 12, 2009. - * - * The Initial Developer of the Original Code is - * the Mozilla Corporation. - * - * Contributor(s): - * Chris Leary - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jswtfbridge_h__ -#define jswtfbridge_h__ - -/* - * The JS/WTF Bridge to Bona-fide Quality. - */ - -#include "assembler/wtf/Platform.h" -#include "jsstr.h" -#include "jsprvtd.h" -#include "jstl.h" - -typedef jschar UChar; -typedef JSLinearString UString; - -class Unicode { - public: - static UChar toUpper(UChar c) { return JS_TOUPPER(c); } - static UChar toLower(UChar c) { return JS_TOLOWER(c); } -}; - -#endif diff --git a/js/src/yarr/pcre/AUTHORS b/js/src/yarr/pcre/AUTHORS deleted file mode 100644 index dbac2a54834b..000000000000 --- a/js/src/yarr/pcre/AUTHORS +++ /dev/null @@ -1,12 +0,0 @@ -Originally written by: Philip Hazel -Email local part: ph10 -Email domain: cam.ac.uk - -University of Cambridge Computing Service, -Cambridge, England. Phone: +44 1223 334714. - -Copyright (c) 1997-2005 University of Cambridge. All rights reserved. - -Adapted for JavaScriptCore and WebKit by Apple Inc. - -Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved. diff --git a/js/src/yarr/pcre/COPYING b/js/src/yarr/pcre/COPYING deleted file mode 100644 index 6ffdc24342d5..000000000000 --- a/js/src/yarr/pcre/COPYING +++ /dev/null @@ -1,35 +0,0 @@ -PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - -This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. - -Copyright (c) 1997-2005 University of Cambridge. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the name of Apple - Inc. nor the names of their contributors may be used to endorse or - promote products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. diff --git a/js/src/yarr/pcre/chartables.c b/js/src/yarr/pcre/chartables.c deleted file mode 100644 index 5c99db0b980f..000000000000 --- a/js/src/yarr/pcre/chartables.c +++ /dev/null @@ -1,96 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* This file is automatically written by the dftables auxiliary -program. If you edit it by hand, you might like to edit the Makefile to -prevent its ever being regenerated. - -This file contains the default tables for characters with codes less than -128 (ASCII characters). These tables are used when no external tables are -passed to PCRE. */ - -const unsigned char jsc_pcre_default_tables[480] = { - -/* This table is a lower casing table. */ - - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - -/* This table is a case flipping table. */ - - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - -/* This table contains bit maps for various character classes. -Each map is 32 bytes long and the bits run from the least -significant end of each byte. The classes are: space, digit, word. */ - - 0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, - 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - -/* This table identifies various classes of character by individual bits: - 0x01 white space character - 0x08 hexadecimal digit - 0x10 alphanumeric or '_' -*/ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0- 7 */ - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 8- 15 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16- 23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24- 31 */ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* - ' */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ( - / */ - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 0 - 7 */ - 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 - ? */ - 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, /* @ - G */ - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* H - O */ - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* P - W */ - 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, /* X - _ */ - 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, /* ` - g */ - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* h - o */ - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* p - w */ - 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /* x -127 */ - - -/* End of chartables.c */ diff --git a/js/src/yarr/pcre/dftables b/js/src/yarr/pcre/dftables deleted file mode 100644 index 669b948ffc91..000000000000 --- a/js/src/yarr/pcre/dftables +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/perl -w -# -# This is JavaScriptCore's variant of the PCRE library. While this library -# started out as a copy of PCRE, many of the features of PCRE have been -# removed. This library now supports only the regular expression features -# required by the JavaScript language specification, and has only the functions -# needed by JavaScriptCore and the rest of WebKit. -# -# Originally written by Philip Hazel -# Copyright (c) 1997-2006 University of Cambridge -# Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * 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. -# -# * Neither the name of the University of Cambridge nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. -# ----------------------------------------------------------------------------- - -# This is a freestanding support program to generate a file containing -# character tables. The tables are built according to the default C -# locale. - -use strict; - -use File::Basename; -use File::Spec; -use File::Temp qw(tempfile); -use Getopt::Long; - -sub readHeaderValues(); - -my %pcre_internal; - -if (scalar(@ARGV) < 1) { - print STDERR "Usage: ", basename($0), " [--preprocessor=program] output-file\n"; - exit 1; -} - -my $outputFile; -my $preprocessor; -GetOptions('preprocessor=s' => \$preprocessor); -if (not $preprocessor) { - $preprocessor = "cpp"; -} - -$outputFile = $ARGV[0]; -die('Must specify output file.') unless defined($outputFile); - -readHeaderValues(); - -open(OUT, ">", $outputFile) or die "$!"; -binmode(OUT); - -printf(OUT - "/*************************************************\n" . - "* Perl-Compatible Regular Expressions *\n" . - "*************************************************/\n\n" . - "/* This file is automatically written by the dftables auxiliary \n" . - "program. If you edit it by hand, you might like to edit the Makefile to \n" . - "prevent its ever being regenerated.\n\n"); -printf(OUT - "This file contains the default tables for characters with codes less than\n" . - "128 (ASCII characters). These tables are used when no external tables are\n" . - "passed to PCRE. */\n\n" . - "const unsigned char jsc_pcre_default_tables[%d] = {\n\n" . - "/* This table is a lower casing table. */\n\n", $pcre_internal{tables_length}); - -if ($pcre_internal{lcc_offset} != 0) { - die "lcc_offset != 0"; -} - -printf(OUT " "); -for (my $i = 0; $i < 128; $i++) { - if (($i & 7) == 0 && $i != 0) { - printf(OUT "\n "); - } - printf(OUT "0x%02X", ord(lc(chr($i)))); - if ($i != 127) { - printf(OUT ", "); - } -} -printf(OUT ",\n\n"); - -printf(OUT "/* This table is a case flipping table. */\n\n"); - -if ($pcre_internal{fcc_offset} != 128) { - die "fcc_offset != 128"; -} - -printf(OUT " "); -for (my $i = 0; $i < 128; $i++) { - if (($i & 7) == 0 && $i != 0) { - printf(OUT "\n "); - } - my $c = chr($i); - printf(OUT "0x%02X", $c =~ /[[:lower:]]/ ? ord(uc($c)) : ord(lc($c))); - if ($i != 127) { - printf(OUT ", "); - } -} -printf(OUT ",\n\n"); - -printf(OUT - "/* This table contains bit maps for various character classes.\n" . - "Each map is 32 bytes long and the bits run from the least\n" . - "significant end of each byte. The classes are: space, digit, word. */\n\n"); - -if ($pcre_internal{cbits_offset} != $pcre_internal{fcc_offset} + 128) { - die "cbits_offset != fcc_offset + 128"; -} - -my @cbit_table = (0) x $pcre_internal{cbit_length}; -for (my $i = ord('0'); $i <= ord('9'); $i++) { - $cbit_table[$pcre_internal{cbit_digit} + $i / 8] |= 1 << ($i & 7); -} -$cbit_table[$pcre_internal{cbit_word} + ord('_') / 8] |= 1 << (ord('_') & 7); -for (my $i = 0; $i < 128; $i++) { - my $c = chr($i); - if ($c =~ /[[:alnum:]]/) { - $cbit_table[$pcre_internal{cbit_word} + $i / 8] |= 1 << ($i & 7); - } - if ($c =~ /[[:space:]]/) { - $cbit_table[$pcre_internal{cbit_space} + $i / 8] |= 1 << ($i & 7); - } -} - -printf(OUT " "); -for (my $i = 0; $i < $pcre_internal{cbit_length}; $i++) { - if (($i & 7) == 0 && $i != 0) { - if (($i & 31) == 0) { - printf(OUT "\n"); - } - printf(OUT "\n "); - } - printf(OUT "0x%02X", $cbit_table[$i]); - if ($i != $pcre_internal{cbit_length} - 1) { - printf(OUT ", "); - } -} -printf(OUT ",\n\n"); - -printf(OUT - "/* This table identifies various classes of character by individual bits:\n" . - " 0x%02x white space character\n" . - " 0x%02x hexadecimal digit\n" . - " 0x%02x alphanumeric or '_'\n*/\n\n", - $pcre_internal{ctype_space}, $pcre_internal{ctype_xdigit}, $pcre_internal{ctype_word}); - -if ($pcre_internal{ctypes_offset} != $pcre_internal{cbits_offset} + $pcre_internal{cbit_length}) { - die "ctypes_offset != cbits_offset + cbit_length"; -} - -printf(OUT " "); -for (my $i = 0; $i < 128; $i++) { - my $x = 0; - my $c = chr($i); - if ($c =~ /[[:space:]]/) { - $x += $pcre_internal{ctype_space}; - } - if ($c =~ /[[:xdigit:]]/) { - $x += $pcre_internal{ctype_xdigit}; - } - if ($c =~ /[[:alnum:]_]/) { - $x += $pcre_internal{ctype_word}; - } - printf(OUT "0x%02X", $x); - if ($i != 127) { - printf(OUT ", "); - } else { - printf(OUT "};"); - } - if (($i & 7) == 7) { - printf(OUT " /* "); - my $d = chr($i - 7); - if ($d =~ /[[:print:]]/) { - printf(OUT " %c -", $i - 7); - } else { - printf(OUT "%3d-", $i - 7); - } - if ($c =~ m/[[:print:]]/) { - printf(OUT " %c ", $i); - } else { - printf(OUT "%3d", $i); - } - printf(OUT " */\n"); - if ($i != 127) { - printf(OUT " "); - } - } -} - -if ($pcre_internal{tables_length} != $pcre_internal{ctypes_offset} + 128) { - die "tables_length != ctypes_offset + 128"; -} - -printf(OUT "\n\n/* End of chartables.c */\n"); - -close(OUT); - -exit 0; - -sub readHeaderValues() -{ - my @variables = qw( - cbit_digit - cbit_length - cbit_space - cbit_word - cbits_offset - ctype_space - ctype_word - ctype_xdigit - ctypes_offset - fcc_offset - lcc_offset - tables_length - ); - - local $/ = undef; - - my $headerPath = File::Spec->catfile(dirname($0), "pcre_internal.h"); - - my ($fh, $tempFile) = tempfile( - basename($0) . "-XXXXXXXX", - DIR => File::Spec->tmpdir(), - SUFFIX => ".in", - UNLINK => 0, - ); - - print $fh "#define DFTABLES\n\n"; - - open(HEADER, "<", $headerPath) or die "$!"; - print $fh
; - close(HEADER); - - print $fh "\n\n"; - - for my $v (@variables) { - print $fh "\$pcre_internal{\"$v\"} = $v;\n"; - } - - close($fh); - - open(CPP, "$preprocessor \"$tempFile\" |") or die "$!"; - my $content = ; - close(CPP); - - eval $content; - die "$@" if $@; - unlink $tempFile; -} diff --git a/js/src/yarr/pcre/pcre.h b/js/src/yarr/pcre/pcre.h deleted file mode 100644 index 91d96b784905..000000000000 --- a/js/src/yarr/pcre/pcre.h +++ /dev/null @@ -1,68 +0,0 @@ -/* This is the public header file for JavaScriptCore's variant of the PCRE -library. While this library started out as a copy of PCRE, many of the -features of PCRE have been removed. This library now supports only the -regular expression features required by the JavaScript language -specification, and has only the functions needed by JavaScriptCore and the -rest of WebKit. - - Copyright (c) 1997-2005 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE. - -#ifndef JSRegExp_h -#define JSRegExp_h - -#include "yarr/jswtfbridge.h" - -struct JSRegExp; -struct JSContext; - -enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase }; -enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline }; - -/* jsRegExpExecute error codes */ -const int JSRegExpErrorNoMatch = -1; -const int JSRegExpErrorHitLimit = -2; -const int JSRegExpErrorInternal = -4; - -JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, - JSRegExpIgnoreCaseOption, JSRegExpMultilineOption, - unsigned* numSubpatterns, int *error); - -int jsRegExpExecute(JSContext *, const JSRegExp*, - const UChar* subject, int subjectLength, int startOffset, - int* offsetsVector, int offsetsVectorLength); - -void jsRegExpFree(JSRegExp*); - -#endif diff --git a/js/src/yarr/pcre/pcre.pri b/js/src/yarr/pcre/pcre.pri deleted file mode 100644 index 4f59e17f4d91..000000000000 --- a/js/src/yarr/pcre/pcre.pri +++ /dev/null @@ -1,12 +0,0 @@ -# Perl Compatible Regular Expressions - Qt4 build info -VPATH += $$PWD -INCLUDEPATH += $$PWD $$OUTPUT_DIR/JavaScriptCore/tmp -DEPENDPATH += $$PWD - -SOURCES += \ - pcre_compile.cpp \ - pcre_exec.cpp \ - pcre_tables.cpp \ - pcre_ucp_searchfuncs.cpp \ - pcre_xclass.cpp - diff --git a/js/src/yarr/pcre/pcre_compile.cpp b/js/src/yarr/pcre/pcre_compile.cpp deleted file mode 100644 index 8d273bcbe5a6..000000000000 --- a/js/src/yarr/pcre/pcre_compile.cpp +++ /dev/null @@ -1,2702 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - Copyright (C) 2007 Eric Seidel - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains the external function jsRegExpExecute(), along with -supporting internal functions that are not used by other modules. */ - -#include "pcre_internal.h" - -#include -#include "yarr/wtf/ASCIICType.h" -#include "jsvector.h" - -using namespace WTF; - -/* Negative values for the firstchar and reqchar variables */ - -#define REQ_UNSET (-2) -#define REQ_NONE (-1) - -/************************************************* -* Code parameters and static tables * -*************************************************/ - -/* Maximum number of items on the nested bracket stacks at compile time. This -applies to the nesting of all kinds of parentheses. It does not limit -un-nested, non-capturing parentheses. This number can be made bigger if -necessary - it is used to dimension one int and one unsigned char vector at -compile time. */ - -#define BRASTACK_SIZE 200 - -/* Table for handling escaped characters in the range '0'-'z'. Positive returns -are simple data values; negative values are for special things like \d and so -on. Zero means further processing is needed (for things like \x), or the escape -is invalid. */ - -static const short escapes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ - 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ - '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ - 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ - 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ - 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */ - '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */ - 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */ - 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */ - 0, 0, 0 /* x - z */ -}; -static const unsigned OPCODE_LEN = 1; -static const unsigned BRAZERO_LEN = OPCODE_LEN; -static const unsigned BRA_NEST_SIZE = 2; -static const unsigned BRA_LEN = OPCODE_LEN + LINK_SIZE + BRA_NEST_SIZE; -static const unsigned KET_LEN = OPCODE_LEN + LINK_SIZE; - -/* Error code numbers. They are given names so that they can more easily be -tracked. */ - -enum ErrorCode { - ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, - ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17 -}; - -/* These are the error texts that correspond to the above error codes: - // 1 - "\\ at end of pattern\0" - "\\c at end of pattern\0" - "character value in \\x{...} sequence is too large\0" - "numbers out of order in {} quantifier\0" - // 5 - "number too big in {} quantifier\0" - "missing terminating ] for character class\0" - "internal error: code overflow\0" - "range out of order in character class\0" - "nothing to repeat\0" - // 10 - "unmatched parentheses\0" - "internal error: unexpected repeat\0" - "unrecognized character after (?\0" - "failed to get memory\0" - "missing )\0" - // 15 - "reference to non-existent subpattern\0" - "regular expression too large\0" - "parentheses nested too deeply" */ - -/* Structure for passing "static" information around between the functions -doing the compiling. */ - -struct CompileData { - CompileData() { - topBackref = 0; - backrefMap = 0; - reqVaryOpt = 0; - needOuterBracket = false; - numCapturingBrackets = 0; - } - int topBackref; /* Maximum back reference */ - unsigned backrefMap; /* Bitmap of low back refs */ - int reqVaryOpt; /* "After variable item" flag for reqByte */ - bool needOuterBracket; - int numCapturingBrackets; -}; - -/* Definitions to allow mutual recursion */ - -static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&); -static bool bracketIsAnchored(const unsigned char* code); -static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap); -static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert); - -/************************************************* -* Handle escapes * -*************************************************/ - -/* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \n, or a negative value which -encodes one of the more complicated things such as \d. When UTF-8 is enabled, -a positive value greater than 255 may be returned. On entry, ptr is pointing at -the \. On exit, it is on the final character of the escape sequence. - -Arguments: - ptrPtr points to the pattern position pointer - errorCodePtr points to the errorcode variable - bracount number of previous extracting brackets - options the options bits - isClass true if inside a character class - -Returns: zero or positive => a data character - negative => a special escape sequence - on error, error is set -*/ - -static int checkEscape(const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int bracount, bool isClass) -{ - const UChar* ptr = *ptrPtr + 1; - - /* If backslash is at the end of the pattern, it's an error. */ - if (ptr == patternEnd) { - *errorCodePtr = ERR1; - *ptrPtr = ptr; - return 0; - } - - int c = *ptr; - - /* Non-alphamerics are literals. For digits or letters, do an initial lookup in - a table. A non-zero result is something that can be returned immediately. - Otherwise further processing may be required. */ - - if (c < '0' || c > 'z') { /* Not alphameric */ - } else if (int escapeValue = escapes[c - '0']) { - c = escapeValue; - if (isClass) { - if (-c == ESC_b) - c = '\b'; /* \b is backslash in a class */ - else if (-c == ESC_B) - c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */ - } - /* Escapes that need further processing, or are illegal. */ - - } else { - switch (c) { - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - /* Escape sequences starting with a non-zero digit are backreferences, - unless there are insufficient brackets, in which case they are octal - escape sequences. Those sequences end on the first non-octal character - or when we overflow 0-255, whichever comes first. */ - - if (!isClass) { - const UChar* oldptr = ptr; - c -= '0'; - while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount) - c = c * 10 + *(++ptr) - '0'; - if (c <= bracount) { - c = -(ESC_REF + c); - break; - } - ptr = oldptr; /* Put the pointer back and fall through */ - } - - /* Handle an octal number following \. If the first digit is 8 or 9, - this is not octal. */ - - if ((c = *ptr) >= '8') { - c = '\\'; - ptr -= 1; - break; - } - - /* \0 always starts an octal number, but we may drop through to here with a - larger first octal digit. */ - - case '0': { - c -= '0'; - int i; - for (i = 1; i <= 2; ++i) { - if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7') - break; - int cc = c * 8 + ptr[i] - '0'; - if (cc > 255) - break; - c = cc; - } - ptr += i - 1; - break; - } - - case 'x': { - c = 0; - int i; - for (i = 1; i <= 2; ++i) { - if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { - c = 'x'; - i = 1; - break; - } - int cc = ptr[i]; - if (cc >= 'a') - cc -= 32; /* Convert to upper case */ - c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); - } - ptr += i - 1; - break; - } - - case 'u': { - c = 0; - int i; - for (i = 1; i <= 4; ++i) { - if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { - c = 'u'; - i = 1; - break; - } - int cc = ptr[i]; - if (cc >= 'a') - cc -= 32; /* Convert to upper case */ - c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); - } - ptr += i - 1; - break; - } - - case 'c': - if (++ptr == patternEnd) { - *errorCodePtr = ERR2; - return 0; - } - - c = *ptr; - - /* To match Firefox, inside a character class, we also accept - numbers and '_' as control characters */ - if ((!isClass && !isASCIIAlpha(c)) || (!isASCIIAlphanumeric(c) && c != '_')) { - c = '\\'; - ptr -= 2; - break; - } - - /* A letter is upper-cased; then the 0x40 bit is flipped. This coding - is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ - c = toASCIIUpper(c) ^ 0x40; - break; - } - } - - *ptrPtr = ptr; - return c; -} - -/************************************************* -* Check for counted repeat * -*************************************************/ - -/* This function is called when a '{' is encountered in a place where it might -start a quantifier. It looks ahead to see if it really is a quantifier or not. -It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} -where the ddds are digits. - -Arguments: - p pointer to the first char after '{' - -Returns: true or false -*/ - -static bool isCountedRepeat(const UChar* p, const UChar* patternEnd) -{ - if (p >= patternEnd || !isASCIIDigit(*p)) - return false; - p++; - while (p < patternEnd && isASCIIDigit(*p)) - p++; - if (p < patternEnd && *p == '}') - return true; - - if (p >= patternEnd || *p++ != ',') - return false; - if (p < patternEnd && *p == '}') - return true; - - if (p >= patternEnd || !isASCIIDigit(*p)) - return false; - p++; - while (p < patternEnd && isASCIIDigit(*p)) - p++; - - return (p < patternEnd && *p == '}'); -} - -/************************************************* -* Read repeat counts * -*************************************************/ - -/* Read an item of the form {n,m} and return the values. This is called only -after isCountedRepeat() has confirmed that a repeat-count quantifier exists, -so the syntax is guaranteed to be correct, but we need to check the values. - -Arguments: - p pointer to first char after '{' - minp pointer to int for min - maxp pointer to int for max - returned as -1 if no max - errorCodePtr points to error code variable - -Returns: pointer to '}' on success; - current ptr on error, with errorCodePtr set non-zero -*/ - -static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorCodePtr) -{ - int min = 0; - int max = -1; - - /* Read the minimum value and do a paranoid check: a negative value indicates - an integer overflow. */ - - while (isASCIIDigit(*p)) - min = min * 10 + *p++ - '0'; - if (min < 0 || min > 65535) { - *errorCodePtr = ERR5; - return p; - } - - /* Read the maximum value if there is one, and again do a paranoid on its size. - Also, max must not be less than min. */ - - if (*p == '}') - max = min; - else { - if (*(++p) != '}') { - max = 0; - while (isASCIIDigit(*p)) - max = max * 10 + *p++ - '0'; - if (max < 0 || max > 65535) { - *errorCodePtr = ERR5; - return p; - } - if (max < min) { - *errorCodePtr = ERR4; - return p; - } - } - } - - /* Fill in the required variables, and pass back the pointer to the terminating - '}'. */ - - *minp = min; - *maxp = max; - return p; -} - -/************************************************* -* Find first significant op code * -*************************************************/ - -/* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring op code etc. It skips over things -that do not influence this. - -Arguments: - code pointer to the start of the group -Returns: pointer to the first significant opcode -*/ - -static const unsigned char* firstSignificantOpcode(const unsigned char* code) -{ - while (*code == OP_BRANUMBER) - code += 3; - return code; -} - -static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code) -{ - while (true) { - switch (*code) { - case OP_ASSERT_NOT: - advanceToEndOfBracket(code); - code += 1 + LINK_SIZE; - break; - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - ++code; - break; - case OP_BRANUMBER: - code += 3; - break; - default: - return code; - } - } -} - -/************************************************* -* Get othercase range * -*************************************************/ - -/* This function is passed the start and end of a class range, in UTF-8 mode -with UCP support. It searches up the characters, looking for internal ranges of -characters in the "other" case. Each call returns the next one, updating the -start address. - -Arguments: - cptr points to starting character value; updated - d end value - ocptr where to put start of othercase range - odptr where to put end of othercase range - -Yield: true when range returned; false when no more -*/ - -static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr) -{ - int c, othercase = 0; - - for (c = *cptr; c <= d; c++) { - if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) - break; - } - - if (c > d) - return false; - - *ocptr = othercase; - int next = othercase + 1; - - for (++c; c <= d; c++) { - if (jsc_pcre_ucp_othercase(c) != next) - break; - next++; - } - - *odptr = next - 1; - *cptr = c; - - return true; -} - -/************************************************* - * Convert character value to UTF-8 * - *************************************************/ - -/* This function takes an integer value in the range 0 - 0x7fffffff - and encodes it as a UTF-8 character in 0 to 6 bytes. - - Arguments: - cvalue the character value - buffer pointer to buffer for result - at least 6 bytes long - - Returns: number of characters placed in the buffer - */ - -static int encodeUTF8(int cvalue, unsigned char *buffer) -{ - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (cvalue <= jsc_pcre_utf8_table1[i]) - break; - buffer += i; - for (int j = i; j > 0; j--) { - *buffer-- = 0x80 | (cvalue & 0x3f); - cvalue >>= 6; - } - *buffer = jsc_pcre_utf8_table2[i] | cvalue; - return i + 1; -} - -/************************************************* -* Compile one branch * -*************************************************/ - -/* Scan the pattern, compiling it into the code vector. - -Arguments: - options the option bits - brackets points to number of extracting brackets used - codePtr points to the pointer to the current code point - ptrPtr points to the current pattern pointer - errorCodePtr points to error code variable - firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) - reqbyteptr set to the last literal character required, else < 0 - cd contains pointers to tables etc. - -Returns: true on success - false, with *errorCodePtr set non-zero on error -*/ - -static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected) -{ - return ((ptr + 1 < patternEnd) && ptr[1] == expected); -} - -static bool -compileBranch(int options, int* brackets, unsigned char** codePtr, - const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int *firstbyteptr, - int* reqbyteptr, CompileData& cd) -{ - int repeatType, opType; - int repeatMin = 0, repeat_max = 0; /* To please picky compilers */ - int bravalue = 0; - int reqvary, tempreqvary; - int c; - unsigned char* code = *codePtr; - unsigned char* tempcode; - bool didGroupSetFirstByte = false; - const UChar* ptr = *ptrPtr; - const UChar* tempptr; - unsigned char* previous = NULL; - unsigned char classbits[32]; - - bool class_utf8; - unsigned char* class_utf8data; - unsigned char utf8_char[6]; - - /* Initialize no first byte, no required byte. REQ_UNSET means "no char - matching encountered yet". It gets changed to REQ_NONE if we hit something that - matches a non-fixed char first char; reqByte just remains unset if we never - find one. - - When we hit a repeat whose minimum is zero, we may have to adjust these values - to take the zero repeat into account. This is implemented by setting them to - zeroFirstByte and zeroReqByte when such a repeat is encountered. The individual - item types that can be repeated set these backoff variables appropriately. */ - - int firstByte = REQ_UNSET; - int reqByte = REQ_UNSET; - int zeroReqByte = REQ_UNSET; - int zeroFirstByte = REQ_UNSET; - - /* The variable reqCaseOpt contains either the REQ_IGNORE_CASE value or zero, - according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit - value > 255. It is added into the firstByte or reqByte variables to record the - case status of the value. This is used only for ASCII characters. */ - - int reqCaseOpt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0; - - /* Switch on next character until the end of the branch */ - - for (;; ptr++) { - bool negateClass; - bool shouldFlipNegation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */ - int classCharCount; - int classLastChar; - int skipBytes; - int subReqByte; - int subFirstByte; - int mcLength; - unsigned char mcbuffer[8]; - - /* Next byte in the pattern */ - - c = ptr < patternEnd ? *ptr : 0; - - /* Fill in length of a previous callout, except when the next thing is - a quantifier. */ - - bool isQuantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd)); - - switch (c) { - /* The branch terminates at end of string, |, or ). */ - - case 0: - if (ptr < patternEnd) - goto NORMAL_CHAR; - // End of string; fall through - case '|': - case ')': - *firstbyteptr = firstByte; - *reqbyteptr = reqByte; - *codePtr = code; - *ptrPtr = ptr; - return true; - - /* Handle single-character metacharacters. In multiline mode, ^ disables - the setting of any following char as a first character. */ - - case '^': - if (options & MatchAcrossMultipleLinesOption) { - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - *code++ = OP_BOL; - } else - *code++ = OP_CIRC; - previous = NULL; - break; - - case '$': - previous = NULL; - if (options & MatchAcrossMultipleLinesOption) - *code++ = OP_EOL; - else - *code++ = OP_DOLL; - break; - - /* There can never be a first char if '.' is first, whatever happens about - repeats. The value of reqByte doesn't change either. */ - - case '.': - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - previous = code; - *code++ = OP_NOT_NEWLINE; - break; - - /* Character classes. If the included characters are all < 256, we build a - 32-byte bitmap of the permitted characters, except in the special case - where there is only one such character. For negated classes, we build the - map as usual, then invert it at the end. However, we use a different opcode - so that data characters > 255 can be handled correctly. - - If the class contains characters outside the 0-255 range, a different - opcode is compiled. It may optionally have a bit map for characters < 256, - but those above are are explicitly listed afterwards. A flag byte tells - whether the bitmap is present, and whether this is a negated class or not. - */ - - case '[': { - previous = code; - shouldFlipNegation = false; - - /* PCRE supports POSIX class stuff inside a class. Perl gives an error if - they are encountered at the top level, so we'll do that too. */ - - /* If the first character is '^', set the negation flag and skip it. */ - - if (ptr + 1 >= patternEnd) { - *errorCodePtr = ERR6; - return false; - } - - if (ptr[1] == '^') { - negateClass = true; - ++ptr; - } else - negateClass = false; - - /* Keep a count of chars with values < 256 so that we can optimize the case - of just a single character (as long as it's < 256). For higher valued UTF-8 - characters, we don't yet do any optimization. */ - - classCharCount = 0; - classLastChar = -1; - - class_utf8 = false; /* No chars >= 256 */ - class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ - - /* Initialize the 32-char bit map to all zeros. We have to build the - map in a temporary bit of store, in case the class contains only 1 - character (< 256), because in that case the compiled code doesn't use the - bit map. */ - - memset(classbits, 0, 32 * sizeof(unsigned char)); - - /* Process characters until ] is reached. The first pass - through the regex checked the overall syntax, so we don't need to be very - strict here. At the start of the loop, c contains the first byte of the - character. */ - - while ((++ptr < patternEnd) && (c = *ptr) != ']') { - /* Backslash may introduce a single character, or it may introduce one - of the specials, which just set a flag. Escaped items are checked for - validity in the pre-compiling pass. The sequence \b is a special case. - Inside a class (and only there) it is treated as backspace. Elsewhere - it marks a word boundary. Other escapes have preset maps ready to - or into the one we are building. We assume they have more than one - character in them, so set classCharCount bigger than one. */ - - if (c == '\\') { - c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); - if (c < 0) { - classCharCount += 2; /* Greater than 1 is what matters */ - switch (-c) { - case ESC_d: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_digit); - continue; - - case ESC_D: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_digit); - continue; - - case ESC_w: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_word); - continue; - - case ESC_W: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_word); - continue; - - case ESC_s: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_space); - continue; - - case ESC_S: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_space); - continue; - - /* Unrecognized escapes are faulted if PCRE is running in its - strict mode. By default, for compatibility with Perl, they are - treated as literals. */ - - default: - c = *ptr; /* The final character */ - classCharCount -= 2; /* Undo the default count from above */ - } - } - - /* Fall through if we have a single character (c >= 0). This may be - > 256 in UTF-8 mode. */ - - } /* End of backslash handling */ - - /* A single character may be followed by '-' to form a range. However, - Perl does not permit ']' to be the end of the range. A '-' character - here is treated as a literal. */ - - if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') { - ptr += 2; - - int d = *ptr; - - /* The second part of a range can be a single-character escape, but - not any of the other escapes. Perl 5.6 treats a hyphen as a literal - in such circumstances. */ - - if (d == '\\') { - const UChar* oldptr = ptr; - d = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); - - /* \X is literal X; any other special means the '-' was literal */ - if (d < 0) { - ptr = oldptr - 2; - goto LONE_SINGLE_CHARACTER; /* A few lines below */ - } - } - - /* The check that the two values are in the correct order happens in - the pre-pass. Optimize one-character ranges */ - - if (d == c) - goto LONE_SINGLE_CHARACTER; /* A few lines below */ - - /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless - matching, we have to use an XCLASS with extra data items. Caseless - matching for characters > 127 is available only if UCP support is - available. */ - - if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) { - class_utf8 = true; - - /* With UCP support, we can find the other case equivalents of - the relevant characters. There may be several ranges. Optimize how - they fit with the basic range. */ - - if (options & IgnoreCaseOption) { - int occ, ocd; - int cc = c; - int origd = d; - while (getOthercaseRange(&cc, origd, &occ, &ocd)) { - if (occ >= c && ocd <= d) - continue; /* Skip embedded ranges */ - - if (occ < c && ocd >= c - 1) /* Extend the basic range */ - { /* if there is overlap, */ - c = occ; /* noting that if occ < c */ - continue; /* we can't have ocd > d */ - } /* because a subrange is */ - if (ocd > d && occ <= d + 1) /* always shorter than */ - { /* the basic range. */ - d = ocd; - continue; - } - - if (occ == ocd) - *class_utf8data++ = XCL_SINGLE; - else { - *class_utf8data++ = XCL_RANGE; - class_utf8data += encodeUTF8(occ, class_utf8data); - } - class_utf8data += encodeUTF8(ocd, class_utf8data); - } - } - - /* Now record the original range, possibly modified for UCP caseless - overlapping ranges. */ - - *class_utf8data++ = XCL_RANGE; - class_utf8data += encodeUTF8(c, class_utf8data); - class_utf8data += encodeUTF8(d, class_utf8data); - - /* With UCP support, we are done. Without UCP support, there is no - caseless matching for UTF-8 characters > 127; we can use the bit map - for the smaller ones. */ - - continue; /* With next character in the class */ - } - - /* We use the bit map for all cases when not in UTF-8 mode; else - ranges that lie entirely within 0-127 when there is UCP support; else - for partial ranges without UCP support. */ - - for (; c <= d; c++) { - classbits[c/8] |= (1 << (c&7)); - if (options & IgnoreCaseOption) { - int uc = flipCase(c); - classbits[uc/8] |= (1 << (uc&7)); - } - classCharCount++; /* in case a one-char range */ - classLastChar = c; - } - - continue; /* Go get the next char in the class */ - } - - /* Handle a lone single character - we can get here for a normal - non-escape char, or after \ that introduces a single character or for an - apparent range that isn't. */ - - LONE_SINGLE_CHARACTER: - - /* Handle a character that cannot go in the bit map */ - - if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) { - class_utf8 = true; - *class_utf8data++ = XCL_SINGLE; - class_utf8data += encodeUTF8(c, class_utf8data); - - if (options & IgnoreCaseOption) { - int othercase; - if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) { - *class_utf8data++ = XCL_SINGLE; - class_utf8data += encodeUTF8(othercase, class_utf8data); - } - } - } else { - /* Handle a single-byte character */ - classbits[c/8] |= (1 << (c&7)); - if (options & IgnoreCaseOption) { - c = flipCase(c); - classbits[c/8] |= (1 << (c&7)); - } - classCharCount++; - classLastChar = c; - } - } - - /* If classCharCount is 1, we saw precisely one character whose value is - less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we - can optimize the negative case only if there were no characters >= 128 - because OP_NOT and the related opcodes like OP_NOTSTAR operate on - single-bytes only. This is an historical hangover. Maybe one day we can - tidy these opcodes to handle multi-byte characters. - - The optimization throws away the bit map. We turn the item into a - 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note - that OP_NOT does not support multibyte characters. In the positive case, it - can cause firstByte to be set. Otherwise, there can be no first char if - this item is first, whatever repeat count may follow. In the case of - reqByte, save the previous value for reinstating. */ - - if (classCharCount == 1 && (!class_utf8 && (!negateClass || classLastChar < 128))) { - zeroReqByte = reqByte; - - /* The OP_NOT opcode works on one-byte characters only. */ - - if (negateClass) { - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - zeroFirstByte = firstByte; - *code++ = OP_NOT; - *code++ = classLastChar; - break; - } - - /* For a single, positive character, get the value into c, and - then we can handle this with the normal one-character code. */ - - c = classLastChar; - goto NORMAL_CHAR; - } /* End of 1-char optimization */ - - /* The general case - not the one-char optimization. If this is the first - thing in the branch, there can be no first char setting, whatever the - repeat count. Any reqByte setting must remain unchanged after any kind of - repeat. */ - - if (firstByte == REQ_UNSET) firstByte = REQ_NONE; - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - - /* If there are characters with values > 255, we have to compile an - extended class, with its own opcode. If there are no characters < 256, - we can omit the bitmap. */ - - if (class_utf8 && !shouldFlipNegation) { - *class_utf8data++ = XCL_END; /* Marks the end of extra data */ - *code++ = OP_XCLASS; - code += LINK_SIZE; - *code = negateClass? XCL_NOT : 0; - - /* If the map is required, install it, and move on to the end of - the extra data */ - - if (classCharCount > 0) { - *code++ |= XCL_MAP; - memcpy(code, classbits, 32); - code = class_utf8data; - } - - /* If the map is not required, slide down the extra data. */ - - else { - int len = class_utf8data - (code + 33); - memmove(code + 1, code + 33, len); - code += len + 1; - } - - /* Now fill in the complete length of the item */ - - putLinkValue(previous + 1, code - previous); - break; /* End of class handling */ - } - - /* If there are no characters > 255, negate the 32-byte map if necessary, - and copy it into the code vector. If this is the first thing in the branch, - there can be no first char setting, whatever the repeat count. Any reqByte - setting must remain unchanged after any kind of repeat. */ - - *code++ = (negateClass == shouldFlipNegation) ? OP_CLASS : OP_NCLASS; - if (negateClass) - for (c = 0; c < 32; c++) - code[c] = ~classbits[c]; - else - memcpy(code, classbits, 32); - code += 32; - break; - } - - /* Various kinds of repeat; '{' is not necessarily a quantifier, but this - has been tested above. */ - - case '{': - if (!isQuantifier) - goto NORMAL_CHAR; - ptr = readRepeatCounts(ptr + 1, &repeatMin, &repeat_max, errorCodePtr); - if (*errorCodePtr) - goto FAILED; - goto REPEAT; - - case '*': - repeatMin = 0; - repeat_max = -1; - goto REPEAT; - - case '+': - repeatMin = 1; - repeat_max = -1; - goto REPEAT; - - case '?': - repeatMin = 0; - repeat_max = 1; - - REPEAT: - if (!previous) { - *errorCodePtr = ERR9; - goto FAILED; - } - - if (repeatMin == 0) { - firstByte = zeroFirstByte; /* Adjust for zero repeat */ - reqByte = zeroReqByte; /* Ditto */ - } - - /* Remember whether this is a variable length repeat */ - - reqvary = (repeatMin == repeat_max) ? 0 : REQ_VARY; - - opType = 0; /* Default single-char op codes */ - - /* Save start of previous item, in case we have to move it up to make space - for an inserted OP_ONCE for the additional '+' extension. */ - /* FIXME: Probably don't need this because we don't use OP_ONCE. */ - - tempcode = previous; - - /* If the next character is '+', we have a possessive quantifier. This - implies greediness, whatever the setting of the PCRE_UNGREEDY option. - If the next character is '?' this is a minimizing repeat, by default, - but if PCRE_UNGREEDY is set, it works the other way round. We change the - repeat type to the non-default. */ - - if (safelyCheckNextChar(ptr, patternEnd, '?')) { - repeatType = 1; - ptr++; - } else - repeatType = 0; - - /* If previous was a character match, abolish the item and generate a - repeat item instead. If a char item has a minumum of more than one, ensure - that it is set in reqByte - it might not be if a sequence such as x{3} is - the first thing in a branch because the x will have gone into firstByte - instead. */ - - if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) { - /* Deal with UTF-8 characters that take up more than one byte. It's - easier to write this out separately than try to macrify it. Use c to - hold the length of the character in bytes, plus 0x80 to flag that it's a - length rather than a small character. */ - - if (code[-1] & 0x80) { - unsigned char *lastchar = code - 1; - while((*lastchar & 0xc0) == 0x80) - lastchar--; - c = code - lastchar; /* Length of UTF-8 character */ - memcpy(utf8_char, lastchar, c); /* Save the char */ - c |= 0x80; /* Flag c as a length */ - } - else { - c = code[-1]; - if (repeatMin > 1) - reqByte = c | reqCaseOpt | cd.reqVaryOpt; - } - - goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ - } - - else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) { - c = previous[1]; - if (repeatMin > 1) - reqByte = c | reqCaseOpt | cd.reqVaryOpt; - goto OUTPUT_SINGLE_REPEAT; - } - - /* If previous was a single negated character ([^a] or similar), we use - one of the special opcodes, replacing it. The code is shared with single- - character repeats by setting opt_type to add a suitable offset into - repeatType. OP_NOT is currently used only for single-byte chars. */ - - else if (*previous == OP_NOT) { - opType = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ - c = previous[1]; - goto OUTPUT_SINGLE_REPEAT; - } - - /* If previous was a character type match (\d or similar), abolish it and - create a suitable repeat item. The code is shared with single-character - repeats by setting opType to add a suitable offset into repeatType. */ - - else if (*previous <= OP_NOT_NEWLINE) { - opType = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ - c = *previous; - - OUTPUT_SINGLE_REPEAT: - int prop_type = -1; - int prop_value = -1; - - unsigned char* oldcode = code; - code = previous; /* Usually overwrite previous item */ - - /* If the maximum is zero then the minimum must also be zero; Perl allows - this case, so we do too - by simply omitting the item altogether. */ - - if (repeat_max == 0) - goto END_REPEAT; - - /* Combine the opType with the repeatType */ - - repeatType += opType; - - /* A minimum of zero is handled either as the special case * or ?, or as - an UPTO, with the maximum given. */ - - if (repeatMin == 0) { - if (repeat_max == -1) - *code++ = OP_STAR + repeatType; - else if (repeat_max == 1) - *code++ = OP_QUERY + repeatType; - else { - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* A repeat minimum of 1 is optimized into some special cases. If the - maximum is unlimited, we use OP_PLUS. Otherwise, the original item it - left in place and, if the maximum is greater than 1, we use OP_UPTO with - one less than the maximum. */ - - else if (repeatMin == 1) { - if (repeat_max == -1) - *code++ = OP_PLUS + repeatType; - else { - code = oldcode; /* leave previous item in place */ - if (repeat_max == 1) - goto END_REPEAT; - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max - 1); - } - } - - /* The case {n,n} is just an EXACT, while the general case {n,m} is - handled as an EXACT followed by an UPTO. */ - - else { - *code++ = OP_EXACT + opType; /* NB EXACT doesn't have repeatType */ - put2ByteValueAndAdvance(code, repeatMin); - - /* If the maximum is unlimited, insert an OP_STAR. Before doing so, - we have to insert the character for the previous code. For a repeated - Unicode property match, there are two extra bytes that define the - required property. In UTF-8 mode, long characters have their length in - c, with the 0x80 bit as a flag. */ - - if (repeat_max < 0) { - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else { - *code++ = c; - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - } - *code++ = OP_STAR + repeatType; - } - - /* Else insert an UPTO if the max is greater than the min, again - preceded by the character, for the previously inserted code. */ - - else if (repeat_max != repeatMin) { - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else - *code++ = c; - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - repeat_max -= repeatMin; - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* The character or character type itself comes last in all cases. */ - - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else - *code++ = c; - - /* For a repeated Unicode property match, there are two extra bytes that - define the required property. */ - - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - } - - /* If previous was a character class or a back reference, we put the repeat - stuff after it, but just skip the item if the repeat was {0,0}. */ - - else if (*previous == OP_CLASS || - *previous == OP_NCLASS || - *previous == OP_XCLASS || - *previous == OP_REF) - { - if (repeat_max == 0) { - code = previous; - goto END_REPEAT; - } - - if (repeatMin == 0 && repeat_max == -1) - *code++ = OP_CRSTAR + repeatType; - else if (repeatMin == 1 && repeat_max == -1) - *code++ = OP_CRPLUS + repeatType; - else if (repeatMin == 0 && repeat_max == 1) - *code++ = OP_CRQUERY + repeatType; - else { - *code++ = OP_CRRANGE + repeatType; - put2ByteValueAndAdvance(code, repeatMin); - if (repeat_max == -1) - repeat_max = 0; /* 2-byte encoding for max */ - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* If previous was a bracket group, we may have to replicate it in certain - cases. */ - - else if (*previous >= OP_BRA) { - int ketoffset = 0; - int len = code - previous; - unsigned char* bralink = NULL; - int nested = get2ByteValue(previous + 1 + LINK_SIZE); - - /* If the maximum repeat count is unlimited, find the end of the bracket - by scanning through from the start, and compute the offset back to it - from the current code pointer. There may be an OP_OPT setting following - the final KET, so we can't find the end just by going back from the code - pointer. */ - - if (repeat_max == -1) { - const unsigned char* ket = previous; - advanceToEndOfBracket(ket); - ketoffset = code - ket; - } - - /* The case of a zero minimum is special because of the need to stick - OP_BRAZERO in front of it, and because the group appears once in the - data, whereas in other cases it appears the minimum number of times. For - this reason, it is simplest to treat this case separately, as otherwise - the code gets far too messy. There are several special subcases when the - minimum is zero. */ - - if (repeatMin == 0) { - /* If the maximum is also zero, we just omit the group from the output - altogether. */ - - if (repeat_max == 0) { - code = previous; - goto END_REPEAT; - } - - /* If the maximum is 1 or unlimited, we just have to stick in the - BRAZERO and do no more at this point. However, we do need to adjust - any OP_RECURSE calls inside the group that refer to the group itself or - any internal group, because the offset is from the start of the whole - regex. Temporarily terminate the pattern while doing this. */ - - if (repeat_max <= 1) { - *code = OP_END; - memmove(previous+1, previous, len); - code++; - *previous++ = OP_BRAZERO + repeatType; - } - - /* If the maximum is greater than 1 and limited, we have to replicate - in a nested fashion, sticking OP_BRAZERO before each set of brackets. - The first one has to be handled carefully because it's the original - copy, which has to be moved up. The remainder can be handled by code - that is common with the non-zero minimum case below. We have to - adjust the value of repeat_max, since one less copy is required. */ - - else { - *code = OP_END; - memmove(previous + 4 + LINK_SIZE, previous, len); - code += 4 + LINK_SIZE; - *previous++ = OP_BRAZERO + repeatType; - *previous++ = OP_BRA; - - /* We chain together the bracket offset fields that have to be - filled in later when the ends of the brackets are reached. */ - - int offset = (!bralink) ? 0 : previous - bralink; - bralink = previous; - putLinkValueAllowZeroAndAdvance(previous, offset); - put2ByteValueAndAdvance(previous, nested); - } - - repeat_max--; - } - - /* If the minimum is greater than zero, replicate the group as many - times as necessary, and adjust the maximum to the number of subsequent - copies that we need. If we set a first char from the group, and didn't - set a required char, copy the latter from the former. */ - - else { - if (repeatMin > 1) { - if (didGroupSetFirstByte && reqByte < 0) - reqByte = firstByte; - for (int i = 1; i < repeatMin; i++) { - memcpy(code, previous, len); - code += len; - } - } - if (repeat_max > 0) - repeat_max -= repeatMin; - } - - /* This code is common to both the zero and non-zero minimum cases. If - the maximum is limited, it replicates the group in a nested fashion, - remembering the bracket starts on a stack. In the case of a zero minimum, - the first one was set up above. In all cases the repeat_max now specifies - the number of additional copies needed. */ - - if (repeat_max >= 0) { - for (int i = repeat_max - 1; i >= 0; i--) { - *code++ = OP_BRAZERO + repeatType; - - /* All but the final copy start a new nesting, maintaining the - chain of brackets outstanding. */ - - if (i != 0) { - *code++ = OP_BRA; - int offset = (!bralink) ? 0 : code - bralink; - bralink = code; - putLinkValueAllowZeroAndAdvance(code, offset); - put2ByteValueAndAdvance(code, nested); - } - - memcpy(code, previous, len); - code += len; - } - - /* Now chain through the pending brackets, and fill in their length - fields (which are holding the chain links pro tem). */ - - while (bralink) { - int offset = code - bralink + 1; - unsigned char* bra = code - offset; - int oldlinkoffset = getLinkValueAllowZero(bra + 1); - bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset; - *code++ = OP_KET; - putLinkValueAndAdvance(code, offset); - putLinkValue(bra + 1, offset); - } - } - - /* If the maximum is unlimited, set a repeater in the final copy. We - can't just offset backwards from the current code point, because we - don't know if there's been an options resetting after the ket. The - correct offset was computed above. */ - - else - code[-ketoffset] = OP_KETRMAX + repeatType; - } - - // A quantifier after an assertion is mostly meaningless, but it - // can nullify the assertion if it has a 0 minimum. - else if (*previous == OP_ASSERT || *previous == OP_ASSERT_NOT) { - if (repeatMin == 0) { - code = previous; - goto END_REPEAT; - } - } - - /* Else there's some kind of shambles */ - - else { - *errorCodePtr = ERR11; - goto FAILED; - } - - /* In all case we no longer have a previous item. We also set the - "follows varying string" flag for subsequently encountered reqbytes if - it isn't already set and we have just passed a varying length item. */ - - END_REPEAT: - previous = NULL; - cd.reqVaryOpt |= reqvary; - break; - - /* Start of nested bracket sub-expression, or comment or lookahead or - lookbehind or option setting or condition. First deal with special things - that can come after a bracket; all are introduced by ?, and the appearance - of any of them means that this is not a referencing group. They were - checked for validity in the first pass over the string, so we don't have to - check for syntax errors here. */ - - case '(': - { - skipBytes = 2; - unsigned minBracket = *brackets + 1; - if (*(++ptr) == '?') { - switch (*(++ptr)) { - case ':': /* Non-extracting bracket */ - bravalue = OP_BRA; - ptr++; - break; - - case '=': /* Positive lookahead */ - bravalue = OP_ASSERT; - ptr++; - break; - - case '!': /* Negative lookahead */ - bravalue = OP_ASSERT_NOT; - ptr++; - break; - - /* Character after (? not specially recognized */ - - default: - *errorCodePtr = ERR12; - goto FAILED; - } - } - - /* Else we have a referencing group; adjust the opcode. If the bracket - number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and - arrange for the true number to follow later, in an OP_BRANUMBER item. */ - - else { - if (++(*brackets) > EXTRACT_BASIC_MAX) { - bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; - code[3 + LINK_SIZE] = OP_BRANUMBER; - put2ByteValue(code + 4 + LINK_SIZE, *brackets); - skipBytes = 5; - } - else - bravalue = OP_BRA + *brackets; - } - - /* Process nested bracketed re. We copy code into a non-variable - in order to be able to pass its address because some compilers - complain otherwise. Pass in a new setting for the ims options - if they have changed. */ - - previous = code; - *code = bravalue; - tempcode = code; - tempreqvary = cd.reqVaryOpt; /* Save value before bracket */ - { - unsigned bracketsBeforeRecursion = *brackets; - if (!compileBracket( - options, - brackets, /* Extracting bracket count */ - &tempcode, /* Where to put code (updated) */ - &ptr, /* Input pointer (updated) */ - patternEnd, - errorCodePtr, /* Where to put an error message */ - skipBytes, /* Skip over OP_BRANUMBER */ - &subFirstByte, /* For possible first char */ - &subReqByte, /* For possible last char */ - cd)) /* Tables block */ - goto FAILED; - unsigned enclosedBrackets = (*brackets - bracketsBeforeRecursion); - unsigned limitBracket = minBracket + enclosedBrackets + (bravalue > OP_BRA); - if (!((minBracket & 0xff) == minBracket && (limitBracket & 0xff) == limitBracket)) { - *errorCodePtr = ERR17; - return false; - } - JS_ASSERT(minBracket <= limitBracket); - put2ByteValue(code + 1 + LINK_SIZE, minBracket << 8 | limitBracket); - } - - /* At the end of compiling, code is still pointing to the start of the - group, while tempcode has been updated to point past the end of the group - and any option resetting that may follow it. The pattern pointer (ptr) - is on the bracket. */ - - /* Handle updating of the required and first characters. Update for normal - brackets of all kinds, and conditions with two branches (see code above). - If the bracket is followed by a quantifier with zero repeat, we have to - back off. Hence the definition of zeroReqByte and zeroFirstByte outside the - main loop so that they can be accessed for the back off. */ - - zeroReqByte = reqByte; - zeroFirstByte = firstByte; - didGroupSetFirstByte = false; - - if (bravalue >= OP_BRA) { - /* If we have not yet set a firstByte in this branch, take it from the - subpattern, remembering that it was set here so that a repeat of more - than one can replicate it as reqByte if necessary. If the subpattern has - no firstByte, set "none" for the whole branch. In both cases, a zero - repeat forces firstByte to "none". */ - - if (firstByte == REQ_UNSET) { - if (subFirstByte >= 0) { - firstByte = subFirstByte; - didGroupSetFirstByte = true; - } - else - firstByte = REQ_NONE; - zeroFirstByte = REQ_NONE; - } - - /* If firstByte was previously set, convert the subpattern's firstByte - into reqByte if there wasn't one, using the vary flag that was in - existence beforehand. */ - - else if (subFirstByte >= 0 && subReqByte < 0) - subReqByte = subFirstByte | tempreqvary; - - /* If the subpattern set a required byte (or set a first byte that isn't - really the first byte - see above), set it. */ - - if (subReqByte >= 0) - reqByte = subReqByte; - } - - /* For a forward assertion, we take the reqByte, if set. This can be - helpful if the pattern that follows the assertion doesn't set a different - char. For example, it's useful for /(?=abcde).+/. We can't set firstByte - for an assertion, however because it leads to incorrect effect for patterns - such as /(?=a)a.+/ when the "real" "a" would then become a reqByte instead - of a firstByte. This is overcome by a scan at the end if there's no - firstByte, looking for an asserted first char. */ - - else if (bravalue == OP_ASSERT && subReqByte >= 0) - reqByte = subReqByte; - - /* Now update the main code pointer to the end of the group. */ - - code = tempcode; - - /* Error if hit end of pattern */ - - if (ptr >= patternEnd || *ptr != ')') { - *errorCodePtr = ERR14; - goto FAILED; - } - break; - - } - /* Check \ for being a real metacharacter; if not, fall through and handle - it as a data character at the start of a string. Escape items are checked - for validity in the pre-compiling pass. */ - - case '\\': - tempptr = ptr; - c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, false); - - /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values - are arranged to be the negation of the corresponding OP_values. For the - back references, the values are ESC_REF plus the reference number. Only - back references and those types that consume a character may be repeated. - We can test for values between ESC_b and ESC_w for the latter; this may - have to change if any new ones are ever created. */ - - if (c < 0) { - /* For metasequences that actually match a character, we disable the - setting of a first character if it hasn't already been set. */ - - if (firstByte == REQ_UNSET && -c > ESC_b && -c <= ESC_w) - firstByte = REQ_NONE; - - /* Set values to reset to if this is followed by a zero repeat. */ - - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - - /* Back references are handled specially */ - - if (-c >= ESC_REF) { - int number = -c - ESC_REF; - previous = code; - *code++ = OP_REF; - put2ByteValueAndAdvance(code, number); - } - - /* For the rest, we can obtain the OP value by negating the escape - value */ - - else { - previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL; - *code++ = -c; - } - continue; - } - - /* Fall through. */ - - /* Handle a literal character. It is guaranteed not to be whitespace or # - when the extended flag is set. If we are in UTF-8 mode, it may be a - multi-byte literal character. */ - - default: - NORMAL_CHAR: - - previous = code; - - if (c < 128) { - mcLength = 1; - mcbuffer[0] = c; - - if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') { - *code++ = OP_ASCII_LETTER_IGNORING_CASE; - *code++ = c | 0x20; - } else { - *code++ = OP_ASCII_CHAR; - *code++ = c; - } - } else { - mcLength = encodeUTF8(c, mcbuffer); - - *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR; - for (c = 0; c < mcLength; c++) - *code++ = mcbuffer[c]; - } - - /* Set the first and required bytes appropriately. If no previous first - byte, set it from this character, but revert to none on a zero repeat. - Otherwise, leave the firstByte value alone, and don't change it on a zero - repeat. */ - - if (firstByte == REQ_UNSET) { - zeroFirstByte = REQ_NONE; - zeroReqByte = reqByte; - - /* If the character is more than one byte long, we can set firstByte - only if it is not to be matched caselessly. */ - - if (mcLength == 1 || reqCaseOpt == 0) { - firstByte = mcbuffer[0] | reqCaseOpt; - if (mcLength != 1) - reqByte = code[-1] | cd.reqVaryOpt; - } - else - firstByte = reqByte = REQ_NONE; - } - - /* firstByte was previously set; we can set reqByte only the length is - 1 or the matching is caseful. */ - - else { - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - if (mcLength == 1 || reqCaseOpt == 0) - reqByte = code[-1] | reqCaseOpt | cd.reqVaryOpt; - } - - break; /* End of literal character handling */ - } - } /* end of big loop */ - - /* Control never reaches here by falling through, only by a goto for all the - error states. Pass back the position in the pattern so that it can be displayed - to the user for diagnosing the error. */ - -FAILED: - *ptrPtr = ptr; - return false; -} - -/************************************************* -* Compile sequence of alternatives * -*************************************************/ - -/* On entry, ptr is pointing past the bracket character, but on return -it points to the closing bracket, or vertical bar, or end of string. -The code variable is pointing at the byte into which the BRA operator has been -stored. If the ims options are changed at the start (for a (?ims: group) or -during any branch, we need to insert an OP_OPT item at the start of every -following branch to ensure they get set correctly at run time, and also pass -the new options into every subsequent branch compile. - -Argument: - options option bits, including any changes for this subpattern - brackets -> int containing the number of extracting brackets used - codePtr -> the address of the current code pointer - ptrPtr -> the address of the current pattern pointer - errorCodePtr -> pointer to error code variable - skipBytes skip this many bytes at start (for OP_BRANUMBER) - firstbyteptr place to put the first required character, or a negative number - reqbyteptr place to put the last required character, or a negative number - cd points to the data block with tables pointers etc. - -Returns: true on success -*/ - -static bool -compileBracket(int options, int* brackets, unsigned char** codePtr, - const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int skipBytes, - int* firstbyteptr, int* reqbyteptr, CompileData& cd) -{ - const UChar* ptr = *ptrPtr; - unsigned char* code = *codePtr; - unsigned char* lastBranch = code; - unsigned char* start_bracket = code; - int firstByte = REQ_UNSET; - int reqByte = REQ_UNSET; - - /* Offset is set zero to mark that this bracket is still open */ - - putLinkValueAllowZero(code + 1, 0); - code += 1 + LINK_SIZE + skipBytes; - - /* Loop for each alternative branch */ - - while (true) { - /* Now compile the branch */ - - int branchFirstByte; - int branchReqByte; - if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorCodePtr, - &branchFirstByte, &branchReqByte, cd)) { - *ptrPtr = ptr; - return false; - } - - /* If this is the first branch, the firstByte and reqByte values for the - branch become the values for the regex. */ - - if (*lastBranch != OP_ALT) { - firstByte = branchFirstByte; - reqByte = branchReqByte; - } - - /* If this is not the first branch, the first char and reqByte have to - match the values from all the previous branches, except that if the previous - value for reqByte didn't have REQ_VARY set, it can still match, and we set - REQ_VARY for the regex. */ - - else { - /* If we previously had a firstByte, but it doesn't match the new branch, - we have to abandon the firstByte for the regex, but if there was previously - no reqByte, it takes on the value of the old firstByte. */ - - if (firstByte >= 0 && firstByte != branchFirstByte) { - if (reqByte < 0) - reqByte = firstByte; - firstByte = REQ_NONE; - } - - /* If we (now or from before) have no firstByte, a firstByte from the - branch becomes a reqByte if there isn't a branch reqByte. */ - - if (firstByte < 0 && branchFirstByte >= 0 && branchReqByte < 0) - branchReqByte = branchFirstByte; - - /* Now ensure that the reqbytes match */ - - if ((reqByte & ~REQ_VARY) != (branchReqByte & ~REQ_VARY)) - reqByte = REQ_NONE; - else - reqByte |= branchReqByte; /* To "or" REQ_VARY */ - } - - /* Reached end of expression, either ')' or end of pattern. Go back through - the alternative branches and reverse the chain of offsets, with the field in - the BRA item now becoming an offset to the first alternative. If there are - no alternatives, it points to the end of the group. The length in the - terminating ket is always the length of the whole bracketed item. - Return leaving the pointer at the terminating char. */ - - if (ptr >= patternEnd || *ptr != '|') { - int length = code - lastBranch; - do { - int prevLength = getLinkValueAllowZero(lastBranch + 1); - putLinkValue(lastBranch + 1, length); - length = prevLength; - lastBranch -= length; - } while (length > 0); - - /* Fill in the ket */ - - *code = OP_KET; - putLinkValue(code + 1, code - start_bracket); - code += 1 + LINK_SIZE; - - /* Set values to pass back */ - - *codePtr = code; - *ptrPtr = ptr; - *firstbyteptr = firstByte; - *reqbyteptr = reqByte; - return true; - } - - /* Another branch follows; insert an "or" node. Its length field points back - to the previous branch while the bracket remains open. At the end the chain - is reversed. It's done like this so that the start of the bracket has a - zero offset until it is closed, making it possible to detect recursion. */ - - *code = OP_ALT; - putLinkValue(code + 1, code - lastBranch); - lastBranch = code; - code += 1 + LINK_SIZE; - ptr++; - } - JS_NOT_REACHED("No fallthru."); -} - -/************************************************* -* Check for anchored expression * -*************************************************/ - -/* Try to find out if this is an anchored regular expression. Consider each -alternative branch. If they all start OP_CIRC, or with a bracket -all of whose alternatives start OP_CIRC (recurse ad lib), then -it's anchored. - -Arguments: - code points to start of expression (the bracket) - captureMap a bitmap of which brackets we are inside while testing; this - handles up to substring 31; all brackets after that share - the zero bit - backrefMap the back reference bitmap -*/ - -static bool branchIsAnchored(const unsigned char* code) -{ - const unsigned char* scode = firstSignificantOpcode(code); - int op = *scode; - - /* Brackets */ - if (op >= OP_BRA || op == OP_ASSERT) - return bracketIsAnchored(scode); - - /* Check for explicit anchoring */ - return op == OP_CIRC; -} - -static bool bracketIsAnchored(const unsigned char* code) -{ - do { - if (!branchIsAnchored(code + 1 + LINK_SIZE)) - return false; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); /* Loop for each alternative */ - return true; -} - -/************************************************* -* Check for starting with ^ or .* * -*************************************************/ - -/* This is called to find out if every branch starts with ^ or .* so that -"first char" processing can be done to speed things up in multiline -matching and for non-DOTALL patterns that start with .* (which must start at -the beginning or after \n) - -Except when the .* appears inside capturing parentheses, and there is a -subsequent back reference to those parentheses. By keeping a bitmap of the -first 31 back references, we can catch some of the more common cases more -precisely; all the greater back references share a single bit. - -Arguments: - code points to start of expression (the bracket) - captureMap a bitmap of which brackets we are inside while testing; this - handles up to substring 31; all brackets after that share - the zero bit - backrefMap the back reference bitmap -*/ - -static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) -{ - const unsigned char* scode = firstSignificantOpcode(code); - int op = *scode; - - /* Capturing brackets */ - if (op > OP_BRA) { - int captureNum = op - OP_BRA; - if (captureNum > EXTRACT_BASIC_MAX) - captureNum = get2ByteValue(scode + 2 + LINK_SIZE); - int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1; - return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap); - } - - /* Other brackets */ - if (op == OP_BRA || op == OP_ASSERT) - return bracketNeedsLineStart(scode, captureMap, backrefMap); - - /* .* means "start at start or after \n" if it isn't in brackets that - may be referenced. */ - - if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) - return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap); - - /* Explicit ^ */ - return op == OP_CIRC || op == OP_BOL; -} - -static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) -{ - do { - if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap)) - return false; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); /* Loop for each alternative */ - return true; -} - -/************************************************* -* Check for asserted fixed first char * -*************************************************/ - -/* During compilation, the "first char" settings from forward assertions are -discarded, because they can cause conflicts with actual literals that follow. -However, if we end up without a first char setting for an unanchored pattern, -it is worth scanning the regex to see if there is an initial asserted first -char. If all branches start with the same asserted char, or with a bracket all -of whose alternatives start with the same asserted char (recurse ad lib), then -we return that char, otherwise -1. - -Arguments: - code points to start of expression (the bracket) - options pointer to the options (used to check casing changes) - inassert true if in an assertion - -Returns: -1 or the fixed first char -*/ - -static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert) -{ - const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code); - int op = *scode; - - if (op >= OP_BRA) - op = OP_BRA; - - switch (op) { - default: - return -1; - - case OP_BRA: - case OP_ASSERT: - return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT); - - case OP_EXACT: - scode += 2; - /* Fall through */ - - case OP_CHAR: - case OP_CHAR_IGNORING_CASE: - case OP_ASCII_CHAR: - case OP_ASCII_LETTER_IGNORING_CASE: - case OP_PLUS: - case OP_MINPLUS: - if (!inassert) - return -1; - return scode[1]; - } -} - -static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert) -{ - int c = -1; - do { - int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert); - if (d < 0) - return -1; - if (c < 0) - c = d; - else if (c != d) - return -1; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); - return c; -} - -static inline int multiplyWithOverflowCheck(int a, int b) -{ - if (!a || !b) - return 0; - if (a > MAX_PATTERN_SIZE / b) - return -1; - return a * b; -} - -static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase, - CompileData& cd, ErrorCode& errorcode) -{ - /* Make a pass over the pattern to compute the - amount of store required to hold the compiled code. This does not have to be - perfect as long as errors are overestimates. */ - - if (patternLength > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - - int length = BRA_LEN; /* For initial BRA. */ - int branch_extra = 0; - int lastitemlength = 0; - unsigned brastackptr = 0; - int brastack[BRASTACK_SIZE]; - unsigned char bralenstack[BRASTACK_SIZE]; - int bracount = 0; - - const UChar* ptr = (const UChar*)(pattern - 1); - const UChar* patternEnd = (const UChar*)(pattern + patternLength); - - while (++ptr < patternEnd) { - int minRepeats = 0, maxRepeats = 0; - int c = *ptr; - - switch (c) { - /* A backslashed item may be an escaped data character or it may be a - character type. */ - - case '\\': - c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false); - if (errorcode != 0) - return -1; - - lastitemlength = 1; /* Default length of last item for repeats */ - - if (c >= 0) { /* Data character */ - length += 2; /* For a one-byte character */ - - if (c > 127) { - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (c <= jsc_pcre_utf8_table1[i]) break; - length += i; - lastitemlength += i; - } - - continue; - } - - /* Other escapes need one byte */ - - length++; - - /* A back reference needs an additional 2 bytes, plus either one or 5 - bytes for a repeat. We also need to keep the value of the highest - back reference. */ - - if (c <= -ESC_REF) { - int refnum = -c - ESC_REF; - cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1; - if (refnum > cd.topBackref) - cd.topBackref = refnum; - length += 2; /* For single back reference */ - if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode) - return -1; - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - else - length += 5; - if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; - } - } - continue; - - case '^': /* Single-byte metacharacters */ - case '.': - case '$': - length++; - lastitemlength = 1; - continue; - - case '*': /* These repeats won't be after brackets; */ - case '+': /* those are handled separately */ - case '?': - length++; - goto POSSESSIVE; - - /* This covers the cases of braced repeats after a single char, metachar, - class, or back reference. */ - - case '{': - if (!isCountedRepeat(ptr + 1, patternEnd)) - goto NORMAL_CHAR; - ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode); - if (errorcode != 0) - return -1; - - /* These special cases just insert one extra opcode */ - - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - - /* These cases might insert additional copies of a preceding character. */ - - else { - if (minRepeats != 1) { - length -= lastitemlength; /* Uncount the original char or metachar */ - if (minRepeats > 0) - length += 5 + lastitemlength; - } - length += lastitemlength + ((maxRepeats > 0) ? 5 : 1); - } - - if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; /* Needs no extra length */ - - POSSESSIVE: /* Test for possessive quantifier */ - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */ - } - continue; - - /* An alternation contains an offset to the next branch or ket. If any ims - options changed in the previous branch(es), and/or if we are in a - lookbehind assertion, extra space will be needed at the start of the - branch. This is handled by branch_extra. */ - - case '|': - if (brastackptr == 0) - cd.needOuterBracket = true; - length += 1 + LINK_SIZE + branch_extra; - continue; - - /* A character class uses 33 characters provided that all the character - values are less than 256. Otherwise, it uses a bit map for low valued - characters, and individual items for others. Don't worry about character - types that aren't allowed in classes - they'll get picked up during the - compile. A character class that contains only one single-byte character - uses 2 or 3 bytes, depending on whether it is negated or not. Notice this - where we can. (In UTF-8 mode we can do this only for chars < 128.) */ - - case '[': { - int class_optcount; - if (*(++ptr) == '^') { - class_optcount = 10; /* Greater than one */ - ptr++; - } - else - class_optcount = 0; - - bool class_utf8 = false; - - for (; ptr < patternEnd && *ptr != ']'; ++ptr) { - /* Check for escapes */ - - if (*ptr == '\\') { - c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); - if (errorcode != 0) - return -1; - - /* Handle escapes that turn into characters */ - - if (c >= 0) - goto NON_SPECIAL_CHARACTER; - - /* Escapes that are meta-things. The normal ones just affect the - bit map, but Unicode properties require an XCLASS extended item. */ - - else - class_optcount = 10; /* \d, \s etc; make sure > 1 */ - } - - /* Anything else increments the possible optimization count. We have to - detect ranges here so that we can compute the number of extra ranges for - caseless wide characters when UCP support is available. If there are wide - characters, we are going to have to use an XCLASS, even for single - characters. */ - - else { - c = *ptr; - - /* Come here from handling \ above when it escapes to a char value */ - - NON_SPECIAL_CHARACTER: - class_optcount++; - - int d = -1; - if (safelyCheckNextChar(ptr, patternEnd, '-')) { - const UChar* hyptr = ptr++; - if (safelyCheckNextChar(ptr, patternEnd, '\\')) { - ptr++; - d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); - if (errorcode != 0) - return -1; - } - else if ((ptr + 1 < patternEnd) && ptr[1] != ']') - d = *++ptr; - if (d < 0) - ptr = hyptr; /* go back to hyphen as data */ - } - - /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or > - 127 for caseless matching, we will need to use an XCLASS. */ - - if (d >= 0) { - class_optcount = 10; /* Ensure > 1 */ - if (d < c) { - errorcode = ERR8; - return -1; - } - - if ((d > 255 || (ignoreCase && d > 127))) { - unsigned char buffer[6]; - if (!class_utf8) /* Allow for XCLASS overhead */ - { - class_utf8 = true; - length += LINK_SIZE + 2; - } - - /* If we have UCP support, find out how many extra ranges are - needed to map the other case of characters within this range. We - have to mimic the range optimization here, because extending the - range upwards might push d over a boundary that makes it use - another byte in the UTF-8 representation. */ - - if (ignoreCase) { - int occ, ocd; - int cc = c; - int origd = d; - while (getOthercaseRange(&cc, origd, &occ, &ocd)) { - if (occ >= c && ocd <= d) - continue; /* Skip embedded */ - - if (occ < c && ocd >= c - 1) /* Extend the basic range */ - { /* if there is overlap, */ - c = occ; /* noting that if occ < c */ - continue; /* we can't have ocd > d */ - } /* because a subrange is */ - if (ocd > d && occ <= d + 1) /* always shorter than */ - { /* the basic range. */ - d = ocd; - continue; - } - - /* An extra item is needed */ - - length += 1 + encodeUTF8(occ, buffer) + - ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer)); - } - } - - /* The length of the (possibly extended) range */ - - length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer); - } - - } - - /* We have a single character. There is nothing to be done unless we - are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must - allow for an XCL_SINGLE item, doubled for caselessness if there is UCP - support. */ - - else { - if ((c > 255 || (ignoreCase && c > 127))) { - unsigned char buffer[6]; - class_optcount = 10; /* Ensure > 1 */ - if (!class_utf8) /* Allow for XCLASS overhead */ - { - class_utf8 = true; - length += LINK_SIZE + 2; - } - length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer)); - } - } - } - } - - if (ptr >= patternEnd) { /* Missing terminating ']' */ - errorcode = ERR6; - return -1; - } - - /* We can optimize when there was only one optimizable character. - Note that this does not detect the case of a negated single character. - In that case we do an incorrect length computation, but it's not a serious - problem because the computed length is too large rather than too small. */ - - if (class_optcount == 1) - goto NORMAL_CHAR; - - /* Here, we handle repeats for the class opcodes. */ - { - length += 33; - - /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, - we also need extra for wrapping the whole thing in a sub-pattern. */ - - if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode != 0) - return -1; - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - else - length += 5; - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; - } else if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; - } - } - continue; - } - - /* Brackets may be genuine groups or special things */ - - case '(': { - int branch_newextra = 0; - int bracket_length = BRA_LEN; - bool capturing = false; - - /* Handle special forms of bracket, which all start (? */ - - if (safelyCheckNextChar(ptr, patternEnd, '?')) { - switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) { - /* Non-referencing groups and lookaheads just move the pointer on, and - then behave like a non-special bracket, except that they don't increment - the count of extracting brackets. Ditto for the "once only" bracket, - which is in Perl from version 5.005. */ - - case ':': - case '=': - case '!': - ptr += 2; - break; - - /* Else loop checking valid options until ) is met. Anything else is an - error. If we are without any brackets, i.e. at top level, the settings - act as if specified in the options, so massage the options immediately. - This is for backward compatibility with Perl 5.004. */ - - default: - errorcode = ERR12; - return -1; - } - } else - capturing = true; - - /* Capturing brackets must be counted so we can process escapes in a - Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need - an additional 3 bytes of memory per capturing bracket. */ - - if (capturing) { - bracount++; - if (bracount > EXTRACT_BASIC_MAX) - bracket_length += 3; - } - - /* Save length for computing whole length at end if there's a repeat that - requires duplication of the group. Also save the current value of - branch_extra, and start the new group with the new value. If non-zero, this - will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ - - if (brastackptr >= sizeof(brastack)/sizeof(int)) { - errorcode = ERR17; - return -1; - } - - bralenstack[brastackptr] = branch_extra; - branch_extra = branch_newextra; - - brastack[brastackptr++] = length; - length += bracket_length; - continue; - } - - /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we - have to replicate this bracket up to that many times. If brastackptr is - 0 this is an unmatched bracket which will generate an error, but take care - not to try to access brastack[-1] when computing the length and restoring - the branch_extra value. */ - - case ')': { - int duplength; - length += KET_LEN; - if (brastackptr > 0) { - duplength = length - brastack[--brastackptr]; - branch_extra = bralenstack[brastackptr]; - } - else - duplength = 0; - - /* Leave ptr at the final char; for readRepeatCounts this happens - automatically; for the others we need an increment. */ - - if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode) - return -1; - } else if (c == '*') { - minRepeats = 0; - maxRepeats = -1; - ptr++; - } else if (c == '+') { - minRepeats = 1; - maxRepeats = -1; - ptr++; - } else if (c == '?') { - minRepeats = 0; - maxRepeats = 1; - ptr++; - } else { - minRepeats = 1; - maxRepeats = 1; - } - - /* If the minimum is zero, we have to allow for an OP_BRAZERO before the - group, and if the maximum is greater than zero, we have to replicate - maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting - bracket set. */ - - int repeatsLength; - if (minRepeats == 0) { - length++; - if (maxRepeats > 0) { - repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + BRA_LEN + KET_LEN + OPCODE_LEN); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength; - if (length > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - } - } - - /* When the minimum is greater than zero, we have to replicate up to - minval-1 times, with no additions required in the copies. Then, if there - is a limited maximum we have to replicate up to maxval-1 times allowing - for a BRAZERO item before each optional copy and nesting brackets for all - but one of the optional copies. */ - - else { - repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength; - if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */ - repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + BRAZERO_LEN + BRA_LEN + KET_LEN); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength - (2 + 2 * LINK_SIZE); - } - if (length > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - } - - /* Allow space for once brackets for "possessive quantifier" */ - - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; - } - continue; - } - - /* Non-special character. It won't be space or # in extended mode, so it is - always a genuine character. If we are in a \Q...\E sequence, check for the - end; if not, we have a literal. */ - - default: - NORMAL_CHAR: - length += 2; /* For a one-byte character */ - lastitemlength = 1; /* Default length of last item for repeats */ - - if (c > 127) { - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (c <= jsc_pcre_utf8_table1[i]) - break; - length += i; - lastitemlength += i; - } - - continue; - } - } - - length += KET_LEN + OPCODE_LEN; /* For final KET and END */ - - cd.numCapturingBrackets = bracount; - return length; -} - -/************************************************* -* Compile a Regular Expression * -*************************************************/ - -/* This function takes a string and returns a pointer to a block of store -holding a compiled version of the expression. The original API for this -function had no error code return variable; it is retained for backwards -compatibility. The new function is given a new name. - -Arguments: - pattern the regular expression - options various option bits - errorCodePtr pointer to error code variable (pcre_compile2() only) - can be NULL if you don't want a code value - error pointer to pointer to error text - erroroffset ptr offset in pattern where error was detected - tables pointer to character tables or NULL - -Returns: pointer to compiled data block, or NULL on error, - with error and erroroffset set -*/ - -static inline JSRegExp* returnError(ErrorCode errorcode, int *error) -{ - *error = static_cast(errorcode); - return 0; -} - -JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, - JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline, - unsigned* numSubpatterns, int *error) -{ - /* We can't pass back an error message if error is NULL; I guess the best we - can do is just return NULL, but we can set a code value if there is a code pointer. */ - if (!error) - return 0; - *error = 0; - - CompileData cd; - - ErrorCode errorcode = ERR0; - /* Call this once just to count the brackets. */ - calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); - /* Call it again to compute the length. */ - int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); - if (errorcode) - return returnError(errorcode, error); - - if (length > MAX_PATTERN_SIZE) - return returnError(ERR16, error); - - size_t size = length + sizeof(JSRegExp); - JSRegExp* re = reinterpret_cast(js::OffTheBooks::array_new(size)); - if (!re) - return returnError(ERR13, error); - - re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0); - - /* The starting points of the name/number translation table and of the code are - passed around in the compile data block. */ - - const unsigned char* codeStart = (const unsigned char*)(re + 1); - - /* Set up a starting, non-extracting bracket, then compile the expression. On - error, errorcode will be set non-zero, so we don't need to look at the result - of the function here. */ - - const UChar* ptr = (const UChar*)pattern; - const UChar* patternEnd = pattern + patternLength; - unsigned char* code = const_cast(codeStart); - int firstByte, reqByte; - int bracketCount = 0; - if (!cd.needOuterBracket) - compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstByte, &reqByte, cd); - else { - *code = OP_BRA; - unsigned char * const codeBefore = code; - compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 2, &firstByte, &reqByte, cd); - JS_ASSERT((bracketCount & 0xff) == bracketCount); - put2ByteValue(codeBefore + 1 + LINK_SIZE, 0 << 8 | (bracketCount & 0xff)); - } - re->topBracket = bracketCount; - re->topBackref = cd.topBackref; - - /* If not reached end of pattern on success, there's an excess bracket. */ - - if (errorcode == 0 && ptr < patternEnd) - errorcode = ERR10; - - /* Fill in the terminating state and check for disastrous overflow, but - if debugging, leave the test till after things are printed out. */ - - *code++ = OP_END; - - JS_ASSERT(code - codeStart <= length); - if (code - codeStart > length) - errorcode = ERR7; - - /* Give an error if there's back reference to a non-existent capturing - subpattern. */ - - if (re->topBackref > re->topBracket) - errorcode = ERR15; - - /* Failed to compile, or error while post-processing */ - - if (errorcode != ERR0) { - js::Foreground::array_delete(reinterpret_cast(re)); - return returnError(errorcode, error); - } - - /* If the anchored option was not passed, set the flag if we can determine that - the pattern is anchored by virtue of ^ characters or \A or anything else (such - as starting with .* when DOTALL is set). - - Otherwise, if we know what the first character has to be, save it, because that - speeds up unanchored matches no end. If not, see if we can set the - UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches - start with ^. and also when all branches start with .* for non-DOTALL matches. - */ - - if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart)) - re->options |= IsAnchoredOption; - else { - if (firstByte < 0) { - firstByte = (cd.needOuterBracket - ? bracketFindFirstAssertedCharacter(codeStart, false) - : branchFindFirstAssertedCharacter(codeStart, false)) - | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0); - } - if (firstByte >= 0) { - int ch = firstByte & 255; - if (ch < 127) { - re->firstByte = ((firstByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstByte; - re->options |= UseFirstByteOptimizationOption; - } - } else { - if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap)) - re->options |= UseMultiLineFirstByteOptimizationOption; - } - } - - /* For an anchored pattern, we use the "required byte" only if it follows a - variable length item in the regex. Remove the caseless flag for non-caseable - bytes. */ - - if (reqByte >= 0 && (!(re->options & IsAnchoredOption) || (reqByte & REQ_VARY))) { - int ch = reqByte & 255; - if (ch < 127) { - re->reqByte = ((reqByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqByte & ~REQ_IGNORE_CASE) : reqByte; - re->options |= UseRequiredByteOptimizationOption; - } - } - - if (numSubpatterns) - *numSubpatterns = re->topBracket; - - return re; -} - -void jsRegExpFree(JSRegExp* re) -{ - js::Foreground::array_delete(reinterpret_cast(re)); -} diff --git a/js/src/yarr/pcre/pcre_exec.cpp b/js/src/yarr/pcre/pcre_exec.cpp deleted file mode 100644 index c2d154d67b8e..000000000000 --- a/js/src/yarr/pcre/pcre_exec.cpp +++ /dev/null @@ -1,2193 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - Copyright (C) 2007 Eric Seidel - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains jsRegExpExecute(), the externally visible function -that does pattern matching using an NFA algorithm, following the rules from -the JavaScript specification. There are also some supporting functions. */ - -#include "pcre_internal.h" - -#include -#include "yarr/jswtfbridge.h" -#include "yarr/wtf/ASCIICType.h" -#include "jsarena.h" -#include "jscntxt.h" - -using namespace WTF; - -#if !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO -#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION -#endif - -/* Note: Webkit sources have USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP disabled. */ -/* Note: There are hardcoded constants all over the place, but in the port of - Yarr to TraceMonkey two bytes are added to the OP_BRA* opcodes, so the - instruction stream now looks like this at the start of a bracket group: - - OP_BRA* [link:LINK_SIZE] [minNestedBracket,maxNestedBracket:2] - - Both capturing and non-capturing brackets encode this information. */ - -/* Avoid warnings on Windows. */ -#undef min -#undef max - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION -typedef int ReturnLocation; -#else -typedef void* ReturnLocation; -#endif - -/* Node on a stack of brackets. This is used to detect and reject - matches of the empty string per ECMAScript repeat match rules. This - also prevents infinite loops on quantified empty matches. One node - represents the start state at the start of this bracket group. */ -struct BracketChainNode { - BracketChainNode* previousBracket; - const UChar* bracketStart; - /* True if the minimum number of matches was already satisfied - when we started matching this group. */ - bool minSatisfied; -}; - -struct MatchFrame { - ReturnLocation returnLocation; - struct MatchFrame* previousFrame; - int *savedOffsets; - /* The frame allocates saved offsets into the regular expression arena pool so - that they can be restored during backtracking. */ - size_t savedOffsetsSize; - JSArenaPool *regExpPool; - - MatchFrame() : savedOffsetsSize(0), regExpPool(0) {} - void init(JSArenaPool *regExpPool) { this->regExpPool = regExpPool; } - - /* Function arguments that may change */ - struct { - const UChar* subjectPtr; - const unsigned char* instructionPtr; - int offsetTop; - BracketChainNode* bracketChain; - } args; - - - /* PCRE uses "fake" recursion built off of gotos, thus - stack-based local variables are not safe to use. Instead we have to - store local variables on the current MatchFrame. */ - struct { - const unsigned char* data; - const unsigned char* startOfRepeatingBracket; - const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare - const unsigned char* instructionPtrAtStartOfOnce; - - int repeatOthercase; - int savedSubjectOffset; - - int ctype; - int fc; - int fi; - int length; - int max; - int number; - int offset; - int skipBytes; - int minBracket; - int limitBracket; - int bracketsBefore; - bool minSatisfied; - - BracketChainNode bracketChainNode; - } locals; - - void saveOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - JS_ASSERT(regExpPool); - JS_ASSERT(minBracket >= 0); - JS_ASSERT(limitBracket >= minBracket); - JS_ASSERT(offsetEnd >= 0); - if (minBracket == limitBracket) - return; - const size_t newSavedOffsetCount = 3 * (limitBracket - minBracket); - /* Increase saved offset space if necessary. */ - { - size_t targetSize = sizeof(*savedOffsets) * newSavedOffsetCount; - if (savedOffsetsSize < targetSize) { - JS_ARENA_ALLOCATE_CAST(savedOffsets, int *, regExpPool, targetSize); - JS_ASSERT(savedOffsets); /* FIXME: error code, bug 574459. */ - savedOffsetsSize = targetSize; - } - } - for (unsigned i = 0; i < unsigned(limitBracket - minBracket); ++i) { - int bracketIter = minBracket + i; - JS_ASSERT(2 * bracketIter + 1 <= offsetEnd); - int start = offsets[2 * bracketIter]; - int end = offsets[2 * bracketIter + 1]; - JS_ASSERT(bracketIter <= offsetEnd); - int offset = offsets[offsetEnd - bracketIter]; - DPRINTF(("saving bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); - JS_ASSERT(start <= end); - JS_ASSERT(i * 3 + 2 < newSavedOffsetCount); - savedOffsets[i * 3 + 0] = start; - savedOffsets[i * 3 + 1] = end; - savedOffsets[i * 3 + 2] = offset; - } - } - - void clobberOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - for (int i = 0; i < limitBracket - minBracket; ++i) { - int bracketIter = minBracket + i; - JS_ASSERT(2 * bracketIter + 1 < offsetEnd); - offsets[2 * bracketIter + 0] = -1; - offsets[2 * bracketIter + 1] = -1; - } - } - - void restoreOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - JS_ASSERT(regExpPool); - JS_ASSERT_IF(limitBracket > minBracket, savedOffsets); - for (int i = 0; i < limitBracket - minBracket; ++i) { - int bracketIter = minBracket + i; - int start = savedOffsets[i * 3 + 0]; - int end = savedOffsets[i * 3 + 1]; - int offset = savedOffsets[i * 3 + 2]; - DPRINTF(("restoring bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); - JS_ASSERT(start <= end); - offsets[2 * bracketIter + 0] = start; - offsets[2 * bracketIter + 1] = end; - offsets[offsetEnd - bracketIter] = offset; - } - } - - /* Extract the bracket data after the current opcode/link at |instructionPtr| into the locals. */ - void extractBrackets(const unsigned char *instructionPtr) { - uint16 bracketMess = get2ByteValue(instructionPtr + 1 + LINK_SIZE); - locals.minBracket = (bracketMess >> 8) & 0xff; - locals.limitBracket = (bracketMess & 0xff); - JS_ASSERT(locals.minBracket <= locals.limitBracket); - } - - /* At the start of a bracketed group, add the current subject pointer to the - stack of such pointers, to be re-instated at the end of the group when we hit - the closing ket. When match() is called in other circumstances, we don't add to - this stack. */ - void startNewGroup(bool minSatisfied) { - locals.bracketChainNode.previousBracket = args.bracketChain; - locals.bracketChainNode.bracketStart = args.subjectPtr; - locals.bracketChainNode.minSatisfied = minSatisfied; - args.bracketChain = &locals.bracketChainNode; - } -}; - -/* Structure for passing "static" information around between the functions -doing traditional NFA matching, so that they are thread-safe. */ - -struct MatchData { - int *offsetVector; /* Offset vector */ - int offsetEnd; /* One past the end */ - int offsetMax; /* The maximum usable for return data */ - bool offsetOverflow; /* Set if too many extractions */ - const UChar *startSubject; /* Start of the subject string */ - const UChar *endSubject; /* End of the subject string */ - const UChar *endMatchPtr; /* Subject position at end match */ - int endOffsetTop; /* Highwater mark at end of match */ - bool multiline; - bool ignoreCase; - - void setOffsetPair(size_t pairNum, int start, int end) { - JS_ASSERT(int(2 * pairNum + 1) < offsetEnd && int(pairNum) < offsetEnd); - JS_ASSERT(start <= end); - JS_ASSERT_IF(start < 0, start == end && start == -1); - DPRINTF(("setting offset pair at %u (%d, %d)\n", pairNum, start, end)); - offsetVector[2 * pairNum + 0] = start; - offsetVector[2 * pairNum + 1] = end; - } -}; - -/* The maximum remaining length of subject we are prepared to search for a -reqByte match. */ - -#define REQ_BYTE_MAX 1000 - -/* The below limit restricts the number of "recursive" match calls in order to -avoid spending exponential time on complex regular expressions. */ - -static const unsigned matchLimit = 1000000; - -/************************************************* -* Match a back-reference * -*************************************************/ - -/* If a back reference hasn't been set, the length that is passed is greater -than the number of characters left in the string, so the match fails. - -Arguments: - offset index into the offset vector - subjectPtr points into the subject - length length to be matched - md points to match data block - -Returns: true if matched -*/ - -static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md) -{ - const UChar* p = md.startSubject + md.offsetVector[offset]; - - /* Always fail if not enough characters left */ - - if (length > md.endSubject - subjectPtr) - return false; - - /* Separate the caselesss case for speed */ - - if (md.ignoreCase) { - while (length-- > 0) { - UChar c = *p++; - int othercase = jsc_pcre_ucp_othercase(c); - UChar d = *subjectPtr++; - if (c != d && othercase != d) - return false; - } - } - else { - while (length-- > 0) - if (*p++ != *subjectPtr++) - return false; - } - - return true; -} - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - -/* Use numbered labels and switch statement at the bottom of the match function. */ - -#define RMATCH_WHERE(num) num -#define RRETURN_LABEL RRETURN_SWITCH - -#else - -/* Use GCC's computed goto extension. */ - -/* For one test case this is more than 40% faster than the switch statement. -We could avoid the use of the num argument entirely by using local labels, -but using it for the GCC case as well as the non-GCC case allows us to share -a bit more code and notice if we use conflicting numbers.*/ - -#define RMATCH_WHERE(num) JS_EXTENSION(&&RRETURN_##num) -#define RRETURN_LABEL *stack.currentFrame->returnLocation - -#endif - -#define RECURSIVE_MATCH_COMMON(num) \ - goto RECURSE;\ - RRETURN_##num: \ - stack.popCurrentFrame(); - -#define RECURSIVE_MATCH(num, ra, rb) \ - do { \ - stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ - RECURSIVE_MATCH_COMMON(num) \ - } while (0) - -#define RECURSIVE_MATCH_NEW_GROUP(num, ra, rb, gm) \ - do { \ - stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ - stack.currentFrame->startNewGroup(gm); \ - RECURSIVE_MATCH_COMMON(num) \ - } while (0) - -#define RRETURN do { JS_EXTENSION_(goto RRETURN_LABEL); } while (0) - -#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0) - -/************************************************* -* Match from current position * -*************************************************/ - -/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character -in the subject string, while substringStart holds the value of subjectPtr at the start of the -last bracketed group - used for breaking infinite loops matching zero-length -strings. This function is called recursively in many circumstances. Whenever it -returns a negative (error) response, the outer match() call must also return the -same response. - -Arguments: - subjectPtr pointer in subject - instructionPtr position in code - offsetTop current top pointer - md pointer to "static" info for the match - -Returns: 1 if matched ) these values are >= 0 - 0 if failed to match ) - a negative error value if aborted by an error condition - (e.g. stopped by repeated call or recursion limit) -*/ - -static const unsigned numFramesOnStack = 16; - -struct MatchStack { - JSArenaPool *regExpPool; - void *regExpPoolMark; - - MatchStack(JSArenaPool *regExpPool) - : regExpPool(regExpPool) - , regExpPoolMark(JS_ARENA_MARK(regExpPool)) - , framesEnd(frames + numFramesOnStack) - , currentFrame(frames) - , size(1) // match() creates accesses the first frame w/o calling pushNewFrame - { - JS_ASSERT((sizeof(frames) / sizeof(frames[0])) == numFramesOnStack); - JS_ASSERT(regExpPool); - for (size_t i = 0; i < numFramesOnStack; ++i) - frames[i].init(regExpPool); - } - - ~MatchStack() { JS_ARENA_RELEASE(regExpPool, regExpPoolMark); } - - MatchFrame frames[numFramesOnStack]; - MatchFrame* framesEnd; - MatchFrame* currentFrame; - unsigned size; - - bool canUseStackBufferForNextFrame() { - return size < numFramesOnStack; - } - - MatchFrame* allocateNextFrame() { - if (canUseStackBufferForNextFrame()) - return currentFrame + 1; - // FIXME: bug 574459 -- no NULL check - MatchFrame *frame = js::OffTheBooks::new_(); - frame->init(regExpPool); - return frame; - } - - void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation) { - MatchFrame* newframe = allocateNextFrame(); - newframe->previousFrame = currentFrame; - - newframe->args.subjectPtr = currentFrame->args.subjectPtr; - newframe->args.offsetTop = currentFrame->args.offsetTop; - newframe->args.instructionPtr = instructionPtr; - newframe->args.bracketChain = bracketChain; - newframe->returnLocation = returnLocation; - size++; - - currentFrame = newframe; - } - - void popCurrentFrame() { - MatchFrame* oldFrame = currentFrame; - currentFrame = currentFrame->previousFrame; - if (size > numFramesOnStack) - js::Foreground::delete_(oldFrame); - size--; - } - - void popAllFrames() { - while (size) - popCurrentFrame(); - } -}; - -static int matchError(int errorCode, MatchStack& stack) -{ - stack.popAllFrames(); - return errorCode; -} - -/* Get the next UTF-8 character, not advancing the pointer, incrementing length - if there are extra bytes. This is called when we know we are in UTF-8 mode. */ - -static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len) -{ - c = *subjectPtr; - if ((c & 0xc0) == 0xc0) { - int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ - int gcss = 6 * gcaa; - c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; - for (int gcii = 1; gcii <= gcaa; gcii++) { - gcss -= 6; - c |= (subjectPtr[gcii] & 0x3f) << gcss; - } - len += gcaa; - } -} - -static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats) -{ - // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR - static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 }; - static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 }; - - JS_ASSERT(instructionOffset >= 0); - JS_ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR)); - - minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2 - minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset]; - maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset]; -} - -/* Helper class for passing a flag value from one op to the next that runs. - This allows us to set the flag in certain ops. When the flag is read, it - will be true only if the previous op set the flag, otherwise it is false. */ -class LinearFlag { -public: - LinearFlag() : flag(false) {} - - bool readAndClear() { - bool rv = flag; - flag = false; - return rv; - } - - void set() { - flag = true; - } - -private: - bool flag; -}; - -static int -match(JSArenaPool *regExpPool, const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md) -{ - bool isMatch = false; - int min; - bool minimize = false; /* Initialization not really needed, but some compilers think so. */ - unsigned remainingMatchCount = matchLimit; - int othercase; /* Declare here to avoid errors during jumps */ - bool minSatisfied; - - MatchStack stack(regExpPool); - LinearFlag minSatNextBracket; - - /* The opcode jump table. */ -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP -#define EMIT_JUMP_TABLE_ENTRY(opcode) JS_EXTENSION(&&LABEL_OP_##opcode) - static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) }; -#undef EMIT_JUMP_TABLE_ENTRY -#endif - - /* One-time setup of the opcode jump table. */ -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - for (int i = 255; !opcodeJumpTable[i]; i--) - opcodeJumpTable[i] = &&CAPTURING_BRACKET; -#endif - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - // Shark shows this as a hot line - // Using a static const here makes this line disappear, but makes later access hotter (not sure why) - stack.currentFrame->returnLocation = JS_EXTENSION(&&RETURN); -#else - stack.currentFrame->returnLocation = 0; -#endif - stack.currentFrame->args.subjectPtr = subjectPtr; - stack.currentFrame->args.instructionPtr = instructionPtr; - stack.currentFrame->args.offsetTop = offsetTop; - stack.currentFrame->args.bracketChain = 0; - stack.currentFrame->startNewGroup(false); - - /* This is where control jumps back to to effect "recursion" */ - -RECURSE: - if (!--remainingMatchCount) - return matchError(JSRegExpErrorHitLimit, stack); - - /* Now start processing the operations. */ - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - while (true) -#endif - { - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP -#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode -#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr] -#else -#define BEGIN_OPCODE(opcode) case OP_##opcode -#define NEXT_OPCODE continue -#endif -#define LOCALS(__ident) (stack.currentFrame->locals.__ident) - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - NEXT_OPCODE; -#else - switch (*stack.currentFrame->args.instructionPtr) -#endif - { - /* Non-capturing bracket: optimized */ - - BEGIN_OPCODE(BRA): - NON_CAPTURING_BRACKET: - DPRINTF(("start non-capturing bracket\n")); - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); - /* If we see no ALT, we have to skip three bytes of bracket data (link plus nested - bracket data. */ - stack.currentFrame->locals.skipBytes = 3; - /* We must compute this value at the top, before we move the instruction pointer. */ - stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); - do { - /* We need to extract this into a variable so we can correctly pass it by value - through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ - minSatisfied = stack.currentFrame->locals.minSatisfied; - RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); - if (isMatch) { - DPRINTF(("non-capturing bracket succeeded\n")); - RRETURN; - } - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - DPRINTF(("non-capturing bracket failed\n")); - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - RRETURN; - - /* Skip over large extraction number data if encountered. */ - - BEGIN_OPCODE(BRANUMBER): - stack.currentFrame->args.instructionPtr += 3; - NEXT_OPCODE; - - /* End of the pattern. */ - - BEGIN_OPCODE(END): - md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */ - md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */ - isMatch = true; - RRETURN; - - /* Assertion brackets. Check the alternative branches in turn - the - matching won't pass the KET for an assertion. If any one branch matches, - the assertion is true. Lookbehind assertions have an OP_REVERSE item at the - start of each branch to move the current point backwards, so the code at - this level is identical to the lookahead case. */ - - BEGIN_OPCODE(ASSERT): - { - uint16 bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); - LOCALS(minBracket) = (bracketMess >> 8) & 0xff; - LOCALS(limitBracket) = bracketMess & 0xff; - JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); - } - stack.currentFrame->locals.skipBytes = 3; - do { - RECURSIVE_MATCH_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); - if (isMatch) - break; - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - if (*stack.currentFrame->args.instructionPtr == OP_KET) { - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - RRETURN_NO_MATCH; - } - - /* Continue from after the assertion, updating the offsets high water - mark, since extracts may have been taken during the assertion. */ - - advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); - stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; - stack.currentFrame->args.offsetTop = md.endOffsetTop; - NEXT_OPCODE; - - /* Negative assertion: all branches must fail to match */ - - BEGIN_OPCODE(ASSERT_NOT): - stack.currentFrame->locals.skipBytes = 3; - { - unsigned bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); - LOCALS(minBracket) = (bracketMess >> 8) & 0xff; - LOCALS(limitBracket) = bracketMess & 0xff; - } - JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); - do { - RECURSIVE_MATCH_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); - if (isMatch) - RRETURN_NO_MATCH; - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.skipBytes + LINK_SIZE; - NEXT_OPCODE; - - /* An alternation is the end of a branch; scan along to find the end of the - bracketed group and go to there. */ - - BEGIN_OPCODE(ALT): - advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); - NEXT_OPCODE; - - /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating - that it may occur zero times. It may repeat infinitely, or not at all - - i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper - repeat limits are compiled as a number of copies, with the optional ones - preceded by BRAZERO or BRAMINZERO. */ - - BEGIN_OPCODE(BRAZERO): { - stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain, true); - if (isMatch) - RRETURN; - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); - stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE; - NEXT_OPCODE; - } - - BEGIN_OPCODE(BRAMINZERO): { - stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; - advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); - RECURSIVE_MATCH_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain, false); - if (isMatch) - RRETURN; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - } - - /* End of a group, repeated or non-repeating. If we are at the end of - an assertion "group", stop matching and return 1, but record the - current high water mark for use by positive assertions. Do this also - for the "once" (not-backup up) groups. */ - - BEGIN_OPCODE(KET): - BEGIN_OPCODE(KETRMIN): - BEGIN_OPCODE(KETRMAX): - stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart; - stack.currentFrame->locals.minSatisfied = stack.currentFrame->args.bracketChain->minSatisfied; - - /* Back up the stack of bracket start pointers. */ - - stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket; - - if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) { - md.endOffsetTop = stack.currentFrame->args.offsetTop; - isMatch = true; - RRETURN; - } - - /* In all other cases except a conditional group we have to check the - group number back at the start and if necessary complete handling an - extraction by setting the offsets and bumping the high water mark. */ - - stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA; - - /* For extended extraction brackets (large number), we have to fish out - the number from a dummy opcode at the start. */ - - if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) - stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 4 + LINK_SIZE); - stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; - - DPRINTF(("end bracket %d\n", stack.currentFrame->locals.number)); - - /* Test for a numbered group. This includes groups called as a result - of recursion. Note that whole-pattern recursion is coded as a recurse - into group 0, so it won't be picked up here. Instead, we catch it when - the OP_END is reached. */ - - if (stack.currentFrame->locals.number > 0) { - if (stack.currentFrame->locals.offset >= md.offsetMax) - md.offsetOverflow = true; - else { - int start = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; - int end = stack.currentFrame->args.subjectPtr - md.startSubject; - if (start == end && stack.currentFrame->locals.minSatisfied) { - DPRINTF(("empty string while group already matched; bailing")); - RRETURN_NO_MATCH; - } - DPRINTF(("saving; start: %d; end: %d\n", start, end)); - JS_ASSERT(start <= end); - md.setOffsetPair(stack.currentFrame->locals.number, start, end); - if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset) - stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2; - } - } - - /* For a non-repeating ket, just continue at this level. This also - happens for a repeating ket if no characters were matched in the group. - This is the forcible breaking of infinite loops as implemented in Perl - 5.005. If there is an options reset, it will get obeyed in the normal - course of events. */ - - if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - DPRINTF(("non-repeating ket or empty match\n")); - if (stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction && stack.currentFrame->locals.minSatisfied) { - DPRINTF(("empty string while group already matched; bailing")); - RRETURN_NO_MATCH; - } - stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; - NEXT_OPCODE; - } - - /* The repeating kets try the rest of the pattern or restart from the - preceding bracket, in the appropriate order. */ - - stack.currentFrame->extractBrackets(LOCALS(instructionPtrAtStartOfOnce)); - JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); - if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) { - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - else - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - DPRINTF(("recursively matching lazy group\n")); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(17, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); - } else { /* OP_KETRMAX */ - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - stack.currentFrame->clobberOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - DPRINTF(("recursively matching greedy group\n")); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(18, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); - if (isMatch) - RRETURN; - else - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); - } - RRETURN; - - /* Start of subject. */ - - BEGIN_OPCODE(CIRC): - if (stack.currentFrame->args.subjectPtr != md.startSubject) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* After internal newline if multiline. */ - - BEGIN_OPCODE(BOL): - if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1])) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* End of subject. */ - - BEGIN_OPCODE(DOLL): - if (stack.currentFrame->args.subjectPtr < md.endSubject) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Before internal newline if multiline. */ - - BEGIN_OPCODE(EOL): - if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Word boundary assertions */ - - BEGIN_OPCODE(NOT_WORD_BOUNDARY): - BEGIN_OPCODE(WORD_BOUNDARY): { - bool currentCharIsWordChar = false; - bool previousCharIsWordChar = false; - - if (stack.currentFrame->args.subjectPtr > md.startSubject) - previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]); - if (stack.currentFrame->args.subjectPtr < md.endSubject) - currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr); - - /* Now see if the situation is what we want */ - bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY); - if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar) - RRETURN_NO_MATCH; - NEXT_OPCODE; - } - - /* Match a single character type; inline for speed */ - - BEGIN_OPCODE(NOT_NEWLINE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isNewline(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_DIGIT): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(DIGIT): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_WHITESPACE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isSpaceChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(WHITESPACE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_WORDCHAR): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isWordChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(WORDCHAR): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isWordChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Match a back reference, possibly repeatedly. Look past the end of the - item to see if there is repeat information following. The code is similar - to that for character classes, but repeated for efficiency. Then obey - similar code to character type repeats - written out again for speed. - However, if the referenced string is the empty string, always treat - it as matched, any number of times (otherwise there could be infinite - loops). */ - - BEGIN_OPCODE(REF): - stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */ - stack.currentFrame->args.instructionPtr += 3; /* Advance past item */ - - /* If the reference is unset, set the length to be longer than the amount - of subject left; this ensures that every attempt at a match fails. We - can't just fail here, because of the possibility of quantifiers with zero - minima. */ - - if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0) - stack.currentFrame->locals.length = 0; - else - stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset]; - - /* Set up for repetition, or handle the non-repeated case */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - NEXT_OPCODE; - } - - /* If the length of the reference is zero, just continue with the - main loop. */ - - if (stack.currentFrame->locals.length == 0) - NEXT_OPCODE; - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - - /* If min = max, continue at the same level without recursion. - They are not both allowed to be zero. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep trying and advancing the pointer */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - /* Control never reaches here */ - } - - /* If maximizing, find the longest string and work backwards */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - break; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - - /* Match a bit-mapped character class, possibly repeatedly. This op code is - used when all the characters in the class have values in the range 0-255, - and either the matching is caseful, or the characters are in the range - 0-127 when UTF-8 processing is enabled. The only difference between - OP_CLASS and OP_NCLASS occurs when a data character outside the range is - encountered. - - First, look past the end of the item to see if there is repeat information - following. Then obey similar code to character type repeats - written out - again for speed. */ - - BEGIN_OPCODE(NCLASS): - BEGIN_OPCODE(CLASS): - stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */ - stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - min = stack.currentFrame->locals.max = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int c = *stack.currentFrame->args.subjectPtr++; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - RRETURN_NO_MATCH; - } else { - if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) - RRETURN_NO_MATCH; - } - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - int c = *stack.currentFrame->args.subjectPtr++; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - RRETURN; - } else { - if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0) - RRETURN; - } - } - /* Control never reaches here */ - } - /* If maximizing, find the longest possible run, then work backwards. */ - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - break; - } else { - if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) - break; - } - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - /* Control never reaches here */ - - /* Match an extended character class. */ - - BEGIN_OPCODE(XCLASS): - stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */ - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - min = stack.currentFrame->locals.max = 1; - } - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int c = *stack.currentFrame->args.subjectPtr++; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - RRETURN_NO_MATCH; - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - int c = *stack.currentFrame->args.subjectPtr++; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - RRETURN; - } - /* Control never reaches here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - break; - ++stack.currentFrame->args.subjectPtr; - } - for(;;) { - RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - RRETURN; - } - - /* Control never reaches here */ - - /* Match a single character, casefully */ - - BEGIN_OPCODE(CHAR): - stack.currentFrame->locals.length = 1; - stack.currentFrame->args.instructionPtr++; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++) - RRETURN_NO_MATCH; - NEXT_OPCODE; - - /* Match a single character, caselessly */ - - BEGIN_OPCODE(CHAR_IGNORING_CASE): { - stack.currentFrame->locals.length = 1; - stack.currentFrame->args.instructionPtr++; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int dc = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fc != dc && jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc) - RRETURN_NO_MATCH; - NEXT_OPCODE; - } - - /* Match a single ASCII character. */ - - BEGIN_OPCODE(ASCII_CHAR): - if (md.endSubject == stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1]) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - stack.currentFrame->args.instructionPtr += 2; - NEXT_OPCODE; - - /* Match one of two cases of an ASCII letter. */ - - BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE): - if (md.endSubject == stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1]) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - stack.currentFrame->args.instructionPtr += 2; - NEXT_OPCODE; - - /* Match a single character repeatedly; different opcodes share code. */ - - BEGIN_OPCODE(EXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = false; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATCHAR; - - BEGIN_OPCODE(UPTO): - BEGIN_OPCODE(MINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATCHAR; - - BEGIN_OPCODE(STAR): - BEGIN_OPCODE(MINSTAR): - BEGIN_OPCODE(PLUS): - BEGIN_OPCODE(MINPLUS): - BEGIN_OPCODE(QUERY): - BEGIN_OPCODE(MINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single-character matches. We can give - up quickly if there are fewer than the minimum number of characters left in - the subject. */ - - REPEATCHAR: - - stack.currentFrame->locals.length = 1; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - - if (stack.currentFrame->locals.fc <= 0xFFFF) { - othercase = md.ignoreCase ? jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1; - - for (int i = 1; i <= min; i++) { - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - stack.currentFrame->locals.repeatOthercase = othercase; - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase) - RRETURN; - ++stack.currentFrame->args.subjectPtr; - } - /* Control never reaches here */ - } else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) - break; - ++stack.currentFrame->args.subjectPtr; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - --stack.currentFrame->args.subjectPtr; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - } else { - /* No case on surrogate pairs, so no need to bother with "othercase". */ - - for (int i = 1; i <= min; i++) { - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += 2; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - RRETURN; - stack.currentFrame->args.subjectPtr += 2; - } - /* Control never reaches here */ - } else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr > md.endSubject - 2) - break; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - break; - stack.currentFrame->args.subjectPtr += 2; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - stack.currentFrame->args.subjectPtr -= 2; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - } - /* Control never reaches here */ - - /* Match a negated single one-byte character. */ - - BEGIN_OPCODE(NOT): { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int b = stack.currentFrame->args.instructionPtr[1]; - int c = *stack.currentFrame->args.subjectPtr++; - stack.currentFrame->args.instructionPtr += 2; - if (md.ignoreCase) { - if (c < 128) - c = toLowerCase(c); - if (toLowerCase(b) == c) - RRETURN_NO_MATCH; - } else { - if (b == c) - RRETURN_NO_MATCH; - } - NEXT_OPCODE; - } - - /* Match a negated single one-byte character repeatedly. This is almost a - repeat of the code for a repeated single character, but I haven't found a - nice way of commoning these up that doesn't require a test of the - positive/negative option for each character match. Maybe that wouldn't add - very much to the time taken, but character matching *is* what this is all - about... */ - - BEGIN_OPCODE(NOTEXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = false; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATNOTCHAR; - - BEGIN_OPCODE(NOTUPTO): - BEGIN_OPCODE(NOTMINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATNOTCHAR; - - BEGIN_OPCODE(NOTSTAR): - BEGIN_OPCODE(NOTMINSTAR): - BEGIN_OPCODE(NOTPLUS): - BEGIN_OPCODE(NOTMINPLUS): - BEGIN_OPCODE(NOTQUERY): - BEGIN_OPCODE(NOTMINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single-byte matches. We can give up quickly - if there are fewer than the minimum number of bytes left in the - subject. */ - - REPEATNOTCHAR: - if (min > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++; - - /* The code is duplicated for the caseless and caseful cases, for speed, - since matching characters is likely to be quite common. First, ensure the - minimum number of matches are present. If min = max, continue at the same - level without recursing. Otherwise, if minimizing, keep trying the rest of - the expression and advancing one matching character if failing, up to the - maximum. Alternatively, if maximizing, find the maximum number of - characters and work backwards. */ - - DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max)); - - if (md.ignoreCase) { - if (stack.currentFrame->locals.fc < 128) - stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc); - - for (int i = 1; i <= min; i++) { - int d = *stack.currentFrame->args.subjectPtr++; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fc == d) - RRETURN_NO_MATCH; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - int d = *stack.currentFrame->args.subjectPtr++; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) - RRETURN; - } - /* Control never reaches here */ - } - - /* Maximize case */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int d = *stack.currentFrame->args.subjectPtr; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fc == d) - break; - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - /* Control never reaches here */ - } - - /* Caseful comparisons */ - - else { - for (int i = 1; i <= min; i++) { - int d = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fc == d) - RRETURN_NO_MATCH; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - int d = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) - RRETURN; - } - /* Control never reaches here */ - } - - /* Maximize case */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int d = *stack.currentFrame->args.subjectPtr; - if (stack.currentFrame->locals.fc == d) - break; - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - } - /* Control never reaches here */ - - /* Match a single character type repeatedly; several different opcodes - share code. This is very similar to the code for single characters, but we - repeat it in the interests of efficiency. */ - - BEGIN_OPCODE(TYPEEXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = true; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATTYPE; - - BEGIN_OPCODE(TYPEUPTO): - BEGIN_OPCODE(TYPEMINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATTYPE; - - BEGIN_OPCODE(TYPESTAR): - BEGIN_OPCODE(TYPEMINSTAR): - BEGIN_OPCODE(TYPEPLUS): - BEGIN_OPCODE(TYPEMINPLUS): - BEGIN_OPCODE(TYPEQUERY): - BEGIN_OPCODE(TYPEMINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single character type matches. Note that - in UTF-8 mode, '.' matches a character of any length, but for the other - character types, the valid characters are all one-byte long. */ - - REPEATTYPE: - stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */ - - /* First, ensure the minimum number of matches are present. Use inline - code for maximizing the speed, and do the type test once at the start - (i.e. keep it out of the loop). Also we can test that there are at least - the minimum number of characters before we start. */ - - if (min > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if (min > 0) { - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - for (int i = 1; i <= min; i++) { - if (isNewline(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_DIGIT: - for (int i = 1; i <= min; i++) { - if (isASCIIDigit(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_DIGIT: - for (int i = 1; i <= min; i++) { - if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WHITESPACE: - for (int i = 1; i <= min; i++) { - if (isSpaceChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WHITESPACE: - for (int i = 1; i <= min; i++) { - if (!isSpaceChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WORDCHAR: - for (int i = 1; i <= min; i++) { - if (isWordChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WORDCHAR: - for (int i = 1; i <= min; i++) { - if (!isWordChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } /* End switch(stack.currentFrame->locals.ctype) */ - } - - /* If min = max, continue at the same level without recursing */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, we have to test the rest of the pattern before each - subsequent match. */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - - int c = *stack.currentFrame->args.subjectPtr++; - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - if (isNewline(c)) - RRETURN; - break; - - case OP_NOT_DIGIT: - if (isASCIIDigit(c)) - RRETURN; - break; - - case OP_DIGIT: - if (!isASCIIDigit(c)) - RRETURN; - break; - - case OP_NOT_WHITESPACE: - if (isSpaceChar(c)) - RRETURN; - break; - - case OP_WHITESPACE: - if (!isSpaceChar(c)) - RRETURN; - break; - - case OP_NOT_WORDCHAR: - if (isWordChar(c)) - RRETURN; - break; - - case OP_WORDCHAR: - if (!isWordChar(c)) - RRETURN; - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } - } - /* Control never reaches here */ - } - - /* If maximizing it is worth using inline code for speed, doing the type - test once at the start (i.e. keep it out of the loop). */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */ - - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr)) - break; - stack.currentFrame->args.subjectPtr++; - } - break; - - case OP_NOT_DIGIT: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isASCIIDigit(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_DIGIT: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isASCIIDigit(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WHITESPACE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isSpaceChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WHITESPACE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isSpaceChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WORDCHAR: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isWordChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WORDCHAR: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isWordChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } - - /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */ - - for (;;) { - RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - /* Get here if we can't make it match with any permitted repetitions */ - - RRETURN; - } - /* Control never reaches here */ - - BEGIN_OPCODE(CRMINPLUS): - BEGIN_OPCODE(CRMINQUERY): - BEGIN_OPCODE(CRMINRANGE): - BEGIN_OPCODE(CRMINSTAR): - BEGIN_OPCODE(CRPLUS): - BEGIN_OPCODE(CRQUERY): - BEGIN_OPCODE(CRRANGE): - BEGIN_OPCODE(CRSTAR): - JS_NOT_REACHED("Invalid opcode."); - return matchError(JSRegExpErrorInternal, stack); - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - CAPTURING_BRACKET: -#else - default: -#endif - /* Opening capturing bracket. If there is space in the offset vector, save - the current subject position in the working slot at the top of the vector. We - mustn't change the current values of the data slot, because they may be set - from a previous iteration of this group, and be referred to by a reference - inside the group. - - If the bracket fails to match, we need to restore this value and also the - values of the final offsets, in case they were set by a previous iteration of - the same bracket. - - If there isn't enough space in the offset vector, treat this as if it were a - non-capturing bracket. Don't worry about setting the flag for the error case - here; that is handled in the code for KET. */ - - JS_ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA); - - LOCALS(number) = *stack.currentFrame->args.instructionPtr - OP_BRA; - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); - DPRINTF(("opening capturing bracket %d\n", stack.currentFrame->locals.number)); - - /* For extended extraction brackets (large number), we have to fish out the - number from a dummy opcode at the start. */ - - if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) - stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 4 + LINK_SIZE); - stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; - - JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); - - if (stack.currentFrame->locals.offset < md.offsetMax) { - stack.currentFrame->locals.savedSubjectOffset = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; - DPRINTF(("setting subject offset for bracket to %d\n", stack.currentFrame->args.subjectPtr - md.startSubject)); - md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject; - stack.currentFrame->locals.skipBytes = 3; /* For OP_BRAs. */ - - /* We must compute this value at the top, before we move the instruction pointer. */ - stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); - do { - /* We need to extract this into a variable so we can correctly pass it by value - through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ - minSatisfied = stack.currentFrame->locals.minSatisfied; - RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); - if (isMatch) - RRETURN; - stack.currentFrame->locals.skipBytes = 1; /* For OP_ALTs. */ - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - - DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number)); - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - DPRINTF(("restoring subject offset for bracket to %d\n", stack.currentFrame->locals.savedSubjectOffset)); - md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.savedSubjectOffset; - - RRETURN; - } - - /* Insufficient room for saving captured contents */ - - goto NON_CAPTURING_BRACKET; - } - - /* Do not stick any code in here without much thought; it is assumed - that "continue" in the code above comes out to here to repeat the main - loop. */ - - } /* End of main loop */ - - JS_NOT_REACHED("Loop does not fallthru."); - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - -RRETURN_SWITCH: - switch (stack.currentFrame->returnLocation) { - case 0: goto RETURN; - case 1: goto RRETURN_1; - case 2: goto RRETURN_2; - case 6: goto RRETURN_6; - case 7: goto RRETURN_7; - case 14: goto RRETURN_14; - case 15: goto RRETURN_15; - case 16: goto RRETURN_16; - case 17: goto RRETURN_17; - case 18: goto RRETURN_18; - case 19: goto RRETURN_19; - case 20: goto RRETURN_20; - case 21: goto RRETURN_21; - case 22: goto RRETURN_22; - case 24: goto RRETURN_24; - case 26: goto RRETURN_26; - case 27: goto RRETURN_27; - case 28: goto RRETURN_28; - case 29: goto RRETURN_29; - case 30: goto RRETURN_30; - case 31: goto RRETURN_31; - case 38: goto RRETURN_38; - case 40: goto RRETURN_40; - case 42: goto RRETURN_42; - case 44: goto RRETURN_44; - case 48: goto RRETURN_48; - case 52: goto RRETURN_52; - } - - JS_NOT_REACHED("Bad computed return location."); - return matchError(JSRegExpErrorInternal, stack); - -#endif - -RETURN: - return isMatch; -} - - -/************************************************* -* Execute a Regular Expression * -*************************************************/ - -/* This function applies a compiled re to a subject string and picks out -portions of the string if it matches. Two elements in the vector are set for -each substring: the offsets to the start and end of the substring. - -Arguments: - re points to the compiled expression - extra_data points to extra data or is NULL - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - offsets points to a vector of ints to be filled in with offsets - offsetCount the number of elements in the vector - -Returns: > 0 => success; value is the number of elements filled in - = 0 => success, but offsets is not big enough - -1 => failed to match - < -1 => some kind of unexpected problem -*/ - -static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int firstByte, bool firstByteIsCaseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart) -{ - // If firstByte is set, try scanning to the first instance of that byte - // no need to try and match against any earlier part of the subject string. - if (firstByte >= 0) { - UChar firstChar = firstByte; - if (firstByteIsCaseless) - while (subjectPtr < endSubject) { - int c = *subjectPtr; - if (c > 127) - break; - if (toLowerCase(c) == firstChar) - break; - subjectPtr++; - } - else { - while (subjectPtr < endSubject && *subjectPtr != firstChar) - subjectPtr++; - } - } else if (useMultiLineFirstCharOptimization) { - /* Or to just after \n for a multiline match if possible */ - // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07 - if (subjectPtr > originalSubjectStart) { - while (subjectPtr < endSubject && !isNewline(subjectPtr[-1])) - subjectPtr++; - } - } -} - -static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int reqByte, int reqByte2, bool reqByteIsCaseless, bool hasFirstByte, const UChar*& reqBytePtr) -{ - /* If reqByte is set, we know that that character must appear in the subject - for the match to succeed. If the first character is set, reqByte must be - later in the subject; otherwise the test starts at the match point. This - optimization can save a huge amount of backtracking in patterns with nested - unlimited repeats that aren't going to match. Writing separate code for - cased/caseless versions makes it go faster, as does using an autoincrement - and backing off on a match. - - HOWEVER: when the subject string is very, very long, searching to its end can - take a long time, and give bad performance on quite ordinary patterns. This - showed up when somebody was matching /^C/ on a 32-megabyte string... so we - don't do this when the string is sufficiently long. - */ - - if (reqByte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) { - const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0); - - /* We don't need to repeat the search if we haven't yet reached the - place we found it at last time. */ - - if (p > reqBytePtr) { - if (reqByteIsCaseless) { - while (p < endSubject) { - int pp = *p++; - if (pp == reqByte || pp == reqByte2) { - p--; - break; - } - } - } else { - while (p < endSubject) { - if (*p++ == reqByte) { - p--; - break; - } - } - } - - /* If we can't find the required character, break the matching loop */ - - if (p >= endSubject) - return true; - - /* If we have found the required character, save the point where we - found it, so that we don't search again next time round the loop if - the start hasn't passed this character yet. */ - - reqBytePtr = p; - } - } - return false; -} - -int jsRegExpExecute(JSContext *cx, const JSRegExp* re, - const UChar* subject, int length, int start_offset, int* offsets, - int offsetCount) -{ - JS_ASSERT(re); - JS_ASSERT(subject || !length); - JS_ASSERT(offsetCount >= 0); - JS_ASSERT(offsets || offsetCount == 0); - - MatchData matchBlock; - matchBlock.startSubject = subject; - matchBlock.endSubject = matchBlock.startSubject + length; - const UChar* endSubject = matchBlock.endSubject; - - matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption); - matchBlock.ignoreCase = (re->options & IgnoreCaseOption); - - /* Use the vector supplied, rounding down its size to a multiple of 3. */ - int ocount = offsetCount - (offsetCount % 3); - - matchBlock.offsetVector = offsets; - matchBlock.offsetEnd = ocount; - matchBlock.offsetMax = (2*ocount)/3; - matchBlock.offsetOverflow = false; - - /* Compute the minimum number of offsets that we need to reset each time. Doing - this makes a huge difference to execution time when there aren't many brackets - in the pattern. */ - - int resetCount = 2 + re->topBracket * 2; - if (resetCount > offsetCount) - resetCount = ocount; - - /* Reset the working variable associated with each extraction. These should - never be used unless previously set, but they get saved and restored, and so we - initialize them to avoid reading uninitialized locations. */ - - if (matchBlock.offsetVector) { - int* iptr = matchBlock.offsetVector + ocount; - int* iend = iptr - resetCount/2 + 1; - while (--iptr >= iend) - *iptr = -1; - } - - /* Set up the first character to match, if available. The firstByte value is - never set for an anchored regular expression, but the anchoring may be forced - at run time, so we have to test for anchoring. The first char may be unset for - an unanchored pattern, of course. If there's no first char and the pattern was - studied, there may be a bitmap of possible first characters. */ - - bool firstByteIsCaseless = false; - int firstByte = -1; - if (re->options & UseFirstByteOptimizationOption) { - firstByte = re->firstByte & 255; - if ((firstByteIsCaseless = (re->firstByte & REQ_IGNORE_CASE))) - firstByte = toLowerCase(firstByte); - } - - /* For anchored or unanchored matches, there may be a "last known required - character" set. */ - - bool reqByteIsCaseless = false; - int reqByte = -1; - int reqByte2 = -1; - if (re->options & UseRequiredByteOptimizationOption) { - reqByte = re->reqByte & 255; - reqByteIsCaseless = (re->reqByte & REQ_IGNORE_CASE); - reqByte2 = flipCase(reqByte); - } - - /* Loop for handling unanchored repeated matching attempts; for anchored regexs - the loop runs just once. */ - - const UChar* startMatch = subject + start_offset; - const UChar* reqBytePtr = startMatch - 1; - bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption; - - do { - /* Reset the maximum number of extractions we might see. */ - if (matchBlock.offsetVector) { - int* iptr = matchBlock.offsetVector; - int* iend = iptr + resetCount; - while (iptr < iend) - *iptr++ = -1; - } - - tryFirstByteOptimization(startMatch, endSubject, firstByte, firstByteIsCaseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset); - if (tryRequiredByteOptimization(startMatch, endSubject, reqByte, reqByte2, reqByteIsCaseless, firstByte >= 0, reqBytePtr)) - break; - - /* When a match occurs, substrings will be set for all internal extractions; - we just need to set up the whole thing as substring 0 before returning. If - there were too many extractions, set the return code to zero. In the case - where we had to get some local store to hold offsets for backreferences, copy - those back references that we can. In this case there need not be overflow - if certain parts of the pattern were not used. */ - - /* The code starts after the JSRegExp block and the capture name table. */ - const unsigned char* start_code = (const unsigned char*)(re + 1); - - int returnCode = match(&cx->regExpPool, startMatch, start_code, 2, matchBlock); - - /* When the result is no match, advance the pointer to the next character - and continue. */ - if (returnCode == 0) { - startMatch++; - continue; - } - - if (returnCode != 1) { - JS_ASSERT(returnCode == JSRegExpErrorHitLimit); - DPRINTF((">>>> error: returning %d\n", returnCode)); - return returnCode; - } - - /* We have a match! */ - - returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2; - - if (offsetCount < 2) - returnCode = 0; - else { - offsets[0] = startMatch - matchBlock.startSubject; - offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject; - } - - JS_ASSERT(returnCode >= 0); - DPRINTF((">>>> returning %d\n", returnCode)); - return returnCode; - } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject); - - DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); - return JSRegExpErrorNoMatch; -} diff --git a/js/src/yarr/pcre/pcre_internal.h b/js/src/yarr/pcre/pcre_internal.h deleted file mode 100644 index d677cfcfa255..000000000000 --- a/js/src/yarr/pcre/pcre_internal.h +++ /dev/null @@ -1,434 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This header contains definitions that are shared between the different -modules, but which are not relevant to the exported API. This includes some -functions whose names all begin with "_pcre_". */ - -#ifndef PCRE_INTERNAL_H -#define PCRE_INTERNAL_H - -/* Bit definitions for entries in the pcre_ctypes table. */ - -#define ctype_space 0x01 -#define ctype_xdigit 0x08 -#define ctype_word 0x10 /* alphameric or '_' */ - -/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set -of bits for a class map. Some classes are built by combining these tables. */ - -#define cbit_space 0 /* \s */ -#define cbit_digit 32 /* \d */ -#define cbit_word 64 /* \w */ -#define cbit_length 96 /* Length of the cbits table */ - -/* Offsets of the various tables from the base tables pointer, and -total length. */ - -#define lcc_offset 0 -#define fcc_offset 128 -#define cbits_offset 256 -#define ctypes_offset (cbits_offset + cbit_length) -#define tables_length (ctypes_offset + 128) - -#ifndef DFTABLES - -#include "pcre.h" - -/* The value of LINK_SIZE determines the number of bytes used to store links as -offsets within the compiled regex. The default is 2, which allows for compiled -patterns up to 64K long. */ - -#define LINK_SIZE 3 - -/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef -inline, and there are *still* stupid compilers about that don't like indented -pre-processor statements, or at least there were when I first wrote this. After -all, it had only been about 10 years then... */ - -#ifdef DEBUG -#define DPRINTF(p) /*printf p; fflush(stdout);*/ -#else -#define DPRINTF(p) /*nothing*/ -#endif - -/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored -in big-endian order) by default. These are used, for example, to link from the -start of a subpattern to its alternatives and its end. The use of 2 bytes per -offset limits the size of the compiled regex to around 64K, which is big enough -for almost everybody. However, I received a request for an even bigger limit. -For this reason, and also to make the code easier to maintain, the storing and -loading of offsets from the byte string is now handled by the functions that are -defined here. */ - -/* PCRE uses some other 2-byte quantities that do not change when the size of -offsets changes. There are used for repeat counts and for other things such as -capturing parenthesis numbers in back references. */ - -static inline void put2ByteValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value >= 0 && value <= 0xFFFF); - opcodePtr[0] = value >> 8; - opcodePtr[1] = value; -} - -static inline void put3ByteValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value >= 0 && value <= 0xFFFFFF); - opcodePtr[0] = value >> 16; - opcodePtr[1] = value >> 8; - opcodePtr[2] = value; -} - -static inline int get2ByteValue(const unsigned char* opcodePtr) -{ - return (opcodePtr[0] << 8) | opcodePtr[1]; -} - -static inline int get3ByteValue(const unsigned char* opcodePtr) -{ - return (opcodePtr[0] << 16) | (opcodePtr[1] << 8) | opcodePtr[2]; -} - -static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - put2ByteValue(opcodePtr, value); - opcodePtr += 2; -} - -static inline void put3ByteValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - put3ByteValue(opcodePtr, value); - opcodePtr += 3; -} - -static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value) -{ -#if LINK_SIZE == 3 - put3ByteValue(opcodePtr, value); -#elif LINK_SIZE == 2 - put2ByteValue(opcodePtr, value); -#else -# error LINK_SIZE not supported. -#endif -} - -static inline int getLinkValueAllowZero(const unsigned char* opcodePtr) -{ -#if LINK_SIZE == 3 - return get3ByteValue(opcodePtr); -#elif LINK_SIZE == 2 - return get2ByteValue(opcodePtr); -#else -# error LINK_SIZE not supported. -#endif -} - -#define MAX_PATTERN_SIZE 1024 * 1024 // Derived by empirical testing of compile time in PCRE and WREC. -JS_STATIC_ASSERT(MAX_PATTERN_SIZE < (1 << (8 * LINK_SIZE))); - -static inline void putLinkValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value); - putLinkValueAllowZero(opcodePtr, value); -} - -static inline int getLinkValue(const unsigned char* opcodePtr) -{ - int value = getLinkValueAllowZero(opcodePtr); - JS_ASSERT(value); - return value; -} - -static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - putLinkValue(opcodePtr, value); - opcodePtr += LINK_SIZE; -} - -static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value) -{ - putLinkValueAllowZero(opcodePtr, value); - opcodePtr += LINK_SIZE; -} - -// FIXME: These are really more of a "compiled regexp state" than "regexp options" -enum RegExpOptions { - UseFirstByteOptimizationOption = 0x40000000, /* firstByte is set */ - UseRequiredByteOptimizationOption = 0x20000000, /* reqByte is set */ - UseMultiLineFirstByteOptimizationOption = 0x10000000, /* start after \n for multiline */ - IsAnchoredOption = 0x02000000, /* can't use partial with this regex */ - IgnoreCaseOption = 0x00000001, - MatchAcrossMultipleLinesOption = 0x00000002 -}; - -/* Flags added to firstByte or reqByte; a "non-literal" item is either a -variable-length repeat, or a anything other than literal characters. */ - -#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */ -#define REQ_VARY 0x0200 /* reqByte followed non-literal item */ - -/* Miscellaneous definitions */ - -/* Flag bits and data types for the extended class (OP_XCLASS) for classes that -contain UTF-8 characters with values greater than 255. */ - -#define XCL_NOT 0x01 /* Flag: this is a negative class */ -#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ - -#define XCL_END 0 /* Marks end of individual items */ -#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ -#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ - -/* These are escaped items that aren't just an encoding of a particular data -value such as \n. They must have non-zero values, as check_escape() returns -their negation. Also, they must appear in the same order as in the opcode -definitions below, up to ESC_w. The final one must be -ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two -tests in the code for an escape > ESC_b and <= ESC_w to -detect the types that may be repeated. These are the types that consume -characters. If any new escapes are put in between that don't consume a -character, that code will have to change. */ - -enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF }; - -/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets -that extract substrings. Starting from 1 (i.e. after OP_END), the values up to -OP_EOD must correspond in order to the list of escapes immediately above. -Note that whenever this list is updated, the two macro definitions that follow -must also be updated to match. */ - -#define FOR_EACH_OPCODE(macro) \ - macro(END) \ - \ - , macro(NOT_WORD_BOUNDARY) \ - , macro(WORD_BOUNDARY) \ - , macro(NOT_DIGIT) \ - , macro(DIGIT) \ - , macro(NOT_WHITESPACE) \ - , macro(WHITESPACE) \ - , macro(NOT_WORDCHAR) \ - , macro(WORDCHAR) \ - \ - , macro(NOT_NEWLINE) \ - \ - , macro(CIRC) \ - , macro(DOLL) \ - , macro(BOL) \ - , macro(EOL) \ - , macro(CHAR) \ - , macro(CHAR_IGNORING_CASE) \ - , macro(ASCII_CHAR) \ - , macro(ASCII_LETTER_IGNORING_CASE) \ - , macro(NOT) \ - \ - , macro(STAR) \ - , macro(MINSTAR) \ - , macro(PLUS) \ - , macro(MINPLUS) \ - , macro(QUERY) \ - , macro(MINQUERY) \ - , macro(UPTO) \ - , macro(MINUPTO) \ - , macro(EXACT) \ - \ - , macro(NOTSTAR) \ - , macro(NOTMINSTAR) \ - , macro(NOTPLUS) \ - , macro(NOTMINPLUS) \ - , macro(NOTQUERY) \ - , macro(NOTMINQUERY) \ - , macro(NOTUPTO) \ - , macro(NOTMINUPTO) \ - , macro(NOTEXACT) \ - \ - , macro(TYPESTAR) \ - , macro(TYPEMINSTAR) \ - , macro(TYPEPLUS) \ - , macro(TYPEMINPLUS) \ - , macro(TYPEQUERY) \ - , macro(TYPEMINQUERY) \ - , macro(TYPEUPTO) \ - , macro(TYPEMINUPTO) \ - , macro(TYPEEXACT) \ - \ - , macro(CRSTAR) \ - , macro(CRMINSTAR) \ - , macro(CRPLUS) \ - , macro(CRMINPLUS) \ - , macro(CRQUERY) \ - , macro(CRMINQUERY) \ - , macro(CRRANGE) \ - , macro(CRMINRANGE) \ - \ - , macro(CLASS) \ - , macro(NCLASS) \ - , macro(XCLASS) \ - \ - , macro(REF) \ - \ - , macro(ALT) \ - , macro(KET) \ - , macro(KETRMAX) \ - , macro(KETRMIN) \ - \ - , macro(ASSERT) \ - , macro(ASSERT_NOT) \ - \ - , macro(BRAZERO) \ - , macro(BRAMINZERO) \ - , macro(BRANUMBER) \ - , macro(BRA) - -#define OPCODE_ENUM_VALUE(opcode) OP_##opcode -enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) }; - -/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and -study.c that all opcodes are less than 128 in value. This makes handling UTF-8 -character sequences easier. */ - -/* The highest extraction number before we have to start using additional -bytes. (Originally PCRE didn't have support for extraction counts higher than -this number.) The value is limited by the number of opcodes left after OP_BRA, -i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional -opcodes. */ - -/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above -are in conflict! */ - -#define EXTRACT_BASIC_MAX 100 - -/* The code vector runs on as long as necessary after the end. */ - -struct JSRegExp { - unsigned options; - - unsigned short topBracket; - unsigned short topBackref; - - unsigned short firstByte; - unsigned short reqByte; -}; - -/* Internal shared data tables. These are tables that are used by more than one - of the exported public functions. They have to be "external" in the C sense, - but are not part of the PCRE public API. The data for these tables is in the - pcre_tables.c module. */ - -#define jsc_pcre_utf8_table1_size 6 - -extern const int jsc_pcre_utf8_table1[6]; -extern const int jsc_pcre_utf8_table2[6]; -extern const int jsc_pcre_utf8_table3[6]; -extern const unsigned char jsc_pcre_utf8_table4[0x40]; - -extern const unsigned char jsc_pcre_default_tables[tables_length]; - -static inline unsigned char toLowerCase(unsigned char c) -{ - static const unsigned char* lowerCaseChars = jsc_pcre_default_tables + lcc_offset; - return lowerCaseChars[c]; -} - -static inline unsigned char flipCase(unsigned char c) -{ - static const unsigned char* flippedCaseChars = jsc_pcre_default_tables + fcc_offset; - return flippedCaseChars[c]; -} - -static inline unsigned char classBitmapForChar(unsigned char c) -{ - static const unsigned char* charClassBitmaps = jsc_pcre_default_tables + cbits_offset; - return charClassBitmaps[c]; -} - -static inline unsigned char charTypeForChar(unsigned char c) -{ - const unsigned char* charTypeMap = jsc_pcre_default_tables + ctypes_offset; - return charTypeMap[c]; -} - -static inline bool isWordChar(UChar c) -{ - return c < 128 && (charTypeForChar(c) & ctype_word); -} - -static inline bool isSpaceChar(UChar c) -{ - return (c < 128 && (charTypeForChar(c) & ctype_space)) || c == 0x00A0; -} - -static inline bool isNewline(UChar nl) -{ - return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029); -} - -static inline bool isBracketStartOpcode(unsigned char opcode) -{ - if (opcode >= OP_BRA) - return true; - switch (opcode) { - case OP_ASSERT: - case OP_ASSERT_NOT: - return true; - default: - return false; - } -} - -static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr) -{ - JS_ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT); - do - opcodePtr += getLinkValue(opcodePtr + 1); - while (*opcodePtr == OP_ALT); -} - -/* Internal shared functions. These are functions that are used in more -that one of the source files. They have to have external linkage, but -but are not part of the public API and so not exported from the library. */ - -extern int jsc_pcre_ucp_othercase(unsigned); -extern bool jsc_pcre_xclass(int, const unsigned char*); - -#endif - -#endif - -/* End of pcre_internal.h */ diff --git a/js/src/yarr/pcre/pcre_tables.cpp b/js/src/yarr/pcre/pcre_tables.cpp deleted file mode 100644 index b1ac229d5912..000000000000 --- a/js/src/yarr/pcre/pcre_tables.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains some fixed tables that are used by more than one of the -PCRE code modules. */ - -#include "pcre_internal.h" - -/************************************************* -* Tables for UTF-8 support * -*************************************************/ - -/* These are the breakpoints for different numbers of bytes in a UTF-8 -character. */ - -const int jsc_pcre_utf8_table1[6] = - { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; - -/* These are the indicator bits and the mask for the data bits to set in the -first byte of a character, indexed by the number of additional bytes. */ - -const int jsc_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; -const int jsc_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; - -/* Table of the number of extra characters, indexed by the first character -masked with 0x3f. The highest number for a valid UTF-8 character is in fact -0x3d. */ - -const unsigned char jsc_pcre_utf8_table4[0x40] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; - -#include "chartables.c" diff --git a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp deleted file mode 100644 index b97db921c981..000000000000 --- a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains code for searching the table of Unicode character -properties. */ - -#include "pcre_internal.h" - -#include "ucpinternal.h" /* Internal table details */ -#include "ucptable.cpp" /* The table itself */ - -/************************************************* -* Search table and return other case * -*************************************************/ - -/* If the given character is a letter, and there is another case for the -letter, return the other case. Otherwise, return -1. - -Arguments: - c the character value - -Returns: the other case or -1 if none -*/ - -int jsc_pcre_ucp_othercase(unsigned c) -{ - int bot = 0; - int top = sizeof(ucp_table) / sizeof(cnode); - int mid; - - /* The table is searched using a binary chop. You might think that using - intermediate variables to hold some of the common expressions would speed - things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it - makes things a lot slower. */ - - for (;;) { - if (top <= bot) - return -1; - mid = (bot + top) >> 1; - if (c == (ucp_table[mid].f0 & f0_charmask)) - break; - if (c < (ucp_table[mid].f0 & f0_charmask)) - top = mid; - else { - if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask))) - break; - bot = mid + 1; - } - } - - /* Found an entry in the table. Return -1 for a range entry. Otherwise return - the other case if there is one, else -1. */ - - if (ucp_table[mid].f0 & f0_rangeflag) - return -1; - - int offset = ucp_table[mid].f1 & f1_casemask; - if (offset & f1_caseneg) - offset |= f1_caseneg; - return !offset ? -1 : c + offset; -} diff --git a/js/src/yarr/pcre/pcre_xclass.cpp b/js/src/yarr/pcre/pcre_xclass.cpp deleted file mode 100644 index 8e59018ead0c..000000000000 --- a/js/src/yarr/pcre/pcre_xclass.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains an internal function that is used to match an extended -class (one that contains characters whose values are > 255). */ - -#include "pcre_internal.h" - -/************************************************* -* Match character against an XCLASS * -*************************************************/ - -/* This function is called to match a character against an extended class that -might contain values > 255. - -Arguments: - c the character - data points to the flag byte of the XCLASS data - -Returns: true if character matches, else false -*/ - -/* Get the next UTF-8 character, advancing the pointer. This is called when we - know we are in UTF-8 mode. */ - -static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr) -{ - c = *subjectPtr++; - if ((c & 0xc0) == 0xc0) { - int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ - int gcss = 6 * gcaa; - c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; - while (gcaa-- > 0) { - gcss -= 6; - c |= (*subjectPtr++ & 0x3f) << gcss; - } - } -} - -bool jsc_pcre_xclass(int c, const unsigned char* data) -{ - bool negated = (*data & XCL_NOT); - - /* Character values < 256 are matched against a bitmap, if one is present. If - not, we still carry on, because there may be ranges that start below 256 in the - additional data. */ - - if (c < 256) { - if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) - return !negated; /* char found */ - } - - /* First skip the bit map if present. Then match against the list of Unicode - properties or large chars or ranges that end with a large char. We won't ever - encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ - - if ((*data++ & XCL_MAP) != 0) - data += 32; - - int t; - while ((t = *data++) != XCL_END) { - if (t == XCL_SINGLE) { - int x; - getUTF8CharAndAdvancePointer(x, data); - if (c == x) - return !negated; - } - else if (t == XCL_RANGE) { - int x, y; - getUTF8CharAndAdvancePointer(x, data); - getUTF8CharAndAdvancePointer(y, data); - if (c >= x && c <= y) - return !negated; - } - } - - return negated; /* char did not match */ -} diff --git a/js/src/yarr/pcre/ucpinternal.h b/js/src/yarr/pcre/ucpinternal.h deleted file mode 100644 index c8bc4aab679c..000000000000 --- a/js/src/yarr/pcre/ucpinternal.h +++ /dev/null @@ -1,126 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/************************************************* -* Unicode Property Table handler * -*************************************************/ - -/* Internal header file defining the layout of the bits in each pair of 32-bit -words that form a data item in the table. */ - -typedef struct cnode { - unsigned f0; - unsigned f1; -} cnode; - -/* Things for the f0 field */ - -#define f0_scriptmask 0xff000000 /* Mask for script field */ -#define f0_scriptshift 24 /* Shift for script value */ -#define f0_rangeflag 0x00f00000 /* Flag for a range item */ -#define f0_charmask 0x001fffff /* Mask for code point value */ - -/* Things for the f1 field */ - -#define f1_typemask 0xfc000000 /* Mask for char type field */ -#define f1_typeshift 26 /* Shift for the type field */ -#define f1_rangemask 0x0000ffff /* Mask for a range offset */ -#define f1_casemask 0x0000ffff /* Mask for a case offset */ -#define f1_caseneg 0xffff8000 /* Bits for negation */ - -/* The data consists of a vector of structures of type cnode. The two unsigned -32-bit integers are used as follows: - -(f0) (1) The most significant byte holds the script number. The numbers are - defined by the enum in ucp.h. - - (2) The 0x00800000 bit is set if this entry defines a range of characters. - It is not set if this entry defines a single character - - (3) The 0x00600000 bits are spare. - - (4) The 0x001fffff bits contain the code point. No Unicode code point will - ever be greater than 0x0010ffff, so this should be OK for ever. - -(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are - defined by an enum in ucp.h. - - (2) The 0x03ff0000 bits are spare. - - (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of - range if this entry defines a range, OR the *signed* offset to the - character's "other case" partner if this entry defines a single - character. There is no partner if the value is zero. - -------------------------------------------------------------------------------- -| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) | -------------------------------------------------------------------------------- - | | | | | - | | |-> spare | |-> spare - | | | - | |-> spare |-> spare - | - |-> range flag - -The upper/lower casing information is set only for characters that come in -pairs. The non-one-to-one mappings in the Unicode data are ignored. - -When searching the data, proceed as follows: - -(1) Set up for a binary chop search. - -(2) If the top is not greater than the bottom, the character is not in the - table. Its type must therefore be "Cn" ("Undefined"). - -(3) Find the middle vector element. - -(4) Extract the code point and compare. If equal, we are done. - -(5) If the test character is smaller, set the top to the current point, and - goto (2). - -(6) If the current entry defines a range, compute the last character by adding - the offset, and see if the test character is within the range. If it is, - we are done. - -(7) Otherwise, set the bottom to one element past the current point and goto - (2). -*/ - -/* End of ucpinternal.h */ diff --git a/js/src/yarr/pcre/ucptable.cpp b/js/src/yarr/pcre/ucptable.cpp deleted file mode 100644 index 011f7f572443..000000000000 --- a/js/src/yarr/pcre/ucptable.cpp +++ /dev/null @@ -1,2968 +0,0 @@ -/* This source module is automatically generated from the Unicode -property table. See ucpinternal.h for a description of the layout. */ - -static const cnode ucp_table[] = { - { 0x09800000, 0x0000001f }, - { 0x09000020, 0x74000000 }, - { 0x09800021, 0x54000002 }, - { 0x09000024, 0x5c000000 }, - { 0x09800025, 0x54000002 }, - { 0x09000028, 0x58000000 }, - { 0x09000029, 0x48000000 }, - { 0x0900002a, 0x54000000 }, - { 0x0900002b, 0x64000000 }, - { 0x0900002c, 0x54000000 }, - { 0x0900002d, 0x44000000 }, - { 0x0980002e, 0x54000001 }, - { 0x09800030, 0x34000009 }, - { 0x0980003a, 0x54000001 }, - { 0x0980003c, 0x64000002 }, - { 0x0980003f, 0x54000001 }, - { 0x21000041, 0x24000020 }, - { 0x21000042, 0x24000020 }, - { 0x21000043, 0x24000020 }, - { 0x21000044, 0x24000020 }, - { 0x21000045, 0x24000020 }, - { 0x21000046, 0x24000020 }, - { 0x21000047, 0x24000020 }, - { 0x21000048, 0x24000020 }, - { 0x21000049, 0x24000020 }, - { 0x2100004a, 0x24000020 }, - { 0x2100004b, 0x24000020 }, - { 0x2100004c, 0x24000020 }, - { 0x2100004d, 0x24000020 }, - { 0x2100004e, 0x24000020 }, - { 0x2100004f, 0x24000020 }, - { 0x21000050, 0x24000020 }, - { 0x21000051, 0x24000020 }, - { 0x21000052, 0x24000020 }, - { 0x21000053, 0x24000020 }, - { 0x21000054, 0x24000020 }, - { 0x21000055, 0x24000020 }, - { 0x21000056, 0x24000020 }, - { 0x21000057, 0x24000020 }, - { 0x21000058, 0x24000020 }, - { 0x21000059, 0x24000020 }, - { 0x2100005a, 0x24000020 }, - { 0x0900005b, 0x58000000 }, - { 0x0900005c, 0x54000000 }, - { 0x0900005d, 0x48000000 }, - { 0x0900005e, 0x60000000 }, - { 0x0900005f, 0x40000000 }, - { 0x09000060, 0x60000000 }, - { 0x21000061, 0x1400ffe0 }, - { 0x21000062, 0x1400ffe0 }, - { 0x21000063, 0x1400ffe0 }, - { 0x21000064, 0x1400ffe0 }, - { 0x21000065, 0x1400ffe0 }, - { 0x21000066, 0x1400ffe0 }, - { 0x21000067, 0x1400ffe0 }, - { 0x21000068, 0x1400ffe0 }, - { 0x21000069, 0x1400ffe0 }, - { 0x2100006a, 0x1400ffe0 }, - { 0x2100006b, 0x1400ffe0 }, - { 0x2100006c, 0x1400ffe0 }, - { 0x2100006d, 0x1400ffe0 }, - { 0x2100006e, 0x1400ffe0 }, - { 0x2100006f, 0x1400ffe0 }, - { 0x21000070, 0x1400ffe0 }, - { 0x21000071, 0x1400ffe0 }, - { 0x21000072, 0x1400ffe0 }, - { 0x21000073, 0x1400ffe0 }, - { 0x21000074, 0x1400ffe0 }, - { 0x21000075, 0x1400ffe0 }, - { 0x21000076, 0x1400ffe0 }, - { 0x21000077, 0x1400ffe0 }, - { 0x21000078, 0x1400ffe0 }, - { 0x21000079, 0x1400ffe0 }, - { 0x2100007a, 0x1400ffe0 }, - { 0x0900007b, 0x58000000 }, - { 0x0900007c, 0x64000000 }, - { 0x0900007d, 0x48000000 }, - { 0x0900007e, 0x64000000 }, - { 0x0980007f, 0x00000020 }, - { 0x090000a0, 0x74000000 }, - { 0x090000a1, 0x54000000 }, - { 0x098000a2, 0x5c000003 }, - { 0x098000a6, 0x68000001 }, - { 0x090000a8, 0x60000000 }, - { 0x090000a9, 0x68000000 }, - { 0x210000aa, 0x14000000 }, - { 0x090000ab, 0x50000000 }, - { 0x090000ac, 0x64000000 }, - { 0x090000ad, 0x04000000 }, - { 0x090000ae, 0x68000000 }, - { 0x090000af, 0x60000000 }, - { 0x090000b0, 0x68000000 }, - { 0x090000b1, 0x64000000 }, - { 0x098000b2, 0x3c000001 }, - { 0x090000b4, 0x60000000 }, - { 0x090000b5, 0x140002e7 }, - { 0x090000b6, 0x68000000 }, - { 0x090000b7, 0x54000000 }, - { 0x090000b8, 0x60000000 }, - { 0x090000b9, 0x3c000000 }, - { 0x210000ba, 0x14000000 }, - { 0x090000bb, 0x4c000000 }, - { 0x098000bc, 0x3c000002 }, - { 0x090000bf, 0x54000000 }, - { 0x210000c0, 0x24000020 }, - { 0x210000c1, 0x24000020 }, - { 0x210000c2, 0x24000020 }, - { 0x210000c3, 0x24000020 }, - { 0x210000c4, 0x24000020 }, - { 0x210000c5, 0x24000020 }, - { 0x210000c6, 0x24000020 }, - { 0x210000c7, 0x24000020 }, - { 0x210000c8, 0x24000020 }, - { 0x210000c9, 0x24000020 }, - { 0x210000ca, 0x24000020 }, - { 0x210000cb, 0x24000020 }, - { 0x210000cc, 0x24000020 }, - { 0x210000cd, 0x24000020 }, - { 0x210000ce, 0x24000020 }, - { 0x210000cf, 0x24000020 }, - { 0x210000d0, 0x24000020 }, - { 0x210000d1, 0x24000020 }, - { 0x210000d2, 0x24000020 }, - { 0x210000d3, 0x24000020 }, - { 0x210000d4, 0x24000020 }, - { 0x210000d5, 0x24000020 }, - { 0x210000d6, 0x24000020 }, - { 0x090000d7, 0x64000000 }, - { 0x210000d8, 0x24000020 }, - { 0x210000d9, 0x24000020 }, - { 0x210000da, 0x24000020 }, - { 0x210000db, 0x24000020 }, - { 0x210000dc, 0x24000020 }, - { 0x210000dd, 0x24000020 }, - { 0x210000de, 0x24000020 }, - { 0x210000df, 0x14000000 }, - { 0x210000e0, 0x1400ffe0 }, - { 0x210000e1, 0x1400ffe0 }, - { 0x210000e2, 0x1400ffe0 }, - { 0x210000e3, 0x1400ffe0 }, - { 0x210000e4, 0x1400ffe0 }, - { 0x210000e5, 0x1400ffe0 }, - { 0x210000e6, 0x1400ffe0 }, - { 0x210000e7, 0x1400ffe0 }, - { 0x210000e8, 0x1400ffe0 }, - { 0x210000e9, 0x1400ffe0 }, - { 0x210000ea, 0x1400ffe0 }, - { 0x210000eb, 0x1400ffe0 }, - { 0x210000ec, 0x1400ffe0 }, - { 0x210000ed, 0x1400ffe0 }, - { 0x210000ee, 0x1400ffe0 }, - { 0x210000ef, 0x1400ffe0 }, - { 0x210000f0, 0x1400ffe0 }, - { 0x210000f1, 0x1400ffe0 }, - { 0x210000f2, 0x1400ffe0 }, - { 0x210000f3, 0x1400ffe0 }, - { 0x210000f4, 0x1400ffe0 }, - { 0x210000f5, 0x1400ffe0 }, - { 0x210000f6, 0x1400ffe0 }, - { 0x090000f7, 0x64000000 }, - { 0x210000f8, 0x1400ffe0 }, - { 0x210000f9, 0x1400ffe0 }, - { 0x210000fa, 0x1400ffe0 }, - { 0x210000fb, 0x1400ffe0 }, - { 0x210000fc, 0x1400ffe0 }, - { 0x210000fd, 0x1400ffe0 }, - { 0x210000fe, 0x1400ffe0 }, - { 0x210000ff, 0x14000079 }, - { 0x21000100, 0x24000001 }, - { 0x21000101, 0x1400ffff }, - { 0x21000102, 0x24000001 }, - { 0x21000103, 0x1400ffff }, - { 0x21000104, 0x24000001 }, - { 0x21000105, 0x1400ffff }, - { 0x21000106, 0x24000001 }, - { 0x21000107, 0x1400ffff }, - { 0x21000108, 0x24000001 }, - { 0x21000109, 0x1400ffff }, - { 0x2100010a, 0x24000001 }, - { 0x2100010b, 0x1400ffff }, - { 0x2100010c, 0x24000001 }, - { 0x2100010d, 0x1400ffff }, - { 0x2100010e, 0x24000001 }, - { 0x2100010f, 0x1400ffff }, - { 0x21000110, 0x24000001 }, - { 0x21000111, 0x1400ffff }, - { 0x21000112, 0x24000001 }, - { 0x21000113, 0x1400ffff }, - { 0x21000114, 0x24000001 }, - { 0x21000115, 0x1400ffff }, - { 0x21000116, 0x24000001 }, - { 0x21000117, 0x1400ffff }, - { 0x21000118, 0x24000001 }, - { 0x21000119, 0x1400ffff }, - { 0x2100011a, 0x24000001 }, - { 0x2100011b, 0x1400ffff }, - { 0x2100011c, 0x24000001 }, - { 0x2100011d, 0x1400ffff }, - { 0x2100011e, 0x24000001 }, - { 0x2100011f, 0x1400ffff }, - { 0x21000120, 0x24000001 }, - { 0x21000121, 0x1400ffff }, - { 0x21000122, 0x24000001 }, - { 0x21000123, 0x1400ffff }, - { 0x21000124, 0x24000001 }, - { 0x21000125, 0x1400ffff }, - { 0x21000126, 0x24000001 }, - { 0x21000127, 0x1400ffff }, - { 0x21000128, 0x24000001 }, - { 0x21000129, 0x1400ffff }, - { 0x2100012a, 0x24000001 }, - { 0x2100012b, 0x1400ffff }, - { 0x2100012c, 0x24000001 }, - { 0x2100012d, 0x1400ffff }, - { 0x2100012e, 0x24000001 }, - { 0x2100012f, 0x1400ffff }, - { 0x21000130, 0x2400ff39 }, - { 0x21000131, 0x1400ff18 }, - { 0x21000132, 0x24000001 }, - { 0x21000133, 0x1400ffff }, - { 0x21000134, 0x24000001 }, - { 0x21000135, 0x1400ffff }, - { 0x21000136, 0x24000001 }, - { 0x21000137, 0x1400ffff }, - { 0x21000138, 0x14000000 }, - { 0x21000139, 0x24000001 }, - { 0x2100013a, 0x1400ffff }, - { 0x2100013b, 0x24000001 }, - { 0x2100013c, 0x1400ffff }, - { 0x2100013d, 0x24000001 }, - { 0x2100013e, 0x1400ffff }, - { 0x2100013f, 0x24000001 }, - { 0x21000140, 0x1400ffff }, - { 0x21000141, 0x24000001 }, - { 0x21000142, 0x1400ffff }, - { 0x21000143, 0x24000001 }, - { 0x21000144, 0x1400ffff }, - { 0x21000145, 0x24000001 }, - { 0x21000146, 0x1400ffff }, - { 0x21000147, 0x24000001 }, - { 0x21000148, 0x1400ffff }, - { 0x21000149, 0x14000000 }, - { 0x2100014a, 0x24000001 }, - { 0x2100014b, 0x1400ffff }, - { 0x2100014c, 0x24000001 }, - { 0x2100014d, 0x1400ffff }, - { 0x2100014e, 0x24000001 }, - { 0x2100014f, 0x1400ffff }, - { 0x21000150, 0x24000001 }, - { 0x21000151, 0x1400ffff }, - { 0x21000152, 0x24000001 }, - { 0x21000153, 0x1400ffff }, - { 0x21000154, 0x24000001 }, - { 0x21000155, 0x1400ffff }, - { 0x21000156, 0x24000001 }, - { 0x21000157, 0x1400ffff }, - { 0x21000158, 0x24000001 }, - { 0x21000159, 0x1400ffff }, - { 0x2100015a, 0x24000001 }, - { 0x2100015b, 0x1400ffff }, - { 0x2100015c, 0x24000001 }, - { 0x2100015d, 0x1400ffff }, - { 0x2100015e, 0x24000001 }, - { 0x2100015f, 0x1400ffff }, - { 0x21000160, 0x24000001 }, - { 0x21000161, 0x1400ffff }, - { 0x21000162, 0x24000001 }, - { 0x21000163, 0x1400ffff }, - { 0x21000164, 0x24000001 }, - { 0x21000165, 0x1400ffff }, - { 0x21000166, 0x24000001 }, - { 0x21000167, 0x1400ffff }, - { 0x21000168, 0x24000001 }, - { 0x21000169, 0x1400ffff }, - { 0x2100016a, 0x24000001 }, - { 0x2100016b, 0x1400ffff }, - { 0x2100016c, 0x24000001 }, - { 0x2100016d, 0x1400ffff }, - { 0x2100016e, 0x24000001 }, - { 0x2100016f, 0x1400ffff }, - { 0x21000170, 0x24000001 }, - { 0x21000171, 0x1400ffff }, - { 0x21000172, 0x24000001 }, - { 0x21000173, 0x1400ffff }, - { 0x21000174, 0x24000001 }, - { 0x21000175, 0x1400ffff }, - { 0x21000176, 0x24000001 }, - { 0x21000177, 0x1400ffff }, - { 0x21000178, 0x2400ff87 }, - { 0x21000179, 0x24000001 }, - { 0x2100017a, 0x1400ffff }, - { 0x2100017b, 0x24000001 }, - { 0x2100017c, 0x1400ffff }, - { 0x2100017d, 0x24000001 }, - { 0x2100017e, 0x1400ffff }, - { 0x2100017f, 0x1400fed4 }, - { 0x21000180, 0x14000000 }, - { 0x21000181, 0x240000d2 }, - { 0x21000182, 0x24000001 }, - { 0x21000183, 0x1400ffff }, - { 0x21000184, 0x24000001 }, - { 0x21000185, 0x1400ffff }, - { 0x21000186, 0x240000ce }, - { 0x21000187, 0x24000001 }, - { 0x21000188, 0x1400ffff }, - { 0x21000189, 0x240000cd }, - { 0x2100018a, 0x240000cd }, - { 0x2100018b, 0x24000001 }, - { 0x2100018c, 0x1400ffff }, - { 0x2100018d, 0x14000000 }, - { 0x2100018e, 0x2400004f }, - { 0x2100018f, 0x240000ca }, - { 0x21000190, 0x240000cb }, - { 0x21000191, 0x24000001 }, - { 0x21000192, 0x1400ffff }, - { 0x21000193, 0x240000cd }, - { 0x21000194, 0x240000cf }, - { 0x21000195, 0x14000061 }, - { 0x21000196, 0x240000d3 }, - { 0x21000197, 0x240000d1 }, - { 0x21000198, 0x24000001 }, - { 0x21000199, 0x1400ffff }, - { 0x2100019a, 0x140000a3 }, - { 0x2100019b, 0x14000000 }, - { 0x2100019c, 0x240000d3 }, - { 0x2100019d, 0x240000d5 }, - { 0x2100019e, 0x14000082 }, - { 0x2100019f, 0x240000d6 }, - { 0x210001a0, 0x24000001 }, - { 0x210001a1, 0x1400ffff }, - { 0x210001a2, 0x24000001 }, - { 0x210001a3, 0x1400ffff }, - { 0x210001a4, 0x24000001 }, - { 0x210001a5, 0x1400ffff }, - { 0x210001a6, 0x240000da }, - { 0x210001a7, 0x24000001 }, - { 0x210001a8, 0x1400ffff }, - { 0x210001a9, 0x240000da }, - { 0x218001aa, 0x14000001 }, - { 0x210001ac, 0x24000001 }, - { 0x210001ad, 0x1400ffff }, - { 0x210001ae, 0x240000da }, - { 0x210001af, 0x24000001 }, - { 0x210001b0, 0x1400ffff }, - { 0x210001b1, 0x240000d9 }, - { 0x210001b2, 0x240000d9 }, - { 0x210001b3, 0x24000001 }, - { 0x210001b4, 0x1400ffff }, - { 0x210001b5, 0x24000001 }, - { 0x210001b6, 0x1400ffff }, - { 0x210001b7, 0x240000db }, - { 0x210001b8, 0x24000001 }, - { 0x210001b9, 0x1400ffff }, - { 0x210001ba, 0x14000000 }, - { 0x210001bb, 0x1c000000 }, - { 0x210001bc, 0x24000001 }, - { 0x210001bd, 0x1400ffff }, - { 0x210001be, 0x14000000 }, - { 0x210001bf, 0x14000038 }, - { 0x218001c0, 0x1c000003 }, - { 0x210001c4, 0x24000002 }, - { 0x210001c5, 0x2000ffff }, - { 0x210001c6, 0x1400fffe }, - { 0x210001c7, 0x24000002 }, - { 0x210001c8, 0x2000ffff }, - { 0x210001c9, 0x1400fffe }, - { 0x210001ca, 0x24000002 }, - { 0x210001cb, 0x2000ffff }, - { 0x210001cc, 0x1400fffe }, - { 0x210001cd, 0x24000001 }, - { 0x210001ce, 0x1400ffff }, - { 0x210001cf, 0x24000001 }, - { 0x210001d0, 0x1400ffff }, - { 0x210001d1, 0x24000001 }, - { 0x210001d2, 0x1400ffff }, - { 0x210001d3, 0x24000001 }, - { 0x210001d4, 0x1400ffff }, - { 0x210001d5, 0x24000001 }, - { 0x210001d6, 0x1400ffff }, - { 0x210001d7, 0x24000001 }, - { 0x210001d8, 0x1400ffff }, - { 0x210001d9, 0x24000001 }, - { 0x210001da, 0x1400ffff }, - { 0x210001db, 0x24000001 }, - { 0x210001dc, 0x1400ffff }, - { 0x210001dd, 0x1400ffb1 }, - { 0x210001de, 0x24000001 }, - { 0x210001df, 0x1400ffff }, - { 0x210001e0, 0x24000001 }, - { 0x210001e1, 0x1400ffff }, - { 0x210001e2, 0x24000001 }, - { 0x210001e3, 0x1400ffff }, - { 0x210001e4, 0x24000001 }, - { 0x210001e5, 0x1400ffff }, - { 0x210001e6, 0x24000001 }, - { 0x210001e7, 0x1400ffff }, - { 0x210001e8, 0x24000001 }, - { 0x210001e9, 0x1400ffff }, - { 0x210001ea, 0x24000001 }, - { 0x210001eb, 0x1400ffff }, - { 0x210001ec, 0x24000001 }, - { 0x210001ed, 0x1400ffff }, - { 0x210001ee, 0x24000001 }, - { 0x210001ef, 0x1400ffff }, - { 0x210001f0, 0x14000000 }, - { 0x210001f1, 0x24000002 }, - { 0x210001f2, 0x2000ffff }, - { 0x210001f3, 0x1400fffe }, - { 0x210001f4, 0x24000001 }, - { 0x210001f5, 0x1400ffff }, - { 0x210001f6, 0x2400ff9f }, - { 0x210001f7, 0x2400ffc8 }, - { 0x210001f8, 0x24000001 }, - { 0x210001f9, 0x1400ffff }, - { 0x210001fa, 0x24000001 }, - { 0x210001fb, 0x1400ffff }, - { 0x210001fc, 0x24000001 }, - { 0x210001fd, 0x1400ffff }, - { 0x210001fe, 0x24000001 }, - { 0x210001ff, 0x1400ffff }, - { 0x21000200, 0x24000001 }, - { 0x21000201, 0x1400ffff }, - { 0x21000202, 0x24000001 }, - { 0x21000203, 0x1400ffff }, - { 0x21000204, 0x24000001 }, - { 0x21000205, 0x1400ffff }, - { 0x21000206, 0x24000001 }, - { 0x21000207, 0x1400ffff }, - { 0x21000208, 0x24000001 }, - { 0x21000209, 0x1400ffff }, - { 0x2100020a, 0x24000001 }, - { 0x2100020b, 0x1400ffff }, - { 0x2100020c, 0x24000001 }, - { 0x2100020d, 0x1400ffff }, - { 0x2100020e, 0x24000001 }, - { 0x2100020f, 0x1400ffff }, - { 0x21000210, 0x24000001 }, - { 0x21000211, 0x1400ffff }, - { 0x21000212, 0x24000001 }, - { 0x21000213, 0x1400ffff }, - { 0x21000214, 0x24000001 }, - { 0x21000215, 0x1400ffff }, - { 0x21000216, 0x24000001 }, - { 0x21000217, 0x1400ffff }, - { 0x21000218, 0x24000001 }, - { 0x21000219, 0x1400ffff }, - { 0x2100021a, 0x24000001 }, - { 0x2100021b, 0x1400ffff }, - { 0x2100021c, 0x24000001 }, - { 0x2100021d, 0x1400ffff }, - { 0x2100021e, 0x24000001 }, - { 0x2100021f, 0x1400ffff }, - { 0x21000220, 0x2400ff7e }, - { 0x21000221, 0x14000000 }, - { 0x21000222, 0x24000001 }, - { 0x21000223, 0x1400ffff }, - { 0x21000224, 0x24000001 }, - { 0x21000225, 0x1400ffff }, - { 0x21000226, 0x24000001 }, - { 0x21000227, 0x1400ffff }, - { 0x21000228, 0x24000001 }, - { 0x21000229, 0x1400ffff }, - { 0x2100022a, 0x24000001 }, - { 0x2100022b, 0x1400ffff }, - { 0x2100022c, 0x24000001 }, - { 0x2100022d, 0x1400ffff }, - { 0x2100022e, 0x24000001 }, - { 0x2100022f, 0x1400ffff }, - { 0x21000230, 0x24000001 }, - { 0x21000231, 0x1400ffff }, - { 0x21000232, 0x24000001 }, - { 0x21000233, 0x1400ffff }, - { 0x21800234, 0x14000005 }, - { 0x2100023a, 0x24000000 }, - { 0x2100023b, 0x24000001 }, - { 0x2100023c, 0x1400ffff }, - { 0x2100023d, 0x2400ff5d }, - { 0x2100023e, 0x24000000 }, - { 0x2180023f, 0x14000001 }, - { 0x21000241, 0x24000053 }, - { 0x21800250, 0x14000002 }, - { 0x21000253, 0x1400ff2e }, - { 0x21000254, 0x1400ff32 }, - { 0x21000255, 0x14000000 }, - { 0x21000256, 0x1400ff33 }, - { 0x21000257, 0x1400ff33 }, - { 0x21000258, 0x14000000 }, - { 0x21000259, 0x1400ff36 }, - { 0x2100025a, 0x14000000 }, - { 0x2100025b, 0x1400ff35 }, - { 0x2180025c, 0x14000003 }, - { 0x21000260, 0x1400ff33 }, - { 0x21800261, 0x14000001 }, - { 0x21000263, 0x1400ff31 }, - { 0x21800264, 0x14000003 }, - { 0x21000268, 0x1400ff2f }, - { 0x21000269, 0x1400ff2d }, - { 0x2180026a, 0x14000004 }, - { 0x2100026f, 0x1400ff2d }, - { 0x21800270, 0x14000001 }, - { 0x21000272, 0x1400ff2b }, - { 0x21800273, 0x14000001 }, - { 0x21000275, 0x1400ff2a }, - { 0x21800276, 0x14000009 }, - { 0x21000280, 0x1400ff26 }, - { 0x21800281, 0x14000001 }, - { 0x21000283, 0x1400ff26 }, - { 0x21800284, 0x14000003 }, - { 0x21000288, 0x1400ff26 }, - { 0x21000289, 0x14000000 }, - { 0x2100028a, 0x1400ff27 }, - { 0x2100028b, 0x1400ff27 }, - { 0x2180028c, 0x14000005 }, - { 0x21000292, 0x1400ff25 }, - { 0x21000293, 0x14000000 }, - { 0x21000294, 0x1400ffad }, - { 0x21800295, 0x1400001a }, - { 0x218002b0, 0x18000011 }, - { 0x098002c2, 0x60000003 }, - { 0x098002c6, 0x1800000b }, - { 0x098002d2, 0x6000000d }, - { 0x218002e0, 0x18000004 }, - { 0x098002e5, 0x60000008 }, - { 0x090002ee, 0x18000000 }, - { 0x098002ef, 0x60000010 }, - { 0x1b800300, 0x30000044 }, - { 0x1b000345, 0x30000054 }, - { 0x1b800346, 0x30000029 }, - { 0x13800374, 0x60000001 }, - { 0x1300037a, 0x18000000 }, - { 0x0900037e, 0x54000000 }, - { 0x13800384, 0x60000001 }, - { 0x13000386, 0x24000026 }, - { 0x09000387, 0x54000000 }, - { 0x13000388, 0x24000025 }, - { 0x13000389, 0x24000025 }, - { 0x1300038a, 0x24000025 }, - { 0x1300038c, 0x24000040 }, - { 0x1300038e, 0x2400003f }, - { 0x1300038f, 0x2400003f }, - { 0x13000390, 0x14000000 }, - { 0x13000391, 0x24000020 }, - { 0x13000392, 0x24000020 }, - { 0x13000393, 0x24000020 }, - { 0x13000394, 0x24000020 }, - { 0x13000395, 0x24000020 }, - { 0x13000396, 0x24000020 }, - { 0x13000397, 0x24000020 }, - { 0x13000398, 0x24000020 }, - { 0x13000399, 0x24000020 }, - { 0x1300039a, 0x24000020 }, - { 0x1300039b, 0x24000020 }, - { 0x1300039c, 0x24000020 }, - { 0x1300039d, 0x24000020 }, - { 0x1300039e, 0x24000020 }, - { 0x1300039f, 0x24000020 }, - { 0x130003a0, 0x24000020 }, - { 0x130003a1, 0x24000020 }, - { 0x130003a3, 0x24000020 }, - { 0x130003a4, 0x24000020 }, - { 0x130003a5, 0x24000020 }, - { 0x130003a6, 0x24000020 }, - { 0x130003a7, 0x24000020 }, - { 0x130003a8, 0x24000020 }, - { 0x130003a9, 0x24000020 }, - { 0x130003aa, 0x24000020 }, - { 0x130003ab, 0x24000020 }, - { 0x130003ac, 0x1400ffda }, - { 0x130003ad, 0x1400ffdb }, - { 0x130003ae, 0x1400ffdb }, - { 0x130003af, 0x1400ffdb }, - { 0x130003b0, 0x14000000 }, - { 0x130003b1, 0x1400ffe0 }, - { 0x130003b2, 0x1400ffe0 }, - { 0x130003b3, 0x1400ffe0 }, - { 0x130003b4, 0x1400ffe0 }, - { 0x130003b5, 0x1400ffe0 }, - { 0x130003b6, 0x1400ffe0 }, - { 0x130003b7, 0x1400ffe0 }, - { 0x130003b8, 0x1400ffe0 }, - { 0x130003b9, 0x1400ffe0 }, - { 0x130003ba, 0x1400ffe0 }, - { 0x130003bb, 0x1400ffe0 }, - { 0x130003bc, 0x1400ffe0 }, - { 0x130003bd, 0x1400ffe0 }, - { 0x130003be, 0x1400ffe0 }, - { 0x130003bf, 0x1400ffe0 }, - { 0x130003c0, 0x1400ffe0 }, - { 0x130003c1, 0x1400ffe0 }, - { 0x130003c2, 0x1400ffe1 }, - { 0x130003c3, 0x1400ffe0 }, - { 0x130003c4, 0x1400ffe0 }, - { 0x130003c5, 0x1400ffe0 }, - { 0x130003c6, 0x1400ffe0 }, - { 0x130003c7, 0x1400ffe0 }, - { 0x130003c8, 0x1400ffe0 }, - { 0x130003c9, 0x1400ffe0 }, - { 0x130003ca, 0x1400ffe0 }, - { 0x130003cb, 0x1400ffe0 }, - { 0x130003cc, 0x1400ffc0 }, - { 0x130003cd, 0x1400ffc1 }, - { 0x130003ce, 0x1400ffc1 }, - { 0x130003d0, 0x1400ffc2 }, - { 0x130003d1, 0x1400ffc7 }, - { 0x138003d2, 0x24000002 }, - { 0x130003d5, 0x1400ffd1 }, - { 0x130003d6, 0x1400ffca }, - { 0x130003d7, 0x14000000 }, - { 0x130003d8, 0x24000001 }, - { 0x130003d9, 0x1400ffff }, - { 0x130003da, 0x24000001 }, - { 0x130003db, 0x1400ffff }, - { 0x130003dc, 0x24000001 }, - { 0x130003dd, 0x1400ffff }, - { 0x130003de, 0x24000001 }, - { 0x130003df, 0x1400ffff }, - { 0x130003e0, 0x24000001 }, - { 0x130003e1, 0x1400ffff }, - { 0x0a0003e2, 0x24000001 }, - { 0x0a0003e3, 0x1400ffff }, - { 0x0a0003e4, 0x24000001 }, - { 0x0a0003e5, 0x1400ffff }, - { 0x0a0003e6, 0x24000001 }, - { 0x0a0003e7, 0x1400ffff }, - { 0x0a0003e8, 0x24000001 }, - { 0x0a0003e9, 0x1400ffff }, - { 0x0a0003ea, 0x24000001 }, - { 0x0a0003eb, 0x1400ffff }, - { 0x0a0003ec, 0x24000001 }, - { 0x0a0003ed, 0x1400ffff }, - { 0x0a0003ee, 0x24000001 }, - { 0x0a0003ef, 0x1400ffff }, - { 0x130003f0, 0x1400ffaa }, - { 0x130003f1, 0x1400ffb0 }, - { 0x130003f2, 0x14000007 }, - { 0x130003f3, 0x14000000 }, - { 0x130003f4, 0x2400ffc4 }, - { 0x130003f5, 0x1400ffa0 }, - { 0x130003f6, 0x64000000 }, - { 0x130003f7, 0x24000001 }, - { 0x130003f8, 0x1400ffff }, - { 0x130003f9, 0x2400fff9 }, - { 0x130003fa, 0x24000001 }, - { 0x130003fb, 0x1400ffff }, - { 0x130003fc, 0x14000000 }, - { 0x138003fd, 0x24000002 }, - { 0x0c000400, 0x24000050 }, - { 0x0c000401, 0x24000050 }, - { 0x0c000402, 0x24000050 }, - { 0x0c000403, 0x24000050 }, - { 0x0c000404, 0x24000050 }, - { 0x0c000405, 0x24000050 }, - { 0x0c000406, 0x24000050 }, - { 0x0c000407, 0x24000050 }, - { 0x0c000408, 0x24000050 }, - { 0x0c000409, 0x24000050 }, - { 0x0c00040a, 0x24000050 }, - { 0x0c00040b, 0x24000050 }, - { 0x0c00040c, 0x24000050 }, - { 0x0c00040d, 0x24000050 }, - { 0x0c00040e, 0x24000050 }, - { 0x0c00040f, 0x24000050 }, - { 0x0c000410, 0x24000020 }, - { 0x0c000411, 0x24000020 }, - { 0x0c000412, 0x24000020 }, - { 0x0c000413, 0x24000020 }, - { 0x0c000414, 0x24000020 }, - { 0x0c000415, 0x24000020 }, - { 0x0c000416, 0x24000020 }, - { 0x0c000417, 0x24000020 }, - { 0x0c000418, 0x24000020 }, - { 0x0c000419, 0x24000020 }, - { 0x0c00041a, 0x24000020 }, - { 0x0c00041b, 0x24000020 }, - { 0x0c00041c, 0x24000020 }, - { 0x0c00041d, 0x24000020 }, - { 0x0c00041e, 0x24000020 }, - { 0x0c00041f, 0x24000020 }, - { 0x0c000420, 0x24000020 }, - { 0x0c000421, 0x24000020 }, - { 0x0c000422, 0x24000020 }, - { 0x0c000423, 0x24000020 }, - { 0x0c000424, 0x24000020 }, - { 0x0c000425, 0x24000020 }, - { 0x0c000426, 0x24000020 }, - { 0x0c000427, 0x24000020 }, - { 0x0c000428, 0x24000020 }, - { 0x0c000429, 0x24000020 }, - { 0x0c00042a, 0x24000020 }, - { 0x0c00042b, 0x24000020 }, - { 0x0c00042c, 0x24000020 }, - { 0x0c00042d, 0x24000020 }, - { 0x0c00042e, 0x24000020 }, - { 0x0c00042f, 0x24000020 }, - { 0x0c000430, 0x1400ffe0 }, - { 0x0c000431, 0x1400ffe0 }, - { 0x0c000432, 0x1400ffe0 }, - { 0x0c000433, 0x1400ffe0 }, - { 0x0c000434, 0x1400ffe0 }, - { 0x0c000435, 0x1400ffe0 }, - { 0x0c000436, 0x1400ffe0 }, - { 0x0c000437, 0x1400ffe0 }, - { 0x0c000438, 0x1400ffe0 }, - { 0x0c000439, 0x1400ffe0 }, - { 0x0c00043a, 0x1400ffe0 }, - { 0x0c00043b, 0x1400ffe0 }, - { 0x0c00043c, 0x1400ffe0 }, - { 0x0c00043d, 0x1400ffe0 }, - { 0x0c00043e, 0x1400ffe0 }, - { 0x0c00043f, 0x1400ffe0 }, - { 0x0c000440, 0x1400ffe0 }, - { 0x0c000441, 0x1400ffe0 }, - { 0x0c000442, 0x1400ffe0 }, - { 0x0c000443, 0x1400ffe0 }, - { 0x0c000444, 0x1400ffe0 }, - { 0x0c000445, 0x1400ffe0 }, - { 0x0c000446, 0x1400ffe0 }, - { 0x0c000447, 0x1400ffe0 }, - { 0x0c000448, 0x1400ffe0 }, - { 0x0c000449, 0x1400ffe0 }, - { 0x0c00044a, 0x1400ffe0 }, - { 0x0c00044b, 0x1400ffe0 }, - { 0x0c00044c, 0x1400ffe0 }, - { 0x0c00044d, 0x1400ffe0 }, - { 0x0c00044e, 0x1400ffe0 }, - { 0x0c00044f, 0x1400ffe0 }, - { 0x0c000450, 0x1400ffb0 }, - { 0x0c000451, 0x1400ffb0 }, - { 0x0c000452, 0x1400ffb0 }, - { 0x0c000453, 0x1400ffb0 }, - { 0x0c000454, 0x1400ffb0 }, - { 0x0c000455, 0x1400ffb0 }, - { 0x0c000456, 0x1400ffb0 }, - { 0x0c000457, 0x1400ffb0 }, - { 0x0c000458, 0x1400ffb0 }, - { 0x0c000459, 0x1400ffb0 }, - { 0x0c00045a, 0x1400ffb0 }, - { 0x0c00045b, 0x1400ffb0 }, - { 0x0c00045c, 0x1400ffb0 }, - { 0x0c00045d, 0x1400ffb0 }, - { 0x0c00045e, 0x1400ffb0 }, - { 0x0c00045f, 0x1400ffb0 }, - { 0x0c000460, 0x24000001 }, - { 0x0c000461, 0x1400ffff }, - { 0x0c000462, 0x24000001 }, - { 0x0c000463, 0x1400ffff }, - { 0x0c000464, 0x24000001 }, - { 0x0c000465, 0x1400ffff }, - { 0x0c000466, 0x24000001 }, - { 0x0c000467, 0x1400ffff }, - { 0x0c000468, 0x24000001 }, - { 0x0c000469, 0x1400ffff }, - { 0x0c00046a, 0x24000001 }, - { 0x0c00046b, 0x1400ffff }, - { 0x0c00046c, 0x24000001 }, - { 0x0c00046d, 0x1400ffff }, - { 0x0c00046e, 0x24000001 }, - { 0x0c00046f, 0x1400ffff }, - { 0x0c000470, 0x24000001 }, - { 0x0c000471, 0x1400ffff }, - { 0x0c000472, 0x24000001 }, - { 0x0c000473, 0x1400ffff }, - { 0x0c000474, 0x24000001 }, - { 0x0c000475, 0x1400ffff }, - { 0x0c000476, 0x24000001 }, - { 0x0c000477, 0x1400ffff }, - { 0x0c000478, 0x24000001 }, - { 0x0c000479, 0x1400ffff }, - { 0x0c00047a, 0x24000001 }, - { 0x0c00047b, 0x1400ffff }, - { 0x0c00047c, 0x24000001 }, - { 0x0c00047d, 0x1400ffff }, - { 0x0c00047e, 0x24000001 }, - { 0x0c00047f, 0x1400ffff }, - { 0x0c000480, 0x24000001 }, - { 0x0c000481, 0x1400ffff }, - { 0x0c000482, 0x68000000 }, - { 0x0c800483, 0x30000003 }, - { 0x0c800488, 0x2c000001 }, - { 0x0c00048a, 0x24000001 }, - { 0x0c00048b, 0x1400ffff }, - { 0x0c00048c, 0x24000001 }, - { 0x0c00048d, 0x1400ffff }, - { 0x0c00048e, 0x24000001 }, - { 0x0c00048f, 0x1400ffff }, - { 0x0c000490, 0x24000001 }, - { 0x0c000491, 0x1400ffff }, - { 0x0c000492, 0x24000001 }, - { 0x0c000493, 0x1400ffff }, - { 0x0c000494, 0x24000001 }, - { 0x0c000495, 0x1400ffff }, - { 0x0c000496, 0x24000001 }, - { 0x0c000497, 0x1400ffff }, - { 0x0c000498, 0x24000001 }, - { 0x0c000499, 0x1400ffff }, - { 0x0c00049a, 0x24000001 }, - { 0x0c00049b, 0x1400ffff }, - { 0x0c00049c, 0x24000001 }, - { 0x0c00049d, 0x1400ffff }, - { 0x0c00049e, 0x24000001 }, - { 0x0c00049f, 0x1400ffff }, - { 0x0c0004a0, 0x24000001 }, - { 0x0c0004a1, 0x1400ffff }, - { 0x0c0004a2, 0x24000001 }, - { 0x0c0004a3, 0x1400ffff }, - { 0x0c0004a4, 0x24000001 }, - { 0x0c0004a5, 0x1400ffff }, - { 0x0c0004a6, 0x24000001 }, - { 0x0c0004a7, 0x1400ffff }, - { 0x0c0004a8, 0x24000001 }, - { 0x0c0004a9, 0x1400ffff }, - { 0x0c0004aa, 0x24000001 }, - { 0x0c0004ab, 0x1400ffff }, - { 0x0c0004ac, 0x24000001 }, - { 0x0c0004ad, 0x1400ffff }, - { 0x0c0004ae, 0x24000001 }, - { 0x0c0004af, 0x1400ffff }, - { 0x0c0004b0, 0x24000001 }, - { 0x0c0004b1, 0x1400ffff }, - { 0x0c0004b2, 0x24000001 }, - { 0x0c0004b3, 0x1400ffff }, - { 0x0c0004b4, 0x24000001 }, - { 0x0c0004b5, 0x1400ffff }, - { 0x0c0004b6, 0x24000001 }, - { 0x0c0004b7, 0x1400ffff }, - { 0x0c0004b8, 0x24000001 }, - { 0x0c0004b9, 0x1400ffff }, - { 0x0c0004ba, 0x24000001 }, - { 0x0c0004bb, 0x1400ffff }, - { 0x0c0004bc, 0x24000001 }, - { 0x0c0004bd, 0x1400ffff }, - { 0x0c0004be, 0x24000001 }, - { 0x0c0004bf, 0x1400ffff }, - { 0x0c0004c0, 0x24000000 }, - { 0x0c0004c1, 0x24000001 }, - { 0x0c0004c2, 0x1400ffff }, - { 0x0c0004c3, 0x24000001 }, - { 0x0c0004c4, 0x1400ffff }, - { 0x0c0004c5, 0x24000001 }, - { 0x0c0004c6, 0x1400ffff }, - { 0x0c0004c7, 0x24000001 }, - { 0x0c0004c8, 0x1400ffff }, - { 0x0c0004c9, 0x24000001 }, - { 0x0c0004ca, 0x1400ffff }, - { 0x0c0004cb, 0x24000001 }, - { 0x0c0004cc, 0x1400ffff }, - { 0x0c0004cd, 0x24000001 }, - { 0x0c0004ce, 0x1400ffff }, - { 0x0c0004d0, 0x24000001 }, - { 0x0c0004d1, 0x1400ffff }, - { 0x0c0004d2, 0x24000001 }, - { 0x0c0004d3, 0x1400ffff }, - { 0x0c0004d4, 0x24000001 }, - { 0x0c0004d5, 0x1400ffff }, - { 0x0c0004d6, 0x24000001 }, - { 0x0c0004d7, 0x1400ffff }, - { 0x0c0004d8, 0x24000001 }, - { 0x0c0004d9, 0x1400ffff }, - { 0x0c0004da, 0x24000001 }, - { 0x0c0004db, 0x1400ffff }, - { 0x0c0004dc, 0x24000001 }, - { 0x0c0004dd, 0x1400ffff }, - { 0x0c0004de, 0x24000001 }, - { 0x0c0004df, 0x1400ffff }, - { 0x0c0004e0, 0x24000001 }, - { 0x0c0004e1, 0x1400ffff }, - { 0x0c0004e2, 0x24000001 }, - { 0x0c0004e3, 0x1400ffff }, - { 0x0c0004e4, 0x24000001 }, - { 0x0c0004e5, 0x1400ffff }, - { 0x0c0004e6, 0x24000001 }, - { 0x0c0004e7, 0x1400ffff }, - { 0x0c0004e8, 0x24000001 }, - { 0x0c0004e9, 0x1400ffff }, - { 0x0c0004ea, 0x24000001 }, - { 0x0c0004eb, 0x1400ffff }, - { 0x0c0004ec, 0x24000001 }, - { 0x0c0004ed, 0x1400ffff }, - { 0x0c0004ee, 0x24000001 }, - { 0x0c0004ef, 0x1400ffff }, - { 0x0c0004f0, 0x24000001 }, - { 0x0c0004f1, 0x1400ffff }, - { 0x0c0004f2, 0x24000001 }, - { 0x0c0004f3, 0x1400ffff }, - { 0x0c0004f4, 0x24000001 }, - { 0x0c0004f5, 0x1400ffff }, - { 0x0c0004f6, 0x24000001 }, - { 0x0c0004f7, 0x1400ffff }, - { 0x0c0004f8, 0x24000001 }, - { 0x0c0004f9, 0x1400ffff }, - { 0x0c000500, 0x24000001 }, - { 0x0c000501, 0x1400ffff }, - { 0x0c000502, 0x24000001 }, - { 0x0c000503, 0x1400ffff }, - { 0x0c000504, 0x24000001 }, - { 0x0c000505, 0x1400ffff }, - { 0x0c000506, 0x24000001 }, - { 0x0c000507, 0x1400ffff }, - { 0x0c000508, 0x24000001 }, - { 0x0c000509, 0x1400ffff }, - { 0x0c00050a, 0x24000001 }, - { 0x0c00050b, 0x1400ffff }, - { 0x0c00050c, 0x24000001 }, - { 0x0c00050d, 0x1400ffff }, - { 0x0c00050e, 0x24000001 }, - { 0x0c00050f, 0x1400ffff }, - { 0x01000531, 0x24000030 }, - { 0x01000532, 0x24000030 }, - { 0x01000533, 0x24000030 }, - { 0x01000534, 0x24000030 }, - { 0x01000535, 0x24000030 }, - { 0x01000536, 0x24000030 }, - { 0x01000537, 0x24000030 }, - { 0x01000538, 0x24000030 }, - { 0x01000539, 0x24000030 }, - { 0x0100053a, 0x24000030 }, - { 0x0100053b, 0x24000030 }, - { 0x0100053c, 0x24000030 }, - { 0x0100053d, 0x24000030 }, - { 0x0100053e, 0x24000030 }, - { 0x0100053f, 0x24000030 }, - { 0x01000540, 0x24000030 }, - { 0x01000541, 0x24000030 }, - { 0x01000542, 0x24000030 }, - { 0x01000543, 0x24000030 }, - { 0x01000544, 0x24000030 }, - { 0x01000545, 0x24000030 }, - { 0x01000546, 0x24000030 }, - { 0x01000547, 0x24000030 }, - { 0x01000548, 0x24000030 }, - { 0x01000549, 0x24000030 }, - { 0x0100054a, 0x24000030 }, - { 0x0100054b, 0x24000030 }, - { 0x0100054c, 0x24000030 }, - { 0x0100054d, 0x24000030 }, - { 0x0100054e, 0x24000030 }, - { 0x0100054f, 0x24000030 }, - { 0x01000550, 0x24000030 }, - { 0x01000551, 0x24000030 }, - { 0x01000552, 0x24000030 }, - { 0x01000553, 0x24000030 }, - { 0x01000554, 0x24000030 }, - { 0x01000555, 0x24000030 }, - { 0x01000556, 0x24000030 }, - { 0x01000559, 0x18000000 }, - { 0x0180055a, 0x54000005 }, - { 0x01000561, 0x1400ffd0 }, - { 0x01000562, 0x1400ffd0 }, - { 0x01000563, 0x1400ffd0 }, - { 0x01000564, 0x1400ffd0 }, - { 0x01000565, 0x1400ffd0 }, - { 0x01000566, 0x1400ffd0 }, - { 0x01000567, 0x1400ffd0 }, - { 0x01000568, 0x1400ffd0 }, - { 0x01000569, 0x1400ffd0 }, - { 0x0100056a, 0x1400ffd0 }, - { 0x0100056b, 0x1400ffd0 }, - { 0x0100056c, 0x1400ffd0 }, - { 0x0100056d, 0x1400ffd0 }, - { 0x0100056e, 0x1400ffd0 }, - { 0x0100056f, 0x1400ffd0 }, - { 0x01000570, 0x1400ffd0 }, - { 0x01000571, 0x1400ffd0 }, - { 0x01000572, 0x1400ffd0 }, - { 0x01000573, 0x1400ffd0 }, - { 0x01000574, 0x1400ffd0 }, - { 0x01000575, 0x1400ffd0 }, - { 0x01000576, 0x1400ffd0 }, - { 0x01000577, 0x1400ffd0 }, - { 0x01000578, 0x1400ffd0 }, - { 0x01000579, 0x1400ffd0 }, - { 0x0100057a, 0x1400ffd0 }, - { 0x0100057b, 0x1400ffd0 }, - { 0x0100057c, 0x1400ffd0 }, - { 0x0100057d, 0x1400ffd0 }, - { 0x0100057e, 0x1400ffd0 }, - { 0x0100057f, 0x1400ffd0 }, - { 0x01000580, 0x1400ffd0 }, - { 0x01000581, 0x1400ffd0 }, - { 0x01000582, 0x1400ffd0 }, - { 0x01000583, 0x1400ffd0 }, - { 0x01000584, 0x1400ffd0 }, - { 0x01000585, 0x1400ffd0 }, - { 0x01000586, 0x1400ffd0 }, - { 0x01000587, 0x14000000 }, - { 0x09000589, 0x54000000 }, - { 0x0100058a, 0x44000000 }, - { 0x19800591, 0x30000028 }, - { 0x198005bb, 0x30000002 }, - { 0x190005be, 0x54000000 }, - { 0x190005bf, 0x30000000 }, - { 0x190005c0, 0x54000000 }, - { 0x198005c1, 0x30000001 }, - { 0x190005c3, 0x54000000 }, - { 0x198005c4, 0x30000001 }, - { 0x190005c6, 0x54000000 }, - { 0x190005c7, 0x30000000 }, - { 0x198005d0, 0x1c00001a }, - { 0x198005f0, 0x1c000002 }, - { 0x198005f3, 0x54000001 }, - { 0x09800600, 0x04000003 }, - { 0x0000060b, 0x5c000000 }, - { 0x0980060c, 0x54000001 }, - { 0x0080060e, 0x68000001 }, - { 0x00800610, 0x30000005 }, - { 0x0900061b, 0x54000000 }, - { 0x0080061e, 0x54000001 }, - { 0x00800621, 0x1c000019 }, - { 0x09000640, 0x18000000 }, - { 0x00800641, 0x1c000009 }, - { 0x1b80064b, 0x30000013 }, - { 0x09800660, 0x34000009 }, - { 0x0080066a, 0x54000003 }, - { 0x0080066e, 0x1c000001 }, - { 0x1b000670, 0x30000000 }, - { 0x00800671, 0x1c000062 }, - { 0x000006d4, 0x54000000 }, - { 0x000006d5, 0x1c000000 }, - { 0x008006d6, 0x30000006 }, - { 0x090006dd, 0x04000000 }, - { 0x000006de, 0x2c000000 }, - { 0x008006df, 0x30000005 }, - { 0x008006e5, 0x18000001 }, - { 0x008006e7, 0x30000001 }, - { 0x000006e9, 0x68000000 }, - { 0x008006ea, 0x30000003 }, - { 0x008006ee, 0x1c000001 }, - { 0x008006f0, 0x34000009 }, - { 0x008006fa, 0x1c000002 }, - { 0x008006fd, 0x68000001 }, - { 0x000006ff, 0x1c000000 }, - { 0x31800700, 0x5400000d }, - { 0x3100070f, 0x04000000 }, - { 0x31000710, 0x1c000000 }, - { 0x31000711, 0x30000000 }, - { 0x31800712, 0x1c00001d }, - { 0x31800730, 0x3000001a }, - { 0x3180074d, 0x1c000020 }, - { 0x37800780, 0x1c000025 }, - { 0x378007a6, 0x3000000a }, - { 0x370007b1, 0x1c000000 }, - { 0x0e800901, 0x30000001 }, - { 0x0e000903, 0x28000000 }, - { 0x0e800904, 0x1c000035 }, - { 0x0e00093c, 0x30000000 }, - { 0x0e00093d, 0x1c000000 }, - { 0x0e80093e, 0x28000002 }, - { 0x0e800941, 0x30000007 }, - { 0x0e800949, 0x28000003 }, - { 0x0e00094d, 0x30000000 }, - { 0x0e000950, 0x1c000000 }, - { 0x0e800951, 0x30000003 }, - { 0x0e800958, 0x1c000009 }, - { 0x0e800962, 0x30000001 }, - { 0x09800964, 0x54000001 }, - { 0x0e800966, 0x34000009 }, - { 0x09000970, 0x54000000 }, - { 0x0e00097d, 0x1c000000 }, - { 0x02000981, 0x30000000 }, - { 0x02800982, 0x28000001 }, - { 0x02800985, 0x1c000007 }, - { 0x0280098f, 0x1c000001 }, - { 0x02800993, 0x1c000015 }, - { 0x028009aa, 0x1c000006 }, - { 0x020009b2, 0x1c000000 }, - { 0x028009b6, 0x1c000003 }, - { 0x020009bc, 0x30000000 }, - { 0x020009bd, 0x1c000000 }, - { 0x028009be, 0x28000002 }, - { 0x028009c1, 0x30000003 }, - { 0x028009c7, 0x28000001 }, - { 0x028009cb, 0x28000001 }, - { 0x020009cd, 0x30000000 }, - { 0x020009ce, 0x1c000000 }, - { 0x020009d7, 0x28000000 }, - { 0x028009dc, 0x1c000001 }, - { 0x028009df, 0x1c000002 }, - { 0x028009e2, 0x30000001 }, - { 0x028009e6, 0x34000009 }, - { 0x028009f0, 0x1c000001 }, - { 0x028009f2, 0x5c000001 }, - { 0x028009f4, 0x3c000005 }, - { 0x020009fa, 0x68000000 }, - { 0x15800a01, 0x30000001 }, - { 0x15000a03, 0x28000000 }, - { 0x15800a05, 0x1c000005 }, - { 0x15800a0f, 0x1c000001 }, - { 0x15800a13, 0x1c000015 }, - { 0x15800a2a, 0x1c000006 }, - { 0x15800a32, 0x1c000001 }, - { 0x15800a35, 0x1c000001 }, - { 0x15800a38, 0x1c000001 }, - { 0x15000a3c, 0x30000000 }, - { 0x15800a3e, 0x28000002 }, - { 0x15800a41, 0x30000001 }, - { 0x15800a47, 0x30000001 }, - { 0x15800a4b, 0x30000002 }, - { 0x15800a59, 0x1c000003 }, - { 0x15000a5e, 0x1c000000 }, - { 0x15800a66, 0x34000009 }, - { 0x15800a70, 0x30000001 }, - { 0x15800a72, 0x1c000002 }, - { 0x14800a81, 0x30000001 }, - { 0x14000a83, 0x28000000 }, - { 0x14800a85, 0x1c000008 }, - { 0x14800a8f, 0x1c000002 }, - { 0x14800a93, 0x1c000015 }, - { 0x14800aaa, 0x1c000006 }, - { 0x14800ab2, 0x1c000001 }, - { 0x14800ab5, 0x1c000004 }, - { 0x14000abc, 0x30000000 }, - { 0x14000abd, 0x1c000000 }, - { 0x14800abe, 0x28000002 }, - { 0x14800ac1, 0x30000004 }, - { 0x14800ac7, 0x30000001 }, - { 0x14000ac9, 0x28000000 }, - { 0x14800acb, 0x28000001 }, - { 0x14000acd, 0x30000000 }, - { 0x14000ad0, 0x1c000000 }, - { 0x14800ae0, 0x1c000001 }, - { 0x14800ae2, 0x30000001 }, - { 0x14800ae6, 0x34000009 }, - { 0x14000af1, 0x5c000000 }, - { 0x2b000b01, 0x30000000 }, - { 0x2b800b02, 0x28000001 }, - { 0x2b800b05, 0x1c000007 }, - { 0x2b800b0f, 0x1c000001 }, - { 0x2b800b13, 0x1c000015 }, - { 0x2b800b2a, 0x1c000006 }, - { 0x2b800b32, 0x1c000001 }, - { 0x2b800b35, 0x1c000004 }, - { 0x2b000b3c, 0x30000000 }, - { 0x2b000b3d, 0x1c000000 }, - { 0x2b000b3e, 0x28000000 }, - { 0x2b000b3f, 0x30000000 }, - { 0x2b000b40, 0x28000000 }, - { 0x2b800b41, 0x30000002 }, - { 0x2b800b47, 0x28000001 }, - { 0x2b800b4b, 0x28000001 }, - { 0x2b000b4d, 0x30000000 }, - { 0x2b000b56, 0x30000000 }, - { 0x2b000b57, 0x28000000 }, - { 0x2b800b5c, 0x1c000001 }, - { 0x2b800b5f, 0x1c000002 }, - { 0x2b800b66, 0x34000009 }, - { 0x2b000b70, 0x68000000 }, - { 0x2b000b71, 0x1c000000 }, - { 0x35000b82, 0x30000000 }, - { 0x35000b83, 0x1c000000 }, - { 0x35800b85, 0x1c000005 }, - { 0x35800b8e, 0x1c000002 }, - { 0x35800b92, 0x1c000003 }, - { 0x35800b99, 0x1c000001 }, - { 0x35000b9c, 0x1c000000 }, - { 0x35800b9e, 0x1c000001 }, - { 0x35800ba3, 0x1c000001 }, - { 0x35800ba8, 0x1c000002 }, - { 0x35800bae, 0x1c00000b }, - { 0x35800bbe, 0x28000001 }, - { 0x35000bc0, 0x30000000 }, - { 0x35800bc1, 0x28000001 }, - { 0x35800bc6, 0x28000002 }, - { 0x35800bca, 0x28000002 }, - { 0x35000bcd, 0x30000000 }, - { 0x35000bd7, 0x28000000 }, - { 0x35800be6, 0x34000009 }, - { 0x35800bf0, 0x3c000002 }, - { 0x35800bf3, 0x68000005 }, - { 0x35000bf9, 0x5c000000 }, - { 0x35000bfa, 0x68000000 }, - { 0x36800c01, 0x28000002 }, - { 0x36800c05, 0x1c000007 }, - { 0x36800c0e, 0x1c000002 }, - { 0x36800c12, 0x1c000016 }, - { 0x36800c2a, 0x1c000009 }, - { 0x36800c35, 0x1c000004 }, - { 0x36800c3e, 0x30000002 }, - { 0x36800c41, 0x28000003 }, - { 0x36800c46, 0x30000002 }, - { 0x36800c4a, 0x30000003 }, - { 0x36800c55, 0x30000001 }, - { 0x36800c60, 0x1c000001 }, - { 0x36800c66, 0x34000009 }, - { 0x1c800c82, 0x28000001 }, - { 0x1c800c85, 0x1c000007 }, - { 0x1c800c8e, 0x1c000002 }, - { 0x1c800c92, 0x1c000016 }, - { 0x1c800caa, 0x1c000009 }, - { 0x1c800cb5, 0x1c000004 }, - { 0x1c000cbc, 0x30000000 }, - { 0x1c000cbd, 0x1c000000 }, - { 0x1c000cbe, 0x28000000 }, - { 0x1c000cbf, 0x30000000 }, - { 0x1c800cc0, 0x28000004 }, - { 0x1c000cc6, 0x30000000 }, - { 0x1c800cc7, 0x28000001 }, - { 0x1c800cca, 0x28000001 }, - { 0x1c800ccc, 0x30000001 }, - { 0x1c800cd5, 0x28000001 }, - { 0x1c000cde, 0x1c000000 }, - { 0x1c800ce0, 0x1c000001 }, - { 0x1c800ce6, 0x34000009 }, - { 0x24800d02, 0x28000001 }, - { 0x24800d05, 0x1c000007 }, - { 0x24800d0e, 0x1c000002 }, - { 0x24800d12, 0x1c000016 }, - { 0x24800d2a, 0x1c00000f }, - { 0x24800d3e, 0x28000002 }, - { 0x24800d41, 0x30000002 }, - { 0x24800d46, 0x28000002 }, - { 0x24800d4a, 0x28000002 }, - { 0x24000d4d, 0x30000000 }, - { 0x24000d57, 0x28000000 }, - { 0x24800d60, 0x1c000001 }, - { 0x24800d66, 0x34000009 }, - { 0x2f800d82, 0x28000001 }, - { 0x2f800d85, 0x1c000011 }, - { 0x2f800d9a, 0x1c000017 }, - { 0x2f800db3, 0x1c000008 }, - { 0x2f000dbd, 0x1c000000 }, - { 0x2f800dc0, 0x1c000006 }, - { 0x2f000dca, 0x30000000 }, - { 0x2f800dcf, 0x28000002 }, - { 0x2f800dd2, 0x30000002 }, - { 0x2f000dd6, 0x30000000 }, - { 0x2f800dd8, 0x28000007 }, - { 0x2f800df2, 0x28000001 }, - { 0x2f000df4, 0x54000000 }, - { 0x38800e01, 0x1c00002f }, - { 0x38000e31, 0x30000000 }, - { 0x38800e32, 0x1c000001 }, - { 0x38800e34, 0x30000006 }, - { 0x09000e3f, 0x5c000000 }, - { 0x38800e40, 0x1c000005 }, - { 0x38000e46, 0x18000000 }, - { 0x38800e47, 0x30000007 }, - { 0x38000e4f, 0x54000000 }, - { 0x38800e50, 0x34000009 }, - { 0x38800e5a, 0x54000001 }, - { 0x20800e81, 0x1c000001 }, - { 0x20000e84, 0x1c000000 }, - { 0x20800e87, 0x1c000001 }, - { 0x20000e8a, 0x1c000000 }, - { 0x20000e8d, 0x1c000000 }, - { 0x20800e94, 0x1c000003 }, - { 0x20800e99, 0x1c000006 }, - { 0x20800ea1, 0x1c000002 }, - { 0x20000ea5, 0x1c000000 }, - { 0x20000ea7, 0x1c000000 }, - { 0x20800eaa, 0x1c000001 }, - { 0x20800ead, 0x1c000003 }, - { 0x20000eb1, 0x30000000 }, - { 0x20800eb2, 0x1c000001 }, - { 0x20800eb4, 0x30000005 }, - { 0x20800ebb, 0x30000001 }, - { 0x20000ebd, 0x1c000000 }, - { 0x20800ec0, 0x1c000004 }, - { 0x20000ec6, 0x18000000 }, - { 0x20800ec8, 0x30000005 }, - { 0x20800ed0, 0x34000009 }, - { 0x20800edc, 0x1c000001 }, - { 0x39000f00, 0x1c000000 }, - { 0x39800f01, 0x68000002 }, - { 0x39800f04, 0x5400000e }, - { 0x39800f13, 0x68000004 }, - { 0x39800f18, 0x30000001 }, - { 0x39800f1a, 0x68000005 }, - { 0x39800f20, 0x34000009 }, - { 0x39800f2a, 0x3c000009 }, - { 0x39000f34, 0x68000000 }, - { 0x39000f35, 0x30000000 }, - { 0x39000f36, 0x68000000 }, - { 0x39000f37, 0x30000000 }, - { 0x39000f38, 0x68000000 }, - { 0x39000f39, 0x30000000 }, - { 0x39000f3a, 0x58000000 }, - { 0x39000f3b, 0x48000000 }, - { 0x39000f3c, 0x58000000 }, - { 0x39000f3d, 0x48000000 }, - { 0x39800f3e, 0x28000001 }, - { 0x39800f40, 0x1c000007 }, - { 0x39800f49, 0x1c000021 }, - { 0x39800f71, 0x3000000d }, - { 0x39000f7f, 0x28000000 }, - { 0x39800f80, 0x30000004 }, - { 0x39000f85, 0x54000000 }, - { 0x39800f86, 0x30000001 }, - { 0x39800f88, 0x1c000003 }, - { 0x39800f90, 0x30000007 }, - { 0x39800f99, 0x30000023 }, - { 0x39800fbe, 0x68000007 }, - { 0x39000fc6, 0x30000000 }, - { 0x39800fc7, 0x68000005 }, - { 0x39000fcf, 0x68000000 }, - { 0x39800fd0, 0x54000001 }, - { 0x26801000, 0x1c000021 }, - { 0x26801023, 0x1c000004 }, - { 0x26801029, 0x1c000001 }, - { 0x2600102c, 0x28000000 }, - { 0x2680102d, 0x30000003 }, - { 0x26001031, 0x28000000 }, - { 0x26001032, 0x30000000 }, - { 0x26801036, 0x30000001 }, - { 0x26001038, 0x28000000 }, - { 0x26001039, 0x30000000 }, - { 0x26801040, 0x34000009 }, - { 0x2680104a, 0x54000005 }, - { 0x26801050, 0x1c000005 }, - { 0x26801056, 0x28000001 }, - { 0x26801058, 0x30000001 }, - { 0x100010a0, 0x24001c60 }, - { 0x100010a1, 0x24001c60 }, - { 0x100010a2, 0x24001c60 }, - { 0x100010a3, 0x24001c60 }, - { 0x100010a4, 0x24001c60 }, - { 0x100010a5, 0x24001c60 }, - { 0x100010a6, 0x24001c60 }, - { 0x100010a7, 0x24001c60 }, - { 0x100010a8, 0x24001c60 }, - { 0x100010a9, 0x24001c60 }, - { 0x100010aa, 0x24001c60 }, - { 0x100010ab, 0x24001c60 }, - { 0x100010ac, 0x24001c60 }, - { 0x100010ad, 0x24001c60 }, - { 0x100010ae, 0x24001c60 }, - { 0x100010af, 0x24001c60 }, - { 0x100010b0, 0x24001c60 }, - { 0x100010b1, 0x24001c60 }, - { 0x100010b2, 0x24001c60 }, - { 0x100010b3, 0x24001c60 }, - { 0x100010b4, 0x24001c60 }, - { 0x100010b5, 0x24001c60 }, - { 0x100010b6, 0x24001c60 }, - { 0x100010b7, 0x24001c60 }, - { 0x100010b8, 0x24001c60 }, - { 0x100010b9, 0x24001c60 }, - { 0x100010ba, 0x24001c60 }, - { 0x100010bb, 0x24001c60 }, - { 0x100010bc, 0x24001c60 }, - { 0x100010bd, 0x24001c60 }, - { 0x100010be, 0x24001c60 }, - { 0x100010bf, 0x24001c60 }, - { 0x100010c0, 0x24001c60 }, - { 0x100010c1, 0x24001c60 }, - { 0x100010c2, 0x24001c60 }, - { 0x100010c3, 0x24001c60 }, - { 0x100010c4, 0x24001c60 }, - { 0x100010c5, 0x24001c60 }, - { 0x108010d0, 0x1c00002a }, - { 0x090010fb, 0x54000000 }, - { 0x100010fc, 0x18000000 }, - { 0x17801100, 0x1c000059 }, - { 0x1780115f, 0x1c000043 }, - { 0x178011a8, 0x1c000051 }, - { 0x0f801200, 0x1c000048 }, - { 0x0f80124a, 0x1c000003 }, - { 0x0f801250, 0x1c000006 }, - { 0x0f001258, 0x1c000000 }, - { 0x0f80125a, 0x1c000003 }, - { 0x0f801260, 0x1c000028 }, - { 0x0f80128a, 0x1c000003 }, - { 0x0f801290, 0x1c000020 }, - { 0x0f8012b2, 0x1c000003 }, - { 0x0f8012b8, 0x1c000006 }, - { 0x0f0012c0, 0x1c000000 }, - { 0x0f8012c2, 0x1c000003 }, - { 0x0f8012c8, 0x1c00000e }, - { 0x0f8012d8, 0x1c000038 }, - { 0x0f801312, 0x1c000003 }, - { 0x0f801318, 0x1c000042 }, - { 0x0f00135f, 0x30000000 }, - { 0x0f001360, 0x68000000 }, - { 0x0f801361, 0x54000007 }, - { 0x0f801369, 0x3c000013 }, - { 0x0f801380, 0x1c00000f }, - { 0x0f801390, 0x68000009 }, - { 0x088013a0, 0x1c000054 }, - { 0x07801401, 0x1c00026b }, - { 0x0780166d, 0x54000001 }, - { 0x0780166f, 0x1c000007 }, - { 0x28001680, 0x74000000 }, - { 0x28801681, 0x1c000019 }, - { 0x2800169b, 0x58000000 }, - { 0x2800169c, 0x48000000 }, - { 0x2d8016a0, 0x1c00004a }, - { 0x098016eb, 0x54000002 }, - { 0x2d8016ee, 0x38000002 }, - { 0x32801700, 0x1c00000c }, - { 0x3280170e, 0x1c000003 }, - { 0x32801712, 0x30000002 }, - { 0x18801720, 0x1c000011 }, - { 0x18801732, 0x30000002 }, - { 0x09801735, 0x54000001 }, - { 0x06801740, 0x1c000011 }, - { 0x06801752, 0x30000001 }, - { 0x33801760, 0x1c00000c }, - { 0x3380176e, 0x1c000002 }, - { 0x33801772, 0x30000001 }, - { 0x1f801780, 0x1c000033 }, - { 0x1f8017b4, 0x04000001 }, - { 0x1f0017b6, 0x28000000 }, - { 0x1f8017b7, 0x30000006 }, - { 0x1f8017be, 0x28000007 }, - { 0x1f0017c6, 0x30000000 }, - { 0x1f8017c7, 0x28000001 }, - { 0x1f8017c9, 0x3000000a }, - { 0x1f8017d4, 0x54000002 }, - { 0x1f0017d7, 0x18000000 }, - { 0x1f8017d8, 0x54000002 }, - { 0x1f0017db, 0x5c000000 }, - { 0x1f0017dc, 0x1c000000 }, - { 0x1f0017dd, 0x30000000 }, - { 0x1f8017e0, 0x34000009 }, - { 0x1f8017f0, 0x3c000009 }, - { 0x25801800, 0x54000005 }, - { 0x25001806, 0x44000000 }, - { 0x25801807, 0x54000003 }, - { 0x2580180b, 0x30000002 }, - { 0x2500180e, 0x74000000 }, - { 0x25801810, 0x34000009 }, - { 0x25801820, 0x1c000022 }, - { 0x25001843, 0x18000000 }, - { 0x25801844, 0x1c000033 }, - { 0x25801880, 0x1c000028 }, - { 0x250018a9, 0x30000000 }, - { 0x22801900, 0x1c00001c }, - { 0x22801920, 0x30000002 }, - { 0x22801923, 0x28000003 }, - { 0x22801927, 0x30000001 }, - { 0x22801929, 0x28000002 }, - { 0x22801930, 0x28000001 }, - { 0x22001932, 0x30000000 }, - { 0x22801933, 0x28000005 }, - { 0x22801939, 0x30000002 }, - { 0x22001940, 0x68000000 }, - { 0x22801944, 0x54000001 }, - { 0x22801946, 0x34000009 }, - { 0x34801950, 0x1c00001d }, - { 0x34801970, 0x1c000004 }, - { 0x27801980, 0x1c000029 }, - { 0x278019b0, 0x28000010 }, - { 0x278019c1, 0x1c000006 }, - { 0x278019c8, 0x28000001 }, - { 0x278019d0, 0x34000009 }, - { 0x278019de, 0x54000001 }, - { 0x1f8019e0, 0x6800001f }, - { 0x05801a00, 0x1c000016 }, - { 0x05801a17, 0x30000001 }, - { 0x05801a19, 0x28000002 }, - { 0x05801a1e, 0x54000001 }, - { 0x21801d00, 0x1400002b }, - { 0x21801d2c, 0x18000035 }, - { 0x21801d62, 0x14000015 }, - { 0x0c001d78, 0x18000000 }, - { 0x21801d79, 0x14000021 }, - { 0x21801d9b, 0x18000024 }, - { 0x1b801dc0, 0x30000003 }, - { 0x21001e00, 0x24000001 }, - { 0x21001e01, 0x1400ffff }, - { 0x21001e02, 0x24000001 }, - { 0x21001e03, 0x1400ffff }, - { 0x21001e04, 0x24000001 }, - { 0x21001e05, 0x1400ffff }, - { 0x21001e06, 0x24000001 }, - { 0x21001e07, 0x1400ffff }, - { 0x21001e08, 0x24000001 }, - { 0x21001e09, 0x1400ffff }, - { 0x21001e0a, 0x24000001 }, - { 0x21001e0b, 0x1400ffff }, - { 0x21001e0c, 0x24000001 }, - { 0x21001e0d, 0x1400ffff }, - { 0x21001e0e, 0x24000001 }, - { 0x21001e0f, 0x1400ffff }, - { 0x21001e10, 0x24000001 }, - { 0x21001e11, 0x1400ffff }, - { 0x21001e12, 0x24000001 }, - { 0x21001e13, 0x1400ffff }, - { 0x21001e14, 0x24000001 }, - { 0x21001e15, 0x1400ffff }, - { 0x21001e16, 0x24000001 }, - { 0x21001e17, 0x1400ffff }, - { 0x21001e18, 0x24000001 }, - { 0x21001e19, 0x1400ffff }, - { 0x21001e1a, 0x24000001 }, - { 0x21001e1b, 0x1400ffff }, - { 0x21001e1c, 0x24000001 }, - { 0x21001e1d, 0x1400ffff }, - { 0x21001e1e, 0x24000001 }, - { 0x21001e1f, 0x1400ffff }, - { 0x21001e20, 0x24000001 }, - { 0x21001e21, 0x1400ffff }, - { 0x21001e22, 0x24000001 }, - { 0x21001e23, 0x1400ffff }, - { 0x21001e24, 0x24000001 }, - { 0x21001e25, 0x1400ffff }, - { 0x21001e26, 0x24000001 }, - { 0x21001e27, 0x1400ffff }, - { 0x21001e28, 0x24000001 }, - { 0x21001e29, 0x1400ffff }, - { 0x21001e2a, 0x24000001 }, - { 0x21001e2b, 0x1400ffff }, - { 0x21001e2c, 0x24000001 }, - { 0x21001e2d, 0x1400ffff }, - { 0x21001e2e, 0x24000001 }, - { 0x21001e2f, 0x1400ffff }, - { 0x21001e30, 0x24000001 }, - { 0x21001e31, 0x1400ffff }, - { 0x21001e32, 0x24000001 }, - { 0x21001e33, 0x1400ffff }, - { 0x21001e34, 0x24000001 }, - { 0x21001e35, 0x1400ffff }, - { 0x21001e36, 0x24000001 }, - { 0x21001e37, 0x1400ffff }, - { 0x21001e38, 0x24000001 }, - { 0x21001e39, 0x1400ffff }, - { 0x21001e3a, 0x24000001 }, - { 0x21001e3b, 0x1400ffff }, - { 0x21001e3c, 0x24000001 }, - { 0x21001e3d, 0x1400ffff }, - { 0x21001e3e, 0x24000001 }, - { 0x21001e3f, 0x1400ffff }, - { 0x21001e40, 0x24000001 }, - { 0x21001e41, 0x1400ffff }, - { 0x21001e42, 0x24000001 }, - { 0x21001e43, 0x1400ffff }, - { 0x21001e44, 0x24000001 }, - { 0x21001e45, 0x1400ffff }, - { 0x21001e46, 0x24000001 }, - { 0x21001e47, 0x1400ffff }, - { 0x21001e48, 0x24000001 }, - { 0x21001e49, 0x1400ffff }, - { 0x21001e4a, 0x24000001 }, - { 0x21001e4b, 0x1400ffff }, - { 0x21001e4c, 0x24000001 }, - { 0x21001e4d, 0x1400ffff }, - { 0x21001e4e, 0x24000001 }, - { 0x21001e4f, 0x1400ffff }, - { 0x21001e50, 0x24000001 }, - { 0x21001e51, 0x1400ffff }, - { 0x21001e52, 0x24000001 }, - { 0x21001e53, 0x1400ffff }, - { 0x21001e54, 0x24000001 }, - { 0x21001e55, 0x1400ffff }, - { 0x21001e56, 0x24000001 }, - { 0x21001e57, 0x1400ffff }, - { 0x21001e58, 0x24000001 }, - { 0x21001e59, 0x1400ffff }, - { 0x21001e5a, 0x24000001 }, - { 0x21001e5b, 0x1400ffff }, - { 0x21001e5c, 0x24000001 }, - { 0x21001e5d, 0x1400ffff }, - { 0x21001e5e, 0x24000001 }, - { 0x21001e5f, 0x1400ffff }, - { 0x21001e60, 0x24000001 }, - { 0x21001e61, 0x1400ffff }, - { 0x21001e62, 0x24000001 }, - { 0x21001e63, 0x1400ffff }, - { 0x21001e64, 0x24000001 }, - { 0x21001e65, 0x1400ffff }, - { 0x21001e66, 0x24000001 }, - { 0x21001e67, 0x1400ffff }, - { 0x21001e68, 0x24000001 }, - { 0x21001e69, 0x1400ffff }, - { 0x21001e6a, 0x24000001 }, - { 0x21001e6b, 0x1400ffff }, - { 0x21001e6c, 0x24000001 }, - { 0x21001e6d, 0x1400ffff }, - { 0x21001e6e, 0x24000001 }, - { 0x21001e6f, 0x1400ffff }, - { 0x21001e70, 0x24000001 }, - { 0x21001e71, 0x1400ffff }, - { 0x21001e72, 0x24000001 }, - { 0x21001e73, 0x1400ffff }, - { 0x21001e74, 0x24000001 }, - { 0x21001e75, 0x1400ffff }, - { 0x21001e76, 0x24000001 }, - { 0x21001e77, 0x1400ffff }, - { 0x21001e78, 0x24000001 }, - { 0x21001e79, 0x1400ffff }, - { 0x21001e7a, 0x24000001 }, - { 0x21001e7b, 0x1400ffff }, - { 0x21001e7c, 0x24000001 }, - { 0x21001e7d, 0x1400ffff }, - { 0x21001e7e, 0x24000001 }, - { 0x21001e7f, 0x1400ffff }, - { 0x21001e80, 0x24000001 }, - { 0x21001e81, 0x1400ffff }, - { 0x21001e82, 0x24000001 }, - { 0x21001e83, 0x1400ffff }, - { 0x21001e84, 0x24000001 }, - { 0x21001e85, 0x1400ffff }, - { 0x21001e86, 0x24000001 }, - { 0x21001e87, 0x1400ffff }, - { 0x21001e88, 0x24000001 }, - { 0x21001e89, 0x1400ffff }, - { 0x21001e8a, 0x24000001 }, - { 0x21001e8b, 0x1400ffff }, - { 0x21001e8c, 0x24000001 }, - { 0x21001e8d, 0x1400ffff }, - { 0x21001e8e, 0x24000001 }, - { 0x21001e8f, 0x1400ffff }, - { 0x21001e90, 0x24000001 }, - { 0x21001e91, 0x1400ffff }, - { 0x21001e92, 0x24000001 }, - { 0x21001e93, 0x1400ffff }, - { 0x21001e94, 0x24000001 }, - { 0x21001e95, 0x1400ffff }, - { 0x21801e96, 0x14000004 }, - { 0x21001e9b, 0x1400ffc5 }, - { 0x21001ea0, 0x24000001 }, - { 0x21001ea1, 0x1400ffff }, - { 0x21001ea2, 0x24000001 }, - { 0x21001ea3, 0x1400ffff }, - { 0x21001ea4, 0x24000001 }, - { 0x21001ea5, 0x1400ffff }, - { 0x21001ea6, 0x24000001 }, - { 0x21001ea7, 0x1400ffff }, - { 0x21001ea8, 0x24000001 }, - { 0x21001ea9, 0x1400ffff }, - { 0x21001eaa, 0x24000001 }, - { 0x21001eab, 0x1400ffff }, - { 0x21001eac, 0x24000001 }, - { 0x21001ead, 0x1400ffff }, - { 0x21001eae, 0x24000001 }, - { 0x21001eaf, 0x1400ffff }, - { 0x21001eb0, 0x24000001 }, - { 0x21001eb1, 0x1400ffff }, - { 0x21001eb2, 0x24000001 }, - { 0x21001eb3, 0x1400ffff }, - { 0x21001eb4, 0x24000001 }, - { 0x21001eb5, 0x1400ffff }, - { 0x21001eb6, 0x24000001 }, - { 0x21001eb7, 0x1400ffff }, - { 0x21001eb8, 0x24000001 }, - { 0x21001eb9, 0x1400ffff }, - { 0x21001eba, 0x24000001 }, - { 0x21001ebb, 0x1400ffff }, - { 0x21001ebc, 0x24000001 }, - { 0x21001ebd, 0x1400ffff }, - { 0x21001ebe, 0x24000001 }, - { 0x21001ebf, 0x1400ffff }, - { 0x21001ec0, 0x24000001 }, - { 0x21001ec1, 0x1400ffff }, - { 0x21001ec2, 0x24000001 }, - { 0x21001ec3, 0x1400ffff }, - { 0x21001ec4, 0x24000001 }, - { 0x21001ec5, 0x1400ffff }, - { 0x21001ec6, 0x24000001 }, - { 0x21001ec7, 0x1400ffff }, - { 0x21001ec8, 0x24000001 }, - { 0x21001ec9, 0x1400ffff }, - { 0x21001eca, 0x24000001 }, - { 0x21001ecb, 0x1400ffff }, - { 0x21001ecc, 0x24000001 }, - { 0x21001ecd, 0x1400ffff }, - { 0x21001ece, 0x24000001 }, - { 0x21001ecf, 0x1400ffff }, - { 0x21001ed0, 0x24000001 }, - { 0x21001ed1, 0x1400ffff }, - { 0x21001ed2, 0x24000001 }, - { 0x21001ed3, 0x1400ffff }, - { 0x21001ed4, 0x24000001 }, - { 0x21001ed5, 0x1400ffff }, - { 0x21001ed6, 0x24000001 }, - { 0x21001ed7, 0x1400ffff }, - { 0x21001ed8, 0x24000001 }, - { 0x21001ed9, 0x1400ffff }, - { 0x21001eda, 0x24000001 }, - { 0x21001edb, 0x1400ffff }, - { 0x21001edc, 0x24000001 }, - { 0x21001edd, 0x1400ffff }, - { 0x21001ede, 0x24000001 }, - { 0x21001edf, 0x1400ffff }, - { 0x21001ee0, 0x24000001 }, - { 0x21001ee1, 0x1400ffff }, - { 0x21001ee2, 0x24000001 }, - { 0x21001ee3, 0x1400ffff }, - { 0x21001ee4, 0x24000001 }, - { 0x21001ee5, 0x1400ffff }, - { 0x21001ee6, 0x24000001 }, - { 0x21001ee7, 0x1400ffff }, - { 0x21001ee8, 0x24000001 }, - { 0x21001ee9, 0x1400ffff }, - { 0x21001eea, 0x24000001 }, - { 0x21001eeb, 0x1400ffff }, - { 0x21001eec, 0x24000001 }, - { 0x21001eed, 0x1400ffff }, - { 0x21001eee, 0x24000001 }, - { 0x21001eef, 0x1400ffff }, - { 0x21001ef0, 0x24000001 }, - { 0x21001ef1, 0x1400ffff }, - { 0x21001ef2, 0x24000001 }, - { 0x21001ef3, 0x1400ffff }, - { 0x21001ef4, 0x24000001 }, - { 0x21001ef5, 0x1400ffff }, - { 0x21001ef6, 0x24000001 }, - { 0x21001ef7, 0x1400ffff }, - { 0x21001ef8, 0x24000001 }, - { 0x21001ef9, 0x1400ffff }, - { 0x13001f00, 0x14000008 }, - { 0x13001f01, 0x14000008 }, - { 0x13001f02, 0x14000008 }, - { 0x13001f03, 0x14000008 }, - { 0x13001f04, 0x14000008 }, - { 0x13001f05, 0x14000008 }, - { 0x13001f06, 0x14000008 }, - { 0x13001f07, 0x14000008 }, - { 0x13001f08, 0x2400fff8 }, - { 0x13001f09, 0x2400fff8 }, - { 0x13001f0a, 0x2400fff8 }, - { 0x13001f0b, 0x2400fff8 }, - { 0x13001f0c, 0x2400fff8 }, - { 0x13001f0d, 0x2400fff8 }, - { 0x13001f0e, 0x2400fff8 }, - { 0x13001f0f, 0x2400fff8 }, - { 0x13001f10, 0x14000008 }, - { 0x13001f11, 0x14000008 }, - { 0x13001f12, 0x14000008 }, - { 0x13001f13, 0x14000008 }, - { 0x13001f14, 0x14000008 }, - { 0x13001f15, 0x14000008 }, - { 0x13001f18, 0x2400fff8 }, - { 0x13001f19, 0x2400fff8 }, - { 0x13001f1a, 0x2400fff8 }, - { 0x13001f1b, 0x2400fff8 }, - { 0x13001f1c, 0x2400fff8 }, - { 0x13001f1d, 0x2400fff8 }, - { 0x13001f20, 0x14000008 }, - { 0x13001f21, 0x14000008 }, - { 0x13001f22, 0x14000008 }, - { 0x13001f23, 0x14000008 }, - { 0x13001f24, 0x14000008 }, - { 0x13001f25, 0x14000008 }, - { 0x13001f26, 0x14000008 }, - { 0x13001f27, 0x14000008 }, - { 0x13001f28, 0x2400fff8 }, - { 0x13001f29, 0x2400fff8 }, - { 0x13001f2a, 0x2400fff8 }, - { 0x13001f2b, 0x2400fff8 }, - { 0x13001f2c, 0x2400fff8 }, - { 0x13001f2d, 0x2400fff8 }, - { 0x13001f2e, 0x2400fff8 }, - { 0x13001f2f, 0x2400fff8 }, - { 0x13001f30, 0x14000008 }, - { 0x13001f31, 0x14000008 }, - { 0x13001f32, 0x14000008 }, - { 0x13001f33, 0x14000008 }, - { 0x13001f34, 0x14000008 }, - { 0x13001f35, 0x14000008 }, - { 0x13001f36, 0x14000008 }, - { 0x13001f37, 0x14000008 }, - { 0x13001f38, 0x2400fff8 }, - { 0x13001f39, 0x2400fff8 }, - { 0x13001f3a, 0x2400fff8 }, - { 0x13001f3b, 0x2400fff8 }, - { 0x13001f3c, 0x2400fff8 }, - { 0x13001f3d, 0x2400fff8 }, - { 0x13001f3e, 0x2400fff8 }, - { 0x13001f3f, 0x2400fff8 }, - { 0x13001f40, 0x14000008 }, - { 0x13001f41, 0x14000008 }, - { 0x13001f42, 0x14000008 }, - { 0x13001f43, 0x14000008 }, - { 0x13001f44, 0x14000008 }, - { 0x13001f45, 0x14000008 }, - { 0x13001f48, 0x2400fff8 }, - { 0x13001f49, 0x2400fff8 }, - { 0x13001f4a, 0x2400fff8 }, - { 0x13001f4b, 0x2400fff8 }, - { 0x13001f4c, 0x2400fff8 }, - { 0x13001f4d, 0x2400fff8 }, - { 0x13001f50, 0x14000000 }, - { 0x13001f51, 0x14000008 }, - { 0x13001f52, 0x14000000 }, - { 0x13001f53, 0x14000008 }, - { 0x13001f54, 0x14000000 }, - { 0x13001f55, 0x14000008 }, - { 0x13001f56, 0x14000000 }, - { 0x13001f57, 0x14000008 }, - { 0x13001f59, 0x2400fff8 }, - { 0x13001f5b, 0x2400fff8 }, - { 0x13001f5d, 0x2400fff8 }, - { 0x13001f5f, 0x2400fff8 }, - { 0x13001f60, 0x14000008 }, - { 0x13001f61, 0x14000008 }, - { 0x13001f62, 0x14000008 }, - { 0x13001f63, 0x14000008 }, - { 0x13001f64, 0x14000008 }, - { 0x13001f65, 0x14000008 }, - { 0x13001f66, 0x14000008 }, - { 0x13001f67, 0x14000008 }, - { 0x13001f68, 0x2400fff8 }, - { 0x13001f69, 0x2400fff8 }, - { 0x13001f6a, 0x2400fff8 }, - { 0x13001f6b, 0x2400fff8 }, - { 0x13001f6c, 0x2400fff8 }, - { 0x13001f6d, 0x2400fff8 }, - { 0x13001f6e, 0x2400fff8 }, - { 0x13001f6f, 0x2400fff8 }, - { 0x13001f70, 0x1400004a }, - { 0x13001f71, 0x1400004a }, - { 0x13001f72, 0x14000056 }, - { 0x13001f73, 0x14000056 }, - { 0x13001f74, 0x14000056 }, - { 0x13001f75, 0x14000056 }, - { 0x13001f76, 0x14000064 }, - { 0x13001f77, 0x14000064 }, - { 0x13001f78, 0x14000080 }, - { 0x13001f79, 0x14000080 }, - { 0x13001f7a, 0x14000070 }, - { 0x13001f7b, 0x14000070 }, - { 0x13001f7c, 0x1400007e }, - { 0x13001f7d, 0x1400007e }, - { 0x13001f80, 0x14000008 }, - { 0x13001f81, 0x14000008 }, - { 0x13001f82, 0x14000008 }, - { 0x13001f83, 0x14000008 }, - { 0x13001f84, 0x14000008 }, - { 0x13001f85, 0x14000008 }, - { 0x13001f86, 0x14000008 }, - { 0x13001f87, 0x14000008 }, - { 0x13001f88, 0x2000fff8 }, - { 0x13001f89, 0x2000fff8 }, - { 0x13001f8a, 0x2000fff8 }, - { 0x13001f8b, 0x2000fff8 }, - { 0x13001f8c, 0x2000fff8 }, - { 0x13001f8d, 0x2000fff8 }, - { 0x13001f8e, 0x2000fff8 }, - { 0x13001f8f, 0x2000fff8 }, - { 0x13001f90, 0x14000008 }, - { 0x13001f91, 0x14000008 }, - { 0x13001f92, 0x14000008 }, - { 0x13001f93, 0x14000008 }, - { 0x13001f94, 0x14000008 }, - { 0x13001f95, 0x14000008 }, - { 0x13001f96, 0x14000008 }, - { 0x13001f97, 0x14000008 }, - { 0x13001f98, 0x2000fff8 }, - { 0x13001f99, 0x2000fff8 }, - { 0x13001f9a, 0x2000fff8 }, - { 0x13001f9b, 0x2000fff8 }, - { 0x13001f9c, 0x2000fff8 }, - { 0x13001f9d, 0x2000fff8 }, - { 0x13001f9e, 0x2000fff8 }, - { 0x13001f9f, 0x2000fff8 }, - { 0x13001fa0, 0x14000008 }, - { 0x13001fa1, 0x14000008 }, - { 0x13001fa2, 0x14000008 }, - { 0x13001fa3, 0x14000008 }, - { 0x13001fa4, 0x14000008 }, - { 0x13001fa5, 0x14000008 }, - { 0x13001fa6, 0x14000008 }, - { 0x13001fa7, 0x14000008 }, - { 0x13001fa8, 0x2000fff8 }, - { 0x13001fa9, 0x2000fff8 }, - { 0x13001faa, 0x2000fff8 }, - { 0x13001fab, 0x2000fff8 }, - { 0x13001fac, 0x2000fff8 }, - { 0x13001fad, 0x2000fff8 }, - { 0x13001fae, 0x2000fff8 }, - { 0x13001faf, 0x2000fff8 }, - { 0x13001fb0, 0x14000008 }, - { 0x13001fb1, 0x14000008 }, - { 0x13001fb2, 0x14000000 }, - { 0x13001fb3, 0x14000009 }, - { 0x13001fb4, 0x14000000 }, - { 0x13801fb6, 0x14000001 }, - { 0x13001fb8, 0x2400fff8 }, - { 0x13001fb9, 0x2400fff8 }, - { 0x13001fba, 0x2400ffb6 }, - { 0x13001fbb, 0x2400ffb6 }, - { 0x13001fbc, 0x2000fff7 }, - { 0x13001fbd, 0x60000000 }, - { 0x13001fbe, 0x1400e3db }, - { 0x13801fbf, 0x60000002 }, - { 0x13001fc2, 0x14000000 }, - { 0x13001fc3, 0x14000009 }, - { 0x13001fc4, 0x14000000 }, - { 0x13801fc6, 0x14000001 }, - { 0x13001fc8, 0x2400ffaa }, - { 0x13001fc9, 0x2400ffaa }, - { 0x13001fca, 0x2400ffaa }, - { 0x13001fcb, 0x2400ffaa }, - { 0x13001fcc, 0x2000fff7 }, - { 0x13801fcd, 0x60000002 }, - { 0x13001fd0, 0x14000008 }, - { 0x13001fd1, 0x14000008 }, - { 0x13801fd2, 0x14000001 }, - { 0x13801fd6, 0x14000001 }, - { 0x13001fd8, 0x2400fff8 }, - { 0x13001fd9, 0x2400fff8 }, - { 0x13001fda, 0x2400ff9c }, - { 0x13001fdb, 0x2400ff9c }, - { 0x13801fdd, 0x60000002 }, - { 0x13001fe0, 0x14000008 }, - { 0x13001fe1, 0x14000008 }, - { 0x13801fe2, 0x14000002 }, - { 0x13001fe5, 0x14000007 }, - { 0x13801fe6, 0x14000001 }, - { 0x13001fe8, 0x2400fff8 }, - { 0x13001fe9, 0x2400fff8 }, - { 0x13001fea, 0x2400ff90 }, - { 0x13001feb, 0x2400ff90 }, - { 0x13001fec, 0x2400fff9 }, - { 0x13801fed, 0x60000002 }, - { 0x13001ff2, 0x14000000 }, - { 0x13001ff3, 0x14000009 }, - { 0x13001ff4, 0x14000000 }, - { 0x13801ff6, 0x14000001 }, - { 0x13001ff8, 0x2400ff80 }, - { 0x13001ff9, 0x2400ff80 }, - { 0x13001ffa, 0x2400ff82 }, - { 0x13001ffb, 0x2400ff82 }, - { 0x13001ffc, 0x2000fff7 }, - { 0x13801ffd, 0x60000001 }, - { 0x09802000, 0x7400000a }, - { 0x0980200b, 0x04000004 }, - { 0x09802010, 0x44000005 }, - { 0x09802016, 0x54000001 }, - { 0x09002018, 0x50000000 }, - { 0x09002019, 0x4c000000 }, - { 0x0900201a, 0x58000000 }, - { 0x0980201b, 0x50000001 }, - { 0x0900201d, 0x4c000000 }, - { 0x0900201e, 0x58000000 }, - { 0x0900201f, 0x50000000 }, - { 0x09802020, 0x54000007 }, - { 0x09002028, 0x6c000000 }, - { 0x09002029, 0x70000000 }, - { 0x0980202a, 0x04000004 }, - { 0x0900202f, 0x74000000 }, - { 0x09802030, 0x54000008 }, - { 0x09002039, 0x50000000 }, - { 0x0900203a, 0x4c000000 }, - { 0x0980203b, 0x54000003 }, - { 0x0980203f, 0x40000001 }, - { 0x09802041, 0x54000002 }, - { 0x09002044, 0x64000000 }, - { 0x09002045, 0x58000000 }, - { 0x09002046, 0x48000000 }, - { 0x09802047, 0x5400000a }, - { 0x09002052, 0x64000000 }, - { 0x09002053, 0x54000000 }, - { 0x09002054, 0x40000000 }, - { 0x09802055, 0x54000009 }, - { 0x0900205f, 0x74000000 }, - { 0x09802060, 0x04000003 }, - { 0x0980206a, 0x04000005 }, - { 0x09002070, 0x3c000000 }, - { 0x21002071, 0x14000000 }, - { 0x09802074, 0x3c000005 }, - { 0x0980207a, 0x64000002 }, - { 0x0900207d, 0x58000000 }, - { 0x0900207e, 0x48000000 }, - { 0x2100207f, 0x14000000 }, - { 0x09802080, 0x3c000009 }, - { 0x0980208a, 0x64000002 }, - { 0x0900208d, 0x58000000 }, - { 0x0900208e, 0x48000000 }, - { 0x21802090, 0x18000004 }, - { 0x098020a0, 0x5c000015 }, - { 0x1b8020d0, 0x3000000c }, - { 0x1b8020dd, 0x2c000003 }, - { 0x1b0020e1, 0x30000000 }, - { 0x1b8020e2, 0x2c000002 }, - { 0x1b8020e5, 0x30000006 }, - { 0x09802100, 0x68000001 }, - { 0x09002102, 0x24000000 }, - { 0x09802103, 0x68000003 }, - { 0x09002107, 0x24000000 }, - { 0x09802108, 0x68000001 }, - { 0x0900210a, 0x14000000 }, - { 0x0980210b, 0x24000002 }, - { 0x0980210e, 0x14000001 }, - { 0x09802110, 0x24000002 }, - { 0x09002113, 0x14000000 }, - { 0x09002114, 0x68000000 }, - { 0x09002115, 0x24000000 }, - { 0x09802116, 0x68000002 }, - { 0x09802119, 0x24000004 }, - { 0x0980211e, 0x68000005 }, - { 0x09002124, 0x24000000 }, - { 0x09002125, 0x68000000 }, - { 0x13002126, 0x2400e2a3 }, - { 0x09002127, 0x68000000 }, - { 0x09002128, 0x24000000 }, - { 0x09002129, 0x68000000 }, - { 0x2100212a, 0x2400df41 }, - { 0x2100212b, 0x2400dfba }, - { 0x0980212c, 0x24000001 }, - { 0x0900212e, 0x68000000 }, - { 0x0900212f, 0x14000000 }, - { 0x09802130, 0x24000001 }, - { 0x09002132, 0x68000000 }, - { 0x09002133, 0x24000000 }, - { 0x09002134, 0x14000000 }, - { 0x09802135, 0x1c000003 }, - { 0x09002139, 0x14000000 }, - { 0x0980213a, 0x68000001 }, - { 0x0980213c, 0x14000001 }, - { 0x0980213e, 0x24000001 }, - { 0x09802140, 0x64000004 }, - { 0x09002145, 0x24000000 }, - { 0x09802146, 0x14000003 }, - { 0x0900214a, 0x68000000 }, - { 0x0900214b, 0x64000000 }, - { 0x0900214c, 0x68000000 }, - { 0x09802153, 0x3c00000c }, - { 0x09002160, 0x38000010 }, - { 0x09002161, 0x38000010 }, - { 0x09002162, 0x38000010 }, - { 0x09002163, 0x38000010 }, - { 0x09002164, 0x38000010 }, - { 0x09002165, 0x38000010 }, - { 0x09002166, 0x38000010 }, - { 0x09002167, 0x38000010 }, - { 0x09002168, 0x38000010 }, - { 0x09002169, 0x38000010 }, - { 0x0900216a, 0x38000010 }, - { 0x0900216b, 0x38000010 }, - { 0x0900216c, 0x38000010 }, - { 0x0900216d, 0x38000010 }, - { 0x0900216e, 0x38000010 }, - { 0x0900216f, 0x38000010 }, - { 0x09002170, 0x3800fff0 }, - { 0x09002171, 0x3800fff0 }, - { 0x09002172, 0x3800fff0 }, - { 0x09002173, 0x3800fff0 }, - { 0x09002174, 0x3800fff0 }, - { 0x09002175, 0x3800fff0 }, - { 0x09002176, 0x3800fff0 }, - { 0x09002177, 0x3800fff0 }, - { 0x09002178, 0x3800fff0 }, - { 0x09002179, 0x3800fff0 }, - { 0x0900217a, 0x3800fff0 }, - { 0x0900217b, 0x3800fff0 }, - { 0x0900217c, 0x3800fff0 }, - { 0x0900217d, 0x3800fff0 }, - { 0x0900217e, 0x3800fff0 }, - { 0x0900217f, 0x3800fff0 }, - { 0x09802180, 0x38000003 }, - { 0x09802190, 0x64000004 }, - { 0x09802195, 0x68000004 }, - { 0x0980219a, 0x64000001 }, - { 0x0980219c, 0x68000003 }, - { 0x090021a0, 0x64000000 }, - { 0x098021a1, 0x68000001 }, - { 0x090021a3, 0x64000000 }, - { 0x098021a4, 0x68000001 }, - { 0x090021a6, 0x64000000 }, - { 0x098021a7, 0x68000006 }, - { 0x090021ae, 0x64000000 }, - { 0x098021af, 0x6800001e }, - { 0x098021ce, 0x64000001 }, - { 0x098021d0, 0x68000001 }, - { 0x090021d2, 0x64000000 }, - { 0x090021d3, 0x68000000 }, - { 0x090021d4, 0x64000000 }, - { 0x098021d5, 0x6800001e }, - { 0x098021f4, 0x6400010b }, - { 0x09802300, 0x68000007 }, - { 0x09802308, 0x64000003 }, - { 0x0980230c, 0x68000013 }, - { 0x09802320, 0x64000001 }, - { 0x09802322, 0x68000006 }, - { 0x09002329, 0x58000000 }, - { 0x0900232a, 0x48000000 }, - { 0x0980232b, 0x68000050 }, - { 0x0900237c, 0x64000000 }, - { 0x0980237d, 0x6800001d }, - { 0x0980239b, 0x64000018 }, - { 0x090023b4, 0x58000000 }, - { 0x090023b5, 0x48000000 }, - { 0x090023b6, 0x54000000 }, - { 0x098023b7, 0x68000024 }, - { 0x09802400, 0x68000026 }, - { 0x09802440, 0x6800000a }, - { 0x09802460, 0x3c00003b }, - { 0x0980249c, 0x68000019 }, - { 0x090024b6, 0x6800001a }, - { 0x090024b7, 0x6800001a }, - { 0x090024b8, 0x6800001a }, - { 0x090024b9, 0x6800001a }, - { 0x090024ba, 0x6800001a }, - { 0x090024bb, 0x6800001a }, - { 0x090024bc, 0x6800001a }, - { 0x090024bd, 0x6800001a }, - { 0x090024be, 0x6800001a }, - { 0x090024bf, 0x6800001a }, - { 0x090024c0, 0x6800001a }, - { 0x090024c1, 0x6800001a }, - { 0x090024c2, 0x6800001a }, - { 0x090024c3, 0x6800001a }, - { 0x090024c4, 0x6800001a }, - { 0x090024c5, 0x6800001a }, - { 0x090024c6, 0x6800001a }, - { 0x090024c7, 0x6800001a }, - { 0x090024c8, 0x6800001a }, - { 0x090024c9, 0x6800001a }, - { 0x090024ca, 0x6800001a }, - { 0x090024cb, 0x6800001a }, - { 0x090024cc, 0x6800001a }, - { 0x090024cd, 0x6800001a }, - { 0x090024ce, 0x6800001a }, - { 0x090024cf, 0x6800001a }, - { 0x090024d0, 0x6800ffe6 }, - { 0x090024d1, 0x6800ffe6 }, - { 0x090024d2, 0x6800ffe6 }, - { 0x090024d3, 0x6800ffe6 }, - { 0x090024d4, 0x6800ffe6 }, - { 0x090024d5, 0x6800ffe6 }, - { 0x090024d6, 0x6800ffe6 }, - { 0x090024d7, 0x6800ffe6 }, - { 0x090024d8, 0x6800ffe6 }, - { 0x090024d9, 0x6800ffe6 }, - { 0x090024da, 0x6800ffe6 }, - { 0x090024db, 0x6800ffe6 }, - { 0x090024dc, 0x6800ffe6 }, - { 0x090024dd, 0x6800ffe6 }, - { 0x090024de, 0x6800ffe6 }, - { 0x090024df, 0x6800ffe6 }, - { 0x090024e0, 0x6800ffe6 }, - { 0x090024e1, 0x6800ffe6 }, - { 0x090024e2, 0x6800ffe6 }, - { 0x090024e3, 0x6800ffe6 }, - { 0x090024e4, 0x6800ffe6 }, - { 0x090024e5, 0x6800ffe6 }, - { 0x090024e6, 0x6800ffe6 }, - { 0x090024e7, 0x6800ffe6 }, - { 0x090024e8, 0x6800ffe6 }, - { 0x090024e9, 0x6800ffe6 }, - { 0x098024ea, 0x3c000015 }, - { 0x09802500, 0x680000b6 }, - { 0x090025b7, 0x64000000 }, - { 0x098025b8, 0x68000008 }, - { 0x090025c1, 0x64000000 }, - { 0x098025c2, 0x68000035 }, - { 0x098025f8, 0x64000007 }, - { 0x09802600, 0x6800006e }, - { 0x0900266f, 0x64000000 }, - { 0x09802670, 0x6800002c }, - { 0x098026a0, 0x68000011 }, - { 0x09802701, 0x68000003 }, - { 0x09802706, 0x68000003 }, - { 0x0980270c, 0x6800001b }, - { 0x09802729, 0x68000022 }, - { 0x0900274d, 0x68000000 }, - { 0x0980274f, 0x68000003 }, - { 0x09002756, 0x68000000 }, - { 0x09802758, 0x68000006 }, - { 0x09802761, 0x68000006 }, - { 0x09002768, 0x58000000 }, - { 0x09002769, 0x48000000 }, - { 0x0900276a, 0x58000000 }, - { 0x0900276b, 0x48000000 }, - { 0x0900276c, 0x58000000 }, - { 0x0900276d, 0x48000000 }, - { 0x0900276e, 0x58000000 }, - { 0x0900276f, 0x48000000 }, - { 0x09002770, 0x58000000 }, - { 0x09002771, 0x48000000 }, - { 0x09002772, 0x58000000 }, - { 0x09002773, 0x48000000 }, - { 0x09002774, 0x58000000 }, - { 0x09002775, 0x48000000 }, - { 0x09802776, 0x3c00001d }, - { 0x09002794, 0x68000000 }, - { 0x09802798, 0x68000017 }, - { 0x098027b1, 0x6800000d }, - { 0x098027c0, 0x64000004 }, - { 0x090027c5, 0x58000000 }, - { 0x090027c6, 0x48000000 }, - { 0x098027d0, 0x64000015 }, - { 0x090027e6, 0x58000000 }, - { 0x090027e7, 0x48000000 }, - { 0x090027e8, 0x58000000 }, - { 0x090027e9, 0x48000000 }, - { 0x090027ea, 0x58000000 }, - { 0x090027eb, 0x48000000 }, - { 0x098027f0, 0x6400000f }, - { 0x04802800, 0x680000ff }, - { 0x09802900, 0x64000082 }, - { 0x09002983, 0x58000000 }, - { 0x09002984, 0x48000000 }, - { 0x09002985, 0x58000000 }, - { 0x09002986, 0x48000000 }, - { 0x09002987, 0x58000000 }, - { 0x09002988, 0x48000000 }, - { 0x09002989, 0x58000000 }, - { 0x0900298a, 0x48000000 }, - { 0x0900298b, 0x58000000 }, - { 0x0900298c, 0x48000000 }, - { 0x0900298d, 0x58000000 }, - { 0x0900298e, 0x48000000 }, - { 0x0900298f, 0x58000000 }, - { 0x09002990, 0x48000000 }, - { 0x09002991, 0x58000000 }, - { 0x09002992, 0x48000000 }, - { 0x09002993, 0x58000000 }, - { 0x09002994, 0x48000000 }, - { 0x09002995, 0x58000000 }, - { 0x09002996, 0x48000000 }, - { 0x09002997, 0x58000000 }, - { 0x09002998, 0x48000000 }, - { 0x09802999, 0x6400003e }, - { 0x090029d8, 0x58000000 }, - { 0x090029d9, 0x48000000 }, - { 0x090029da, 0x58000000 }, - { 0x090029db, 0x48000000 }, - { 0x098029dc, 0x6400001f }, - { 0x090029fc, 0x58000000 }, - { 0x090029fd, 0x48000000 }, - { 0x098029fe, 0x64000101 }, - { 0x09802b00, 0x68000013 }, - { 0x11002c00, 0x24000030 }, - { 0x11002c01, 0x24000030 }, - { 0x11002c02, 0x24000030 }, - { 0x11002c03, 0x24000030 }, - { 0x11002c04, 0x24000030 }, - { 0x11002c05, 0x24000030 }, - { 0x11002c06, 0x24000030 }, - { 0x11002c07, 0x24000030 }, - { 0x11002c08, 0x24000030 }, - { 0x11002c09, 0x24000030 }, - { 0x11002c0a, 0x24000030 }, - { 0x11002c0b, 0x24000030 }, - { 0x11002c0c, 0x24000030 }, - { 0x11002c0d, 0x24000030 }, - { 0x11002c0e, 0x24000030 }, - { 0x11002c0f, 0x24000030 }, - { 0x11002c10, 0x24000030 }, - { 0x11002c11, 0x24000030 }, - { 0x11002c12, 0x24000030 }, - { 0x11002c13, 0x24000030 }, - { 0x11002c14, 0x24000030 }, - { 0x11002c15, 0x24000030 }, - { 0x11002c16, 0x24000030 }, - { 0x11002c17, 0x24000030 }, - { 0x11002c18, 0x24000030 }, - { 0x11002c19, 0x24000030 }, - { 0x11002c1a, 0x24000030 }, - { 0x11002c1b, 0x24000030 }, - { 0x11002c1c, 0x24000030 }, - { 0x11002c1d, 0x24000030 }, - { 0x11002c1e, 0x24000030 }, - { 0x11002c1f, 0x24000030 }, - { 0x11002c20, 0x24000030 }, - { 0x11002c21, 0x24000030 }, - { 0x11002c22, 0x24000030 }, - { 0x11002c23, 0x24000030 }, - { 0x11002c24, 0x24000030 }, - { 0x11002c25, 0x24000030 }, - { 0x11002c26, 0x24000030 }, - { 0x11002c27, 0x24000030 }, - { 0x11002c28, 0x24000030 }, - { 0x11002c29, 0x24000030 }, - { 0x11002c2a, 0x24000030 }, - { 0x11002c2b, 0x24000030 }, - { 0x11002c2c, 0x24000030 }, - { 0x11002c2d, 0x24000030 }, - { 0x11002c2e, 0x24000030 }, - { 0x11002c30, 0x1400ffd0 }, - { 0x11002c31, 0x1400ffd0 }, - { 0x11002c32, 0x1400ffd0 }, - { 0x11002c33, 0x1400ffd0 }, - { 0x11002c34, 0x1400ffd0 }, - { 0x11002c35, 0x1400ffd0 }, - { 0x11002c36, 0x1400ffd0 }, - { 0x11002c37, 0x1400ffd0 }, - { 0x11002c38, 0x1400ffd0 }, - { 0x11002c39, 0x1400ffd0 }, - { 0x11002c3a, 0x1400ffd0 }, - { 0x11002c3b, 0x1400ffd0 }, - { 0x11002c3c, 0x1400ffd0 }, - { 0x11002c3d, 0x1400ffd0 }, - { 0x11002c3e, 0x1400ffd0 }, - { 0x11002c3f, 0x1400ffd0 }, - { 0x11002c40, 0x1400ffd0 }, - { 0x11002c41, 0x1400ffd0 }, - { 0x11002c42, 0x1400ffd0 }, - { 0x11002c43, 0x1400ffd0 }, - { 0x11002c44, 0x1400ffd0 }, - { 0x11002c45, 0x1400ffd0 }, - { 0x11002c46, 0x1400ffd0 }, - { 0x11002c47, 0x1400ffd0 }, - { 0x11002c48, 0x1400ffd0 }, - { 0x11002c49, 0x1400ffd0 }, - { 0x11002c4a, 0x1400ffd0 }, - { 0x11002c4b, 0x1400ffd0 }, - { 0x11002c4c, 0x1400ffd0 }, - { 0x11002c4d, 0x1400ffd0 }, - { 0x11002c4e, 0x1400ffd0 }, - { 0x11002c4f, 0x1400ffd0 }, - { 0x11002c50, 0x1400ffd0 }, - { 0x11002c51, 0x1400ffd0 }, - { 0x11002c52, 0x1400ffd0 }, - { 0x11002c53, 0x1400ffd0 }, - { 0x11002c54, 0x1400ffd0 }, - { 0x11002c55, 0x1400ffd0 }, - { 0x11002c56, 0x1400ffd0 }, - { 0x11002c57, 0x1400ffd0 }, - { 0x11002c58, 0x1400ffd0 }, - { 0x11002c59, 0x1400ffd0 }, - { 0x11002c5a, 0x1400ffd0 }, - { 0x11002c5b, 0x1400ffd0 }, - { 0x11002c5c, 0x1400ffd0 }, - { 0x11002c5d, 0x1400ffd0 }, - { 0x11002c5e, 0x1400ffd0 }, - { 0x0a002c80, 0x24000001 }, - { 0x0a002c81, 0x1400ffff }, - { 0x0a002c82, 0x24000001 }, - { 0x0a002c83, 0x1400ffff }, - { 0x0a002c84, 0x24000001 }, - { 0x0a002c85, 0x1400ffff }, - { 0x0a002c86, 0x24000001 }, - { 0x0a002c87, 0x1400ffff }, - { 0x0a002c88, 0x24000001 }, - { 0x0a002c89, 0x1400ffff }, - { 0x0a002c8a, 0x24000001 }, - { 0x0a002c8b, 0x1400ffff }, - { 0x0a002c8c, 0x24000001 }, - { 0x0a002c8d, 0x1400ffff }, - { 0x0a002c8e, 0x24000001 }, - { 0x0a002c8f, 0x1400ffff }, - { 0x0a002c90, 0x24000001 }, - { 0x0a002c91, 0x1400ffff }, - { 0x0a002c92, 0x24000001 }, - { 0x0a002c93, 0x1400ffff }, - { 0x0a002c94, 0x24000001 }, - { 0x0a002c95, 0x1400ffff }, - { 0x0a002c96, 0x24000001 }, - { 0x0a002c97, 0x1400ffff }, - { 0x0a002c98, 0x24000001 }, - { 0x0a002c99, 0x1400ffff }, - { 0x0a002c9a, 0x24000001 }, - { 0x0a002c9b, 0x1400ffff }, - { 0x0a002c9c, 0x24000001 }, - { 0x0a002c9d, 0x1400ffff }, - { 0x0a002c9e, 0x24000001 }, - { 0x0a002c9f, 0x1400ffff }, - { 0x0a002ca0, 0x24000001 }, - { 0x0a002ca1, 0x1400ffff }, - { 0x0a002ca2, 0x24000001 }, - { 0x0a002ca3, 0x1400ffff }, - { 0x0a002ca4, 0x24000001 }, - { 0x0a002ca5, 0x1400ffff }, - { 0x0a002ca6, 0x24000001 }, - { 0x0a002ca7, 0x1400ffff }, - { 0x0a002ca8, 0x24000001 }, - { 0x0a002ca9, 0x1400ffff }, - { 0x0a002caa, 0x24000001 }, - { 0x0a002cab, 0x1400ffff }, - { 0x0a002cac, 0x24000001 }, - { 0x0a002cad, 0x1400ffff }, - { 0x0a002cae, 0x24000001 }, - { 0x0a002caf, 0x1400ffff }, - { 0x0a002cb0, 0x24000001 }, - { 0x0a002cb1, 0x1400ffff }, - { 0x0a002cb2, 0x24000001 }, - { 0x0a002cb3, 0x1400ffff }, - { 0x0a002cb4, 0x24000001 }, - { 0x0a002cb5, 0x1400ffff }, - { 0x0a002cb6, 0x24000001 }, - { 0x0a002cb7, 0x1400ffff }, - { 0x0a002cb8, 0x24000001 }, - { 0x0a002cb9, 0x1400ffff }, - { 0x0a002cba, 0x24000001 }, - { 0x0a002cbb, 0x1400ffff }, - { 0x0a002cbc, 0x24000001 }, - { 0x0a002cbd, 0x1400ffff }, - { 0x0a002cbe, 0x24000001 }, - { 0x0a002cbf, 0x1400ffff }, - { 0x0a002cc0, 0x24000001 }, - { 0x0a002cc1, 0x1400ffff }, - { 0x0a002cc2, 0x24000001 }, - { 0x0a002cc3, 0x1400ffff }, - { 0x0a002cc4, 0x24000001 }, - { 0x0a002cc5, 0x1400ffff }, - { 0x0a002cc6, 0x24000001 }, - { 0x0a002cc7, 0x1400ffff }, - { 0x0a002cc8, 0x24000001 }, - { 0x0a002cc9, 0x1400ffff }, - { 0x0a002cca, 0x24000001 }, - { 0x0a002ccb, 0x1400ffff }, - { 0x0a002ccc, 0x24000001 }, - { 0x0a002ccd, 0x1400ffff }, - { 0x0a002cce, 0x24000001 }, - { 0x0a002ccf, 0x1400ffff }, - { 0x0a002cd0, 0x24000001 }, - { 0x0a002cd1, 0x1400ffff }, - { 0x0a002cd2, 0x24000001 }, - { 0x0a002cd3, 0x1400ffff }, - { 0x0a002cd4, 0x24000001 }, - { 0x0a002cd5, 0x1400ffff }, - { 0x0a002cd6, 0x24000001 }, - { 0x0a002cd7, 0x1400ffff }, - { 0x0a002cd8, 0x24000001 }, - { 0x0a002cd9, 0x1400ffff }, - { 0x0a002cda, 0x24000001 }, - { 0x0a002cdb, 0x1400ffff }, - { 0x0a002cdc, 0x24000001 }, - { 0x0a002cdd, 0x1400ffff }, - { 0x0a002cde, 0x24000001 }, - { 0x0a002cdf, 0x1400ffff }, - { 0x0a002ce0, 0x24000001 }, - { 0x0a002ce1, 0x1400ffff }, - { 0x0a002ce2, 0x24000001 }, - { 0x0a002ce3, 0x1400ffff }, - { 0x0a002ce4, 0x14000000 }, - { 0x0a802ce5, 0x68000005 }, - { 0x0a802cf9, 0x54000003 }, - { 0x0a002cfd, 0x3c000000 }, - { 0x0a802cfe, 0x54000001 }, - { 0x10002d00, 0x1400e3a0 }, - { 0x10002d01, 0x1400e3a0 }, - { 0x10002d02, 0x1400e3a0 }, - { 0x10002d03, 0x1400e3a0 }, - { 0x10002d04, 0x1400e3a0 }, - { 0x10002d05, 0x1400e3a0 }, - { 0x10002d06, 0x1400e3a0 }, - { 0x10002d07, 0x1400e3a0 }, - { 0x10002d08, 0x1400e3a0 }, - { 0x10002d09, 0x1400e3a0 }, - { 0x10002d0a, 0x1400e3a0 }, - { 0x10002d0b, 0x1400e3a0 }, - { 0x10002d0c, 0x1400e3a0 }, - { 0x10002d0d, 0x1400e3a0 }, - { 0x10002d0e, 0x1400e3a0 }, - { 0x10002d0f, 0x1400e3a0 }, - { 0x10002d10, 0x1400e3a0 }, - { 0x10002d11, 0x1400e3a0 }, - { 0x10002d12, 0x1400e3a0 }, - { 0x10002d13, 0x1400e3a0 }, - { 0x10002d14, 0x1400e3a0 }, - { 0x10002d15, 0x1400e3a0 }, - { 0x10002d16, 0x1400e3a0 }, - { 0x10002d17, 0x1400e3a0 }, - { 0x10002d18, 0x1400e3a0 }, - { 0x10002d19, 0x1400e3a0 }, - { 0x10002d1a, 0x1400e3a0 }, - { 0x10002d1b, 0x1400e3a0 }, - { 0x10002d1c, 0x1400e3a0 }, - { 0x10002d1d, 0x1400e3a0 }, - { 0x10002d1e, 0x1400e3a0 }, - { 0x10002d1f, 0x1400e3a0 }, - { 0x10002d20, 0x1400e3a0 }, - { 0x10002d21, 0x1400e3a0 }, - { 0x10002d22, 0x1400e3a0 }, - { 0x10002d23, 0x1400e3a0 }, - { 0x10002d24, 0x1400e3a0 }, - { 0x10002d25, 0x1400e3a0 }, - { 0x3a802d30, 0x1c000035 }, - { 0x3a002d6f, 0x18000000 }, - { 0x0f802d80, 0x1c000016 }, - { 0x0f802da0, 0x1c000006 }, - { 0x0f802da8, 0x1c000006 }, - { 0x0f802db0, 0x1c000006 }, - { 0x0f802db8, 0x1c000006 }, - { 0x0f802dc0, 0x1c000006 }, - { 0x0f802dc8, 0x1c000006 }, - { 0x0f802dd0, 0x1c000006 }, - { 0x0f802dd8, 0x1c000006 }, - { 0x09802e00, 0x54000001 }, - { 0x09002e02, 0x50000000 }, - { 0x09002e03, 0x4c000000 }, - { 0x09002e04, 0x50000000 }, - { 0x09002e05, 0x4c000000 }, - { 0x09802e06, 0x54000002 }, - { 0x09002e09, 0x50000000 }, - { 0x09002e0a, 0x4c000000 }, - { 0x09002e0b, 0x54000000 }, - { 0x09002e0c, 0x50000000 }, - { 0x09002e0d, 0x4c000000 }, - { 0x09802e0e, 0x54000008 }, - { 0x09002e17, 0x44000000 }, - { 0x09002e1c, 0x50000000 }, - { 0x09002e1d, 0x4c000000 }, - { 0x16802e80, 0x68000019 }, - { 0x16802e9b, 0x68000058 }, - { 0x16802f00, 0x680000d5 }, - { 0x09802ff0, 0x6800000b }, - { 0x09003000, 0x74000000 }, - { 0x09803001, 0x54000002 }, - { 0x09003004, 0x68000000 }, - { 0x16003005, 0x18000000 }, - { 0x09003006, 0x1c000000 }, - { 0x16003007, 0x38000000 }, - { 0x09003008, 0x58000000 }, - { 0x09003009, 0x48000000 }, - { 0x0900300a, 0x58000000 }, - { 0x0900300b, 0x48000000 }, - { 0x0900300c, 0x58000000 }, - { 0x0900300d, 0x48000000 }, - { 0x0900300e, 0x58000000 }, - { 0x0900300f, 0x48000000 }, - { 0x09003010, 0x58000000 }, - { 0x09003011, 0x48000000 }, - { 0x09803012, 0x68000001 }, - { 0x09003014, 0x58000000 }, - { 0x09003015, 0x48000000 }, - { 0x09003016, 0x58000000 }, - { 0x09003017, 0x48000000 }, - { 0x09003018, 0x58000000 }, - { 0x09003019, 0x48000000 }, - { 0x0900301a, 0x58000000 }, - { 0x0900301b, 0x48000000 }, - { 0x0900301c, 0x44000000 }, - { 0x0900301d, 0x58000000 }, - { 0x0980301e, 0x48000001 }, - { 0x09003020, 0x68000000 }, - { 0x16803021, 0x38000008 }, - { 0x1b80302a, 0x30000005 }, - { 0x09003030, 0x44000000 }, - { 0x09803031, 0x18000004 }, - { 0x09803036, 0x68000001 }, - { 0x16803038, 0x38000002 }, - { 0x1600303b, 0x18000000 }, - { 0x0900303c, 0x1c000000 }, - { 0x0900303d, 0x54000000 }, - { 0x0980303e, 0x68000001 }, - { 0x1a803041, 0x1c000055 }, - { 0x1b803099, 0x30000001 }, - { 0x0980309b, 0x60000001 }, - { 0x1a80309d, 0x18000001 }, - { 0x1a00309f, 0x1c000000 }, - { 0x090030a0, 0x44000000 }, - { 0x1d8030a1, 0x1c000059 }, - { 0x090030fb, 0x54000000 }, - { 0x098030fc, 0x18000002 }, - { 0x1d0030ff, 0x1c000000 }, - { 0x03803105, 0x1c000027 }, - { 0x17803131, 0x1c00005d }, - { 0x09803190, 0x68000001 }, - { 0x09803192, 0x3c000003 }, - { 0x09803196, 0x68000009 }, - { 0x038031a0, 0x1c000017 }, - { 0x098031c0, 0x6800000f }, - { 0x1d8031f0, 0x1c00000f }, - { 0x17803200, 0x6800001e }, - { 0x09803220, 0x3c000009 }, - { 0x0980322a, 0x68000019 }, - { 0x09003250, 0x68000000 }, - { 0x09803251, 0x3c00000e }, - { 0x17803260, 0x6800001f }, - { 0x09803280, 0x3c000009 }, - { 0x0980328a, 0x68000026 }, - { 0x098032b1, 0x3c00000e }, - { 0x098032c0, 0x6800003e }, - { 0x09803300, 0x680000ff }, - { 0x16803400, 0x1c0019b5 }, - { 0x09804dc0, 0x6800003f }, - { 0x16804e00, 0x1c0051bb }, - { 0x3c80a000, 0x1c000014 }, - { 0x3c00a015, 0x18000000 }, - { 0x3c80a016, 0x1c000476 }, - { 0x3c80a490, 0x68000036 }, - { 0x0980a700, 0x60000016 }, - { 0x3080a800, 0x1c000001 }, - { 0x3000a802, 0x28000000 }, - { 0x3080a803, 0x1c000002 }, - { 0x3000a806, 0x30000000 }, - { 0x3080a807, 0x1c000003 }, - { 0x3000a80b, 0x30000000 }, - { 0x3080a80c, 0x1c000016 }, - { 0x3080a823, 0x28000001 }, - { 0x3080a825, 0x30000001 }, - { 0x3000a827, 0x28000000 }, - { 0x3080a828, 0x68000003 }, - { 0x1780ac00, 0x1c002ba3 }, - { 0x0980d800, 0x1000037f }, - { 0x0980db80, 0x1000007f }, - { 0x0980dc00, 0x100003ff }, - { 0x0980e000, 0x0c0018ff }, - { 0x1680f900, 0x1c00012d }, - { 0x1680fa30, 0x1c00003a }, - { 0x1680fa70, 0x1c000069 }, - { 0x2180fb00, 0x14000006 }, - { 0x0180fb13, 0x14000004 }, - { 0x1900fb1d, 0x1c000000 }, - { 0x1900fb1e, 0x30000000 }, - { 0x1980fb1f, 0x1c000009 }, - { 0x1900fb29, 0x64000000 }, - { 0x1980fb2a, 0x1c00000c }, - { 0x1980fb38, 0x1c000004 }, - { 0x1900fb3e, 0x1c000000 }, - { 0x1980fb40, 0x1c000001 }, - { 0x1980fb43, 0x1c000001 }, - { 0x1980fb46, 0x1c00006b }, - { 0x0080fbd3, 0x1c00016a }, - { 0x0900fd3e, 0x58000000 }, - { 0x0900fd3f, 0x48000000 }, - { 0x0080fd50, 0x1c00003f }, - { 0x0080fd92, 0x1c000035 }, - { 0x0080fdf0, 0x1c00000b }, - { 0x0000fdfc, 0x5c000000 }, - { 0x0900fdfd, 0x68000000 }, - { 0x1b80fe00, 0x3000000f }, - { 0x0980fe10, 0x54000006 }, - { 0x0900fe17, 0x58000000 }, - { 0x0900fe18, 0x48000000 }, - { 0x0900fe19, 0x54000000 }, - { 0x1b80fe20, 0x30000003 }, - { 0x0900fe30, 0x54000000 }, - { 0x0980fe31, 0x44000001 }, - { 0x0980fe33, 0x40000001 }, - { 0x0900fe35, 0x58000000 }, - { 0x0900fe36, 0x48000000 }, - { 0x0900fe37, 0x58000000 }, - { 0x0900fe38, 0x48000000 }, - { 0x0900fe39, 0x58000000 }, - { 0x0900fe3a, 0x48000000 }, - { 0x0900fe3b, 0x58000000 }, - { 0x0900fe3c, 0x48000000 }, - { 0x0900fe3d, 0x58000000 }, - { 0x0900fe3e, 0x48000000 }, - { 0x0900fe3f, 0x58000000 }, - { 0x0900fe40, 0x48000000 }, - { 0x0900fe41, 0x58000000 }, - { 0x0900fe42, 0x48000000 }, - { 0x0900fe43, 0x58000000 }, - { 0x0900fe44, 0x48000000 }, - { 0x0980fe45, 0x54000001 }, - { 0x0900fe47, 0x58000000 }, - { 0x0900fe48, 0x48000000 }, - { 0x0980fe49, 0x54000003 }, - { 0x0980fe4d, 0x40000002 }, - { 0x0980fe50, 0x54000002 }, - { 0x0980fe54, 0x54000003 }, - { 0x0900fe58, 0x44000000 }, - { 0x0900fe59, 0x58000000 }, - { 0x0900fe5a, 0x48000000 }, - { 0x0900fe5b, 0x58000000 }, - { 0x0900fe5c, 0x48000000 }, - { 0x0900fe5d, 0x58000000 }, - { 0x0900fe5e, 0x48000000 }, - { 0x0980fe5f, 0x54000002 }, - { 0x0900fe62, 0x64000000 }, - { 0x0900fe63, 0x44000000 }, - { 0x0980fe64, 0x64000002 }, - { 0x0900fe68, 0x54000000 }, - { 0x0900fe69, 0x5c000000 }, - { 0x0980fe6a, 0x54000001 }, - { 0x0080fe70, 0x1c000004 }, - { 0x0080fe76, 0x1c000086 }, - { 0x0900feff, 0x04000000 }, - { 0x0980ff01, 0x54000002 }, - { 0x0900ff04, 0x5c000000 }, - { 0x0980ff05, 0x54000002 }, - { 0x0900ff08, 0x58000000 }, - { 0x0900ff09, 0x48000000 }, - { 0x0900ff0a, 0x54000000 }, - { 0x0900ff0b, 0x64000000 }, - { 0x0900ff0c, 0x54000000 }, - { 0x0900ff0d, 0x44000000 }, - { 0x0980ff0e, 0x54000001 }, - { 0x0980ff10, 0x34000009 }, - { 0x0980ff1a, 0x54000001 }, - { 0x0980ff1c, 0x64000002 }, - { 0x0980ff1f, 0x54000001 }, - { 0x2100ff21, 0x24000020 }, - { 0x2100ff22, 0x24000020 }, - { 0x2100ff23, 0x24000020 }, - { 0x2100ff24, 0x24000020 }, - { 0x2100ff25, 0x24000020 }, - { 0x2100ff26, 0x24000020 }, - { 0x2100ff27, 0x24000020 }, - { 0x2100ff28, 0x24000020 }, - { 0x2100ff29, 0x24000020 }, - { 0x2100ff2a, 0x24000020 }, - { 0x2100ff2b, 0x24000020 }, - { 0x2100ff2c, 0x24000020 }, - { 0x2100ff2d, 0x24000020 }, - { 0x2100ff2e, 0x24000020 }, - { 0x2100ff2f, 0x24000020 }, - { 0x2100ff30, 0x24000020 }, - { 0x2100ff31, 0x24000020 }, - { 0x2100ff32, 0x24000020 }, - { 0x2100ff33, 0x24000020 }, - { 0x2100ff34, 0x24000020 }, - { 0x2100ff35, 0x24000020 }, - { 0x2100ff36, 0x24000020 }, - { 0x2100ff37, 0x24000020 }, - { 0x2100ff38, 0x24000020 }, - { 0x2100ff39, 0x24000020 }, - { 0x2100ff3a, 0x24000020 }, - { 0x0900ff3b, 0x58000000 }, - { 0x0900ff3c, 0x54000000 }, - { 0x0900ff3d, 0x48000000 }, - { 0x0900ff3e, 0x60000000 }, - { 0x0900ff3f, 0x40000000 }, - { 0x0900ff40, 0x60000000 }, - { 0x2100ff41, 0x1400ffe0 }, - { 0x2100ff42, 0x1400ffe0 }, - { 0x2100ff43, 0x1400ffe0 }, - { 0x2100ff44, 0x1400ffe0 }, - { 0x2100ff45, 0x1400ffe0 }, - { 0x2100ff46, 0x1400ffe0 }, - { 0x2100ff47, 0x1400ffe0 }, - { 0x2100ff48, 0x1400ffe0 }, - { 0x2100ff49, 0x1400ffe0 }, - { 0x2100ff4a, 0x1400ffe0 }, - { 0x2100ff4b, 0x1400ffe0 }, - { 0x2100ff4c, 0x1400ffe0 }, - { 0x2100ff4d, 0x1400ffe0 }, - { 0x2100ff4e, 0x1400ffe0 }, - { 0x2100ff4f, 0x1400ffe0 }, - { 0x2100ff50, 0x1400ffe0 }, - { 0x2100ff51, 0x1400ffe0 }, - { 0x2100ff52, 0x1400ffe0 }, - { 0x2100ff53, 0x1400ffe0 }, - { 0x2100ff54, 0x1400ffe0 }, - { 0x2100ff55, 0x1400ffe0 }, - { 0x2100ff56, 0x1400ffe0 }, - { 0x2100ff57, 0x1400ffe0 }, - { 0x2100ff58, 0x1400ffe0 }, - { 0x2100ff59, 0x1400ffe0 }, - { 0x2100ff5a, 0x1400ffe0 }, - { 0x0900ff5b, 0x58000000 }, - { 0x0900ff5c, 0x64000000 }, - { 0x0900ff5d, 0x48000000 }, - { 0x0900ff5e, 0x64000000 }, - { 0x0900ff5f, 0x58000000 }, - { 0x0900ff60, 0x48000000 }, - { 0x0900ff61, 0x54000000 }, - { 0x0900ff62, 0x58000000 }, - { 0x0900ff63, 0x48000000 }, - { 0x0980ff64, 0x54000001 }, - { 0x1d80ff66, 0x1c000009 }, - { 0x0900ff70, 0x18000000 }, - { 0x1d80ff71, 0x1c00002c }, - { 0x0980ff9e, 0x18000001 }, - { 0x1780ffa0, 0x1c00001e }, - { 0x1780ffc2, 0x1c000005 }, - { 0x1780ffca, 0x1c000005 }, - { 0x1780ffd2, 0x1c000005 }, - { 0x1780ffda, 0x1c000002 }, - { 0x0980ffe0, 0x5c000001 }, - { 0x0900ffe2, 0x64000000 }, - { 0x0900ffe3, 0x60000000 }, - { 0x0900ffe4, 0x68000000 }, - { 0x0980ffe5, 0x5c000001 }, - { 0x0900ffe8, 0x68000000 }, - { 0x0980ffe9, 0x64000003 }, - { 0x0980ffed, 0x68000001 }, - { 0x0980fff9, 0x04000002 }, - { 0x0980fffc, 0x68000001 }, - { 0x23810000, 0x1c00000b }, - { 0x2381000d, 0x1c000019 }, - { 0x23810028, 0x1c000012 }, - { 0x2381003c, 0x1c000001 }, - { 0x2381003f, 0x1c00000e }, - { 0x23810050, 0x1c00000d }, - { 0x23810080, 0x1c00007a }, - { 0x09810100, 0x54000001 }, - { 0x09010102, 0x68000000 }, - { 0x09810107, 0x3c00002c }, - { 0x09810137, 0x68000008 }, - { 0x13810140, 0x38000034 }, - { 0x13810175, 0x3c000003 }, - { 0x13810179, 0x68000010 }, - { 0x1301018a, 0x3c000000 }, - { 0x29810300, 0x1c00001e }, - { 0x29810320, 0x3c000003 }, - { 0x12810330, 0x1c000019 }, - { 0x1201034a, 0x38000000 }, - { 0x3b810380, 0x1c00001d }, - { 0x3b01039f, 0x54000000 }, - { 0x2a8103a0, 0x1c000023 }, - { 0x2a8103c8, 0x1c000007 }, - { 0x2a0103d0, 0x68000000 }, - { 0x2a8103d1, 0x38000004 }, - { 0x0d010400, 0x24000028 }, - { 0x0d010401, 0x24000028 }, - { 0x0d010402, 0x24000028 }, - { 0x0d010403, 0x24000028 }, - { 0x0d010404, 0x24000028 }, - { 0x0d010405, 0x24000028 }, - { 0x0d010406, 0x24000028 }, - { 0x0d010407, 0x24000028 }, - { 0x0d010408, 0x24000028 }, - { 0x0d010409, 0x24000028 }, - { 0x0d01040a, 0x24000028 }, - { 0x0d01040b, 0x24000028 }, - { 0x0d01040c, 0x24000028 }, - { 0x0d01040d, 0x24000028 }, - { 0x0d01040e, 0x24000028 }, - { 0x0d01040f, 0x24000028 }, - { 0x0d010410, 0x24000028 }, - { 0x0d010411, 0x24000028 }, - { 0x0d010412, 0x24000028 }, - { 0x0d010413, 0x24000028 }, - { 0x0d010414, 0x24000028 }, - { 0x0d010415, 0x24000028 }, - { 0x0d010416, 0x24000028 }, - { 0x0d010417, 0x24000028 }, - { 0x0d010418, 0x24000028 }, - { 0x0d010419, 0x24000028 }, - { 0x0d01041a, 0x24000028 }, - { 0x0d01041b, 0x24000028 }, - { 0x0d01041c, 0x24000028 }, - { 0x0d01041d, 0x24000028 }, - { 0x0d01041e, 0x24000028 }, - { 0x0d01041f, 0x24000028 }, - { 0x0d010420, 0x24000028 }, - { 0x0d010421, 0x24000028 }, - { 0x0d010422, 0x24000028 }, - { 0x0d010423, 0x24000028 }, - { 0x0d010424, 0x24000028 }, - { 0x0d010425, 0x24000028 }, - { 0x0d010426, 0x24000028 }, - { 0x0d010427, 0x24000028 }, - { 0x0d010428, 0x1400ffd8 }, - { 0x0d010429, 0x1400ffd8 }, - { 0x0d01042a, 0x1400ffd8 }, - { 0x0d01042b, 0x1400ffd8 }, - { 0x0d01042c, 0x1400ffd8 }, - { 0x0d01042d, 0x1400ffd8 }, - { 0x0d01042e, 0x1400ffd8 }, - { 0x0d01042f, 0x1400ffd8 }, - { 0x0d010430, 0x1400ffd8 }, - { 0x0d010431, 0x1400ffd8 }, - { 0x0d010432, 0x1400ffd8 }, - { 0x0d010433, 0x1400ffd8 }, - { 0x0d010434, 0x1400ffd8 }, - { 0x0d010435, 0x1400ffd8 }, - { 0x0d010436, 0x1400ffd8 }, - { 0x0d010437, 0x1400ffd8 }, - { 0x0d010438, 0x1400ffd8 }, - { 0x0d010439, 0x1400ffd8 }, - { 0x0d01043a, 0x1400ffd8 }, - { 0x0d01043b, 0x1400ffd8 }, - { 0x0d01043c, 0x1400ffd8 }, - { 0x0d01043d, 0x1400ffd8 }, - { 0x0d01043e, 0x1400ffd8 }, - { 0x0d01043f, 0x1400ffd8 }, - { 0x0d010440, 0x1400ffd8 }, - { 0x0d010441, 0x1400ffd8 }, - { 0x0d010442, 0x1400ffd8 }, - { 0x0d010443, 0x1400ffd8 }, - { 0x0d010444, 0x1400ffd8 }, - { 0x0d010445, 0x1400ffd8 }, - { 0x0d010446, 0x1400ffd8 }, - { 0x0d010447, 0x1400ffd8 }, - { 0x0d010448, 0x1400ffd8 }, - { 0x0d010449, 0x1400ffd8 }, - { 0x0d01044a, 0x1400ffd8 }, - { 0x0d01044b, 0x1400ffd8 }, - { 0x0d01044c, 0x1400ffd8 }, - { 0x0d01044d, 0x1400ffd8 }, - { 0x0d01044e, 0x1400ffd8 }, - { 0x0d01044f, 0x1400ffd8 }, - { 0x2e810450, 0x1c00004d }, - { 0x2c8104a0, 0x34000009 }, - { 0x0b810800, 0x1c000005 }, - { 0x0b010808, 0x1c000000 }, - { 0x0b81080a, 0x1c00002b }, - { 0x0b810837, 0x1c000001 }, - { 0x0b01083c, 0x1c000000 }, - { 0x0b01083f, 0x1c000000 }, - { 0x1e010a00, 0x1c000000 }, - { 0x1e810a01, 0x30000002 }, - { 0x1e810a05, 0x30000001 }, - { 0x1e810a0c, 0x30000003 }, - { 0x1e810a10, 0x1c000003 }, - { 0x1e810a15, 0x1c000002 }, - { 0x1e810a19, 0x1c00001a }, - { 0x1e810a38, 0x30000002 }, - { 0x1e010a3f, 0x30000000 }, - { 0x1e810a40, 0x3c000007 }, - { 0x1e810a50, 0x54000008 }, - { 0x0981d000, 0x680000f5 }, - { 0x0981d100, 0x68000026 }, - { 0x0981d12a, 0x6800003a }, - { 0x0981d165, 0x28000001 }, - { 0x1b81d167, 0x30000002 }, - { 0x0981d16a, 0x68000002 }, - { 0x0981d16d, 0x28000005 }, - { 0x0981d173, 0x04000007 }, - { 0x1b81d17b, 0x30000007 }, - { 0x0981d183, 0x68000001 }, - { 0x1b81d185, 0x30000006 }, - { 0x0981d18c, 0x6800001d }, - { 0x1b81d1aa, 0x30000003 }, - { 0x0981d1ae, 0x6800002f }, - { 0x1381d200, 0x68000041 }, - { 0x1381d242, 0x30000002 }, - { 0x1301d245, 0x68000000 }, - { 0x0981d300, 0x68000056 }, - { 0x0981d400, 0x24000019 }, - { 0x0981d41a, 0x14000019 }, - { 0x0981d434, 0x24000019 }, - { 0x0981d44e, 0x14000006 }, - { 0x0981d456, 0x14000011 }, - { 0x0981d468, 0x24000019 }, - { 0x0981d482, 0x14000019 }, - { 0x0901d49c, 0x24000000 }, - { 0x0981d49e, 0x24000001 }, - { 0x0901d4a2, 0x24000000 }, - { 0x0981d4a5, 0x24000001 }, - { 0x0981d4a9, 0x24000003 }, - { 0x0981d4ae, 0x24000007 }, - { 0x0981d4b6, 0x14000003 }, - { 0x0901d4bb, 0x14000000 }, - { 0x0981d4bd, 0x14000006 }, - { 0x0981d4c5, 0x1400000a }, - { 0x0981d4d0, 0x24000019 }, - { 0x0981d4ea, 0x14000019 }, - { 0x0981d504, 0x24000001 }, - { 0x0981d507, 0x24000003 }, - { 0x0981d50d, 0x24000007 }, - { 0x0981d516, 0x24000006 }, - { 0x0981d51e, 0x14000019 }, - { 0x0981d538, 0x24000001 }, - { 0x0981d53b, 0x24000003 }, - { 0x0981d540, 0x24000004 }, - { 0x0901d546, 0x24000000 }, - { 0x0981d54a, 0x24000006 }, - { 0x0981d552, 0x14000019 }, - { 0x0981d56c, 0x24000019 }, - { 0x0981d586, 0x14000019 }, - { 0x0981d5a0, 0x24000019 }, - { 0x0981d5ba, 0x14000019 }, - { 0x0981d5d4, 0x24000019 }, - { 0x0981d5ee, 0x14000019 }, - { 0x0981d608, 0x24000019 }, - { 0x0981d622, 0x14000019 }, - { 0x0981d63c, 0x24000019 }, - { 0x0981d656, 0x14000019 }, - { 0x0981d670, 0x24000019 }, - { 0x0981d68a, 0x1400001b }, - { 0x0981d6a8, 0x24000018 }, - { 0x0901d6c1, 0x64000000 }, - { 0x0981d6c2, 0x14000018 }, - { 0x0901d6db, 0x64000000 }, - { 0x0981d6dc, 0x14000005 }, - { 0x0981d6e2, 0x24000018 }, - { 0x0901d6fb, 0x64000000 }, - { 0x0981d6fc, 0x14000018 }, - { 0x0901d715, 0x64000000 }, - { 0x0981d716, 0x14000005 }, - { 0x0981d71c, 0x24000018 }, - { 0x0901d735, 0x64000000 }, - { 0x0981d736, 0x14000018 }, - { 0x0901d74f, 0x64000000 }, - { 0x0981d750, 0x14000005 }, - { 0x0981d756, 0x24000018 }, - { 0x0901d76f, 0x64000000 }, - { 0x0981d770, 0x14000018 }, - { 0x0901d789, 0x64000000 }, - { 0x0981d78a, 0x14000005 }, - { 0x0981d790, 0x24000018 }, - { 0x0901d7a9, 0x64000000 }, - { 0x0981d7aa, 0x14000018 }, - { 0x0901d7c3, 0x64000000 }, - { 0x0981d7c4, 0x14000005 }, - { 0x0981d7ce, 0x34000031 }, - { 0x16820000, 0x1c00a6d6 }, - { 0x1682f800, 0x1c00021d }, - { 0x090e0001, 0x04000000 }, - { 0x098e0020, 0x0400005f }, - { 0x1b8e0100, 0x300000ef }, - { 0x098f0000, 0x0c00fffd }, - { 0x09900000, 0x0c00fffd }, -}; diff --git a/js/src/yarr/wtfbridge.h b/js/src/yarr/wtfbridge.h new file mode 100644 index 000000000000..25a4bc5ee3d9 --- /dev/null +++ b/js/src/yarr/wtfbridge.h @@ -0,0 +1,321 @@ +/* -*- 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 ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 12, 2009. + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jswtfbridge_h__ +#define jswtfbridge_h__ + +/* + * WTF compatibility layer. This file provides various type and data + * definitions for use by Yarr. + */ + +#include "jsstr.h" +#include "jsprvtd.h" +#include "jstl.h" +#include "assembler/wtf/Platform.h" +#include "assembler/jit/ExecutableAllocator.h" + +namespace JSC { namespace Yarr { + +/* + * Basic type definitions. + */ + +typedef jschar UChar; +typedef JSLinearString UString; + +class Unicode { + public: + static UChar toUpper(UChar c) { return JS_TOUPPER(c); } + static UChar toLower(UChar c) { return JS_TOLOWER(c); } +}; + +/* + * Do-nothing smart pointer classes. These have a compatible interface + * with the smart pointers used by Yarr, but they don't actually do + * reference counting. + */ +template +class RefCounted { +}; + +template +class RefPtr { + T *ptr; + public: + RefPtr(T *p) { ptr = p; } + operator bool() const { return ptr != NULL; } + const T *operator ->() const { return ptr; } + T *get() { return ptr; } +}; + +template +class PassRefPtr { + T *ptr; + public: + PassRefPtr(T *p) { ptr = p; } + operator T*() { return ptr; } +}; + +template +class PassOwnPtr { + T *ptr; + public: + PassOwnPtr(T *p) { ptr = p; } + + T *get() { return ptr; } +}; + +template +class OwnPtr { + T *ptr; + public: + OwnPtr() : ptr(NULL) { } + OwnPtr(PassOwnPtr p) : ptr(p.get()) { } + + ~OwnPtr() { + if (ptr) + js::Foreground::delete_(ptr); + } + + OwnPtr &operator=(PassOwnPtr p) { + ptr = p.get(); + return *this; + } + + T *operator ->() { return ptr; } + + T *get() { return ptr; } + + T *release() { + T *result = ptr; + ptr = NULL; + return result; + } +}; + +template +PassRefPtr adoptRef(T *p) { return PassRefPtr(p); } + +template +PassOwnPtr adoptPtr(T *p) { return PassOwnPtr(p); } + +#define WTF_MAKE_FAST_ALLOCATED + +/* + * Vector class for Yarr. This wraps js::Vector and provides all + * the API method signatures used by Yarr. + */ +template +class Vector { + public: + js::Vector impl; + public: + Vector() {} + + Vector(const Vector &v) { + // XXX yarr-oom + (void) append(v); + } + + size_t size() const { + return impl.length(); + } + + T &operator[](size_t i) { + return impl[i]; + } + + const T &operator[](size_t i) const { + return impl[i]; + } + + T &at(size_t i) { + return impl[i]; + } + + const T *begin() const { + return impl.begin(); + } + + T &last() { + return impl.back(); + } + + bool isEmpty() const { + return impl.empty(); + } + + template + void append(const U &u) { + // XXX yarr-oom + (void) impl.append(static_cast(u)); + } + + template + void append(const Vector &v) { + // XXX yarr-oom + (void) impl.append(v.impl); + } + + void insert(size_t i, const T& t) { + // XXX yarr-oom + (void) impl.insert(&impl[i], t); + } + + void remove(size_t i) { + impl.erase(&impl[i]); + } + + void clear() { + return impl.clear(); + } + + void shrink(size_t newLength) { + // XXX yarr-oom + JS_ASSERT(newLength <= impl.length()); + (void) impl.resize(newLength); + } + + void deleteAllValues() { + for (T *p = impl.begin(); p != impl.end(); ++p) + js::Foreground::delete_(*p); + } +}; + +template +class Vector > { + public: + js::Vector impl; + public: + Vector() {} + + size_t size() const { + return impl.length(); + } + + void append(T *t) { + // XXX yarr-oom + (void) impl.append(t); + } + + PassOwnPtr operator[](size_t i) { + return PassOwnPtr(impl[i]); + } + + void clear() { + for (T **p = impl.begin(); p != impl.end(); ++p) + js::Foreground::delete_(*p); + return impl.clear(); + } +}; + +template +inline void +deleteAllValues(Vector &v) { + v.deleteAllValues(); +} + +/* + * Minimal JSGlobalData. This used by Yarr to get the allocator. + */ +class JSGlobalData { + public: + ExecutableAllocator *regexAllocator; + + JSGlobalData(ExecutableAllocator *regexAllocator) + : regexAllocator(regexAllocator) { } +}; + +/* + * Sentinel value used in Yarr. + */ +const size_t notFound = size_t(-1); + + /* + * Do-nothing version of a macro used by WTF to avoid unused + * parameter warnings. + */ +#define UNUSED_PARAM(e) + +} /* namespace Yarr */ + +/* + * Replacements for std:: functions used in Yarr. We put them in + * namespace JSC::std so that they can still be called as std::X + * in Yarr. + */ +namespace std { + +/* + * windows.h defines a 'min' macro that would mangle the function + * name. + */ +#if WTF_COMPILER_MSVC +# undef min +# undef max +#endif + +template +inline T +min(T t1, T t2) +{ + return JS_MIN(t1, t2); +} + +template +inline T +max(T t1, T t2) +{ + return JS_MAX(t1, t2); +} + +template +inline void +swap(T &t1, T &t2) +{ + T tmp = t1; + t1 = t2; + t2 = tmp; +} +} /* namespace std */ + +} /* namespace JSC */ + +#endif diff --git a/js/src/yarr/yarr/RegexJIT.cpp b/js/src/yarr/yarr/RegexJIT.cpp deleted file mode 100644 index 1571c35b7125..000000000000 --- a/js/src/yarr/yarr/RegexJIT.cpp +++ /dev/null @@ -1,1589 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#include "RegexJIT.h" - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/LinkBuffer.h" -#include "assembler/assembler/MacroAssembler.h" -#include "RegexCompiler.h" - -#include "yarr/pcre/pcre.h" // temporary, remove when fallback is removed. - -using namespace WTF; - -namespace JSC { namespace Yarr { - -class JSGlobalData; - -class RegexGenerator : private MacroAssembler { - friend void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); - -#if WTF_CPU_ARM - static const RegisterID input = ARMRegisters::r0; - static const RegisterID index = ARMRegisters::r1; - static const RegisterID length = ARMRegisters::r2; - static const RegisterID output = ARMRegisters::r4; - - static const RegisterID regT0 = ARMRegisters::r5; - static const RegisterID regT1 = ARMRegisters::r6; - - static const RegisterID returnRegister = ARMRegisters::r0; -#elif WTF_CPU_MIPS - static const RegisterID input = MIPSRegisters::a0; - static const RegisterID index = MIPSRegisters::a1; - static const RegisterID length = MIPSRegisters::a2; - static const RegisterID output = MIPSRegisters::a3; - - static const RegisterID regT0 = MIPSRegisters::t4; - static const RegisterID regT1 = MIPSRegisters::t5; - - static const RegisterID returnRegister = MIPSRegisters::v0; -#elif WTF_CPU_SPARC - static const RegisterID input = SparcRegisters::i0; - static const RegisterID index = SparcRegisters::i1; - static const RegisterID length = SparcRegisters::i2; - static const RegisterID output = SparcRegisters::i3; - - static const RegisterID regT0 = SparcRegisters::i4; - static const RegisterID regT1 = SparcRegisters::i5; - - static const RegisterID returnRegister = SparcRegisters::i0; -#elif WTF_CPU_X86 - static const RegisterID input = X86Registers::eax; - static const RegisterID index = X86Registers::edx; - static const RegisterID length = X86Registers::ecx; - static const RegisterID output = X86Registers::edi; - - static const RegisterID regT0 = X86Registers::ebx; - static const RegisterID regT1 = X86Registers::esi; - - static const RegisterID returnRegister = X86Registers::eax; -#elif WTF_CPU_X86_64 -#if WTF_PLATFORM_WIN - static const RegisterID input = X86Registers::ecx; - static const RegisterID index = X86Registers::edx; - static const RegisterID length = X86Registers::r8; - static const RegisterID output = X86Registers::r9; -#else - static const RegisterID input = X86Registers::edi; - static const RegisterID index = X86Registers::esi; - static const RegisterID length = X86Registers::edx; - static const RegisterID output = X86Registers::ecx; -#endif - - static const RegisterID regT0 = X86Registers::eax; - static const RegisterID regT1 = X86Registers::ebx; - - static const RegisterID returnRegister = X86Registers::eax; -#endif - - void optimizeAlternative(PatternAlternative* alternative) - { - if (!alternative->m_terms.length()) - return; - - for (unsigned i = 0; i < alternative->m_terms.length() - 1; ++i) { - PatternTerm& term = alternative->m_terms[i]; - PatternTerm& nextTerm = alternative->m_terms[i + 1]; - - if ((term.type == PatternTerm::TypeCharacterClass) - && (term.quantityType == QuantifierFixedCount) - && (nextTerm.type == PatternTerm::TypePatternCharacter) - && (nextTerm.quantityType == QuantifierFixedCount)) { - PatternTerm termCopy = term; - alternative->m_terms[i] = nextTerm; - alternative->m_terms[i + 1] = termCopy; - } - } - } - - void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) - { - do { - // pick which range we're going to generate - int which = count >> 1; - char lo = ranges[which].begin; - char hi = ranges[which].end; - - // check if there are any ranges or matches below lo. If not, just jl to failure - - // if there is anything else to check, check that first, if it falls through jmp to failure. - if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { - Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); - - // generate code for all ranges before this one - if (which) - matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); - - while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { - matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex]))); - ++*matchIndex; - } - failures.append(jump()); - - loOrAbove.link(this); - } else if (which) { - Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); - - matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); - failures.append(jump()); - - loOrAbove.link(this); - } else - failures.append(branch32(LessThan, character, Imm32((unsigned short)lo))); - - while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) - ++*matchIndex; - - matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi))); - // fall through to here, the value is above hi. - - // shuffle along & loop around if there are any more matches to handle. - unsigned next = which + 1; - ranges += next; - count -= next; - } while (count); - } - - void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass) - { - if (charClass->m_table) { - ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table)); - matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry)); - return; - } - Jump unicodeFail; - if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) { - Jump isAscii = branch32(LessThanOrEqual, character, Imm32(0x7f)); - - if (charClass->m_matchesUnicode.length()) { - for (unsigned i = 0; i < charClass->m_matchesUnicode.length(); ++i) { - UChar ch = charClass->m_matchesUnicode[i]; - matchDest.append(branch32(Equal, character, Imm32(ch))); - } - } - - if (charClass->m_rangesUnicode.length()) { - for (unsigned i = 0; i < charClass->m_rangesUnicode.length(); ++i) { - UChar lo = charClass->m_rangesUnicode[i].begin; - UChar hi = charClass->m_rangesUnicode[i].end; - - Jump below = branch32(LessThan, character, Imm32(lo)); - matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi))); - below.link(this); - } - } - - unicodeFail = jump(); - isAscii.link(this); - } - - if (charClass->m_ranges.length()) { - unsigned matchIndex = 0; - JumpList failures; - matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.length(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.length()); - while (matchIndex < charClass->m_matches.length()) - matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++]))); - - failures.link(this); - } else if (charClass->m_matches.length()) { - // optimization: gather 'a','A' etc back together, can mask & test once. - js::Vector matchesAZaz; - - for (unsigned i = 0; i < charClass->m_matches.length(); ++i) { - char ch = charClass->m_matches[i]; - if (m_pattern.m_ignoreCase) { - if (isASCIILower(ch)) { - matchesAZaz.append(ch); - continue; - } - if (isASCIIUpper(ch)) - continue; - } - matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch))); - } - - if (unsigned countAZaz = matchesAZaz.length()) { - or32(Imm32(32), character); - for (unsigned i = 0; i < countAZaz; ++i) - matchDest.append(branch32(Equal, character, Imm32(matchesAZaz[i]))); - } - } - - if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) - unicodeFail.link(this); - } - - // Jumps if input not available; will have (incorrectly) incremented already! - Jump jumpIfNoAvailableInput(unsigned countToCheck) - { - add32(Imm32(countToCheck), index); - return branch32(Above, index, length); - } - - Jump jumpIfAvailableInput(unsigned countToCheck) - { - add32(Imm32(countToCheck), index); - return branch32(BelowOrEqual, index, length); - } - - Jump checkInput() - { - return branch32(BelowOrEqual, index, length); - } - - Jump atEndOfInput() - { - return branch32(Equal, index, length); - } - - Jump notAtEndOfInput() - { - return branch32(NotEqual, index, length); - } - - Jump jumpIfCharEquals(UChar ch, int inputPosition) - { - return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); - } - - Jump jumpIfCharNotEquals(UChar ch, int inputPosition) - { - return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); - } - - void readCharacter(int inputPosition, RegisterID reg) - { - load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg); - } - - void storeToFrame(RegisterID reg, unsigned frameLocation) - { - poke(reg, frameLocation); - } - - void storeToFrame(Imm32 imm, unsigned frameLocation) - { - poke(imm, frameLocation); - } - - DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) - { - return storePtrWithPatch(ImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*))); - } - - void loadFromFrame(unsigned frameLocation, RegisterID reg) - { - peek(reg, frameLocation); - } - - void loadFromFrameAndJump(unsigned frameLocation) - { - jump(Address(stackPointerRegister, frameLocation * sizeof(void*))); - } - - struct AlternativeBacktrackRecord { - DataLabelPtr dataLabel; - Label backtrackLocation; - - AlternativeBacktrackRecord(DataLabelPtr dataLabel, Label backtrackLocation) - : dataLabel(dataLabel) - , backtrackLocation(backtrackLocation) - { - } - }; - - struct TermGenerationState { - TermGenerationState(PatternDisjunction* disjunction, unsigned checkedTotal) - : disjunction(disjunction) - , checkedTotal(checkedTotal) - { - } - - void resetAlternative() - { - isBackTrackGenerated = false; - alt = 0; - } - bool alternativeValid() - { - return alt < disjunction->m_alternatives.length(); - } - void nextAlternative() - { - ++alt; - } - PatternAlternative* alternative() - { - return disjunction->m_alternatives[alt]; - } - - void resetTerm() - { - ASSERT(alternativeValid()); - t = 0; - } - bool termValid() - { - ASSERT(alternativeValid()); - return t < alternative()->m_terms.length(); - } - void nextTerm() - { - ASSERT(alternativeValid()); - ++t; - } - PatternTerm& term() - { - ASSERT(alternativeValid()); - return alternative()->m_terms[t]; - } - bool isLastTerm() - { - ASSERT(alternativeValid()); - return (t + 1) == alternative()->m_terms.length(); - } - bool isMainDisjunction() - { - return !disjunction->m_parent; - } - - PatternTerm& lookaheadTerm() - { - ASSERT(alternativeValid()); - ASSERT((t + 1) < alternative()->m_terms.length()); - return alternative()->m_terms[t + 1]; - } - bool isSinglePatternCharacterLookaheadTerm() - { - ASSERT(alternativeValid()); - return ((t + 1) < alternative()->m_terms.length()) - && (lookaheadTerm().type == PatternTerm::TypePatternCharacter) - && (lookaheadTerm().quantityType == QuantifierFixedCount) - && (lookaheadTerm().quantityCount == 1); - } - - int inputOffset() - { - return term().inputPosition - checkedTotal; - } - - void jumpToBacktrack(Jump jump, MacroAssembler* masm) - { - if (isBackTrackGenerated) - jump.linkTo(backtrackLabel, masm); - else - backTrackJumps.append(jump); - } - void jumpToBacktrack(JumpList& jumps, MacroAssembler* masm) - { - if (isBackTrackGenerated) - jumps.linkTo(backtrackLabel, masm); - else - backTrackJumps.append(jumps); - } - bool plantJumpToBacktrackIfExists(MacroAssembler* masm) - { - if (isBackTrackGenerated) { - masm->jump(backtrackLabel); - return true; - } - return false; - } - void addBacktrackJump(Jump jump) - { - backTrackJumps.append(jump); - } - void setBacktrackGenerated(Label label) - { - isBackTrackGenerated = true; - backtrackLabel = label; - } - void linkAlternativeBacktracks(MacroAssembler* masm) - { - isBackTrackGenerated = false; - backTrackJumps.link(masm); - } - void linkAlternativeBacktracksTo(Label label, MacroAssembler* masm) - { - isBackTrackGenerated = false; - backTrackJumps.linkTo(label, masm); - } - void propagateBacktrackingFrom(TermGenerationState& nestedParenthesesState, MacroAssembler* masm) - { - jumpToBacktrack(nestedParenthesesState.backTrackJumps, masm); - if (nestedParenthesesState.isBackTrackGenerated) - setBacktrackGenerated(nestedParenthesesState.backtrackLabel); - } - - PatternDisjunction* disjunction; - int checkedTotal; - private: - unsigned alt; - unsigned t; - JumpList backTrackJumps; - Label backtrackLabel; - bool isBackTrackGenerated; - }; - - void generateAssertionBOL(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - if (m_pattern.m_multiline) { - const RegisterID character = regT0; - - JumpList matchDest; - if (!term.inputPosition) - matchDest.append(branch32(Equal, index, Imm32(state.checkedTotal))); - - readCharacter(state.inputOffset() - 1, character); - matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); - state.jumpToBacktrack(jump(), this); - - matchDest.link(this); - } else { - // Erk, really should poison out these alternatives early. :-/ - if (term.inputPosition) - state.jumpToBacktrack(jump(), this); - else - state.jumpToBacktrack(branch32(NotEqual, index, Imm32(state.checkedTotal)), this); - } - } - - void generateAssertionEOL(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - if (m_pattern.m_multiline) { - const RegisterID character = regT0; - - JumpList matchDest; - if (term.inputPosition == state.checkedTotal) - matchDest.append(atEndOfInput()); - - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); - state.jumpToBacktrack(jump(), this); - - matchDest.link(this); - } else { - if (term.inputPosition == state.checkedTotal) - state.jumpToBacktrack(notAtEndOfInput(), this); - // Erk, really should poison out these alternatives early. :-/ - else - state.jumpToBacktrack(jump(), this); - } - } - - // Also falls though on nextIsNotWordChar. - void matchAssertionWordchar(TermGenerationState& state, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - if (term.inputPosition == state.checkedTotal) - nextIsNotWordChar.append(atEndOfInput()); - - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass()); - } - - void generateAssertionWordBoundary(TermGenerationState& state) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - Jump atBegin; - JumpList matchDest; - if (!term.inputPosition) - atBegin = branch32(Equal, index, Imm32(state.checkedTotal)); - readCharacter(state.inputOffset() - 1, character); - matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass()); - if (!term.inputPosition) - atBegin.link(this); - - // We fall through to here if the last character was not a wordchar. - JumpList nonWordCharThenWordChar; - JumpList nonWordCharThenNonWordChar; - if (term.invertOrCapture) { - matchAssertionWordchar(state, nonWordCharThenNonWordChar, nonWordCharThenWordChar); - nonWordCharThenWordChar.append(jump()); - } else { - matchAssertionWordchar(state, nonWordCharThenWordChar, nonWordCharThenNonWordChar); - nonWordCharThenNonWordChar.append(jump()); - } - state.jumpToBacktrack(nonWordCharThenNonWordChar, this); - - // We jump here if the last character was a wordchar. - matchDest.link(this); - JumpList wordCharThenWordChar; - JumpList wordCharThenNonWordChar; - if (term.invertOrCapture) { - matchAssertionWordchar(state, wordCharThenNonWordChar, wordCharThenWordChar); - wordCharThenWordChar.append(jump()); - } else { - matchAssertionWordchar(state, wordCharThenWordChar, wordCharThenNonWordChar); - // This can fall-though! - } - - state.jumpToBacktrack(wordCharThenWordChar, this); - - nonWordCharThenWordChar.link(this); - wordCharThenNonWordChar.link(this); - } - - void generatePatternCharacterSingle(TermGenerationState& state) - { - const RegisterID character = regT0; - UChar ch = state.term().patternCharacter; - - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - state.jumpToBacktrack(jumpIfCharNotEquals(ch, state.inputOffset()), this); - } - } - - void generatePatternCharacterPair(TermGenerationState& state) - { - const RegisterID character = regT0; -#if WTF_CPU_BIG_ENDIAN - UChar ch2 = state.term().patternCharacter; - UChar ch1 = state.lookaheadTerm().patternCharacter; -#else - UChar ch1 = state.term().patternCharacter; - UChar ch2 = state.lookaheadTerm().patternCharacter; -#endif - - int mask = 0; - int chPair = ch1 | (ch2 << 16); - - if (m_pattern.m_ignoreCase) { - if (isASCIIAlpha(ch1)) - mask |= 32; - if (isASCIIAlpha(ch2)) - mask |= 32 << 16; - } - - if (mask) { - load32WithUnalignedHalfWords(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character); - or32(Imm32(mask), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(chPair | mask)), this); - } else - state.jumpToBacktrack(branch32WithUnalignedHalfWords(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this); - } - - void generatePatternCharacterFixed(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(index, countRegister); - sub32(Imm32(term.quantityCount), countRegister); - - Label loop(this); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); - or32(Imm32(32), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - state.jumpToBacktrack(branch16(NotEqual, BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), Imm32(ch)), this); - } - add32(Imm32(1), countRegister); - branch32(NotEqual, countRegister, index).linkTo(loop, this); - } - - void generatePatternCharacterGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(Imm32(0), countRegister); - - JumpList failures; - Label loop(this); - failures.append(atEndOfInput()); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - failures.append(jumpIfCharNotEquals(ch, state.inputOffset())); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - if (term.quantityCount != 0xffffffff) { - branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); - failures.append(jump()); - } else - jump(loop); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - state.jumpToBacktrack(branchTest32(Zero, countRegister), this); - sub32(Imm32(1), countRegister); - sub32(Imm32(1), index); - - failures.link(this); - - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generatePatternCharacterNonGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(Imm32(0), countRegister); - - Jump firstTimeDoNothing = jump(); - - Label hardFail(this); - sub32(countRegister, index); - state.jumpToBacktrack(jump(), this); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - - atEndOfInput().linkTo(hardFail, this); - if (term.quantityCount != 0xffffffff) - branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - branch32(NotEqual, character, Imm32(Unicode::toLower(ch))).linkTo(hardFail, this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - jumpIfCharNotEquals(ch, state.inputOffset()).linkTo(hardFail, this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - - firstTimeDoNothing.link(this); - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateCharacterClassSingle(TermGenerationState& state) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - state.jumpToBacktrack(matchDest, this); - else { - state.jumpToBacktrack(jump(), this); - matchDest.link(this); - } - } - - void generateCharacterClassFixed(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(index, countRegister); - sub32(Imm32(term.quantityCount), countRegister); - - Label loop(this); - JumpList matchDest; - load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - state.jumpToBacktrack(matchDest, this); - else { - state.jumpToBacktrack(jump(), this); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - branch32(NotEqual, countRegister, index).linkTo(loop, this); - } - - void generateCharacterClassGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(Imm32(0), countRegister); - - JumpList failures; - Label loop(this); - failures.append(atEndOfInput()); - - if (term.invertOrCapture) { - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, failures, term.characterClass); - } else { - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - failures.append(jump()); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - if (term.quantityCount != 0xffffffff) { - branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); - failures.append(jump()); - } else - jump(loop); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - state.jumpToBacktrack(branchTest32(Zero, countRegister), this); - sub32(Imm32(1), countRegister); - sub32(Imm32(1), index); - - failures.link(this); - - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateCharacterClassNonGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(Imm32(0), countRegister); - - Jump firstTimeDoNothing = jump(); - - Label hardFail(this); - sub32(countRegister, index); - state.jumpToBacktrack(jump(), this); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - - atEndOfInput().linkTo(hardFail, this); - branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); - - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - matchDest.linkTo(hardFail, this); - else { - jump(hardFail); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - - firstTimeDoNothing.link(this); - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateParenthesesDisjunction(PatternTerm& parenthesesTerm, TermGenerationState& state, unsigned alternativeFrameLocation) - { - ASSERT((parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern) || (parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion)); - ASSERT(parenthesesTerm.quantityCount == 1); - - PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; - unsigned preCheckedCount = ((parenthesesTerm.quantityType == QuantifierFixedCount) && (parenthesesTerm.type != PatternTerm::TypeParentheticalAssertion)) ? disjunction->m_minimumSize : 0; - - if (disjunction->m_alternatives.length() == 1) { - state.resetAlternative(); - ASSERT(state.alternativeValid()); - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - int countToCheck = alternative->m_minimumSize - preCheckedCount; - if (countToCheck) { - ASSERT((parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion) || (parenthesesTerm.quantityType != QuantifierFixedCount)); - - // FIXME: This is quite horrible. The call to 'plantJumpToBacktrackIfExists' - // will be forced to always trampoline into here, just to decrement the index. - // Ick. - Jump skip = jump(); - - Label backtrackBegin(this); - sub32(Imm32(countToCheck), index); - state.addBacktrackJump(jump()); - - skip.link(this); - - state.setBacktrackGenerated(backtrackBegin); - - state.jumpToBacktrack(jumpIfNoAvailableInput(countToCheck), this); - state.checkedTotal += countToCheck; - } - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - state.checkedTotal -= countToCheck; - } else { - JumpList successes; - - for (state.resetAlternative(); state.alternativeValid(); state.nextAlternative()) { - - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - ASSERT(alternative->m_minimumSize >= preCheckedCount); - int countToCheck = alternative->m_minimumSize - preCheckedCount; - if (countToCheck) { - state.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); - state.checkedTotal += countToCheck; - } - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - // Matched an alternative. - DataLabelPtr dataLabel = storeToFrameWithPatch(alternativeFrameLocation); - successes.append(jump()); - - // Alternative did not match. - Label backtrackLocation(this); - - // Can we backtrack the alternative? - if so, do so. If not, just fall through to the next one. - state.plantJumpToBacktrackIfExists(this); - - state.linkAlternativeBacktracks(this); - - if (countToCheck) { - sub32(Imm32(countToCheck), index); - state.checkedTotal -= countToCheck; - } - - m_backtrackRecords.append(AlternativeBacktrackRecord(dataLabel, backtrackLocation)); - } - // We fall through to here when the last alternative fails. - // Add a backtrack out of here for the parenthese handling code to link up. - state.addBacktrackJump(jump()); - - // Generate a trampoline for the parens code to backtrack to, to retry the - // next alternative. - state.setBacktrackGenerated(label()); - loadFromFrameAndJump(alternativeFrameLocation); - - // FIXME: both of the above hooks are a little inefficient, in that you - // may end up trampolining here, just to trampoline back out to the - // parentheses code, or vice versa. We can probably eliminate a jump - // by restructuring, but coding this way for now for simplicity during - // development. - - successes.link(this); - } - } - - void generateParenthesesSingle(TermGenerationState& state) - { - const RegisterID indexTemporary = regT0; - PatternTerm& term = state.term(); - PatternDisjunction* disjunction = term.parentheses.disjunction; - ASSERT(term.quantityCount == 1); - - unsigned preCheckedCount = (term.quantityType == QuantifierFixedCount) ? disjunction->m_minimumSize : 0; - - unsigned parenthesesFrameLocation = term.frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation; - if (term.quantityType != QuantifierFixedCount) - alternativeFrameLocation += RegexStackSpaceForBackTrackInfoParenthesesOnce; - - // optimized case - no capture & no quantifier can be handled in a light-weight manner. - if (!term.invertOrCapture && (term.quantityType == QuantifierFixedCount)) { - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // this expects that any backtracks back out of the parentheses will be in the - // parenthesesState's backTrackJumps vector, and that if they need backtracking - // they will have set an entry point on the parenthesesState's backtrackLabel. - state.propagateBacktrackingFrom(parenthesesState, this); - } else { - Jump nonGreedySkipParentheses; - Label nonGreedyTryParentheses; - if (term.quantityType == QuantifierGreedy) - storeToFrame(index, parenthesesFrameLocation); - else if (term.quantityType == QuantifierNonGreedy) { - storeToFrame(Imm32(-1), parenthesesFrameLocation); - nonGreedySkipParentheses = jump(); - nonGreedyTryParentheses = label(); - storeToFrame(index, parenthesesFrameLocation); - } - - // store the match start index - if (term.invertOrCapture) { - int inputOffset = state.inputOffset() - preCheckedCount; - if (inputOffset) { - move(index, indexTemporary); - add32(Imm32(inputOffset), indexTemporary); - store32(indexTemporary, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); - } else - store32(index, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); - } - - // generate the body of the parentheses - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - - Jump success = (term.quantityType == QuantifierFixedCount) ? - jump() : - branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesFrameLocation * sizeof(void*)))); - - // A failure AFTER the parens jumps here - Label backtrackFromAfterParens(this); - - if (term.quantityType == QuantifierGreedy) { - // If this is -1 we have now tested with both with and without the parens. - loadFromFrame(parenthesesFrameLocation, indexTemporary); - state.jumpToBacktrack(branch32(Equal, indexTemporary, Imm32(-1)), this); - } else if (term.quantityType == QuantifierNonGreedy) { - // If this is -1 we have now tested without the parens, now test with. - loadFromFrame(parenthesesFrameLocation, indexTemporary); - branch32(Equal, indexTemporary, Imm32(-1)).linkTo(nonGreedyTryParentheses, this); - } - - parenthesesState.plantJumpToBacktrackIfExists(this); - // A failure WITHIN the parens jumps here - parenthesesState.linkAlternativeBacktracks(this); - if (term.invertOrCapture) { - store32(Imm32(-1), Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); -#if 0 - store32(Imm32(-1), Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); -#endif - } - - if (term.quantityType == QuantifierGreedy) - storeToFrame(Imm32(-1), parenthesesFrameLocation); - else - state.jumpToBacktrack(jump(), this); - - state.setBacktrackGenerated(backtrackFromAfterParens); - if (term.quantityType == QuantifierNonGreedy) - nonGreedySkipParentheses.link(this); - success.link(this); - - // store the match end index - if (term.invertOrCapture) { - int inputOffset = state.inputOffset(); - if (inputOffset) { - move(index, indexTemporary); - add32(Imm32(state.inputOffset()), indexTemporary); - store32(indexTemporary, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); - } else - store32(index, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); - } - } - } - - void generateParenthesesGreedyNoBacktrack(TermGenerationState& state) - { - PatternTerm& parenthesesTerm = state.term(); - PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; - ASSERT(parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern); - ASSERT(parenthesesTerm.quantityCount != 1); // Handled by generateParenthesesSingle. - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - - Label matchAgain(this); - - storeToFrame(index, parenthesesTerm.frameLocation); // Save the current index to check for zero len matches later. - - for (parenthesesState.resetAlternative(); parenthesesState.alternativeValid(); parenthesesState.nextAlternative()) { - - PatternAlternative* alternative = parenthesesState.alternative(); - optimizeAlternative(alternative); - - int countToCheck = alternative->m_minimumSize; - if (countToCheck) { - parenthesesState.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); - parenthesesState.checkedTotal += countToCheck; - } - - for (parenthesesState.resetTerm(); parenthesesState.termValid(); parenthesesState.nextTerm()) - generateTerm(parenthesesState); - - // If we get here, we matched! If the index advanced then try to match more since limit isn't supported yet. - branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesTerm.frameLocation * sizeof(void*))), matchAgain); - - // If we get here we matched, but we matched "" - cannot accept this alternative as is, so either backtrack, - // or fall through to try the next alternative if no backtrack is available. - parenthesesState.plantJumpToBacktrackIfExists(this); - - parenthesesState.linkAlternativeBacktracks(this); - // We get here if the alternative fails to match - fall through to the next iteration, or out of the loop. - - if (countToCheck) { - sub32(Imm32(countToCheck), index); - parenthesesState.checkedTotal -= countToCheck; - } - } - - // If the last alternative falls through to here, we have a failed match... - // Which means that we match whatever we have matched up to this point (even if nothing). - } - - void generateParentheticalAssertion(TermGenerationState& state) - { - PatternTerm& term = state.term(); - PatternDisjunction* disjunction = term.parentheses.disjunction; - ASSERT(term.quantityCount == 1); - ASSERT(term.quantityType == QuantifierFixedCount); - - unsigned parenthesesFrameLocation = term.frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation + RegexStackSpaceForBackTrackInfoParentheticalAssertion; - - int countCheckedAfterAssertion = state.checkedTotal - term.inputPosition; - - if (term.invertOrCapture) { - // Inverted case - storeToFrame(index, parenthesesFrameLocation); - - state.checkedTotal -= countCheckedAfterAssertion; - if (countCheckedAfterAssertion) - sub32(Imm32(countCheckedAfterAssertion), index); - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // Success! - which means - Fail! - loadFromFrame(parenthesesFrameLocation, index); - state.jumpToBacktrack(jump(), this); - - // And fail means success. - parenthesesState.linkAlternativeBacktracks(this); - loadFromFrame(parenthesesFrameLocation, index); - - state.checkedTotal += countCheckedAfterAssertion; - } else { - // Normal case - storeToFrame(index, parenthesesFrameLocation); - - state.checkedTotal -= countCheckedAfterAssertion; - if (countCheckedAfterAssertion) - sub32(Imm32(countCheckedAfterAssertion), index); - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // Success! - which means - Success! - loadFromFrame(parenthesesFrameLocation, index); - Jump success = jump(); - - parenthesesState.linkAlternativeBacktracks(this); - loadFromFrame(parenthesesFrameLocation, index); - state.jumpToBacktrack(jump(), this); - - success.link(this); - - state.checkedTotal += countCheckedAfterAssertion; - } - } - - void generateTerm(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - switch (term.type) { - case PatternTerm::TypeAssertionBOL: - generateAssertionBOL(state); - break; - - case PatternTerm::TypeAssertionEOL: - generateAssertionEOL(state); - break; - - case PatternTerm::TypeAssertionWordBoundary: - generateAssertionWordBoundary(state); - break; - - case PatternTerm::TypePatternCharacter: - switch (term.quantityType) { - case QuantifierFixedCount: - if (term.quantityCount == 1) { - if (state.isSinglePatternCharacterLookaheadTerm() && (state.lookaheadTerm().inputPosition == (term.inputPosition + 1))) { - generatePatternCharacterPair(state); - state.nextTerm(); - } else - generatePatternCharacterSingle(state); - } else - generatePatternCharacterFixed(state); - break; - case QuantifierGreedy: - generatePatternCharacterGreedy(state); - break; - case QuantifierNonGreedy: - generatePatternCharacterNonGreedy(state); - break; - } - break; - - case PatternTerm::TypeCharacterClass: - switch (term.quantityType) { - case QuantifierFixedCount: - if (term.quantityCount == 1) - generateCharacterClassSingle(state); - else - generateCharacterClassFixed(state); - break; - case QuantifierGreedy: - generateCharacterClassGreedy(state); - break; - case QuantifierNonGreedy: - generateCharacterClassNonGreedy(state); - break; - } - break; - - case PatternTerm::TypeBackReference: - m_shouldFallBack = true; - break; - - case PatternTerm::TypeForwardReference: - break; - - case PatternTerm::TypeParenthesesSubpattern: - if (term.quantityCount == 1 && !term.parentheses.isCopy) - generateParenthesesSingle(state); - else if (term.parentheses.isTerminal) - generateParenthesesGreedyNoBacktrack(state); - else - m_shouldFallBack = true; - break; - - case PatternTerm::TypeParentheticalAssertion: - generateParentheticalAssertion(state); - break; - } - } - - void generateDisjunction(PatternDisjunction* disjunction) - { - TermGenerationState state(disjunction, 0); - state.resetAlternative(); - - // check availability for the next alternative - int countCheckedForCurrentAlternative = 0; - int countToCheckForFirstAlternative = 0; - bool hasShorterAlternatives = false; - bool setRepeatAlternativeLabels = false; - JumpList notEnoughInputForPreviousAlternative; - Label firstAlternative; - Label firstAlternativeInputChecked; - - // The label 'firstAlternative' is used to plant a check to see if there is - // sufficient input available to run the first repeating alternative. - // The label 'firstAlternativeInputChecked' will jump directly to matching - // the first repeating alternative having skipped this check. - - if (state.alternativeValid()) { - PatternAlternative* alternative = state.alternative(); - if (!alternative->onceThrough()) { - firstAlternative = Label(this); - setRepeatAlternativeLabels = true; - } - countToCheckForFirstAlternative = alternative->m_minimumSize; - state.checkedTotal += countToCheckForFirstAlternative; - if (countToCheckForFirstAlternative) - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); - countCheckedForCurrentAlternative = countToCheckForFirstAlternative; - } - - if (setRepeatAlternativeLabels) - firstAlternativeInputChecked = Label(this); - - while (state.alternativeValid()) { - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - // Track whether any alternatives are shorter than the first one. - if (!alternative->onceThrough()) - hasShorterAlternatives = hasShorterAlternatives || (countCheckedForCurrentAlternative < countToCheckForFirstAlternative); - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - // If we get here, the alternative matched. - if (m_pattern.m_body->m_callFrameSize) - addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - ASSERT(index != returnRegister); - if (m_pattern.m_body->m_hasFixedSize) { - move(index, returnRegister); - if (alternative->m_minimumSize) - sub32(Imm32(alternative->m_minimumSize), returnRegister); - - store32(returnRegister, output); - } else - load32(Address(output), returnRegister); - - store32(index, Address(output, 4)); - - generateReturn(); - - state.nextAlternative(); - - // if there are any more alternatives, plant the check for input before looping. - if (state.alternativeValid()) { - PatternAlternative* nextAlternative = state.alternative(); - if (!setRepeatAlternativeLabels && !nextAlternative->onceThrough()) { - // We have handled non-repeating alternatives, jump to next iteration - // and loop over repeating alternatives. - state.jumpToBacktrack(jump(), this); - - countToCheckForFirstAlternative = nextAlternative->m_minimumSize; - - // If we get here, there the last input checked failed. - notEnoughInputForPreviousAlternative.link(this); - - state.linkAlternativeBacktracks(this); - - // Back up to start the looping alternatives. - if (countCheckedForCurrentAlternative) - sub32(Imm32(countCheckedForCurrentAlternative), index); - - firstAlternative = Label(this); - - state.checkedTotal = countToCheckForFirstAlternative; - if (countToCheckForFirstAlternative) - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); - - countCheckedForCurrentAlternative = countToCheckForFirstAlternative; - - firstAlternativeInputChecked = Label(this); - - setRepeatAlternativeLabels = true; - } else { - int countToCheckForNextAlternative = nextAlternative->m_minimumSize; - - if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one. - // If we get here, then the last input checked failed. - notEnoughInputForPreviousAlternative.link(this); - - // Check if sufficent input available to run the next alternative - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); - // We are now in the correct state to enter the next alternative; this add is only required - // to mirror and revert operation of the sub32, just below. - add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); - - // If we get here, then the last input checked passed. - state.linkAlternativeBacktracks(this); - // No need to check if we can run the next alternative, since it is shorter - - // just update index. - sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); - } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one. - // If we get here, then the last input checked failed. - // If there is insufficient input to run the current alternative, and the next alternative is longer, - // then there is definitely not enough input to run it - don't even check. Just adjust index, as if - // we had checked. - notEnoughInputForPreviousAlternative.link(this); - add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index); - notEnoughInputForPreviousAlternative.append(jump()); - - // The next alternative is longer than the current one; check the difference. - state.linkAlternativeBacktracks(this); - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); - } else { // CASE 3: Both alternatives are the same length. - ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative); - - // If the next alterative is the same length as this one, then no need to check the input - - // if there was sufficent input to run the current alternative then there is sufficient - // input to run the next one; if not, there isn't. - state.linkAlternativeBacktracks(this); - } - state.checkedTotal -= countCheckedForCurrentAlternative; - countCheckedForCurrentAlternative = countToCheckForNextAlternative; - state.checkedTotal += countCheckedForCurrentAlternative; - } - } - } - - // If we get here, all Alternatives failed... - - state.checkedTotal -= countCheckedForCurrentAlternative; - - if (!setRepeatAlternativeLabels) { - // If there are no alternatives that need repeating (all are marked 'onceThrough') then just link - // the match failures to this point, and fall through to the return below. - state.linkAlternativeBacktracks(this); - notEnoughInputForPreviousAlternative.link(this); - } else { - // How much more input need there be to be able to retry from the first alternative? - // examples: - // /yarr_jit/ or /wrec|pcre/ - // In these examples we need check for one more input before looping. - // /yarr_jit|pcre/ - // In this case we need check for 5 more input to loop (+4 to allow for the first alterative - // being four longer than the last alternative checked, and another +1 to effectively move - // the start position along by one). - // /yarr|rules/ or /wrec|notsomuch/ - // In these examples, provided that there was sufficient input to have just been matching for - // the second alternative we can loop without checking for available input (since the second - // alternative is longer than the first). In the latter example we need to decrement index - // (by 4) so the start position is only progressed by 1 from the last iteration. - int incrementForNextIter = (countToCheckForFirstAlternative - countCheckedForCurrentAlternative) + 1; - - // First, deal with the cases where there was sufficient input to try the last alternative. - if (incrementForNextIter > 0) // We need to check for more input anyway, fall through to the checking below. - state.linkAlternativeBacktracks(this); - else if (m_pattern.m_body->m_hasFixedSize && !incrementForNextIter) // No need to update anything, link these backtracks straight to the to pof the loop! - state.linkAlternativeBacktracksTo(firstAlternativeInputChecked, this); - else { // no need to check the input, but we do have some bookkeeping to do first. - state.linkAlternativeBacktracks(this); - - // Where necessary update our preserved start position. - if (!m_pattern.m_body->m_hasFixedSize) { - move(index, regT0); - sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); - store32(regT0, Address(output)); - } - - // Update index if necessary, and loop (without checking). - if (incrementForNextIter) - add32(Imm32(incrementForNextIter), index); - jump().linkTo(firstAlternativeInputChecked, this); - } - - notEnoughInputForPreviousAlternative.link(this); - // Update our idea of the start position, if we're tracking this. - if (!m_pattern.m_body->m_hasFixedSize) { - if (countCheckedForCurrentAlternative - 1) { - move(index, regT0); - sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); - store32(regT0, Address(output)); - } else - store32(index, Address(output)); - } - - // Check if there is sufficent input to run the first alternative again. - jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this); - // No - insufficent input to run the first alteranative, are there any other alternatives we - // might need to check? If so, the last check will have left the index incremented by - // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative - // LESS input is available, to have the effect of just progressing the start position by 1 - // from the last iteration. If this check passes we can just jump up to the check associated - // with the first alternative in the loop. This is a bit sad, since we'll end up trying the - // first alternative again, and this check will fail (otherwise the check planted just above - // here would have passed). This is a bit sad, however it saves trying to do something more - // complex here in compilation, and in the common case we should end up coallescing the checks. - // - // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least - // of the minimum-alternative-lengths. E.g. if I have two alternatives of length 200 and 150, - // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there - // is sufficient input to run either alternative (constantly failing). If there had been only - // one alternative, or if the shorter alternative had come first, we would have terminated - // immediately. :-/ - if (hasShorterAlternatives) - jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this); - // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true, - // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... - // but since we're about to return a failure this doesn't really matter!) - } - - if (m_pattern.m_body->m_callFrameSize) - addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - move(Imm32(-1), returnRegister); - - generateReturn(); - } - - void generateEnter() - { -#if WTF_CPU_X86_64 - push(X86Registers::ebp); - move(stackPointerRegister, X86Registers::ebp); - push(X86Registers::ebx); -#elif WTF_CPU_X86 - push(X86Registers::ebp); - move(stackPointerRegister, X86Registers::ebp); - // TODO: do we need spill registers to fill the output pointer if there are no sub captures? - push(X86Registers::ebx); - push(X86Registers::edi); - push(X86Registers::esi); - // load output into edi (2 = saved ebp + return address). - #if WTF_COMPILER_MSVC || WTF_COMPILER_SUNPRO - loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); - loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); - loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); - loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); - #else - loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); - #endif -#elif WTF_CPU_ARM - push(ARMRegisters::r4); - push(ARMRegisters::r5); - push(ARMRegisters::r6); -#if WTF_CPU_ARM_TRADITIONAL - push(ARMRegisters::r8); // scratch register -#endif - move(ARMRegisters::r3, output); -#elif WTF_CPU_SPARC - save(Imm32(-m_pattern.m_body->m_callFrameSize * sizeof(void*))); - // set m_callFrameSize to 0 avoid and stack movement later. - m_pattern.m_body->m_callFrameSize = 0; -#elif WTF_CPU_MIPS - // Do nothing. -#endif - } - - void generateReturn() - { -#if WTF_CPU_X86_64 - pop(X86Registers::ebx); - pop(X86Registers::ebp); -#elif WTF_CPU_X86 - pop(X86Registers::esi); - pop(X86Registers::edi); - pop(X86Registers::ebx); - pop(X86Registers::ebp); -#elif WTF_CPU_ARM -#if WTF_CPU_ARM_TRADITIONAL - pop(ARMRegisters::r8); // scratch register -#endif - pop(ARMRegisters::r6); - pop(ARMRegisters::r5); - pop(ARMRegisters::r4); -#elif WTF_CPU_SPARC - ret_and_restore(); - return; -#elif WTF_CPU_MIPS - // Do nothing -#endif - ret(); - } - -public: - RegexGenerator(RegexPattern& pattern) - : m_pattern(pattern) - , m_shouldFallBack(false) - { - } - - void generate() - { - generateEnter(); - - if (!m_pattern.m_body->m_hasFixedSize) - store32(index, Address(output)); - - if (m_pattern.m_body->m_callFrameSize) - subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - generateDisjunction(m_pattern.m_body); - } - - void compile(ExecutableAllocator& allocator, RegexCodeBlock& jitObject) - { - generate(); - - if (oom()) { - m_shouldFallBack = true; - return; - } - - ExecutablePool *dummy; - bool ok; - LinkBuffer patchBuffer(this, &allocator, &dummy, &ok); - if (!ok) { - m_shouldFallBack = true; - return; - } - - for (unsigned i = 0; i < m_backtrackRecords.length(); ++i) - patchBuffer.patch(m_backtrackRecords[i].dataLabel, patchBuffer.locationOf(m_backtrackRecords[i].backtrackLocation)); - - jitObject.set(patchBuffer.finalizeCode()); - } - - bool shouldFallBack() - { - return m_shouldFallBack; - } - -private: - RegexPattern& m_pattern; - bool m_shouldFallBack; - js::Vector m_backtrackRecords; -}; - -void jitCompileRegex(ExecutableAllocator& allocator, RegexCodeBlock& jitObject, const UString&patternString, unsigned& numSubpatterns, int &error, bool &fellBack, bool ignoreCase, bool multiline -#ifdef ANDROID - , bool forceFallback -#endif -) -{ -#ifdef ANDROID - if (!forceFallback) { -#endif - fellBack = false; - RegexPattern pattern(ignoreCase, multiline); - if ((error = compileRegex(patternString, pattern))) - return; - numSubpatterns = pattern.m_numSubpatterns; - - if (!pattern.m_containsBackreferences) { - RegexGenerator generator(pattern); - generator.compile(allocator, jitObject); - if (!generator.shouldFallBack()) - return; - } -#ifdef ANDROID - } // forceFallback -#endif - - fellBack = true; - JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase; - JSRegExpMultilineOption multilineOption = multiline ? JSRegExpMultiline : JSRegExpSingleLine; - jitObject.setFallback(jsRegExpCompile(reinterpret_cast(const_cast(patternString).chars()), patternString.length(), ignoreCaseOption, multilineOption, &numSubpatterns, &error)); -} - -}} - -#endif diff --git a/js/src/yarr/yarr/RegexJIT.h b/js/src/yarr/yarr/RegexJIT.h deleted file mode 100644 index 60a51b484c02..000000000000 --- a/js/src/yarr/yarr/RegexJIT.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2009 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 RegexJIT_h -#define RegexJIT_h - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/MacroAssembler.h" -#include "assembler/assembler/MacroAssemblerCodeRef.h" -#include "assembler/jit/ExecutableAllocator.h" -#include "RegexPattern.h" -#include "yarr/jswtfbridge.h" - -#include "yarr/pcre/pcre.h" -struct JSRegExp; // temporary, remove when fallback is removed. - -#if WTF_CPU_X86 && !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO -#define YARR_CALL __attribute__ ((regparm (3))) -#else -#define YARR_CALL -#endif - -struct JSContext; - -namespace JSC { - -namespace Yarr { - -class RegexCodeBlock { - typedef int (*RegexJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; - -public: - RegexCodeBlock() - : m_fallback(0) - { - } - - ~RegexCodeBlock() - { - if (m_fallback) - jsRegExpFree(m_fallback); - if (m_ref.m_size) - m_ref.m_executablePool->release(); - } - - JSRegExp* getFallback() { return m_fallback; } - void setFallback(JSRegExp* fallback) { m_fallback = fallback; } - - bool operator!() { return (!m_ref.m_code.executableAddress() && !m_fallback); } - void set(MacroAssembler::CodeRef ref) { m_ref = ref; } - - int execute(const UChar* input, unsigned start, unsigned length, int* output) - { - void *code = m_ref.m_code.executableAddress(); - return JS_EXTENSION((reinterpret_cast(code))(input, start, length, output)); - } - -private: - MacroAssembler::CodeRef m_ref; - JSRegExp* m_fallback; -}; - -void jitCompileRegex(ExecutableAllocator &allocator, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, int& error, bool &fellBack, bool ignoreCase = false, bool multiline = false -#ifdef ANDROID - , bool forceFallback = false -#endif -); - -inline int executeRegex(JSContext *cx, RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize) -{ - if (JSRegExp* fallback = jitObject.getFallback()) { - int result = jsRegExpExecute(cx, fallback, input, length, start, output, outputArraySize); - - if (result == JSRegExpErrorHitLimit) - return HitRecursionLimit; - - // -1 represents no-match for both PCRE and YARR. - JS_ASSERT(result >= -1); - return result; - } - - return jitObject.execute(input, start, length, output); -} - -} } // namespace JSC::Yarr - -#endif /* ENABLE_ASSEMBLER */ - -#endif // RegexJIT_h diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 50711ae8a547..7341d40d7f65 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -2032,7 +2032,7 @@ POSSIBILITY OF SUCH DAMAGE.

Apple License

-

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr/wtf, js/src/yarr/yarr, and widget/src/cocoa.

+

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr, and widget/src/cocoa.

 Copyright (C) 2008, 2009 Apple Inc. All rights reserved.

From 173afee041896fb62f006a7588950826723c5091 Mon Sep 17 00:00:00 2001
From: David Mandelin 
Date: Mon, 23 May 2011 14:22:03 -0700
Subject: [PATCH 100/145] Backed out changeset de6dfe16fd91 due to Linux/Mac
 build bustage

---
 js/src/Makefile.in                            |   37 +-
 .../assembler/AbstractMacroAssembler.h        |   63 +-
 js/src/assembler/assembler/MacroAssembler.h   |   12 +-
 .../assembler/assembler/MacroAssemblerARM.cpp |    2 +-
 .../assembler/assembler/MacroAssemblerARM.h   |   50 +-
 .../assembler/assembler/MacroAssemblerARMv7.h |   44 +-
 .../assembler/MacroAssemblerCodeRef.h         |   17 +-
 .../assembler/assembler/MacroAssemblerSparc.h |   48 +-
 .../assembler/assembler/MacroAssemblerX86.h   |   14 +-
 .../assembler/MacroAssemblerX86Common.h       |   44 +-
 .../assembler/MacroAssemblerX86_64.h          |   16 +-
 js/src/assembler/jit/ExecutableAllocator.h    |   20 +-
 .../assembler/jit/ExecutableAllocatorOS2.cpp  |    2 +-
 .../jit/ExecutableAllocatorPosix.cpp          |    4 +-
 .../jit/ExecutableAllocatorSymbian.cpp        |    2 +-
 .../assembler/jit/ExecutableAllocatorWin.cpp  |    2 +-
 js/src/assembler/wtf/Platform.h               |  989 ++----
 .../jit-test/tests/basic/bug632964-regexp.js  |    3 +
 js/src/jscompartment.cpp                      |   11 +-
 js/src/jscompartment.h                        |   10 +-
 js/src/jsregexp.cpp                           |   46 +-
 js/src/jsregexpinlines.h                      |  119 +-
 js/src/jsutil.h                               |   10 -
 js/src/jsvector.h                             |   22 +-
 js/src/methodjit/Compiler.cpp                 |   10 +-
 js/src/methodjit/MethodJIT.cpp                |    7 +-
 js/src/methodjit/TrampolineCompiler.cpp       |    2 +-
 js/src/yarr/BumpPointerAllocator.h            |  254 --
 js/src/yarr/Makefile                          |    5 +
 js/src/yarr/OSAllocator.h                     |  103 -
 js/src/yarr/OSAllocatorPosix.cpp              |  129 -
 js/src/yarr/OSAllocatorWin.cpp                |   89 -
 js/src/yarr/PageAllocation.h                  |  131 -
 js/src/yarr/PageBlock.cpp                     |   88 -
 js/src/yarr/PageBlock.h                       |   91 -
 js/src/yarr/VMTags.h                          |   90 -
 js/src/yarr/Yarr.h                            |   72 -
 js/src/yarr/YarrInterpreter.cpp               | 1914 -----------
 js/src/yarr/YarrInterpreter.h                 |  380 ---
 js/src/yarr/YarrJIT.cpp                       | 2405 -------------
 js/src/yarr/YarrJIT.h                         |   93 -
 js/src/yarr/jswtfbridge.h                     |   61 +
 js/src/yarr/pcre/AUTHORS                      |   12 +
 js/src/yarr/pcre/COPYING                      |   35 +
 js/src/yarr/pcre/chartables.c                 |   96 +
 js/src/yarr/pcre/dftables                     |  273 ++
 js/src/yarr/pcre/pcre.h                       |   68 +
 js/src/yarr/pcre/pcre.pri                     |   12 +
 js/src/yarr/pcre/pcre_compile.cpp             | 2702 +++++++++++++++
 js/src/yarr/pcre/pcre_exec.cpp                | 2193 ++++++++++++
 js/src/yarr/pcre/pcre_internal.h              |  434 +++
 js/src/yarr/pcre/pcre_tables.cpp              |   71 +
 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp     |   98 +
 js/src/yarr/pcre/pcre_xclass.cpp              |  114 +
 js/src/yarr/pcre/ucpinternal.h                |  126 +
 js/src/yarr/pcre/ucptable.cpp                 | 2968 +++++++++++++++++
 js/src/yarr/{ => wtf}/ASCIICType.h            |   33 +-
 js/src/yarr/wtfbridge.h                       |  321 --
 js/src/yarr/{ => yarr}/RegExpJitTables.h      |    0
 .../RegexCommon.h}                            |   56 +-
 .../RegexCompiler.cpp}                        |  568 +---
 .../RegexCompiler.h}                          |   25 +-
 js/src/yarr/yarr/RegexJIT.cpp                 | 1589 +++++++++
 js/src/yarr/yarr/RegexJIT.h                   |  112 +
 .../yarr/{YarrParser.h => yarr/RegexParser.h} |  260 +-
 .../{YarrPattern.h => yarr/RegexPattern.h}    |  218 +-
 toolkit/content/license.html                  |    2 +-
 67 files changed, 12024 insertions(+), 7873 deletions(-)
 delete mode 100644 js/src/yarr/BumpPointerAllocator.h
 create mode 100644 js/src/yarr/Makefile
 delete mode 100644 js/src/yarr/OSAllocator.h
 delete mode 100644 js/src/yarr/OSAllocatorPosix.cpp
 delete mode 100644 js/src/yarr/OSAllocatorWin.cpp
 delete mode 100644 js/src/yarr/PageAllocation.h
 delete mode 100644 js/src/yarr/PageBlock.cpp
 delete mode 100644 js/src/yarr/PageBlock.h
 delete mode 100644 js/src/yarr/VMTags.h
 delete mode 100644 js/src/yarr/Yarr.h
 delete mode 100644 js/src/yarr/YarrInterpreter.cpp
 delete mode 100644 js/src/yarr/YarrInterpreter.h
 delete mode 100644 js/src/yarr/YarrJIT.cpp
 delete mode 100644 js/src/yarr/YarrJIT.h
 create mode 100644 js/src/yarr/jswtfbridge.h
 create mode 100644 js/src/yarr/pcre/AUTHORS
 create mode 100644 js/src/yarr/pcre/COPYING
 create mode 100644 js/src/yarr/pcre/chartables.c
 create mode 100644 js/src/yarr/pcre/dftables
 create mode 100644 js/src/yarr/pcre/pcre.h
 create mode 100644 js/src/yarr/pcre/pcre.pri
 create mode 100644 js/src/yarr/pcre/pcre_compile.cpp
 create mode 100644 js/src/yarr/pcre/pcre_exec.cpp
 create mode 100644 js/src/yarr/pcre/pcre_internal.h
 create mode 100644 js/src/yarr/pcre/pcre_tables.cpp
 create mode 100644 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp
 create mode 100644 js/src/yarr/pcre/pcre_xclass.cpp
 create mode 100644 js/src/yarr/pcre/ucpinternal.h
 create mode 100644 js/src/yarr/pcre/ucptable.cpp
 rename js/src/yarr/{ => wtf}/ASCIICType.h (81%)
 delete mode 100644 js/src/yarr/wtfbridge.h
 rename js/src/yarr/{ => yarr}/RegExpJitTables.h (100%)
 rename js/src/yarr/{YarrSyntaxChecker.cpp => yarr/RegexCommon.h} (52%)
 rename js/src/yarr/{YarrPattern.cpp => yarr/RegexCompiler.cpp} (52%)
 rename js/src/yarr/{YarrSyntaxChecker.h => yarr/RegexCompiler.h} (74%)
 create mode 100644 js/src/yarr/yarr/RegexJIT.cpp
 create mode 100644 js/src/yarr/yarr/RegexJIT.h
 rename js/src/yarr/{YarrParser.h => yarr/RegexParser.h} (81%)
 rename js/src/yarr/{YarrPattern.h => yarr/RegexPattern.h} (70%)

diff --git a/js/src/Makefile.in b/js/src/Makefile.in
index 71f35a53d881..8023b1750b05 100644
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -362,6 +362,7 @@ CPPSRCS += 	MethodJIT.cpp \
 		Retcon.cpp \
 		TrampolineCompiler.cpp \
 		$(NULL)
+#		PICStubCompiler.cpp \
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
 ifeq (x86_64, $(TARGET_CPU))
@@ -419,17 +420,14 @@ ifeq (,$(filter arm% sparc %86 x86_64,$(TARGET_CPU)))
 
 VPATH +=	$(srcdir)/assembler \
 		$(srcdir)/assembler/wtf \
-		$(srcdir)/yarr\
+		$(srcdir)/yarr/pcre \
 		$(NULL)
 
-CPPSRCS += \
-		Assertions.cpp \
-		OSAllocatorPosix.cpp \
-		OSAllocatorWin.cpp \
-		PageBlock.cpp \
-		YarrInterpreter.cpp \
-		YarrPattern.cpp \
-		YarrSyntaxChecker.cpp \
+CPPSRCS += 	pcre_compile.cpp \
+                pcre_exec.cpp \
+                pcre_tables.cpp \
+                pcre_xclass.cpp \
+                pcre_ucp_searchfuncs.cpp \
 		$(NULL)
 else
 
@@ -442,6 +440,9 @@ VPATH += 	$(srcdir)/assembler \
 		$(srcdir)/assembler/assembler \
 		$(srcdir)/methodjit \
 		$(srcdir)/yarr \
+		$(srcdir)/yarr/yarr \
+		$(srcdir)/yarr/pcre \
+		$(srcdir)/yarr/wtf \
 		$(NONE)
 
 CPPSRCS += 	Assertions.cpp \
@@ -450,16 +451,16 @@ CPPSRCS += 	Assertions.cpp \
 		ExecutableAllocatorOS2.cpp \
 		ExecutableAllocator.cpp \
 		ARMAssembler.cpp \
-        Logging.cpp \
+                Logging.cpp \
 		MacroAssemblerARM.cpp \
 		MacroAssemblerX86Common.cpp \
-		OSAllocatorPosix.cpp \
-		OSAllocatorWin.cpp \
-		PageBlock.cpp \
-		YarrInterpreter.cpp \
-		YarrJIT.cpp \
-		YarrPattern.cpp \
-		YarrSyntaxChecker.cpp \
+		RegexCompiler.cpp \
+		RegexJIT.cpp \
+		pcre_compile.cpp \
+                pcre_exec.cpp \
+                pcre_tables.cpp \
+                pcre_xclass.cpp \
+                pcre_ucp_searchfuncs.cpp \
 		$(NONE)
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
@@ -652,7 +653,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
 
 	# We desire these numbers to go down, not up. See "User guide to memory
 	# management within SpiderMonkey" in jsutil.h.
-	$(srcdir)/config/check_source_count.py OffTheBooks:: 54 \
+	$(srcdir)/config/check_source_count.py OffTheBooks:: 52 \
 		"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
 	# This should go to zero, if possible.
 	$(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \
diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h
index 3c14c80bd4b0..260380acd307 100644
--- a/js/src/assembler/assembler/AbstractMacroAssembler.h
+++ b/js/src/assembler/assembler/AbstractMacroAssembler.h
@@ -166,13 +166,13 @@ public:
         void* m_ptr;
     };
 
-    // TrustedImmPtr:
+    // ImmPtr:
     //
     // A pointer sized immediate operand to an instruction - this is wrapped
     // in a class requiring explicit construction in order to differentiate
     // from pointers used as absolute addresses to memory operations
-    struct TrustedImmPtr {
-        explicit TrustedImmPtr(const void* value)
+    struct ImmPtr {
+        explicit ImmPtr(const void* value)
             : m_value(value)
         {
         }
@@ -185,21 +185,14 @@ public:
         const void* m_value;
     };
 
-    struct ImmPtr : public TrustedImmPtr {
-        explicit ImmPtr(const void* value)
-            : TrustedImmPtr(value)
-        {
-        }
-    };
- 
-    // TrustedImm32:
+    // Imm32:
     //
     // A 32bit immediate operand to an instruction - this is wrapped in a
     // class requiring explicit construction in order to prevent RegisterIDs
     // (which are implemented as an enum) from accidentally being passed as
     // immediate values.
-    struct TrustedImm32 {
-        explicit TrustedImm32(int32_t value)
+    struct Imm32 {
+        explicit Imm32(int32_t value)
             : m_value(value)
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(false)
@@ -208,7 +201,7 @@ public:
         }
 
 #if !WTF_CPU_X86_64
-        explicit TrustedImm32(TrustedImmPtr ptr)
+        explicit Imm32(ImmPtr ptr)
             : m_value(ptr.asIntptr())
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(true)
@@ -230,20 +223,6 @@ public:
 #endif
     };
 
-
-    struct Imm32 : public TrustedImm32 {
-        explicit Imm32(int32_t value)
-            : TrustedImm32(value)
-        {
-        }
-#if !WTF_CPU_X86_64
-        explicit Imm32(TrustedImmPtr ptr)
-            : TrustedImm32(ptr)
-        {
-        }
-#endif
-    };
-
     struct ImmDouble {
         union {
             struct {
@@ -262,6 +241,7 @@ public:
         }
     };
 
+
     // Section 2: MacroAssembler code buffer handles
     //
     // The following types are used to reference items in the code buffer
@@ -293,7 +273,7 @@ public:
         
         bool isUsed() const { return m_label.isUsed(); }
         void used() { m_label.used(); }
-        bool isSet() const { return m_label.isValid(); }
+        bool isValid() const { return m_label.isValid(); }
     private:
         JmpDst m_label;
     };
@@ -316,8 +296,6 @@ public:
         {
         }
         
-        bool isSet() const { return m_label.isValid(); }
-
     private:
         JmpDst m_label;
     };
@@ -433,20 +411,6 @@ public:
     public:
         typedef js::Vector JumpVector;
 
-        JumpList() {}
-
-        JumpList(const JumpList &other)
-        {
-            m_jumps.append(other.m_jumps);
-        }
-
-        JumpList &operator=(const JumpList &other)
-        {
-            m_jumps.clear();
-            m_jumps.append(other.m_jumps);
-            return *this;
-        }
-
         void link(AbstractMacroAssembler* masm)
         {
             size_t size = m_jumps.length();
@@ -468,22 +432,17 @@ public:
             m_jumps.append(jump);
         }
         
-        void append(const JumpList& other)
+        void append(JumpList& other)
         {
             m_jumps.append(other.m_jumps.begin(), other.m_jumps.length());
         }
 
-        void clear()
-        {
-            m_jumps.clear();
-        }
-
         bool empty()
         {
             return !m_jumps.length();
         }
         
-        const JumpVector& jumps() const { return m_jumps; }
+        const JumpVector& jumps() { return m_jumps; }
 
     private:
         JumpVector m_jumps;
diff --git a/js/src/assembler/assembler/MacroAssembler.h b/js/src/assembler/assembler/MacroAssembler.h
index 38d5a31a2590..73bda22a8ee2 100644
--- a/js/src/assembler/assembler/MacroAssembler.h
+++ b/js/src/assembler/assembler/MacroAssembler.h
@@ -95,12 +95,12 @@ public:
         storePtr(src, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(TrustedImm32 value, int index = 0)
+    void poke(Imm32 value, int index = 0)
     {
         store32(value, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(TrustedImmPtr imm, int index = 0)
+    void poke(ImmPtr imm, int index = 0)
     {
         storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*))));
     }
@@ -117,7 +117,7 @@ public:
         branch32(cond, op1, op2).linkTo(target, this);
     }
 
-    void branch32(Condition cond, RegisterID op1, TrustedImm32 imm, Label target)
+    void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target)
     {
         branch32(cond, op1, imm).linkTo(target, this);
     }
@@ -288,17 +288,17 @@ public:
         store32(src, address);
     }
 
-    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
+    void storePtr(ImmPtr imm, ImplicitAddress address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(TrustedImmPtr imm, BaseIndex address)
+    void storePtr(ImmPtr imm, BaseIndex address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(TrustedImmPtr imm, void* address)
+    void storePtr(ImmPtr imm, void* address)
     {
         store32(Imm32(imm), address);
     }
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.cpp b/js/src/assembler/assembler/MacroAssemblerARM.cpp
index 065c98197395..14b4166b7ea9 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.cpp
+++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp
@@ -34,7 +34,7 @@
 
 #include "MacroAssemblerARM.h"
 
-#if WTF_OS_LINUX || WTF_OS_ANDROID
+#if WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID
 #include 
 #include 
 #include 
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h
index 2630bce7a909..7413411f4500 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -91,14 +91,14 @@ public:
         m_assembler.adds_r(dest, dest, src);
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         add32(imm, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -173,7 +173,7 @@ public:
         m_assembler.orrs_r(dest, dest, src);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -211,12 +211,12 @@ public:
         m_assembler.subs_r(dest, dest, src);
     }
 
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
 
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         sub32(imm, ARMRegisters::S1);
@@ -240,7 +240,7 @@ public:
         m_assembler.eors_r(dest, dest, src);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -380,7 +380,7 @@ public:
         m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset);
     }
 
-    void store32(TrustedImm32 imm, BaseIndex address)
+    void store32(Imm32 imm, BaseIndex address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -389,7 +389,7 @@ public:
         store32(ARMRegisters::S1, address);
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -404,7 +404,7 @@ public:
         m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address));
         if (imm.m_isPointer)
@@ -436,7 +436,7 @@ public:
         push(ARMRegisters::S0);
     }
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(dest, imm.m_value);
@@ -449,7 +449,7 @@ public:
         m_assembler.mov_r(dest, src);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -485,7 +485,7 @@ public:
         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
     {
         ASSERT(left != ARMRegisters::S0);
         if (right.m_isPointer) {
@@ -500,21 +500,21 @@ public:
     // number of instructions emitted is constant, regardless of the argument
     // values. For ARM, this is identical to branch32WithPatch, except that it
     // does not generate a DataLabel32.
-    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
     // As branch32_force32, but allow the value ('right') to be patched.
-    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left != ARMRegisters::S1);
         dataLabel = moveWithPatch(right, ARMRegisters::S1);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left.base != ARMRegisters::S1);
         load32(left, ARMRegisters::S1);
@@ -534,19 +534,19 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -828,7 +828,7 @@ public:
         setTest32(cond, address, mask, dest);
     }
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -850,7 +850,7 @@ public:
         move(ARMRegisters::S1, dest);
     }
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -859,7 +859,7 @@ public:
         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -880,7 +880,7 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         load32(left.m_ptr, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -908,14 +908,14 @@ public:
         return Call::fromTailJump(oldJump);
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         DataLabelPtr dataLabel(this);
         m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value));
         return dataLabel;
     }
 
-    DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
+    DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
     {
         DataLabel32 dataLabel(this);
         m_assembler.ldr_un_imm(dest, initialValue.m_value);
@@ -937,7 +937,7 @@ public:
         return jump;
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h
index c23e9ea6655f..5492f8246a06 100644
--- a/js/src/assembler/assembler/MacroAssemblerARMv7.h
+++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h
@@ -131,12 +131,12 @@ public:
         m_assembler.add(dest, dest, src);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         add32(imm, dest, dest);
     }
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -147,7 +147,7 @@ public:
         }
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -170,7 +170,7 @@ public:
         add32(dataTempRegister, dest);
     }
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -239,7 +239,7 @@ public:
         m_assembler.orr(dest, dest, src);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -285,7 +285,7 @@ public:
         m_assembler.sub(dest, dest, src);
     }
 
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -296,7 +296,7 @@ public:
         }
     }
 
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -319,7 +319,7 @@ public:
         sub32(dataTempRegister, dest);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -341,7 +341,7 @@ public:
         m_assembler.eor(dest, dest, src);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -486,7 +486,7 @@ public:
         store32(src, setupArmAddress(address));
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, setupArmAddress(address));
@@ -498,7 +498,7 @@ public:
         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, address);
@@ -667,7 +667,7 @@ public:
     //
     // Move values in registers.
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         uint32_t value = imm.m_value;
 
@@ -693,7 +693,7 @@ public:
         m_assembler.mov(dest, src);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -780,7 +780,7 @@ public:
         return Jump(makeBranch(cond));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right)
     {
         compare32(left, right);
         return Jump(makeBranch(cond));
@@ -798,21 +798,21 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32WithUnalignedHalfWords(left, addressTempRegister);
@@ -825,7 +825,7 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left.m_ptr, addressTempRegister);
@@ -1065,13 +1065,13 @@ public:
         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
     }
 
-    DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
+    DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst)
     {
         moveFixedWidthEncoding(imm, dst);
         return DataLabel32(this);
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
+    DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst)
     {
         moveFixedWidthEncoding(Imm32(imm), dst);
         return DataLabelPtr(this);
@@ -1090,7 +1090,7 @@ public:
         return branch32(cond, addressTempRegister, dataTempRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
         store32(dataTempRegister, address);
@@ -1179,7 +1179,7 @@ protected:
         return addressTempRegister;
     }
 
-    void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
+    void moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
     {
         uint32_t value = imm.m_value;
         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
diff --git a/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
index 6acdfd67a74d..841fa9647128 100644
--- a/js/src/assembler/assembler/MacroAssemblerCodeRef.h
+++ b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
@@ -180,8 +180,7 @@ private:
 class MacroAssemblerCodeRef {
 public:
     MacroAssemblerCodeRef()
-        : m_executablePool(NULL),
-          m_size(0)
+        : m_size(0)
     {
     }
 
@@ -192,20 +191,6 @@ public:
     {
     }
 
-    // Release the code memory in this code ref.
-    void release()
-    {
-        if (!m_executablePool)
-            return;
-
-#if defined DEBUG && (defined WTF_CPU_X86 || defined WTF_CPU_X86_64) 
-        void *addr = m_code.executableAddress();
-        memset(addr, 0xcc, m_size);
-#endif
-        m_executablePool->release();
-        m_executablePool = NULL;
-    }
-
     MacroAssemblerCodePtr m_code;
     ExecutablePool* m_executablePool;
     size_t m_size;
diff --git a/js/src/assembler/assembler/MacroAssemblerSparc.h b/js/src/assembler/assembler/MacroAssemblerSparc.h
index 91a8f0e16163..3bdd2d871b1b 100644
--- a/js/src/assembler/assembler/MacroAssemblerSparc.h
+++ b/js/src/assembler/assembler/MacroAssemblerSparc.h
@@ -97,14 +97,14 @@ namespace JSC {
             m_assembler.addcc_r(dest, src, dest);
         }
 
-        void add32(TrustedImm32 imm, Address address)
+        void add32(Imm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             add32(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
         }
 
-        void add32(TrustedImm32 imm, RegisterID dest)
+        void add32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(dest, imm.m_value, dest);
@@ -126,7 +126,7 @@ namespace JSC {
             m_assembler.andcc_r(dest, SparcRegisters::g2, dest);
         }
 
-        void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+        void add32(Imm32 imm, RegisterID src, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(src, imm.m_value, dest);
@@ -194,7 +194,7 @@ namespace JSC {
             m_assembler.orcc_r(dest, src, dest);
         }
 
-        void or32(TrustedImm32 imm, RegisterID dest)
+        void or32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.orcc_imm(dest, imm.m_value, dest);
@@ -240,7 +240,7 @@ namespace JSC {
             m_assembler.subcc_r(dest, src, dest);
         }
 
-        void sub32(TrustedImm32 imm, RegisterID dest)
+        void sub32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.subcc_imm(dest, imm.m_value, dest);
@@ -250,7 +250,7 @@ namespace JSC {
             }
         }
 
-        void sub32(TrustedImm32 imm, Address address)
+        void sub32(Imm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -268,7 +268,7 @@ namespace JSC {
             m_assembler.xorcc_r(src, dest, dest);
         }
 
-        void xor32(TrustedImm32 imm, RegisterID dest)
+        void xor32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.xorcc_imm(dest, imm.m_value, dest);
@@ -548,7 +548,7 @@ namespace JSC {
             m_assembler.stw_r(src, address.base, SparcRegisters::g2);
         }
 
-        void store32(TrustedImm32 imm, BaseIndex address)
+        void store32(Imm32 imm, BaseIndex address)
         {
             m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
             add32(Imm32(address.offset), SparcRegisters::g2);
@@ -556,7 +556,7 @@ namespace JSC {
             m_assembler.stw_r(SparcRegisters::g3, SparcRegisters::g2, address.base);
         }
 
-        void store32(TrustedImm32 imm, ImplicitAddress address)
+        void store32(Imm32 imm, ImplicitAddress address)
         {
             m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -568,7 +568,7 @@ namespace JSC {
             m_assembler.stw_r(src, SparcRegisters::g0, SparcRegisters::g3);
         }
 
-        void store32(TrustedImm32 imm, void* address)
+        void store32(Imm32 imm, void* address)
         {
             move(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -598,7 +598,7 @@ namespace JSC {
             push(SparcRegisters::g2);
         }
 
-        void move(TrustedImm32 imm, RegisterID dest)
+        void move(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.or_imm(SparcRegisters::g0, imm.m_value, dest);
@@ -611,7 +611,7 @@ namespace JSC {
             m_assembler.or_r(src, SparcRegisters::g0, dest);
         }
 
-        void move(TrustedImmPtr imm, RegisterID dest)
+        void move(ImmPtr imm, RegisterID dest)
         {
             move(Imm32(imm), dest);
         }
@@ -641,20 +641,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32_force32(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32_force32(Condition cond, RegisterID left, Imm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
             m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g2);
             return branch32(cond, left, SparcRegisters::g2);
         }
 
-        Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+        Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
         {
             // Always use move_nocheck, since the value is to be patched.
             dataLabel = DataLabel32(this);
@@ -669,7 +669,7 @@ namespace JSC {
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32(Condition cond, RegisterID left, Imm32 right)
         {
             if (m_assembler.isimm13(right.m_value))
                 m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0);
@@ -692,20 +692,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, Address left, TrustedImm32 right)
+        Jump branch32(Condition cond, Address left, Imm32 right)
         {
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+        Jump branch32(Condition cond, BaseIndex left, Imm32 right)
         {
 
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
         {
             load32WithUnalignedHalfWords(left, SparcRegisters::g4);
             return branch32(cond, SparcRegisters::g4, right);
@@ -1052,7 +1052,7 @@ namespace JSC {
             store32(SparcRegisters::g2, address.m_ptr);
         }
 
-        void sub32(TrustedImm32 imm, AbsoluteAddress address)
+        void sub32(Imm32 imm, AbsoluteAddress address)
         {
             load32(address.m_ptr, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -1071,7 +1071,7 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+        Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
         {
             load32(left.m_ptr, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
@@ -1099,7 +1099,7 @@ namespace JSC {
             return Call::fromTailJump(oldJump);
         }
 
-        DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+        DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
         {
             DataLabelPtr dataLabel(this);
             Imm32 imm = Imm32(initialValue);
@@ -1107,7 +1107,7 @@ namespace JSC {
             return dataLabel;
         }
 
-        DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
+        DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
         {
             DataLabel32 dataLabel(this);
             m_assembler.move_nocheck(initialValue.m_value, dest);
@@ -1129,7 +1129,7 @@ namespace JSC {
             return jump;
         }
 
-        DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+        DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
         {
             DataLabelPtr dataLabel = moveWithPatch(initialValue, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86.h b/js/src/assembler/assembler/MacroAssemblerX86.h
index c6ab40f587fa..ee61b895a8fe 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.leal_mr(imm.m_value, src, dest);
     }
@@ -90,12 +90,12 @@ public:
         m_assembler.andl_im(imm.m_value, address.m_ptr);
     }
     
-    void or32(TrustedImm32 imm, AbsoluteAddress address)
+    void or32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.orl_im(imm.m_value, address.m_ptr);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.subl_im(imm.m_value, address.m_ptr);
     }
@@ -148,7 +148,7 @@ public:
         addDouble(Address(srcDest), dest);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         m_assembler.movl_i32m(imm.m_value, address);
     }
@@ -164,7 +164,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.m_ptr);
         return Jump(m_assembler.jCC(x86Condition(cond)));
@@ -186,7 +186,7 @@ public:
     }
 
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movl_i32r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -206,7 +206,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base);
         return DataLabelPtr(this);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h
index fa1b7ba8cb10..1ead9665f4e2 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86Common.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h
@@ -116,12 +116,12 @@ public:
         m_assembler.addl_rr(src, dest);
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         m_assembler.addl_im(imm.m_value, address.offset, address.base);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         m_assembler.addl_ir(imm.m_value, dest);
     }
@@ -234,7 +234,7 @@ public:
         m_assembler.orl_rr(src, dest);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         m_assembler.orl_ir(imm.m_value, dest);
     }
@@ -249,7 +249,7 @@ public:
         m_assembler.orl_mr(src.offset, src.base, dest);
     }
 
-    void or32(TrustedImm32 imm, Address address)
+    void or32(Imm32 imm, Address address)
     {
         m_assembler.orl_im(imm.m_value, address.offset, address.base);
     }
@@ -313,12 +313,12 @@ public:
         m_assembler.subl_rr(src, dest);
     }
     
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         m_assembler.subl_ir(imm.m_value, dest);
     }
     
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         m_assembler.subl_im(imm.m_value, address.offset, address.base);
     }
@@ -339,12 +339,12 @@ public:
         m_assembler.xorl_rr(src, dest);
     }
 
-    void xor32(TrustedImm32 imm, Address dest)
+    void xor32(Imm32 imm, Address dest)
     {
         m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         m_assembler.xorl_ir(imm.m_value, dest);
     }
@@ -468,7 +468,7 @@ public:
         m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(TrustedImm32 imm, BaseIndex address)
+    void store32(Imm32 imm, BaseIndex address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
@@ -483,7 +483,7 @@ public:
         m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
     }
@@ -748,7 +748,7 @@ public:
     //
     // Move values in registers.
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         // Note: on 64-bit the Imm32 value is zero extended into the register, it
         // may be useful to have a separate version that sign extends the value?
@@ -767,7 +767,7 @@ public:
             m_assembler.movq_rr(src, dest);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         m_assembler.movq_i64r(imm.asIntptr(), dest);
     }
@@ -798,7 +798,7 @@ public:
             m_assembler.movl_rr(src, dest);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         m_assembler.movl_i32r(imm.asIntptr(), dest);
     }
@@ -852,7 +852,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right)
     {
         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
             m_assembler.testl_rr(left, left);
@@ -864,14 +864,14 @@ public:
     // Branch based on a 32-bit comparison, forcing the size of the
     // immediate operand to 32 bits in the native code stream to ensure that
     // the length of code emitted by this instruction is consistent.
-    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
     {
         m_assembler.cmpl_ir_force32(right.m_value, left);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
     // Branch and record a label after the comparison.
-    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
     {
         // Always use cmpl, since the value is to be patched.
         m_assembler.cmpl_ir_force32(right.m_value, left);
@@ -879,7 +879,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
     {
         m_assembler.cmpl_im_force32(right.m_value, left.offset, left.base);
         dataLabel = DataLabel32(this);
@@ -898,19 +898,19 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         return branch32(cond, left, right);
     }
@@ -1369,7 +1369,7 @@ private:
     }
 
 #if WTF_CPU_X86
-#if WTF_OS_MAC_OS_X
+#if WTF_PLATFORM_MAC
 
     // All X86 Macs are guaranteed to support at least SSE2
     static bool isSSEPresent()
@@ -1382,7 +1382,7 @@ private:
         return true;
     }
 
-#else // OS(MAC_OS_X)
+#else // PLATFORM(MAC)
 
     static bool isSSEPresent()
     {
diff --git a/js/src/assembler/assembler/MacroAssemblerX86_64.h b/js/src/assembler/assembler/MacroAssemblerX86_64.h
index a5038a930e56..7dadc6bcaf2e 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86_64.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         add32(imm, Address(scratchRegister));
@@ -72,13 +72,13 @@ public:
         and32(imm, Address(scratchRegister));
     }
     
-    void or32(TrustedImm32 imm, AbsoluteAddress address)
+    void or32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         or32(imm, Address(scratchRegister));
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         sub32(imm, Address(scratchRegister));
@@ -114,7 +114,7 @@ public:
         m_assembler.cvtsq2sd_rr(srcDest, dest);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         move(X86Registers::eax, scratchRegister);
         move(imm, X86Registers::eax);
@@ -311,7 +311,7 @@ public:
         m_assembler.movq_rm(src, address.offset, address.base);
     }
 
-    void storePtr(TrustedImmPtr imm, BaseIndex address)
+    void storePtr(ImmPtr imm, BaseIndex address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -341,7 +341,7 @@ public:
         }
     }
 
-    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
+    void storePtr(ImmPtr imm, ImplicitAddress address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -487,7 +487,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -505,7 +505,7 @@ public:
         return branchPtr(cond, left, scratchRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
         storePtr(scratchRegister, address);
diff --git a/js/src/assembler/jit/ExecutableAllocator.h b/js/src/assembler/jit/ExecutableAllocator.h
index 9cca26f48c99..a54a4dab143b 100644
--- a/js/src/assembler/jit/ExecutableAllocator.h
+++ b/js/src/assembler/jit/ExecutableAllocator.h
@@ -52,16 +52,16 @@ extern  "C" void sync_instruction_memory(caddr_t v, u_int len);
 #endif
 #endif
 
-#if WTF_OS_IOS
+#if WTF_PLATFORM_IPHONE
 #include 
 #include 
 #endif
 
-#if WTF_OS_SYMBIAN
+#if WTF_PLATFORM_SYMBIAN
 #include 
 #endif
 
-#if WTF_CPU_MIPS && WTF_OS_LINUX
+#if WTF_CPU_MIPS && WTF_PLATFORM_LINUX
 #include 
 #endif
 
@@ -90,7 +90,7 @@ private:
     struct Allocation {
         char* pages;
         size_t size;
-#if WTF_OS_SYMBIAN
+#if WTF_PLATFORM_SYMBIAN
         RChunk* chunk;
 #endif
     };
@@ -269,7 +269,6 @@ private:
         return pool;
     }
 
-public:
     ExecutablePool* poolForSize(size_t n)
     {
 #ifndef DEBUG_STRESS_JSC_ALLOCATOR
@@ -328,6 +327,7 @@ public:
         return pool;
     }
 
+public:
 #if ENABLE_ASSEMBLER_WX_EXCLUSIVE
     static void makeWritable(void* start, size_t size)
     {
@@ -374,13 +374,13 @@ public:
         _flush_cache(reinterpret_cast(code), size, BCACHE);
 #endif
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_OS_IOS
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
     static void cacheFlush(void* code, size_t size)
     {
         sys_dcache_flush(code, size);
         sys_icache_invalidate(code, size);
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_IOS
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_LINUX
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
@@ -396,14 +396,14 @@ public:
             : "r" (code), "r" (reinterpret_cast(code) + size)
             : "r0", "r1", "r2");
     }
-#elif WTF_OS_SYMBIAN
+#elif WTF_PLATFORM_SYMBIAN
     static void cacheFlush(void* code, size_t size)
     {
         User::IMB_Range(code, static_cast(code) + size);
     }
-#elif WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
     static __asm void cacheFlush(void* code, size_t size);
-#elif WTF_CPU_ARM_TRADITIONAL && (WTF_OS_LINUX || WTF_OS_ANDROID) && WTF_COMPILER_GCC
+#elif WTF_CPU_ARM_TRADITIONAL && (WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID) && WTF_COMPILER_GCC
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
diff --git a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
index 675b604ae914..ef9e27d92b47 100644
--- a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_OS2
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_OS2
 
 #define INCL_DOS
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
index e334626ccc2f..50efd932e02a 100644
--- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
@@ -25,7 +25,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
 
 #include 
 #include 
@@ -74,7 +74,7 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe
 }
 #endif
 
-#if WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
+#if WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
 __asm void ExecutableAllocator::cacheFlush(void* code, size_t size)
 {
     ARM
diff --git a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
index f51c0d507877..c66fa80fff12 100644
--- a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
@@ -22,7 +22,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_SYMBIAN
 
 #include 
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorWin.cpp b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
index da6e756cfa66..f5775608f36f 100644
--- a/js/src/assembler/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_WIN_OS
 
 #include "jswin.h"
 
diff --git a/js/src/assembler/wtf/Platform.h b/js/src/assembler/wtf/Platform.h
index 217c9b8a1eec..68713cd4c810 100644
--- a/js/src/assembler/wtf/Platform.h
+++ b/js/src/assembler/wtf/Platform.h
@@ -1,7 +1,6 @@
 /*
  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc.  All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,267 +27,206 @@
 #ifndef WTF_Platform_h
 #define WTF_Platform_h
 
+/* Either XX(YY) --> WTF_XX_YY  or  XX(YY) --> XX_YY, depending on XX
+
+   PLATFORM(YY) --> WTF_PLATFORM_YY
+   COMPILER(YY) --> WTF_COMPILER_YY
+   CPU(YY)      --> WTF_CPU_YY
+   OS(YY)       --> WTF_OS_YY
+   USE(YY)      --> WTF_USE_YY
+
+   HAVE(YY)     --> HAVE_YY
+   ENABLE(YY)   --> ENABLE_YY
+*/
+
 /* ==== PLATFORM handles OS, operating environment, graphics API, and
    CPU. This macro will be phased out in favor of platform adaptation
    macros, policy decision macros, and top-level port definitions. ==== */
-#define PLATFORM(WTF_FEATURE) (defined WTF_PLATFORM_##WTF_FEATURE  && WTF_PLATFORM_##WTF_FEATURE)
+//#define PLATFORM(WTF_FEATURE) (defined(WTF_PLATFORM_##WTF_FEATURE)  && WTF_PLATFORM_##WTF_FEATURE)
 
 
 /* ==== Platform adaptation macros: these describe properties of the target environment. ==== */
 
 /* COMPILER() - the compiler being used to build the project */
-#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE  && WTF_COMPILER_##WTF_FEATURE)
+//#define COMPILER(WTF_FEATURE) (defined(WTF_COMPILER_##WTF_FEATURE)  && WTF_COMPILER_##WTF_FEATURE)
 /* CPU() - the target CPU architecture */
-#define CPU(WTF_FEATURE) (defined WTF_CPU_##WTF_FEATURE  && WTF_CPU_##WTF_FEATURE)
+//#define CPU(WTF_FEATURE) (defined(WTF_CPU_##WTF_FEATURE)  && WTF_CPU_##WTF_FEATURE)
 /* HAVE() - specific system features (headers, functions or similar) that are present or not */
-#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE  && HAVE_##WTF_FEATURE)
+//#define HAVE(WTF_FEATURE) (defined(HAVE_##WTF_FEATURE)  && HAVE_##WTF_FEATURE)
 /* OS() - underlying operating system; only to be used for mandated low-level services like 
    virtual memory, not to choose a GUI toolkit */
-#define OS(WTF_FEATURE) (defined WTF_OS_##WTF_FEATURE  && WTF_OS_##WTF_FEATURE)
+//#define OS(WTF_FEATURE) (defined(WTF_OS_##WTF_FEATURE)  && WTF_OS_##WTF_FEATURE)
 
 
 /* ==== Policy decision macros: these define policy choices for a particular port. ==== */
 
 /* USE() - use a particular third-party library or optional OS service */
-#define USE(WTF_FEATURE) (defined WTF_USE_##WTF_FEATURE  && WTF_USE_##WTF_FEATURE)
+//#define USE(WTF_FEATURE) (defined(WTF_USE_##WTF_FEATURE)  && WTF_USE_##WTF_FEATURE)
 /* ENABLE() - turn on a specific feature of WebKit */
-#define ENABLE(WTF_FEATURE) (defined ENABLE_##WTF_FEATURE  && ENABLE_##WTF_FEATURE)
+//#define ENABLE(WTF_FEATURE) (defined(ENABLE_##WTF_FEATURE)  && ENABLE_##WTF_FEATURE)
 
 
 
 /* ==== COMPILER() - the compiler being used to build the project ==== */
 
-/* WTF_COMPILER_MSVC Microsoft Visual C++ */
-/* WTF_COMPILER_MSVC7_OR_LOWER Microsoft Visual C++ 2003 or lower*/
-/* WTF_COMPILER_MSVC9_OR_LOWER Microsoft Visual C++ 2008 or lower*/
+/* COMPILER(MSVC) Microsoft Visual C++ */
+/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/
 #if defined(_MSC_VER)
 #define WTF_COMPILER_MSVC 1
 #if _MSC_VER < 1400
-#define WTF_COMPILER_MSVC7_OR_LOWER 1
-#elif _MSC_VER < 1600
-#define WTF_COMPILER_MSVC9_OR_LOWER 1
+#define WTF_COMPILER_MSVC7 1
 #endif
 #endif
 
-/* WTF_COMPILER_RVCT  - ARM RealView Compilation Tools */
-/* WTF_COMPILER_RVCT4_OR_GREATER - ARM RealView Compilation Tools 4.0 or greater */
+/* COMPILER(RVCT)  - ARM RealView Compilation Tools */
 #if defined(__CC_ARM) || defined(__ARMCC__)
 #define WTF_COMPILER_RVCT 1
-#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) (__ARMCC_VERSION >= (major * 100000 + minor * 10000 + patch * 1000 + build))
-#else
-/* Define this for !RVCT compilers, just so we can write things like RVCT_VERSION_AT_LEAST(3, 0, 0, 0). */
-#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) 0
 #endif
 
-/* WTF_COMPILER_GCC - GNU Compiler Collection */
+/* COMPILER(GCC) - GNU Compiler Collection */
 /* --gnu option of the RVCT compiler also defines __GNUC__ */
 #if defined(__GNUC__) && !WTF_COMPILER_RVCT
 #define WTF_COMPILER_GCC 1
 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch))
-#else
-/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */
-#define GCC_VERSION_AT_LEAST(major, minor, patch) 0
 #endif
 
-/* WTF_COMPILER_MINGW - MinGW GCC */
-/* WTF_COMPILER_MINGW64 - mingw-w64 GCC - only used as additional check to exclude mingw.org specific functions */
-#if defined(__MINGW32__)
+/* COMPILER(MINGW) - MinGW GCC */
+#if defined(MINGW) || defined(__MINGW32__)
 #define WTF_COMPILER_MINGW 1
-#include <_mingw.h> /* private MinGW header */
-    #if defined(__MINGW64_VERSION_MAJOR) /* best way to check for mingw-w64 vs mingw.org */
-        #define WTF_COMPILER_MINGW64 1
-    #endif /* __MINGW64_VERSION_MAJOR */
-#endif /* __MINGW32__ */
+#endif
 
-/* WTF_COMPILER_WINSCW - CodeWarrior for Symbian emulator */
+/* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */
 #if defined(__WINSCW__)
 #define WTF_COMPILER_WINSCW 1
-/* cross-compiling, it is not really windows */
-#undef WIN32
-#undef _WIN32
 #endif
 
-/* WTF_COMPILER_INTEL - Intel C++ Compiler */
-#if defined(__INTEL_COMPILER)
-#define WTF_COMPILER_INTEL 1
+/* COMPILER(SUNPRO) - Sun Studio for Solaris */
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#define WTF_COMPILER_SUNPRO 1
 #endif
 
-/* WTF_COMPILER_SUNCC */
-#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
-#define WTF_COMPILER_SUNCC 1
-#endif
 
 /* ==== CPU() - the target CPU architecture ==== */
 
-/* This also defines WTF_CPU_BIG_ENDIAN or WTF_CPU_MIDDLE_ENDIAN or neither, as appropriate. */
+/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */
 
-/* WTF_CPU_ALPHA - DEC Alpha */
+
+/* CPU(ALPHA) - DEC Alpha */
 #if defined(__alpha__)
 #define WTF_CPU_ALPHA 1
 #endif
 
-/* WTF_CPU_IA64 - Itanium / IA-64 */
+/* CPU(IA64) - Itanium / IA-64 */
 #if defined(__ia64__)
 #define WTF_CPU_IA64 1
-/* 32-bit mode on Itanium */
-#if !defined(__LP64__)
-#define WTF_CPU_IA64_32 1
-#endif
 #endif
 
-/* WTF_CPU_MIPS - MIPS 32-bit */
-/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now.  */
-#if (defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_)) \
-    && defined(_ABIO32)
-#define WTF_CPU_MIPS 1
-#if defined(__MIPSEB__)
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-#define WTF_MIPS_PIC (defined __PIC__)
-#define WTF_MIPS_ARCH __mips
-#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v)
-#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v)
-#define WTF_MIPS_ARCH_REV __mips_isa_rev
-#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
-#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float)
-#define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64)
-/* MIPS requires allocators to use aligned memory */
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-#endif /* MIPS */
-
-/* WTF_CPU_PPC - PowerPC 32-bit */
+/* CPU(PPC) - PowerPC 32-bit */
 #if   defined(__ppc__)     \
-    || defined(__PPC__)     \
-    || defined(__powerpc__) \
-    || defined(__powerpc)   \
-    || defined(__POWERPC__) \
-    || defined(_M_PPC)      \
-    || defined(__PPC)
+   || defined(__PPC__)     \
+   || defined(__powerpc__) \
+   || defined(__powerpc)   \
+   || defined(__POWERPC__) \
+   || defined(_M_PPC)      \
+   || defined(__PPC)
 #define WTF_CPU_PPC 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_PPC64 - PowerPC 64-bit */
+/* CPU(PPC64) - PowerPC 64-bit */
 #if   defined(__ppc64__) \
-    || defined(__PPC64__)
+   || defined(__PPC64__)
 #define WTF_CPU_PPC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SH4 - SuperH SH-4 */
+/* CPU(SH4) - SuperH SH-4 */
 #if defined(__SH4__)
 #define WTF_CPU_SH4 1
 #endif
 
-/* WTF_CPU_SPARC32 - SPARC 32-bit */
+/* CPU(SPARC32) - SPARC 32-bit */
 #if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8)
 #define WTF_CPU_SPARC32 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SPARC64 - SPARC 64-bit */
+/* CPU(SPARC64) - SPARC 64-bit */
 #if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)
 #define WTF_CPU_SPARC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SPARC - any SPARC, true for WTF_CPU_SPARC32 and WTF_CPU_SPARC64 */
+/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */
 #if WTF_CPU_SPARC32 || WTF_CPU_SPARC64
 #define WTF_CPU_SPARC 1
 #endif
 
-/* WTF_CPU_S390X - S390 64-bit */
-#if defined(__s390x__)
-#define WTF_CPU_S390X 1
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-
-/* WTF_CPU_S390 - S390 32-bit */
-#if defined(__s390__)
-#define WTF_CPU_S390 1
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-
-/* WTF_CPU_X86 - i386 / x86 32-bit */
+/* CPU(X86) - i386 / x86 32-bit */
 #if   defined(__i386__) \
-    || defined(i386)     \
-    || defined(_M_IX86)  \
-    || defined(_X86_)    \
-    || defined(__THW_INTEL)
+   || defined(i386)     \
+   || defined(_M_IX86)  \
+   || defined(_X86_)    \
+   || defined(__THW_INTEL)
 #define WTF_CPU_X86 1
 #endif
 
-/* WTF_CPU_X86_64 - AMD64 / Intel64 / x86_64 64-bit */
+/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */
 #if   defined(__x86_64__) \
-    || defined(_M_X64)
+   || defined(_M_X64)
 #define WTF_CPU_X86_64 1
 #endif
 
-/* WTF_CPU_ARM - ARM, any version*/
+/* CPU(ARM) - ARM, any version*/
 #if   defined(arm) \
-    || defined(__arm__) \
-    || defined(ARM) \
-    || defined(_ARM_)
+   || defined(__arm__)
 #define WTF_CPU_ARM 1
 
-#if defined(__ARMEB__) || (WTF_COMPILER_RVCT && defined(__BIG_ENDIAN))
+#if defined(__ARMEB__)
 #define WTF_CPU_BIG_ENDIAN 1
 
 #elif !defined(__ARM_EABI__) \
-    && !defined(__EABI__) \
-    && !defined(__VFP_FP__) \
-    && !defined(_WIN32_WCE) \
-    && !defined(ANDROID)
+   && !defined(__EABI__) \
+   && !defined(__VFP_FP__) \
+   && !defined(ANDROID)
 #define WTF_CPU_MIDDLE_ENDIAN 1
 
 #endif
 
-#define WTF_ARM_ARCH_AT_LEAST(N) (CPU(ARM) && WTF_ARM_ARCH_VERSION >= N)
+#define WTF_ARM_ARCH_AT_LEAST(N) (WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= N)
 
 /* Set WTF_ARM_ARCH_VERSION */
 #if   defined(__ARM_ARCH_4__) \
-    || defined(__ARM_ARCH_4T__) \
-    || defined(__MARM_ARMV4__) \
-    || defined(_ARMV4I_)
+   || defined(__ARM_ARCH_4T__) \
+   || defined(__MARM_ARMV4__) \
+   || defined(_ARMV4I_)
 #define WTF_ARM_ARCH_VERSION 4
 
 #elif defined(__ARM_ARCH_5__) \
-    || defined(__ARM_ARCH_5T__) \
-    || defined(__MARM_ARMV5__)
+   || defined(__ARM_ARCH_5T__) \
+   || defined(__ARM_ARCH_5E__) \
+   || defined(__ARM_ARCH_5TE__) \
+   || defined(__ARM_ARCH_5TEJ__) \
+   || defined(__MARM_ARMV5__)
 #define WTF_ARM_ARCH_VERSION 5
 
-#elif defined(__ARM_ARCH_5E__) \
-    || defined(__ARM_ARCH_5TE__) \
-    || defined(__ARM_ARCH_5TEJ__)
-#define WTF_ARM_ARCH_VERSION 5
-/*ARMv5TE requires allocators to use aligned memory*/
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-
 #elif defined(__ARM_ARCH_6__) \
-    || defined(__ARM_ARCH_6J__) \
-    || defined(__ARM_ARCH_6K__) \
-    || defined(__ARM_ARCH_6Z__) \
-    || defined(__ARM_ARCH_6ZK__) \
-    || defined(__ARM_ARCH_6T2__) \
-    || defined(__ARMV6__)
+   || defined(__ARM_ARCH_6J__) \
+   || defined(__ARM_ARCH_6K__) \
+   || defined(__ARM_ARCH_6Z__) \
+   || defined(__ARM_ARCH_6ZK__) \
+   || defined(__ARM_ARCH_6T2__) \
+   || defined(__ARMV6__)
 #define WTF_ARM_ARCH_VERSION 6
 
 #elif defined(__ARM_ARCH_7A__) \
-    || defined(__ARM_ARCH_7R__)
+   || defined(__ARM_ARCH_7R__)
 #define WTF_ARM_ARCH_VERSION 7
 
 /* RVCT sets _TARGET_ARCH_ARM */
 #elif defined(__TARGET_ARCH_ARM)
 #define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM
 
-#if defined(__TARGET_ARCH_5E) \
-    || defined(__TARGET_ARCH_5TE) \
-    || defined(__TARGET_ARCH_5TEJ)
-/*ARMv5TE requires allocators to use aligned memory*/
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-#endif
-
 #else
 #define WTF_ARM_ARCH_VERSION 0
 
@@ -299,22 +237,22 @@
 #define WTF_THUMB_ARCH_VERSION 1
 
 #elif defined(__ARM_ARCH_5T__) \
-    || defined(__ARM_ARCH_5TE__) \
-    || defined(__ARM_ARCH_5TEJ__)
+   || defined(__ARM_ARCH_5TE__) \
+   || defined(__ARM_ARCH_5TEJ__)
 #define WTF_THUMB_ARCH_VERSION 2
 
 #elif defined(__ARM_ARCH_6J__) \
-    || defined(__ARM_ARCH_6K__) \
-    || defined(__ARM_ARCH_6Z__) \
-    || defined(__ARM_ARCH_6ZK__) \
-    || defined(__ARM_ARCH_6M__)
+   || defined(__ARM_ARCH_6K__) \
+   || defined(__ARM_ARCH_6Z__) \
+   || defined(__ARM_ARCH_6ZK__) \
+   || defined(__ARM_ARCH_6M__)
 #define WTF_THUMB_ARCH_VERSION 3
 
 #elif defined(__ARM_ARCH_6T2__) \
-    || defined(__ARM_ARCH_7__) \
-    || defined(__ARM_ARCH_7A__) \
-    || defined(__ARM_ARCH_7R__) \
-    || defined(__ARM_ARCH_7M__)
+   || defined(__ARM_ARCH_7__) \
+   || defined(__ARM_ARCH_7A__) \
+   || defined(__ARM_ARCH_7R__) \
+   || defined(__ARM_ARCH_7M__)
 #define WTF_THUMB_ARCH_VERSION 4
 
 /* RVCT sets __TARGET_ARCH_THUMB */
@@ -326,22 +264,22 @@
 #endif
 
 
-/* WTF_CPU_ARMV5_OR_LOWER - ARM instruction set v5 or earlier */
+/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */
 /* On ARMv5 and below the natural alignment is required. 
    And there are some other differences for v5 or earlier. */
-#if !defined(ARMV5_OR_LOWER) && !WTF_ARM_ARCH_AT_LEAST(6)
+#if !defined(ARMV5_OR_LOWER) /* && !CPU_ARM_ARCH_AT_LEAST(6) */
 #define WTF_CPU_ARMV5_OR_LOWER 1
 #endif
 
 
-/* WTF_CPU_ARM_TRADITIONAL - Thumb2 is not available, only traditional ARM (v4 or greater) */
-/* WTF_CPU_ARM_THUMB2 - Thumb2 instruction set is available */
+/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */
+/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */
 /* Only one of these will be defined. */
 #if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
 #  if defined(thumb2) || defined(__thumb2__) \
-    || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
-#    define WTF_CPU_ARM_TRADITIONAL 0
-#    define WTF_CPU_ARM_THUMB2 1
+  || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
+#    define WTF_CPU_ARM_TRADITIONAL 1
+#    define WTF_CPU_ARM_THUMB2 0
 #  elif WTF_ARM_ARCH_AT_LEAST(4)
 #    define WTF_CPU_ARM_TRADITIONAL 1
 #    define WTF_CPU_ARM_THUMB2 0
@@ -350,36 +288,19 @@
 #  endif
 #elif WTF_CPU_ARM_TRADITIONAL && WTF_CPU_ARM_THUMB2 /* Sanity Check */
 #  error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms"
-#endif /* !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) */
-
-#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON)
-#define WTF_CPU_ARM_NEON 1
-#endif
+#endif // !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
 
 #endif /* ARM */
 
-#if WTF_CPU_ARM || WTF_CPU_MIPS
-#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
-#endif
 
-/* ==== OS() - underlying operating system; only to be used for mandated low-level services like 
-   virtual memory, not to choose a GUI toolkit ==== */
 
-/* WTF_OS_ANDROID - Android */
-#ifdef ANDROID
-#define WTF_OS_ANDROID 1
-#endif
+/* Operating systems - low-level dependencies */
 
-/* WTF_OS_AIX - AIX */
-#ifdef _AIX
-#define WTF_OS_AIX 1
-#endif
-
-/* WTF_OS_DARWIN - Any Darwin-based OS, including Mac OS X and iPhone OS */
+/* PLATFORM(DARWIN) */
+/* Operating system level dependencies for Mac OS X / Darwin that should */
+/* be used regardless of operating environment */
 #ifdef __APPLE__
-#define WTF_OS_DARWIN 1
-
-/* FIXME: BUILDING_ON_.., and TARGETING... macros should be folded into the OS() system */
+#define WTF_PLATFORM_DARWIN 1
 #include 
 #if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
 #define BUILDING_ON_TIGER 1
@@ -396,97 +317,98 @@
 #define TARGETING_SNOW_LEOPARD 1
 #endif
 #include 
-
 #endif
 
-/* WTF_OS_IOS - iOS */
-/* WTF_OS_MAC_OS_X - Mac OS X (not including iOS) */
-#if WTF_OS_DARWIN && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED)  \
-    || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)                   \
-    || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR))
-#define WTF_OS_IOS 1
-#elif WTF_OS_DARWIN && defined(TARGET_OS_MAC) && TARGET_OS_MAC
-#define WTF_OS_MAC_OS_X 1
-#endif
-
-/* WTF_OS_FREEBSD - FreeBSD */
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#define WTF_OS_FREEBSD 1
-#endif
-
-/* WTF_OS_HAIKU - Haiku */
-#ifdef __HAIKU__
-#define WTF_OS_HAIKU 1
-#endif
-
-/* WTF_OS_LINUX - Linux */
-#ifdef __linux__
-#define WTF_OS_LINUX 1
-#endif
-
-/* WTF_OS_NETBSD - NetBSD */
-#if defined(__NetBSD__)
-#define WTF_OS_NETBSD 1
-#endif
-
-/* WTF_OS_OPENBSD - OpenBSD */
-#ifdef __OpenBSD__
-#define WTF_OS_OPENBSD 1
-#endif
-
-/* WTF_OS_QNX - QNX */
-#if defined(__QNXNTO__)
-#define WTF_OS_QNX 1
-#endif
-
-/* WTF_OS_SOLARIS - Solaris */
-#if defined(sun) || defined(__sun)
-#define WTF_OS_SOLARIS 1
-#endif
-
-/* WTF_OS_WINCE - Windows CE; note that for this platform WTF_OS_WINDOWS is also defined */
-#if defined(_WIN32_WCE)
-#define WTF_OS_WINCE 1
-#endif
-
-/* WTF_OS_WINDOWS - Any version of Windows */
+/* PLATFORM(WIN_OS) */
+/* Operating system level dependencies for Windows that should be used */
+/* regardless of operating environment */
 #if defined(WIN32) || defined(_WIN32)
-#define WTF_OS_WINDOWS 1
+#define WTF_PLATFORM_WIN_OS 1
+#endif
+
+/* PLATFORM(LINUX) */
+/* Operating system level dependencies for Linux-like systems that */
+/* should be used regardless of operating environment */
+#ifdef __linux__
+#define WTF_PLATFORM_LINUX 1
+#endif
+
+/* PLATFORM(FREEBSD) */
+/* Operating system level dependencies for FreeBSD-like systems that */
+/* should be used regardless of operating environment */
+#ifdef __FreeBSD__
+#define WTF_PLATFORM_FREEBSD 1
+#endif
+
+/* PLATFORM(OPENBSD) */
+/* Operating system level dependencies for OpenBSD systems that */
+/* should be used regardless of operating environment */
+#ifdef __OpenBSD__
+#define WTF_PLATFORM_OPENBSD 1
+#endif
+
+/* PLATFORM(SOLARIS) */
+/* Operating system level dependencies for Solaris that should be used */
+/* regardless of operating environment */
+#if defined(sun) || defined(__sun)
+#define WTF_PLATFORM_SOLARIS 1
+#endif
+
+/* PLATFORM(OS2) */
+/* Operating system level dependencies for OS/2 that should be used */
+/* regardless of operating environment */
+#if defined(OS2) || defined(__OS2__)
+#define WTF_PLATFORM_OS2 1
 #endif
 
-/* WTF_OS_SYMBIAN - Symbian */
 #if defined (__SYMBIAN32__)
-#define WTF_OS_SYMBIAN 1
+/* we are cross-compiling, it is not really windows */
+#undef WTF_PLATFORM_WIN_OS
+#undef WTF_PLATFORM_WIN
+#define WTF_PLATFORM_SYMBIAN 1
 #endif
 
-/* WTF_OS_UNIX - Any Unix-like system */
-#if   WTF_OS_AIX              \
-    || WTF_OS_ANDROID          \
-    || WTF_OS_DARWIN           \
-    || WTF_OS_FREEBSD          \
-    || WTF_OS_HAIKU            \
-    || WTF_OS_LINUX            \
-    || WTF_OS_NETBSD           \
-    || WTF_OS_OPENBSD          \
-    || WTF_OS_QNX              \
-    || WTF_OS_SOLARIS          \
-    || WTF_OS_SYMBIAN          \
-    || defined(unix)        \
-    || defined(__unix)      \
-    || defined(__unix__)
-#define WTF_OS_UNIX 1
+
+/* PLATFORM(NETBSD) */
+/* Operating system level dependencies for NetBSD that should be used */
+/* regardless of operating environment */
+#if defined(__NetBSD__)
+#define WTF_PLATFORM_NETBSD 1
+#endif
+
+/* PLATFORM(QNX) */
+/* Operating system level dependencies for QNX that should be used */
+/* regardless of operating environment */
+#if defined(__QNXNTO__)
+#define WTF_PLATFORM_QNX 1
+#endif
+
+/* PLATFORM(UNIX) */
+/* Operating system level dependencies for Unix-like systems that */
+/* should be used regardless of operating environment */
+#if   WTF_PLATFORM_DARWIN     \
+   || WTF_PLATFORM_FREEBSD    \
+   || WTF_PLATFORM_SYMBIAN    \
+   || WTF_PLATFORM_NETBSD     \
+   || defined(unix)        \
+   || defined(__unix)      \
+   || defined(__unix__)    \
+   || defined(_AIX)        \
+   || defined(__HAIKU__)   \
+   || defined(__QNXNTO__)  \
+   || defined(ANDROID)
+#define WTF_PLATFORM_UNIX 1
 #endif
 
 /* Operating environments */
 
-/* FIXME: these are all mixes of OS, operating environment and policy choices. */
-/* WTF_PLATFORM_CHROMIUM */
-/* WTF_PLATFORM_QT */
-/* WTF_PLATFORM_WX */
-/* WTF_PLATFORM_GTK */
-/* WTF_PLATFORM_HAIKU */
-/* WTF_PLATFORM_MAC */
-/* WTF_PLATFORM_WIN */
+/* PLATFORM(CHROMIUM) */
+/* PLATFORM(QT) */
+/* PLATFORM(WX) */
+/* PLATFORM(GTK) */
+/* PLATFORM(HAIKU) */
+/* PLATFORM(MAC) */
+/* PLATFORM(WIN) */
 #if defined(BUILDING_CHROMIUM__)
 #define WTF_PLATFORM_CHROMIUM 1
 #elif defined(BUILDING_QT__)
@@ -497,229 +419,142 @@
 #define WTF_PLATFORM_GTK 1
 #elif defined(BUILDING_HAIKU__)
 #define WTF_PLATFORM_HAIKU 1
-#elif defined(BUILDING_BREWMP__)
-#define WTF_PLATFORM_BREWMP 1
-#if defined(AEE_SIMULATOR)
-#define WTF_PLATFORM_BREWMP_SIMULATOR 1
-#else
-#define WTF_PLATFORM_BREWMP_SIMULATOR 0
-#endif
-#undef WTF_OS_WINDOWS
-#undef WTF_PLATFORM_WIN
-#elif WTF_OS_DARWIN
+#elif WTF_PLATFORM_DARWIN
 #define WTF_PLATFORM_MAC 1
-#elif WTF_OS_WINDOWS
+#elif WTF_PLATFORM_WIN_OS
 #define WTF_PLATFORM_WIN 1
 #endif
 
-/* WTF_PLATFORM_IOS */
-/* FIXME: this is sometimes used as an OS switch and sometimes for higher-level things */
+/* PLATFORM(IPHONE) */
 #if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
-#define WTF_PLATFORM_IOS 1
+#define WTF_PLATFORM_IPHONE 1
 #endif
 
-/* WTF_PLATFORM_IOS_SIMULATOR */
+/* PLATFORM(IPHONE_SIMULATOR) */
 #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
-#define WTF_PLATFORM_IOS 1
-#define WTF_PLATFORM_IOS_SIMULATOR 1
+#define WTF_PLATFORM_IPHONE 1
+#define WTF_PLATFORM_IPHONE_SIMULATOR 1
 #else
-#define WTF_PLATFORM_IOS_SIMULATOR 0
+#define WTF_PLATFORM_IPHONE_SIMULATOR 0
 #endif
 
-#if !defined(WTF_PLATFORM_IOS)
-#define WTF_PLATFORM_IOS 0
+#if !defined(WTF_PLATFORM_IPHONE)
+#define WTF_PLATFORM_IPHONE 0
 #endif
 
-/* WTF_PLATFORM_ANDROID */
-/* FIXME: this is sometimes used as an OS() switch, and other times to drive
-   policy choices */
+/* PLATFORM(ANDROID) */
 #if defined(ANDROID)
 #define WTF_PLATFORM_ANDROID 1
 #endif
 
 /* Graphics engines */
 
-/* WTF_USE_CG and WTF_PLATFORM_CI */
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS
-#define WTF_USE_CG 1
+/* PLATFORM(CG) and PLATFORM(CI) */
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CG 1
 #endif
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS || (WTF_PLATFORM_WIN && WTF_USE_CG)
-#define WTF_USE_CA 1
+#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CI 1
 #endif
 
-/* WTF_USE_SKIA for Win/Linux, CG for Mac */
+/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */
 #if WTF_PLATFORM_CHROMIUM
-#if WTF_OS_DARWIN
-#define WTF_USE_CG 1
+#if WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CG 1
+#define WTF_PLATFORM_CI 1
 #define WTF_USE_ATSUI 1
 #define WTF_USE_CORE_TEXT 1
-#define WTF_USE_ICCJPEG 1
 #else
-#define WTF_USE_SKIA 1
-#define WTF_USE_CHROMIUM_NET 1
+#define WTF_PLATFORM_SKIA 1
 #endif
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define WTF_USE_SKIA 1
-#endif
-
 #if WTF_PLATFORM_GTK
-#define WTF_USE_CAIRO 1
+#define WTF_PLATFORM_CAIRO 1
 #endif
 
 
-#if WTF_OS_WINCE
-#include 
-#define WTF_USE_MERSENNE_TWISTER_19937 1
-#endif
-
-#if WTF_PLATFORM_QT && WTF_OS_UNIX && !WTF_OS_SYMBIAN && !WTF_OS_DARWIN
-#define WTF_USE_PTHREAD_BASED_QT 1
-#endif
-
-#if (WTF_PLATFORM_GTK || WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || (WTF_PLATFORM_QT && (WTF_OS_DARWIN || WTF_USE_PTHREAD_BASED_QT) && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
+#if (WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_OS2 || (WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
 #define ENABLE_JSC_MULTIPLE_THREADS 1
 #endif
 
-#if ENABLE_JSC_MULTIPLE_THREADS
-#define ENABLE_WTF_MULTIPLE_THREADS 1
-#endif
-
 /* On Windows, use QueryPerformanceCounter by default */
-#if WTF_OS_WINDOWS
+#if WTF_PLATFORM_WIN_OS
 #define WTF_USE_QUERY_PERFORMANCE_COUNTER  1
 #endif
 
-#if WTF_OS_WINCE && !WTF_PLATFORM_QT
-#define NOMINMAX       /* Windows min and max conflict with standard macros */
-#define NOSHLWAPI      /* shlwapi.h not available on WinCe */
-
-/* MSDN documentation says these functions are provided with uspce.lib.  But we cannot find this file. */
-#define __usp10__      /* disable "usp10.h" */
-
-#define _INC_ASSERT    /* disable "assert.h" */
-#define assert(x)
-
-#endif  /* WTF_OS_WINCE && !WTF_PLATFORM_QT */
-
 #if WTF_PLATFORM_QT
 #define WTF_USE_QT4_UNICODE 1
-#elif WTF_OS_WINCE
-#define WTF_USE_WINCE_UNICODE 1
-#elif WTF_PLATFORM_BREWMP
-#define WTF_USE_BREWMP_UNICODE 1
 #elif WTF_PLATFORM_GTK
 /* The GTK+ Unicode backend is configurable */
 #else
 #define WTF_USE_ICU_UNICODE 1
 #endif
 
-#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS
+#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CF 1
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && WTF_CPU_X86_64
 #define WTF_USE_PLUGIN_HOST_PROCESS 1
 #endif
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-#define ENABLE_GESTURE_EVENTS 1
-#define ENABLE_RUBBER_BANDING 1
-#define WTF_USE_WK_SCROLLBAR_PAINTER 1
-#endif
-#if !defined(ENABLE_JAVA_BRIDGE)
-#define ENABLE_JAVA_BRIDGE 1
+#if !defined(ENABLE_MAC_JAVA_BRIDGE)
+#define ENABLE_MAC_JAVA_BRIDGE 1
 #endif
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 1
 #endif
-#define WTF_USE_CF 1
-#define WTF_USE_PTHREADS 1
-#define HAVE_PTHREAD_RWLOCK 1
 #define HAVE_READLINE 1
 #define HAVE_RUNLOOP_TIMER 1
-#define ENABLE_FULLSCREEN_API 1
-#define ENABLE_SMOOTH_SCROLLING 1
-#define ENABLE_WEB_ARCHIVE 1
-#endif /* WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS */
+#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */
 
-#if WTF_PLATFORM_CHROMIUM && WTF_OS_DARWIN
-#define WTF_USE_CF 1
+#if WTF_PLATFORM_CHROMIUM && WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define ENABLE_SINGLE_THREADED 1
+#if WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #endif
 
-#if WTF_PLATFORM_QT && WTF_OS_DARWIN
-#define WTF_USE_CF 1
-#endif
-
-#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER) && !WTF_PLATFORM_GTK && !WTF_PLATFORM_QT
-#define ENABLE_PURGEABLE_MEMORY 1
-#endif
-
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define ENABLE_CONTEXT_MENUS 0
 #define ENABLE_DRAG_SUPPORT 0
-#define ENABLE_DATA_TRANSFER_ITEMS 0
 #define ENABLE_FTPDIR 1
 #define ENABLE_GEOLOCATION 1
 #define ENABLE_ICONDATABASE 0
 #define ENABLE_INSPECTOR 0
-#define ENABLE_JAVA_BRIDGE 0
+#define ENABLE_MAC_JAVA_BRIDGE 0
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #define ENABLE_ORIENTATION_EVENTS 1
 #define ENABLE_REPAINT_THROTTLING 1
 #define HAVE_READLINE 1
-#define WTF_USE_CF 1
+#define WTF_PLATFORM_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
-#define ENABLE_WEB_ARCHIVE 1
 #endif
 
 #if WTF_PLATFORM_ANDROID
 #define WTF_USE_PTHREADS 1
+#define WTF_PLATFORM_SGL 1
 #define USE_SYSTEM_MALLOC 1
-#define ENABLE_JAVA_BRIDGE 1
+#define ENABLE_MAC_JAVA_BRIDGE 1
 #define LOG_DISABLED 1
-/* Prevents Webkit from drawing the caret in textfields and textareas
-   This prevents unnecessary invals. */
+// Prevents Webkit from drawing the caret in textfields and textareas
+// This prevents unnecessary invals.
 #define ENABLE_TEXT_CARET 1
 #define ENABLE_JAVASCRIPT_DEBUGGER 0
-#if !defined(ENABLE_JIT) && !ENABLE_ANDROID_JSC_JIT
-#define ENABLE_JIT 0
-#endif
 #endif
 
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE
-#define WTF_USE_CF 1
-#define WTF_USE_PTHREADS 0
-#endif
-
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !defined(WIN_CAIRO)
-#define WTF_USE_CFNETWORK 1
-#endif
-
-#if WTF_USE_CFNETWORK || WTF_PLATFORM_MAC
-#define WTF_USE_CFURLCACHE 1
-#define WTF_USE_CFURLSTORAGESESSIONS 1
-#endif
-
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !WTF_PLATFORM_QT
-#define ENABLE_WEB_ARCHIVE 1
+#if WTF_PLATFORM_WIN
+#define WTF_USE_WININET 1
 #endif
 
 #if WTF_PLATFORM_WX
 #define ENABLE_ASSEMBLER 1
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
-#if WTF_OS_DARWIN
-#define WTF_USE_CF 1
-#ifndef BUILDING_ON_TIGER
-#define WTF_USE_CORE_TEXT 1
-#define ENABLE_WEB_ARCHIVE 1
-#else
-#define WTF_USE_ATSUI 1
-#endif
+#if WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #endif
 #endif
 
@@ -739,39 +574,25 @@
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define USE_SYSTEM_MALLOC 1
-#endif
-
-#if WTF_PLATFORM_BREWMP_SIMULATOR
-#define ENABLE_JIT 0
-#endif
-
 #if !defined(HAVE_ACCESSIBILITY)
-#if WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
+#if WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
 #define HAVE_ACCESSIBILITY 1
 #endif
 #endif /* !defined(HAVE_ACCESSIBILITY) */
 
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
+#if WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
 #define HAVE_SIGNAL_H 1
 #endif
 
-#if !defined(HAVE_STRNSTR)
-#if WTF_OS_DARWIN || WTF_OS_FREEBSD
-#define HAVE_STRNSTR 1
-#endif
-#endif
-
-#if !WTF_OS_WINDOWS && !WTF_OS_SOLARIS && !WTF_OS_QNX \
-    && !WTF_OS_SYMBIAN && !WTF_OS_HAIKU && !WTF_OS_RVCT \
-    && !WTF_OS_ANDROID && !WTF_PLATFORM_BREWMP
+#if !WTF_PLATFORM_WIN_OS && !WTF_PLATFORM_SOLARIS && !WTF_PLATFORM_QNX \
+    && !WTF_PLATFORM_SYMBIAN && !WTF_PLATFORM_HAIKU && !WTF_COMPILER_RVCT \
+    && !WTF_PLATFORM_ANDROID && !WTF_PLATFORM_OS2
 #define HAVE_TM_GMTOFF 1
 #define HAVE_TM_ZONE 1
 #define HAVE_TIMEGM 1
-#endif
+#endif     
 
-#if WTF_OS_DARWIN
+#if WTF_PLATFORM_DARWIN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 1
@@ -782,37 +603,23 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 #define HAVE_SYS_TIMEB_H 1
-#define WTF_USE_ACCELERATE 1
 
-#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD)
-
-#define HAVE_DISPATCH_H 1
-#define HAVE_HOSTED_CORE_ANIMATION 1
-
-#if !WTF_PLATFORM_IOS
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !WTF_PLATFORM_IPHONE && !WTF_PLATFORM_QT
 #define HAVE_MADV_FREE_REUSE 1
 #define HAVE_MADV_FREE 1
 #define HAVE_PTHREAD_SETNAME_NP 1
 #endif
 
-#endif
-
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define HAVE_MADV_FREE 1
 #endif
 
-#elif WTF_OS_WINDOWS
+#elif WTF_PLATFORM_WIN_OS
 
-#if WTF_OS_WINCE
-#define HAVE_ERRNO_H 0
-#else
 #define HAVE_SYS_TIMEB_H 1
-#define HAVE_ALIGNED_MALLOC 1
-#define HAVE_ISDEBUGGERPRESENT 1
-#endif
 #define HAVE_VIRTUALALLOC 1
 
-#elif WTF_OS_SYMBIAN
+#elif WTF_PLATFORM_SYMBIAN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 0
@@ -825,11 +632,7 @@
 #define HAVE_SYS_PARAM_H 1
 #endif
 
-#elif WTF_PLATFORM_BREWMP
-
-#define HAVE_ERRNO_H 1
-
-#elif WTF_OS_QNX
+#elif WTF_PLATFORM_QNX
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 1
@@ -838,7 +641,7 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
-#elif WTF_OS_ANDROID
+#elif WTF_PLATFORM_ANDROID
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 0
@@ -848,13 +651,23 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
+#elif WTF_PLATFORM_OS2
+
+#define HAVE_MMAP 1
+#define ENABLE_ASSEMBLER 1
+#define HAVE_ERRNO_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIMEB_H 1
+
 #else
 
 /* FIXME: is this actually used or do other platforms generate their own config.h? */
 
 #define HAVE_ERRNO_H 1
 /* As long as Haiku doesn't have a complete support of locale this will be disabled. */
-#if !WTF_OS_HAIKU
+#if !WTF_PLATFORM_HAIKU
 #define HAVE_LANGINFO_H 1
 #endif
 #define HAVE_MMAP 1
@@ -867,14 +680,6 @@
 
 /* ENABLE macro defaults */
 
-#if WTF_PLATFORM_QT
-/* We must not customize the global operator new and delete for the Qt port. */
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
-#if !WTF_OS_UNIX || WTF_OS_SYMBIAN
-#define USE_SYSTEM_MALLOC 1
-#endif
-#endif
-
 /* fastMalloc match validation allows for runtime verification that
    new is matched by delete, fastMalloc is matched by fastFree, etc. */
 #if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION)
@@ -905,10 +710,6 @@
 #define ENABLE_DRAG_SUPPORT 1
 #endif
 
-#if !defined(ENABLE_DATA_TRANSFER_ITEMS)
-#define ENABLE_DATA_TRANSFER_ITEMS 0
-#endif
-
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 0
 #endif
@@ -917,22 +718,14 @@
 #define ENABLE_INSPECTOR 1
 #endif
 
-#if !defined(ENABLE_JAVA_BRIDGE)
-#define ENABLE_JAVA_BRIDGE 0
+#if !defined(ENABLE_MAC_JAVA_BRIDGE)
+#define ENABLE_MAC_JAVA_BRIDGE 0
 #endif
 
 #if !defined(ENABLE_NETSCAPE_PLUGIN_API)
 #define ENABLE_NETSCAPE_PLUGIN_API 1
 #endif
 
-#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE)
-#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0
-#endif
-
-#if !defined(ENABLE_PURGEABLE_MEMORY)
-#define ENABLE_PURGEABLE_MEMORY 0
-#endif
-
 #if !defined(WTF_USE_PLUGIN_HOST_PROCESS)
 #define WTF_USE_PLUGIN_HOST_PROCESS 0
 #endif
@@ -945,11 +738,6 @@
 #define ENABLE_OPCODE_STATS 0
 #endif
 
-#if !defined(ENABLE_GLOBAL_FASTMALLOC_NEW)
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 1
-#endif
-
-#define ENABLE_DEBUG_WITH_BREAKPOINT 0
 #define ENABLE_SAMPLING_COUNTERS 0
 #define ENABLE_SAMPLING_FLAGS 0
 #define ENABLE_OPCODE_SAMPLING 0
@@ -965,18 +753,10 @@
 #define ENABLE_GEOLOCATION 0
 #endif
 
-#if !defined(ENABLE_GESTURE_RECOGNIZER)
-#define ENABLE_GESTURE_RECOGNIZER 0
-#endif
-
 #if !defined(ENABLE_NOTIFICATIONS)
 #define ENABLE_NOTIFICATIONS 0
 #endif
 
-#if WTF_PLATFORM_IOS
-#define ENABLE_TEXT_CARET 0
-#endif
-
 #if !defined(ENABLE_TEXT_CARET)
 #define ENABLE_TEXT_CARET 1
 #endif
@@ -985,88 +765,80 @@
 #define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0
 #endif
 
-#if !defined(ENABLE_FULLSCREEN_API)
-#define ENABLE_FULLSCREEN_API 0
-#endif
-
-#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64)
-#if (WTF_CPU_X86_64 && (WTF_OS_UNIX || WTF_OS_WINDOWS)) \
-    || (WTF_CPU_IA64 && !WTF_CPU_IA64_32) \
-    || WTF_CPU_ALPHA \
-    || WTF_CPU_SPARC64 \
-    || WTF_CPU_S390X \
-    || WTF_CPU_PPC64
+#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
+#if (WTF_CPU_X86_64 && (WTF_PLATFORM_UNIX || WTF_PLATFORM_WIN_OS)) || WTF_CPU_IA64 || WTF_CPU_ALPHA
 #define WTF_USE_JSVALUE64 1
+#elif WTF_CPU_ARM || WTF_CPU_PPC64
+#define WTF_USE_JSVALUE32 1
+#elif WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW
+/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
+on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
+#define WTF_USE_JSVALUE32 1
 #else
 #define WTF_USE_JSVALUE32_64 1
 #endif
-#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */
+#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */
 
 #if !defined(ENABLE_REPAINT_THROTTLING)
 #define ENABLE_REPAINT_THROTTLING 0
 #endif
 
-/* Disable the JIT on versions of GCC prior to 4.1 */
-#if !defined(ENABLE_JIT) && WTF_COMPILER_GCC && !GCC_VERSION_AT_LEAST(4, 1, 0)
-#define ENABLE_JIT 0
+#if !defined(ENABLE_JIT)
+
+/* The JIT is tested & working on x86_64 Mac */
+#if WTF_CPU_X86_64 && WTF_PLATFORM_MAC
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 Mac */
+#elif WTF_CPU_X86 && WTF_PLATFORM_MAC
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 OS/2 */
+#elif WTF_CPU_X86 && WTF_PLATFORM_OS2
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 Windows */
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN
+    #define ENABLE_JIT 1
+#elif WTF_CPU_SPARC
+    #define ENABLE_JIT 1
 #endif
 
-/* JIT is not implemented for 64 bit on MSVC */
-#if !defined(ENABLE_JIT) && WTF_COMPILER_MSVC && WTF_CPU_X86_64
-#define ENABLE_JIT 0
+#if WTF_PLATFORM_QT
+#if WTF_CPU_X86_64 && WTF_PLATFORM_DARWIN
+    #define ENABLE_JIT 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_DARWIN
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX
+    #define ENABLE_JIT 1
 #endif
+#endif /* PLATFORM(QT) */
 
-/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */
-#if !defined(ENABLE_JIT) \
-    && (WTF_CPU_X86 || WTF_CPU_X86_64 || WTF_CPU_ARM || WTF_CPU_MIPS) \
-    && (WTF_OS_DARWIN || !WTF_COMPILER_GCC || GCC_VERSION_AT_LEAST(4, 1, 0)) \
-    && !WTF_OS_WINCE
-#define ENABLE_JIT 1
-#endif
+#endif /* !defined(ENABLE_JIT) */
 
-/* Currently only implemented for JSVALUE64, only tested on WTF_PLATFORM_MAC */
-#if ENABLE_JIT && WTF_USE_JSVALUE64 && WTF_PLATFORM_MAC
-#define ENABLE_DFG_JIT 1
-/* Enabled with restrictions to circumvent known performance regressions. */
-#define ENABLE_DFG_JIT_RESTRICTIONS 1
-#endif
-
-/* Ensure that either the JIT or the interpreter has been enabled. */
-#if !defined(ENABLE_INTERPRETER) && !ENABLE_JIT
-#define ENABLE_INTERPRETER 1
-#endif
-#if !(ENABLE_JIT || ENABLE_INTERPRETER)
-#error You have to have at least one execution model enabled to build JSC
-#endif
-
-#if WTF_CPU_SH4 && WTF_PLATFORM_QT
-#define ENABLE_JIT 1
-#define ENABLE_YARR 1
-#define ENABLE_YARR_JIT 1
-#define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
-#define ENABLE_ASSEMBLER 1
-#endif
-
-/* Configure the JIT */
 #if ENABLE_JIT
-    #if WTF_CPU_ARM
-    #if !defined(ENABLE_JIT_USE_SOFT_MODULO) && WTF_ARM_ARCH_AT_LEAST(5)
-    #define ENABLE_JIT_USE_SOFT_MODULO 1
-    #endif
-    #endif
-
-    #ifndef ENABLE_JIT_OPTIMIZE_CALL
-    #define ENABLE_JIT_OPTIMIZE_CALL 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
-    #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
-    #define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
-    #define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
-    #endif
+#ifndef ENABLE_JIT_OPTIMIZE_CALL
+#define ENABLE_JIT_OPTIMIZE_CALL 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
+#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
+#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
+#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
+#endif
 #endif
 
 #if WTF_CPU_X86 && WTF_COMPILER_MSVC
@@ -1077,89 +849,80 @@
 #define JSC_HOST_CALL
 #endif
 
-/* Configure the interpreter */
-#if WTF_COMPILER_GCC || (RVCT_VERSION_AT_LEAST(4, 0, 0, 0) && defined(__GNUC__))
+#if WTF_COMPILER_GCC && !ENABLE_JIT
 #define HAVE_COMPUTED_GOTO 1
 #endif
-#if HAVE_COMPUTED_GOTO && ENABLE_INTERPRETER
-#define ENABLE_COMPUTED_GOTO_INTERPRETER 1
+
+#if ENABLE_JIT && defined(COVERAGE)
+    #define WTF_USE_INTERPRETER 0
+#else
+    #define WTF_USE_INTERPRETER 1
 #endif
 
-/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc.  Results dumped at exit */
-#define ENABLE_REGEXP_TRACING 0
+/* Yet Another Regex Runtime. */
+#if !defined(ENABLE_YARR_JIT)
 
-/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */
-#if WTF_PLATFORM_CHROMIUM
-#define ENABLE_YARR_JIT 0
-
-#elif ENABLE_JIT && !defined(ENABLE_YARR_JIT)
+/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */
+#if (WTF_CPU_X86 \
+ || WTF_CPU_X86_64 \
+ || WTF_CPU_SPARC \
+ || WTF_CPU_ARM_TRADITIONAL \
+ || WTF_CPU_ARM_THUMB2 \
+ || WTF_CPU_X86)
 #define ENABLE_YARR_JIT 1
-
-/* Setting this flag compares JIT results with interpreter results. */
-#define ENABLE_YARR_JIT_DEBUG 0
+#else
+#define ENABLE_YARR_JIT 0
 #endif
 
-#if ENABLE_JIT || ENABLE_YARR_JIT
+#endif /* !defined(ENABLE_YARR_JIT) */
+
+#if (ENABLE_JIT || ENABLE_YARR_JIT)
 #define ENABLE_ASSEMBLER 1
 #endif
 /* Setting this flag prevents the assembler from using RWX memory; this may improve
    security but currectly comes at a significant performance cost. */
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1
-#endif
-
-/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in.
-   On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */
-#if ENABLE_ASSEMBLER
-#if WTF_CPU_X86_64
-#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1
 #else
-#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1
-#endif
+#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0
 #endif
 
-#if !defined(ENABLE_PAN_SCROLLING) && WTF_OS_WINDOWS
+#if !defined(ENABLE_PAN_SCROLLING) && WTF_PLATFORM_WIN_OS
 #define ENABLE_PAN_SCROLLING 1
 #endif
 
-#if !defined(ENABLE_SMOOTH_SCROLLING)
-#define ENABLE_SMOOTH_SCROLLING 0
-#endif
-
-#if !defined(ENABLE_WEB_ARCHIVE)
-#define ENABLE_WEB_ARCHIVE 0
-#endif
-
-/* Use the QXmlStreamReader implementation for XMLDocumentParser */
+/* Use the QXmlStreamReader implementation for XMLTokenizer */
 /* Use the QXmlQuery implementation for XSLTProcessor */
 #if WTF_PLATFORM_QT
 #define WTF_USE_QXMLSTREAM 1
 #define WTF_USE_QXMLQUERY 1
 #endif
 
-#if WTF_PLATFORM_MAC
-/* Complex text framework */
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
-#define WTF_USE_ATSUI 0
-#define WTF_USE_CORE_TEXT 1
-#else
-#define WTF_USE_ATSUI 1
-#define WTF_USE_CORE_TEXT 0
-#endif
+#if !WTF_PLATFORM_QT
+#define WTF_USE_FONT_FAST_PATH 1
 #endif
 
 /* Accelerated compositing */
-#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER)) || WTF_PLATFORM_IOS || WTF_PLATFORM_QT || (WTF_PLATFORM_WIN && !WTF_OS_WINCE &&!defined(WIN_CAIRO))
+#if WTF_PLATFORM_MAC
+#if !defined(BUILDING_ON_TIGER)
+#define WTF_USE_ACCELERATED_COMPOSITING 1
+#endif
+#endif
+
+#if WTF_PLATFORM_IPHONE
 #define WTF_USE_ACCELERATED_COMPOSITING 1
 #endif
 
-#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || WTF_PLATFORM_IOS
-#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1
-#endif
-
-#if WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-#define WTF_USE_AVFOUNDATION 1
-#endif
+/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with
+   with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and
+   off in one place. */
+//#if WTF_PLATFORM_WIN
+//#include "QuartzCorePresent.h"
+//#if QUARTZCORE_PRESENT
+//#define WTF_USE_ACCELERATED_COMPOSITING 1
+//#define ENABLE_3D_RENDERING 1
+//#endif
+//#endif
 
 #if WTF_COMPILER_GCC
 #define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result))
@@ -1167,7 +930,7 @@
 #define WARN_UNUSED_RETURN
 #endif
 
-#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_OS_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
+#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_PLATFORM_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
 #define ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH 1
 #endif
 
@@ -1176,46 +939,4 @@
 
 #define ENABLE_JSC_ZOMBIES 0
 
-/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_QT
-#define WTF_USE_PLATFORM_STRATEGIES 1
-#endif
-
-#if WTF_PLATFORM_WIN
-#define WTF_USE_CROSS_PLATFORM_CONTEXT_MENUS 1
-#endif
-
-/* Geolocation request policy. pre-emptive policy is to acquire user permission before acquiring location.
-   Client based implementations will have option to choose between pre-emptive and nonpre-emptive permission policy.
-   pre-emptive permission policy is enabled by default for all client-based implementations. */
-#if ENABLE_CLIENT_BASED_GEOLOCATION
-#define WTF_USE_PREEMPT_GEOLOCATION_PERMISSION 1
-#endif
-
-#if WTF_CPU_ARM_THUMB2
-#define ENABLE_BRANCH_COMPACTION 1
-#endif
-
-#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
-#define ENABLE_THREADING_OPENMP 1
-#endif
-
-#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE_SINGLE_THREADED && (ENABLE_THREADING_GENERIC || ENABLE_THREADING_LIBDISPATCH || ENABLE_THREADING_OPENMP)
-#define ENABLE_PARALLEL_JOBS 1
-#endif
-
-#if ENABLE_GLIB_SUPPORT
-#include "GTypedefs.h"
-#endif
-
-/* FIXME: This define won't be needed once #27551 is fully landed. However, 
-   since most ports try to support sub-project independence, adding new headers
-   to WTF causes many ports to break, and so this way we can address the build
-   breakages one port at a time. */
-#define WTF_USE_EXPORT_MACROS 0
-
-#if WTF_PLATFORM_QT || WTF_PLATFORM_GTK
-#define WTF_USE_UNIX_DOMAIN_SOCKETS 1
-#endif
-
 #endif /* WTF_Platform_h */
diff --git a/js/src/jit-test/tests/basic/bug632964-regexp.js b/js/src/jit-test/tests/basic/bug632964-regexp.js
index 75612dbc735d..7151d3713647 100644
--- a/js/src/jit-test/tests/basic/bug632964-regexp.js
+++ b/js/src/jit-test/tests/basic/bug632964-regexp.js
@@ -1,3 +1,5 @@
+// |jit-test| error: InternalError: regular expression too complex
+
 var sText = "s";
 
 for (var i = 0; i < 250000; ++i)
@@ -10,5 +12,6 @@ var match = sText.match(/s(\s|.)*?e/gi);
 //var match = sText.match(/s([\s\S]*?)e/gi);
 //var match = sText.match(/s(?:[\s\S]*?)e/gi);
 var end = new Date();
+print(end - start);
 
 assertEq(match.length, 1);
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index c88fae9fdaf0..ecc336cdc4c3 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -48,7 +48,6 @@
 #include "jstracer.h"
 #include "jswrapper.h"
 #include "assembler/wtf/Platform.h"
-#include "yarr/BumpPointerAllocator.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
@@ -74,9 +73,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     active(false),
 #ifdef JS_METHODJIT
     jaegerCompartment(NULL),
-#endif
-#if ENABLE_YARR_JIT
-    regExpAllocator(NULL),
 #endif
     propertyTree(thisForCtor()),
     emptyArgumentsShape(NULL),
@@ -88,6 +84,9 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     initialRegExpShape(NULL),
     initialStringShape(NULL),
     debugMode(rt->debugMode),
+#if ENABLE_YARR_JIT
+    regExpAllocator(NULL),
+#endif
     mathCache(NULL)
 {
     JS_INIT_CLIST(&scripts);
@@ -136,9 +135,11 @@ JSCompartment::init()
         return false;
 #endif
 
-    regExpAllocator = rt->new_();
+#if ENABLE_YARR_JIT
+    regExpAllocator = rt->new_();
     if (!regExpAllocator)
         return false;
+#endif
 
     if (!backEdgeTable.init())
         return false;
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 8827a275f796..5b3f16643050 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -54,8 +54,11 @@
 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
 #endif
 
-namespace JSC { class ExecutableAllocator; }
-namespace WTF { class BumpPointerAllocator; }
+namespace JSC {
+
+class ExecutableAllocator;
+
+}
 
 namespace js {
 
@@ -417,7 +420,6 @@ struct JS_FRIEND_API(JSCompartment) {
      */
     size_t getMjitCodeSize() const;
 #endif
-    WTF::BumpPointerAllocator    *regExpAllocator;
 
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
@@ -464,6 +466,8 @@ struct JS_FRIEND_API(JSCompartment) {
     bool                         debugMode;  // true iff debug mode on
     JSCList                      scripts;    // scripts in this compartment
 
+    JSC::ExecutableAllocator     *regExpAllocator;
+
     js::NativeIterCache          nativeIterCache;
 
     typedef js::Maybe LazyToSourceCache;
diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp
index 3d9f09f56559..0df8ae536a47 100644
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -59,6 +59,8 @@
 #include "jsobjinlines.h"
 #include "jsregexpinlines.h"
 
+#include "yarr/RegexParser.h"
+
 #ifdef JS_TRACER
 #include "jstracer.h"
 using namespace nanojit;
@@ -191,11 +193,11 @@ js_ObjectIsRegExp(JSObject *obj)
  */
 
 void
-RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error)
+RegExp::handleYarrError(JSContext *cx, int error)
 {
     switch (error) {
       case JSC::Yarr::NoError:
-        JS_NOT_REACHED("Called reportYarrError with value for no error");
+        JS_NOT_REACHED("Precondition violation: an error must have occurred.");
         return;
 #define COMPILE_EMSG(__code, __msg) \
       case JSC::Yarr::__code: \
@@ -208,16 +210,49 @@ RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error)
       COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN);
       COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */
       COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE);
       COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
+      COMPILE_EMSG(CharacterClassRangeSingleChar, JSMSG_BAD_CLASS_RANGE);
       COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
+      COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
+      COMPILE_EMSG(HitRecursionLimit, JSMSG_REGEXP_TOO_COMPLEX);
 #undef COMPILE_EMSG
       default:
-        JS_NOT_REACHED("Unknown Yarr error code");
+        JS_NOT_REACHED("Precondition violation: unknown Yarr error code.");
     }
 }
 
+void
+RegExp::handlePCREError(JSContext *cx, int error)
+{
+#define REPORT(msg_) \
+    JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \
+    return
+    switch (error) {
+      case -2: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 0: JS_NOT_REACHED("Precondition violation: an error must have occurred.");
+      case 1: REPORT(JSMSG_TRAILING_SLASH);
+      case 2: REPORT(JSMSG_TRAILING_SLASH);
+      case 3: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 4: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 5: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 6: REPORT(JSMSG_BAD_CLASS_RANGE);
+      case 7: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 8: REPORT(JSMSG_BAD_CLASS_RANGE);
+      case 9: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 10: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
+      case 11: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 12: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
+      case 13: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 14: REPORT(JSMSG_MISSING_PAREN);
+      case 15: REPORT(JSMSG_BAD_BACKREF);
+      case 16: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 17: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      default:
+        JS_NOT_REACHED("Precondition violation: unknown PCRE error code.");
+    }
+#undef REPORT
+}
+
 bool
 RegExp::parseFlags(JSContext *cx, JSString *flagStr, uintN *flagsOut)
 {
@@ -894,4 +929,3 @@ js_InitRegExpClass(JSContext *cx, JSObject *global)
 
     return proto;
 }
-
diff --git a/js/src/jsregexpinlines.h b/js/src/jsregexpinlines.h
index 305cf1590462..70db45413e1d 100644
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -48,13 +48,12 @@
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
-#include "methodjit/MethodJIT.h"
 #include "assembler/wtf/Platform.h"
-#include "yarr/BumpPointerAllocator.h"
 
-#include "yarr/Yarr.h"
 #if ENABLE_YARR_JIT
-#include "yarr/YarrJIT.h"
+#include "yarr/yarr/RegexJIT.h"
+#else
+#include "yarr/pcre/pcre.h"
 #endif
 
 namespace js {
@@ -96,10 +95,10 @@ regexp_statics_construct(JSContext *cx, GlobalObject *parent)
 class RegExp
 {
 #if ENABLE_YARR_JIT
-    /* native code is valid only if codeBlock.isFallBack() == false */
-    JSC::Yarr::YarrCodeBlock    codeBlock;
+    JSC::Yarr::RegexCodeBlock   compiled;
+#else
+    JSRegExp                    *compiled;
 #endif
-    JSC::Yarr::BytecodePattern  *byteCode;
     JSLinearString              *source;
     size_t                      refCount;
     unsigned                    parenCount; /* Must be |unsigned| to interface with YARR. */
@@ -112,11 +111,7 @@ class RegExp
 #endif
 
     RegExp(JSLinearString *source, uint32 flags, JSCompartment *compartment)
-      :
-#if ENABLE_YARR_JIT
-        codeBlock(),
-#endif
-        byteCode(NULL), source(source), refCount(1), parenCount(0), flags(flags)
+      : compiled(), source(source), refCount(1), parenCount(0), flags(flags)
 #ifdef DEBUG
         , compartment(compartment)
 #endif
@@ -125,18 +120,17 @@ class RegExp
     JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
 
     ~RegExp() {
-#if ENABLE_YARR_JIT
-        codeBlock.release();
+#if !ENABLE_YARR_JIT
+        if (compiled)
+            jsRegExpFree(compiled);
 #endif
-        // YYY
-        if (byteCode)
-            delete byteCode;
     }
 
     bool compileHelper(JSContext *cx, JSLinearString &pattern);
     bool compile(JSContext *cx);
     static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
-    void reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error);
+    void handlePCREError(JSContext *cx, int error);
+    void handleYarrError(JSContext *cx, int error);
     static inline bool initArena(JSContext *cx);
     static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
     static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
@@ -324,6 +318,9 @@ inline bool
 RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
                         size_t *lastIndex, bool test, Value *rval)
 {
+#if !ENABLE_YARR_JIT
+    JS_ASSERT(compiled);
+#endif
     const size_t pairCount = parenCount + 1;
     const size_t bufCount = pairCount * 3; /* Should be x2, but PCRE has... needs. */
     const size_t matchItemCount = pairCount * 2;
@@ -363,20 +360,27 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
         inputOffset = *lastIndex;
     }
 
-    int result;
 #if ENABLE_YARR_JIT
-    if (!codeBlock.isFallBack())
-        result = JSC::Yarr::execute(codeBlock, chars, *lastIndex - inputOffset, len, buf);
-    else
-        result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
+    int result = JSC::Yarr::executeRegex(cx, compiled, chars, *lastIndex - inputOffset, len, buf,
+                                         bufCount);
 #else
-    result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
+    int result = jsRegExpExecute(cx, compiled, chars, len, *lastIndex - inputOffset, buf, 
+                                 bufCount);
 #endif
     if (result == -1) {
         *rval = NullValue();
         return true;
     }
 
+    if (result < 0) {
+#if ENABLE_YARR_JIT
+        handleYarrError(cx, result);
+#else
+        handlePCREError(cx, result);
+#endif
+        return false;
+    }
+
     /* 
      * Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so
      * just do another pass.
@@ -456,44 +460,53 @@ RegExp::createObjectNoStatics(JSContext *cx, const jschar *chars, size_t length,
     return obj;
 }
 
-/*
- * This function should be deleted once we can. See bug 604774.
- */
-static inline bool
-EnableYarrJIT(JSContext *cx)
+#ifdef ANDROID
+static bool
+YarrJITIsBroken(JSContext *cx)
 {
-#if defined ANDROID && defined(JS_TRACER) && defined(JS_METHODJIT)
-    return cx->traceJitEnabled || cx->methodJitEnabled;
+#if defined(JS_TRACER) && defined(JS_METHODJIT)
+    /* FIXME/bug 604774: dead code walking.
+     *
+     * If both JITs are disabled, assume they were disabled because
+     * we're running on a blacklisted device.
+     */
+    return !cx->traceJitEnabled && !cx->methodJitEnabled;
 #else
-    return true;
+    return false;
 #endif
 }
+#endif  /* ANDROID */
 
 inline bool
 RegExp::compileHelper(JSContext *cx, JSLinearString &pattern)
 {
-    JSC::Yarr::ErrorCode yarrError;
-    JSC::Yarr::YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError);
-    if (yarrError) {
-        reportYarrError(cx, yarrError);
-        return false;
-    }
-    parenCount = yarrPattern.m_numSubpatterns;
-
-#if ENABLE_YARR_JIT && defined(JS_METHODJIT)
-    if (EnableYarrJIT(cx) && !yarrPattern.m_containsBackreferences) {
-        JSC::Yarr::JSGlobalData globalData(cx->compartment->jaegerCompartment->execAlloc());
-        JSC::Yarr::jitCompile(yarrPattern, &globalData, codeBlock);
-        if (!codeBlock.isFallBack())
-            return true;
-    } else {
-        codeBlock.setFallBack(true);
-    }
+#if ENABLE_YARR_JIT
+    bool fellBack = false;
+    int error = 0;
+    jitCompileRegex(*cx->compartment->regExpAllocator, compiled, pattern, parenCount, error, fellBack, ignoreCase(), multiline()
+#ifdef ANDROID
+                    /* Temporary gross hack to work around buggy kernels. */
+                    , YarrJITIsBroken(cx)
+#endif
+);
+    if (!error)
+        return true;
+    if (fellBack)
+        handlePCREError(cx, error);
+    else
+        handleYarrError(cx, error);
+    return false;
+#else
+    int error = 0;
+    compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
+                               ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
+                               multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
+                               &parenCount, &error);
+    if (!error)
+        return true;
+    handlePCREError(cx, error);
+    return false;
 #endif
-
-    byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
-
-    return true;
 }
 
 inline bool
diff --git a/js/src/jsutil.h b/js/src/jsutil.h
index 37b44d137b2e..1b249c1874a7 100644
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -374,21 +374,11 @@ JS_END_EXTERN_C
     QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3) {\
         JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\
     }\
-\
-    template \
-    QUALIFIERS T *new_(P1 &p1, const P2 &p2, const P3 &p3) {\
-        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\
-    }\
 \
     template \
     QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4) {\
         JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\
     }\
-\
-    template \
-    QUALIFIERS T *new_(const P1 &p1, const P2 &p2, P3 &p3, const P4 &p4) {\
-        JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\
-    }\
 \
     template \
     QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {\
diff --git a/js/src/jsvector.h b/js/src/jsvector.h
index 4eaf58b6a4e7..3d413c1f64b6 100644
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -208,30 +208,12 @@ class Vector : private AllocPolicy
 
     /* compute constants */
 
-    /*
-     * Consider element size to be 1 for buffer sizing if there are
-     * 0 inline elements. This allows us to compile when the definition
-     * of the element type is not visible here.
-     *
-     * Explicit specialization is only allowed at namespace scope, so
-     * in order to keep everything here, we use a dummy template
-     * parameter with partial specialization.
-     */
-    template 
-    struct ElemSize {
-        static const size_t result = sizeof(T);
-    };
-    template 
-    struct ElemSize<0, Dummy> {
-        static const size_t result = 1;
-    };
-
     static const size_t sInlineCapacity =
-        tl::Min::result>::result;
+        tl::Min::result;
 
     /* Calculate inline buffer size; avoid 0-sized array. */
     static const size_t sInlineBytes =
-        tl::Max<1, sInlineCapacity * ElemSize::result>::result;
+        tl::Max<1, sInlineCapacity * sizeof(T)>::result;
 
     /* member data */
 
diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp
index b03c6afa0990..603d76a59c88 100644
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -503,7 +503,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             analyze::Bytecode *opinfo = analysis->maybeCode(i);
             if (opinfo && opinfo->safePoint) {
                 Label L = jumpMap[i];
-                JS_ASSERT(L.isSet());
+                JS_ASSERT(L.isValid());
                 jitNmap[ix].bcOff = i;
                 jitNmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L));
                 ix++;
@@ -625,7 +625,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
     cursor += sizeof(ic::EqualityICInfo) * jit->nEqualityICs;
     for (size_t i = 0; i < jit->nEqualityICs; i++) {
         uint32 offs = uint32(equalityICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isSet());
+        JS_ASSERT(jumpMap[offs].isValid());
         jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]);
         jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry);
         jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall);
@@ -650,7 +650,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             continue;
 
         uint32 offs = uint32(traceICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isSet());
+        JS_ASSERT(jumpMap[offs].isValid());
         jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint);
         jitTraceICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]);
         jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
@@ -800,7 +800,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
 
     for (size_t i = 0; i < jumpTableOffsets.length(); i++) {
         uint32 offset = jumpTableOffsets[i];
-        JS_ASSERT(jumpMap[offset].isSet());
+        JS_ASSERT(jumpMap[offset].isValid());
         jumpVec[i] = (void *)(result + masm.distanceOf(jumpMap[offset]));
     }
 
@@ -2089,7 +2089,7 @@ JSC::MacroAssembler::Label
 mjit::Compiler::labelOf(jsbytecode *pc)
 {
     uint32 offs = uint32(pc - script->code);
-    JS_ASSERT(jumpMap[offs].isSet());
+    JS_ASSERT(jumpMap[offs].isValid());
     return jumpMap[offs];
 }
 
diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp
index b55b0dba48a5..bd738b92ba2b 100644
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -846,7 +846,12 @@ static inline void Destroy(T &t)
 
 mjit::JITScript::~JITScript()
 {
-    code.release();
+#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) 
+    void *addr = code.m_code.executableAddress();
+    memset(addr, 0xcc, code.m_size);
+#endif
+
+    code.m_executablePool->release();
 
 #if defined JS_POLYIC
     ic::GetElementIC *getElems_ = getElems();
diff --git a/js/src/methodjit/TrampolineCompiler.cpp b/js/src/methodjit/TrampolineCompiler.cpp
index 77bb148ba311..a6ac9d709f0e 100644
--- a/js/src/methodjit/TrampolineCompiler.cpp
+++ b/js/src/methodjit/TrampolineCompiler.cpp
@@ -93,7 +93,7 @@ TrampolineCompiler::compileTrampoline(Trampolines::TrampolinePtr *where,
 
     Label entry = masm.label();
     CHECK_RESULT(generator(masm));
-    JS_ASSERT(entry.isSet());
+    JS_ASSERT(entry.isValid());
 
     bool ok;
     JSC::LinkBuffer buffer(&masm, execAlloc, poolp, &ok);
diff --git a/js/src/yarr/BumpPointerAllocator.h b/js/src/yarr/BumpPointerAllocator.h
deleted file mode 100644
index 8ef5a780f9d8..000000000000
--- a/js/src/yarr/BumpPointerAllocator.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/* -*- 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) 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef BumpPointerAllocator_h
-#define BumpPointerAllocator_h
-
-#include "PageAllocation.h"
-
-namespace WTF {
-
-#define MINIMUM_BUMP_POOL_SIZE 0x1000
-
-class BumpPointerPool {
-public:
-    // ensureCapacity will check whether the current pool has capacity to
-    // allocate 'size' bytes of memory  If it does not, it will attempt to
-    // allocate a new pool (which will be added to this one in a chain).
-    //
-    // If allocation fails (out of memory) this method will return null.
-    // If the return value is non-null, then callers should update any
-    // references they have to this current (possibly full) BumpPointerPool
-    // to instead point to the newly returned BumpPointerPool.
-    BumpPointerPool* ensureCapacity(size_t size)
-    {
-        void* allocationEnd = static_cast(m_current) + size;
-        ASSERT(allocationEnd > m_current); // check for overflow
-        if (allocationEnd <= static_cast(this))
-            return this;
-        return ensureCapacityCrossPool(this, size);
-    }
-
-    // alloc should only be called after calling ensureCapacity; as such
-    // alloc will never fail.
-    void* alloc(size_t size)
-    {
-        void* current = m_current;
-        void* allocationEnd = static_cast(current) + size;
-        ASSERT(allocationEnd > current); // check for overflow
-        ASSERT(allocationEnd <= static_cast(this));
-        m_current = allocationEnd;
-        return current;
-    }
-
-    // The dealloc method releases memory allocated using alloc.  Memory
-    // must be released in a LIFO fashion, e.g. if the client calls alloc
-    // four times, returning pointer A, B, C, D, then the only valid order
-    // in which these may be deallocaed is D, C, B, A.
-    //
-    // The client may optionally skip some deallocations.  In the example
-    // above, it would be valid to only explicitly dealloc C, A (D being
-    // dealloced along with C, B along with A).
-    //
-    // If pointer was not allocated from this pool (or pools) then dealloc
-    // will CRASH().  Callers should update any references they have to
-    // this current BumpPointerPool to instead point to the returned
-    // BumpPointerPool.
-    BumpPointerPool* dealloc(void* position)
-    {
-        if ((position >= m_start) && (position <= static_cast(this))) {
-            ASSERT(position <= m_current);
-            m_current = position;
-            return this;
-        }
-        return deallocCrossPool(this, position);
-    }
-
-private:
-    // Placement operator new, returns the last 'size' bytes of allocation for use as this.
-    void* operator new(size_t size, const PageAllocation& allocation)
-    {
-        ASSERT(size < allocation.size());
-        return reinterpret_cast(reinterpret_cast(allocation.base()) + allocation.size()) - size;
-    }
-
-    BumpPointerPool(const PageAllocation& allocation)
-        : m_current(allocation.base())
-        , m_start(allocation.base())
-        , m_next(0)
-        , m_previous(0)
-        , m_allocation(allocation)
-    {
-    }
-
-    static BumpPointerPool* create(size_t minimumCapacity = 0)
-    {
-        // Add size of BumpPointerPool object, check for overflow.
-        minimumCapacity += sizeof(BumpPointerPool);
-        if (minimumCapacity < sizeof(BumpPointerPool))
-            return 0;
-
-        size_t poolSize = MINIMUM_BUMP_POOL_SIZE;
-        while (poolSize < minimumCapacity) {
-            poolSize <<= 1;
-            // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2!
-            ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1)));
-            if (!poolSize)
-                return 0;
-        }
-
-        PageAllocation allocation = PageAllocation::allocate(poolSize);
-        if (!!allocation)
-            return new(allocation) BumpPointerPool(allocation);
-        return 0;
-    }
-
-    void shrink()
-    {
-        ASSERT(!m_previous);
-        m_current = m_start;
-        while (m_next) {
-            BumpPointerPool* nextNext = m_next->m_next;
-            m_next->destroy();
-            m_next = nextNext;
-        }
-    }
-
-    void destroy()
-    {
-        m_allocation.deallocate();
-    }
-
-    static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size)
-    {
-        // The pool passed should not have capacity, so we'll start with the next one.
-        ASSERT(previousPool);
-        ASSERT((static_cast(previousPool->m_current) + size) > previousPool->m_current); // check for overflow
-        ASSERT((static_cast(previousPool->m_current) + size) > static_cast(previousPool));
-        BumpPointerPool* pool = previousPool->m_next;
-
-        while (true) {
-            if (!pool) {
-                // We've run to the end; allocate a new pool.
-                pool = BumpPointerPool::create(size);
-                previousPool->m_next = pool;
-                pool->m_previous = previousPool;
-                return pool;
-            }
-
-            // 
-            void* current = pool->m_current;
-            void* allocationEnd = static_cast(current) + size;
-            ASSERT(allocationEnd > current); // check for overflow
-            if (allocationEnd <= static_cast(pool))
-                return pool;
-        }
-    }
-
-    static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position)
-    {
-        // Should only be called if position is not in the current pool.
-        ASSERT((position < pool->m_start) || (position > static_cast(pool)));
-
-        while (true) {
-            // Unwind the current pool to the start, move back in the chain to the previous pool.
-            pool->m_current = pool->m_start;
-            pool = pool->m_previous;
-
-            // position was nowhere in the chain!
-            if (!pool)
-                CRASH();
-
-            if ((position >= pool->m_start) && (position <= static_cast(pool))) {
-                ASSERT(position <= pool->m_current);
-                pool->m_current = position;
-                return pool;
-            }
-        }
-    }
-
-    void* m_current;
-    void* m_start;
-    BumpPointerPool* m_next;
-    BumpPointerPool* m_previous;
-    PageAllocation m_allocation;
-
-    friend class BumpPointerAllocator;
-};
-
-// A BumpPointerAllocator manages a set of BumpPointerPool objects, which
-// can be used for LIFO (stack like) allocation.
-//
-// To begin allocating using this class call startAllocator().  The result
-// of this method will be null if the initial pool allocation fails, or a
-// pointer to a BumpPointerPool object that can be used to perform
-// allocations.  Whilst running no memory will be released until
-// stopAllocator() is called.  At this point all allocations made through
-// this allocator will be reaped, and underlying memory may be freed.
-//
-// (In practice we will still hold on to the initial pool to allow allocation
-// to be quickly restared, but aditional pools will be freed).
-//
-// This allocator is non-renetrant, it is encumbant on the clients to ensure
-// startAllocator() is not called again until stopAllocator() has been called.
-class BumpPointerAllocator {
-public:
-    BumpPointerAllocator()
-        : m_head(0)
-    {
-    }
-
-    ~BumpPointerAllocator()
-    {
-        if (m_head)
-            m_head->destroy();
-    }
-
-    BumpPointerPool* startAllocator()
-    {
-        if (!m_head)
-            m_head = BumpPointerPool::create();
-        return m_head;
-    }
-
-    void stopAllocator()
-    {
-        if (m_head)
-            m_head->shrink();
-    }
-
-private:
-    BumpPointerPool* m_head;
-};
-
-}
-
-using WTF::BumpPointerAllocator;
-
-#endif // BumpPointerAllocator_h
diff --git a/js/src/yarr/Makefile b/js/src/yarr/Makefile
new file mode 100644
index 000000000000..c824cdb96b6c
--- /dev/null
+++ b/js/src/yarr/Makefile
@@ -0,0 +1,5 @@
+INCLUDES := -I. -Iyarr -Iwtf -I../assembler/assembler -I../assembler
+
+all: 
+	$(CXX) -g3 -c $(INCLUDES) yarr/*.cpp
+	$(CXX) -g3 $(INCLUDES) TestMain.cpp *.o
diff --git a/js/src/yarr/OSAllocator.h b/js/src/yarr/OSAllocator.h
deleted file mode 100644
index ecfdc3b042ec..000000000000
--- a/js/src/yarr/OSAllocator.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef OSAllocator_h
-#define OSAllocator_h
-
-#include 
-#include "wtfbridge.h"
-#include "assembler/wtf/VMTags.h"
-#include "assembler/wtf/Assertions.h"
-
-namespace WTF {
-
-class OSAllocator {
-public:
-    enum Usage {
-        UnknownUsage = -1,
-        FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY,
-        JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY,
-        JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY,
-        JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY
-    };
-
-    // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state,
-    // releaseDecommitted should be called on a region of VM allocated by a single reservation,
-    // the memory must all currently be in a decommitted state.
-    static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void releaseDecommitted(void*, size_t);
-
-    // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should
-    // never be accessed, since the OS may not have attached physical memory for these regions).
-    // Clients should only call commit on uncommitted regions and decommit on committed regions.
-    static void commit(void*, size_t, bool writable, bool executable);
-    static void decommit(void*, size_t);
-
-    // These methods are symmetric; reserveAndCommit allocates VM in an committed state,
-    // decommitAndRelease should be called on a region of VM allocated by a single reservation,
-    // the memory must all currently be in a committed state.
-    static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void decommitAndRelease(void* base, size_t size);
-
-    // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than
-    // committing/decommitting the entire region additional parameters allow a subregion to be
-    // specified.
-    static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize);
-};
-
-inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable)
-{
-    void* base = reserveUncommitted(reserveSize, usage, writable, executable);
-    commit(base, commitSize, writable, executable);
-    return base;
-}
-
-inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize)
-{
-    ASSERT(decommitBase >= releaseBase && (static_cast(decommitBase) + decommitSize) <= (static_cast(releaseBase) + releaseSize));
-#if WTF_OS_WINCE || WTF_OS_SYMBIAN
-    // On most platforms we can actually skip this final decommit; releasing the VM will
-    // implicitly decommit any physical memory in the region. This is not true on WINCE.
-    // On Symbian, this makes implementation simpler and better aligned with the RChunk API
-    decommit(decommitBase, decommitSize);
-#endif
-    releaseDecommitted(releaseBase, releaseSize);
-}
-
-inline void OSAllocator::decommitAndRelease(void* base, size_t size)
-{
-    decommitAndRelease(base, size, base, size);
-}
-
-} // namespace WTF
-
-using WTF::OSAllocator;
-
-#endif // OSAllocator_h
diff --git a/js/src/yarr/OSAllocatorPosix.cpp b/js/src/yarr/OSAllocatorPosix.cpp
deleted file mode 100644
index 57c240b22fe5..000000000000
--- a/js/src/yarr/OSAllocatorPosix.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
-
-#include "OSAllocator.h"
-
-#include 
-#include 
-#include "wtf/Assertions.h"
-
-namespace WTF {
-
-void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
-{
-    void* result = reserveAndCommit(bytes, usage, writable, executable);
-#if HAVE_MADV_FREE_REUSE
-    // To support the "reserve then commit" model, we have to initially decommit.
-    while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
-#endif
-    return result;
-}
-
-void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable)
-{
-    // All POSIX reservations start out logically committed.
-    int protection = PROT_READ;
-    if (writable)
-        protection |= PROT_WRITE;
-    if (executable)
-        protection |= PROT_EXEC;
-
-    int flags = MAP_PRIVATE | MAP_ANON;
-
-#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER)
-    int fd = usage;
-#else
-    int fd = -1;
-#endif
-
-    void* result = 0;
-#if (WTF_OS_DARWIN && WTF_CPU_X86_64)
-    if (executable) {
-        // Cook up an address to allocate at, using the following recipe:
-        //   17 bits of zero, stay in userspace kids.
-        //   26 bits of randomness for ASLR.
-        //   21 bits of zero, at least stay aligned within one level of the pagetables.
-        //
-        // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
-        // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus
-        // 2^24, which should put up somewhere in the middle of userspace (in the address range
-        // 0x200000000000 .. 0x5fffffffffff).
-        intptr_t randomLocation = 0;
-        randomLocation = arc4random() & ((1 << 25) - 1);
-        randomLocation += (1 << 24);
-        randomLocation <<= 21;
-        result = reinterpret_cast(randomLocation);
-    }
-#endif
-
-    result = mmap(result, bytes, protection, flags, fd, 0);
-    if (result == MAP_FAILED)
-        CRASH();
-    return result;
-}
-
-void OSAllocator::commit(void* address, size_t bytes, bool, bool)
-{
-#if HAVE_MADV_FREE_REUSE
-    while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
-#else
-    // Non-MADV_FREE_REUSE reservations automatically commit on demand.
-    UNUSED_PARAM(address);
-    UNUSED_PARAM(bytes);
-#endif
-}
-
-void OSAllocator::decommit(void* address, size_t bytes)
-{
-#if HAVE_MADV_FREE_REUSE
-    while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
-#elif HAVE_MADV_FREE
-    while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { }
-#elif HAVE_MADV_DONTNEED
-    while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
-#else
-    UNUSED_PARAM(address);
-    UNUSED_PARAM(bytes);
-#endif
-}
-
-void OSAllocator::releaseDecommitted(void* address, size_t bytes)
-{
-    int result = munmap(address, bytes);
-    if (result == -1)
-        CRASH();
-}
-
-} // namespace WTF
-
-#endif
diff --git a/js/src/yarr/OSAllocatorWin.cpp b/js/src/yarr/OSAllocatorWin.cpp
deleted file mode 100644
index 08df9e98aefb..000000000000
--- a/js/src/yarr/OSAllocatorWin.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
-
-#include "windows.h"
-#include "wtf/Assertions.h"
-
-#include "OSAllocator.h"
-
-namespace WTF {
-
-static inline DWORD protection(bool writable, bool executable)
-{
-    return executable ?
-        (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) :
-        (writable ? PAGE_READWRITE : PAGE_READONLY);
-}
-
-void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable));
-    if (!result)
-        CRASH();
-    return result;
-}
-
-void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable));
-    if (!result)
-        CRASH();
-    return result;
-}
-
-void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable));
-    if (!result)
-        CRASH();
-}
-
-void OSAllocator::decommit(void* address, size_t bytes)
-{
-    bool result = VirtualFree(address, bytes, MEM_DECOMMIT);
-    if (!result)
-        CRASH();
-}
-
-void OSAllocator::releaseDecommitted(void* address, size_t bytes)
-{
-    // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx,
-    // dwSize must be 0 if dwFreeType is MEM_RELEASE.
-    bool result = VirtualFree(address, 0, MEM_RELEASE);
-    if (!result)
-        CRASH();
-}
-
-} // namespace WTF
-
-#endif
diff --git a/js/src/yarr/PageAllocation.h b/js/src/yarr/PageAllocation.h
deleted file mode 100644
index a86f37116e50..000000000000
--- a/js/src/yarr/PageAllocation.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- 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) 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PageAllocation_h
-#define PageAllocation_h
-
-#include "wtfbridge.h"
-#include "OSAllocator.h"
-#include "PageBlock.h"
-#include "assembler/wtf/VMTags.h"
-
-#if WTF_OS_DARWIN
-#include 
-#include 
-#endif
-
-#if WTF_OS_HAIKU
-#include 
-#endif
-
-#if WTF_OS_WINDOWS
-#include 
-#include 
-#endif
-
-#if WTF_OS_SYMBIAN
-#include 
-#include 
-#endif
-
-#if WTF_HAVE_ERRNO_H
-#include 
-#endif
-
-#if WTF_HAVE_MMAP
-#include 
-#include 
-#endif
-
-namespace WTF {
-
-/*
-    PageAllocation
-
-    The PageAllocation class provides a cross-platform memory allocation interface
-    with similar capabilities to posix mmap/munmap.  Memory is allocated by calling
-    PageAllocation::allocate, and deallocated by calling deallocate on the
-    PageAllocation object.  The PageAllocation holds the allocation's base pointer
-    and size.
-
-    The allocate method is passed the size required (which must be a multiple of
-    the system page size, which can be accessed using PageAllocation::pageSize).
-    Callers may also optinally provide a flag indicating the usage (for use by
-    system memory usage tracking tools, where implemented), and boolean values
-    specifying the required protection (defaulting to writable, non-executable).
-*/
-
-class PageAllocation : private PageBlock {
-public:
-    PageAllocation()
-    {
-    }
-
-    using PageBlock::size;
-    using PageBlock::base;
-
-#ifndef __clang__
-    using PageBlock::operator bool;
-#else
-    // FIXME: This is a workaround for , wherein Clang incorrectly emits an access
-    // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
-    operator bool() const { return PageBlock::operator bool(); }
-#endif
-
-    static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
-    {
-        ASSERT(isPageAligned(size));
-        return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size);
-    }
-
-    void deallocate()
-    {
-        // Clear base & size before calling release; if this is *inside* allocation
-        // then we won't be able to clear then after deallocating the memory.
-        PageAllocation tmp;
-        JSC::std::swap(tmp, *this);
-
-        ASSERT(tmp);
-        ASSERT(!*this);
-
-        OSAllocator::decommitAndRelease(tmp.base(), tmp.size());
-    }
-
-private:
-    PageAllocation(void* base, size_t size)
-        : PageBlock(base, size)
-    {
-    }
-};
-
-} // namespace WTF
-
-using WTF::PageAllocation;
-
-#endif // PageAllocation_h
diff --git a/js/src/yarr/PageBlock.cpp b/js/src/yarr/PageBlock.cpp
deleted file mode 100644
index 0f435b772860..000000000000
--- a/js/src/yarr/PageBlock.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "PageBlock.h"
-#include "wtf/Assertions.h"
-
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
-#include 
-#endif
-
-#if WTF_OS_WINDOWS
-#include 
-#include 
-#endif
-
-#if WTF_OS_SYMBIAN
-#include 
-#include 
-#endif
-
-namespace WTF {
-
-static size_t s_pageSize;
-
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
-
-inline size_t systemPageSize()
-{
-    return getpagesize();
-}
-
-#elif WTF_OS_WINDOWS
-
-inline size_t systemPageSize()
-{
-    static size_t size = 0;
-    SYSTEM_INFO system_info;
-    GetSystemInfo(&system_info);
-    size = system_info.dwPageSize;
-    return size;
-}
-
-#elif WTF_OS_SYMBIAN
-
-inline size_t systemPageSize()
-{
-    static TInt page_size = 0;
-    UserHal::PageSizeInBytes(page_size);
-    return page_size;
-}
-
-#endif
-
-size_t pageSize()
-{
-    if (!s_pageSize)
-        s_pageSize = systemPageSize();
-    ASSERT(isPowerOfTwo(s_pageSize));
-    return s_pageSize;
-}
-
-} // namespace WTF
diff --git a/js/src/yarr/PageBlock.h b/js/src/yarr/PageBlock.h
deleted file mode 100644
index 33751315e049..000000000000
--- a/js/src/yarr/PageBlock.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PageBlock_h
-#define PageBlock_h
-
-#include 
-#include "jsstdint.h"
-#include "assembler/wtf/Platform.h"
-
-namespace WTF {
-
-size_t pageSize();
-inline bool isPageAligned(void* address) { return !(reinterpret_cast(address) & (pageSize() - 1)); }
-inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
-inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
-
-class PageBlock {
-public:
-    PageBlock();
-    PageBlock(const PageBlock&);
-    PageBlock(void*, size_t);
-    
-    void* base() const { return m_base; }
-    size_t size() const { return m_size; }
-
-    operator bool() const { return !!m_base; }
-
-    bool contains(void* containedBase, size_t containedSize)
-    {
-        return containedBase >= m_base
-            && (static_cast(containedBase) + containedSize) <= (static_cast(m_base) + m_size);
-    }
-
-private:
-    void* m_base;
-    size_t m_size;
-};
-
-inline PageBlock::PageBlock()
-    : m_base(0)
-    , m_size(0)
-{
-}
-
-inline PageBlock::PageBlock(const PageBlock& other)
-    : m_base(other.m_base)
-    , m_size(other.m_size)
-{
-}
-
-inline PageBlock::PageBlock(void* base, size_t size)
-    : m_base(base)
-    , m_size(size)
-{
-}
-
-} // namespace WTF
-
-using WTF::pageSize;
-using WTF::isPageAligned;
-using WTF::isPageAligned;
-using WTF::isPowerOfTwo;
-
-#endif // PageBlock_h
diff --git a/js/src/yarr/VMTags.h b/js/src/yarr/VMTags.h
deleted file mode 100644
index fe6a006d3601..000000000000
--- a/js/src/yarr/VMTags.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2009 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 VMTags_h
-#define VMTags_h
-
-// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map
-// in order to aid tools that inspect system memory use. 
-#if WTF_OS_DARWIN
-
-#include 
-
-#if !defined(TARGETING_TIGER)
-
-#if defined(VM_MEMORY_TCMALLOC)
-#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
-#else
-#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53)
-#endif // defined(VM_MEMORY_TCMALLOC)
-
-#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-#else
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64)
-#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-
-#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-#else
-#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65)
-#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-
-#else // !defined(TARGETING_TIGER)
-
-// mmap on Tiger fails with tags that work on Leopard, so fall
-// back to Tiger-compatible tags (that also work on Leopard)
-// when targeting Tiger.
-#define VM_TAG_FOR_TCMALLOC_MEMORY -1
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
-#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
-
-#endif // !defined(TARGETING_TIGER)
-
-// Tags for vm_map and vm_allocate work on both Tiger and Leopard.
-
-#if defined(VM_MEMORY_JAVASCRIPT_CORE)
-#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE)
-#else
-#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63)
-#endif // defined(VM_MEMORY_JAVASCRIPT_CORE)
-
-#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-#else
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69)
-#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-
-#else // OS(DARWIN)
-
-#define VM_TAG_FOR_TCMALLOC_MEMORY -1
-#define VM_TAG_FOR_COLLECTOR_MEMORY -1
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
-#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1
-
-#endif // OS(DARWIN)
-
-#endif // VMTags_h
diff --git a/js/src/yarr/Yarr.h b/js/src/yarr/Yarr.h
deleted file mode 100644
index 40ebcca096af..000000000000
--- a/js/src/yarr/Yarr.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- 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.
- *
- * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef Yarr_h
-#define Yarr_h
-
-#include 
-
-#include "YarrInterpreter.h"
-#include "YarrPattern.h"
-
-namespace JSC { namespace Yarr {
-
-#define YarrStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoBackReference 2
-#define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
-#define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1
-#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1
-#define YarrStackSpaceForBackTrackInfoParentheses 2
-
-static const unsigned quantifyInfinite = UINT_MAX;
-
-// The below limit restricts the number of "recursive" match calls in order to
-// avoid spending exponential time on complex regular expressions.
-static const unsigned matchLimit = 1000000;
-
-enum JSRegExpResult {
-    JSRegExpMatch = 1,
-    JSRegExpNoMatch = 0,
-    JSRegExpErrorNoMatch = -1,
-    JSRegExpErrorHitLimit = -2,
-    JSRegExpErrorNoMemory = -3,
-    JSRegExpErrorInternal = -4
-};
-
-PassOwnPtr byteCompile(YarrPattern&, BumpPointerAllocator*);
-int interpret(BytecodePattern*, const UChar* input, unsigned start, unsigned length, int* output);
-
-} } // namespace JSC::Yarr
-
-#endif // Yarr_h
-
diff --git a/js/src/yarr/YarrInterpreter.cpp b/js/src/yarr/YarrInterpreter.cpp
deleted file mode 100644
index 2be8240efe60..000000000000
--- a/js/src/yarr/YarrInterpreter.cpp
+++ /dev/null
@@ -1,1914 +0,0 @@
-/* -*- 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
- *
- * 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "YarrInterpreter.h"
-
-#include "Yarr.h"
-#include "BumpPointerAllocator.h"
-
-#ifndef NDEBUG
-#include 
-#endif
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-class Interpreter {
-public:
-    struct ParenthesesDisjunctionContext;
-
-    struct BackTrackInfoPatternCharacter {
-        uintptr_t matchAmount;
-    };
-    struct BackTrackInfoCharacterClass {
-        uintptr_t matchAmount;
-    };
-    struct BackTrackInfoBackReference {
-        uintptr_t begin; // Not really needed for greedy quantifiers.
-        uintptr_t matchAmount; // Not really needed for fixed quantifiers.
-    };
-    struct BackTrackInfoAlternative {
-        uintptr_t offset;
-    };
-    struct BackTrackInfoParentheticalAssertion {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParenthesesOnce {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParenthesesTerminal {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParentheses {
-        uintptr_t matchAmount;
-        ParenthesesDisjunctionContext* lastContext;
-    };
-
-    static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context)
-    {
-        context->next = backTrack->lastContext;
-        backTrack->lastContext = context;
-        ++backTrack->matchAmount;
-    }
-
-    static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack)
-    {
-        ASSERT(backTrack->matchAmount);
-        ASSERT(backTrack->lastContext);
-        backTrack->lastContext = backTrack->lastContext->next;
-        --backTrack->matchAmount;
-    }
-
-    struct DisjunctionContext
-    {
-        DisjunctionContext()
-            : term(0)
-        {
-        }
-
-        void* operator new(size_t, void* where)
-        {
-            return where;
-        }
-
-        int term;
-        unsigned matchBegin;
-        unsigned matchEnd;
-        uintptr_t frame[1];
-    };
-
-    DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction)
-    {
-        size_t size = sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
-        allocatorPool = allocatorPool->ensureCapacity(size);
-        if (!allocatorPool)
-            CRASH();
-        return new(allocatorPool->alloc(size)) DisjunctionContext();
-    }
-
-    void freeDisjunctionContext(DisjunctionContext* context)
-    {
-        allocatorPool = allocatorPool->dealloc(context);
-    }
-
-    struct ParenthesesDisjunctionContext
-    {
-        ParenthesesDisjunctionContext(int* output, ByteTerm& term)
-            : next(0)
-        {
-            unsigned firstSubpatternId = term.atom.subpatternId;
-            unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns;
-
-            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) {
-                subpatternBackup[i] = output[(firstSubpatternId << 1) + i];
-                output[(firstSubpatternId << 1) + i] = -1;
-            }
-
-            new(getDisjunctionContext(term)) DisjunctionContext();
-        }
-
-        void* operator new(size_t, void* where)
-        {
-            return where;
-        }
-
-        void restoreOutput(int* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns)
-        {
-            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i)
-                output[(firstSubpatternId << 1) + i] = subpatternBackup[i];
-        }
-
-        DisjunctionContext* getDisjunctionContext(ByteTerm& term)
-        {
-            return reinterpret_cast(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1]));
-        }
-
-        ParenthesesDisjunctionContext* next;
-        int subpatternBackup[1];
-    };
-
-    ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, int* output, ByteTerm& term)
-    {
-        size_t size = sizeof(ParenthesesDisjunctionContext) - sizeof(int) + (term.atom.parenthesesDisjunction->m_numSubpatterns << 1) * sizeof(int) + sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
-        allocatorPool = allocatorPool->ensureCapacity(size);
-        if (!allocatorPool)
-            CRASH();
-        return new(allocatorPool->alloc(size)) ParenthesesDisjunctionContext(output, term);
-    }
-
-    void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context)
-    {
-        allocatorPool = allocatorPool->dealloc(context);
-    }
-
-    class InputStream {
-    public:
-        InputStream(const UChar* input, unsigned start, unsigned length)
-            : input(input)
-            , pos(start)
-            , length(length)
-        {
-        }
-
-        void next()
-        {
-            ++pos;
-        }
-
-        void rewind(unsigned amount)
-        {
-            ASSERT(pos >= amount);
-            pos -= amount;
-        }
-
-        int read()
-        {
-            ASSERT(pos < length);
-            if (pos < length)
-                return input[pos];
-            return -1;
-        }
-
-        int readPair()
-        {
-            ASSERT(pos + 1 < length);
-            return input[pos] | input[pos + 1] << 16;
-        }
-
-        int readChecked(int position)
-        {
-            ASSERT(position < 0);
-            ASSERT(static_cast(-position) <= pos);
-            unsigned p = pos + position;
-            ASSERT(p < length);
-            return input[p];
-        }
-
-        int reread(unsigned from)
-        {
-            ASSERT(from < length);
-            return input[from];
-        }
-
-        int prev()
-        {
-            ASSERT(!(pos > length));
-            if (pos && length)
-                return input[pos - 1];
-            return -1;
-        }
-
-        unsigned getPos()
-        {
-            return pos;
-        }
-
-        void setPos(unsigned p)
-        {
-            pos = p;
-        }
-
-        bool atStart()
-        {
-            return pos == 0;
-        }
-
-        bool atEnd()
-        {
-            return pos == length;
-        }
-
-        bool checkInput(int count)
-        {
-            if ((pos + count) <= length) {
-                pos += count;
-                return true;
-            }
-            return false;
-        }
-
-        void uncheckInput(int count)
-        {
-            pos -= count;
-        }
-
-        bool atStart(int position)
-        {
-            return (pos + position) == 0;
-        }
-
-        bool atEnd(int position)
-        {
-            return (pos + position) == length;
-        }
-
-        bool isNotAvailableInput(int position)
-        {
-            return (pos + position) > length;
-        }
-
-    private:
-        const UChar* input;
-        unsigned pos;
-        unsigned length;
-    };
-
-    bool testCharacterClass(CharacterClass* characterClass, int ch)
-    {
-        if (ch & 0xFF80) {
-            for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i)
-                if (ch == characterClass->m_matchesUnicode[i])
-                    return true;
-            for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i)
-                if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end))
-                    return true;
-        } else {
-            for (unsigned i = 0; i < characterClass->m_matches.size(); ++i)
-                if (ch == characterClass->m_matches[i])
-                    return true;
-            for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i)
-                if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end))
-                    return true;
-        }
-
-        return false;
-    }
-
-    bool checkCharacter(int testChar, int inputPosition)
-    {
-        return testChar == input.readChecked(inputPosition);
-    }
-
-    bool checkCasedCharacter(int loChar, int hiChar, int inputPosition)
-    {
-        int ch = input.readChecked(inputPosition);
-        return (loChar == ch) || (hiChar == ch);
-    }
-
-    bool checkCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition)
-    {
-        bool match = testCharacterClass(characterClass, input.readChecked(inputPosition));
-        return invert ? !match : match;
-    }
-
-    bool tryConsumeBackReference(int matchBegin, int matchEnd, int inputOffset)
-    {
-        int matchSize = matchEnd - matchBegin;
-
-        if (!input.checkInput(matchSize))
-            return false;
-
-        if (pattern->m_ignoreCase) {
-            for (int i = 0; i < matchSize; ++i) {
-                int ch = input.reread(matchBegin + i);
-
-                int lo = Unicode::toLower(ch);
-                int hi = Unicode::toUpper(ch);
-
-                if ((lo != hi) ? (!checkCasedCharacter(lo, hi, inputOffset - matchSize + i)) : (!checkCharacter(ch, inputOffset - matchSize + i))) {
-                    input.uncheckInput(matchSize);
-                    return false;
-                }
-            }
-        } else {
-            for (int i = 0; i < matchSize; ++i) {
-                if (!checkCharacter(input.reread(matchBegin + i), inputOffset - matchSize + i)) {
-                    input.uncheckInput(matchSize);
-                    return false;
-                }
-            }
-        }
-
-        return true;
-    }
-
-    bool matchAssertionBOL(ByteTerm& term)
-    {
-        return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition - 1)));
-    }
-
-    bool matchAssertionEOL(ByteTerm& term)
-    {
-        if (term.inputPosition)
-            return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition)));
-
-        return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read()));
-    }
-
-    bool matchAssertionWordBoundary(ByteTerm& term)
-    {
-        bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition - 1));
-        bool readIsWordchar;
-        if (term.inputPosition)
-            readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition));
-        else
-            readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read());
-
-        bool wordBoundary = prevIsWordchar != readIsWordchar;
-        return term.invert() ? !wordBoundary : wordBoundary;
-    }
-
-    bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context)
-    {
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCharacter(term.atom.patternCharacter, term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context)
-    {
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeCharacterClass);
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
-                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + matchAmount))
-                    return false;
-            }
-            return true;
-        }
-
-        case QuantifierGreedy: {
-            unsigned matchAmount = 0;
-            while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            return true;
-        }
-
-        case QuantifierNonGreedy:
-            backTrack->matchAmount = 0;
-            return true;
-        }
-
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeCharacterClass);
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchBackReference(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeBackReference);
-        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        int matchBegin = output[(term.atom.subpatternId << 1)];
-        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
-
-        // If the end position of the referenced match hasn't set yet then the backreference in the same parentheses where it references to that.
-        // In this case the result of match is empty string like when it references to a parentheses with zero-width match.
-        // Eg.: /(a\1)/
-        if (matchEnd == -1)
-            return true;
-
-        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
-
-        if (matchBegin == matchEnd)
-            return true;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            backTrack->begin = input.getPos();
-            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
-                if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
-                    input.setPos(backTrack->begin);
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        case QuantifierGreedy: {
-            unsigned matchAmount = 0;
-            while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
-                ++matchAmount;
-            backTrack->matchAmount = matchAmount;
-            return true;
-        }
-
-        case QuantifierNonGreedy:
-            backTrack->begin = input.getPos();
-            backTrack->matchAmount = 0;
-            return true;
-        }
-
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeBackReference);
-        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        int matchBegin = output[(term.atom.subpatternId << 1)];
-        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
-        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
-
-        if (matchBegin == matchEnd)
-            return false;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            // for quantityCount == 1, could rewind.
-            input.setPos(backTrack->begin);
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.rewind(matchEnd - matchBegin);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
-                ++backTrack->matchAmount;
-                return true;
-            }
-            input.setPos(backTrack->begin);
-            break;
-        }
-
-        return false;
-    }
-
-    void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context)
-    {
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition;
-            output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition;
-        }
-    }
-    void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context)
-    {
-        unsigned firstSubpatternId = term.atom.subpatternId;
-        unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns;
-        context->restoreOutput(output, firstSubpatternId, count);
-    }
-    JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack)
-    {
-        while (backTrack->matchAmount) {
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-
-            JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true);
-            if (result == JSRegExpMatch)
-                return JSRegExpMatch;
-
-            resetMatches(term, context);
-            popParenthesesDisjunctionContext(backTrack);
-            freeParenthesesDisjunctionContext(context);
-
-            if (result != JSRegExpNoMatch)
-                return result;
-        }
-
-        return JSRegExpNoMatch;
-    }
-
-    bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy: {
-            // set this speculatively; if we get to the parens end this will be true.
-            backTrack->begin = input.getPos();
-            break;
-        }
-        case QuantifierNonGreedy: {
-            backTrack->begin = notFound;
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        }
-        case QuantifierFixedCount:
-            break;
-        }
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = input.getPos() + term.inputPosition;
-        }
-
-        return true;
-    }
-
-    bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
-        }
-
-        if (term.atom.quantityType == QuantifierFixedCount)
-            return true;
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        return backTrack->begin != input.getPos();
-    }
-
-    bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = -1;
-            output[(subpatternId << 1) + 1] = -1;
-        }
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy:
-            // if we backtrack to this point, there is another chance - try matching nothing.
-            ASSERT(backTrack->begin != notFound);
-            backTrack->begin = notFound;
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        case QuantifierNonGreedy:
-            ASSERT(backTrack->begin != notFound);
-        case QuantifierFixedCount:
-            break;
-        }
-
-        return false;
-    }
-
-    bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy:
-            if (backTrack->begin == notFound) {
-                context->term -= term.atom.parenthesesWidth;
-                return false;
-            }
-        case QuantifierNonGreedy:
-            if (backTrack->begin == notFound) {
-                backTrack->begin = input.getPos();
-                if (term.capture()) {
-                    // Technically this access to inputPosition should be accessing the begin term's
-                    // inputPosition, but for repeats other than fixed these values should be
-                    // the same anyway! (We don't pre-check for greedy or non-greedy matches.)
-                    ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-                    ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition);
-                    unsigned subpatternId = term.atom.subpatternId;
-                    output[subpatternId << 1] = input.getPos() + term.inputPosition;
-                }
-                context->term -= term.atom.parenthesesWidth;
-                return true;
-            }
-        case QuantifierFixedCount:
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-        ASSERT(term.atom.quantityType == QuantifierGreedy);
-        ASSERT(term.atom.quantityCount == quantifyInfinite);
-        ASSERT(!term.capture());
-
-        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        backTrack->begin = input.getPos();
-        return true;
-    }
-
-    bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd);
-
-        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        // Empty match is a failed match.
-        if (backTrack->begin == input.getPos())
-            return false;
-
-        // Successful match! Okay, what's next? - loop around and try to match moar!
-        context->term -= (term.atom.parenthesesWidth + 1);
-        return true;
-    }
-
-    bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-        ASSERT(term.atom.quantityType == QuantifierGreedy);
-        ASSERT(term.atom.quantityCount == quantifyInfinite);
-        ASSERT(!term.capture());
-
-        // If we backtrack to this point, we have failed to match this iteration of the parens.
-        // Since this is greedy / zero minimum a failed is also accepted as a match!
-        context->term += term.atom.parenthesesWidth;
-        return true;
-    }
-
-    bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*)
-    {
-        // 'Terminal' parentheses are at the end of the regex, and as such a match past end
-        // should always be returned as a successful match - we should never backtrack to here.
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        backTrack->begin = input.getPos();
-        return true;
-    }
-
-    bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        input.setPos(backTrack->begin);
-
-        // We've reached the end of the parens; if they are inverted, this is failure.
-        if (term.invert()) {
-            context->term -= term.atom.parenthesesWidth;
-            return false;
-        }
-
-        return true;
-    }
-
-    bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        // We've failed to match parens; if they are inverted, this is win!
-        if (term.invert()) {
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        }
-
-        return false;
-    }
-
-    bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        input.setPos(backTrack->begin);
-
-        context->term -= term.atom.parenthesesWidth;
-        return false;
-    }
-
-    JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
-
-        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
-
-        backTrack->matchAmount = 0;
-        backTrack->lastContext = 0;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            // While we haven't yet reached our fixed limit,
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                // Try to do a match, and it it succeeds, add it to the list.
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    // The match failed; try to find an alternate point to carry on from.
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result == JSRegExpNoMatch) {
-                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
-                        if (backtrackResult != JSRegExpMatch)
-                            return backtrackResult;
-                    } else
-                        return result;
-                }
-            }
-
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-            recordParenthesesMatch(term, context);
-            return JSRegExpMatch;
-        }
-
-        case QuantifierGreedy: {
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result != JSRegExpNoMatch)
-                        return result;
-
-                    break;
-                }
-            }
-
-            if (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                recordParenthesesMatch(term, context);
-            }
-            return JSRegExpMatch;
-        }
-
-        case QuantifierNonGreedy:
-            return JSRegExpMatch;
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    // Rules for backtracking differ depending on whether this is greedy or non-greedy.
-    //
-    // Greedy matches never should try just adding more - you should already have done
-    // the 'more' cases.  Always backtrack, at least a leetle bit.  However cases where
-    // you backtrack an item off the list needs checking, since we'll never have matched
-    // the one less case.  Tracking forwards, still add as much as possible.
-    //
-    // Non-greedy, we've already done the one less case, so don't match on popping.
-    // We haven't done the one more case, so always try to add that.
-    //
-    JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
-
-        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-
-            ParenthesesDisjunctionContext* context = 0;
-            JSRegExpResult result = parenthesesDoBacktrack(term, backTrack);
-
-            if (result != JSRegExpMatch)
-                return result;
-
-            // While we haven't yet reached our fixed limit,
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                // Try to do a match, and it it succeeds, add it to the list.
-                context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    // The match failed; try to find an alternate point to carry on from.
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result == JSRegExpNoMatch) {
-                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
-                        if (backtrackResult != JSRegExpMatch)
-                            return backtrackResult;
-                    } else
-                        return result;
-                }
-            }
-
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-            context = backTrack->lastContext;
-            recordParenthesesMatch(term, context);
-            return JSRegExpMatch;
-        }
-
-        case QuantifierGreedy: {
-            if (!backTrack->matchAmount)
-                return JSRegExpNoMatch;
-
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-            JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
-            if (result == JSRegExpMatch) {
-                while (backTrack->matchAmount < term.atom.quantityCount) {
-                    ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                    JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                    if (parenthesesResult == JSRegExpMatch)
-                        appendParenthesesDisjunctionContext(backTrack, context);
-                    else {
-                        resetMatches(term, context);
-                        freeParenthesesDisjunctionContext(context);
-
-                        if (parenthesesResult != JSRegExpNoMatch)
-                            return parenthesesResult;
-
-                        break;
-                    }
-                }
-            } else {
-                resetMatches(term, context);
-                popParenthesesDisjunctionContext(backTrack);
-                freeParenthesesDisjunctionContext(context);
-
-                if (result != JSRegExpNoMatch)
-                    return result;
-            }
-
-            if (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                recordParenthesesMatch(term, context);
-            }
-            return JSRegExpMatch;
-        }
-
-        case QuantifierNonGreedy: {
-            // If we've not reached the limit, try to add one more match.
-            if (backTrack->matchAmount < term.atom.quantityCount) {
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch) {
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                    recordParenthesesMatch(term, context);
-                    return JSRegExpMatch;
-                }
-
-                resetMatches(term, context);
-                freeParenthesesDisjunctionContext(context);
-
-                if (result != JSRegExpNoMatch)
-                    return result;
-            }
-
-            // Nope - okay backtrack looking for an alternative.
-            while (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
-                if (result == JSRegExpMatch) {
-                    // successful backtrack! we're back in the game!
-                    if (backTrack->matchAmount) {
-                        context = backTrack->lastContext;
-                        recordParenthesesMatch(term, context);
-                    }
-                    return JSRegExpMatch;
-                }
-
-                // pop a match off the stack
-                resetMatches(term, context);
-                popParenthesesDisjunctionContext(backTrack);
-                freeParenthesesDisjunctionContext(context);
-
-                return result;
-            }
-
-            return JSRegExpNoMatch;
-        }
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    void lookupForBeginChars()
-    {
-        int character;
-        bool firstSingleCharFound;
-
-        while (true) {
-            if (input.isNotAvailableInput(2))
-                return;
-
-            firstSingleCharFound = false;
-
-            character = input.readPair();
-
-            for (unsigned i = 0; i < pattern->m_beginChars.size(); ++i) {
-                BeginChar bc = pattern->m_beginChars[i];
-
-                if (!firstSingleCharFound && bc.value <= 0xFFFF) {
-                    firstSingleCharFound = true;
-                    character &= 0xFFFF;
-                }
-
-                if ((character | bc.mask) == bc.value)
-                    return;
-            }
-
-            input.next();
-        }
-    }
-
-#define MATCH_NEXT() { ++context->term; goto matchAgain; }
-#define BACKTRACK() { --context->term; goto backtrack; }
-#define currentTerm() (disjunction->terms[context->term])
-    JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false, bool isBody = false)
-    {
-        if (!--remainingMatchCount)
-            return JSRegExpErrorHitLimit;
-
-        if (btrack)
-            BACKTRACK();
-
-        if (pattern->m_containsBeginChars && isBody)
-            lookupForBeginChars();
-
-        context->matchBegin = input.getPos();
-        context->term = 0;
-
-    matchAgain:
-        ASSERT(context->term < static_cast(disjunction->terms.size()));
-
-        switch (currentTerm().type) {
-        case ByteTerm::TypeSubpatternBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeSubpatternEnd:
-            context->matchEnd = input.getPos();
-            return JSRegExpMatch;
-
-        case ByteTerm::TypeBodyAlternativeBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeBodyAlternativeDisjunction:
-        case ByteTerm::TypeBodyAlternativeEnd:
-            context->matchEnd = input.getPos();
-            return JSRegExpMatch;
-
-        case ByteTerm::TypeAlternativeBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeAlternativeDisjunction:
-        case ByteTerm::TypeAlternativeEnd: {
-            int offset = currentTerm().alternative.end;
-            BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->offset = offset;
-            context->term += offset;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypeAssertionBOL:
-            if (matchAssertionBOL(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeAssertionEOL:
-            if (matchAssertionEOL(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeAssertionWordBoundary:
-            if (matchAssertionWordBoundary(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-
-        case ByteTerm::TypePatternCharacterOnce:
-        case ByteTerm::TypePatternCharacterFixed: {
-            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
-                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + matchAmount))
-                    BACKTRACK();
-            }
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCharacterGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            unsigned matchAmount = 0;
-            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCharacterNonGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->matchAmount = 0;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypePatternCasedCharacterOnce:
-        case ByteTerm::TypePatternCasedCharacterFixed: {
-            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
-                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + matchAmount))
-                    BACKTRACK();
-            }
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCasedCharacterGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            unsigned matchAmount = 0;
-            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCasedCharacterNonGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->matchAmount = 0;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypeCharacterClass:
-            if (matchCharacterClass(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeBackReference:
-            if (matchBackReference(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpattern: {
-            JSRegExpResult result = matchParentheses(currentTerm(), context);
-
-            if (result == JSRegExpMatch) {
-                MATCH_NEXT();
-            }  else if (result != JSRegExpNoMatch)
-                return result;
-
-            BACKTRACK();
-        }
-        case ByteTerm::TypeParenthesesSubpatternOnceBegin:
-            if (matchParenthesesOnceBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternOnceEnd:
-            if (matchParenthesesOnceEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
-            if (matchParenthesesTerminalBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
-            if (matchParenthesesTerminalEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParentheticalAssertionBegin:
-            if (matchParentheticalAssertionBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParentheticalAssertionEnd:
-            if (matchParentheticalAssertionEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-
-        case ByteTerm::TypeCheckInput:
-            if (input.checkInput(currentTerm().checkInputCount))
-                MATCH_NEXT();
-            BACKTRACK();
-
-            case ByteTerm::TypeUncheckInput:
-                input.uncheckInput(currentTerm().checkInputCount);
-                MATCH_NEXT();
-        }
-
-        // We should never fall-through to here.
-        ASSERT_NOT_REACHED();
-
-    backtrack:
-        ASSERT(context->term < static_cast(disjunction->terms.size()));
-
-        switch (currentTerm().type) {
-        case ByteTerm::TypeSubpatternBegin:
-            return JSRegExpNoMatch;
-        case ByteTerm::TypeSubpatternEnd:
-            ASSERT_NOT_REACHED();
-
-        case ByteTerm::TypeBodyAlternativeBegin:
-        case ByteTerm::TypeBodyAlternativeDisjunction: {
-            int offset = currentTerm().alternative.next;
-            context->term += offset;
-            if (offset > 0)
-                MATCH_NEXT();
-
-            if (input.atEnd())
-                return JSRegExpNoMatch;
-
-            input.next();
-
-            if (pattern->m_containsBeginChars && isBody)
-                lookupForBeginChars();
-
-            context->matchBegin = input.getPos();
-
-            if (currentTerm().alternative.onceThrough)
-                context->term += currentTerm().alternative.next;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypeBodyAlternativeEnd:
-            ASSERT_NOT_REACHED();
-
-            case ByteTerm::TypeAlternativeBegin:
-            case ByteTerm::TypeAlternativeDisjunction: {
-                int offset = currentTerm().alternative.next;
-                context->term += offset;
-                if (offset > 0)
-                    MATCH_NEXT();
-                BACKTRACK();
-            }
-            case ByteTerm::TypeAlternativeEnd: {
-                // We should never backtrack back into an alternative of the main body of the regex.
-                BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-                unsigned offset = backTrack->offset;
-                context->term -= offset;
-                BACKTRACK();
-            }
-
-            case ByteTerm::TypeAssertionBOL:
-            case ByteTerm::TypeAssertionEOL:
-            case ByteTerm::TypeAssertionWordBoundary:
-                BACKTRACK();
-
-            case ByteTerm::TypePatternCharacterOnce:
-            case ByteTerm::TypePatternCharacterFixed:
-            case ByteTerm::TypePatternCharacterGreedy:
-            case ByteTerm::TypePatternCharacterNonGreedy:
-                if (backtrackPatternCharacter(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypePatternCasedCharacterOnce:
-            case ByteTerm::TypePatternCasedCharacterFixed:
-            case ByteTerm::TypePatternCasedCharacterGreedy:
-            case ByteTerm::TypePatternCasedCharacterNonGreedy:
-                if (backtrackPatternCasedCharacter(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeCharacterClass:
-                if (backtrackCharacterClass(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeBackReference:
-                if (backtrackBackReference(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpattern: {
-                JSRegExpResult result = backtrackParentheses(currentTerm(), context);
-
-                if (result == JSRegExpMatch) {
-                    MATCH_NEXT();
-                } else if (result != JSRegExpNoMatch)
-                    return result;
-
-                BACKTRACK();
-            }
-            case ByteTerm::TypeParenthesesSubpatternOnceBegin:
-                if (backtrackParenthesesOnceBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternOnceEnd:
-                if (backtrackParenthesesOnceEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
-                if (backtrackParenthesesTerminalBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
-                if (backtrackParenthesesTerminalEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParentheticalAssertionBegin:
-                if (backtrackParentheticalAssertionBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParentheticalAssertionEnd:
-                if (backtrackParentheticalAssertionEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-
-            case ByteTerm::TypeCheckInput:
-                input.uncheckInput(currentTerm().checkInputCount);
-                BACKTRACK();
-
-            case ByteTerm::TypeUncheckInput:
-                input.checkInput(currentTerm().checkInputCount);
-                BACKTRACK();
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
-    {
-        JSRegExpResult result = matchDisjunction(disjunction, context, btrack);
-
-        if (result == JSRegExpMatch) {
-            while (context->matchBegin == context->matchEnd) {
-                result = matchDisjunction(disjunction, context, true);
-                if (result != JSRegExpMatch)
-                    return result;
-            }
-            return JSRegExpMatch;
-        }
-
-        return result;
-    }
-
-    int interpret()
-    {
-        allocatorPool = pattern->m_allocator->startAllocator();
-        if (!allocatorPool)
-            CRASH();
-
-        for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i)
-            output[i] = -1;
-
-        DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get());
-
-        JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false, true);
-        if (result == JSRegExpMatch) {
-            output[0] = context->matchBegin;
-            output[1] = context->matchEnd;
-        }
-
-        freeDisjunctionContext(context);
-
-        pattern->m_allocator->stopAllocator();
-
-        // RegExp.cpp currently expects all error to be converted to -1.
-        ASSERT((result == JSRegExpMatch) == (output[0] != -1));
-        return output[0];
-    }
-
-    Interpreter(BytecodePattern* pattern, int* output, const UChar* inputChar, unsigned start, unsigned length)
-        : pattern(pattern)
-        , output(output)
-        , input(inputChar, start, length)
-        , allocatorPool(0)
-        , remainingMatchCount(matchLimit)
-    {
-    }
-
-private:
-    BytecodePattern* pattern;
-    int* output;
-    InputStream input;
-    BumpPointerPool* allocatorPool;
-    unsigned remainingMatchCount;
-};
-
-
-
-class ByteCompiler {
-    struct ParenthesesStackEntry {
-        unsigned beginTerm;
-        unsigned savedAlternativeIndex;
-        // For js::Vector. Does not create a valid object.
-        ParenthesesStackEntry() {}
-        ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/)
-            : beginTerm(beginTerm)
-            , savedAlternativeIndex(savedAlternativeIndex)
-        {
-        }
-    };
-
-public:
-    ByteCompiler(YarrPattern& pattern)
-        : m_pattern(pattern)
-    {
-        m_currentAlternativeIndex = 0;
-    }
-
-    PassOwnPtr compile(BumpPointerAllocator* allocator)
-    {
-        regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough());
-        emitDisjunction(m_pattern.m_body);
-        regexEnd();
-
-        return adoptPtr(js::OffTheBooks::new_(m_bodyDisjunction.release(), m_allParenthesesInfo, m_pattern, allocator));
-    }
-
-    void checkInput(unsigned count)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count));
-    }
-
-    void uncheckInput(unsigned count)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::UncheckInput(count));
-    }
-    
-    void assertionBOL(int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition));
-    }
-
-    void assertionEOL(int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition));
-    }
-
-    void assertionWordBoundary(bool invert, int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition));
-    }
-
-    void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        if (m_pattern.m_ignoreCase) {
-            UChar lo = Unicode::toLower(ch);
-            UChar hi = Unicode::toUpper(ch);
-
-            if (lo != hi) {
-                m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType));
-                return;
-            }
-        }
-
-        m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType));
-    }
-
-    void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition));
-
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-    }
-
-    void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        ASSERT(subpatternId);
-
-        m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition));
-
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin,
-        // then fix this up at the end! - simplifying this should make it much clearer.
-        // https://bugs.webkit.org/show_bug.cgi?id=50136
-
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, false, invert, 0));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParentheticalAssertionEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin);
-
-        bool invert = m_bodyDisjunction->terms[beginTerm].invert();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, false, invert, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    unsigned popParenthesesStack()
-    {
-        ASSERT(m_parenthesesStack.size());
-        int stackEnd = m_parenthesesStack.size() - 1;
-        unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm;
-        m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex;
-        m_parenthesesStack.shrink(stackEnd);
-
-        ASSERT(beginTerm < m_bodyDisjunction->terms.size());
-        ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size());
-
-        return beginTerm;
-    }
-
-#ifndef NDEBUG
-    void dumpDisjunction(ByteDisjunction* disjunction)
-    {
-        printf("ByteDisjunction(%p):\n\t", disjunction);
-        for (unsigned i = 0; i < disjunction->terms.size(); ++i)
-            printf("{ %d } ", disjunction->terms[i].type);
-        printf("\n");
-    }
-#endif
-
-    void closeAlternative(int beginTerm)
-    {
-        int origBeginTerm = beginTerm;
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin);
-        int endIndex = m_bodyDisjunction->terms.size();
-
-        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
-
-        if (!m_bodyDisjunction->terms[beginTerm].alternative.next)
-            m_bodyDisjunction->terms.remove(beginTerm);
-        else {
-            while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
-                beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
-                ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction);
-                m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
-                m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-            }
-
-            m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
-
-            m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd());
-            m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
-        }
-    }
-
-    void closeBodyAlternative()
-    {
-        int beginTerm = 0;
-        int origBeginTerm = 0;
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin);
-        int endIndex = m_bodyDisjunction->terms.size();
-
-        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
-
-        while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
-            beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
-            ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction);
-            m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
-            m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-        }
-
-        m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
-
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd());
-        m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-
-        ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
-
-        bool capture = parenthesesBegin.capture();
-        unsigned subpatternId = parenthesesBegin.atom.subpatternId;
-
-        unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
-        ByteDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(numSubpatterns, callFrameSize);
-
-        parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
-        for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
-            parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
-        parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
-
-        m_bodyDisjunction->terms.shrink(beginTerm);
-
-        m_allParenthesesInfo.append(parenthesesDisjunction);
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, inputPosition));
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-
-        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-
-        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough)
-    {
-        m_bodyDisjunction = adoptPtr(js::OffTheBooks::new_(numSubpatterns, callFrameSize));
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough));
-        m_bodyDisjunction->terms[0].frameLocation = 0;
-        m_currentAlternativeIndex = 0;
-    }
-
-    void regexEnd()
-    {
-        closeBodyAlternative();
-    }
-
-    void alternativeBodyDisjunction(bool onceThrough)
-    {
-        int newAlternativeIndex = m_bodyDisjunction->terms.size();
-        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough));
-
-        m_currentAlternativeIndex = newAlternativeIndex;
-    }
-
-    void alternativeDisjunction()
-    {
-        int newAlternativeIndex = m_bodyDisjunction->terms.size();
-        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction());
-
-        m_currentAlternativeIndex = newAlternativeIndex;
-    }
-
-    void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0)
-    {
-        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
-            unsigned currentCountAlreadyChecked = inputCountAlreadyChecked;
-
-            PatternAlternative* alternative = disjunction->m_alternatives[alt];
-
-            if (alt) {
-                if (disjunction == m_pattern.m_body)
-                    alternativeBodyDisjunction(alternative->onceThrough());
-                else
-                    alternativeDisjunction();
-            }
-
-            unsigned minimumSize = alternative->m_minimumSize;
-            int countToCheck = minimumSize - parenthesesInputCountAlreadyChecked;
-
-            ASSERT(countToCheck >= 0);
-            if (countToCheck) {
-                checkInput(countToCheck);
-                currentCountAlreadyChecked += countToCheck;
-            }
-
-            for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
-                PatternTerm& term = alternative->m_terms[i];
-
-                switch (term.type) {
-                case PatternTerm::TypeAssertionBOL:
-                    assertionBOL(term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypeAssertionEOL:
-                    assertionEOL(term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypeAssertionWordBoundary:
-                    assertionWordBoundary(term.invert(), term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypePatternCharacter:
-                    atomPatternCharacter(term.patternCharacter, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                    break;
-
-                case PatternTerm::TypeCharacterClass:
-                    atomCharacterClass(term.characterClass, term.invert(), term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                    break;
-
-                case PatternTerm::TypeBackReference:
-                    atomBackReference(term.backReferenceSubpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                        break;
-
-                case PatternTerm::TypeForwardReference:
-                    break;
-
-                case PatternTerm::TypeParenthesesSubpattern: {
-                    unsigned disjunctionAlreadyCheckedCount = 0;
-                    if (term.quantityCount == 1 && !term.parentheses.isCopy) {
-                        unsigned alternativeFrameLocation = term.frameLocation;
-                        // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame.
-                        if (term.quantityType == QuantifierFixedCount)
-                            disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize;
-                        else
-                            alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, alternativeFrameLocation);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
-                        atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
-                    } else if (term.parentheses.isTerminal) {
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
-                        atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
-                    } else {
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
-                        atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
-                    }
-                    break;
-                }
-
-                case PatternTerm::TypeParentheticalAssertion: {
-                    unsigned alternativeFrameLocation = term.frameLocation + YarrStackSpaceForBackTrackInfoParentheticalAssertion;
-
-                    ASSERT(currentCountAlreadyChecked >= static_cast(term.inputPosition));
-                    int positiveInputOffset = currentCountAlreadyChecked - term.inputPosition;
-                    int uncheckAmount = positiveInputOffset - term.parentheses.disjunction->m_minimumSize;
-
-                    if (uncheckAmount > 0) {
-                        uncheckInput(uncheckAmount);
-                        currentCountAlreadyChecked -= uncheckAmount;
-                    } else
-                        uncheckAmount = 0;
-
-                    atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation);
-                    emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount);
-                    atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType);
-                    if (uncheckAmount) {
-                        checkInput(uncheckAmount);
-                        currentCountAlreadyChecked += uncheckAmount;
-                    }
-                    break;
-                }
-                }
-            }
-        }
-    }
-
-private:
-    YarrPattern& m_pattern;
-    OwnPtr m_bodyDisjunction;
-    unsigned m_currentAlternativeIndex;
-    Vector m_parenthesesStack;
-    Vector m_allParenthesesInfo;
-};
-
-PassOwnPtr byteCompile(YarrPattern& pattern, BumpPointerAllocator* allocator)
-{
-    return ByteCompiler(pattern).compile(allocator);
-}
-
-int interpret(BytecodePattern* bytecode, const UChar* input, unsigned start, unsigned length, int* output)
-{
-    return Interpreter(bytecode, output, input, start, length).interpret();
-}
-
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoPatternCharacter);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoCharacterClass);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoBackReference);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);
-
-
-} }
diff --git a/js/src/yarr/YarrInterpreter.h b/js/src/yarr/YarrInterpreter.h
deleted file mode 100644
index 32b72858cad1..000000000000
--- a/js/src/yarr/YarrInterpreter.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/* -*- 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, 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef YarrInterpreter_h
-#define YarrInterpreter_h
-
-#include "YarrPattern.h"
-
-namespace WTF {
-class BumpPointerAllocator;
-}
-using WTF::BumpPointerAllocator;
-
-namespace JSC { namespace Yarr {
-
-class ByteDisjunction;
-
-struct ByteTerm {
-    enum Type {
-        TypeBodyAlternativeBegin,
-        TypeBodyAlternativeDisjunction,
-        TypeBodyAlternativeEnd,
-        TypeAlternativeBegin,
-        TypeAlternativeDisjunction,
-        TypeAlternativeEnd,
-        TypeSubpatternBegin,
-        TypeSubpatternEnd,
-        TypeAssertionBOL,
-        TypeAssertionEOL,
-        TypeAssertionWordBoundary,
-        TypePatternCharacterOnce,
-        TypePatternCharacterFixed,
-        TypePatternCharacterGreedy,
-        TypePatternCharacterNonGreedy,
-        TypePatternCasedCharacterOnce,
-        TypePatternCasedCharacterFixed,
-        TypePatternCasedCharacterGreedy,
-        TypePatternCasedCharacterNonGreedy,
-        TypeCharacterClass,
-        TypeBackReference,
-        TypeParenthesesSubpattern,
-        TypeParenthesesSubpatternOnceBegin,
-        TypeParenthesesSubpatternOnceEnd,
-        TypeParenthesesSubpatternTerminalBegin,
-        TypeParenthesesSubpatternTerminalEnd,
-        TypeParentheticalAssertionBegin,
-        TypeParentheticalAssertionEnd,
-        TypeCheckInput,
-        TypeUncheckInput
-    } type;
-    union {
-        struct {
-            union {
-                UChar patternCharacter;
-                struct {
-                    UChar lo;
-                    UChar hi;
-                } casedCharacter;
-                CharacterClass* characterClass;
-                unsigned subpatternId;
-            };
-            union {
-                ByteDisjunction* parenthesesDisjunction;
-                unsigned parenthesesWidth;
-            };
-            QuantifierType quantityType;
-            unsigned quantityCount;
-        } atom;
-        struct {
-            int next;
-            int end;
-            bool onceThrough;
-        } alternative;
-        unsigned checkInputCount;
-    };
-    unsigned frameLocation;
-    bool m_capture : 1;
-    bool m_invert : 1;
-    int inputPosition;
-
-    // For js::Vector. Does not create a valid object.
-    ByteTerm()
-    {
-    }
-
-    ByteTerm(UChar ch, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-        : frameLocation(frameLocation)
-        , m_capture(false)
-        , m_invert(false)
-    {
-        switch (quantityType) {
-        case QuantifierFixedCount:
-            type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed;
-            break;
-        case QuantifierGreedy:
-            type = ByteTerm::TypePatternCharacterGreedy;
-            break;
-        case QuantifierNonGreedy:
-            type = ByteTerm::TypePatternCharacterNonGreedy;
-            break;
-        }
-
-        atom.patternCharacter = ch;
-        atom.quantityType = quantityType;
-        atom.quantityCount = quantityCount;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-        : frameLocation(frameLocation)
-        , m_capture(false)
-        , m_invert(false)
-    {
-        switch (quantityType) {
-        case QuantifierFixedCount:
-            type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed;
-            break;
-        case QuantifierGreedy:
-            type = ByteTerm::TypePatternCasedCharacterGreedy;
-            break;
-        case QuantifierNonGreedy:
-            type = ByteTerm::TypePatternCasedCharacterNonGreedy;
-            break;
-        }
-
-        atom.casedCharacter.lo = lo;
-        atom.casedCharacter.hi = hi;
-        atom.quantityType = quantityType;
-        atom.quantityCount = quantityCount;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(CharacterClass* characterClass, bool invert, int inputPos)
-        : type(ByteTerm::TypeCharacterClass)
-        , m_capture(false)
-        , m_invert(invert)
-    {
-        atom.characterClass = characterClass;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool capture, int inputPos)
-        : type(type)
-        , m_capture(capture)
-        , m_invert(false)
-    {
-        atom.subpatternId = subpatternId;
-        atom.parenthesesDisjunction = parenthesesInfo;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-    
-    ByteTerm(Type type, bool invert = false)
-        : type(type)
-        , m_capture(false)
-        , m_invert(invert)
-    {
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-    }
-
-    ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, int inputPos)
-        : type(type)
-        , m_capture(capture)
-        , m_invert(invert)
-    {
-        atom.subpatternId = subpatternId;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-
-    static ByteTerm BOL(int inputPos)
-    {
-        ByteTerm term(TypeAssertionBOL);
-        term.inputPosition = inputPos;
-        return term;
-    }
-
-    static ByteTerm CheckInput(unsigned count)
-    {
-        ByteTerm term(TypeCheckInput);
-        term.checkInputCount = count;
-        return term;
-    }
-
-    static ByteTerm UncheckInput(unsigned count)
-    {
-        ByteTerm term(TypeUncheckInput);
-        term.checkInputCount = count;
-        return term;
-    }
-    
-    static ByteTerm EOL(int inputPos)
-    {
-        ByteTerm term(TypeAssertionEOL);
-        term.inputPosition = inputPos;
-        return term;
-    }
-
-    static ByteTerm WordBoundary(bool invert, int inputPos)
-    {
-        ByteTerm term(TypeAssertionWordBoundary, invert);
-        term.inputPosition = inputPos;
-        return term;
-    }
-    
-    static ByteTerm BackReference(unsigned subpatternId, int inputPos)
-    {
-        return ByteTerm(TypeBackReference, subpatternId, false, false, inputPos);
-    }
-
-    static ByteTerm BodyAlternativeBegin(bool onceThrough)
-    {
-        ByteTerm term(TypeBodyAlternativeBegin);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = onceThrough;
-        return term;
-    }
-
-    static ByteTerm BodyAlternativeDisjunction(bool onceThrough)
-    {
-        ByteTerm term(TypeBodyAlternativeDisjunction);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = onceThrough;
-        return term;
-    }
-
-    static ByteTerm BodyAlternativeEnd()
-    {
-        ByteTerm term(TypeBodyAlternativeEnd);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeBegin()
-    {
-        ByteTerm term(TypeAlternativeBegin);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeDisjunction()
-    {
-        ByteTerm term(TypeAlternativeDisjunction);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeEnd()
-    {
-        ByteTerm term(TypeAlternativeEnd);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm SubpatternBegin()
-    {
-        return ByteTerm(TypeSubpatternBegin);
-    }
-
-    static ByteTerm SubpatternEnd()
-    {
-        return ByteTerm(TypeSubpatternEnd);
-    }
-
-    bool invert()
-    {
-        return m_invert;
-    }
-
-    bool capture()
-    {
-        return m_capture;
-    }
-};
-
-class ByteDisjunction {
-    WTF_MAKE_FAST_ALLOCATED
-public:
-    ByteDisjunction(unsigned numSubpatterns, unsigned frameSize)
-        : m_numSubpatterns(numSubpatterns)
-        , m_frameSize(frameSize)
-    {
-    }
-
-    Vector terms;
-    unsigned m_numSubpatterns;
-    unsigned m_frameSize;
-};
-
-struct BytecodePattern {
-    WTF_MAKE_FAST_ALLOCATED
-public:
-    BytecodePattern(PassOwnPtr body, Vector allParenthesesInfo, YarrPattern& pattern, BumpPointerAllocator* allocator)
-        : m_body(body)
-        , m_ignoreCase(pattern.m_ignoreCase)
-        , m_multiline(pattern.m_multiline)
-        , m_containsBeginChars(pattern.m_containsBeginChars)
-        , m_allocator(allocator)
-    {
-        newlineCharacterClass = pattern.newlineCharacterClass();
-        wordcharCharacterClass = pattern.wordcharCharacterClass();
-
-        m_allParenthesesInfo.append(allParenthesesInfo);
-        m_userCharacterClasses.append(pattern.m_userCharacterClasses);
-        // 'Steal' the YarrPattern's CharacterClasses!  We clear its
-        // array, so that it won't delete them on destruction.  We'll
-        // take responsibility for that.
-        pattern.m_userCharacterClasses.clear();
-
-        m_beginChars.append(pattern.m_beginChars);
-    }
-
-    ~BytecodePattern()
-    {
-        deleteAllValues(m_allParenthesesInfo);
-        deleteAllValues(m_userCharacterClasses);
-    }
-
-    OwnPtr m_body;
-    bool m_ignoreCase;
-    bool m_multiline;
-    bool m_containsBeginChars;
-    // Each BytecodePattern is associated with a RegExp, each RegExp is associated
-    // with a JSGlobalData.  Cache a pointer to out JSGlobalData's m_regExpAllocator.
-    BumpPointerAllocator* m_allocator;
-
-    CharacterClass* newlineCharacterClass;
-    CharacterClass* wordcharCharacterClass;
-
-    Vector m_beginChars;
-
-private:
-    Vector m_allParenthesesInfo;
-    Vector m_userCharacterClasses;
-};
-
-} } // namespace JSC::Yarr
-
-#endif // YarrInterpreter_h
diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp
deleted file mode 100644
index c0187f240b6d..000000000000
--- a/js/src/yarr/YarrJIT.cpp
+++ /dev/null
@@ -1,2405 +0,0 @@
-/* -*- 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.
- *
- * 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "YarrJIT.h"
-
-#include "assembler/assembler/LinkBuffer.h"
-#include "Yarr.h"
-
-#if ENABLE_YARR_JIT
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-class YarrGenerator : private MacroAssembler {
-    friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
-
-#if WTF_CPU_ARM
-    static const RegisterID input = ARMRegisters::r0;
-    static const RegisterID index = ARMRegisters::r1;
-    static const RegisterID length = ARMRegisters::r2;
-    static const RegisterID output = ARMRegisters::r4;
-
-    static const RegisterID regT0 = ARMRegisters::r5;
-    static const RegisterID regT1 = ARMRegisters::r6;
-
-    static const RegisterID returnRegister = ARMRegisters::r0;
-#elif WTF_CPU_MIPS
-    static const RegisterID input = MIPSRegisters::a0;
-    static const RegisterID index = MIPSRegisters::a1;
-    static const RegisterID length = MIPSRegisters::a2;
-    static const RegisterID output = MIPSRegisters::a3;
-
-    static const RegisterID regT0 = MIPSRegisters::t4;
-    static const RegisterID regT1 = MIPSRegisters::t5;
-
-    static const RegisterID returnRegister = MIPSRegisters::v0;
-#elif WTF_CPU_SH4
-    static const RegisterID input = SH4Registers::r4;
-    static const RegisterID index = SH4Registers::r5;
-    static const RegisterID length = SH4Registers::r6;
-    static const RegisterID output = SH4Registers::r7;
-
-    static const RegisterID regT0 = SH4Registers::r0;
-    static const RegisterID regT1 = SH4Registers::r1;
-
-    static const RegisterID returnRegister = SH4Registers::r0;
-#elif WTF_CPU_X86
-    static const RegisterID input = X86Registers::eax;
-    static const RegisterID index = X86Registers::edx;
-    static const RegisterID length = X86Registers::ecx;
-    static const RegisterID output = X86Registers::edi;
-
-    static const RegisterID regT0 = X86Registers::ebx;
-    static const RegisterID regT1 = X86Registers::esi;
-
-    static const RegisterID returnRegister = X86Registers::eax;
-#elif WTF_CPU_X86_64
-    static const RegisterID input = X86Registers::edi;
-    static const RegisterID index = X86Registers::esi;
-    static const RegisterID length = X86Registers::edx;
-    static const RegisterID output = X86Registers::ecx;
-
-    static const RegisterID regT0 = X86Registers::eax;
-    static const RegisterID regT1 = X86Registers::ebx;
-
-    static const RegisterID returnRegister = X86Registers::eax;
-#endif
-
-    void optimizeAlternative(PatternAlternative* alternative)
-    {
-        if (!alternative->m_terms.size())
-            return;
-
-        for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) {
-            PatternTerm& term = alternative->m_terms[i];
-            PatternTerm& nextTerm = alternative->m_terms[i + 1];
-
-            if ((term.type == PatternTerm::TypeCharacterClass)
-                && (term.quantityType == QuantifierFixedCount)
-                && (nextTerm.type == PatternTerm::TypePatternCharacter)
-                && (nextTerm.quantityType == QuantifierFixedCount)) {
-                PatternTerm termCopy = term;
-                alternative->m_terms[i] = nextTerm;
-                alternative->m_terms[i + 1] = termCopy;
-            }
-        }
-    }
-
-    void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount)
-    {
-        do {
-            // pick which range we're going to generate
-            int which = count >> 1;
-            char lo = ranges[which].begin;
-            char hi = ranges[which].end;
-
-            // check if there are any ranges or matches below lo.  If not, just jl to failure -
-            // if there is anything else to check, check that first, if it falls through jmp to failure.
-            if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
-                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
-
-                // generate code for all ranges before this one
-                if (which)
-                    matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
-
-                while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
-                    matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex])));
-                    ++*matchIndex;
-                }
-                failures.append(jump());
-
-                loOrAbove.link(this);
-            } else if (which) {
-                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
-
-                matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
-                failures.append(jump());
-
-                loOrAbove.link(this);
-            } else
-                failures.append(branch32(LessThan, character, Imm32((unsigned short)lo)));
-
-            while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi))
-                ++*matchIndex;
-
-            matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi)));
-            // fall through to here, the value is above hi.
-
-            // shuffle along & loop around if there are any more matches to handle.
-            unsigned next = which + 1;
-            ranges += next;
-            count -= next;
-        } while (count);
-    }
-
-    void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass)
-    {
-        if (charClass->m_table) {
-            ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table));
-            matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry));
-            return;
-        }
-        Jump unicodeFail;
-        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) {
-            Jump isAscii = branch32(LessThanOrEqual, character, TrustedImm32(0x7f));
-
-            if (charClass->m_matchesUnicode.size()) {
-                for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) {
-                    UChar ch = charClass->m_matchesUnicode[i];
-                    matchDest.append(branch32(Equal, character, Imm32(ch)));
-                }
-            }
-
-            if (charClass->m_rangesUnicode.size()) {
-                for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) {
-                    UChar lo = charClass->m_rangesUnicode[i].begin;
-                    UChar hi = charClass->m_rangesUnicode[i].end;
-
-                    Jump below = branch32(LessThan, character, Imm32(lo));
-                    matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi)));
-                    below.link(this);
-                }
-            }
-
-            unicodeFail = jump();
-            isAscii.link(this);
-        }
-
-        if (charClass->m_ranges.size()) {
-            unsigned matchIndex = 0;
-            JumpList failures;
-            matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size());
-            while (matchIndex < charClass->m_matches.size())
-                matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++])));
-
-            failures.link(this);
-        } else if (charClass->m_matches.size()) {
-            // optimization: gather 'a','A' etc back together, can mask & test once.
-            Vector matchesAZaz;
-
-            for (unsigned i = 0; i < charClass->m_matches.size(); ++i) {
-                char ch = charClass->m_matches[i];
-                if (m_pattern.m_ignoreCase) {
-                    if (isASCIILower(ch)) {
-                        matchesAZaz.append(ch);
-                        continue;
-                    }
-                    if (isASCIIUpper(ch))
-                        continue;
-                }
-                matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch)));
-            }
-
-            if (unsigned countAZaz = matchesAZaz.size()) {
-                or32(TrustedImm32(32), character);
-                for (unsigned i = 0; i < countAZaz; ++i)
-                    matchDest.append(branch32(Equal, character, TrustedImm32(matchesAZaz[i])));
-            }
-        }
-
-        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size())
-            unicodeFail.link(this);
-    }
-
-    // Jumps if input not available; will have (incorrectly) incremented already!
-    Jump jumpIfNoAvailableInput(unsigned countToCheck = 0)
-    {
-        if (countToCheck)
-            add32(Imm32(countToCheck), index);
-        return branch32(Above, index, length);
-    }
-
-    Jump jumpIfAvailableInput(unsigned countToCheck)
-    {
-        add32(Imm32(countToCheck), index);
-        return branch32(BelowOrEqual, index, length);
-    }
-
-    Jump checkInput()
-    {
-        return branch32(BelowOrEqual, index, length);
-    }
-
-    Jump atEndOfInput()
-    {
-        return branch32(Equal, index, length);
-    }
-
-    Jump notAtEndOfInput()
-    {
-        return branch32(NotEqual, index, length);
-    }
-
-    Jump jumpIfCharEquals(UChar ch, int inputPosition)
-    {
-        return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
-    }
-
-    Jump jumpIfCharNotEquals(UChar ch, int inputPosition)
-    {
-        return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
-    }
-
-    void readCharacter(int inputPosition, RegisterID reg)
-    {
-        load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg);
-    }
-
-    void storeToFrame(RegisterID reg, unsigned frameLocation)
-    {
-        poke(reg, frameLocation);
-    }
-
-    void storeToFrame(TrustedImm32 imm, unsigned frameLocation)
-    {
-        poke(imm, frameLocation);
-    }
-
-    DataLabelPtr storeToFrameWithPatch(unsigned frameLocation)
-    {
-        return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*)));
-    }
-
-    void loadFromFrame(unsigned frameLocation, RegisterID reg)
-    {
-        peek(reg, frameLocation);
-    }
-
-    void loadFromFrameAndJump(unsigned frameLocation)
-    {
-        jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
-    }
-
-    enum YarrOpCode {
-        // These nodes wrap body alternatives - those in the main disjunction,
-        // rather than subpatterns or assertions. These are chained together in
-        // a doubly linked list, with a 'begin' node for the first alternative,
-        // a 'next' node for each subsequent alternative, and an 'end' node at
-        // the end. In the case of repeating alternatives, the 'end' node also
-        // has a reference back to 'begin'.
-        OpBodyAlternativeBegin,
-        OpBodyAlternativeNext,
-        OpBodyAlternativeEnd,
-        // Similar to the body alternatives, but used for subpatterns with two
-        // or more alternatives.
-        OpNestedAlternativeBegin,
-        OpNestedAlternativeNext,
-        OpNestedAlternativeEnd,
-        // Used for alternatives in subpatterns where there is only a single
-        // alternative (backtrackingis easier in these cases), or for alternatives
-        // which never need to be backtracked (those in parenthetical assertions,
-        // terminal subpatterns).
-        OpSimpleNestedAlternativeBegin,
-        OpSimpleNestedAlternativeNext,
-        OpSimpleNestedAlternativeEnd,
-        // Used to wrap 'Once' subpattern matches (quantityCount == 1).
-        OpParenthesesSubpatternOnceBegin,
-        OpParenthesesSubpatternOnceEnd,
-        // Used to wrap 'Terminal' subpattern matches (at the end of the regexp).
-        OpParenthesesSubpatternTerminalBegin,
-        OpParenthesesSubpatternTerminalEnd,
-        // Used to wrap parenthetical assertions.
-        OpParentheticalAssertionBegin,
-        OpParentheticalAssertionEnd,
-        // Wraps all simple terms (pattern characters, character classes).
-        OpTerm,
-        // Where an expression contains only 'once through' body alternatives
-        // and no repeating ones, this op is used to return match failure.
-        OpMatchFailed
-    };
-
-    // This structure is used to hold the compiled opcode information,
-    // including reference back to the original PatternTerm/PatternAlternatives,
-    // and JIT compilation data structures.
-    struct YarrOp {
-        explicit YarrOp(PatternTerm* term)
-            : m_op(OpTerm)
-            , m_term(term)
-            , m_isDeadCode(false)
-        {
-        }
-
-        explicit YarrOp(YarrOpCode op)
-            : m_op(op)
-            , m_isDeadCode(false)
-        {
-        }
-
-        // The operation, as a YarrOpCode, and also a reference to the PatternTerm.
-        YarrOpCode m_op;
-        PatternTerm* m_term;
-
-        // For alternatives, this holds the PatternAlternative and doubly linked
-        // references to this alternative's siblings. In the case of the
-        // OpBodyAlternativeEnd node at the end of a section of repeating nodes,
-        // m_nextOp will reference the OpBodyAlternativeBegin node of the first
-        // repeating alternative.
-        PatternAlternative* m_alternative;
-        size_t m_previousOp;
-        size_t m_nextOp;
-
-        // Used to record a set of Jumps out of the generated code, typically
-        // used for jumps out to backtracking code, and a single reentry back
-        // into the code for a node (likely where a backtrack will trigger
-        // rematching).
-        Label m_reentry;
-        JumpList m_jumps;
-
-        // This flag is used to null out the second pattern character, when
-        // two are fused to match a pair together.
-        bool m_isDeadCode;
-
-        // Currently used in the case of some of the more complex management of
-        // 'm_checked', to cache the offset used in this alternative, to avoid
-        // recalculating it.
-        int m_checkAdjust;
-
-        // Used by OpNestedAlternativeNext/End to hold the pointer to the
-        // value that will be pushed into the pattern's frame to return to,
-        // upon backtracking back into the disjunction.
-        DataLabelPtr m_returnAddress;
-    };
-
-    // BacktrackingState
-    // This class encapsulates information about the state of code generation
-    // whilst generating the code for backtracking, when a term fails to match.
-    // Upon entry to code generation of the backtracking code for a given node,
-    // the Backtracking state will hold references to all control flow sources
-    // that are outputs in need of further backtracking from the prior node
-    // generated (which is the subsequent operation in the regular expression,
-    // and in the m_ops Vector, since we generated backtracking backwards).
-    // These references to control flow take the form of:
-    //  - A jump list of jumps, to be linked to code that will backtrack them
-    //    further.
-    //  - A set of DataLabelPtr values, to be populated with values to be
-    //    treated effectively as return addresses backtracking into complex
-    //    subpatterns.
-    //  - A flag indicating that the current sequence of generated code up to
-    //    this point requires backtracking.
-    class BacktrackingState {
-    public:
-        BacktrackingState()
-            : m_pendingFallthrough(false)
-        {
-        }
-
-        // Add a jump or jumps, a return address, or set the flag indicating
-        // that the current 'fallthrough' control flow requires backtracking.
-        void append(const Jump& jump)
-        {
-            m_laterFailures.append(jump);
-        }
-        void append(JumpList& jumpList)
-        {
-            m_laterFailures.append(jumpList);
-        }
-        void append(const DataLabelPtr& returnAddress)
-        {
-            m_pendingReturns.append(returnAddress);
-        }
-        void fallthrough()
-        {
-            ASSERT(!m_pendingFallthrough);
-            m_pendingFallthrough = true;
-        }
-
-        // These methods clear the backtracking state, either linking to the
-        // current location, a provided label, or copying the backtracking out
-        // to a JumpList. All actions may require code generation to take place,
-        // and as such are passed a pointer to the assembler.
-        void link(MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                Label here(assembler);
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
-                m_pendingReturns.clear();
-            }
-            m_laterFailures.link(assembler);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-        void linkTo(Label label, MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], label));
-                m_pendingReturns.clear();
-            }
-            if (m_pendingFallthrough)
-                assembler->jump(label);
-            m_laterFailures.linkTo(label, assembler);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-        void takeBacktracksToJumpList(JumpList& jumpList, MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                Label here(assembler);
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
-                m_pendingReturns.clear();
-                m_pendingFallthrough = true;
-            }
-            if (m_pendingFallthrough)
-                jumpList.append(assembler->jump());
-            jumpList.append(m_laterFailures);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-
-        bool isEmpty()
-        {
-            return m_laterFailures.empty() && m_pendingReturns.isEmpty() && !m_pendingFallthrough;
-        }
-
-        // Called at the end of code generation to link all return addresses.
-        void linkDataLabels(LinkBuffer& linkBuffer)
-        {
-            ASSERT(isEmpty());
-            for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
-                linkBuffer.patch(m_backtrackRecords[i].m_dataLabel, linkBuffer.locationOf(m_backtrackRecords[i].m_backtrackLocation));
-        }
-
-    private:
-        struct ReturnAddressRecord {
-            ReturnAddressRecord(DataLabelPtr dataLabel, Label backtrackLocation)
-                : m_dataLabel(dataLabel)
-                , m_backtrackLocation(backtrackLocation)
-            {
-            }
-
-            DataLabelPtr m_dataLabel;
-            Label m_backtrackLocation;
-        };
-
-        JumpList m_laterFailures;
-        bool m_pendingFallthrough;
-        Vector m_pendingReturns;
-        Vector m_backtrackRecords;
-    };
-
-    // Generation methods:
-    // ===================
-
-    // This method provides a default implementation of backtracking common
-    // to many terms; terms commonly jump out of the forwards  matching path
-    // on any failed conditions, and add these jumps to the m_jumps list. If
-    // no special handling is required we can often just backtrack to m_jumps.
-    void backtrackTermDefault(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        m_backtrackingState.append(op.m_jumps);
-    }
-
-    void generateAssertionBOL(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        if (m_pattern.m_multiline) {
-            const RegisterID character = regT0;
-
-            JumpList matchDest;
-            if (!term->inputPosition)
-                matchDest.append(branch32(Equal, index, Imm32(m_checked)));
-
-            readCharacter((term->inputPosition - m_checked) - 1, character);
-            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
-            op.m_jumps.append(jump());
-
-            matchDest.link(this);
-        } else {
-            // Erk, really should poison out these alternatives early. :-/
-            if (term->inputPosition)
-                op.m_jumps.append(jump());
-            else
-                op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked)));
-        }
-    }
-    void backtrackAssertionBOL(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateAssertionEOL(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        if (m_pattern.m_multiline) {
-            const RegisterID character = regT0;
-
-            JumpList matchDest;
-            if (term->inputPosition == m_checked)
-                matchDest.append(atEndOfInput());
-
-            readCharacter((term->inputPosition - m_checked), character);
-            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
-            op.m_jumps.append(jump());
-
-            matchDest.link(this);
-        } else {
-            if (term->inputPosition == m_checked)
-                op.m_jumps.append(notAtEndOfInput());
-            // Erk, really should poison out these alternatives early. :-/
-            else
-                op.m_jumps.append(jump());
-        }
-    }
-    void backtrackAssertionEOL(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    // Also falls though on nextIsNotWordChar.
-    void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        if (term->inputPosition == m_checked)
-            nextIsNotWordChar.append(atEndOfInput());
-
-        readCharacter((term->inputPosition - m_checked), character);
-        matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass());
-    }
-
-    void generateAssertionWordBoundary(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        Jump atBegin;
-        JumpList matchDest;
-        if (!term->inputPosition)
-            atBegin = branch32(Equal, index, Imm32(m_checked));
-        readCharacter((term->inputPosition - m_checked) - 1, character);
-        matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass());
-        if (!term->inputPosition)
-            atBegin.link(this);
-
-        // We fall through to here if the last character was not a wordchar.
-        JumpList nonWordCharThenWordChar;
-        JumpList nonWordCharThenNonWordChar;
-        if (term->invert()) {
-            matchAssertionWordchar(opIndex, nonWordCharThenNonWordChar, nonWordCharThenWordChar);
-            nonWordCharThenWordChar.append(jump());
-        } else {
-            matchAssertionWordchar(opIndex, nonWordCharThenWordChar, nonWordCharThenNonWordChar);
-            nonWordCharThenNonWordChar.append(jump());
-        }
-        op.m_jumps.append(nonWordCharThenNonWordChar);
-
-        // We jump here if the last character was a wordchar.
-        matchDest.link(this);
-        JumpList wordCharThenWordChar;
-        JumpList wordCharThenNonWordChar;
-        if (term->invert()) {
-            matchAssertionWordchar(opIndex, wordCharThenNonWordChar, wordCharThenWordChar);
-            wordCharThenWordChar.append(jump());
-        } else {
-            matchAssertionWordchar(opIndex, wordCharThenWordChar, wordCharThenNonWordChar);
-            // This can fall-though!
-        }
-
-        op.m_jumps.append(wordCharThenWordChar);
-
-        nonWordCharThenWordChar.link(this);
-        wordCharThenNonWordChar.link(this);
-    }
-    void backtrackAssertionWordBoundary(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterOnce(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-
-        // m_ops always ends with a OpBodyAlternativeEnd or OpMatchFailed
-        // node, so there must always be at least one more node.
-        ASSERT(opIndex + 1 < m_ops.size());
-        YarrOp& nextOp = m_ops[opIndex + 1];
-
-        if (op.m_isDeadCode)
-            return;
-
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-
-        if (nextOp.m_op == OpTerm) {
-            PatternTerm* nextTerm = nextOp.m_term;
-            if (nextTerm->type == PatternTerm::TypePatternCharacter
-                && nextTerm->quantityType == QuantifierFixedCount
-                && nextTerm->quantityCount == 1
-                && nextTerm->inputPosition == (term->inputPosition + 1)) {
-
-                UChar ch2 = nextTerm->patternCharacter;
-
-                int mask = 0;
-                int chPair = ch | (ch2 << 16);
-
-                if (m_pattern.m_ignoreCase) {
-                    if (isASCIIAlpha(ch))
-                        mask |= 32;
-                    if (isASCIIAlpha(ch2))
-                        mask |= 32 << 16;
-                }
-
-                BaseIndex address(input, index, TimesTwo, (term->inputPosition - m_checked) * sizeof(UChar));
-                if (mask) {
-                    load32WithUnalignedHalfWords(address, character);
-                    or32(Imm32(mask), character);
-                    op.m_jumps.append(branch32(NotEqual, character, Imm32(chPair | mask)));
-                } else
-                    op.m_jumps.append(branch32WithUnalignedHalfWords(NotEqual, address, Imm32(chPair)));
-
-                nextOp.m_isDeadCode = true;
-                return;
-            }
-        }
-
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            op.m_jumps.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-    }
-    void backtrackPatternCharacterOnce(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterFixed(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(index, countRegister);
-        sub32(Imm32(term->quantityCount), countRegister);
-
-        Label loop(this);
-        BaseIndex address(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar));
-
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            load16(address, character);
-            or32(TrustedImm32(32), character);
-            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            op.m_jumps.append(branch16(NotEqual, address, Imm32(ch)));
-        }
-        add32(TrustedImm32(1), countRegister);
-        branch32(NotEqual, countRegister, index).linkTo(loop, this);
-    }
-    void backtrackPatternCharacterFixed(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-
-        JumpList failures;
-        Label loop(this);
-        failures.append(atEndOfInput());
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-        if (term->quantityCount == quantifyInfinite)
-            jump(loop);
-        else
-            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
-
-        failures.link(this);
-        op.m_reentry = label();
-
-        storeToFrame(countRegister, term->frameLocation);
-
-    }
-    void backtrackPatternCharacterGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-        m_backtrackingState.append(branchTest32(Zero, countRegister));
-        sub32(TrustedImm32(1), countRegister);
-        sub32(TrustedImm32(1), index);
-        jump(op.m_reentry);
-    }
-
-    void generatePatternCharacterNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-        op.m_reentry = label();
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackPatternCharacterNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        JumpList nonGreedyFailures;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-
-        nonGreedyFailures.append(atEndOfInput());
-        if (term->quantityCount != quantifyInfinite)
-            nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            nonGreedyFailures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-
-        jump(op.m_reentry);
-
-        nonGreedyFailures.link(this);
-        sub32(countRegister, index);
-        m_backtrackingState.fallthrough();
-    }
-
-    void generateCharacterClassOnce(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        JumpList matchDest;
-        readCharacter((term->inputPosition - m_checked), character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            op.m_jumps.append(matchDest);
-        else {
-            op.m_jumps.append(jump());
-            matchDest.link(this);
-        }
-    }
-    void backtrackCharacterClassOnce(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateCharacterClassFixed(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(index, countRegister);
-        sub32(Imm32(term->quantityCount), countRegister);
-
-        Label loop(this);
-        JumpList matchDest;
-        load16(BaseIndex(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar)), character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            op.m_jumps.append(matchDest);
-        else {
-            op.m_jumps.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        branch32(NotEqual, countRegister, index).linkTo(loop, this);
-    }
-    void backtrackCharacterClassFixed(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateCharacterClassGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-
-        JumpList failures;
-        Label loop(this);
-        failures.append(atEndOfInput());
-
-        if (term->invert()) {
-            readCharacter(term->inputPosition - m_checked, character);
-            matchCharacterClass(character, failures, term->characterClass);
-        } else {
-            JumpList matchDest;
-            readCharacter(term->inputPosition - m_checked, character);
-            matchCharacterClass(character, matchDest, term->characterClass);
-            failures.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-        if (term->quantityCount != quantifyInfinite) {
-            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
-            failures.append(jump());
-        } else
-            jump(loop);
-
-        failures.link(this);
-        op.m_reentry = label();
-
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackCharacterClassGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-        m_backtrackingState.append(branchTest32(Zero, countRegister));
-        sub32(TrustedImm32(1), countRegister);
-        sub32(TrustedImm32(1), index);
-        jump(op.m_reentry);
-    }
-
-    void generateCharacterClassNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-        op.m_reentry = label();
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackCharacterClassNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        JumpList nonGreedyFailures;
-
-        m_backtrackingState.link(this);
-
-        Label backtrackBegin(this);
-        loadFromFrame(term->frameLocation, countRegister);
-
-        nonGreedyFailures.append(atEndOfInput());
-        nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
-
-        JumpList matchDest;
-        readCharacter(term->inputPosition - m_checked, character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            nonGreedyFailures.append(matchDest);
-        else {
-            nonGreedyFailures.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-
-        jump(op.m_reentry);
-
-        nonGreedyFailures.link(this);
-        sub32(countRegister, index);
-        m_backtrackingState.fallthrough();
-    }
-
-    // Code generation/backtracking for simple terms
-    // (pattern characters, character classes, and assertions).
-    // These methods farm out work to the set of functions above.
-    void generateTerm(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        switch (term->type) {
-        case PatternTerm::TypePatternCharacter:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    generatePatternCharacterOnce(opIndex);
-                else
-                    generatePatternCharacterFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                generatePatternCharacterGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                generatePatternCharacterNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeCharacterClass:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    generateCharacterClassOnce(opIndex);
-                else
-                    generateCharacterClassFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                generateCharacterClassGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                generateCharacterClassNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeAssertionBOL:
-            generateAssertionBOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionEOL:
-            generateAssertionEOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionWordBoundary:
-            generateAssertionWordBoundary(opIndex);
-            break;
-
-        case PatternTerm::TypeForwardReference:
-            break;
-
-        case PatternTerm::TypeParenthesesSubpattern:
-        case PatternTerm::TypeParentheticalAssertion:
-            ASSERT_NOT_REACHED();
-        case PatternTerm::TypeBackReference:
-            m_shouldFallBack = true;
-            break;
-        }
-    }
-    void backtrackTerm(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        switch (term->type) {
-        case PatternTerm::TypePatternCharacter:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    backtrackPatternCharacterOnce(opIndex);
-                else
-                    backtrackPatternCharacterFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                backtrackPatternCharacterGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                backtrackPatternCharacterNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeCharacterClass:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    backtrackCharacterClassOnce(opIndex);
-                else
-                    backtrackCharacterClassFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                backtrackCharacterClassGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                backtrackCharacterClassNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeAssertionBOL:
-            backtrackAssertionBOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionEOL:
-            backtrackAssertionEOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionWordBoundary:
-            backtrackAssertionWordBoundary(opIndex);
-            break;
-
-        case PatternTerm::TypeForwardReference:
-            break;
-
-        case PatternTerm::TypeParenthesesSubpattern:
-        case PatternTerm::TypeParentheticalAssertion:
-            ASSERT_NOT_REACHED();
-        case PatternTerm::TypeBackReference:
-            m_shouldFallBack = true;
-            break;
-        }
-    }
-
-    void generate()
-    {
-        // Forwards generate the matching code.
-        ASSERT(m_ops.size());
-        size_t opIndex = 0;
-
-        do {
-            YarrOp& op = m_ops[opIndex];
-            switch (op.m_op) {
-
-            case OpTerm:
-                generateTerm(opIndex);
-                break;
-
-            // OpBodyAlternativeBegin/Next/End
-            //
-            // These nodes wrap the set of alternatives in the body of the regular expression.
-            // There may be either one or two chains of OpBodyAlternative nodes, one representing
-            // the 'once through' sequence of alternatives (if any exist), and one representing
-            // the repeating alternatives (again, if any exist).
-            //
-            // Upon normal entry to the Begin alternative, we will check that input is available.
-            // Reentry to the Begin alternative will take place after the check has taken place,
-            // and will assume that the input position has already been progressed as appropriate.
-            //
-            // Entry to subsequent Next/End alternatives occurs when the prior alternative has
-            // successfully completed a match - return a success state from JIT code.
-            //
-            // Next alternatives allow for reentry optimized to suit backtracking from its
-            // preceding alternative. It expects the input position to still be set to a position
-            // appropriate to its predecessor, and it will only perform an input check if the
-            // predecessor had a minimum size less than its own.
-            //
-            // In the case 'once through' expressions, the End node will also have a reentry
-            // point to jump to when the last alternative fails. Again, this expects the input
-            // position to still reflect that expected by the prior alternative.
-            case OpBodyAlternativeBegin: {
-                PatternAlternative* alternative = op.m_alternative;
-
-                // Upon entry at the head of the set of alternatives, check if input is available
-                // to run the first alternative. (This progresses the input position).
-                op.m_jumps.append(jumpIfNoAvailableInput(alternative->m_minimumSize));
-                // We will reenter after the check, and assume the input position to have been
-                // set as appropriate to this alternative.
-                op.m_reentry = label();
-
-                m_checked += alternative->m_minimumSize;
-                break;
-            }
-            case OpBodyAlternativeNext:
-            case OpBodyAlternativeEnd: {
-                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                PatternAlternative* alternative = op.m_alternative;
-
-                // If we get here, the prior alternative matched - return success.
-                
-                // Adjust the stack pointer to remove the pattern's frame.
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-
-                // Load appropriate values into the return register and the first output
-                // slot, and return. In the case of pattern with a fixed size, we will
-                // not have yet set the value in the first 
-                ASSERT(index != returnRegister);
-                if (m_pattern.m_body->m_hasFixedSize) {
-                    move(index, returnRegister);
-                    if (priorAlternative->m_minimumSize)
-                        sub32(Imm32(priorAlternative->m_minimumSize), returnRegister);
-                    store32(returnRegister, output);
-                } else
-                    load32(Address(output), returnRegister);
-                store32(index, Address(output, 4));
-                generateReturn();
-
-                // This is the divide between the tail of the prior alternative, above, and
-                // the head of the subsequent alternative, below.
-
-                if (op.m_op == OpBodyAlternativeNext) {
-                    // This is the reentry point for the Next alternative. We expect any code
-                    // that jumps here to do so with the input position matching that of the
-                    // PRIOR alteranative, and we will only check input availability if we
-                    // need to progress it forwards.
-                    op.m_reentry = label();
-                    if (int delta = alternative->m_minimumSize - priorAlternative->m_minimumSize) {
-                        add32(Imm32(delta), index);
-                        if (delta > 0)
-                            op.m_jumps.append(jumpIfNoAvailableInput());
-                    }
-                } else if (op.m_nextOp == notFound) {
-                    // This is the reentry point for the End of 'once through' alternatives,
-                    // jumped to when the las alternative fails to match.
-                    op.m_reentry = label();
-                    sub32(Imm32(priorAlternative->m_minimumSize), index);
-                }
-
-                if (op.m_op == OpBodyAlternativeNext)
-                    m_checked += alternative->m_minimumSize;
-                m_checked -= priorAlternative->m_minimumSize;
-                break;
-            }
-
-            // OpSimpleNestedAlternativeBegin/Next/End
-            // OpNestedAlternativeBegin/Next/End
-            //
-            // These nodes are used to handle sets of alternatives that are nested within
-            // subpatterns and parenthetical assertions. The 'simple' forms are used where
-            // we do not need to be able to backtrack back into any alternative other than
-            // the last, the normal forms allow backtracking into any alternative.
-            //
-            // Each Begin/Next node is responsible for planting an input check to ensure
-            // sufficient input is available on entry. Next nodes additionally need to
-            // jump to the end - Next nodes use the End node's m_jumps list to hold this
-            // set of jumps.
-            //
-            // In the non-simple forms, successful alternative matches must store a
-            // 'return address' using a DataLabelPtr, used to store the address to jump
-            // to when backtracking, to get to the code for the appropriate alternative.
-            case OpSimpleNestedAlternativeBegin:
-            case OpNestedAlternativeBegin: {
-                PatternTerm* term = op.m_term;
-                PatternAlternative* alternative = op.m_alternative;
-                PatternDisjunction* disjunction = term->parentheses.disjunction;
-
-                // Calculate how much input we need to check for, and if non-zero check.
-                op.m_checkAdjust = alternative->m_minimumSize;
-                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
-                    op.m_checkAdjust -= disjunction->m_minimumSize;
-                if (op.m_checkAdjust)
-                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
- 
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeNext:
-            case OpNestedAlternativeNext: {
-                PatternTerm* term = op.m_term;
-                PatternAlternative* alternative = op.m_alternative;
-                PatternDisjunction* disjunction = term->parentheses.disjunction;
-
-                // In the non-simple case, store a 'return address' so we can backtrack correctly.
-                if (op.m_op == OpNestedAlternativeNext) {
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
-                }
-
-                // If we reach here then the last alternative has matched - jump to the
-                // End node, to skip over any further alternatives.
-                //
-                // FIXME: this is logically O(N^2) (though N can be expected to be very
-                // small). We could avoid this either by adding an extra jump to the JIT
-                // data structures, or by making backtracking code that jumps to Next
-                // alternatives are responsible for checking that input is available (if
-                // we didn't need to plant the input checks, then m_jumps would be free).
-                YarrOp* endOp = &m_ops[op.m_nextOp];
-                while (endOp->m_nextOp != notFound) {
-                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
-                    endOp = &m_ops[endOp->m_nextOp];
-                }
-                ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
-                endOp->m_jumps.append(jump());
-
-                // This is the entry point for the next alternative.
-                op.m_reentry = label();
-
-                // Calculate how much input we need to check for, and if non-zero check.
-                op.m_checkAdjust = alternative->m_minimumSize;
-                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
-                    op.m_checkAdjust -= disjunction->m_minimumSize;
-                if (op.m_checkAdjust)
-                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeEnd:
-            case OpNestedAlternativeEnd: {
-                PatternTerm* term = op.m_term;
-
-                // In the non-simple case, store a 'return address' so we can backtrack correctly.
-                if (op.m_op == OpNestedAlternativeEnd) {
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
-                }
-
-                // If this set of alternatives contains more than one alternative,
-                // then the Next nodes will have planted jumps to the End, and added
-                // them to this node's m_jumps list.
-                op.m_jumps.link(this);
-                op.m_jumps.clear();
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                break;
-            }
-
-            // OpParenthesesSubpatternOnceBegin/End
-            //
-            // These nodes support (optionally) capturing subpatterns, that have a
-            // quantity count of 1 (this covers fixed once, and ?/?? quantifiers). 
-            case OpParenthesesSubpatternOnceBegin: {
-                PatternTerm* term = op.m_term;
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                const RegisterID indexTemporary = regT0;
-                ASSERT(term->quantityCount == 1);
-
-                // Upon entry to a Greedy quantified set of parenthese store the index.
-                // We'll use this for two purposes:
-                //  - To indicate which iteration we are on of mathing the remainder of
-                //    the expression after the parentheses - the first, including the
-                //    match within the parentheses, or the second having skipped over them.
-                //  - To check for empty matches, which must be rejected.
-                //
-                // At the head of a NonGreedy set of parentheses we'll immediately set the
-                // value on the stack to -1 (indicating a match skipping the subpattern),
-                // and plant a jump to the end. We'll also plant a label to backtrack to
-                // to reenter the subpattern later, with a store to set up index on the
-                // second iteration.
-                //
-                // FIXME: for capturing parens, could use the index in the capture array?
-                if (term->quantityType == QuantifierGreedy)
-                    storeToFrame(index, parenthesesFrameLocation);
-                else if (term->quantityType == QuantifierNonGreedy) {
-                    storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
-                    op.m_jumps.append(jump());
-                    op.m_reentry = label();
-                    storeToFrame(index, parenthesesFrameLocation);
-                }
-
-                // If the parenthese are capturing, store the starting index value to the
-                // captures array, offsetting as necessary.
-                //
-                // FIXME: could avoid offsetting this value in JIT code, apply
-                // offsets only afterwards, at the point the results array is
-                // being accessed.
-                if (term->capture()) {
-                    int offsetId = term->parentheses.subpatternId << 1;
-                    int inputOffset = term->inputPosition - m_checked;
-                    if (term->quantityType == QuantifierFixedCount)
-                        inputOffset -= term->parentheses.disjunction->m_minimumSize;
-                    if (inputOffset) {
-                        move(index, indexTemporary);
-                        add32(Imm32(inputOffset), indexTemporary);
-                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
-                    } else
-                        store32(index, Address(output, offsetId * sizeof(int)));
-                }
-                break;
-            }
-            case OpParenthesesSubpatternOnceEnd: {
-                PatternTerm* term = op.m_term;
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                const RegisterID indexTemporary = regT0;
-                ASSERT(term->quantityCount == 1);
-
-                // For Greedy/NonGreedy quantified parentheses, we must reject zero length
-                // matches. If the minimum size is know to be non-zero we need not check.
-                if (term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize)
-                    op.m_jumps.append(branch32(Equal, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*))));
-
-                // If the parenthese are capturing, store the ending index value to the
-                // captures array, offsetting as necessary.
-                //
-                // FIXME: could avoid offsetting this value in JIT code, apply
-                // offsets only afterwards, at the point the results array is
-                // being accessed.
-                if (term->capture()) {
-                    int offsetId = (term->parentheses.subpatternId << 1) + 1;
-                    int inputOffset = term->inputPosition - m_checked;
-                    if (inputOffset) {
-                        move(index, indexTemporary);
-                        add32(Imm32(inputOffset), indexTemporary);
-                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
-                    } else
-                        store32(index, Address(output, offsetId * sizeof(int)));
-                }
-
-                // If the parentheses are quantified Greedy then add a label to jump back
-                // to if get a failed match from after the parentheses. For NonGreedy
-                // parentheses, link the jump from before the subpattern to here.
-                if (term->quantityType == QuantifierGreedy)
-                    op.m_reentry = label();
-                else if (term->quantityType == QuantifierNonGreedy) {
-                    YarrOp& beginOp = m_ops[op.m_previousOp];
-                    beginOp.m_jumps.link(this);
-                }
-                break;
-            }
-
-            // OpParenthesesSubpatternTerminalBegin/End
-            case OpParenthesesSubpatternTerminalBegin: {
-                PatternTerm* term = op.m_term;
-                ASSERT(term->quantityType == QuantifierGreedy);
-                ASSERT(term->quantityCount == quantifyInfinite);
-                ASSERT(!term->capture());
-
-                // Upon entry set a label to loop back to.
-                op.m_reentry = label();
-
-                // Store the start index of the current match; we need to reject zero
-                // length matches.
-                storeToFrame(index, term->frameLocation);
-                break;
-            }
-            case OpParenthesesSubpatternTerminalEnd: {
-                PatternTerm* term = op.m_term;
-
-                // Check for zero length matches - if the match is non-zero, then we
-                // can accept it & loop back up to the head of the subpattern.
-                YarrOp& beginOp = m_ops[op.m_previousOp];
-                branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*)), beginOp.m_reentry);
-
-                // Reject the match - backtrack back into the subpattern.
-                op.m_jumps.append(jump());
-
-                // This is the entry point to jump to when we stop matching - we will
-                // do so once the subpattern cannot match any more.
-                op.m_reentry = label();
-                break;
-            }
-
-            // OpParentheticalAssertionBegin/End
-            case OpParentheticalAssertionBegin: {
-                PatternTerm* term = op.m_term;
-
-                // Store the current index - assertions should not update index, so
-                // we will need to restore it upon a successful match.
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                storeToFrame(index, parenthesesFrameLocation);
-
-                // Check 
-                op.m_checkAdjust = m_checked - term->inputPosition;
-                if (op.m_checkAdjust)
-                    sub32(Imm32(op.m_checkAdjust), index);
-
-                m_checked -= op.m_checkAdjust;
-                break;
-            }
-            case OpParentheticalAssertionEnd: {
-                PatternTerm* term = op.m_term;
-
-                // Restore the input index value.
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                loadFromFrame(parenthesesFrameLocation, index);
-
-                // If inverted, a successful match of the assertion must be treated
-                // as a failure, so jump to backtracking.
-                if (term->invert()) {
-                    op.m_jumps.append(jump());
-                    op.m_reentry = label();
-                }
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked += lastOp.m_checkAdjust;
-                break;
-            }
-
-            case OpMatchFailed:
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-                move(TrustedImm32(-1), returnRegister);
-                generateReturn();
-                break;
-            }
-
-            ++opIndex;
-        } while (opIndex < m_ops.size());
-    }
-
-    void backtrack()
-    {
-        // Backwards generate the backtracking code.
-        size_t opIndex = m_ops.size();
-        ASSERT(opIndex);
-
-        do {
-            --opIndex;
-            YarrOp& op = m_ops[opIndex];
-            switch (op.m_op) {
-
-            case OpTerm:
-                backtrackTerm(opIndex);
-                break;
-
-            // OpBodyAlternativeBegin/Next/End
-            //
-            // For each Begin/Next node representing an alternative, we need to decide what to do
-            // in two circumstances:
-            //  - If we backtrack back into this node, from within the alternative.
-            //  - If the input check at the head of the alternative fails (if this exists).
-            //
-            // We treat these two cases differently since in the former case we have slightly
-            // more information - since we are backtracking out of a prior alternative we know
-            // that at least enough input was available to run it. For example, given the regular
-            // expression /a|b/, if we backtrack out of the first alternative (a failed pattern
-            // character match of 'a'), then we need not perform an additional input availability
-            // check before running the second alternative.
-            //
-            // Backtracking required differs for the last alternative, which in the case of the
-            // repeating set of alternatives must loop. The code generated for the last alternative
-            // will also be used to handle all input check failures from any prior alternatives -
-            // these require similar functionality, in seeking the next available alternative for
-            // which there is sufficient input.
-            //
-            // Since backtracking of all other alternatives simply requires us to link backtracks
-            // to the reentry point for the subsequent alternative, we will only be generating any
-            // code when backtracking the last alternative.
-            case OpBodyAlternativeBegin:
-            case OpBodyAlternativeNext: {
-                PatternAlternative* alternative = op.m_alternative;
-
-                if (op.m_op == OpBodyAlternativeNext) {
-                    PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                    m_checked += priorAlternative->m_minimumSize;
-                }
-                m_checked -= alternative->m_minimumSize;
-
-                // Is this the last alternative? If not, then if we backtrack to this point we just
-                // need to jump to try to match the next alternative.
-                if (m_ops[op.m_nextOp].m_op != OpBodyAlternativeEnd) {
-                    m_backtrackingState.linkTo(m_ops[op.m_nextOp].m_reentry, this);
-                    break;
-                }
-                YarrOp& endOp = m_ops[op.m_nextOp];
-
-                YarrOp* beginOp = &op;
-                while (beginOp->m_op != OpBodyAlternativeBegin) {
-                    ASSERT(beginOp->m_op == OpBodyAlternativeNext);
-                    beginOp = &m_ops[beginOp->m_previousOp];
-                }
-
-                bool onceThrough = endOp.m_nextOp == notFound;
-
-                // First, generate code to handle cases where we backtrack out of an attempted match
-                // of the last alternative. If this is a 'once through' set of alternatives then we
-                // have nothing to do - link this straight through to the End.
-                if (onceThrough)
-                    m_backtrackingState.linkTo(endOp.m_reentry, this);
-                else {
-                    // Okay, we're going to need to loop. Calculate the delta between where the input
-                    // position was, and where we want it to be allowing for the fact that we need to
-                    // increment by 1. E.g. for the regexp /a|x/ we need to increment the position by
-                    // 1 between loop iterations, but for /abcd|xyz/ we need to increment by two when
-                    // looping from the last alternative to the first, for /a|xyz/ we need to decrement
-                    // by 1, and for /a|xy/ we don't need to move the input position at all.
-                    int deltaLastAlternativeToFirstAlternativePlusOne = (beginOp->m_alternative->m_minimumSize - alternative->m_minimumSize) + 1;
-
-                    // If we don't need to move the input poistion, and the pattern has a fixed size
-                    // (in which case we omit the store of the start index until the pattern has matched)
-                    // then we can just link the backtrack out of the last alternative straight to the
-                    // head of the first alternative.
-                    if (!deltaLastAlternativeToFirstAlternativePlusOne && m_pattern.m_body->m_hasFixedSize)
-                        m_backtrackingState.linkTo(beginOp->m_reentry, this);
-                    else {
-                        // We need to generate a trampoline of code to execute before looping back
-                        // around to the first alternative.
-                        m_backtrackingState.link(this);
-
-                        // If the pattern size is not fixed, then store the start index, for use if we match.
-                        if (!m_pattern.m_body->m_hasFixedSize) {
-                            if (alternative->m_minimumSize == 1)
-                                store32(index, Address(output));
-                            else {
-                                move(index, regT0);
-                                if (alternative->m_minimumSize)
-                                    sub32(Imm32(alternative->m_minimumSize - 1), regT0);
-                                else
-                                    add32(Imm32(1), regT0);
-                                store32(regT0, Address(output));
-                            }
-                        }
-
-                        if (deltaLastAlternativeToFirstAlternativePlusOne)
-                            add32(Imm32(deltaLastAlternativeToFirstAlternativePlusOne), index);
-
-                        // Loop. Since this code is only reached when we backtrack out of the last
-                        // alternative (and NOT linked to from the input check upon entry to the
-                        // last alternative) we know that there must be at least enough input as
-                        // required by the last alternative. As such, we only need to check if the
-                        // first will require more to run - if the same or less is required we can
-                        // unconditionally jump.
-                        if (deltaLastAlternativeToFirstAlternativePlusOne > 0)
-                            checkInput().linkTo(beginOp->m_reentry, this);
-                        else
-                            jump(beginOp->m_reentry);
-                    }
-                }
-
-                // We can reach this point in the code in two ways:
-                //  - Fallthrough from the code above (a repeating alternative backtracked out of its
-                //    last alternative, and did not have sufficent input to run the first).
-                //  - We will loop back up to the following label when a releating alternative loops,
-                //    following a failed input check.
-                //
-                // Either way, we have just failed the input check for the first alternative.
-                Label firstInputCheckFailed(this);
-
-                // Generate code to handle input check failures from alternatives except the last.
-                // prevOp is the alternative we're handling a bail out from (initially Begin), and
-                // nextOp is the alternative we will be attempting to reenter into.
-                // 
-                // We will link input check failures from the forwards matching path back to the code
-                // that can handle them.
-                YarrOp* prevOp = beginOp;
-                YarrOp* nextOp = &m_ops[beginOp->m_nextOp];
-                while (nextOp->m_op != OpBodyAlternativeEnd) {
-                    prevOp->m_jumps.link(this);
-
-                    int delta = nextOp->m_alternative->m_minimumSize - prevOp->m_alternative->m_minimumSize;
-                    if (delta)
-                        add32(Imm32(delta), index);
-
-                    // We only get here if an input check fails, it is only worth checking again
-                    // if the next alternative has a minimum size less than the last.
-                    if (delta < 0) {
-                        // FIXME: if we added an extra label to YarrOp, we could avoid needing to
-                        // subtract delta back out, and reduce this code. Should performance test
-                        // the benefit of this.
-                        Jump fail = jumpIfNoAvailableInput();
-                        sub32(Imm32(delta), index);
-                        jump(nextOp->m_reentry);
-                        fail.link(this);
-                    }
-                    prevOp = nextOp;
-                    nextOp = &m_ops[nextOp->m_nextOp];
-                }
-
-                // We fall through to here if there is insufficient input to run the last alternative.
-
-                // If there is insufficient input to run the last alternative, then for 'once through'
-                // alternatives we are done - just jump back up into the forwards matching path at the End.
-                if (onceThrough) {
-                    op.m_jumps.linkTo(endOp.m_reentry, this);
-                    jump(endOp.m_reentry);
-                    break;
-                }
-
-                // For repeating alternatives, link any input check failure from the last alternative to
-                // this point.
-                op.m_jumps.link(this);
-
-                bool needsToUpdateMatchStart = !m_pattern.m_body->m_hasFixedSize;
-
-                // Check for cases where input position is already incremented by 1 for the last
-                // alternative (this is particularly useful where the minimum size of the body
-                // disjunction is 0, e.g. /a*|b/).
-                if (needsToUpdateMatchStart && alternative->m_minimumSize == 1) {
-                    // index is already incremented by 1, so just store it now!
-                    store32(index, Address(output));
-                    needsToUpdateMatchStart = false;
-                }
-
-                // Check whether there is sufficient input to loop. Increment the input position by
-                // one, and check. Also add in the minimum disjunction size before checking - there
-                // is no point in looping if we're just going to fail all the input checks around
-                // the next iteration.
-                int deltaLastAlternativeToBodyMinimumPlusOne = (m_pattern.m_body->m_minimumSize + 1) - alternative->m_minimumSize;
-                if (deltaLastAlternativeToBodyMinimumPlusOne)
-                    add32(Imm32(deltaLastAlternativeToBodyMinimumPlusOne), index);
-                Jump matchFailed = jumpIfNoAvailableInput();
-
-                if (needsToUpdateMatchStart) {
-                    if (!m_pattern.m_body->m_minimumSize)
-                        store32(index, Address(output));
-                    else {
-                        move(index, regT0);
-                        sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0);
-                        store32(regT0, Address(output));
-                    }
-                }
-
-                // Calculate how much more input the first alternative requires than the minimum
-                // for the body as a whole. If no more is needed then we dont need an additional
-                // input check here - jump straight back up to the start of the first alternative.
-                int deltaBodyMinimumToFirstAlternative = beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize;
-                if (!deltaBodyMinimumToFirstAlternative)
-                    jump(beginOp->m_reentry);
-                else {
-                    add32(Imm32(deltaBodyMinimumToFirstAlternative), index);
-                    checkInput().linkTo(beginOp->m_reentry, this);
-                    jump(firstInputCheckFailed);
-                }
-
-                // We jump to here if we iterate to the point that there is insufficient input to
-                // run any matches, and need to return a failure state from JIT code.
-                matchFailed.link(this);
-
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-                move(TrustedImm32(-1), returnRegister);
-                generateReturn();
-                break;
-            }
-            case OpBodyAlternativeEnd: {
-                // We should never backtrack back into a body disjunction.
-                ASSERT(m_backtrackingState.isEmpty());
-
-                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                m_checked += priorAlternative->m_minimumSize;
-                break;
-            }
-
-            // OpSimpleNestedAlternativeBegin/Next/End
-            // OpNestedAlternativeBegin/Next/End
-            //
-            // Generate code for when we backtrack back out of an alternative into
-            // a Begin or Next node, or when the entry input count check fails. If
-            // there are more alternatives we need to jump to the next alternative,
-            // if not we backtrack back out of the current set of parentheses.
-            //
-            // In the case of non-simple nested assertions we need to also link the
-            // 'return address' appropriately to backtrack back out into the correct
-            // alternative.
-            case OpSimpleNestedAlternativeBegin:
-            case OpSimpleNestedAlternativeNext:
-            case OpNestedAlternativeBegin:
-            case OpNestedAlternativeNext: {
-                YarrOp& nextOp = m_ops[op.m_nextOp];
-                bool isBegin = op.m_previousOp == notFound;
-                bool isLastAlternative = nextOp.m_nextOp == notFound;
-                ASSERT(isBegin == (op.m_op == OpSimpleNestedAlternativeBegin || op.m_op == OpNestedAlternativeBegin));
-                ASSERT(isLastAlternative == (nextOp.m_op == OpSimpleNestedAlternativeEnd || nextOp.m_op == OpNestedAlternativeEnd));
-
-                // Treat an input check failure the same as a failed match.
-                m_backtrackingState.append(op.m_jumps);
-
-                // Set the backtracks to jump to the appropriate place. We may need
-                // to link the backtracks in one of three different way depending on
-                // the type of alternative we are dealing with:
-                //  - A single alternative, with no simplings.
-                //  - The last alternative of a set of two or more.
-                //  - An alternative other than the last of a set of two or more.
-                //
-                // In the case of a single alternative on its own, we don't need to
-                // jump anywhere - if the alternative fails to match we can just
-                // continue to backtrack out of the parentheses without jumping.
-                //
-                // In the case of the last alternative in a set of more than one, we
-                // need to jump to return back out to the beginning. We'll do so by
-                // adding a jump to the End node's m_jumps list, and linking this
-                // when we come to generate the Begin node. For alternatives other
-                // than the last, we need to jump to the next alternative.
-                //
-                // If the alternative had adjusted the input position we must link
-                // backtracking to here, correct, and then jump on. If not we can
-                // link the backtracks directly to their destination.
-                if (op.m_checkAdjust) {
-                    // Handle the cases where we need to link the backtracks here.
-                    m_backtrackingState.link(this);
-                    sub32(Imm32(op.m_checkAdjust), index);
-                    if (!isLastAlternative) {
-                        // An alternative that is not the last should jump to its successor.
-                        jump(nextOp.m_reentry);
-                    } else if (!isBegin) {
-                        // The last of more than one alternatives must jump back to the begnning.
-                        nextOp.m_jumps.append(jump());
-                    } else {
-                        // A single alternative on its own can fall through.
-                        m_backtrackingState.fallthrough();
-                    }
-                } else {
-                    // Handle the cases where we can link the backtracks directly to their destinations.
-                    if (!isLastAlternative) {
-                        // An alternative that is not the last should jump to its successor.
-                        m_backtrackingState.linkTo(nextOp.m_reentry, this);
-                    } else if (!isBegin) {
-                        // The last of more than one alternatives must jump back to the begnning.
-                        m_backtrackingState.takeBacktracksToJumpList(nextOp.m_jumps, this);
-                    }
-                    // In the case of a single alternative on its own do nothing - it can fall through.
-                }
-
-                // At this point we've handled the backtracking back into this node.
-                // Now link any backtracks that need to jump to here.
-
-                // For non-simple alternatives, link the alternative's 'return address'
-                // so that we backtrack back out into the previous alternative.
-                if (op.m_op == OpNestedAlternativeNext)
-                    m_backtrackingState.append(op.m_returnAddress);
-
-                // If there is more than one alternative, then the last alternative will
-                // have planted a jump to be linked to the end. This jump was added to the
-                // End node's m_jumps list. If we are back at the beginning, link it here.
-                if (isBegin) {
-                    YarrOp* endOp = &m_ops[op.m_nextOp];
-                    while (endOp->m_nextOp != notFound) {
-                        ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
-                        endOp = &m_ops[endOp->m_nextOp];
-                    }
-                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
-                    m_backtrackingState.append(endOp->m_jumps);
-                }
-
-                if (!isBegin) {
-                    YarrOp& lastOp = m_ops[op.m_previousOp];
-                    m_checked += lastOp.m_checkAdjust;
-                }
-                m_checked -= op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeEnd:
-            case OpNestedAlternativeEnd: {
-                PatternTerm* term = op.m_term;
-
-                // If we backtrack into the end of a simple subpattern do nothing;
-                // just continue through into the last alternative. If we backtrack
-                // into the end of a non-simple set of alterntives we need to jump
-                // to the backtracking return address set up during generation.
-                if (op.m_op == OpNestedAlternativeEnd) {
-                    m_backtrackingState.link(this);
-
-                    // Plant a jump to the return address.
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    loadFromFrameAndJump(alternativeFrameLocation);
-
-                    // Link the DataLabelPtr associated with the end of the last
-                    // alternative to this point.
-                    m_backtrackingState.append(op.m_returnAddress);
-                }
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked += lastOp.m_checkAdjust;
-                break;
-            }
-
-            // OpParenthesesSubpatternOnceBegin/End
-            //
-            // When we are backtracking back out of a capturing subpattern we need
-            // to clear the start index in the matches output array, to record that
-            // this subpattern has not been captured.
-            //
-            // When backtracking back out of a Greedy quantified subpattern we need
-            // to catch this, and try running the remainder of the alternative after
-            // the subpattern again, skipping the parentheses.
-            //
-            // Upon backtracking back into a quantified set of parentheses we need to
-            // check whether we were currently skipping the subpattern. If not, we
-            // can backtrack into them, if we were we need to either backtrack back
-            // out of the start of the parentheses, or jump back to the forwards
-            // matching start, depending of whether the match is Greedy or NonGreedy.
-            case OpParenthesesSubpatternOnceBegin: {
-                PatternTerm* term = op.m_term;
-                ASSERT(term->quantityCount == 1);
-
-                // We only need to backtrack to thispoint if capturing or greedy.
-                if (term->capture() || term->quantityType == QuantifierGreedy) {
-                    m_backtrackingState.link(this);
-
-                    // If capturing, clear the capture (we only need to reset start).
-                    if (term->capture())
-                        store32(TrustedImm32(-1), Address(output, (term->parentheses.subpatternId << 1) * sizeof(int)));
-
-                    // If Greedy, jump to the end.
-                    if (term->quantityType == QuantifierGreedy) {
-                        // Clear the flag in the stackframe indicating we ran through the subpattern.
-                        unsigned parenthesesFrameLocation = term->frameLocation;
-                        storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
-                        // Jump to after the parentheses, skipping the subpattern.
-                        jump(m_ops[op.m_nextOp].m_reentry);
-                        // A backtrack from after the parentheses, when skipping the subpattern,
-                        // will jump back to here.
-                        op.m_jumps.link(this);
-                    }
-
-                    m_backtrackingState.fallthrough();
-                }
-                break;
-            }
-            case OpParenthesesSubpatternOnceEnd: {
-                PatternTerm* term = op.m_term;
-
-                if (term->quantityType != QuantifierFixedCount) {
-                    m_backtrackingState.link(this);
-
-                    // Check whether we should backtrack back into the parentheses, or if we
-                    // are currently in a state where we had skipped over the subpattern
-                    // (in which case the flag value on the stack will be -1).
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1));
-
-                    if (term->quantityType == QuantifierGreedy) {
-                        // For Greedy parentheses, we skip after having already tried going
-                        // through the subpattern, so if we get here we're done.
-                        YarrOp& beginOp = m_ops[op.m_previousOp];
-                        beginOp.m_jumps.append(hadSkipped);
-                    } else {
-                        // For NonGreedy parentheses, we try skipping the subpattern first,
-                        // so if we get here we need to try running through the subpattern
-                        // next. Jump back to the start of the parentheses in the forwards
-                        // matching path.
-                        ASSERT(term->quantityType == QuantifierNonGreedy);
-                        YarrOp& beginOp = m_ops[op.m_previousOp];
-                        hadSkipped.linkTo(beginOp.m_reentry, this);
-                    }
-
-                    m_backtrackingState.fallthrough();
-                }
-
-                m_backtrackingState.append(op.m_jumps);
-                break;
-            }
-
-            // OpParenthesesSubpatternTerminalBegin/End
-            //
-            // Terminal subpatterns will always match - there is nothing after them to
-            // force a backtrack, and they have a minimum count of 0, and as such will
-            // always produce an acceptable result.
-            case OpParenthesesSubpatternTerminalBegin: {
-                // We will backtrack to this point once the subpattern cannot match any
-                // more. Since no match is accepted as a successful match (we are Greedy
-                // quantified with a minimum of zero) jump back to the forwards matching
-                // path at the end.
-                YarrOp& endOp = m_ops[op.m_nextOp];
-                m_backtrackingState.linkTo(endOp.m_reentry, this);
-                break;
-            }
-            case OpParenthesesSubpatternTerminalEnd:
-                // We should never be backtracking to here (hence the 'terminal' in the name).
-                ASSERT(m_backtrackingState.isEmpty());
-                m_backtrackingState.append(op.m_jumps);
-                break;
-
-            // OpParentheticalAssertionBegin/End
-            case OpParentheticalAssertionBegin: {
-                PatternTerm* term = op.m_term;
-                YarrOp& endOp = m_ops[op.m_nextOp];
-
-                // We need to handle the backtracks upon backtracking back out
-                // of a parenthetical assertion if either we need to correct
-                // the input index, or the assertion was inverted.
-                if (op.m_checkAdjust || term->invert()) {
-                     m_backtrackingState.link(this);
-
-                    if (op.m_checkAdjust)
-                        add32(Imm32(op.m_checkAdjust), index);
-
-                    // In an inverted assertion failure to match the subpattern
-                    // is treated as a successful match - jump to the end of the
-                    // subpattern. We already have adjusted the input position
-                    // back to that before the assertion, which is correct.
-                    if (term->invert())
-                        jump(endOp.m_reentry);
-
-                    m_backtrackingState.fallthrough();
-                }
-
-                // The End node's jump list will contain any backtracks into
-                // the end of the assertion. Also, if inverted, we will have
-                // added the failure caused by a successful match to this.
-                m_backtrackingState.append(endOp.m_jumps);
-
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpParentheticalAssertionEnd: {
-                // FIXME: We should really be clearing any nested subpattern
-                // matches on bailing out from after the pattern. Firefox has
-                // this bug too (presumably because they use YARR!)
-
-                // Never backtrack into an assertion; later failures bail to before the begin.
-                m_backtrackingState.takeBacktracksToJumpList(op.m_jumps, this);
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                break;
-            }
-
-            case OpMatchFailed:
-                break;
-            }
-
-        } while (opIndex);
-    }
-
-    // Compilation methods:
-    // ====================
-
-    // opCompileParenthesesSubpattern
-    // Emits ops for a subpattern (set of parentheses). These consist
-    // of a set of alternatives wrapped in an outer set of nodes for
-    // the parentheses.
-    // Supported types of parentheses are 'Once' (quantityCount == 1)
-    // and 'Terminal' (non-capturing parentheses quantified as greedy
-    // and infinite).
-    // Alternatives will use the 'Simple' set of ops if either the
-    // subpattern is terminal (in which case we will never need to
-    // backtrack), or if the subpattern only contains one alternative.
-    void opCompileParenthesesSubpattern(PatternTerm* term)
-    {
-        YarrOpCode parenthesesBeginOpCode;
-        YarrOpCode parenthesesEndOpCode;
-        YarrOpCode alternativeBeginOpCode = OpSimpleNestedAlternativeBegin;
-        YarrOpCode alternativeNextOpCode = OpSimpleNestedAlternativeNext;
-        YarrOpCode alternativeEndOpCode = OpSimpleNestedAlternativeEnd;
-
-        // We can currently only compile quantity 1 subpatterns that are
-        // not copies. We generate a copy in the case of a range quantifier,
-        // e.g. /(?:x){3,9}/, or /(?:x)+/ (These are effectively expanded to
-        // /(?:x){3,3}(?:x){0,6}/ and /(?:x)(?:x)*/ repectively). The problem
-        // comes where the subpattern is capturing, in which case we would
-        // need to restore the capture from the first subpattern upon a
-        // failure in the second.
-        if (term->quantityCount == 1 && !term->parentheses.isCopy) {
-            // Select the 'Once' nodes.
-            parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin;
-            parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd;
-
-            // If there is more than one alternative we cannot use the 'simple' nodes.
-            if (term->parentheses.disjunction->m_alternatives.size() != 1) {
-                alternativeBeginOpCode = OpNestedAlternativeBegin;
-                alternativeNextOpCode = OpNestedAlternativeNext;
-                alternativeEndOpCode = OpNestedAlternativeEnd;
-            }
-        } else if (term->parentheses.isTerminal) {
-            // Select the 'Terminal' nodes.
-            parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin;
-            parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd;
-        } else {
-            // This subpattern is not supported by the JIT.
-            m_shouldFallBack = true;
-            return;
-        }
-
-        size_t parenBegin = m_ops.size();
-        m_ops.append(parenthesesBeginOpCode);
-
-        m_ops.append(alternativeBeginOpCode);
-        m_ops.last().m_previousOp = notFound;
-        m_ops.last().m_term = term;
-        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
-        for (unsigned i = 0; i < alternatives.size(); ++i) {
-            size_t lastOpIndex = m_ops.size() - 1;
-
-            PatternAlternative* nestedAlternative = alternatives[i];
-            opCompileAlternative(nestedAlternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(alternativeNextOpCode));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = nestedAlternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            thisOp.m_term = term;
-        }
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == alternativeNextOpCode);
-        lastOp.m_op = alternativeEndOpCode;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = notFound;
-
-        size_t parenEnd = m_ops.size();
-        m_ops.append(parenthesesEndOpCode);
-
-        m_ops[parenBegin].m_term = term;
-        m_ops[parenBegin].m_previousOp = notFound;
-        m_ops[parenBegin].m_nextOp = parenEnd;
-        m_ops[parenEnd].m_term = term;
-        m_ops[parenEnd].m_previousOp = parenBegin;
-        m_ops[parenEnd].m_nextOp = notFound;
-    }
-
-    // opCompileParentheticalAssertion
-    // Emits ops for a parenthetical assertion. These consist of an
-    // OpSimpleNestedAlternativeBegin/Next/End set of nodes wrapping
-    // the alternatives, with these wrapped by an outer pair of
-    // OpParentheticalAssertionBegin/End nodes.
-    // We can always use the OpSimpleNestedAlternative nodes in the
-    // case of parenthetical assertions since these only ever match
-    // once, and will never backtrack back into the assertion.
-    void opCompileParentheticalAssertion(PatternTerm* term)
-    {
-        size_t parenBegin = m_ops.size();
-        m_ops.append(OpParentheticalAssertionBegin);
-
-        m_ops.append(OpSimpleNestedAlternativeBegin);
-        m_ops.last().m_previousOp = notFound;
-        m_ops.last().m_term = term;
-        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
-        for (unsigned i = 0; i < alternatives.size(); ++i) {
-            size_t lastOpIndex = m_ops.size() - 1;
-
-            PatternAlternative* nestedAlternative = alternatives[i];
-            opCompileAlternative(nestedAlternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(OpSimpleNestedAlternativeNext));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = nestedAlternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            thisOp.m_term = term;
-        }
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == OpSimpleNestedAlternativeNext);
-        lastOp.m_op = OpSimpleNestedAlternativeEnd;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = notFound;
-
-        size_t parenEnd = m_ops.size();
-        m_ops.append(OpParentheticalAssertionEnd);
-
-        m_ops[parenBegin].m_term = term;
-        m_ops[parenBegin].m_previousOp = notFound;
-        m_ops[parenBegin].m_nextOp = parenEnd;
-        m_ops[parenEnd].m_term = term;
-        m_ops[parenEnd].m_previousOp = parenBegin;
-        m_ops[parenEnd].m_nextOp = notFound;
-    }
-
-    // opCompileAlternative
-    // Called to emit nodes for all terms in an alternative.
-    void opCompileAlternative(PatternAlternative* alternative)
-    {
-        optimizeAlternative(alternative);
-
-        for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
-            PatternTerm* term = &alternative->m_terms[i];
-
-            switch (term->type) {
-            case PatternTerm::TypeParenthesesSubpattern:
-                opCompileParenthesesSubpattern(term);
-                break;
-
-            case PatternTerm::TypeParentheticalAssertion:
-                opCompileParentheticalAssertion(term);
-                break;
-
-            default:
-                m_ops.append(term);
-            }
-        }
-    }
-
-    // opCompileBody
-    // This method compiles the body disjunction of the regular expression.
-    // The body consists of two sets of alternatives - zero or more 'once
-    // through' (BOL anchored) alternatives, followed by zero or more
-    // repeated alternatives.
-    // For each of these two sets of alteratives, if not empty they will be
-    // wrapped in a set of OpBodyAlternativeBegin/Next/End nodes (with the
-    // 'begin' node referencing the first alternative, and 'next' nodes
-    // referencing any further alternatives. The begin/next/end nodes are
-    // linked together in a doubly linked list. In the case of repeating
-    // alternatives, the end node is also linked back to the beginning.
-    // If no repeating alternatives exist, then a OpMatchFailed node exists
-    // to return the failing result.
-    void opCompileBody(PatternDisjunction* disjunction)
-    {
-        Vector& alternatives =  disjunction->m_alternatives;
-        size_t currentAlternativeIndex = 0;
-
-        // Emit the 'once through' alternatives.
-        if (alternatives.size() && alternatives[0]->onceThrough()) {
-            m_ops.append(YarrOp(OpBodyAlternativeBegin));
-            m_ops.last().m_previousOp = notFound;
-
-            do {
-                size_t lastOpIndex = m_ops.size() - 1;
-                PatternAlternative* alternative = alternatives[currentAlternativeIndex];
-                opCompileAlternative(alternative);
-
-                size_t thisOpIndex = m_ops.size();
-                m_ops.append(YarrOp(OpBodyAlternativeNext));
-
-                YarrOp& lastOp = m_ops[lastOpIndex];
-                YarrOp& thisOp = m_ops[thisOpIndex];
-
-                lastOp.m_alternative = alternative;
-                lastOp.m_nextOp = thisOpIndex;
-                thisOp.m_previousOp = lastOpIndex;
-                
-                ++currentAlternativeIndex;
-            } while (currentAlternativeIndex < alternatives.size() && alternatives[currentAlternativeIndex]->onceThrough());
-
-            YarrOp& lastOp = m_ops.last();
-
-            ASSERT(lastOp.m_op == OpBodyAlternativeNext);
-            lastOp.m_op = OpBodyAlternativeEnd;
-            lastOp.m_alternative = 0;
-            lastOp.m_nextOp = notFound;
-        }
-
-        if (currentAlternativeIndex == alternatives.size()) {
-            m_ops.append(YarrOp(OpMatchFailed));
-            return;
-        }
-
-        // Emit the repeated alternatives.
-        size_t repeatLoop = m_ops.size();
-        m_ops.append(YarrOp(OpBodyAlternativeBegin));
-        m_ops.last().m_previousOp = notFound;
-        do {
-            size_t lastOpIndex = m_ops.size() - 1;
-            PatternAlternative* alternative = alternatives[currentAlternativeIndex];
-            ASSERT(!alternative->onceThrough());
-            opCompileAlternative(alternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(OpBodyAlternativeNext));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = alternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            
-            ++currentAlternativeIndex;
-        } while (currentAlternativeIndex < alternatives.size());
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == OpBodyAlternativeNext);
-        lastOp.m_op = OpBodyAlternativeEnd;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = repeatLoop;
-    }
-
-    void generateEnter()
-    {
-#if WTF_CPU_X86_64
-        push(X86Registers::ebp);
-        move(stackPointerRegister, X86Registers::ebp);
-        push(X86Registers::ebx);
-#elif WTF_CPU_X86
-        push(X86Registers::ebp);
-        move(stackPointerRegister, X86Registers::ebp);
-        // TODO: do we need spill registers to fill the output pointer if there are no sub captures?
-        push(X86Registers::ebx);
-        push(X86Registers::edi);
-        push(X86Registers::esi);
-        // load output into edi (2 = saved ebp + return address).
-    #if WTF_COMPILER_MSVC
-        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input);
-        loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index);
-        loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length);
-        loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output);
-    #else
-        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
-    #endif
-#elif WTF_CPU_ARM
-        push(ARMRegisters::r4);
-        push(ARMRegisters::r5);
-        push(ARMRegisters::r6);
-#if WTF_CPU_ARM_TRADITIONAL
-        push(ARMRegisters::r8); // scratch register
-#endif
-        move(ARMRegisters::r3, output);
-#elif WTF_CPU_SH4
-        push(SH4Registers::r11);
-        push(SH4Registers::r13);
-#elif WTF_CPU_MIPS
-        // Do nothing.
-#endif
-    }
-
-    void generateReturn()
-    {
-#if WTF_CPU_X86_64
-        pop(X86Registers::ebx);
-        pop(X86Registers::ebp);
-#elif WTF_CPU_X86
-        pop(X86Registers::esi);
-        pop(X86Registers::edi);
-        pop(X86Registers::ebx);
-        pop(X86Registers::ebp);
-#elif WTF_CPU_ARM
-#if WTF_CPU_ARM_TRADITIONAL
-        pop(ARMRegisters::r8); // scratch register
-#endif
-        pop(ARMRegisters::r6);
-        pop(ARMRegisters::r5);
-        pop(ARMRegisters::r4);
-#elif WTF_CPU_SH4
-        pop(SH4Registers::r13);
-        pop(SH4Registers::r11);
-#elif WTF_CPU_MIPS
-        // Do nothing
-#endif
-        ret();
-    }
-
-public:
-    YarrGenerator(YarrPattern& pattern)
-        : m_pattern(pattern)
-        , m_shouldFallBack(false)
-        , m_checked(0)
-    {
-    }
-
-    void compile(JSGlobalData* globalData, YarrCodeBlock& jitObject)
-    {
-        generateEnter();
-
-        if (!m_pattern.m_body->m_hasFixedSize)
-            store32(index, Address(output));
-
-        if (m_pattern.m_body->m_callFrameSize)
-            subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-
-        // Compile the pattern to the internal 'YarrOp' representation.
-        opCompileBody(m_pattern.m_body);
-
-        // If we encountered anything we can't handle in the JIT code
-        // (e.g. backreferences) then return early.
-        if (m_shouldFallBack) {
-            jitObject.setFallBack(true);
-            return;
-        }
-
-        generate();
-        backtrack();
-
-        // Link & finalize the code.
-        // XXX yarr-oom
-        ExecutablePool *pool;
-        bool ok;
-        LinkBuffer linkBuffer(this, globalData->regexAllocator, &pool, &ok);
-        m_backtrackingState.linkDataLabels(linkBuffer);
-        jitObject.set(linkBuffer.finalizeCode());
-        jitObject.setFallBack(m_shouldFallBack);
-    }
-
-private:
-    YarrPattern& m_pattern;
-
-    // Used to detect regular expression constructs that are not currently
-    // supported in the JIT; fall back to the interpreter when this is detected.
-    bool m_shouldFallBack;
-
-    // The regular expression expressed as a linear sequence of operations.
-    Vector m_ops;
-
-    // This records the current input offset being applied due to the current
-    // set of alternatives we are nested within. E.g. when matching the
-    // character 'b' within the regular expression /abc/, we will know that
-    // the minimum size for the alternative is 3, checked upon entry to the
-    // alternative, and that 'b' is at offset 1 from the start, and as such
-    // when matching 'b' we need to apply an offset of -2 to the load.
-    //
-    // FIXME: This should go away. Rather than tracking this value throughout
-    // code generation, we should gather this information up front & store it
-    // on the YarrOp structure.
-    int m_checked;
-
-    // This class records state whilst generating the backtracking path of code.
-    BacktrackingState m_backtrackingState;
-};
-
-void jitCompile(YarrPattern& pattern, JSGlobalData* globalData, YarrCodeBlock& jitObject)
-{
-    YarrGenerator(pattern).compile(globalData, jitObject);
-}
-
-int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output)
-{
-    return jitObject.execute(input, start, length, output);
-}
-
-}}
-
-#endif
diff --git a/js/src/yarr/YarrJIT.h b/js/src/yarr/YarrJIT.h
deleted file mode 100644
index 4f0f47f8c548..000000000000
--- a/js/src/yarr/YarrJIT.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- 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.
- *
- * 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef YarrJIT_h
-#define YarrJIT_h
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_YARR_JIT
-
-#include "assembler/assembler/MacroAssembler.h"
-#include "YarrPattern.h"
-
-#if WTF_CPU_X86 && !WTF_COMPILER_MSVC
-#define YARR_CALL __attribute__ ((regparm (3)))
-#else
-#define YARR_CALL
-#endif
-
-namespace JSC {
-
-class JSGlobalData;
-class ExecutablePool;
-
-namespace Yarr {
-
-class YarrCodeBlock {
-    typedef int (*YarrJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
-
-public:
-    YarrCodeBlock()
-        : m_needFallBack(false)
-    {
-    }
-
-    ~YarrCodeBlock()
-    {
-    }
-
-    void setFallBack(bool fallback) { m_needFallBack = fallback; }
-    bool isFallBack() { return m_needFallBack; }
-    void set(MacroAssembler::CodeRef ref) { m_ref = ref; }
-
-    int execute(const UChar* input, unsigned start, unsigned length, int* output)
-    {
-        return JS_EXTENSION((reinterpret_cast(m_ref.m_code.executableAddress()))(input, start, length, output));
-    }
-
-#if ENABLE_REGEXP_TRACING
-    void *getAddr() { return m_ref.m_code.executableAddress(); }
-#endif
-
-    void release() { m_ref.release(); }
-
-private:
-    MacroAssembler::CodeRef m_ref;
-    bool m_needFallBack;
-};
-
-void jitCompile(YarrPattern&, JSGlobalData*, YarrCodeBlock& jitObject);
-int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output);
-
-} } // namespace JSC::Yarr
-
-#endif
-
-#endif // YarrJIT_h
diff --git a/js/src/yarr/jswtfbridge.h b/js/src/yarr/jswtfbridge.h
new file mode 100644
index 000000000000..b38f76ead5a8
--- /dev/null
+++ b/js/src/yarr/jswtfbridge.h
@@ -0,0 +1,61 @@
+/* -*- 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 *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
+ * June 12, 2009.
+ *
+ * The Initial Developer of the Original Code is
+ *   the Mozilla Corporation.
+ *
+ * Contributor(s):
+ *   Chris Leary 
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jswtfbridge_h__
+#define jswtfbridge_h__
+
+/*
+ * The JS/WTF Bridge to Bona-fide Quality.
+ */
+
+#include "assembler/wtf/Platform.h"
+#include "jsstr.h"
+#include "jsprvtd.h"
+#include "jstl.h"
+
+typedef jschar UChar;
+typedef JSLinearString UString;
+
+class Unicode {
+  public:
+    static UChar toUpper(UChar c) { return JS_TOUPPER(c); }
+    static UChar toLower(UChar c) { return JS_TOLOWER(c); }
+};
+
+#endif
diff --git a/js/src/yarr/pcre/AUTHORS b/js/src/yarr/pcre/AUTHORS
new file mode 100644
index 000000000000..dbac2a54834b
--- /dev/null
+++ b/js/src/yarr/pcre/AUTHORS
@@ -0,0 +1,12 @@
+Originally written by:  Philip Hazel
+Email local part:       ph10
+Email domain:           cam.ac.uk
+
+University of Cambridge Computing Service,
+Cambridge, England. Phone: +44 1223 334714.
+
+Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
+
+Adapted for JavaScriptCore and WebKit by Apple Inc.
+
+Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/js/src/yarr/pcre/COPYING b/js/src/yarr/pcre/COPYING
new file mode 100644
index 000000000000..6ffdc24342d5
--- /dev/null
+++ b/js/src/yarr/pcre/COPYING
@@ -0,0 +1,35 @@
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed.
+
+Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * 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.
+
+    * Neither the name of the University of Cambridge nor the name of Apple
+      Inc. nor the names of their contributors may be used to endorse or
+      promote products derived from this software without specific prior
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
diff --git a/js/src/yarr/pcre/chartables.c b/js/src/yarr/pcre/chartables.c
new file mode 100644
index 000000000000..5c99db0b980f
--- /dev/null
+++ b/js/src/yarr/pcre/chartables.c
@@ -0,0 +1,96 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* This file is automatically written by the dftables auxiliary 
+program. If you edit it by hand, you might like to edit the Makefile to 
+prevent its ever being regenerated.
+
+This file contains the default tables for characters with codes less than
+128 (ASCII characters). These tables are used when no external tables are
+passed to PCRE. */
+
+const unsigned char jsc_pcre_default_tables[480] = {
+
+/* This table is a lower casing table. */
+
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
+  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+/* This table is a case flipping table. */
+
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
+  0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
+  0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 
+  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
+  0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+/* This table contains bit maps for various character classes.
+Each map is 32 bytes long and the bits run from the least
+significant end of each byte. The classes are: space, digit, word. */
+
+  0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
+  0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* This table identifies various classes of character by individual bits:
+  0x01   white space character
+  0x08   hexadecimal digit
+  0x10   alphanumeric or '_'
+*/
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*   0-  7 */
+  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /*   8- 15 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  16- 23 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  24- 31 */
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*    - '  */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  ( - /  */
+  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,  /*  0 - 7  */
+  0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  8 - ?  */
+  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  @ - G  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  H - O  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  P - W  */
+  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,  /*  X - _  */
+  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  ` - g  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  h - o  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  p - w  */
+  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /*  x -127 */
+
+
+/* End of chartables.c */
diff --git a/js/src/yarr/pcre/dftables b/js/src/yarr/pcre/dftables
new file mode 100644
index 000000000000..669b948ffc91
--- /dev/null
+++ b/js/src/yarr/pcre/dftables
@@ -0,0 +1,273 @@
+#!/usr/bin/perl -w
+#
+# This is JavaScriptCore's variant of the PCRE library. While this library
+# started out as a copy of PCRE, many of the features of PCRE have been
+# removed. This library now supports only the regular expression features
+# required by the JavaScript language specification, and has only the functions
+# needed by JavaScriptCore and the rest of WebKit.
+# 
+#                  Originally written by Philip Hazel
+#            Copyright (c) 1997-2006 University of Cambridge
+#  Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
+# 
+#     * Redistributions of source code must retain the above copyright notice,
+#       this list of conditions and the following disclaimer.
+# 
+#     * 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.
+# 
+#     * Neither the name of the University of Cambridge nor the names of its
+#       contributors may be used to endorse or promote products derived from
+#       this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
+# -----------------------------------------------------------------------------
+
+# This is a freestanding support program to generate a file containing
+# character tables. The tables are built according to the default C
+# locale.
+
+use strict;
+
+use File::Basename;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+
+sub readHeaderValues();
+
+my %pcre_internal;
+
+if (scalar(@ARGV) < 1) {
+    print STDERR "Usage: ", basename($0), " [--preprocessor=program] output-file\n";
+    exit 1;
+}
+
+my $outputFile;
+my $preprocessor;
+GetOptions('preprocessor=s' => \$preprocessor);
+if (not $preprocessor) {
+    $preprocessor = "cpp";
+}
+
+$outputFile = $ARGV[0];
+die('Must specify output file.') unless defined($outputFile);
+
+readHeaderValues();
+
+open(OUT, ">", $outputFile) or die "$!";
+binmode(OUT);
+
+printf(OUT
+    "/*************************************************\n" .
+    "*      Perl-Compatible Regular Expressions       *\n" .
+    "*************************************************/\n\n" .
+    "/* This file is automatically written by the dftables auxiliary \n" .
+    "program. If you edit it by hand, you might like to edit the Makefile to \n" .
+    "prevent its ever being regenerated.\n\n");
+printf(OUT
+    "This file contains the default tables for characters with codes less than\n" .
+    "128 (ASCII characters). These tables are used when no external tables are\n" .
+    "passed to PCRE. */\n\n" .
+    "const unsigned char jsc_pcre_default_tables[%d] = {\n\n" .
+    "/* This table is a lower casing table. */\n\n", $pcre_internal{tables_length});
+
+if ($pcre_internal{lcc_offset} != 0) {
+    die "lcc_offset != 0";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        printf(OUT "\n  ");
+    }
+    printf(OUT "0x%02X", ord(lc(chr($i))));
+    if ($i != 127) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT "/* This table is a case flipping table. */\n\n");
+
+if ($pcre_internal{fcc_offset} != 128) {
+  die "fcc_offset != 128";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        printf(OUT "\n  ");
+    }
+    my $c = chr($i);
+    printf(OUT "0x%02X", $c =~ /[[:lower:]]/ ? ord(uc($c)) : ord(lc($c)));
+    if ($i != 127) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT
+    "/* This table contains bit maps for various character classes.\n" .
+    "Each map is 32 bytes long and the bits run from the least\n" .
+    "significant end of each byte. The classes are: space, digit, word. */\n\n");
+
+if ($pcre_internal{cbits_offset} != $pcre_internal{fcc_offset} + 128) {
+    die "cbits_offset != fcc_offset + 128";
+}
+
+my @cbit_table = (0) x $pcre_internal{cbit_length};
+for (my $i = ord('0'); $i <= ord('9'); $i++) {
+    $cbit_table[$pcre_internal{cbit_digit} + $i / 8] |= 1 << ($i & 7);
+}
+$cbit_table[$pcre_internal{cbit_word} + ord('_') / 8] |= 1 << (ord('_') & 7);
+for (my $i = 0; $i < 128; $i++) {
+    my $c = chr($i);
+    if ($c =~ /[[:alnum:]]/) {
+        $cbit_table[$pcre_internal{cbit_word} + $i / 8] |= 1 << ($i & 7);
+    }
+    if ($c =~ /[[:space:]]/) {
+        $cbit_table[$pcre_internal{cbit_space} + $i / 8] |= 1 << ($i & 7);
+    }
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < $pcre_internal{cbit_length}; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        if (($i & 31) == 0) {
+            printf(OUT "\n");
+        }
+        printf(OUT "\n  ");
+    }
+    printf(OUT "0x%02X", $cbit_table[$i]);
+    if ($i != $pcre_internal{cbit_length} - 1) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT
+    "/* This table identifies various classes of character by individual bits:\n" .
+    "  0x%02x   white space character\n" .
+    "  0x%02x   hexadecimal digit\n" .
+    "  0x%02x   alphanumeric or '_'\n*/\n\n",
+    $pcre_internal{ctype_space}, $pcre_internal{ctype_xdigit}, $pcre_internal{ctype_word});
+
+if ($pcre_internal{ctypes_offset} != $pcre_internal{cbits_offset} + $pcre_internal{cbit_length}) {
+    die "ctypes_offset != cbits_offset + cbit_length";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    my $x = 0;
+    my $c = chr($i);
+    if ($c =~ /[[:space:]]/) {
+        $x += $pcre_internal{ctype_space};
+    }
+    if ($c =~ /[[:xdigit:]]/) {
+        $x += $pcre_internal{ctype_xdigit};
+    }
+    if ($c =~ /[[:alnum:]_]/) {
+        $x += $pcre_internal{ctype_word};
+    }
+    printf(OUT "0x%02X", $x);
+    if ($i != 127) {
+        printf(OUT ", ");
+    } else {
+        printf(OUT "};");
+    }
+    if (($i & 7) == 7) {
+        printf(OUT " /* ");
+        my $d = chr($i - 7);
+        if ($d =~ /[[:print:]]/) {
+            printf(OUT " %c -", $i - 7);
+        } else {
+            printf(OUT "%3d-", $i - 7);
+        }
+        if ($c =~ m/[[:print:]]/) {
+            printf(OUT " %c ", $i);
+        } else {
+            printf(OUT "%3d", $i);
+        }
+        printf(OUT " */\n");
+        if ($i != 127) {
+            printf(OUT "  ");
+        }
+    }
+}
+
+if ($pcre_internal{tables_length} != $pcre_internal{ctypes_offset} + 128) {
+    die "tables_length != ctypes_offset + 128";
+}
+
+printf(OUT "\n\n/* End of chartables.c */\n");
+
+close(OUT);
+
+exit 0;
+
+sub readHeaderValues()
+{
+    my @variables = qw(
+        cbit_digit
+        cbit_length
+        cbit_space
+        cbit_word
+        cbits_offset
+        ctype_space
+        ctype_word
+        ctype_xdigit
+        ctypes_offset
+        fcc_offset
+        lcc_offset
+        tables_length
+    );
+
+    local $/ = undef;
+
+    my $headerPath = File::Spec->catfile(dirname($0), "pcre_internal.h");
+ 
+    my ($fh, $tempFile) = tempfile(
+        basename($0) . "-XXXXXXXX",
+        DIR => File::Spec->tmpdir(),
+        SUFFIX => ".in",
+        UNLINK => 0,
+    );
+
+    print $fh "#define DFTABLES\n\n";
+
+    open(HEADER, "<", $headerPath) or die "$!";
+    print $fh 
; + close(HEADER); + + print $fh "\n\n"; + + for my $v (@variables) { + print $fh "\$pcre_internal{\"$v\"} = $v;\n"; + } + + close($fh); + + open(CPP, "$preprocessor \"$tempFile\" |") or die "$!"; + my $content = ; + close(CPP); + + eval $content; + die "$@" if $@; + unlink $tempFile; +} diff --git a/js/src/yarr/pcre/pcre.h b/js/src/yarr/pcre/pcre.h new file mode 100644 index 000000000000..91d96b784905 --- /dev/null +++ b/js/src/yarr/pcre/pcre.h @@ -0,0 +1,68 @@ +/* This is the public header file for JavaScriptCore's variant of the PCRE +library. While this library started out as a copy of PCRE, many of the +features of PCRE have been removed. This library now supports only the +regular expression features required by the JavaScript language +specification, and has only the functions needed by JavaScriptCore and the +rest of WebKit. + + Copyright (c) 1997-2005 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE. + +#ifndef JSRegExp_h +#define JSRegExp_h + +#include "yarr/jswtfbridge.h" + +struct JSRegExp; +struct JSContext; + +enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase }; +enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline }; + +/* jsRegExpExecute error codes */ +const int JSRegExpErrorNoMatch = -1; +const int JSRegExpErrorHitLimit = -2; +const int JSRegExpErrorInternal = -4; + +JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, + JSRegExpIgnoreCaseOption, JSRegExpMultilineOption, + unsigned* numSubpatterns, int *error); + +int jsRegExpExecute(JSContext *, const JSRegExp*, + const UChar* subject, int subjectLength, int startOffset, + int* offsetsVector, int offsetsVectorLength); + +void jsRegExpFree(JSRegExp*); + +#endif diff --git a/js/src/yarr/pcre/pcre.pri b/js/src/yarr/pcre/pcre.pri new file mode 100644 index 000000000000..4f59e17f4d91 --- /dev/null +++ b/js/src/yarr/pcre/pcre.pri @@ -0,0 +1,12 @@ +# Perl Compatible Regular Expressions - Qt4 build info +VPATH += $$PWD +INCLUDEPATH += $$PWD $$OUTPUT_DIR/JavaScriptCore/tmp +DEPENDPATH += $$PWD + +SOURCES += \ + pcre_compile.cpp \ + pcre_exec.cpp \ + pcre_tables.cpp \ + pcre_ucp_searchfuncs.cpp \ + pcre_xclass.cpp + diff --git a/js/src/yarr/pcre/pcre_compile.cpp b/js/src/yarr/pcre/pcre_compile.cpp new file mode 100644 index 000000000000..8d273bcbe5a6 --- /dev/null +++ b/js/src/yarr/pcre/pcre_compile.cpp @@ -0,0 +1,2702 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + Copyright (C) 2007 Eric Seidel + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains the external function jsRegExpExecute(), along with +supporting internal functions that are not used by other modules. */ + +#include "pcre_internal.h" + +#include +#include "yarr/wtf/ASCIICType.h" +#include "jsvector.h" + +using namespace WTF; + +/* Negative values for the firstchar and reqchar variables */ + +#define REQ_UNSET (-2) +#define REQ_NONE (-1) + +/************************************************* +* Code parameters and static tables * +*************************************************/ + +/* Maximum number of items on the nested bracket stacks at compile time. This +applies to the nesting of all kinds of parentheses. It does not limit +un-nested, non-capturing parentheses. This number can be made bigger if +necessary - it is used to dimension one int and one unsigned char vector at +compile time. */ + +#define BRASTACK_SIZE 200 + +/* Table for handling escaped characters in the range '0'-'z'. Positive returns +are simple data values; negative values are for special things like \d and so +on. Zero means further processing is needed (for things like \x), or the escape +is invalid. */ + +static const short escapes[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ + 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ + '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ + 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */ + '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */ + 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */ + 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */ + 0, 0, 0 /* x - z */ +}; +static const unsigned OPCODE_LEN = 1; +static const unsigned BRAZERO_LEN = OPCODE_LEN; +static const unsigned BRA_NEST_SIZE = 2; +static const unsigned BRA_LEN = OPCODE_LEN + LINK_SIZE + BRA_NEST_SIZE; +static const unsigned KET_LEN = OPCODE_LEN + LINK_SIZE; + +/* Error code numbers. They are given names so that they can more easily be +tracked. */ + +enum ErrorCode { + ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, + ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17 +}; + +/* These are the error texts that correspond to the above error codes: + // 1 + "\\ at end of pattern\0" + "\\c at end of pattern\0" + "character value in \\x{...} sequence is too large\0" + "numbers out of order in {} quantifier\0" + // 5 + "number too big in {} quantifier\0" + "missing terminating ] for character class\0" + "internal error: code overflow\0" + "range out of order in character class\0" + "nothing to repeat\0" + // 10 + "unmatched parentheses\0" + "internal error: unexpected repeat\0" + "unrecognized character after (?\0" + "failed to get memory\0" + "missing )\0" + // 15 + "reference to non-existent subpattern\0" + "regular expression too large\0" + "parentheses nested too deeply" */ + +/* Structure for passing "static" information around between the functions +doing the compiling. */ + +struct CompileData { + CompileData() { + topBackref = 0; + backrefMap = 0; + reqVaryOpt = 0; + needOuterBracket = false; + numCapturingBrackets = 0; + } + int topBackref; /* Maximum back reference */ + unsigned backrefMap; /* Bitmap of low back refs */ + int reqVaryOpt; /* "After variable item" flag for reqByte */ + bool needOuterBracket; + int numCapturingBrackets; +}; + +/* Definitions to allow mutual recursion */ + +static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&); +static bool bracketIsAnchored(const unsigned char* code); +static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap); +static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert); + +/************************************************* +* Handle escapes * +*************************************************/ + +/* This function is called when a \ has been encountered. It either returns a +positive value for a simple escape such as \n, or a negative value which +encodes one of the more complicated things such as \d. When UTF-8 is enabled, +a positive value greater than 255 may be returned. On entry, ptr is pointing at +the \. On exit, it is on the final character of the escape sequence. + +Arguments: + ptrPtr points to the pattern position pointer + errorCodePtr points to the errorcode variable + bracount number of previous extracting brackets + options the options bits + isClass true if inside a character class + +Returns: zero or positive => a data character + negative => a special escape sequence + on error, error is set +*/ + +static int checkEscape(const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int bracount, bool isClass) +{ + const UChar* ptr = *ptrPtr + 1; + + /* If backslash is at the end of the pattern, it's an error. */ + if (ptr == patternEnd) { + *errorCodePtr = ERR1; + *ptrPtr = ptr; + return 0; + } + + int c = *ptr; + + /* Non-alphamerics are literals. For digits or letters, do an initial lookup in + a table. A non-zero result is something that can be returned immediately. + Otherwise further processing may be required. */ + + if (c < '0' || c > 'z') { /* Not alphameric */ + } else if (int escapeValue = escapes[c - '0']) { + c = escapeValue; + if (isClass) { + if (-c == ESC_b) + c = '\b'; /* \b is backslash in a class */ + else if (-c == ESC_B) + c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */ + } + /* Escapes that need further processing, or are illegal. */ + + } else { + switch (c) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* Escape sequences starting with a non-zero digit are backreferences, + unless there are insufficient brackets, in which case they are octal + escape sequences. Those sequences end on the first non-octal character + or when we overflow 0-255, whichever comes first. */ + + if (!isClass) { + const UChar* oldptr = ptr; + c -= '0'; + while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount) + c = c * 10 + *(++ptr) - '0'; + if (c <= bracount) { + c = -(ESC_REF + c); + break; + } + ptr = oldptr; /* Put the pointer back and fall through */ + } + + /* Handle an octal number following \. If the first digit is 8 or 9, + this is not octal. */ + + if ((c = *ptr) >= '8') { + c = '\\'; + ptr -= 1; + break; + } + + /* \0 always starts an octal number, but we may drop through to here with a + larger first octal digit. */ + + case '0': { + c -= '0'; + int i; + for (i = 1; i <= 2; ++i) { + if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7') + break; + int cc = c * 8 + ptr[i] - '0'; + if (cc > 255) + break; + c = cc; + } + ptr += i - 1; + break; + } + + case 'x': { + c = 0; + int i; + for (i = 1; i <= 2; ++i) { + if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { + c = 'x'; + i = 1; + break; + } + int cc = ptr[i]; + if (cc >= 'a') + cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); + } + ptr += i - 1; + break; + } + + case 'u': { + c = 0; + int i; + for (i = 1; i <= 4; ++i) { + if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { + c = 'u'; + i = 1; + break; + } + int cc = ptr[i]; + if (cc >= 'a') + cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); + } + ptr += i - 1; + break; + } + + case 'c': + if (++ptr == patternEnd) { + *errorCodePtr = ERR2; + return 0; + } + + c = *ptr; + + /* To match Firefox, inside a character class, we also accept + numbers and '_' as control characters */ + if ((!isClass && !isASCIIAlpha(c)) || (!isASCIIAlphanumeric(c) && c != '_')) { + c = '\\'; + ptr -= 2; + break; + } + + /* A letter is upper-cased; then the 0x40 bit is flipped. This coding + is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ + c = toASCIIUpper(c) ^ 0x40; + break; + } + } + + *ptrPtr = ptr; + return c; +} + +/************************************************* +* Check for counted repeat * +*************************************************/ + +/* This function is called when a '{' is encountered in a place where it might +start a quantifier. It looks ahead to see if it really is a quantifier or not. +It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} +where the ddds are digits. + +Arguments: + p pointer to the first char after '{' + +Returns: true or false +*/ + +static bool isCountedRepeat(const UChar* p, const UChar* patternEnd) +{ + if (p >= patternEnd || !isASCIIDigit(*p)) + return false; + p++; + while (p < patternEnd && isASCIIDigit(*p)) + p++; + if (p < patternEnd && *p == '}') + return true; + + if (p >= patternEnd || *p++ != ',') + return false; + if (p < patternEnd && *p == '}') + return true; + + if (p >= patternEnd || !isASCIIDigit(*p)) + return false; + p++; + while (p < patternEnd && isASCIIDigit(*p)) + p++; + + return (p < patternEnd && *p == '}'); +} + +/************************************************* +* Read repeat counts * +*************************************************/ + +/* Read an item of the form {n,m} and return the values. This is called only +after isCountedRepeat() has confirmed that a repeat-count quantifier exists, +so the syntax is guaranteed to be correct, but we need to check the values. + +Arguments: + p pointer to first char after '{' + minp pointer to int for min + maxp pointer to int for max + returned as -1 if no max + errorCodePtr points to error code variable + +Returns: pointer to '}' on success; + current ptr on error, with errorCodePtr set non-zero +*/ + +static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorCodePtr) +{ + int min = 0; + int max = -1; + + /* Read the minimum value and do a paranoid check: a negative value indicates + an integer overflow. */ + + while (isASCIIDigit(*p)) + min = min * 10 + *p++ - '0'; + if (min < 0 || min > 65535) { + *errorCodePtr = ERR5; + return p; + } + + /* Read the maximum value if there is one, and again do a paranoid on its size. + Also, max must not be less than min. */ + + if (*p == '}') + max = min; + else { + if (*(++p) != '}') { + max = 0; + while (isASCIIDigit(*p)) + max = max * 10 + *p++ - '0'; + if (max < 0 || max > 65535) { + *errorCodePtr = ERR5; + return p; + } + if (max < min) { + *errorCodePtr = ERR4; + return p; + } + } + } + + /* Fill in the required variables, and pass back the pointer to the terminating + '}'. */ + + *minp = min; + *maxp = max; + return p; +} + +/************************************************* +* Find first significant op code * +*************************************************/ + +/* This is called by several functions that scan a compiled expression looking +for a fixed first character, or an anchoring op code etc. It skips over things +that do not influence this. + +Arguments: + code pointer to the start of the group +Returns: pointer to the first significant opcode +*/ + +static const unsigned char* firstSignificantOpcode(const unsigned char* code) +{ + while (*code == OP_BRANUMBER) + code += 3; + return code; +} + +static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code) +{ + while (true) { + switch (*code) { + case OP_ASSERT_NOT: + advanceToEndOfBracket(code); + code += 1 + LINK_SIZE; + break; + case OP_WORD_BOUNDARY: + case OP_NOT_WORD_BOUNDARY: + ++code; + break; + case OP_BRANUMBER: + code += 3; + break; + default: + return code; + } + } +} + +/************************************************* +* Get othercase range * +*************************************************/ + +/* This function is passed the start and end of a class range, in UTF-8 mode +with UCP support. It searches up the characters, looking for internal ranges of +characters in the "other" case. Each call returns the next one, updating the +start address. + +Arguments: + cptr points to starting character value; updated + d end value + ocptr where to put start of othercase range + odptr where to put end of othercase range + +Yield: true when range returned; false when no more +*/ + +static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr) +{ + int c, othercase = 0; + + for (c = *cptr; c <= d; c++) { + if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) + break; + } + + if (c > d) + return false; + + *ocptr = othercase; + int next = othercase + 1; + + for (++c; c <= d; c++) { + if (jsc_pcre_ucp_othercase(c) != next) + break; + next++; + } + + *odptr = next - 1; + *cptr = c; + + return true; +} + +/************************************************* + * Convert character value to UTF-8 * + *************************************************/ + +/* This function takes an integer value in the range 0 - 0x7fffffff + and encodes it as a UTF-8 character in 0 to 6 bytes. + + Arguments: + cvalue the character value + buffer pointer to buffer for result - at least 6 bytes long + + Returns: number of characters placed in the buffer + */ + +static int encodeUTF8(int cvalue, unsigned char *buffer) +{ + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (cvalue <= jsc_pcre_utf8_table1[i]) + break; + buffer += i; + for (int j = i; j > 0; j--) { + *buffer-- = 0x80 | (cvalue & 0x3f); + cvalue >>= 6; + } + *buffer = jsc_pcre_utf8_table2[i] | cvalue; + return i + 1; +} + +/************************************************* +* Compile one branch * +*************************************************/ + +/* Scan the pattern, compiling it into the code vector. + +Arguments: + options the option bits + brackets points to number of extracting brackets used + codePtr points to the pointer to the current code point + ptrPtr points to the current pattern pointer + errorCodePtr points to error code variable + firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) + reqbyteptr set to the last literal character required, else < 0 + cd contains pointers to tables etc. + +Returns: true on success + false, with *errorCodePtr set non-zero on error +*/ + +static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected) +{ + return ((ptr + 1 < patternEnd) && ptr[1] == expected); +} + +static bool +compileBranch(int options, int* brackets, unsigned char** codePtr, + const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int *firstbyteptr, + int* reqbyteptr, CompileData& cd) +{ + int repeatType, opType; + int repeatMin = 0, repeat_max = 0; /* To please picky compilers */ + int bravalue = 0; + int reqvary, tempreqvary; + int c; + unsigned char* code = *codePtr; + unsigned char* tempcode; + bool didGroupSetFirstByte = false; + const UChar* ptr = *ptrPtr; + const UChar* tempptr; + unsigned char* previous = NULL; + unsigned char classbits[32]; + + bool class_utf8; + unsigned char* class_utf8data; + unsigned char utf8_char[6]; + + /* Initialize no first byte, no required byte. REQ_UNSET means "no char + matching encountered yet". It gets changed to REQ_NONE if we hit something that + matches a non-fixed char first char; reqByte just remains unset if we never + find one. + + When we hit a repeat whose minimum is zero, we may have to adjust these values + to take the zero repeat into account. This is implemented by setting them to + zeroFirstByte and zeroReqByte when such a repeat is encountered. The individual + item types that can be repeated set these backoff variables appropriately. */ + + int firstByte = REQ_UNSET; + int reqByte = REQ_UNSET; + int zeroReqByte = REQ_UNSET; + int zeroFirstByte = REQ_UNSET; + + /* The variable reqCaseOpt contains either the REQ_IGNORE_CASE value or zero, + according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit + value > 255. It is added into the firstByte or reqByte variables to record the + case status of the value. This is used only for ASCII characters. */ + + int reqCaseOpt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0; + + /* Switch on next character until the end of the branch */ + + for (;; ptr++) { + bool negateClass; + bool shouldFlipNegation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */ + int classCharCount; + int classLastChar; + int skipBytes; + int subReqByte; + int subFirstByte; + int mcLength; + unsigned char mcbuffer[8]; + + /* Next byte in the pattern */ + + c = ptr < patternEnd ? *ptr : 0; + + /* Fill in length of a previous callout, except when the next thing is + a quantifier. */ + + bool isQuantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd)); + + switch (c) { + /* The branch terminates at end of string, |, or ). */ + + case 0: + if (ptr < patternEnd) + goto NORMAL_CHAR; + // End of string; fall through + case '|': + case ')': + *firstbyteptr = firstByte; + *reqbyteptr = reqByte; + *codePtr = code; + *ptrPtr = ptr; + return true; + + /* Handle single-character metacharacters. In multiline mode, ^ disables + the setting of any following char as a first character. */ + + case '^': + if (options & MatchAcrossMultipleLinesOption) { + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + *code++ = OP_BOL; + } else + *code++ = OP_CIRC; + previous = NULL; + break; + + case '$': + previous = NULL; + if (options & MatchAcrossMultipleLinesOption) + *code++ = OP_EOL; + else + *code++ = OP_DOLL; + break; + + /* There can never be a first char if '.' is first, whatever happens about + repeats. The value of reqByte doesn't change either. */ + + case '.': + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + previous = code; + *code++ = OP_NOT_NEWLINE; + break; + + /* Character classes. If the included characters are all < 256, we build a + 32-byte bitmap of the permitted characters, except in the special case + where there is only one such character. For negated classes, we build the + map as usual, then invert it at the end. However, we use a different opcode + so that data characters > 255 can be handled correctly. + + If the class contains characters outside the 0-255 range, a different + opcode is compiled. It may optionally have a bit map for characters < 256, + but those above are are explicitly listed afterwards. A flag byte tells + whether the bitmap is present, and whether this is a negated class or not. + */ + + case '[': { + previous = code; + shouldFlipNegation = false; + + /* PCRE supports POSIX class stuff inside a class. Perl gives an error if + they are encountered at the top level, so we'll do that too. */ + + /* If the first character is '^', set the negation flag and skip it. */ + + if (ptr + 1 >= patternEnd) { + *errorCodePtr = ERR6; + return false; + } + + if (ptr[1] == '^') { + negateClass = true; + ++ptr; + } else + negateClass = false; + + /* Keep a count of chars with values < 256 so that we can optimize the case + of just a single character (as long as it's < 256). For higher valued UTF-8 + characters, we don't yet do any optimization. */ + + classCharCount = 0; + classLastChar = -1; + + class_utf8 = false; /* No chars >= 256 */ + class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ + + /* Initialize the 32-char bit map to all zeros. We have to build the + map in a temporary bit of store, in case the class contains only 1 + character (< 256), because in that case the compiled code doesn't use the + bit map. */ + + memset(classbits, 0, 32 * sizeof(unsigned char)); + + /* Process characters until ] is reached. The first pass + through the regex checked the overall syntax, so we don't need to be very + strict here. At the start of the loop, c contains the first byte of the + character. */ + + while ((++ptr < patternEnd) && (c = *ptr) != ']') { + /* Backslash may introduce a single character, or it may introduce one + of the specials, which just set a flag. Escaped items are checked for + validity in the pre-compiling pass. The sequence \b is a special case. + Inside a class (and only there) it is treated as backspace. Elsewhere + it marks a word boundary. Other escapes have preset maps ready to + or into the one we are building. We assume they have more than one + character in them, so set classCharCount bigger than one. */ + + if (c == '\\') { + c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); + if (c < 0) { + classCharCount += 2; /* Greater than 1 is what matters */ + switch (-c) { + case ESC_d: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_digit); + continue; + + case ESC_D: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_digit); + continue; + + case ESC_w: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_word); + continue; + + case ESC_W: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_word); + continue; + + case ESC_s: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_space); + continue; + + case ESC_S: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_space); + continue; + + /* Unrecognized escapes are faulted if PCRE is running in its + strict mode. By default, for compatibility with Perl, they are + treated as literals. */ + + default: + c = *ptr; /* The final character */ + classCharCount -= 2; /* Undo the default count from above */ + } + } + + /* Fall through if we have a single character (c >= 0). This may be + > 256 in UTF-8 mode. */ + + } /* End of backslash handling */ + + /* A single character may be followed by '-' to form a range. However, + Perl does not permit ']' to be the end of the range. A '-' character + here is treated as a literal. */ + + if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') { + ptr += 2; + + int d = *ptr; + + /* The second part of a range can be a single-character escape, but + not any of the other escapes. Perl 5.6 treats a hyphen as a literal + in such circumstances. */ + + if (d == '\\') { + const UChar* oldptr = ptr; + d = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); + + /* \X is literal X; any other special means the '-' was literal */ + if (d < 0) { + ptr = oldptr - 2; + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + } + } + + /* The check that the two values are in the correct order happens in + the pre-pass. Optimize one-character ranges */ + + if (d == c) + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + + /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless + matching, we have to use an XCLASS with extra data items. Caseless + matching for characters > 127 is available only if UCP support is + available. */ + + if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) { + class_utf8 = true; + + /* With UCP support, we can find the other case equivalents of + the relevant characters. There may be several ranges. Optimize how + they fit with the basic range. */ + + if (options & IgnoreCaseOption) { + int occ, ocd; + int cc = c; + int origd = d; + while (getOthercaseRange(&cc, origd, &occ, &ocd)) { + if (occ >= c && ocd <= d) + continue; /* Skip embedded ranges */ + + if (occ < c && ocd >= c - 1) /* Extend the basic range */ + { /* if there is overlap, */ + c = occ; /* noting that if occ < c */ + continue; /* we can't have ocd > d */ + } /* because a subrange is */ + if (ocd > d && occ <= d + 1) /* always shorter than */ + { /* the basic range. */ + d = ocd; + continue; + } + + if (occ == ocd) + *class_utf8data++ = XCL_SINGLE; + else { + *class_utf8data++ = XCL_RANGE; + class_utf8data += encodeUTF8(occ, class_utf8data); + } + class_utf8data += encodeUTF8(ocd, class_utf8data); + } + } + + /* Now record the original range, possibly modified for UCP caseless + overlapping ranges. */ + + *class_utf8data++ = XCL_RANGE; + class_utf8data += encodeUTF8(c, class_utf8data); + class_utf8data += encodeUTF8(d, class_utf8data); + + /* With UCP support, we are done. Without UCP support, there is no + caseless matching for UTF-8 characters > 127; we can use the bit map + for the smaller ones. */ + + continue; /* With next character in the class */ + } + + /* We use the bit map for all cases when not in UTF-8 mode; else + ranges that lie entirely within 0-127 when there is UCP support; else + for partial ranges without UCP support. */ + + for (; c <= d; c++) { + classbits[c/8] |= (1 << (c&7)); + if (options & IgnoreCaseOption) { + int uc = flipCase(c); + classbits[uc/8] |= (1 << (uc&7)); + } + classCharCount++; /* in case a one-char range */ + classLastChar = c; + } + + continue; /* Go get the next char in the class */ + } + + /* Handle a lone single character - we can get here for a normal + non-escape char, or after \ that introduces a single character or for an + apparent range that isn't. */ + + LONE_SINGLE_CHARACTER: + + /* Handle a character that cannot go in the bit map */ + + if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) { + class_utf8 = true; + *class_utf8data++ = XCL_SINGLE; + class_utf8data += encodeUTF8(c, class_utf8data); + + if (options & IgnoreCaseOption) { + int othercase; + if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) { + *class_utf8data++ = XCL_SINGLE; + class_utf8data += encodeUTF8(othercase, class_utf8data); + } + } + } else { + /* Handle a single-byte character */ + classbits[c/8] |= (1 << (c&7)); + if (options & IgnoreCaseOption) { + c = flipCase(c); + classbits[c/8] |= (1 << (c&7)); + } + classCharCount++; + classLastChar = c; + } + } + + /* If classCharCount is 1, we saw precisely one character whose value is + less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we + can optimize the negative case only if there were no characters >= 128 + because OP_NOT and the related opcodes like OP_NOTSTAR operate on + single-bytes only. This is an historical hangover. Maybe one day we can + tidy these opcodes to handle multi-byte characters. + + The optimization throws away the bit map. We turn the item into a + 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note + that OP_NOT does not support multibyte characters. In the positive case, it + can cause firstByte to be set. Otherwise, there can be no first char if + this item is first, whatever repeat count may follow. In the case of + reqByte, save the previous value for reinstating. */ + + if (classCharCount == 1 && (!class_utf8 && (!negateClass || classLastChar < 128))) { + zeroReqByte = reqByte; + + /* The OP_NOT opcode works on one-byte characters only. */ + + if (negateClass) { + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + zeroFirstByte = firstByte; + *code++ = OP_NOT; + *code++ = classLastChar; + break; + } + + /* For a single, positive character, get the value into c, and + then we can handle this with the normal one-character code. */ + + c = classLastChar; + goto NORMAL_CHAR; + } /* End of 1-char optimization */ + + /* The general case - not the one-char optimization. If this is the first + thing in the branch, there can be no first char setting, whatever the + repeat count. Any reqByte setting must remain unchanged after any kind of + repeat. */ + + if (firstByte == REQ_UNSET) firstByte = REQ_NONE; + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + + /* If there are characters with values > 255, we have to compile an + extended class, with its own opcode. If there are no characters < 256, + we can omit the bitmap. */ + + if (class_utf8 && !shouldFlipNegation) { + *class_utf8data++ = XCL_END; /* Marks the end of extra data */ + *code++ = OP_XCLASS; + code += LINK_SIZE; + *code = negateClass? XCL_NOT : 0; + + /* If the map is required, install it, and move on to the end of + the extra data */ + + if (classCharCount > 0) { + *code++ |= XCL_MAP; + memcpy(code, classbits, 32); + code = class_utf8data; + } + + /* If the map is not required, slide down the extra data. */ + + else { + int len = class_utf8data - (code + 33); + memmove(code + 1, code + 33, len); + code += len + 1; + } + + /* Now fill in the complete length of the item */ + + putLinkValue(previous + 1, code - previous); + break; /* End of class handling */ + } + + /* If there are no characters > 255, negate the 32-byte map if necessary, + and copy it into the code vector. If this is the first thing in the branch, + there can be no first char setting, whatever the repeat count. Any reqByte + setting must remain unchanged after any kind of repeat. */ + + *code++ = (negateClass == shouldFlipNegation) ? OP_CLASS : OP_NCLASS; + if (negateClass) + for (c = 0; c < 32; c++) + code[c] = ~classbits[c]; + else + memcpy(code, classbits, 32); + code += 32; + break; + } + + /* Various kinds of repeat; '{' is not necessarily a quantifier, but this + has been tested above. */ + + case '{': + if (!isQuantifier) + goto NORMAL_CHAR; + ptr = readRepeatCounts(ptr + 1, &repeatMin, &repeat_max, errorCodePtr); + if (*errorCodePtr) + goto FAILED; + goto REPEAT; + + case '*': + repeatMin = 0; + repeat_max = -1; + goto REPEAT; + + case '+': + repeatMin = 1; + repeat_max = -1; + goto REPEAT; + + case '?': + repeatMin = 0; + repeat_max = 1; + + REPEAT: + if (!previous) { + *errorCodePtr = ERR9; + goto FAILED; + } + + if (repeatMin == 0) { + firstByte = zeroFirstByte; /* Adjust for zero repeat */ + reqByte = zeroReqByte; /* Ditto */ + } + + /* Remember whether this is a variable length repeat */ + + reqvary = (repeatMin == repeat_max) ? 0 : REQ_VARY; + + opType = 0; /* Default single-char op codes */ + + /* Save start of previous item, in case we have to move it up to make space + for an inserted OP_ONCE for the additional '+' extension. */ + /* FIXME: Probably don't need this because we don't use OP_ONCE. */ + + tempcode = previous; + + /* If the next character is '+', we have a possessive quantifier. This + implies greediness, whatever the setting of the PCRE_UNGREEDY option. + If the next character is '?' this is a minimizing repeat, by default, + but if PCRE_UNGREEDY is set, it works the other way round. We change the + repeat type to the non-default. */ + + if (safelyCheckNextChar(ptr, patternEnd, '?')) { + repeatType = 1; + ptr++; + } else + repeatType = 0; + + /* If previous was a character match, abolish the item and generate a + repeat item instead. If a char item has a minumum of more than one, ensure + that it is set in reqByte - it might not be if a sequence such as x{3} is + the first thing in a branch because the x will have gone into firstByte + instead. */ + + if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) { + /* Deal with UTF-8 characters that take up more than one byte. It's + easier to write this out separately than try to macrify it. Use c to + hold the length of the character in bytes, plus 0x80 to flag that it's a + length rather than a small character. */ + + if (code[-1] & 0x80) { + unsigned char *lastchar = code - 1; + while((*lastchar & 0xc0) == 0x80) + lastchar--; + c = code - lastchar; /* Length of UTF-8 character */ + memcpy(utf8_char, lastchar, c); /* Save the char */ + c |= 0x80; /* Flag c as a length */ + } + else { + c = code[-1]; + if (repeatMin > 1) + reqByte = c | reqCaseOpt | cd.reqVaryOpt; + } + + goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ + } + + else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) { + c = previous[1]; + if (repeatMin > 1) + reqByte = c | reqCaseOpt | cd.reqVaryOpt; + goto OUTPUT_SINGLE_REPEAT; + } + + /* If previous was a single negated character ([^a] or similar), we use + one of the special opcodes, replacing it. The code is shared with single- + character repeats by setting opt_type to add a suitable offset into + repeatType. OP_NOT is currently used only for single-byte chars. */ + + else if (*previous == OP_NOT) { + opType = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ + c = previous[1]; + goto OUTPUT_SINGLE_REPEAT; + } + + /* If previous was a character type match (\d or similar), abolish it and + create a suitable repeat item. The code is shared with single-character + repeats by setting opType to add a suitable offset into repeatType. */ + + else if (*previous <= OP_NOT_NEWLINE) { + opType = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ + c = *previous; + + OUTPUT_SINGLE_REPEAT: + int prop_type = -1; + int prop_value = -1; + + unsigned char* oldcode = code; + code = previous; /* Usually overwrite previous item */ + + /* If the maximum is zero then the minimum must also be zero; Perl allows + this case, so we do too - by simply omitting the item altogether. */ + + if (repeat_max == 0) + goto END_REPEAT; + + /* Combine the opType with the repeatType */ + + repeatType += opType; + + /* A minimum of zero is handled either as the special case * or ?, or as + an UPTO, with the maximum given. */ + + if (repeatMin == 0) { + if (repeat_max == -1) + *code++ = OP_STAR + repeatType; + else if (repeat_max == 1) + *code++ = OP_QUERY + repeatType; + else { + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* A repeat minimum of 1 is optimized into some special cases. If the + maximum is unlimited, we use OP_PLUS. Otherwise, the original item it + left in place and, if the maximum is greater than 1, we use OP_UPTO with + one less than the maximum. */ + + else if (repeatMin == 1) { + if (repeat_max == -1) + *code++ = OP_PLUS + repeatType; + else { + code = oldcode; /* leave previous item in place */ + if (repeat_max == 1) + goto END_REPEAT; + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max - 1); + } + } + + /* The case {n,n} is just an EXACT, while the general case {n,m} is + handled as an EXACT followed by an UPTO. */ + + else { + *code++ = OP_EXACT + opType; /* NB EXACT doesn't have repeatType */ + put2ByteValueAndAdvance(code, repeatMin); + + /* If the maximum is unlimited, insert an OP_STAR. Before doing so, + we have to insert the character for the previous code. For a repeated + Unicode property match, there are two extra bytes that define the + required property. In UTF-8 mode, long characters have their length in + c, with the 0x80 bit as a flag. */ + + if (repeat_max < 0) { + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else { + *code++ = c; + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + } + *code++ = OP_STAR + repeatType; + } + + /* Else insert an UPTO if the max is greater than the min, again + preceded by the character, for the previously inserted code. */ + + else if (repeat_max != repeatMin) { + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else + *code++ = c; + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + repeat_max -= repeatMin; + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* The character or character type itself comes last in all cases. */ + + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else + *code++ = c; + + /* For a repeated Unicode property match, there are two extra bytes that + define the required property. */ + + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + } + + /* If previous was a character class or a back reference, we put the repeat + stuff after it, but just skip the item if the repeat was {0,0}. */ + + else if (*previous == OP_CLASS || + *previous == OP_NCLASS || + *previous == OP_XCLASS || + *previous == OP_REF) + { + if (repeat_max == 0) { + code = previous; + goto END_REPEAT; + } + + if (repeatMin == 0 && repeat_max == -1) + *code++ = OP_CRSTAR + repeatType; + else if (repeatMin == 1 && repeat_max == -1) + *code++ = OP_CRPLUS + repeatType; + else if (repeatMin == 0 && repeat_max == 1) + *code++ = OP_CRQUERY + repeatType; + else { + *code++ = OP_CRRANGE + repeatType; + put2ByteValueAndAdvance(code, repeatMin); + if (repeat_max == -1) + repeat_max = 0; /* 2-byte encoding for max */ + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* If previous was a bracket group, we may have to replicate it in certain + cases. */ + + else if (*previous >= OP_BRA) { + int ketoffset = 0; + int len = code - previous; + unsigned char* bralink = NULL; + int nested = get2ByteValue(previous + 1 + LINK_SIZE); + + /* If the maximum repeat count is unlimited, find the end of the bracket + by scanning through from the start, and compute the offset back to it + from the current code pointer. There may be an OP_OPT setting following + the final KET, so we can't find the end just by going back from the code + pointer. */ + + if (repeat_max == -1) { + const unsigned char* ket = previous; + advanceToEndOfBracket(ket); + ketoffset = code - ket; + } + + /* The case of a zero minimum is special because of the need to stick + OP_BRAZERO in front of it, and because the group appears once in the + data, whereas in other cases it appears the minimum number of times. For + this reason, it is simplest to treat this case separately, as otherwise + the code gets far too messy. There are several special subcases when the + minimum is zero. */ + + if (repeatMin == 0) { + /* If the maximum is also zero, we just omit the group from the output + altogether. */ + + if (repeat_max == 0) { + code = previous; + goto END_REPEAT; + } + + /* If the maximum is 1 or unlimited, we just have to stick in the + BRAZERO and do no more at this point. However, we do need to adjust + any OP_RECURSE calls inside the group that refer to the group itself or + any internal group, because the offset is from the start of the whole + regex. Temporarily terminate the pattern while doing this. */ + + if (repeat_max <= 1) { + *code = OP_END; + memmove(previous+1, previous, len); + code++; + *previous++ = OP_BRAZERO + repeatType; + } + + /* If the maximum is greater than 1 and limited, we have to replicate + in a nested fashion, sticking OP_BRAZERO before each set of brackets. + The first one has to be handled carefully because it's the original + copy, which has to be moved up. The remainder can be handled by code + that is common with the non-zero minimum case below. We have to + adjust the value of repeat_max, since one less copy is required. */ + + else { + *code = OP_END; + memmove(previous + 4 + LINK_SIZE, previous, len); + code += 4 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeatType; + *previous++ = OP_BRA; + + /* We chain together the bracket offset fields that have to be + filled in later when the ends of the brackets are reached. */ + + int offset = (!bralink) ? 0 : previous - bralink; + bralink = previous; + putLinkValueAllowZeroAndAdvance(previous, offset); + put2ByteValueAndAdvance(previous, nested); + } + + repeat_max--; + } + + /* If the minimum is greater than zero, replicate the group as many + times as necessary, and adjust the maximum to the number of subsequent + copies that we need. If we set a first char from the group, and didn't + set a required char, copy the latter from the former. */ + + else { + if (repeatMin > 1) { + if (didGroupSetFirstByte && reqByte < 0) + reqByte = firstByte; + for (int i = 1; i < repeatMin; i++) { + memcpy(code, previous, len); + code += len; + } + } + if (repeat_max > 0) + repeat_max -= repeatMin; + } + + /* This code is common to both the zero and non-zero minimum cases. If + the maximum is limited, it replicates the group in a nested fashion, + remembering the bracket starts on a stack. In the case of a zero minimum, + the first one was set up above. In all cases the repeat_max now specifies + the number of additional copies needed. */ + + if (repeat_max >= 0) { + for (int i = repeat_max - 1; i >= 0; i--) { + *code++ = OP_BRAZERO + repeatType; + + /* All but the final copy start a new nesting, maintaining the + chain of brackets outstanding. */ + + if (i != 0) { + *code++ = OP_BRA; + int offset = (!bralink) ? 0 : code - bralink; + bralink = code; + putLinkValueAllowZeroAndAdvance(code, offset); + put2ByteValueAndAdvance(code, nested); + } + + memcpy(code, previous, len); + code += len; + } + + /* Now chain through the pending brackets, and fill in their length + fields (which are holding the chain links pro tem). */ + + while (bralink) { + int offset = code - bralink + 1; + unsigned char* bra = code - offset; + int oldlinkoffset = getLinkValueAllowZero(bra + 1); + bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset; + *code++ = OP_KET; + putLinkValueAndAdvance(code, offset); + putLinkValue(bra + 1, offset); + } + } + + /* If the maximum is unlimited, set a repeater in the final copy. We + can't just offset backwards from the current code point, because we + don't know if there's been an options resetting after the ket. The + correct offset was computed above. */ + + else + code[-ketoffset] = OP_KETRMAX + repeatType; + } + + // A quantifier after an assertion is mostly meaningless, but it + // can nullify the assertion if it has a 0 minimum. + else if (*previous == OP_ASSERT || *previous == OP_ASSERT_NOT) { + if (repeatMin == 0) { + code = previous; + goto END_REPEAT; + } + } + + /* Else there's some kind of shambles */ + + else { + *errorCodePtr = ERR11; + goto FAILED; + } + + /* In all case we no longer have a previous item. We also set the + "follows varying string" flag for subsequently encountered reqbytes if + it isn't already set and we have just passed a varying length item. */ + + END_REPEAT: + previous = NULL; + cd.reqVaryOpt |= reqvary; + break; + + /* Start of nested bracket sub-expression, or comment or lookahead or + lookbehind or option setting or condition. First deal with special things + that can come after a bracket; all are introduced by ?, and the appearance + of any of them means that this is not a referencing group. They were + checked for validity in the first pass over the string, so we don't have to + check for syntax errors here. */ + + case '(': + { + skipBytes = 2; + unsigned minBracket = *brackets + 1; + if (*(++ptr) == '?') { + switch (*(++ptr)) { + case ':': /* Non-extracting bracket */ + bravalue = OP_BRA; + ptr++; + break; + + case '=': /* Positive lookahead */ + bravalue = OP_ASSERT; + ptr++; + break; + + case '!': /* Negative lookahead */ + bravalue = OP_ASSERT_NOT; + ptr++; + break; + + /* Character after (? not specially recognized */ + + default: + *errorCodePtr = ERR12; + goto FAILED; + } + } + + /* Else we have a referencing group; adjust the opcode. If the bracket + number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and + arrange for the true number to follow later, in an OP_BRANUMBER item. */ + + else { + if (++(*brackets) > EXTRACT_BASIC_MAX) { + bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; + code[3 + LINK_SIZE] = OP_BRANUMBER; + put2ByteValue(code + 4 + LINK_SIZE, *brackets); + skipBytes = 5; + } + else + bravalue = OP_BRA + *brackets; + } + + /* Process nested bracketed re. We copy code into a non-variable + in order to be able to pass its address because some compilers + complain otherwise. Pass in a new setting for the ims options + if they have changed. */ + + previous = code; + *code = bravalue; + tempcode = code; + tempreqvary = cd.reqVaryOpt; /* Save value before bracket */ + { + unsigned bracketsBeforeRecursion = *brackets; + if (!compileBracket( + options, + brackets, /* Extracting bracket count */ + &tempcode, /* Where to put code (updated) */ + &ptr, /* Input pointer (updated) */ + patternEnd, + errorCodePtr, /* Where to put an error message */ + skipBytes, /* Skip over OP_BRANUMBER */ + &subFirstByte, /* For possible first char */ + &subReqByte, /* For possible last char */ + cd)) /* Tables block */ + goto FAILED; + unsigned enclosedBrackets = (*brackets - bracketsBeforeRecursion); + unsigned limitBracket = minBracket + enclosedBrackets + (bravalue > OP_BRA); + if (!((minBracket & 0xff) == minBracket && (limitBracket & 0xff) == limitBracket)) { + *errorCodePtr = ERR17; + return false; + } + JS_ASSERT(minBracket <= limitBracket); + put2ByteValue(code + 1 + LINK_SIZE, minBracket << 8 | limitBracket); + } + + /* At the end of compiling, code is still pointing to the start of the + group, while tempcode has been updated to point past the end of the group + and any option resetting that may follow it. The pattern pointer (ptr) + is on the bracket. */ + + /* Handle updating of the required and first characters. Update for normal + brackets of all kinds, and conditions with two branches (see code above). + If the bracket is followed by a quantifier with zero repeat, we have to + back off. Hence the definition of zeroReqByte and zeroFirstByte outside the + main loop so that they can be accessed for the back off. */ + + zeroReqByte = reqByte; + zeroFirstByte = firstByte; + didGroupSetFirstByte = false; + + if (bravalue >= OP_BRA) { + /* If we have not yet set a firstByte in this branch, take it from the + subpattern, remembering that it was set here so that a repeat of more + than one can replicate it as reqByte if necessary. If the subpattern has + no firstByte, set "none" for the whole branch. In both cases, a zero + repeat forces firstByte to "none". */ + + if (firstByte == REQ_UNSET) { + if (subFirstByte >= 0) { + firstByte = subFirstByte; + didGroupSetFirstByte = true; + } + else + firstByte = REQ_NONE; + zeroFirstByte = REQ_NONE; + } + + /* If firstByte was previously set, convert the subpattern's firstByte + into reqByte if there wasn't one, using the vary flag that was in + existence beforehand. */ + + else if (subFirstByte >= 0 && subReqByte < 0) + subReqByte = subFirstByte | tempreqvary; + + /* If the subpattern set a required byte (or set a first byte that isn't + really the first byte - see above), set it. */ + + if (subReqByte >= 0) + reqByte = subReqByte; + } + + /* For a forward assertion, we take the reqByte, if set. This can be + helpful if the pattern that follows the assertion doesn't set a different + char. For example, it's useful for /(?=abcde).+/. We can't set firstByte + for an assertion, however because it leads to incorrect effect for patterns + such as /(?=a)a.+/ when the "real" "a" would then become a reqByte instead + of a firstByte. This is overcome by a scan at the end if there's no + firstByte, looking for an asserted first char. */ + + else if (bravalue == OP_ASSERT && subReqByte >= 0) + reqByte = subReqByte; + + /* Now update the main code pointer to the end of the group. */ + + code = tempcode; + + /* Error if hit end of pattern */ + + if (ptr >= patternEnd || *ptr != ')') { + *errorCodePtr = ERR14; + goto FAILED; + } + break; + + } + /* Check \ for being a real metacharacter; if not, fall through and handle + it as a data character at the start of a string. Escape items are checked + for validity in the pre-compiling pass. */ + + case '\\': + tempptr = ptr; + c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, false); + + /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values + are arranged to be the negation of the corresponding OP_values. For the + back references, the values are ESC_REF plus the reference number. Only + back references and those types that consume a character may be repeated. + We can test for values between ESC_b and ESC_w for the latter; this may + have to change if any new ones are ever created. */ + + if (c < 0) { + /* For metasequences that actually match a character, we disable the + setting of a first character if it hasn't already been set. */ + + if (firstByte == REQ_UNSET && -c > ESC_b && -c <= ESC_w) + firstByte = REQ_NONE; + + /* Set values to reset to if this is followed by a zero repeat. */ + + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + + /* Back references are handled specially */ + + if (-c >= ESC_REF) { + int number = -c - ESC_REF; + previous = code; + *code++ = OP_REF; + put2ByteValueAndAdvance(code, number); + } + + /* For the rest, we can obtain the OP value by negating the escape + value */ + + else { + previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL; + *code++ = -c; + } + continue; + } + + /* Fall through. */ + + /* Handle a literal character. It is guaranteed not to be whitespace or # + when the extended flag is set. If we are in UTF-8 mode, it may be a + multi-byte literal character. */ + + default: + NORMAL_CHAR: + + previous = code; + + if (c < 128) { + mcLength = 1; + mcbuffer[0] = c; + + if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') { + *code++ = OP_ASCII_LETTER_IGNORING_CASE; + *code++ = c | 0x20; + } else { + *code++ = OP_ASCII_CHAR; + *code++ = c; + } + } else { + mcLength = encodeUTF8(c, mcbuffer); + + *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR; + for (c = 0; c < mcLength; c++) + *code++ = mcbuffer[c]; + } + + /* Set the first and required bytes appropriately. If no previous first + byte, set it from this character, but revert to none on a zero repeat. + Otherwise, leave the firstByte value alone, and don't change it on a zero + repeat. */ + + if (firstByte == REQ_UNSET) { + zeroFirstByte = REQ_NONE; + zeroReqByte = reqByte; + + /* If the character is more than one byte long, we can set firstByte + only if it is not to be matched caselessly. */ + + if (mcLength == 1 || reqCaseOpt == 0) { + firstByte = mcbuffer[0] | reqCaseOpt; + if (mcLength != 1) + reqByte = code[-1] | cd.reqVaryOpt; + } + else + firstByte = reqByte = REQ_NONE; + } + + /* firstByte was previously set; we can set reqByte only the length is + 1 or the matching is caseful. */ + + else { + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + if (mcLength == 1 || reqCaseOpt == 0) + reqByte = code[-1] | reqCaseOpt | cd.reqVaryOpt; + } + + break; /* End of literal character handling */ + } + } /* end of big loop */ + + /* Control never reaches here by falling through, only by a goto for all the + error states. Pass back the position in the pattern so that it can be displayed + to the user for diagnosing the error. */ + +FAILED: + *ptrPtr = ptr; + return false; +} + +/************************************************* +* Compile sequence of alternatives * +*************************************************/ + +/* On entry, ptr is pointing past the bracket character, but on return +it points to the closing bracket, or vertical bar, or end of string. +The code variable is pointing at the byte into which the BRA operator has been +stored. If the ims options are changed at the start (for a (?ims: group) or +during any branch, we need to insert an OP_OPT item at the start of every +following branch to ensure they get set correctly at run time, and also pass +the new options into every subsequent branch compile. + +Argument: + options option bits, including any changes for this subpattern + brackets -> int containing the number of extracting brackets used + codePtr -> the address of the current code pointer + ptrPtr -> the address of the current pattern pointer + errorCodePtr -> pointer to error code variable + skipBytes skip this many bytes at start (for OP_BRANUMBER) + firstbyteptr place to put the first required character, or a negative number + reqbyteptr place to put the last required character, or a negative number + cd points to the data block with tables pointers etc. + +Returns: true on success +*/ + +static bool +compileBracket(int options, int* brackets, unsigned char** codePtr, + const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int skipBytes, + int* firstbyteptr, int* reqbyteptr, CompileData& cd) +{ + const UChar* ptr = *ptrPtr; + unsigned char* code = *codePtr; + unsigned char* lastBranch = code; + unsigned char* start_bracket = code; + int firstByte = REQ_UNSET; + int reqByte = REQ_UNSET; + + /* Offset is set zero to mark that this bracket is still open */ + + putLinkValueAllowZero(code + 1, 0); + code += 1 + LINK_SIZE + skipBytes; + + /* Loop for each alternative branch */ + + while (true) { + /* Now compile the branch */ + + int branchFirstByte; + int branchReqByte; + if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorCodePtr, + &branchFirstByte, &branchReqByte, cd)) { + *ptrPtr = ptr; + return false; + } + + /* If this is the first branch, the firstByte and reqByte values for the + branch become the values for the regex. */ + + if (*lastBranch != OP_ALT) { + firstByte = branchFirstByte; + reqByte = branchReqByte; + } + + /* If this is not the first branch, the first char and reqByte have to + match the values from all the previous branches, except that if the previous + value for reqByte didn't have REQ_VARY set, it can still match, and we set + REQ_VARY for the regex. */ + + else { + /* If we previously had a firstByte, but it doesn't match the new branch, + we have to abandon the firstByte for the regex, but if there was previously + no reqByte, it takes on the value of the old firstByte. */ + + if (firstByte >= 0 && firstByte != branchFirstByte) { + if (reqByte < 0) + reqByte = firstByte; + firstByte = REQ_NONE; + } + + /* If we (now or from before) have no firstByte, a firstByte from the + branch becomes a reqByte if there isn't a branch reqByte. */ + + if (firstByte < 0 && branchFirstByte >= 0 && branchReqByte < 0) + branchReqByte = branchFirstByte; + + /* Now ensure that the reqbytes match */ + + if ((reqByte & ~REQ_VARY) != (branchReqByte & ~REQ_VARY)) + reqByte = REQ_NONE; + else + reqByte |= branchReqByte; /* To "or" REQ_VARY */ + } + + /* Reached end of expression, either ')' or end of pattern. Go back through + the alternative branches and reverse the chain of offsets, with the field in + the BRA item now becoming an offset to the first alternative. If there are + no alternatives, it points to the end of the group. The length in the + terminating ket is always the length of the whole bracketed item. + Return leaving the pointer at the terminating char. */ + + if (ptr >= patternEnd || *ptr != '|') { + int length = code - lastBranch; + do { + int prevLength = getLinkValueAllowZero(lastBranch + 1); + putLinkValue(lastBranch + 1, length); + length = prevLength; + lastBranch -= length; + } while (length > 0); + + /* Fill in the ket */ + + *code = OP_KET; + putLinkValue(code + 1, code - start_bracket); + code += 1 + LINK_SIZE; + + /* Set values to pass back */ + + *codePtr = code; + *ptrPtr = ptr; + *firstbyteptr = firstByte; + *reqbyteptr = reqByte; + return true; + } + + /* Another branch follows; insert an "or" node. Its length field points back + to the previous branch while the bracket remains open. At the end the chain + is reversed. It's done like this so that the start of the bracket has a + zero offset until it is closed, making it possible to detect recursion. */ + + *code = OP_ALT; + putLinkValue(code + 1, code - lastBranch); + lastBranch = code; + code += 1 + LINK_SIZE; + ptr++; + } + JS_NOT_REACHED("No fallthru."); +} + +/************************************************* +* Check for anchored expression * +*************************************************/ + +/* Try to find out if this is an anchored regular expression. Consider each +alternative branch. If they all start OP_CIRC, or with a bracket +all of whose alternatives start OP_CIRC (recurse ad lib), then +it's anchored. + +Arguments: + code points to start of expression (the bracket) + captureMap a bitmap of which brackets we are inside while testing; this + handles up to substring 31; all brackets after that share + the zero bit + backrefMap the back reference bitmap +*/ + +static bool branchIsAnchored(const unsigned char* code) +{ + const unsigned char* scode = firstSignificantOpcode(code); + int op = *scode; + + /* Brackets */ + if (op >= OP_BRA || op == OP_ASSERT) + return bracketIsAnchored(scode); + + /* Check for explicit anchoring */ + return op == OP_CIRC; +} + +static bool bracketIsAnchored(const unsigned char* code) +{ + do { + if (!branchIsAnchored(code + 1 + LINK_SIZE)) + return false; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); /* Loop for each alternative */ + return true; +} + +/************************************************* +* Check for starting with ^ or .* * +*************************************************/ + +/* This is called to find out if every branch starts with ^ or .* so that +"first char" processing can be done to speed things up in multiline +matching and for non-DOTALL patterns that start with .* (which must start at +the beginning or after \n) + +Except when the .* appears inside capturing parentheses, and there is a +subsequent back reference to those parentheses. By keeping a bitmap of the +first 31 back references, we can catch some of the more common cases more +precisely; all the greater back references share a single bit. + +Arguments: + code points to start of expression (the bracket) + captureMap a bitmap of which brackets we are inside while testing; this + handles up to substring 31; all brackets after that share + the zero bit + backrefMap the back reference bitmap +*/ + +static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) +{ + const unsigned char* scode = firstSignificantOpcode(code); + int op = *scode; + + /* Capturing brackets */ + if (op > OP_BRA) { + int captureNum = op - OP_BRA; + if (captureNum > EXTRACT_BASIC_MAX) + captureNum = get2ByteValue(scode + 2 + LINK_SIZE); + int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1; + return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap); + } + + /* Other brackets */ + if (op == OP_BRA || op == OP_ASSERT) + return bracketNeedsLineStart(scode, captureMap, backrefMap); + + /* .* means "start at start or after \n" if it isn't in brackets that + may be referenced. */ + + if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) + return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap); + + /* Explicit ^ */ + return op == OP_CIRC || op == OP_BOL; +} + +static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) +{ + do { + if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap)) + return false; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); /* Loop for each alternative */ + return true; +} + +/************************************************* +* Check for asserted fixed first char * +*************************************************/ + +/* During compilation, the "first char" settings from forward assertions are +discarded, because they can cause conflicts with actual literals that follow. +However, if we end up without a first char setting for an unanchored pattern, +it is worth scanning the regex to see if there is an initial asserted first +char. If all branches start with the same asserted char, or with a bracket all +of whose alternatives start with the same asserted char (recurse ad lib), then +we return that char, otherwise -1. + +Arguments: + code points to start of expression (the bracket) + options pointer to the options (used to check casing changes) + inassert true if in an assertion + +Returns: -1 or the fixed first char +*/ + +static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert) +{ + const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code); + int op = *scode; + + if (op >= OP_BRA) + op = OP_BRA; + + switch (op) { + default: + return -1; + + case OP_BRA: + case OP_ASSERT: + return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT); + + case OP_EXACT: + scode += 2; + /* Fall through */ + + case OP_CHAR: + case OP_CHAR_IGNORING_CASE: + case OP_ASCII_CHAR: + case OP_ASCII_LETTER_IGNORING_CASE: + case OP_PLUS: + case OP_MINPLUS: + if (!inassert) + return -1; + return scode[1]; + } +} + +static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert) +{ + int c = -1; + do { + int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert); + if (d < 0) + return -1; + if (c < 0) + c = d; + else if (c != d) + return -1; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); + return c; +} + +static inline int multiplyWithOverflowCheck(int a, int b) +{ + if (!a || !b) + return 0; + if (a > MAX_PATTERN_SIZE / b) + return -1; + return a * b; +} + +static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase, + CompileData& cd, ErrorCode& errorcode) +{ + /* Make a pass over the pattern to compute the + amount of store required to hold the compiled code. This does not have to be + perfect as long as errors are overestimates. */ + + if (patternLength > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + + int length = BRA_LEN; /* For initial BRA. */ + int branch_extra = 0; + int lastitemlength = 0; + unsigned brastackptr = 0; + int brastack[BRASTACK_SIZE]; + unsigned char bralenstack[BRASTACK_SIZE]; + int bracount = 0; + + const UChar* ptr = (const UChar*)(pattern - 1); + const UChar* patternEnd = (const UChar*)(pattern + patternLength); + + while (++ptr < patternEnd) { + int minRepeats = 0, maxRepeats = 0; + int c = *ptr; + + switch (c) { + /* A backslashed item may be an escaped data character or it may be a + character type. */ + + case '\\': + c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false); + if (errorcode != 0) + return -1; + + lastitemlength = 1; /* Default length of last item for repeats */ + + if (c >= 0) { /* Data character */ + length += 2; /* For a one-byte character */ + + if (c > 127) { + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (c <= jsc_pcre_utf8_table1[i]) break; + length += i; + lastitemlength += i; + } + + continue; + } + + /* Other escapes need one byte */ + + length++; + + /* A back reference needs an additional 2 bytes, plus either one or 5 + bytes for a repeat. We also need to keep the value of the highest + back reference. */ + + if (c <= -ESC_REF) { + int refnum = -c - ESC_REF; + cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1; + if (refnum > cd.topBackref) + cd.topBackref = refnum; + length += 2; /* For single back reference */ + if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode) + return -1; + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + else + length += 5; + if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; + } + } + continue; + + case '^': /* Single-byte metacharacters */ + case '.': + case '$': + length++; + lastitemlength = 1; + continue; + + case '*': /* These repeats won't be after brackets; */ + case '+': /* those are handled separately */ + case '?': + length++; + goto POSSESSIVE; + + /* This covers the cases of braced repeats after a single char, metachar, + class, or back reference. */ + + case '{': + if (!isCountedRepeat(ptr + 1, patternEnd)) + goto NORMAL_CHAR; + ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode); + if (errorcode != 0) + return -1; + + /* These special cases just insert one extra opcode */ + + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + + /* These cases might insert additional copies of a preceding character. */ + + else { + if (minRepeats != 1) { + length -= lastitemlength; /* Uncount the original char or metachar */ + if (minRepeats > 0) + length += 5 + lastitemlength; + } + length += lastitemlength + ((maxRepeats > 0) ? 5 : 1); + } + + if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; /* Needs no extra length */ + + POSSESSIVE: /* Test for possessive quantifier */ + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */ + } + continue; + + /* An alternation contains an offset to the next branch or ket. If any ims + options changed in the previous branch(es), and/or if we are in a + lookbehind assertion, extra space will be needed at the start of the + branch. This is handled by branch_extra. */ + + case '|': + if (brastackptr == 0) + cd.needOuterBracket = true; + length += 1 + LINK_SIZE + branch_extra; + continue; + + /* A character class uses 33 characters provided that all the character + values are less than 256. Otherwise, it uses a bit map for low valued + characters, and individual items for others. Don't worry about character + types that aren't allowed in classes - they'll get picked up during the + compile. A character class that contains only one single-byte character + uses 2 or 3 bytes, depending on whether it is negated or not. Notice this + where we can. (In UTF-8 mode we can do this only for chars < 128.) */ + + case '[': { + int class_optcount; + if (*(++ptr) == '^') { + class_optcount = 10; /* Greater than one */ + ptr++; + } + else + class_optcount = 0; + + bool class_utf8 = false; + + for (; ptr < patternEnd && *ptr != ']'; ++ptr) { + /* Check for escapes */ + + if (*ptr == '\\') { + c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); + if (errorcode != 0) + return -1; + + /* Handle escapes that turn into characters */ + + if (c >= 0) + goto NON_SPECIAL_CHARACTER; + + /* Escapes that are meta-things. The normal ones just affect the + bit map, but Unicode properties require an XCLASS extended item. */ + + else + class_optcount = 10; /* \d, \s etc; make sure > 1 */ + } + + /* Anything else increments the possible optimization count. We have to + detect ranges here so that we can compute the number of extra ranges for + caseless wide characters when UCP support is available. If there are wide + characters, we are going to have to use an XCLASS, even for single + characters. */ + + else { + c = *ptr; + + /* Come here from handling \ above when it escapes to a char value */ + + NON_SPECIAL_CHARACTER: + class_optcount++; + + int d = -1; + if (safelyCheckNextChar(ptr, patternEnd, '-')) { + const UChar* hyptr = ptr++; + if (safelyCheckNextChar(ptr, patternEnd, '\\')) { + ptr++; + d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); + if (errorcode != 0) + return -1; + } + else if ((ptr + 1 < patternEnd) && ptr[1] != ']') + d = *++ptr; + if (d < 0) + ptr = hyptr; /* go back to hyphen as data */ + } + + /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or > + 127 for caseless matching, we will need to use an XCLASS. */ + + if (d >= 0) { + class_optcount = 10; /* Ensure > 1 */ + if (d < c) { + errorcode = ERR8; + return -1; + } + + if ((d > 255 || (ignoreCase && d > 127))) { + unsigned char buffer[6]; + if (!class_utf8) /* Allow for XCLASS overhead */ + { + class_utf8 = true; + length += LINK_SIZE + 2; + } + + /* If we have UCP support, find out how many extra ranges are + needed to map the other case of characters within this range. We + have to mimic the range optimization here, because extending the + range upwards might push d over a boundary that makes it use + another byte in the UTF-8 representation. */ + + if (ignoreCase) { + int occ, ocd; + int cc = c; + int origd = d; + while (getOthercaseRange(&cc, origd, &occ, &ocd)) { + if (occ >= c && ocd <= d) + continue; /* Skip embedded */ + + if (occ < c && ocd >= c - 1) /* Extend the basic range */ + { /* if there is overlap, */ + c = occ; /* noting that if occ < c */ + continue; /* we can't have ocd > d */ + } /* because a subrange is */ + if (ocd > d && occ <= d + 1) /* always shorter than */ + { /* the basic range. */ + d = ocd; + continue; + } + + /* An extra item is needed */ + + length += 1 + encodeUTF8(occ, buffer) + + ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer)); + } + } + + /* The length of the (possibly extended) range */ + + length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer); + } + + } + + /* We have a single character. There is nothing to be done unless we + are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must + allow for an XCL_SINGLE item, doubled for caselessness if there is UCP + support. */ + + else { + if ((c > 255 || (ignoreCase && c > 127))) { + unsigned char buffer[6]; + class_optcount = 10; /* Ensure > 1 */ + if (!class_utf8) /* Allow for XCLASS overhead */ + { + class_utf8 = true; + length += LINK_SIZE + 2; + } + length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer)); + } + } + } + } + + if (ptr >= patternEnd) { /* Missing terminating ']' */ + errorcode = ERR6; + return -1; + } + + /* We can optimize when there was only one optimizable character. + Note that this does not detect the case of a negated single character. + In that case we do an incorrect length computation, but it's not a serious + problem because the computed length is too large rather than too small. */ + + if (class_optcount == 1) + goto NORMAL_CHAR; + + /* Here, we handle repeats for the class opcodes. */ + { + length += 33; + + /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, + we also need extra for wrapping the whole thing in a sub-pattern. */ + + if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode != 0) + return -1; + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + else + length += 5; + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; + } else if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; + } + } + continue; + } + + /* Brackets may be genuine groups or special things */ + + case '(': { + int branch_newextra = 0; + int bracket_length = BRA_LEN; + bool capturing = false; + + /* Handle special forms of bracket, which all start (? */ + + if (safelyCheckNextChar(ptr, patternEnd, '?')) { + switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) { + /* Non-referencing groups and lookaheads just move the pointer on, and + then behave like a non-special bracket, except that they don't increment + the count of extracting brackets. Ditto for the "once only" bracket, + which is in Perl from version 5.005. */ + + case ':': + case '=': + case '!': + ptr += 2; + break; + + /* Else loop checking valid options until ) is met. Anything else is an + error. If we are without any brackets, i.e. at top level, the settings + act as if specified in the options, so massage the options immediately. + This is for backward compatibility with Perl 5.004. */ + + default: + errorcode = ERR12; + return -1; + } + } else + capturing = true; + + /* Capturing brackets must be counted so we can process escapes in a + Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need + an additional 3 bytes of memory per capturing bracket. */ + + if (capturing) { + bracount++; + if (bracount > EXTRACT_BASIC_MAX) + bracket_length += 3; + } + + /* Save length for computing whole length at end if there's a repeat that + requires duplication of the group. Also save the current value of + branch_extra, and start the new group with the new value. If non-zero, this + will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ + + if (brastackptr >= sizeof(brastack)/sizeof(int)) { + errorcode = ERR17; + return -1; + } + + bralenstack[brastackptr] = branch_extra; + branch_extra = branch_newextra; + + brastack[brastackptr++] = length; + length += bracket_length; + continue; + } + + /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we + have to replicate this bracket up to that many times. If brastackptr is + 0 this is an unmatched bracket which will generate an error, but take care + not to try to access brastack[-1] when computing the length and restoring + the branch_extra value. */ + + case ')': { + int duplength; + length += KET_LEN; + if (brastackptr > 0) { + duplength = length - brastack[--brastackptr]; + branch_extra = bralenstack[brastackptr]; + } + else + duplength = 0; + + /* Leave ptr at the final char; for readRepeatCounts this happens + automatically; for the others we need an increment. */ + + if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode) + return -1; + } else if (c == '*') { + minRepeats = 0; + maxRepeats = -1; + ptr++; + } else if (c == '+') { + minRepeats = 1; + maxRepeats = -1; + ptr++; + } else if (c == '?') { + minRepeats = 0; + maxRepeats = 1; + ptr++; + } else { + minRepeats = 1; + maxRepeats = 1; + } + + /* If the minimum is zero, we have to allow for an OP_BRAZERO before the + group, and if the maximum is greater than zero, we have to replicate + maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting + bracket set. */ + + int repeatsLength; + if (minRepeats == 0) { + length++; + if (maxRepeats > 0) { + repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + BRA_LEN + KET_LEN + OPCODE_LEN); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength; + if (length > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + } + } + + /* When the minimum is greater than zero, we have to replicate up to + minval-1 times, with no additions required in the copies. Then, if there + is a limited maximum we have to replicate up to maxval-1 times allowing + for a BRAZERO item before each optional copy and nesting brackets for all + but one of the optional copies. */ + + else { + repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength; + if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */ + repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + BRAZERO_LEN + BRA_LEN + KET_LEN); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength - (2 + 2 * LINK_SIZE); + } + if (length > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + } + + /* Allow space for once brackets for "possessive quantifier" */ + + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; + } + continue; + } + + /* Non-special character. It won't be space or # in extended mode, so it is + always a genuine character. If we are in a \Q...\E sequence, check for the + end; if not, we have a literal. */ + + default: + NORMAL_CHAR: + length += 2; /* For a one-byte character */ + lastitemlength = 1; /* Default length of last item for repeats */ + + if (c > 127) { + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (c <= jsc_pcre_utf8_table1[i]) + break; + length += i; + lastitemlength += i; + } + + continue; + } + } + + length += KET_LEN + OPCODE_LEN; /* For final KET and END */ + + cd.numCapturingBrackets = bracount; + return length; +} + +/************************************************* +* Compile a Regular Expression * +*************************************************/ + +/* This function takes a string and returns a pointer to a block of store +holding a compiled version of the expression. The original API for this +function had no error code return variable; it is retained for backwards +compatibility. The new function is given a new name. + +Arguments: + pattern the regular expression + options various option bits + errorCodePtr pointer to error code variable (pcre_compile2() only) + can be NULL if you don't want a code value + error pointer to pointer to error text + erroroffset ptr offset in pattern where error was detected + tables pointer to character tables or NULL + +Returns: pointer to compiled data block, or NULL on error, + with error and erroroffset set +*/ + +static inline JSRegExp* returnError(ErrorCode errorcode, int *error) +{ + *error = static_cast(errorcode); + return 0; +} + +JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, + JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline, + unsigned* numSubpatterns, int *error) +{ + /* We can't pass back an error message if error is NULL; I guess the best we + can do is just return NULL, but we can set a code value if there is a code pointer. */ + if (!error) + return 0; + *error = 0; + + CompileData cd; + + ErrorCode errorcode = ERR0; + /* Call this once just to count the brackets. */ + calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); + /* Call it again to compute the length. */ + int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); + if (errorcode) + return returnError(errorcode, error); + + if (length > MAX_PATTERN_SIZE) + return returnError(ERR16, error); + + size_t size = length + sizeof(JSRegExp); + JSRegExp* re = reinterpret_cast(js::OffTheBooks::array_new(size)); + if (!re) + return returnError(ERR13, error); + + re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0); + + /* The starting points of the name/number translation table and of the code are + passed around in the compile data block. */ + + const unsigned char* codeStart = (const unsigned char*)(re + 1); + + /* Set up a starting, non-extracting bracket, then compile the expression. On + error, errorcode will be set non-zero, so we don't need to look at the result + of the function here. */ + + const UChar* ptr = (const UChar*)pattern; + const UChar* patternEnd = pattern + patternLength; + unsigned char* code = const_cast(codeStart); + int firstByte, reqByte; + int bracketCount = 0; + if (!cd.needOuterBracket) + compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstByte, &reqByte, cd); + else { + *code = OP_BRA; + unsigned char * const codeBefore = code; + compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 2, &firstByte, &reqByte, cd); + JS_ASSERT((bracketCount & 0xff) == bracketCount); + put2ByteValue(codeBefore + 1 + LINK_SIZE, 0 << 8 | (bracketCount & 0xff)); + } + re->topBracket = bracketCount; + re->topBackref = cd.topBackref; + + /* If not reached end of pattern on success, there's an excess bracket. */ + + if (errorcode == 0 && ptr < patternEnd) + errorcode = ERR10; + + /* Fill in the terminating state and check for disastrous overflow, but + if debugging, leave the test till after things are printed out. */ + + *code++ = OP_END; + + JS_ASSERT(code - codeStart <= length); + if (code - codeStart > length) + errorcode = ERR7; + + /* Give an error if there's back reference to a non-existent capturing + subpattern. */ + + if (re->topBackref > re->topBracket) + errorcode = ERR15; + + /* Failed to compile, or error while post-processing */ + + if (errorcode != ERR0) { + js::Foreground::array_delete(reinterpret_cast(re)); + return returnError(errorcode, error); + } + + /* If the anchored option was not passed, set the flag if we can determine that + the pattern is anchored by virtue of ^ characters or \A or anything else (such + as starting with .* when DOTALL is set). + + Otherwise, if we know what the first character has to be, save it, because that + speeds up unanchored matches no end. If not, see if we can set the + UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches + start with ^. and also when all branches start with .* for non-DOTALL matches. + */ + + if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart)) + re->options |= IsAnchoredOption; + else { + if (firstByte < 0) { + firstByte = (cd.needOuterBracket + ? bracketFindFirstAssertedCharacter(codeStart, false) + : branchFindFirstAssertedCharacter(codeStart, false)) + | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0); + } + if (firstByte >= 0) { + int ch = firstByte & 255; + if (ch < 127) { + re->firstByte = ((firstByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstByte; + re->options |= UseFirstByteOptimizationOption; + } + } else { + if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap)) + re->options |= UseMultiLineFirstByteOptimizationOption; + } + } + + /* For an anchored pattern, we use the "required byte" only if it follows a + variable length item in the regex. Remove the caseless flag for non-caseable + bytes. */ + + if (reqByte >= 0 && (!(re->options & IsAnchoredOption) || (reqByte & REQ_VARY))) { + int ch = reqByte & 255; + if (ch < 127) { + re->reqByte = ((reqByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqByte & ~REQ_IGNORE_CASE) : reqByte; + re->options |= UseRequiredByteOptimizationOption; + } + } + + if (numSubpatterns) + *numSubpatterns = re->topBracket; + + return re; +} + +void jsRegExpFree(JSRegExp* re) +{ + js::Foreground::array_delete(reinterpret_cast(re)); +} diff --git a/js/src/yarr/pcre/pcre_exec.cpp b/js/src/yarr/pcre/pcre_exec.cpp new file mode 100644 index 000000000000..c2d154d67b8e --- /dev/null +++ b/js/src/yarr/pcre/pcre_exec.cpp @@ -0,0 +1,2193 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + Copyright (C) 2007 Eric Seidel + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains jsRegExpExecute(), the externally visible function +that does pattern matching using an NFA algorithm, following the rules from +the JavaScript specification. There are also some supporting functions. */ + +#include "pcre_internal.h" + +#include +#include "yarr/jswtfbridge.h" +#include "yarr/wtf/ASCIICType.h" +#include "jsarena.h" +#include "jscntxt.h" + +using namespace WTF; + +#if !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO +#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION +#endif + +/* Note: Webkit sources have USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP disabled. */ +/* Note: There are hardcoded constants all over the place, but in the port of + Yarr to TraceMonkey two bytes are added to the OP_BRA* opcodes, so the + instruction stream now looks like this at the start of a bracket group: + + OP_BRA* [link:LINK_SIZE] [minNestedBracket,maxNestedBracket:2] + + Both capturing and non-capturing brackets encode this information. */ + +/* Avoid warnings on Windows. */ +#undef min +#undef max + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION +typedef int ReturnLocation; +#else +typedef void* ReturnLocation; +#endif + +/* Node on a stack of brackets. This is used to detect and reject + matches of the empty string per ECMAScript repeat match rules. This + also prevents infinite loops on quantified empty matches. One node + represents the start state at the start of this bracket group. */ +struct BracketChainNode { + BracketChainNode* previousBracket; + const UChar* bracketStart; + /* True if the minimum number of matches was already satisfied + when we started matching this group. */ + bool minSatisfied; +}; + +struct MatchFrame { + ReturnLocation returnLocation; + struct MatchFrame* previousFrame; + int *savedOffsets; + /* The frame allocates saved offsets into the regular expression arena pool so + that they can be restored during backtracking. */ + size_t savedOffsetsSize; + JSArenaPool *regExpPool; + + MatchFrame() : savedOffsetsSize(0), regExpPool(0) {} + void init(JSArenaPool *regExpPool) { this->regExpPool = regExpPool; } + + /* Function arguments that may change */ + struct { + const UChar* subjectPtr; + const unsigned char* instructionPtr; + int offsetTop; + BracketChainNode* bracketChain; + } args; + + + /* PCRE uses "fake" recursion built off of gotos, thus + stack-based local variables are not safe to use. Instead we have to + store local variables on the current MatchFrame. */ + struct { + const unsigned char* data; + const unsigned char* startOfRepeatingBracket; + const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare + const unsigned char* instructionPtrAtStartOfOnce; + + int repeatOthercase; + int savedSubjectOffset; + + int ctype; + int fc; + int fi; + int length; + int max; + int number; + int offset; + int skipBytes; + int minBracket; + int limitBracket; + int bracketsBefore; + bool minSatisfied; + + BracketChainNode bracketChainNode; + } locals; + + void saveOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + JS_ASSERT(regExpPool); + JS_ASSERT(minBracket >= 0); + JS_ASSERT(limitBracket >= minBracket); + JS_ASSERT(offsetEnd >= 0); + if (minBracket == limitBracket) + return; + const size_t newSavedOffsetCount = 3 * (limitBracket - minBracket); + /* Increase saved offset space if necessary. */ + { + size_t targetSize = sizeof(*savedOffsets) * newSavedOffsetCount; + if (savedOffsetsSize < targetSize) { + JS_ARENA_ALLOCATE_CAST(savedOffsets, int *, regExpPool, targetSize); + JS_ASSERT(savedOffsets); /* FIXME: error code, bug 574459. */ + savedOffsetsSize = targetSize; + } + } + for (unsigned i = 0; i < unsigned(limitBracket - minBracket); ++i) { + int bracketIter = minBracket + i; + JS_ASSERT(2 * bracketIter + 1 <= offsetEnd); + int start = offsets[2 * bracketIter]; + int end = offsets[2 * bracketIter + 1]; + JS_ASSERT(bracketIter <= offsetEnd); + int offset = offsets[offsetEnd - bracketIter]; + DPRINTF(("saving bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); + JS_ASSERT(start <= end); + JS_ASSERT(i * 3 + 2 < newSavedOffsetCount); + savedOffsets[i * 3 + 0] = start; + savedOffsets[i * 3 + 1] = end; + savedOffsets[i * 3 + 2] = offset; + } + } + + void clobberOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + for (int i = 0; i < limitBracket - minBracket; ++i) { + int bracketIter = minBracket + i; + JS_ASSERT(2 * bracketIter + 1 < offsetEnd); + offsets[2 * bracketIter + 0] = -1; + offsets[2 * bracketIter + 1] = -1; + } + } + + void restoreOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + JS_ASSERT(regExpPool); + JS_ASSERT_IF(limitBracket > minBracket, savedOffsets); + for (int i = 0; i < limitBracket - minBracket; ++i) { + int bracketIter = minBracket + i; + int start = savedOffsets[i * 3 + 0]; + int end = savedOffsets[i * 3 + 1]; + int offset = savedOffsets[i * 3 + 2]; + DPRINTF(("restoring bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); + JS_ASSERT(start <= end); + offsets[2 * bracketIter + 0] = start; + offsets[2 * bracketIter + 1] = end; + offsets[offsetEnd - bracketIter] = offset; + } + } + + /* Extract the bracket data after the current opcode/link at |instructionPtr| into the locals. */ + void extractBrackets(const unsigned char *instructionPtr) { + uint16 bracketMess = get2ByteValue(instructionPtr + 1 + LINK_SIZE); + locals.minBracket = (bracketMess >> 8) & 0xff; + locals.limitBracket = (bracketMess & 0xff); + JS_ASSERT(locals.minBracket <= locals.limitBracket); + } + + /* At the start of a bracketed group, add the current subject pointer to the + stack of such pointers, to be re-instated at the end of the group when we hit + the closing ket. When match() is called in other circumstances, we don't add to + this stack. */ + void startNewGroup(bool minSatisfied) { + locals.bracketChainNode.previousBracket = args.bracketChain; + locals.bracketChainNode.bracketStart = args.subjectPtr; + locals.bracketChainNode.minSatisfied = minSatisfied; + args.bracketChain = &locals.bracketChainNode; + } +}; + +/* Structure for passing "static" information around between the functions +doing traditional NFA matching, so that they are thread-safe. */ + +struct MatchData { + int *offsetVector; /* Offset vector */ + int offsetEnd; /* One past the end */ + int offsetMax; /* The maximum usable for return data */ + bool offsetOverflow; /* Set if too many extractions */ + const UChar *startSubject; /* Start of the subject string */ + const UChar *endSubject; /* End of the subject string */ + const UChar *endMatchPtr; /* Subject position at end match */ + int endOffsetTop; /* Highwater mark at end of match */ + bool multiline; + bool ignoreCase; + + void setOffsetPair(size_t pairNum, int start, int end) { + JS_ASSERT(int(2 * pairNum + 1) < offsetEnd && int(pairNum) < offsetEnd); + JS_ASSERT(start <= end); + JS_ASSERT_IF(start < 0, start == end && start == -1); + DPRINTF(("setting offset pair at %u (%d, %d)\n", pairNum, start, end)); + offsetVector[2 * pairNum + 0] = start; + offsetVector[2 * pairNum + 1] = end; + } +}; + +/* The maximum remaining length of subject we are prepared to search for a +reqByte match. */ + +#define REQ_BYTE_MAX 1000 + +/* The below limit restricts the number of "recursive" match calls in order to +avoid spending exponential time on complex regular expressions. */ + +static const unsigned matchLimit = 1000000; + +/************************************************* +* Match a back-reference * +*************************************************/ + +/* If a back reference hasn't been set, the length that is passed is greater +than the number of characters left in the string, so the match fails. + +Arguments: + offset index into the offset vector + subjectPtr points into the subject + length length to be matched + md points to match data block + +Returns: true if matched +*/ + +static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md) +{ + const UChar* p = md.startSubject + md.offsetVector[offset]; + + /* Always fail if not enough characters left */ + + if (length > md.endSubject - subjectPtr) + return false; + + /* Separate the caselesss case for speed */ + + if (md.ignoreCase) { + while (length-- > 0) { + UChar c = *p++; + int othercase = jsc_pcre_ucp_othercase(c); + UChar d = *subjectPtr++; + if (c != d && othercase != d) + return false; + } + } + else { + while (length-- > 0) + if (*p++ != *subjectPtr++) + return false; + } + + return true; +} + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + +/* Use numbered labels and switch statement at the bottom of the match function. */ + +#define RMATCH_WHERE(num) num +#define RRETURN_LABEL RRETURN_SWITCH + +#else + +/* Use GCC's computed goto extension. */ + +/* For one test case this is more than 40% faster than the switch statement. +We could avoid the use of the num argument entirely by using local labels, +but using it for the GCC case as well as the non-GCC case allows us to share +a bit more code and notice if we use conflicting numbers.*/ + +#define RMATCH_WHERE(num) JS_EXTENSION(&&RRETURN_##num) +#define RRETURN_LABEL *stack.currentFrame->returnLocation + +#endif + +#define RECURSIVE_MATCH_COMMON(num) \ + goto RECURSE;\ + RRETURN_##num: \ + stack.popCurrentFrame(); + +#define RECURSIVE_MATCH(num, ra, rb) \ + do { \ + stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ + RECURSIVE_MATCH_COMMON(num) \ + } while (0) + +#define RECURSIVE_MATCH_NEW_GROUP(num, ra, rb, gm) \ + do { \ + stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ + stack.currentFrame->startNewGroup(gm); \ + RECURSIVE_MATCH_COMMON(num) \ + } while (0) + +#define RRETURN do { JS_EXTENSION_(goto RRETURN_LABEL); } while (0) + +#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0) + +/************************************************* +* Match from current position * +*************************************************/ + +/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character +in the subject string, while substringStart holds the value of subjectPtr at the start of the +last bracketed group - used for breaking infinite loops matching zero-length +strings. This function is called recursively in many circumstances. Whenever it +returns a negative (error) response, the outer match() call must also return the +same response. + +Arguments: + subjectPtr pointer in subject + instructionPtr position in code + offsetTop current top pointer + md pointer to "static" info for the match + +Returns: 1 if matched ) these values are >= 0 + 0 if failed to match ) + a negative error value if aborted by an error condition + (e.g. stopped by repeated call or recursion limit) +*/ + +static const unsigned numFramesOnStack = 16; + +struct MatchStack { + JSArenaPool *regExpPool; + void *regExpPoolMark; + + MatchStack(JSArenaPool *regExpPool) + : regExpPool(regExpPool) + , regExpPoolMark(JS_ARENA_MARK(regExpPool)) + , framesEnd(frames + numFramesOnStack) + , currentFrame(frames) + , size(1) // match() creates accesses the first frame w/o calling pushNewFrame + { + JS_ASSERT((sizeof(frames) / sizeof(frames[0])) == numFramesOnStack); + JS_ASSERT(regExpPool); + for (size_t i = 0; i < numFramesOnStack; ++i) + frames[i].init(regExpPool); + } + + ~MatchStack() { JS_ARENA_RELEASE(regExpPool, regExpPoolMark); } + + MatchFrame frames[numFramesOnStack]; + MatchFrame* framesEnd; + MatchFrame* currentFrame; + unsigned size; + + bool canUseStackBufferForNextFrame() { + return size < numFramesOnStack; + } + + MatchFrame* allocateNextFrame() { + if (canUseStackBufferForNextFrame()) + return currentFrame + 1; + // FIXME: bug 574459 -- no NULL check + MatchFrame *frame = js::OffTheBooks::new_(); + frame->init(regExpPool); + return frame; + } + + void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation) { + MatchFrame* newframe = allocateNextFrame(); + newframe->previousFrame = currentFrame; + + newframe->args.subjectPtr = currentFrame->args.subjectPtr; + newframe->args.offsetTop = currentFrame->args.offsetTop; + newframe->args.instructionPtr = instructionPtr; + newframe->args.bracketChain = bracketChain; + newframe->returnLocation = returnLocation; + size++; + + currentFrame = newframe; + } + + void popCurrentFrame() { + MatchFrame* oldFrame = currentFrame; + currentFrame = currentFrame->previousFrame; + if (size > numFramesOnStack) + js::Foreground::delete_(oldFrame); + size--; + } + + void popAllFrames() { + while (size) + popCurrentFrame(); + } +}; + +static int matchError(int errorCode, MatchStack& stack) +{ + stack.popAllFrames(); + return errorCode; +} + +/* Get the next UTF-8 character, not advancing the pointer, incrementing length + if there are extra bytes. This is called when we know we are in UTF-8 mode. */ + +static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len) +{ + c = *subjectPtr; + if ((c & 0xc0) == 0xc0) { + int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + int gcss = 6 * gcaa; + c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; + for (int gcii = 1; gcii <= gcaa; gcii++) { + gcss -= 6; + c |= (subjectPtr[gcii] & 0x3f) << gcss; + } + len += gcaa; + } +} + +static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats) +{ + // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR + static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 }; + static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 }; + + JS_ASSERT(instructionOffset >= 0); + JS_ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR)); + + minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2 + minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset]; + maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset]; +} + +/* Helper class for passing a flag value from one op to the next that runs. + This allows us to set the flag in certain ops. When the flag is read, it + will be true only if the previous op set the flag, otherwise it is false. */ +class LinearFlag { +public: + LinearFlag() : flag(false) {} + + bool readAndClear() { + bool rv = flag; + flag = false; + return rv; + } + + void set() { + flag = true; + } + +private: + bool flag; +}; + +static int +match(JSArenaPool *regExpPool, const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md) +{ + bool isMatch = false; + int min; + bool minimize = false; /* Initialization not really needed, but some compilers think so. */ + unsigned remainingMatchCount = matchLimit; + int othercase; /* Declare here to avoid errors during jumps */ + bool minSatisfied; + + MatchStack stack(regExpPool); + LinearFlag minSatNextBracket; + + /* The opcode jump table. */ +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP +#define EMIT_JUMP_TABLE_ENTRY(opcode) JS_EXTENSION(&&LABEL_OP_##opcode) + static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) }; +#undef EMIT_JUMP_TABLE_ENTRY +#endif + + /* One-time setup of the opcode jump table. */ +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + for (int i = 255; !opcodeJumpTable[i]; i--) + opcodeJumpTable[i] = &&CAPTURING_BRACKET; +#endif + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + // Shark shows this as a hot line + // Using a static const here makes this line disappear, but makes later access hotter (not sure why) + stack.currentFrame->returnLocation = JS_EXTENSION(&&RETURN); +#else + stack.currentFrame->returnLocation = 0; +#endif + stack.currentFrame->args.subjectPtr = subjectPtr; + stack.currentFrame->args.instructionPtr = instructionPtr; + stack.currentFrame->args.offsetTop = offsetTop; + stack.currentFrame->args.bracketChain = 0; + stack.currentFrame->startNewGroup(false); + + /* This is where control jumps back to to effect "recursion" */ + +RECURSE: + if (!--remainingMatchCount) + return matchError(JSRegExpErrorHitLimit, stack); + + /* Now start processing the operations. */ + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + while (true) +#endif + { + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP +#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode +#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr] +#else +#define BEGIN_OPCODE(opcode) case OP_##opcode +#define NEXT_OPCODE continue +#endif +#define LOCALS(__ident) (stack.currentFrame->locals.__ident) + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + NEXT_OPCODE; +#else + switch (*stack.currentFrame->args.instructionPtr) +#endif + { + /* Non-capturing bracket: optimized */ + + BEGIN_OPCODE(BRA): + NON_CAPTURING_BRACKET: + DPRINTF(("start non-capturing bracket\n")); + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); + /* If we see no ALT, we have to skip three bytes of bracket data (link plus nested + bracket data. */ + stack.currentFrame->locals.skipBytes = 3; + /* We must compute this value at the top, before we move the instruction pointer. */ + stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); + do { + /* We need to extract this into a variable so we can correctly pass it by value + through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ + minSatisfied = stack.currentFrame->locals.minSatisfied; + RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); + if (isMatch) { + DPRINTF(("non-capturing bracket succeeded\n")); + RRETURN; + } + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + DPRINTF(("non-capturing bracket failed\n")); + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + RRETURN; + + /* Skip over large extraction number data if encountered. */ + + BEGIN_OPCODE(BRANUMBER): + stack.currentFrame->args.instructionPtr += 3; + NEXT_OPCODE; + + /* End of the pattern. */ + + BEGIN_OPCODE(END): + md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */ + md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */ + isMatch = true; + RRETURN; + + /* Assertion brackets. Check the alternative branches in turn - the + matching won't pass the KET for an assertion. If any one branch matches, + the assertion is true. Lookbehind assertions have an OP_REVERSE item at the + start of each branch to move the current point backwards, so the code at + this level is identical to the lookahead case. */ + + BEGIN_OPCODE(ASSERT): + { + uint16 bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); + LOCALS(minBracket) = (bracketMess >> 8) & 0xff; + LOCALS(limitBracket) = bracketMess & 0xff; + JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); + } + stack.currentFrame->locals.skipBytes = 3; + do { + RECURSIVE_MATCH_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); + if (isMatch) + break; + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + if (*stack.currentFrame->args.instructionPtr == OP_KET) { + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + RRETURN_NO_MATCH; + } + + /* Continue from after the assertion, updating the offsets high water + mark, since extracts may have been taken during the assertion. */ + + advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); + stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; + stack.currentFrame->args.offsetTop = md.endOffsetTop; + NEXT_OPCODE; + + /* Negative assertion: all branches must fail to match */ + + BEGIN_OPCODE(ASSERT_NOT): + stack.currentFrame->locals.skipBytes = 3; + { + unsigned bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); + LOCALS(minBracket) = (bracketMess >> 8) & 0xff; + LOCALS(limitBracket) = bracketMess & 0xff; + } + JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); + do { + RECURSIVE_MATCH_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); + if (isMatch) + RRETURN_NO_MATCH; + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.skipBytes + LINK_SIZE; + NEXT_OPCODE; + + /* An alternation is the end of a branch; scan along to find the end of the + bracketed group and go to there. */ + + BEGIN_OPCODE(ALT): + advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); + NEXT_OPCODE; + + /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating + that it may occur zero times. It may repeat infinitely, or not at all - + i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper + repeat limits are compiled as a number of copies, with the optional ones + preceded by BRAZERO or BRAMINZERO. */ + + BEGIN_OPCODE(BRAZERO): { + stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain, true); + if (isMatch) + RRETURN; + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); + stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE; + NEXT_OPCODE; + } + + BEGIN_OPCODE(BRAMINZERO): { + stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; + advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); + RECURSIVE_MATCH_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain, false); + if (isMatch) + RRETURN; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + } + + /* End of a group, repeated or non-repeating. If we are at the end of + an assertion "group", stop matching and return 1, but record the + current high water mark for use by positive assertions. Do this also + for the "once" (not-backup up) groups. */ + + BEGIN_OPCODE(KET): + BEGIN_OPCODE(KETRMIN): + BEGIN_OPCODE(KETRMAX): + stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart; + stack.currentFrame->locals.minSatisfied = stack.currentFrame->args.bracketChain->minSatisfied; + + /* Back up the stack of bracket start pointers. */ + + stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket; + + if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) { + md.endOffsetTop = stack.currentFrame->args.offsetTop; + isMatch = true; + RRETURN; + } + + /* In all other cases except a conditional group we have to check the + group number back at the start and if necessary complete handling an + extraction by setting the offsets and bumping the high water mark. */ + + stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA; + + /* For extended extraction brackets (large number), we have to fish out + the number from a dummy opcode at the start. */ + + if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) + stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 4 + LINK_SIZE); + stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; + + DPRINTF(("end bracket %d\n", stack.currentFrame->locals.number)); + + /* Test for a numbered group. This includes groups called as a result + of recursion. Note that whole-pattern recursion is coded as a recurse + into group 0, so it won't be picked up here. Instead, we catch it when + the OP_END is reached. */ + + if (stack.currentFrame->locals.number > 0) { + if (stack.currentFrame->locals.offset >= md.offsetMax) + md.offsetOverflow = true; + else { + int start = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; + int end = stack.currentFrame->args.subjectPtr - md.startSubject; + if (start == end && stack.currentFrame->locals.minSatisfied) { + DPRINTF(("empty string while group already matched; bailing")); + RRETURN_NO_MATCH; + } + DPRINTF(("saving; start: %d; end: %d\n", start, end)); + JS_ASSERT(start <= end); + md.setOffsetPair(stack.currentFrame->locals.number, start, end); + if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset) + stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2; + } + } + + /* For a non-repeating ket, just continue at this level. This also + happens for a repeating ket if no characters were matched in the group. + This is the forcible breaking of infinite loops as implemented in Perl + 5.005. If there is an options reset, it will get obeyed in the normal + course of events. */ + + if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + DPRINTF(("non-repeating ket or empty match\n")); + if (stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction && stack.currentFrame->locals.minSatisfied) { + DPRINTF(("empty string while group already matched; bailing")); + RRETURN_NO_MATCH; + } + stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; + NEXT_OPCODE; + } + + /* The repeating kets try the rest of the pattern or restart from the + preceding bracket, in the appropriate order. */ + + stack.currentFrame->extractBrackets(LOCALS(instructionPtrAtStartOfOnce)); + JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); + if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) { + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + else + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + DPRINTF(("recursively matching lazy group\n")); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(17, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); + } else { /* OP_KETRMAX */ + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + stack.currentFrame->clobberOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + DPRINTF(("recursively matching greedy group\n")); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(18, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); + if (isMatch) + RRETURN; + else + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); + } + RRETURN; + + /* Start of subject. */ + + BEGIN_OPCODE(CIRC): + if (stack.currentFrame->args.subjectPtr != md.startSubject) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* After internal newline if multiline. */ + + BEGIN_OPCODE(BOL): + if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1])) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* End of subject. */ + + BEGIN_OPCODE(DOLL): + if (stack.currentFrame->args.subjectPtr < md.endSubject) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Before internal newline if multiline. */ + + BEGIN_OPCODE(EOL): + if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Word boundary assertions */ + + BEGIN_OPCODE(NOT_WORD_BOUNDARY): + BEGIN_OPCODE(WORD_BOUNDARY): { + bool currentCharIsWordChar = false; + bool previousCharIsWordChar = false; + + if (stack.currentFrame->args.subjectPtr > md.startSubject) + previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]); + if (stack.currentFrame->args.subjectPtr < md.endSubject) + currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr); + + /* Now see if the situation is what we want */ + bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY); + if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar) + RRETURN_NO_MATCH; + NEXT_OPCODE; + } + + /* Match a single character type; inline for speed */ + + BEGIN_OPCODE(NOT_NEWLINE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isNewline(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_DIGIT): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(DIGIT): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_WHITESPACE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isSpaceChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(WHITESPACE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_WORDCHAR): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isWordChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(WORDCHAR): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isWordChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Match a back reference, possibly repeatedly. Look past the end of the + item to see if there is repeat information following. The code is similar + to that for character classes, but repeated for efficiency. Then obey + similar code to character type repeats - written out again for speed. + However, if the referenced string is the empty string, always treat + it as matched, any number of times (otherwise there could be infinite + loops). */ + + BEGIN_OPCODE(REF): + stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */ + stack.currentFrame->args.instructionPtr += 3; /* Advance past item */ + + /* If the reference is unset, set the length to be longer than the amount + of subject left; this ensures that every attempt at a match fails. We + can't just fail here, because of the possibility of quantifiers with zero + minima. */ + + if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0) + stack.currentFrame->locals.length = 0; + else + stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset]; + + /* Set up for repetition, or handle the non-repeated case */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + NEXT_OPCODE; + } + + /* If the length of the reference is zero, just continue with the + main loop. */ + + if (stack.currentFrame->locals.length == 0) + NEXT_OPCODE; + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + + /* If min = max, continue at the same level without recursion. + They are not both allowed to be zero. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep trying and advancing the pointer */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + /* Control never reaches here */ + } + + /* If maximizing, find the longest string and work backwards */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + break; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + + /* Match a bit-mapped character class, possibly repeatedly. This op code is + used when all the characters in the class have values in the range 0-255, + and either the matching is caseful, or the characters are in the range + 0-127 when UTF-8 processing is enabled. The only difference between + OP_CLASS and OP_NCLASS occurs when a data character outside the range is + encountered. + + First, look past the end of the item to see if there is repeat information + following. Then obey similar code to character type repeats - written out + again for speed. */ + + BEGIN_OPCODE(NCLASS): + BEGIN_OPCODE(CLASS): + stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */ + stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + min = stack.currentFrame->locals.max = 1; + break; + } + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int c = *stack.currentFrame->args.subjectPtr++; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + RRETURN_NO_MATCH; + } else { + if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) + RRETURN_NO_MATCH; + } + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + int c = *stack.currentFrame->args.subjectPtr++; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + RRETURN; + } else { + if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0) + RRETURN; + } + } + /* Control never reaches here */ + } + /* If maximizing, find the longest possible run, then work backwards. */ + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + break; + } else { + if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) + break; + } + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + /* Control never reaches here */ + + /* Match an extended character class. */ + + BEGIN_OPCODE(XCLASS): + stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */ + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + min = stack.currentFrame->locals.max = 1; + } + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int c = *stack.currentFrame->args.subjectPtr++; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + RRETURN_NO_MATCH; + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + int c = *stack.currentFrame->args.subjectPtr++; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + RRETURN; + } + /* Control never reaches here */ + } + + /* If maximizing, find the longest possible run, then work backwards. */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + break; + ++stack.currentFrame->args.subjectPtr; + } + for(;;) { + RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + RRETURN; + } + + /* Control never reaches here */ + + /* Match a single character, casefully */ + + BEGIN_OPCODE(CHAR): + stack.currentFrame->locals.length = 1; + stack.currentFrame->args.instructionPtr++; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++) + RRETURN_NO_MATCH; + NEXT_OPCODE; + + /* Match a single character, caselessly */ + + BEGIN_OPCODE(CHAR_IGNORING_CASE): { + stack.currentFrame->locals.length = 1; + stack.currentFrame->args.instructionPtr++; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int dc = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fc != dc && jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc) + RRETURN_NO_MATCH; + NEXT_OPCODE; + } + + /* Match a single ASCII character. */ + + BEGIN_OPCODE(ASCII_CHAR): + if (md.endSubject == stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1]) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + stack.currentFrame->args.instructionPtr += 2; + NEXT_OPCODE; + + /* Match one of two cases of an ASCII letter. */ + + BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE): + if (md.endSubject == stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1]) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + stack.currentFrame->args.instructionPtr += 2; + NEXT_OPCODE; + + /* Match a single character repeatedly; different opcodes share code. */ + + BEGIN_OPCODE(EXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = false; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATCHAR; + + BEGIN_OPCODE(UPTO): + BEGIN_OPCODE(MINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATCHAR; + + BEGIN_OPCODE(STAR): + BEGIN_OPCODE(MINSTAR): + BEGIN_OPCODE(PLUS): + BEGIN_OPCODE(MINPLUS): + BEGIN_OPCODE(QUERY): + BEGIN_OPCODE(MINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single-character matches. We can give + up quickly if there are fewer than the minimum number of characters left in + the subject. */ + + REPEATCHAR: + + stack.currentFrame->locals.length = 1; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + + if (stack.currentFrame->locals.fc <= 0xFFFF) { + othercase = md.ignoreCase ? jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1; + + for (int i = 1; i <= min; i++) { + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + stack.currentFrame->locals.repeatOthercase = othercase; + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase) + RRETURN; + ++stack.currentFrame->args.subjectPtr; + } + /* Control never reaches here */ + } else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) + break; + ++stack.currentFrame->args.subjectPtr; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + --stack.currentFrame->args.subjectPtr; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + } else { + /* No case on surrogate pairs, so no need to bother with "othercase". */ + + for (int i = 1; i <= min; i++) { + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += 2; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + RRETURN; + stack.currentFrame->args.subjectPtr += 2; + } + /* Control never reaches here */ + } else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr > md.endSubject - 2) + break; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + break; + stack.currentFrame->args.subjectPtr += 2; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + stack.currentFrame->args.subjectPtr -= 2; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + } + /* Control never reaches here */ + + /* Match a negated single one-byte character. */ + + BEGIN_OPCODE(NOT): { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int b = stack.currentFrame->args.instructionPtr[1]; + int c = *stack.currentFrame->args.subjectPtr++; + stack.currentFrame->args.instructionPtr += 2; + if (md.ignoreCase) { + if (c < 128) + c = toLowerCase(c); + if (toLowerCase(b) == c) + RRETURN_NO_MATCH; + } else { + if (b == c) + RRETURN_NO_MATCH; + } + NEXT_OPCODE; + } + + /* Match a negated single one-byte character repeatedly. This is almost a + repeat of the code for a repeated single character, but I haven't found a + nice way of commoning these up that doesn't require a test of the + positive/negative option for each character match. Maybe that wouldn't add + very much to the time taken, but character matching *is* what this is all + about... */ + + BEGIN_OPCODE(NOTEXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = false; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATNOTCHAR; + + BEGIN_OPCODE(NOTUPTO): + BEGIN_OPCODE(NOTMINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATNOTCHAR; + + BEGIN_OPCODE(NOTSTAR): + BEGIN_OPCODE(NOTMINSTAR): + BEGIN_OPCODE(NOTPLUS): + BEGIN_OPCODE(NOTMINPLUS): + BEGIN_OPCODE(NOTQUERY): + BEGIN_OPCODE(NOTMINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single-byte matches. We can give up quickly + if there are fewer than the minimum number of bytes left in the + subject. */ + + REPEATNOTCHAR: + if (min > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++; + + /* The code is duplicated for the caseless and caseful cases, for speed, + since matching characters is likely to be quite common. First, ensure the + minimum number of matches are present. If min = max, continue at the same + level without recursing. Otherwise, if minimizing, keep trying the rest of + the expression and advancing one matching character if failing, up to the + maximum. Alternatively, if maximizing, find the maximum number of + characters and work backwards. */ + + DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max)); + + if (md.ignoreCase) { + if (stack.currentFrame->locals.fc < 128) + stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc); + + for (int i = 1; i <= min; i++) { + int d = *stack.currentFrame->args.subjectPtr++; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fc == d) + RRETURN_NO_MATCH; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + int d = *stack.currentFrame->args.subjectPtr++; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) + RRETURN; + } + /* Control never reaches here */ + } + + /* Maximize case */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int d = *stack.currentFrame->args.subjectPtr; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fc == d) + break; + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + /* Control never reaches here */ + } + + /* Caseful comparisons */ + + else { + for (int i = 1; i <= min; i++) { + int d = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fc == d) + RRETURN_NO_MATCH; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + int d = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) + RRETURN; + } + /* Control never reaches here */ + } + + /* Maximize case */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int d = *stack.currentFrame->args.subjectPtr; + if (stack.currentFrame->locals.fc == d) + break; + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + } + /* Control never reaches here */ + + /* Match a single character type repeatedly; several different opcodes + share code. This is very similar to the code for single characters, but we + repeat it in the interests of efficiency. */ + + BEGIN_OPCODE(TYPEEXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = true; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATTYPE; + + BEGIN_OPCODE(TYPEUPTO): + BEGIN_OPCODE(TYPEMINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATTYPE; + + BEGIN_OPCODE(TYPESTAR): + BEGIN_OPCODE(TYPEMINSTAR): + BEGIN_OPCODE(TYPEPLUS): + BEGIN_OPCODE(TYPEMINPLUS): + BEGIN_OPCODE(TYPEQUERY): + BEGIN_OPCODE(TYPEMINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single character type matches. Note that + in UTF-8 mode, '.' matches a character of any length, but for the other + character types, the valid characters are all one-byte long. */ + + REPEATTYPE: + stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */ + + /* First, ensure the minimum number of matches are present. Use inline + code for maximizing the speed, and do the type test once at the start + (i.e. keep it out of the loop). Also we can test that there are at least + the minimum number of characters before we start. */ + + if (min > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if (min > 0) { + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + for (int i = 1; i <= min; i++) { + if (isNewline(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_DIGIT: + for (int i = 1; i <= min; i++) { + if (isASCIIDigit(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_DIGIT: + for (int i = 1; i <= min; i++) { + if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WHITESPACE: + for (int i = 1; i <= min; i++) { + if (isSpaceChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WHITESPACE: + for (int i = 1; i <= min; i++) { + if (!isSpaceChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WORDCHAR: + for (int i = 1; i <= min; i++) { + if (isWordChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WORDCHAR: + for (int i = 1; i <= min; i++) { + if (!isWordChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } /* End switch(stack.currentFrame->locals.ctype) */ + } + + /* If min = max, continue at the same level without recursing */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, we have to test the rest of the pattern before each + subsequent match. */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + + int c = *stack.currentFrame->args.subjectPtr++; + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + if (isNewline(c)) + RRETURN; + break; + + case OP_NOT_DIGIT: + if (isASCIIDigit(c)) + RRETURN; + break; + + case OP_DIGIT: + if (!isASCIIDigit(c)) + RRETURN; + break; + + case OP_NOT_WHITESPACE: + if (isSpaceChar(c)) + RRETURN; + break; + + case OP_WHITESPACE: + if (!isSpaceChar(c)) + RRETURN; + break; + + case OP_NOT_WORDCHAR: + if (isWordChar(c)) + RRETURN; + break; + + case OP_WORDCHAR: + if (!isWordChar(c)) + RRETURN; + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } + } + /* Control never reaches here */ + } + + /* If maximizing it is worth using inline code for speed, doing the type + test once at the start (i.e. keep it out of the loop). */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */ + + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr)) + break; + stack.currentFrame->args.subjectPtr++; + } + break; + + case OP_NOT_DIGIT: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isASCIIDigit(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_DIGIT: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isASCIIDigit(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WHITESPACE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isSpaceChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WHITESPACE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isSpaceChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WORDCHAR: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isWordChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WORDCHAR: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isWordChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } + + /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */ + + for (;;) { + RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + /* Get here if we can't make it match with any permitted repetitions */ + + RRETURN; + } + /* Control never reaches here */ + + BEGIN_OPCODE(CRMINPLUS): + BEGIN_OPCODE(CRMINQUERY): + BEGIN_OPCODE(CRMINRANGE): + BEGIN_OPCODE(CRMINSTAR): + BEGIN_OPCODE(CRPLUS): + BEGIN_OPCODE(CRQUERY): + BEGIN_OPCODE(CRRANGE): + BEGIN_OPCODE(CRSTAR): + JS_NOT_REACHED("Invalid opcode."); + return matchError(JSRegExpErrorInternal, stack); + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + CAPTURING_BRACKET: +#else + default: +#endif + /* Opening capturing bracket. If there is space in the offset vector, save + the current subject position in the working slot at the top of the vector. We + mustn't change the current values of the data slot, because they may be set + from a previous iteration of this group, and be referred to by a reference + inside the group. + + If the bracket fails to match, we need to restore this value and also the + values of the final offsets, in case they were set by a previous iteration of + the same bracket. + + If there isn't enough space in the offset vector, treat this as if it were a + non-capturing bracket. Don't worry about setting the flag for the error case + here; that is handled in the code for KET. */ + + JS_ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA); + + LOCALS(number) = *stack.currentFrame->args.instructionPtr - OP_BRA; + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); + DPRINTF(("opening capturing bracket %d\n", stack.currentFrame->locals.number)); + + /* For extended extraction brackets (large number), we have to fish out the + number from a dummy opcode at the start. */ + + if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) + stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 4 + LINK_SIZE); + stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; + + JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); + + if (stack.currentFrame->locals.offset < md.offsetMax) { + stack.currentFrame->locals.savedSubjectOffset = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; + DPRINTF(("setting subject offset for bracket to %d\n", stack.currentFrame->args.subjectPtr - md.startSubject)); + md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject; + stack.currentFrame->locals.skipBytes = 3; /* For OP_BRAs. */ + + /* We must compute this value at the top, before we move the instruction pointer. */ + stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); + do { + /* We need to extract this into a variable so we can correctly pass it by value + through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ + minSatisfied = stack.currentFrame->locals.minSatisfied; + RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); + if (isMatch) + RRETURN; + stack.currentFrame->locals.skipBytes = 1; /* For OP_ALTs. */ + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + + DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number)); + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + DPRINTF(("restoring subject offset for bracket to %d\n", stack.currentFrame->locals.savedSubjectOffset)); + md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.savedSubjectOffset; + + RRETURN; + } + + /* Insufficient room for saving captured contents */ + + goto NON_CAPTURING_BRACKET; + } + + /* Do not stick any code in here without much thought; it is assumed + that "continue" in the code above comes out to here to repeat the main + loop. */ + + } /* End of main loop */ + + JS_NOT_REACHED("Loop does not fallthru."); + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + +RRETURN_SWITCH: + switch (stack.currentFrame->returnLocation) { + case 0: goto RETURN; + case 1: goto RRETURN_1; + case 2: goto RRETURN_2; + case 6: goto RRETURN_6; + case 7: goto RRETURN_7; + case 14: goto RRETURN_14; + case 15: goto RRETURN_15; + case 16: goto RRETURN_16; + case 17: goto RRETURN_17; + case 18: goto RRETURN_18; + case 19: goto RRETURN_19; + case 20: goto RRETURN_20; + case 21: goto RRETURN_21; + case 22: goto RRETURN_22; + case 24: goto RRETURN_24; + case 26: goto RRETURN_26; + case 27: goto RRETURN_27; + case 28: goto RRETURN_28; + case 29: goto RRETURN_29; + case 30: goto RRETURN_30; + case 31: goto RRETURN_31; + case 38: goto RRETURN_38; + case 40: goto RRETURN_40; + case 42: goto RRETURN_42; + case 44: goto RRETURN_44; + case 48: goto RRETURN_48; + case 52: goto RRETURN_52; + } + + JS_NOT_REACHED("Bad computed return location."); + return matchError(JSRegExpErrorInternal, stack); + +#endif + +RETURN: + return isMatch; +} + + +/************************************************* +* Execute a Regular Expression * +*************************************************/ + +/* This function applies a compiled re to a subject string and picks out +portions of the string if it matches. Two elements in the vector are set for +each substring: the offsets to the start and end of the substring. + +Arguments: + re points to the compiled expression + extra_data points to extra data or is NULL + subject points to the subject string + length length of subject string (may contain binary zeros) + start_offset where to start in the subject string + options option bits + offsets points to a vector of ints to be filled in with offsets + offsetCount the number of elements in the vector + +Returns: > 0 => success; value is the number of elements filled in + = 0 => success, but offsets is not big enough + -1 => failed to match + < -1 => some kind of unexpected problem +*/ + +static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int firstByte, bool firstByteIsCaseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart) +{ + // If firstByte is set, try scanning to the first instance of that byte + // no need to try and match against any earlier part of the subject string. + if (firstByte >= 0) { + UChar firstChar = firstByte; + if (firstByteIsCaseless) + while (subjectPtr < endSubject) { + int c = *subjectPtr; + if (c > 127) + break; + if (toLowerCase(c) == firstChar) + break; + subjectPtr++; + } + else { + while (subjectPtr < endSubject && *subjectPtr != firstChar) + subjectPtr++; + } + } else if (useMultiLineFirstCharOptimization) { + /* Or to just after \n for a multiline match if possible */ + // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07 + if (subjectPtr > originalSubjectStart) { + while (subjectPtr < endSubject && !isNewline(subjectPtr[-1])) + subjectPtr++; + } + } +} + +static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int reqByte, int reqByte2, bool reqByteIsCaseless, bool hasFirstByte, const UChar*& reqBytePtr) +{ + /* If reqByte is set, we know that that character must appear in the subject + for the match to succeed. If the first character is set, reqByte must be + later in the subject; otherwise the test starts at the match point. This + optimization can save a huge amount of backtracking in patterns with nested + unlimited repeats that aren't going to match. Writing separate code for + cased/caseless versions makes it go faster, as does using an autoincrement + and backing off on a match. + + HOWEVER: when the subject string is very, very long, searching to its end can + take a long time, and give bad performance on quite ordinary patterns. This + showed up when somebody was matching /^C/ on a 32-megabyte string... so we + don't do this when the string is sufficiently long. + */ + + if (reqByte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) { + const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0); + + /* We don't need to repeat the search if we haven't yet reached the + place we found it at last time. */ + + if (p > reqBytePtr) { + if (reqByteIsCaseless) { + while (p < endSubject) { + int pp = *p++; + if (pp == reqByte || pp == reqByte2) { + p--; + break; + } + } + } else { + while (p < endSubject) { + if (*p++ == reqByte) { + p--; + break; + } + } + } + + /* If we can't find the required character, break the matching loop */ + + if (p >= endSubject) + return true; + + /* If we have found the required character, save the point where we + found it, so that we don't search again next time round the loop if + the start hasn't passed this character yet. */ + + reqBytePtr = p; + } + } + return false; +} + +int jsRegExpExecute(JSContext *cx, const JSRegExp* re, + const UChar* subject, int length, int start_offset, int* offsets, + int offsetCount) +{ + JS_ASSERT(re); + JS_ASSERT(subject || !length); + JS_ASSERT(offsetCount >= 0); + JS_ASSERT(offsets || offsetCount == 0); + + MatchData matchBlock; + matchBlock.startSubject = subject; + matchBlock.endSubject = matchBlock.startSubject + length; + const UChar* endSubject = matchBlock.endSubject; + + matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption); + matchBlock.ignoreCase = (re->options & IgnoreCaseOption); + + /* Use the vector supplied, rounding down its size to a multiple of 3. */ + int ocount = offsetCount - (offsetCount % 3); + + matchBlock.offsetVector = offsets; + matchBlock.offsetEnd = ocount; + matchBlock.offsetMax = (2*ocount)/3; + matchBlock.offsetOverflow = false; + + /* Compute the minimum number of offsets that we need to reset each time. Doing + this makes a huge difference to execution time when there aren't many brackets + in the pattern. */ + + int resetCount = 2 + re->topBracket * 2; + if (resetCount > offsetCount) + resetCount = ocount; + + /* Reset the working variable associated with each extraction. These should + never be used unless previously set, but they get saved and restored, and so we + initialize them to avoid reading uninitialized locations. */ + + if (matchBlock.offsetVector) { + int* iptr = matchBlock.offsetVector + ocount; + int* iend = iptr - resetCount/2 + 1; + while (--iptr >= iend) + *iptr = -1; + } + + /* Set up the first character to match, if available. The firstByte value is + never set for an anchored regular expression, but the anchoring may be forced + at run time, so we have to test for anchoring. The first char may be unset for + an unanchored pattern, of course. If there's no first char and the pattern was + studied, there may be a bitmap of possible first characters. */ + + bool firstByteIsCaseless = false; + int firstByte = -1; + if (re->options & UseFirstByteOptimizationOption) { + firstByte = re->firstByte & 255; + if ((firstByteIsCaseless = (re->firstByte & REQ_IGNORE_CASE))) + firstByte = toLowerCase(firstByte); + } + + /* For anchored or unanchored matches, there may be a "last known required + character" set. */ + + bool reqByteIsCaseless = false; + int reqByte = -1; + int reqByte2 = -1; + if (re->options & UseRequiredByteOptimizationOption) { + reqByte = re->reqByte & 255; + reqByteIsCaseless = (re->reqByte & REQ_IGNORE_CASE); + reqByte2 = flipCase(reqByte); + } + + /* Loop for handling unanchored repeated matching attempts; for anchored regexs + the loop runs just once. */ + + const UChar* startMatch = subject + start_offset; + const UChar* reqBytePtr = startMatch - 1; + bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption; + + do { + /* Reset the maximum number of extractions we might see. */ + if (matchBlock.offsetVector) { + int* iptr = matchBlock.offsetVector; + int* iend = iptr + resetCount; + while (iptr < iend) + *iptr++ = -1; + } + + tryFirstByteOptimization(startMatch, endSubject, firstByte, firstByteIsCaseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset); + if (tryRequiredByteOptimization(startMatch, endSubject, reqByte, reqByte2, reqByteIsCaseless, firstByte >= 0, reqBytePtr)) + break; + + /* When a match occurs, substrings will be set for all internal extractions; + we just need to set up the whole thing as substring 0 before returning. If + there were too many extractions, set the return code to zero. In the case + where we had to get some local store to hold offsets for backreferences, copy + those back references that we can. In this case there need not be overflow + if certain parts of the pattern were not used. */ + + /* The code starts after the JSRegExp block and the capture name table. */ + const unsigned char* start_code = (const unsigned char*)(re + 1); + + int returnCode = match(&cx->regExpPool, startMatch, start_code, 2, matchBlock); + + /* When the result is no match, advance the pointer to the next character + and continue. */ + if (returnCode == 0) { + startMatch++; + continue; + } + + if (returnCode != 1) { + JS_ASSERT(returnCode == JSRegExpErrorHitLimit); + DPRINTF((">>>> error: returning %d\n", returnCode)); + return returnCode; + } + + /* We have a match! */ + + returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2; + + if (offsetCount < 2) + returnCode = 0; + else { + offsets[0] = startMatch - matchBlock.startSubject; + offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject; + } + + JS_ASSERT(returnCode >= 0); + DPRINTF((">>>> returning %d\n", returnCode)); + return returnCode; + } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject); + + DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); + return JSRegExpErrorNoMatch; +} diff --git a/js/src/yarr/pcre/pcre_internal.h b/js/src/yarr/pcre/pcre_internal.h new file mode 100644 index 000000000000..d677cfcfa255 --- /dev/null +++ b/js/src/yarr/pcre/pcre_internal.h @@ -0,0 +1,434 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This header contains definitions that are shared between the different +modules, but which are not relevant to the exported API. This includes some +functions whose names all begin with "_pcre_". */ + +#ifndef PCRE_INTERNAL_H +#define PCRE_INTERNAL_H + +/* Bit definitions for entries in the pcre_ctypes table. */ + +#define ctype_space 0x01 +#define ctype_xdigit 0x08 +#define ctype_word 0x10 /* alphameric or '_' */ + +/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set +of bits for a class map. Some classes are built by combining these tables. */ + +#define cbit_space 0 /* \s */ +#define cbit_digit 32 /* \d */ +#define cbit_word 64 /* \w */ +#define cbit_length 96 /* Length of the cbits table */ + +/* Offsets of the various tables from the base tables pointer, and +total length. */ + +#define lcc_offset 0 +#define fcc_offset 128 +#define cbits_offset 256 +#define ctypes_offset (cbits_offset + cbit_length) +#define tables_length (ctypes_offset + 128) + +#ifndef DFTABLES + +#include "pcre.h" + +/* The value of LINK_SIZE determines the number of bytes used to store links as +offsets within the compiled regex. The default is 2, which allows for compiled +patterns up to 64K long. */ + +#define LINK_SIZE 3 + +/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef +inline, and there are *still* stupid compilers about that don't like indented +pre-processor statements, or at least there were when I first wrote this. After +all, it had only been about 10 years then... */ + +#ifdef DEBUG +#define DPRINTF(p) /*printf p; fflush(stdout);*/ +#else +#define DPRINTF(p) /*nothing*/ +#endif + +/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored +in big-endian order) by default. These are used, for example, to link from the +start of a subpattern to its alternatives and its end. The use of 2 bytes per +offset limits the size of the compiled regex to around 64K, which is big enough +for almost everybody. However, I received a request for an even bigger limit. +For this reason, and also to make the code easier to maintain, the storing and +loading of offsets from the byte string is now handled by the functions that are +defined here. */ + +/* PCRE uses some other 2-byte quantities that do not change when the size of +offsets changes. There are used for repeat counts and for other things such as +capturing parenthesis numbers in back references. */ + +static inline void put2ByteValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value >= 0 && value <= 0xFFFF); + opcodePtr[0] = value >> 8; + opcodePtr[1] = value; +} + +static inline void put3ByteValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value >= 0 && value <= 0xFFFFFF); + opcodePtr[0] = value >> 16; + opcodePtr[1] = value >> 8; + opcodePtr[2] = value; +} + +static inline int get2ByteValue(const unsigned char* opcodePtr) +{ + return (opcodePtr[0] << 8) | opcodePtr[1]; +} + +static inline int get3ByteValue(const unsigned char* opcodePtr) +{ + return (opcodePtr[0] << 16) | (opcodePtr[1] << 8) | opcodePtr[2]; +} + +static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + put2ByteValue(opcodePtr, value); + opcodePtr += 2; +} + +static inline void put3ByteValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + put3ByteValue(opcodePtr, value); + opcodePtr += 3; +} + +static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value) +{ +#if LINK_SIZE == 3 + put3ByteValue(opcodePtr, value); +#elif LINK_SIZE == 2 + put2ByteValue(opcodePtr, value); +#else +# error LINK_SIZE not supported. +#endif +} + +static inline int getLinkValueAllowZero(const unsigned char* opcodePtr) +{ +#if LINK_SIZE == 3 + return get3ByteValue(opcodePtr); +#elif LINK_SIZE == 2 + return get2ByteValue(opcodePtr); +#else +# error LINK_SIZE not supported. +#endif +} + +#define MAX_PATTERN_SIZE 1024 * 1024 // Derived by empirical testing of compile time in PCRE and WREC. +JS_STATIC_ASSERT(MAX_PATTERN_SIZE < (1 << (8 * LINK_SIZE))); + +static inline void putLinkValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value); + putLinkValueAllowZero(opcodePtr, value); +} + +static inline int getLinkValue(const unsigned char* opcodePtr) +{ + int value = getLinkValueAllowZero(opcodePtr); + JS_ASSERT(value); + return value; +} + +static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + putLinkValue(opcodePtr, value); + opcodePtr += LINK_SIZE; +} + +static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value) +{ + putLinkValueAllowZero(opcodePtr, value); + opcodePtr += LINK_SIZE; +} + +// FIXME: These are really more of a "compiled regexp state" than "regexp options" +enum RegExpOptions { + UseFirstByteOptimizationOption = 0x40000000, /* firstByte is set */ + UseRequiredByteOptimizationOption = 0x20000000, /* reqByte is set */ + UseMultiLineFirstByteOptimizationOption = 0x10000000, /* start after \n for multiline */ + IsAnchoredOption = 0x02000000, /* can't use partial with this regex */ + IgnoreCaseOption = 0x00000001, + MatchAcrossMultipleLinesOption = 0x00000002 +}; + +/* Flags added to firstByte or reqByte; a "non-literal" item is either a +variable-length repeat, or a anything other than literal characters. */ + +#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */ +#define REQ_VARY 0x0200 /* reqByte followed non-literal item */ + +/* Miscellaneous definitions */ + +/* Flag bits and data types for the extended class (OP_XCLASS) for classes that +contain UTF-8 characters with values greater than 255. */ + +#define XCL_NOT 0x01 /* Flag: this is a negative class */ +#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ + +#define XCL_END 0 /* Marks end of individual items */ +#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ +#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ + +/* These are escaped items that aren't just an encoding of a particular data +value such as \n. They must have non-zero values, as check_escape() returns +their negation. Also, they must appear in the same order as in the opcode +definitions below, up to ESC_w. The final one must be +ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two +tests in the code for an escape > ESC_b and <= ESC_w to +detect the types that may be repeated. These are the types that consume +characters. If any new escapes are put in between that don't consume a +character, that code will have to change. */ + +enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF }; + +/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets +that extract substrings. Starting from 1 (i.e. after OP_END), the values up to +OP_EOD must correspond in order to the list of escapes immediately above. +Note that whenever this list is updated, the two macro definitions that follow +must also be updated to match. */ + +#define FOR_EACH_OPCODE(macro) \ + macro(END) \ + \ + , macro(NOT_WORD_BOUNDARY) \ + , macro(WORD_BOUNDARY) \ + , macro(NOT_DIGIT) \ + , macro(DIGIT) \ + , macro(NOT_WHITESPACE) \ + , macro(WHITESPACE) \ + , macro(NOT_WORDCHAR) \ + , macro(WORDCHAR) \ + \ + , macro(NOT_NEWLINE) \ + \ + , macro(CIRC) \ + , macro(DOLL) \ + , macro(BOL) \ + , macro(EOL) \ + , macro(CHAR) \ + , macro(CHAR_IGNORING_CASE) \ + , macro(ASCII_CHAR) \ + , macro(ASCII_LETTER_IGNORING_CASE) \ + , macro(NOT) \ + \ + , macro(STAR) \ + , macro(MINSTAR) \ + , macro(PLUS) \ + , macro(MINPLUS) \ + , macro(QUERY) \ + , macro(MINQUERY) \ + , macro(UPTO) \ + , macro(MINUPTO) \ + , macro(EXACT) \ + \ + , macro(NOTSTAR) \ + , macro(NOTMINSTAR) \ + , macro(NOTPLUS) \ + , macro(NOTMINPLUS) \ + , macro(NOTQUERY) \ + , macro(NOTMINQUERY) \ + , macro(NOTUPTO) \ + , macro(NOTMINUPTO) \ + , macro(NOTEXACT) \ + \ + , macro(TYPESTAR) \ + , macro(TYPEMINSTAR) \ + , macro(TYPEPLUS) \ + , macro(TYPEMINPLUS) \ + , macro(TYPEQUERY) \ + , macro(TYPEMINQUERY) \ + , macro(TYPEUPTO) \ + , macro(TYPEMINUPTO) \ + , macro(TYPEEXACT) \ + \ + , macro(CRSTAR) \ + , macro(CRMINSTAR) \ + , macro(CRPLUS) \ + , macro(CRMINPLUS) \ + , macro(CRQUERY) \ + , macro(CRMINQUERY) \ + , macro(CRRANGE) \ + , macro(CRMINRANGE) \ + \ + , macro(CLASS) \ + , macro(NCLASS) \ + , macro(XCLASS) \ + \ + , macro(REF) \ + \ + , macro(ALT) \ + , macro(KET) \ + , macro(KETRMAX) \ + , macro(KETRMIN) \ + \ + , macro(ASSERT) \ + , macro(ASSERT_NOT) \ + \ + , macro(BRAZERO) \ + , macro(BRAMINZERO) \ + , macro(BRANUMBER) \ + , macro(BRA) + +#define OPCODE_ENUM_VALUE(opcode) OP_##opcode +enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) }; + +/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and +study.c that all opcodes are less than 128 in value. This makes handling UTF-8 +character sequences easier. */ + +/* The highest extraction number before we have to start using additional +bytes. (Originally PCRE didn't have support for extraction counts higher than +this number.) The value is limited by the number of opcodes left after OP_BRA, +i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional +opcodes. */ + +/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above +are in conflict! */ + +#define EXTRACT_BASIC_MAX 100 + +/* The code vector runs on as long as necessary after the end. */ + +struct JSRegExp { + unsigned options; + + unsigned short topBracket; + unsigned short topBackref; + + unsigned short firstByte; + unsigned short reqByte; +}; + +/* Internal shared data tables. These are tables that are used by more than one + of the exported public functions. They have to be "external" in the C sense, + but are not part of the PCRE public API. The data for these tables is in the + pcre_tables.c module. */ + +#define jsc_pcre_utf8_table1_size 6 + +extern const int jsc_pcre_utf8_table1[6]; +extern const int jsc_pcre_utf8_table2[6]; +extern const int jsc_pcre_utf8_table3[6]; +extern const unsigned char jsc_pcre_utf8_table4[0x40]; + +extern const unsigned char jsc_pcre_default_tables[tables_length]; + +static inline unsigned char toLowerCase(unsigned char c) +{ + static const unsigned char* lowerCaseChars = jsc_pcre_default_tables + lcc_offset; + return lowerCaseChars[c]; +} + +static inline unsigned char flipCase(unsigned char c) +{ + static const unsigned char* flippedCaseChars = jsc_pcre_default_tables + fcc_offset; + return flippedCaseChars[c]; +} + +static inline unsigned char classBitmapForChar(unsigned char c) +{ + static const unsigned char* charClassBitmaps = jsc_pcre_default_tables + cbits_offset; + return charClassBitmaps[c]; +} + +static inline unsigned char charTypeForChar(unsigned char c) +{ + const unsigned char* charTypeMap = jsc_pcre_default_tables + ctypes_offset; + return charTypeMap[c]; +} + +static inline bool isWordChar(UChar c) +{ + return c < 128 && (charTypeForChar(c) & ctype_word); +} + +static inline bool isSpaceChar(UChar c) +{ + return (c < 128 && (charTypeForChar(c) & ctype_space)) || c == 0x00A0; +} + +static inline bool isNewline(UChar nl) +{ + return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029); +} + +static inline bool isBracketStartOpcode(unsigned char opcode) +{ + if (opcode >= OP_BRA) + return true; + switch (opcode) { + case OP_ASSERT: + case OP_ASSERT_NOT: + return true; + default: + return false; + } +} + +static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr) +{ + JS_ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT); + do + opcodePtr += getLinkValue(opcodePtr + 1); + while (*opcodePtr == OP_ALT); +} + +/* Internal shared functions. These are functions that are used in more +that one of the source files. They have to have external linkage, but +but are not part of the public API and so not exported from the library. */ + +extern int jsc_pcre_ucp_othercase(unsigned); +extern bool jsc_pcre_xclass(int, const unsigned char*); + +#endif + +#endif + +/* End of pcre_internal.h */ diff --git a/js/src/yarr/pcre/pcre_tables.cpp b/js/src/yarr/pcre/pcre_tables.cpp new file mode 100644 index 000000000000..b1ac229d5912 --- /dev/null +++ b/js/src/yarr/pcre/pcre_tables.cpp @@ -0,0 +1,71 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains some fixed tables that are used by more than one of the +PCRE code modules. */ + +#include "pcre_internal.h" + +/************************************************* +* Tables for UTF-8 support * +*************************************************/ + +/* These are the breakpoints for different numbers of bytes in a UTF-8 +character. */ + +const int jsc_pcre_utf8_table1[6] = + { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; + +/* These are the indicator bits and the mask for the data bits to set in the +first byte of a character, indexed by the number of additional bytes. */ + +const int jsc_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; +const int jsc_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +/* Table of the number of extra characters, indexed by the first character +masked with 0x3f. The highest number for a valid UTF-8 character is in fact +0x3d. */ + +const unsigned char jsc_pcre_utf8_table4[0x40] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; + +#include "chartables.c" diff --git a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp new file mode 100644 index 000000000000..b97db921c981 --- /dev/null +++ b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp @@ -0,0 +1,98 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + + +/* This module contains code for searching the table of Unicode character +properties. */ + +#include "pcre_internal.h" + +#include "ucpinternal.h" /* Internal table details */ +#include "ucptable.cpp" /* The table itself */ + +/************************************************* +* Search table and return other case * +*************************************************/ + +/* If the given character is a letter, and there is another case for the +letter, return the other case. Otherwise, return -1. + +Arguments: + c the character value + +Returns: the other case or -1 if none +*/ + +int jsc_pcre_ucp_othercase(unsigned c) +{ + int bot = 0; + int top = sizeof(ucp_table) / sizeof(cnode); + int mid; + + /* The table is searched using a binary chop. You might think that using + intermediate variables to hold some of the common expressions would speed + things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it + makes things a lot slower. */ + + for (;;) { + if (top <= bot) + return -1; + mid = (bot + top) >> 1; + if (c == (ucp_table[mid].f0 & f0_charmask)) + break; + if (c < (ucp_table[mid].f0 & f0_charmask)) + top = mid; + else { + if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask))) + break; + bot = mid + 1; + } + } + + /* Found an entry in the table. Return -1 for a range entry. Otherwise return + the other case if there is one, else -1. */ + + if (ucp_table[mid].f0 & f0_rangeflag) + return -1; + + int offset = ucp_table[mid].f1 & f1_casemask; + if (offset & f1_caseneg) + offset |= f1_caseneg; + return !offset ? -1 : c + offset; +} diff --git a/js/src/yarr/pcre/pcre_xclass.cpp b/js/src/yarr/pcre/pcre_xclass.cpp new file mode 100644 index 000000000000..8e59018ead0c --- /dev/null +++ b/js/src/yarr/pcre/pcre_xclass.cpp @@ -0,0 +1,114 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains an internal function that is used to match an extended +class (one that contains characters whose values are > 255). */ + +#include "pcre_internal.h" + +/************************************************* +* Match character against an XCLASS * +*************************************************/ + +/* This function is called to match a character against an extended class that +might contain values > 255. + +Arguments: + c the character + data points to the flag byte of the XCLASS data + +Returns: true if character matches, else false +*/ + +/* Get the next UTF-8 character, advancing the pointer. This is called when we + know we are in UTF-8 mode. */ + +static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr) +{ + c = *subjectPtr++; + if ((c & 0xc0) == 0xc0) { + int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + int gcss = 6 * gcaa; + c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; + while (gcaa-- > 0) { + gcss -= 6; + c |= (*subjectPtr++ & 0x3f) << gcss; + } + } +} + +bool jsc_pcre_xclass(int c, const unsigned char* data) +{ + bool negated = (*data & XCL_NOT); + + /* Character values < 256 are matched against a bitmap, if one is present. If + not, we still carry on, because there may be ranges that start below 256 in the + additional data. */ + + if (c < 256) { + if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) + return !negated; /* char found */ + } + + /* First skip the bit map if present. Then match against the list of Unicode + properties or large chars or ranges that end with a large char. We won't ever + encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ + + if ((*data++ & XCL_MAP) != 0) + data += 32; + + int t; + while ((t = *data++) != XCL_END) { + if (t == XCL_SINGLE) { + int x; + getUTF8CharAndAdvancePointer(x, data); + if (c == x) + return !negated; + } + else if (t == XCL_RANGE) { + int x, y; + getUTF8CharAndAdvancePointer(x, data); + getUTF8CharAndAdvancePointer(y, data); + if (c >= x && c <= y) + return !negated; + } + } + + return negated; /* char did not match */ +} diff --git a/js/src/yarr/pcre/ucpinternal.h b/js/src/yarr/pcre/ucpinternal.h new file mode 100644 index 000000000000..c8bc4aab679c --- /dev/null +++ b/js/src/yarr/pcre/ucpinternal.h @@ -0,0 +1,126 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/************************************************* +* Unicode Property Table handler * +*************************************************/ + +/* Internal header file defining the layout of the bits in each pair of 32-bit +words that form a data item in the table. */ + +typedef struct cnode { + unsigned f0; + unsigned f1; +} cnode; + +/* Things for the f0 field */ + +#define f0_scriptmask 0xff000000 /* Mask for script field */ +#define f0_scriptshift 24 /* Shift for script value */ +#define f0_rangeflag 0x00f00000 /* Flag for a range item */ +#define f0_charmask 0x001fffff /* Mask for code point value */ + +/* Things for the f1 field */ + +#define f1_typemask 0xfc000000 /* Mask for char type field */ +#define f1_typeshift 26 /* Shift for the type field */ +#define f1_rangemask 0x0000ffff /* Mask for a range offset */ +#define f1_casemask 0x0000ffff /* Mask for a case offset */ +#define f1_caseneg 0xffff8000 /* Bits for negation */ + +/* The data consists of a vector of structures of type cnode. The two unsigned +32-bit integers are used as follows: + +(f0) (1) The most significant byte holds the script number. The numbers are + defined by the enum in ucp.h. + + (2) The 0x00800000 bit is set if this entry defines a range of characters. + It is not set if this entry defines a single character + + (3) The 0x00600000 bits are spare. + + (4) The 0x001fffff bits contain the code point. No Unicode code point will + ever be greater than 0x0010ffff, so this should be OK for ever. + +(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are + defined by an enum in ucp.h. + + (2) The 0x03ff0000 bits are spare. + + (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of + range if this entry defines a range, OR the *signed* offset to the + character's "other case" partner if this entry defines a single + character. There is no partner if the value is zero. + +------------------------------------------------------------------------------- +| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) | +------------------------------------------------------------------------------- + | | | | | + | | |-> spare | |-> spare + | | | + | |-> spare |-> spare + | + |-> range flag + +The upper/lower casing information is set only for characters that come in +pairs. The non-one-to-one mappings in the Unicode data are ignored. + +When searching the data, proceed as follows: + +(1) Set up for a binary chop search. + +(2) If the top is not greater than the bottom, the character is not in the + table. Its type must therefore be "Cn" ("Undefined"). + +(3) Find the middle vector element. + +(4) Extract the code point and compare. If equal, we are done. + +(5) If the test character is smaller, set the top to the current point, and + goto (2). + +(6) If the current entry defines a range, compute the last character by adding + the offset, and see if the test character is within the range. If it is, + we are done. + +(7) Otherwise, set the bottom to one element past the current point and goto + (2). +*/ + +/* End of ucpinternal.h */ diff --git a/js/src/yarr/pcre/ucptable.cpp b/js/src/yarr/pcre/ucptable.cpp new file mode 100644 index 000000000000..011f7f572443 --- /dev/null +++ b/js/src/yarr/pcre/ucptable.cpp @@ -0,0 +1,2968 @@ +/* This source module is automatically generated from the Unicode +property table. See ucpinternal.h for a description of the layout. */ + +static const cnode ucp_table[] = { + { 0x09800000, 0x0000001f }, + { 0x09000020, 0x74000000 }, + { 0x09800021, 0x54000002 }, + { 0x09000024, 0x5c000000 }, + { 0x09800025, 0x54000002 }, + { 0x09000028, 0x58000000 }, + { 0x09000029, 0x48000000 }, + { 0x0900002a, 0x54000000 }, + { 0x0900002b, 0x64000000 }, + { 0x0900002c, 0x54000000 }, + { 0x0900002d, 0x44000000 }, + { 0x0980002e, 0x54000001 }, + { 0x09800030, 0x34000009 }, + { 0x0980003a, 0x54000001 }, + { 0x0980003c, 0x64000002 }, + { 0x0980003f, 0x54000001 }, + { 0x21000041, 0x24000020 }, + { 0x21000042, 0x24000020 }, + { 0x21000043, 0x24000020 }, + { 0x21000044, 0x24000020 }, + { 0x21000045, 0x24000020 }, + { 0x21000046, 0x24000020 }, + { 0x21000047, 0x24000020 }, + { 0x21000048, 0x24000020 }, + { 0x21000049, 0x24000020 }, + { 0x2100004a, 0x24000020 }, + { 0x2100004b, 0x24000020 }, + { 0x2100004c, 0x24000020 }, + { 0x2100004d, 0x24000020 }, + { 0x2100004e, 0x24000020 }, + { 0x2100004f, 0x24000020 }, + { 0x21000050, 0x24000020 }, + { 0x21000051, 0x24000020 }, + { 0x21000052, 0x24000020 }, + { 0x21000053, 0x24000020 }, + { 0x21000054, 0x24000020 }, + { 0x21000055, 0x24000020 }, + { 0x21000056, 0x24000020 }, + { 0x21000057, 0x24000020 }, + { 0x21000058, 0x24000020 }, + { 0x21000059, 0x24000020 }, + { 0x2100005a, 0x24000020 }, + { 0x0900005b, 0x58000000 }, + { 0x0900005c, 0x54000000 }, + { 0x0900005d, 0x48000000 }, + { 0x0900005e, 0x60000000 }, + { 0x0900005f, 0x40000000 }, + { 0x09000060, 0x60000000 }, + { 0x21000061, 0x1400ffe0 }, + { 0x21000062, 0x1400ffe0 }, + { 0x21000063, 0x1400ffe0 }, + { 0x21000064, 0x1400ffe0 }, + { 0x21000065, 0x1400ffe0 }, + { 0x21000066, 0x1400ffe0 }, + { 0x21000067, 0x1400ffe0 }, + { 0x21000068, 0x1400ffe0 }, + { 0x21000069, 0x1400ffe0 }, + { 0x2100006a, 0x1400ffe0 }, + { 0x2100006b, 0x1400ffe0 }, + { 0x2100006c, 0x1400ffe0 }, + { 0x2100006d, 0x1400ffe0 }, + { 0x2100006e, 0x1400ffe0 }, + { 0x2100006f, 0x1400ffe0 }, + { 0x21000070, 0x1400ffe0 }, + { 0x21000071, 0x1400ffe0 }, + { 0x21000072, 0x1400ffe0 }, + { 0x21000073, 0x1400ffe0 }, + { 0x21000074, 0x1400ffe0 }, + { 0x21000075, 0x1400ffe0 }, + { 0x21000076, 0x1400ffe0 }, + { 0x21000077, 0x1400ffe0 }, + { 0x21000078, 0x1400ffe0 }, + { 0x21000079, 0x1400ffe0 }, + { 0x2100007a, 0x1400ffe0 }, + { 0x0900007b, 0x58000000 }, + { 0x0900007c, 0x64000000 }, + { 0x0900007d, 0x48000000 }, + { 0x0900007e, 0x64000000 }, + { 0x0980007f, 0x00000020 }, + { 0x090000a0, 0x74000000 }, + { 0x090000a1, 0x54000000 }, + { 0x098000a2, 0x5c000003 }, + { 0x098000a6, 0x68000001 }, + { 0x090000a8, 0x60000000 }, + { 0x090000a9, 0x68000000 }, + { 0x210000aa, 0x14000000 }, + { 0x090000ab, 0x50000000 }, + { 0x090000ac, 0x64000000 }, + { 0x090000ad, 0x04000000 }, + { 0x090000ae, 0x68000000 }, + { 0x090000af, 0x60000000 }, + { 0x090000b0, 0x68000000 }, + { 0x090000b1, 0x64000000 }, + { 0x098000b2, 0x3c000001 }, + { 0x090000b4, 0x60000000 }, + { 0x090000b5, 0x140002e7 }, + { 0x090000b6, 0x68000000 }, + { 0x090000b7, 0x54000000 }, + { 0x090000b8, 0x60000000 }, + { 0x090000b9, 0x3c000000 }, + { 0x210000ba, 0x14000000 }, + { 0x090000bb, 0x4c000000 }, + { 0x098000bc, 0x3c000002 }, + { 0x090000bf, 0x54000000 }, + { 0x210000c0, 0x24000020 }, + { 0x210000c1, 0x24000020 }, + { 0x210000c2, 0x24000020 }, + { 0x210000c3, 0x24000020 }, + { 0x210000c4, 0x24000020 }, + { 0x210000c5, 0x24000020 }, + { 0x210000c6, 0x24000020 }, + { 0x210000c7, 0x24000020 }, + { 0x210000c8, 0x24000020 }, + { 0x210000c9, 0x24000020 }, + { 0x210000ca, 0x24000020 }, + { 0x210000cb, 0x24000020 }, + { 0x210000cc, 0x24000020 }, + { 0x210000cd, 0x24000020 }, + { 0x210000ce, 0x24000020 }, + { 0x210000cf, 0x24000020 }, + { 0x210000d0, 0x24000020 }, + { 0x210000d1, 0x24000020 }, + { 0x210000d2, 0x24000020 }, + { 0x210000d3, 0x24000020 }, + { 0x210000d4, 0x24000020 }, + { 0x210000d5, 0x24000020 }, + { 0x210000d6, 0x24000020 }, + { 0x090000d7, 0x64000000 }, + { 0x210000d8, 0x24000020 }, + { 0x210000d9, 0x24000020 }, + { 0x210000da, 0x24000020 }, + { 0x210000db, 0x24000020 }, + { 0x210000dc, 0x24000020 }, + { 0x210000dd, 0x24000020 }, + { 0x210000de, 0x24000020 }, + { 0x210000df, 0x14000000 }, + { 0x210000e0, 0x1400ffe0 }, + { 0x210000e1, 0x1400ffe0 }, + { 0x210000e2, 0x1400ffe0 }, + { 0x210000e3, 0x1400ffe0 }, + { 0x210000e4, 0x1400ffe0 }, + { 0x210000e5, 0x1400ffe0 }, + { 0x210000e6, 0x1400ffe0 }, + { 0x210000e7, 0x1400ffe0 }, + { 0x210000e8, 0x1400ffe0 }, + { 0x210000e9, 0x1400ffe0 }, + { 0x210000ea, 0x1400ffe0 }, + { 0x210000eb, 0x1400ffe0 }, + { 0x210000ec, 0x1400ffe0 }, + { 0x210000ed, 0x1400ffe0 }, + { 0x210000ee, 0x1400ffe0 }, + { 0x210000ef, 0x1400ffe0 }, + { 0x210000f0, 0x1400ffe0 }, + { 0x210000f1, 0x1400ffe0 }, + { 0x210000f2, 0x1400ffe0 }, + { 0x210000f3, 0x1400ffe0 }, + { 0x210000f4, 0x1400ffe0 }, + { 0x210000f5, 0x1400ffe0 }, + { 0x210000f6, 0x1400ffe0 }, + { 0x090000f7, 0x64000000 }, + { 0x210000f8, 0x1400ffe0 }, + { 0x210000f9, 0x1400ffe0 }, + { 0x210000fa, 0x1400ffe0 }, + { 0x210000fb, 0x1400ffe0 }, + { 0x210000fc, 0x1400ffe0 }, + { 0x210000fd, 0x1400ffe0 }, + { 0x210000fe, 0x1400ffe0 }, + { 0x210000ff, 0x14000079 }, + { 0x21000100, 0x24000001 }, + { 0x21000101, 0x1400ffff }, + { 0x21000102, 0x24000001 }, + { 0x21000103, 0x1400ffff }, + { 0x21000104, 0x24000001 }, + { 0x21000105, 0x1400ffff }, + { 0x21000106, 0x24000001 }, + { 0x21000107, 0x1400ffff }, + { 0x21000108, 0x24000001 }, + { 0x21000109, 0x1400ffff }, + { 0x2100010a, 0x24000001 }, + { 0x2100010b, 0x1400ffff }, + { 0x2100010c, 0x24000001 }, + { 0x2100010d, 0x1400ffff }, + { 0x2100010e, 0x24000001 }, + { 0x2100010f, 0x1400ffff }, + { 0x21000110, 0x24000001 }, + { 0x21000111, 0x1400ffff }, + { 0x21000112, 0x24000001 }, + { 0x21000113, 0x1400ffff }, + { 0x21000114, 0x24000001 }, + { 0x21000115, 0x1400ffff }, + { 0x21000116, 0x24000001 }, + { 0x21000117, 0x1400ffff }, + { 0x21000118, 0x24000001 }, + { 0x21000119, 0x1400ffff }, + { 0x2100011a, 0x24000001 }, + { 0x2100011b, 0x1400ffff }, + { 0x2100011c, 0x24000001 }, + { 0x2100011d, 0x1400ffff }, + { 0x2100011e, 0x24000001 }, + { 0x2100011f, 0x1400ffff }, + { 0x21000120, 0x24000001 }, + { 0x21000121, 0x1400ffff }, + { 0x21000122, 0x24000001 }, + { 0x21000123, 0x1400ffff }, + { 0x21000124, 0x24000001 }, + { 0x21000125, 0x1400ffff }, + { 0x21000126, 0x24000001 }, + { 0x21000127, 0x1400ffff }, + { 0x21000128, 0x24000001 }, + { 0x21000129, 0x1400ffff }, + { 0x2100012a, 0x24000001 }, + { 0x2100012b, 0x1400ffff }, + { 0x2100012c, 0x24000001 }, + { 0x2100012d, 0x1400ffff }, + { 0x2100012e, 0x24000001 }, + { 0x2100012f, 0x1400ffff }, + { 0x21000130, 0x2400ff39 }, + { 0x21000131, 0x1400ff18 }, + { 0x21000132, 0x24000001 }, + { 0x21000133, 0x1400ffff }, + { 0x21000134, 0x24000001 }, + { 0x21000135, 0x1400ffff }, + { 0x21000136, 0x24000001 }, + { 0x21000137, 0x1400ffff }, + { 0x21000138, 0x14000000 }, + { 0x21000139, 0x24000001 }, + { 0x2100013a, 0x1400ffff }, + { 0x2100013b, 0x24000001 }, + { 0x2100013c, 0x1400ffff }, + { 0x2100013d, 0x24000001 }, + { 0x2100013e, 0x1400ffff }, + { 0x2100013f, 0x24000001 }, + { 0x21000140, 0x1400ffff }, + { 0x21000141, 0x24000001 }, + { 0x21000142, 0x1400ffff }, + { 0x21000143, 0x24000001 }, + { 0x21000144, 0x1400ffff }, + { 0x21000145, 0x24000001 }, + { 0x21000146, 0x1400ffff }, + { 0x21000147, 0x24000001 }, + { 0x21000148, 0x1400ffff }, + { 0x21000149, 0x14000000 }, + { 0x2100014a, 0x24000001 }, + { 0x2100014b, 0x1400ffff }, + { 0x2100014c, 0x24000001 }, + { 0x2100014d, 0x1400ffff }, + { 0x2100014e, 0x24000001 }, + { 0x2100014f, 0x1400ffff }, + { 0x21000150, 0x24000001 }, + { 0x21000151, 0x1400ffff }, + { 0x21000152, 0x24000001 }, + { 0x21000153, 0x1400ffff }, + { 0x21000154, 0x24000001 }, + { 0x21000155, 0x1400ffff }, + { 0x21000156, 0x24000001 }, + { 0x21000157, 0x1400ffff }, + { 0x21000158, 0x24000001 }, + { 0x21000159, 0x1400ffff }, + { 0x2100015a, 0x24000001 }, + { 0x2100015b, 0x1400ffff }, + { 0x2100015c, 0x24000001 }, + { 0x2100015d, 0x1400ffff }, + { 0x2100015e, 0x24000001 }, + { 0x2100015f, 0x1400ffff }, + { 0x21000160, 0x24000001 }, + { 0x21000161, 0x1400ffff }, + { 0x21000162, 0x24000001 }, + { 0x21000163, 0x1400ffff }, + { 0x21000164, 0x24000001 }, + { 0x21000165, 0x1400ffff }, + { 0x21000166, 0x24000001 }, + { 0x21000167, 0x1400ffff }, + { 0x21000168, 0x24000001 }, + { 0x21000169, 0x1400ffff }, + { 0x2100016a, 0x24000001 }, + { 0x2100016b, 0x1400ffff }, + { 0x2100016c, 0x24000001 }, + { 0x2100016d, 0x1400ffff }, + { 0x2100016e, 0x24000001 }, + { 0x2100016f, 0x1400ffff }, + { 0x21000170, 0x24000001 }, + { 0x21000171, 0x1400ffff }, + { 0x21000172, 0x24000001 }, + { 0x21000173, 0x1400ffff }, + { 0x21000174, 0x24000001 }, + { 0x21000175, 0x1400ffff }, + { 0x21000176, 0x24000001 }, + { 0x21000177, 0x1400ffff }, + { 0x21000178, 0x2400ff87 }, + { 0x21000179, 0x24000001 }, + { 0x2100017a, 0x1400ffff }, + { 0x2100017b, 0x24000001 }, + { 0x2100017c, 0x1400ffff }, + { 0x2100017d, 0x24000001 }, + { 0x2100017e, 0x1400ffff }, + { 0x2100017f, 0x1400fed4 }, + { 0x21000180, 0x14000000 }, + { 0x21000181, 0x240000d2 }, + { 0x21000182, 0x24000001 }, + { 0x21000183, 0x1400ffff }, + { 0x21000184, 0x24000001 }, + { 0x21000185, 0x1400ffff }, + { 0x21000186, 0x240000ce }, + { 0x21000187, 0x24000001 }, + { 0x21000188, 0x1400ffff }, + { 0x21000189, 0x240000cd }, + { 0x2100018a, 0x240000cd }, + { 0x2100018b, 0x24000001 }, + { 0x2100018c, 0x1400ffff }, + { 0x2100018d, 0x14000000 }, + { 0x2100018e, 0x2400004f }, + { 0x2100018f, 0x240000ca }, + { 0x21000190, 0x240000cb }, + { 0x21000191, 0x24000001 }, + { 0x21000192, 0x1400ffff }, + { 0x21000193, 0x240000cd }, + { 0x21000194, 0x240000cf }, + { 0x21000195, 0x14000061 }, + { 0x21000196, 0x240000d3 }, + { 0x21000197, 0x240000d1 }, + { 0x21000198, 0x24000001 }, + { 0x21000199, 0x1400ffff }, + { 0x2100019a, 0x140000a3 }, + { 0x2100019b, 0x14000000 }, + { 0x2100019c, 0x240000d3 }, + { 0x2100019d, 0x240000d5 }, + { 0x2100019e, 0x14000082 }, + { 0x2100019f, 0x240000d6 }, + { 0x210001a0, 0x24000001 }, + { 0x210001a1, 0x1400ffff }, + { 0x210001a2, 0x24000001 }, + { 0x210001a3, 0x1400ffff }, + { 0x210001a4, 0x24000001 }, + { 0x210001a5, 0x1400ffff }, + { 0x210001a6, 0x240000da }, + { 0x210001a7, 0x24000001 }, + { 0x210001a8, 0x1400ffff }, + { 0x210001a9, 0x240000da }, + { 0x218001aa, 0x14000001 }, + { 0x210001ac, 0x24000001 }, + { 0x210001ad, 0x1400ffff }, + { 0x210001ae, 0x240000da }, + { 0x210001af, 0x24000001 }, + { 0x210001b0, 0x1400ffff }, + { 0x210001b1, 0x240000d9 }, + { 0x210001b2, 0x240000d9 }, + { 0x210001b3, 0x24000001 }, + { 0x210001b4, 0x1400ffff }, + { 0x210001b5, 0x24000001 }, + { 0x210001b6, 0x1400ffff }, + { 0x210001b7, 0x240000db }, + { 0x210001b8, 0x24000001 }, + { 0x210001b9, 0x1400ffff }, + { 0x210001ba, 0x14000000 }, + { 0x210001bb, 0x1c000000 }, + { 0x210001bc, 0x24000001 }, + { 0x210001bd, 0x1400ffff }, + { 0x210001be, 0x14000000 }, + { 0x210001bf, 0x14000038 }, + { 0x218001c0, 0x1c000003 }, + { 0x210001c4, 0x24000002 }, + { 0x210001c5, 0x2000ffff }, + { 0x210001c6, 0x1400fffe }, + { 0x210001c7, 0x24000002 }, + { 0x210001c8, 0x2000ffff }, + { 0x210001c9, 0x1400fffe }, + { 0x210001ca, 0x24000002 }, + { 0x210001cb, 0x2000ffff }, + { 0x210001cc, 0x1400fffe }, + { 0x210001cd, 0x24000001 }, + { 0x210001ce, 0x1400ffff }, + { 0x210001cf, 0x24000001 }, + { 0x210001d0, 0x1400ffff }, + { 0x210001d1, 0x24000001 }, + { 0x210001d2, 0x1400ffff }, + { 0x210001d3, 0x24000001 }, + { 0x210001d4, 0x1400ffff }, + { 0x210001d5, 0x24000001 }, + { 0x210001d6, 0x1400ffff }, + { 0x210001d7, 0x24000001 }, + { 0x210001d8, 0x1400ffff }, + { 0x210001d9, 0x24000001 }, + { 0x210001da, 0x1400ffff }, + { 0x210001db, 0x24000001 }, + { 0x210001dc, 0x1400ffff }, + { 0x210001dd, 0x1400ffb1 }, + { 0x210001de, 0x24000001 }, + { 0x210001df, 0x1400ffff }, + { 0x210001e0, 0x24000001 }, + { 0x210001e1, 0x1400ffff }, + { 0x210001e2, 0x24000001 }, + { 0x210001e3, 0x1400ffff }, + { 0x210001e4, 0x24000001 }, + { 0x210001e5, 0x1400ffff }, + { 0x210001e6, 0x24000001 }, + { 0x210001e7, 0x1400ffff }, + { 0x210001e8, 0x24000001 }, + { 0x210001e9, 0x1400ffff }, + { 0x210001ea, 0x24000001 }, + { 0x210001eb, 0x1400ffff }, + { 0x210001ec, 0x24000001 }, + { 0x210001ed, 0x1400ffff }, + { 0x210001ee, 0x24000001 }, + { 0x210001ef, 0x1400ffff }, + { 0x210001f0, 0x14000000 }, + { 0x210001f1, 0x24000002 }, + { 0x210001f2, 0x2000ffff }, + { 0x210001f3, 0x1400fffe }, + { 0x210001f4, 0x24000001 }, + { 0x210001f5, 0x1400ffff }, + { 0x210001f6, 0x2400ff9f }, + { 0x210001f7, 0x2400ffc8 }, + { 0x210001f8, 0x24000001 }, + { 0x210001f9, 0x1400ffff }, + { 0x210001fa, 0x24000001 }, + { 0x210001fb, 0x1400ffff }, + { 0x210001fc, 0x24000001 }, + { 0x210001fd, 0x1400ffff }, + { 0x210001fe, 0x24000001 }, + { 0x210001ff, 0x1400ffff }, + { 0x21000200, 0x24000001 }, + { 0x21000201, 0x1400ffff }, + { 0x21000202, 0x24000001 }, + { 0x21000203, 0x1400ffff }, + { 0x21000204, 0x24000001 }, + { 0x21000205, 0x1400ffff }, + { 0x21000206, 0x24000001 }, + { 0x21000207, 0x1400ffff }, + { 0x21000208, 0x24000001 }, + { 0x21000209, 0x1400ffff }, + { 0x2100020a, 0x24000001 }, + { 0x2100020b, 0x1400ffff }, + { 0x2100020c, 0x24000001 }, + { 0x2100020d, 0x1400ffff }, + { 0x2100020e, 0x24000001 }, + { 0x2100020f, 0x1400ffff }, + { 0x21000210, 0x24000001 }, + { 0x21000211, 0x1400ffff }, + { 0x21000212, 0x24000001 }, + { 0x21000213, 0x1400ffff }, + { 0x21000214, 0x24000001 }, + { 0x21000215, 0x1400ffff }, + { 0x21000216, 0x24000001 }, + { 0x21000217, 0x1400ffff }, + { 0x21000218, 0x24000001 }, + { 0x21000219, 0x1400ffff }, + { 0x2100021a, 0x24000001 }, + { 0x2100021b, 0x1400ffff }, + { 0x2100021c, 0x24000001 }, + { 0x2100021d, 0x1400ffff }, + { 0x2100021e, 0x24000001 }, + { 0x2100021f, 0x1400ffff }, + { 0x21000220, 0x2400ff7e }, + { 0x21000221, 0x14000000 }, + { 0x21000222, 0x24000001 }, + { 0x21000223, 0x1400ffff }, + { 0x21000224, 0x24000001 }, + { 0x21000225, 0x1400ffff }, + { 0x21000226, 0x24000001 }, + { 0x21000227, 0x1400ffff }, + { 0x21000228, 0x24000001 }, + { 0x21000229, 0x1400ffff }, + { 0x2100022a, 0x24000001 }, + { 0x2100022b, 0x1400ffff }, + { 0x2100022c, 0x24000001 }, + { 0x2100022d, 0x1400ffff }, + { 0x2100022e, 0x24000001 }, + { 0x2100022f, 0x1400ffff }, + { 0x21000230, 0x24000001 }, + { 0x21000231, 0x1400ffff }, + { 0x21000232, 0x24000001 }, + { 0x21000233, 0x1400ffff }, + { 0x21800234, 0x14000005 }, + { 0x2100023a, 0x24000000 }, + { 0x2100023b, 0x24000001 }, + { 0x2100023c, 0x1400ffff }, + { 0x2100023d, 0x2400ff5d }, + { 0x2100023e, 0x24000000 }, + { 0x2180023f, 0x14000001 }, + { 0x21000241, 0x24000053 }, + { 0x21800250, 0x14000002 }, + { 0x21000253, 0x1400ff2e }, + { 0x21000254, 0x1400ff32 }, + { 0x21000255, 0x14000000 }, + { 0x21000256, 0x1400ff33 }, + { 0x21000257, 0x1400ff33 }, + { 0x21000258, 0x14000000 }, + { 0x21000259, 0x1400ff36 }, + { 0x2100025a, 0x14000000 }, + { 0x2100025b, 0x1400ff35 }, + { 0x2180025c, 0x14000003 }, + { 0x21000260, 0x1400ff33 }, + { 0x21800261, 0x14000001 }, + { 0x21000263, 0x1400ff31 }, + { 0x21800264, 0x14000003 }, + { 0x21000268, 0x1400ff2f }, + { 0x21000269, 0x1400ff2d }, + { 0x2180026a, 0x14000004 }, + { 0x2100026f, 0x1400ff2d }, + { 0x21800270, 0x14000001 }, + { 0x21000272, 0x1400ff2b }, + { 0x21800273, 0x14000001 }, + { 0x21000275, 0x1400ff2a }, + { 0x21800276, 0x14000009 }, + { 0x21000280, 0x1400ff26 }, + { 0x21800281, 0x14000001 }, + { 0x21000283, 0x1400ff26 }, + { 0x21800284, 0x14000003 }, + { 0x21000288, 0x1400ff26 }, + { 0x21000289, 0x14000000 }, + { 0x2100028a, 0x1400ff27 }, + { 0x2100028b, 0x1400ff27 }, + { 0x2180028c, 0x14000005 }, + { 0x21000292, 0x1400ff25 }, + { 0x21000293, 0x14000000 }, + { 0x21000294, 0x1400ffad }, + { 0x21800295, 0x1400001a }, + { 0x218002b0, 0x18000011 }, + { 0x098002c2, 0x60000003 }, + { 0x098002c6, 0x1800000b }, + { 0x098002d2, 0x6000000d }, + { 0x218002e0, 0x18000004 }, + { 0x098002e5, 0x60000008 }, + { 0x090002ee, 0x18000000 }, + { 0x098002ef, 0x60000010 }, + { 0x1b800300, 0x30000044 }, + { 0x1b000345, 0x30000054 }, + { 0x1b800346, 0x30000029 }, + { 0x13800374, 0x60000001 }, + { 0x1300037a, 0x18000000 }, + { 0x0900037e, 0x54000000 }, + { 0x13800384, 0x60000001 }, + { 0x13000386, 0x24000026 }, + { 0x09000387, 0x54000000 }, + { 0x13000388, 0x24000025 }, + { 0x13000389, 0x24000025 }, + { 0x1300038a, 0x24000025 }, + { 0x1300038c, 0x24000040 }, + { 0x1300038e, 0x2400003f }, + { 0x1300038f, 0x2400003f }, + { 0x13000390, 0x14000000 }, + { 0x13000391, 0x24000020 }, + { 0x13000392, 0x24000020 }, + { 0x13000393, 0x24000020 }, + { 0x13000394, 0x24000020 }, + { 0x13000395, 0x24000020 }, + { 0x13000396, 0x24000020 }, + { 0x13000397, 0x24000020 }, + { 0x13000398, 0x24000020 }, + { 0x13000399, 0x24000020 }, + { 0x1300039a, 0x24000020 }, + { 0x1300039b, 0x24000020 }, + { 0x1300039c, 0x24000020 }, + { 0x1300039d, 0x24000020 }, + { 0x1300039e, 0x24000020 }, + { 0x1300039f, 0x24000020 }, + { 0x130003a0, 0x24000020 }, + { 0x130003a1, 0x24000020 }, + { 0x130003a3, 0x24000020 }, + { 0x130003a4, 0x24000020 }, + { 0x130003a5, 0x24000020 }, + { 0x130003a6, 0x24000020 }, + { 0x130003a7, 0x24000020 }, + { 0x130003a8, 0x24000020 }, + { 0x130003a9, 0x24000020 }, + { 0x130003aa, 0x24000020 }, + { 0x130003ab, 0x24000020 }, + { 0x130003ac, 0x1400ffda }, + { 0x130003ad, 0x1400ffdb }, + { 0x130003ae, 0x1400ffdb }, + { 0x130003af, 0x1400ffdb }, + { 0x130003b0, 0x14000000 }, + { 0x130003b1, 0x1400ffe0 }, + { 0x130003b2, 0x1400ffe0 }, + { 0x130003b3, 0x1400ffe0 }, + { 0x130003b4, 0x1400ffe0 }, + { 0x130003b5, 0x1400ffe0 }, + { 0x130003b6, 0x1400ffe0 }, + { 0x130003b7, 0x1400ffe0 }, + { 0x130003b8, 0x1400ffe0 }, + { 0x130003b9, 0x1400ffe0 }, + { 0x130003ba, 0x1400ffe0 }, + { 0x130003bb, 0x1400ffe0 }, + { 0x130003bc, 0x1400ffe0 }, + { 0x130003bd, 0x1400ffe0 }, + { 0x130003be, 0x1400ffe0 }, + { 0x130003bf, 0x1400ffe0 }, + { 0x130003c0, 0x1400ffe0 }, + { 0x130003c1, 0x1400ffe0 }, + { 0x130003c2, 0x1400ffe1 }, + { 0x130003c3, 0x1400ffe0 }, + { 0x130003c4, 0x1400ffe0 }, + { 0x130003c5, 0x1400ffe0 }, + { 0x130003c6, 0x1400ffe0 }, + { 0x130003c7, 0x1400ffe0 }, + { 0x130003c8, 0x1400ffe0 }, + { 0x130003c9, 0x1400ffe0 }, + { 0x130003ca, 0x1400ffe0 }, + { 0x130003cb, 0x1400ffe0 }, + { 0x130003cc, 0x1400ffc0 }, + { 0x130003cd, 0x1400ffc1 }, + { 0x130003ce, 0x1400ffc1 }, + { 0x130003d0, 0x1400ffc2 }, + { 0x130003d1, 0x1400ffc7 }, + { 0x138003d2, 0x24000002 }, + { 0x130003d5, 0x1400ffd1 }, + { 0x130003d6, 0x1400ffca }, + { 0x130003d7, 0x14000000 }, + { 0x130003d8, 0x24000001 }, + { 0x130003d9, 0x1400ffff }, + { 0x130003da, 0x24000001 }, + { 0x130003db, 0x1400ffff }, + { 0x130003dc, 0x24000001 }, + { 0x130003dd, 0x1400ffff }, + { 0x130003de, 0x24000001 }, + { 0x130003df, 0x1400ffff }, + { 0x130003e0, 0x24000001 }, + { 0x130003e1, 0x1400ffff }, + { 0x0a0003e2, 0x24000001 }, + { 0x0a0003e3, 0x1400ffff }, + { 0x0a0003e4, 0x24000001 }, + { 0x0a0003e5, 0x1400ffff }, + { 0x0a0003e6, 0x24000001 }, + { 0x0a0003e7, 0x1400ffff }, + { 0x0a0003e8, 0x24000001 }, + { 0x0a0003e9, 0x1400ffff }, + { 0x0a0003ea, 0x24000001 }, + { 0x0a0003eb, 0x1400ffff }, + { 0x0a0003ec, 0x24000001 }, + { 0x0a0003ed, 0x1400ffff }, + { 0x0a0003ee, 0x24000001 }, + { 0x0a0003ef, 0x1400ffff }, + { 0x130003f0, 0x1400ffaa }, + { 0x130003f1, 0x1400ffb0 }, + { 0x130003f2, 0x14000007 }, + { 0x130003f3, 0x14000000 }, + { 0x130003f4, 0x2400ffc4 }, + { 0x130003f5, 0x1400ffa0 }, + { 0x130003f6, 0x64000000 }, + { 0x130003f7, 0x24000001 }, + { 0x130003f8, 0x1400ffff }, + { 0x130003f9, 0x2400fff9 }, + { 0x130003fa, 0x24000001 }, + { 0x130003fb, 0x1400ffff }, + { 0x130003fc, 0x14000000 }, + { 0x138003fd, 0x24000002 }, + { 0x0c000400, 0x24000050 }, + { 0x0c000401, 0x24000050 }, + { 0x0c000402, 0x24000050 }, + { 0x0c000403, 0x24000050 }, + { 0x0c000404, 0x24000050 }, + { 0x0c000405, 0x24000050 }, + { 0x0c000406, 0x24000050 }, + { 0x0c000407, 0x24000050 }, + { 0x0c000408, 0x24000050 }, + { 0x0c000409, 0x24000050 }, + { 0x0c00040a, 0x24000050 }, + { 0x0c00040b, 0x24000050 }, + { 0x0c00040c, 0x24000050 }, + { 0x0c00040d, 0x24000050 }, + { 0x0c00040e, 0x24000050 }, + { 0x0c00040f, 0x24000050 }, + { 0x0c000410, 0x24000020 }, + { 0x0c000411, 0x24000020 }, + { 0x0c000412, 0x24000020 }, + { 0x0c000413, 0x24000020 }, + { 0x0c000414, 0x24000020 }, + { 0x0c000415, 0x24000020 }, + { 0x0c000416, 0x24000020 }, + { 0x0c000417, 0x24000020 }, + { 0x0c000418, 0x24000020 }, + { 0x0c000419, 0x24000020 }, + { 0x0c00041a, 0x24000020 }, + { 0x0c00041b, 0x24000020 }, + { 0x0c00041c, 0x24000020 }, + { 0x0c00041d, 0x24000020 }, + { 0x0c00041e, 0x24000020 }, + { 0x0c00041f, 0x24000020 }, + { 0x0c000420, 0x24000020 }, + { 0x0c000421, 0x24000020 }, + { 0x0c000422, 0x24000020 }, + { 0x0c000423, 0x24000020 }, + { 0x0c000424, 0x24000020 }, + { 0x0c000425, 0x24000020 }, + { 0x0c000426, 0x24000020 }, + { 0x0c000427, 0x24000020 }, + { 0x0c000428, 0x24000020 }, + { 0x0c000429, 0x24000020 }, + { 0x0c00042a, 0x24000020 }, + { 0x0c00042b, 0x24000020 }, + { 0x0c00042c, 0x24000020 }, + { 0x0c00042d, 0x24000020 }, + { 0x0c00042e, 0x24000020 }, + { 0x0c00042f, 0x24000020 }, + { 0x0c000430, 0x1400ffe0 }, + { 0x0c000431, 0x1400ffe0 }, + { 0x0c000432, 0x1400ffe0 }, + { 0x0c000433, 0x1400ffe0 }, + { 0x0c000434, 0x1400ffe0 }, + { 0x0c000435, 0x1400ffe0 }, + { 0x0c000436, 0x1400ffe0 }, + { 0x0c000437, 0x1400ffe0 }, + { 0x0c000438, 0x1400ffe0 }, + { 0x0c000439, 0x1400ffe0 }, + { 0x0c00043a, 0x1400ffe0 }, + { 0x0c00043b, 0x1400ffe0 }, + { 0x0c00043c, 0x1400ffe0 }, + { 0x0c00043d, 0x1400ffe0 }, + { 0x0c00043e, 0x1400ffe0 }, + { 0x0c00043f, 0x1400ffe0 }, + { 0x0c000440, 0x1400ffe0 }, + { 0x0c000441, 0x1400ffe0 }, + { 0x0c000442, 0x1400ffe0 }, + { 0x0c000443, 0x1400ffe0 }, + { 0x0c000444, 0x1400ffe0 }, + { 0x0c000445, 0x1400ffe0 }, + { 0x0c000446, 0x1400ffe0 }, + { 0x0c000447, 0x1400ffe0 }, + { 0x0c000448, 0x1400ffe0 }, + { 0x0c000449, 0x1400ffe0 }, + { 0x0c00044a, 0x1400ffe0 }, + { 0x0c00044b, 0x1400ffe0 }, + { 0x0c00044c, 0x1400ffe0 }, + { 0x0c00044d, 0x1400ffe0 }, + { 0x0c00044e, 0x1400ffe0 }, + { 0x0c00044f, 0x1400ffe0 }, + { 0x0c000450, 0x1400ffb0 }, + { 0x0c000451, 0x1400ffb0 }, + { 0x0c000452, 0x1400ffb0 }, + { 0x0c000453, 0x1400ffb0 }, + { 0x0c000454, 0x1400ffb0 }, + { 0x0c000455, 0x1400ffb0 }, + { 0x0c000456, 0x1400ffb0 }, + { 0x0c000457, 0x1400ffb0 }, + { 0x0c000458, 0x1400ffb0 }, + { 0x0c000459, 0x1400ffb0 }, + { 0x0c00045a, 0x1400ffb0 }, + { 0x0c00045b, 0x1400ffb0 }, + { 0x0c00045c, 0x1400ffb0 }, + { 0x0c00045d, 0x1400ffb0 }, + { 0x0c00045e, 0x1400ffb0 }, + { 0x0c00045f, 0x1400ffb0 }, + { 0x0c000460, 0x24000001 }, + { 0x0c000461, 0x1400ffff }, + { 0x0c000462, 0x24000001 }, + { 0x0c000463, 0x1400ffff }, + { 0x0c000464, 0x24000001 }, + { 0x0c000465, 0x1400ffff }, + { 0x0c000466, 0x24000001 }, + { 0x0c000467, 0x1400ffff }, + { 0x0c000468, 0x24000001 }, + { 0x0c000469, 0x1400ffff }, + { 0x0c00046a, 0x24000001 }, + { 0x0c00046b, 0x1400ffff }, + { 0x0c00046c, 0x24000001 }, + { 0x0c00046d, 0x1400ffff }, + { 0x0c00046e, 0x24000001 }, + { 0x0c00046f, 0x1400ffff }, + { 0x0c000470, 0x24000001 }, + { 0x0c000471, 0x1400ffff }, + { 0x0c000472, 0x24000001 }, + { 0x0c000473, 0x1400ffff }, + { 0x0c000474, 0x24000001 }, + { 0x0c000475, 0x1400ffff }, + { 0x0c000476, 0x24000001 }, + { 0x0c000477, 0x1400ffff }, + { 0x0c000478, 0x24000001 }, + { 0x0c000479, 0x1400ffff }, + { 0x0c00047a, 0x24000001 }, + { 0x0c00047b, 0x1400ffff }, + { 0x0c00047c, 0x24000001 }, + { 0x0c00047d, 0x1400ffff }, + { 0x0c00047e, 0x24000001 }, + { 0x0c00047f, 0x1400ffff }, + { 0x0c000480, 0x24000001 }, + { 0x0c000481, 0x1400ffff }, + { 0x0c000482, 0x68000000 }, + { 0x0c800483, 0x30000003 }, + { 0x0c800488, 0x2c000001 }, + { 0x0c00048a, 0x24000001 }, + { 0x0c00048b, 0x1400ffff }, + { 0x0c00048c, 0x24000001 }, + { 0x0c00048d, 0x1400ffff }, + { 0x0c00048e, 0x24000001 }, + { 0x0c00048f, 0x1400ffff }, + { 0x0c000490, 0x24000001 }, + { 0x0c000491, 0x1400ffff }, + { 0x0c000492, 0x24000001 }, + { 0x0c000493, 0x1400ffff }, + { 0x0c000494, 0x24000001 }, + { 0x0c000495, 0x1400ffff }, + { 0x0c000496, 0x24000001 }, + { 0x0c000497, 0x1400ffff }, + { 0x0c000498, 0x24000001 }, + { 0x0c000499, 0x1400ffff }, + { 0x0c00049a, 0x24000001 }, + { 0x0c00049b, 0x1400ffff }, + { 0x0c00049c, 0x24000001 }, + { 0x0c00049d, 0x1400ffff }, + { 0x0c00049e, 0x24000001 }, + { 0x0c00049f, 0x1400ffff }, + { 0x0c0004a0, 0x24000001 }, + { 0x0c0004a1, 0x1400ffff }, + { 0x0c0004a2, 0x24000001 }, + { 0x0c0004a3, 0x1400ffff }, + { 0x0c0004a4, 0x24000001 }, + { 0x0c0004a5, 0x1400ffff }, + { 0x0c0004a6, 0x24000001 }, + { 0x0c0004a7, 0x1400ffff }, + { 0x0c0004a8, 0x24000001 }, + { 0x0c0004a9, 0x1400ffff }, + { 0x0c0004aa, 0x24000001 }, + { 0x0c0004ab, 0x1400ffff }, + { 0x0c0004ac, 0x24000001 }, + { 0x0c0004ad, 0x1400ffff }, + { 0x0c0004ae, 0x24000001 }, + { 0x0c0004af, 0x1400ffff }, + { 0x0c0004b0, 0x24000001 }, + { 0x0c0004b1, 0x1400ffff }, + { 0x0c0004b2, 0x24000001 }, + { 0x0c0004b3, 0x1400ffff }, + { 0x0c0004b4, 0x24000001 }, + { 0x0c0004b5, 0x1400ffff }, + { 0x0c0004b6, 0x24000001 }, + { 0x0c0004b7, 0x1400ffff }, + { 0x0c0004b8, 0x24000001 }, + { 0x0c0004b9, 0x1400ffff }, + { 0x0c0004ba, 0x24000001 }, + { 0x0c0004bb, 0x1400ffff }, + { 0x0c0004bc, 0x24000001 }, + { 0x0c0004bd, 0x1400ffff }, + { 0x0c0004be, 0x24000001 }, + { 0x0c0004bf, 0x1400ffff }, + { 0x0c0004c0, 0x24000000 }, + { 0x0c0004c1, 0x24000001 }, + { 0x0c0004c2, 0x1400ffff }, + { 0x0c0004c3, 0x24000001 }, + { 0x0c0004c4, 0x1400ffff }, + { 0x0c0004c5, 0x24000001 }, + { 0x0c0004c6, 0x1400ffff }, + { 0x0c0004c7, 0x24000001 }, + { 0x0c0004c8, 0x1400ffff }, + { 0x0c0004c9, 0x24000001 }, + { 0x0c0004ca, 0x1400ffff }, + { 0x0c0004cb, 0x24000001 }, + { 0x0c0004cc, 0x1400ffff }, + { 0x0c0004cd, 0x24000001 }, + { 0x0c0004ce, 0x1400ffff }, + { 0x0c0004d0, 0x24000001 }, + { 0x0c0004d1, 0x1400ffff }, + { 0x0c0004d2, 0x24000001 }, + { 0x0c0004d3, 0x1400ffff }, + { 0x0c0004d4, 0x24000001 }, + { 0x0c0004d5, 0x1400ffff }, + { 0x0c0004d6, 0x24000001 }, + { 0x0c0004d7, 0x1400ffff }, + { 0x0c0004d8, 0x24000001 }, + { 0x0c0004d9, 0x1400ffff }, + { 0x0c0004da, 0x24000001 }, + { 0x0c0004db, 0x1400ffff }, + { 0x0c0004dc, 0x24000001 }, + { 0x0c0004dd, 0x1400ffff }, + { 0x0c0004de, 0x24000001 }, + { 0x0c0004df, 0x1400ffff }, + { 0x0c0004e0, 0x24000001 }, + { 0x0c0004e1, 0x1400ffff }, + { 0x0c0004e2, 0x24000001 }, + { 0x0c0004e3, 0x1400ffff }, + { 0x0c0004e4, 0x24000001 }, + { 0x0c0004e5, 0x1400ffff }, + { 0x0c0004e6, 0x24000001 }, + { 0x0c0004e7, 0x1400ffff }, + { 0x0c0004e8, 0x24000001 }, + { 0x0c0004e9, 0x1400ffff }, + { 0x0c0004ea, 0x24000001 }, + { 0x0c0004eb, 0x1400ffff }, + { 0x0c0004ec, 0x24000001 }, + { 0x0c0004ed, 0x1400ffff }, + { 0x0c0004ee, 0x24000001 }, + { 0x0c0004ef, 0x1400ffff }, + { 0x0c0004f0, 0x24000001 }, + { 0x0c0004f1, 0x1400ffff }, + { 0x0c0004f2, 0x24000001 }, + { 0x0c0004f3, 0x1400ffff }, + { 0x0c0004f4, 0x24000001 }, + { 0x0c0004f5, 0x1400ffff }, + { 0x0c0004f6, 0x24000001 }, + { 0x0c0004f7, 0x1400ffff }, + { 0x0c0004f8, 0x24000001 }, + { 0x0c0004f9, 0x1400ffff }, + { 0x0c000500, 0x24000001 }, + { 0x0c000501, 0x1400ffff }, + { 0x0c000502, 0x24000001 }, + { 0x0c000503, 0x1400ffff }, + { 0x0c000504, 0x24000001 }, + { 0x0c000505, 0x1400ffff }, + { 0x0c000506, 0x24000001 }, + { 0x0c000507, 0x1400ffff }, + { 0x0c000508, 0x24000001 }, + { 0x0c000509, 0x1400ffff }, + { 0x0c00050a, 0x24000001 }, + { 0x0c00050b, 0x1400ffff }, + { 0x0c00050c, 0x24000001 }, + { 0x0c00050d, 0x1400ffff }, + { 0x0c00050e, 0x24000001 }, + { 0x0c00050f, 0x1400ffff }, + { 0x01000531, 0x24000030 }, + { 0x01000532, 0x24000030 }, + { 0x01000533, 0x24000030 }, + { 0x01000534, 0x24000030 }, + { 0x01000535, 0x24000030 }, + { 0x01000536, 0x24000030 }, + { 0x01000537, 0x24000030 }, + { 0x01000538, 0x24000030 }, + { 0x01000539, 0x24000030 }, + { 0x0100053a, 0x24000030 }, + { 0x0100053b, 0x24000030 }, + { 0x0100053c, 0x24000030 }, + { 0x0100053d, 0x24000030 }, + { 0x0100053e, 0x24000030 }, + { 0x0100053f, 0x24000030 }, + { 0x01000540, 0x24000030 }, + { 0x01000541, 0x24000030 }, + { 0x01000542, 0x24000030 }, + { 0x01000543, 0x24000030 }, + { 0x01000544, 0x24000030 }, + { 0x01000545, 0x24000030 }, + { 0x01000546, 0x24000030 }, + { 0x01000547, 0x24000030 }, + { 0x01000548, 0x24000030 }, + { 0x01000549, 0x24000030 }, + { 0x0100054a, 0x24000030 }, + { 0x0100054b, 0x24000030 }, + { 0x0100054c, 0x24000030 }, + { 0x0100054d, 0x24000030 }, + { 0x0100054e, 0x24000030 }, + { 0x0100054f, 0x24000030 }, + { 0x01000550, 0x24000030 }, + { 0x01000551, 0x24000030 }, + { 0x01000552, 0x24000030 }, + { 0x01000553, 0x24000030 }, + { 0x01000554, 0x24000030 }, + { 0x01000555, 0x24000030 }, + { 0x01000556, 0x24000030 }, + { 0x01000559, 0x18000000 }, + { 0x0180055a, 0x54000005 }, + { 0x01000561, 0x1400ffd0 }, + { 0x01000562, 0x1400ffd0 }, + { 0x01000563, 0x1400ffd0 }, + { 0x01000564, 0x1400ffd0 }, + { 0x01000565, 0x1400ffd0 }, + { 0x01000566, 0x1400ffd0 }, + { 0x01000567, 0x1400ffd0 }, + { 0x01000568, 0x1400ffd0 }, + { 0x01000569, 0x1400ffd0 }, + { 0x0100056a, 0x1400ffd0 }, + { 0x0100056b, 0x1400ffd0 }, + { 0x0100056c, 0x1400ffd0 }, + { 0x0100056d, 0x1400ffd0 }, + { 0x0100056e, 0x1400ffd0 }, + { 0x0100056f, 0x1400ffd0 }, + { 0x01000570, 0x1400ffd0 }, + { 0x01000571, 0x1400ffd0 }, + { 0x01000572, 0x1400ffd0 }, + { 0x01000573, 0x1400ffd0 }, + { 0x01000574, 0x1400ffd0 }, + { 0x01000575, 0x1400ffd0 }, + { 0x01000576, 0x1400ffd0 }, + { 0x01000577, 0x1400ffd0 }, + { 0x01000578, 0x1400ffd0 }, + { 0x01000579, 0x1400ffd0 }, + { 0x0100057a, 0x1400ffd0 }, + { 0x0100057b, 0x1400ffd0 }, + { 0x0100057c, 0x1400ffd0 }, + { 0x0100057d, 0x1400ffd0 }, + { 0x0100057e, 0x1400ffd0 }, + { 0x0100057f, 0x1400ffd0 }, + { 0x01000580, 0x1400ffd0 }, + { 0x01000581, 0x1400ffd0 }, + { 0x01000582, 0x1400ffd0 }, + { 0x01000583, 0x1400ffd0 }, + { 0x01000584, 0x1400ffd0 }, + { 0x01000585, 0x1400ffd0 }, + { 0x01000586, 0x1400ffd0 }, + { 0x01000587, 0x14000000 }, + { 0x09000589, 0x54000000 }, + { 0x0100058a, 0x44000000 }, + { 0x19800591, 0x30000028 }, + { 0x198005bb, 0x30000002 }, + { 0x190005be, 0x54000000 }, + { 0x190005bf, 0x30000000 }, + { 0x190005c0, 0x54000000 }, + { 0x198005c1, 0x30000001 }, + { 0x190005c3, 0x54000000 }, + { 0x198005c4, 0x30000001 }, + { 0x190005c6, 0x54000000 }, + { 0x190005c7, 0x30000000 }, + { 0x198005d0, 0x1c00001a }, + { 0x198005f0, 0x1c000002 }, + { 0x198005f3, 0x54000001 }, + { 0x09800600, 0x04000003 }, + { 0x0000060b, 0x5c000000 }, + { 0x0980060c, 0x54000001 }, + { 0x0080060e, 0x68000001 }, + { 0x00800610, 0x30000005 }, + { 0x0900061b, 0x54000000 }, + { 0x0080061e, 0x54000001 }, + { 0x00800621, 0x1c000019 }, + { 0x09000640, 0x18000000 }, + { 0x00800641, 0x1c000009 }, + { 0x1b80064b, 0x30000013 }, + { 0x09800660, 0x34000009 }, + { 0x0080066a, 0x54000003 }, + { 0x0080066e, 0x1c000001 }, + { 0x1b000670, 0x30000000 }, + { 0x00800671, 0x1c000062 }, + { 0x000006d4, 0x54000000 }, + { 0x000006d5, 0x1c000000 }, + { 0x008006d6, 0x30000006 }, + { 0x090006dd, 0x04000000 }, + { 0x000006de, 0x2c000000 }, + { 0x008006df, 0x30000005 }, + { 0x008006e5, 0x18000001 }, + { 0x008006e7, 0x30000001 }, + { 0x000006e9, 0x68000000 }, + { 0x008006ea, 0x30000003 }, + { 0x008006ee, 0x1c000001 }, + { 0x008006f0, 0x34000009 }, + { 0x008006fa, 0x1c000002 }, + { 0x008006fd, 0x68000001 }, + { 0x000006ff, 0x1c000000 }, + { 0x31800700, 0x5400000d }, + { 0x3100070f, 0x04000000 }, + { 0x31000710, 0x1c000000 }, + { 0x31000711, 0x30000000 }, + { 0x31800712, 0x1c00001d }, + { 0x31800730, 0x3000001a }, + { 0x3180074d, 0x1c000020 }, + { 0x37800780, 0x1c000025 }, + { 0x378007a6, 0x3000000a }, + { 0x370007b1, 0x1c000000 }, + { 0x0e800901, 0x30000001 }, + { 0x0e000903, 0x28000000 }, + { 0x0e800904, 0x1c000035 }, + { 0x0e00093c, 0x30000000 }, + { 0x0e00093d, 0x1c000000 }, + { 0x0e80093e, 0x28000002 }, + { 0x0e800941, 0x30000007 }, + { 0x0e800949, 0x28000003 }, + { 0x0e00094d, 0x30000000 }, + { 0x0e000950, 0x1c000000 }, + { 0x0e800951, 0x30000003 }, + { 0x0e800958, 0x1c000009 }, + { 0x0e800962, 0x30000001 }, + { 0x09800964, 0x54000001 }, + { 0x0e800966, 0x34000009 }, + { 0x09000970, 0x54000000 }, + { 0x0e00097d, 0x1c000000 }, + { 0x02000981, 0x30000000 }, + { 0x02800982, 0x28000001 }, + { 0x02800985, 0x1c000007 }, + { 0x0280098f, 0x1c000001 }, + { 0x02800993, 0x1c000015 }, + { 0x028009aa, 0x1c000006 }, + { 0x020009b2, 0x1c000000 }, + { 0x028009b6, 0x1c000003 }, + { 0x020009bc, 0x30000000 }, + { 0x020009bd, 0x1c000000 }, + { 0x028009be, 0x28000002 }, + { 0x028009c1, 0x30000003 }, + { 0x028009c7, 0x28000001 }, + { 0x028009cb, 0x28000001 }, + { 0x020009cd, 0x30000000 }, + { 0x020009ce, 0x1c000000 }, + { 0x020009d7, 0x28000000 }, + { 0x028009dc, 0x1c000001 }, + { 0x028009df, 0x1c000002 }, + { 0x028009e2, 0x30000001 }, + { 0x028009e6, 0x34000009 }, + { 0x028009f0, 0x1c000001 }, + { 0x028009f2, 0x5c000001 }, + { 0x028009f4, 0x3c000005 }, + { 0x020009fa, 0x68000000 }, + { 0x15800a01, 0x30000001 }, + { 0x15000a03, 0x28000000 }, + { 0x15800a05, 0x1c000005 }, + { 0x15800a0f, 0x1c000001 }, + { 0x15800a13, 0x1c000015 }, + { 0x15800a2a, 0x1c000006 }, + { 0x15800a32, 0x1c000001 }, + { 0x15800a35, 0x1c000001 }, + { 0x15800a38, 0x1c000001 }, + { 0x15000a3c, 0x30000000 }, + { 0x15800a3e, 0x28000002 }, + { 0x15800a41, 0x30000001 }, + { 0x15800a47, 0x30000001 }, + { 0x15800a4b, 0x30000002 }, + { 0x15800a59, 0x1c000003 }, + { 0x15000a5e, 0x1c000000 }, + { 0x15800a66, 0x34000009 }, + { 0x15800a70, 0x30000001 }, + { 0x15800a72, 0x1c000002 }, + { 0x14800a81, 0x30000001 }, + { 0x14000a83, 0x28000000 }, + { 0x14800a85, 0x1c000008 }, + { 0x14800a8f, 0x1c000002 }, + { 0x14800a93, 0x1c000015 }, + { 0x14800aaa, 0x1c000006 }, + { 0x14800ab2, 0x1c000001 }, + { 0x14800ab5, 0x1c000004 }, + { 0x14000abc, 0x30000000 }, + { 0x14000abd, 0x1c000000 }, + { 0x14800abe, 0x28000002 }, + { 0x14800ac1, 0x30000004 }, + { 0x14800ac7, 0x30000001 }, + { 0x14000ac9, 0x28000000 }, + { 0x14800acb, 0x28000001 }, + { 0x14000acd, 0x30000000 }, + { 0x14000ad0, 0x1c000000 }, + { 0x14800ae0, 0x1c000001 }, + { 0x14800ae2, 0x30000001 }, + { 0x14800ae6, 0x34000009 }, + { 0x14000af1, 0x5c000000 }, + { 0x2b000b01, 0x30000000 }, + { 0x2b800b02, 0x28000001 }, + { 0x2b800b05, 0x1c000007 }, + { 0x2b800b0f, 0x1c000001 }, + { 0x2b800b13, 0x1c000015 }, + { 0x2b800b2a, 0x1c000006 }, + { 0x2b800b32, 0x1c000001 }, + { 0x2b800b35, 0x1c000004 }, + { 0x2b000b3c, 0x30000000 }, + { 0x2b000b3d, 0x1c000000 }, + { 0x2b000b3e, 0x28000000 }, + { 0x2b000b3f, 0x30000000 }, + { 0x2b000b40, 0x28000000 }, + { 0x2b800b41, 0x30000002 }, + { 0x2b800b47, 0x28000001 }, + { 0x2b800b4b, 0x28000001 }, + { 0x2b000b4d, 0x30000000 }, + { 0x2b000b56, 0x30000000 }, + { 0x2b000b57, 0x28000000 }, + { 0x2b800b5c, 0x1c000001 }, + { 0x2b800b5f, 0x1c000002 }, + { 0x2b800b66, 0x34000009 }, + { 0x2b000b70, 0x68000000 }, + { 0x2b000b71, 0x1c000000 }, + { 0x35000b82, 0x30000000 }, + { 0x35000b83, 0x1c000000 }, + { 0x35800b85, 0x1c000005 }, + { 0x35800b8e, 0x1c000002 }, + { 0x35800b92, 0x1c000003 }, + { 0x35800b99, 0x1c000001 }, + { 0x35000b9c, 0x1c000000 }, + { 0x35800b9e, 0x1c000001 }, + { 0x35800ba3, 0x1c000001 }, + { 0x35800ba8, 0x1c000002 }, + { 0x35800bae, 0x1c00000b }, + { 0x35800bbe, 0x28000001 }, + { 0x35000bc0, 0x30000000 }, + { 0x35800bc1, 0x28000001 }, + { 0x35800bc6, 0x28000002 }, + { 0x35800bca, 0x28000002 }, + { 0x35000bcd, 0x30000000 }, + { 0x35000bd7, 0x28000000 }, + { 0x35800be6, 0x34000009 }, + { 0x35800bf0, 0x3c000002 }, + { 0x35800bf3, 0x68000005 }, + { 0x35000bf9, 0x5c000000 }, + { 0x35000bfa, 0x68000000 }, + { 0x36800c01, 0x28000002 }, + { 0x36800c05, 0x1c000007 }, + { 0x36800c0e, 0x1c000002 }, + { 0x36800c12, 0x1c000016 }, + { 0x36800c2a, 0x1c000009 }, + { 0x36800c35, 0x1c000004 }, + { 0x36800c3e, 0x30000002 }, + { 0x36800c41, 0x28000003 }, + { 0x36800c46, 0x30000002 }, + { 0x36800c4a, 0x30000003 }, + { 0x36800c55, 0x30000001 }, + { 0x36800c60, 0x1c000001 }, + { 0x36800c66, 0x34000009 }, + { 0x1c800c82, 0x28000001 }, + { 0x1c800c85, 0x1c000007 }, + { 0x1c800c8e, 0x1c000002 }, + { 0x1c800c92, 0x1c000016 }, + { 0x1c800caa, 0x1c000009 }, + { 0x1c800cb5, 0x1c000004 }, + { 0x1c000cbc, 0x30000000 }, + { 0x1c000cbd, 0x1c000000 }, + { 0x1c000cbe, 0x28000000 }, + { 0x1c000cbf, 0x30000000 }, + { 0x1c800cc0, 0x28000004 }, + { 0x1c000cc6, 0x30000000 }, + { 0x1c800cc7, 0x28000001 }, + { 0x1c800cca, 0x28000001 }, + { 0x1c800ccc, 0x30000001 }, + { 0x1c800cd5, 0x28000001 }, + { 0x1c000cde, 0x1c000000 }, + { 0x1c800ce0, 0x1c000001 }, + { 0x1c800ce6, 0x34000009 }, + { 0x24800d02, 0x28000001 }, + { 0x24800d05, 0x1c000007 }, + { 0x24800d0e, 0x1c000002 }, + { 0x24800d12, 0x1c000016 }, + { 0x24800d2a, 0x1c00000f }, + { 0x24800d3e, 0x28000002 }, + { 0x24800d41, 0x30000002 }, + { 0x24800d46, 0x28000002 }, + { 0x24800d4a, 0x28000002 }, + { 0x24000d4d, 0x30000000 }, + { 0x24000d57, 0x28000000 }, + { 0x24800d60, 0x1c000001 }, + { 0x24800d66, 0x34000009 }, + { 0x2f800d82, 0x28000001 }, + { 0x2f800d85, 0x1c000011 }, + { 0x2f800d9a, 0x1c000017 }, + { 0x2f800db3, 0x1c000008 }, + { 0x2f000dbd, 0x1c000000 }, + { 0x2f800dc0, 0x1c000006 }, + { 0x2f000dca, 0x30000000 }, + { 0x2f800dcf, 0x28000002 }, + { 0x2f800dd2, 0x30000002 }, + { 0x2f000dd6, 0x30000000 }, + { 0x2f800dd8, 0x28000007 }, + { 0x2f800df2, 0x28000001 }, + { 0x2f000df4, 0x54000000 }, + { 0x38800e01, 0x1c00002f }, + { 0x38000e31, 0x30000000 }, + { 0x38800e32, 0x1c000001 }, + { 0x38800e34, 0x30000006 }, + { 0x09000e3f, 0x5c000000 }, + { 0x38800e40, 0x1c000005 }, + { 0x38000e46, 0x18000000 }, + { 0x38800e47, 0x30000007 }, + { 0x38000e4f, 0x54000000 }, + { 0x38800e50, 0x34000009 }, + { 0x38800e5a, 0x54000001 }, + { 0x20800e81, 0x1c000001 }, + { 0x20000e84, 0x1c000000 }, + { 0x20800e87, 0x1c000001 }, + { 0x20000e8a, 0x1c000000 }, + { 0x20000e8d, 0x1c000000 }, + { 0x20800e94, 0x1c000003 }, + { 0x20800e99, 0x1c000006 }, + { 0x20800ea1, 0x1c000002 }, + { 0x20000ea5, 0x1c000000 }, + { 0x20000ea7, 0x1c000000 }, + { 0x20800eaa, 0x1c000001 }, + { 0x20800ead, 0x1c000003 }, + { 0x20000eb1, 0x30000000 }, + { 0x20800eb2, 0x1c000001 }, + { 0x20800eb4, 0x30000005 }, + { 0x20800ebb, 0x30000001 }, + { 0x20000ebd, 0x1c000000 }, + { 0x20800ec0, 0x1c000004 }, + { 0x20000ec6, 0x18000000 }, + { 0x20800ec8, 0x30000005 }, + { 0x20800ed0, 0x34000009 }, + { 0x20800edc, 0x1c000001 }, + { 0x39000f00, 0x1c000000 }, + { 0x39800f01, 0x68000002 }, + { 0x39800f04, 0x5400000e }, + { 0x39800f13, 0x68000004 }, + { 0x39800f18, 0x30000001 }, + { 0x39800f1a, 0x68000005 }, + { 0x39800f20, 0x34000009 }, + { 0x39800f2a, 0x3c000009 }, + { 0x39000f34, 0x68000000 }, + { 0x39000f35, 0x30000000 }, + { 0x39000f36, 0x68000000 }, + { 0x39000f37, 0x30000000 }, + { 0x39000f38, 0x68000000 }, + { 0x39000f39, 0x30000000 }, + { 0x39000f3a, 0x58000000 }, + { 0x39000f3b, 0x48000000 }, + { 0x39000f3c, 0x58000000 }, + { 0x39000f3d, 0x48000000 }, + { 0x39800f3e, 0x28000001 }, + { 0x39800f40, 0x1c000007 }, + { 0x39800f49, 0x1c000021 }, + { 0x39800f71, 0x3000000d }, + { 0x39000f7f, 0x28000000 }, + { 0x39800f80, 0x30000004 }, + { 0x39000f85, 0x54000000 }, + { 0x39800f86, 0x30000001 }, + { 0x39800f88, 0x1c000003 }, + { 0x39800f90, 0x30000007 }, + { 0x39800f99, 0x30000023 }, + { 0x39800fbe, 0x68000007 }, + { 0x39000fc6, 0x30000000 }, + { 0x39800fc7, 0x68000005 }, + { 0x39000fcf, 0x68000000 }, + { 0x39800fd0, 0x54000001 }, + { 0x26801000, 0x1c000021 }, + { 0x26801023, 0x1c000004 }, + { 0x26801029, 0x1c000001 }, + { 0x2600102c, 0x28000000 }, + { 0x2680102d, 0x30000003 }, + { 0x26001031, 0x28000000 }, + { 0x26001032, 0x30000000 }, + { 0x26801036, 0x30000001 }, + { 0x26001038, 0x28000000 }, + { 0x26001039, 0x30000000 }, + { 0x26801040, 0x34000009 }, + { 0x2680104a, 0x54000005 }, + { 0x26801050, 0x1c000005 }, + { 0x26801056, 0x28000001 }, + { 0x26801058, 0x30000001 }, + { 0x100010a0, 0x24001c60 }, + { 0x100010a1, 0x24001c60 }, + { 0x100010a2, 0x24001c60 }, + { 0x100010a3, 0x24001c60 }, + { 0x100010a4, 0x24001c60 }, + { 0x100010a5, 0x24001c60 }, + { 0x100010a6, 0x24001c60 }, + { 0x100010a7, 0x24001c60 }, + { 0x100010a8, 0x24001c60 }, + { 0x100010a9, 0x24001c60 }, + { 0x100010aa, 0x24001c60 }, + { 0x100010ab, 0x24001c60 }, + { 0x100010ac, 0x24001c60 }, + { 0x100010ad, 0x24001c60 }, + { 0x100010ae, 0x24001c60 }, + { 0x100010af, 0x24001c60 }, + { 0x100010b0, 0x24001c60 }, + { 0x100010b1, 0x24001c60 }, + { 0x100010b2, 0x24001c60 }, + { 0x100010b3, 0x24001c60 }, + { 0x100010b4, 0x24001c60 }, + { 0x100010b5, 0x24001c60 }, + { 0x100010b6, 0x24001c60 }, + { 0x100010b7, 0x24001c60 }, + { 0x100010b8, 0x24001c60 }, + { 0x100010b9, 0x24001c60 }, + { 0x100010ba, 0x24001c60 }, + { 0x100010bb, 0x24001c60 }, + { 0x100010bc, 0x24001c60 }, + { 0x100010bd, 0x24001c60 }, + { 0x100010be, 0x24001c60 }, + { 0x100010bf, 0x24001c60 }, + { 0x100010c0, 0x24001c60 }, + { 0x100010c1, 0x24001c60 }, + { 0x100010c2, 0x24001c60 }, + { 0x100010c3, 0x24001c60 }, + { 0x100010c4, 0x24001c60 }, + { 0x100010c5, 0x24001c60 }, + { 0x108010d0, 0x1c00002a }, + { 0x090010fb, 0x54000000 }, + { 0x100010fc, 0x18000000 }, + { 0x17801100, 0x1c000059 }, + { 0x1780115f, 0x1c000043 }, + { 0x178011a8, 0x1c000051 }, + { 0x0f801200, 0x1c000048 }, + { 0x0f80124a, 0x1c000003 }, + { 0x0f801250, 0x1c000006 }, + { 0x0f001258, 0x1c000000 }, + { 0x0f80125a, 0x1c000003 }, + { 0x0f801260, 0x1c000028 }, + { 0x0f80128a, 0x1c000003 }, + { 0x0f801290, 0x1c000020 }, + { 0x0f8012b2, 0x1c000003 }, + { 0x0f8012b8, 0x1c000006 }, + { 0x0f0012c0, 0x1c000000 }, + { 0x0f8012c2, 0x1c000003 }, + { 0x0f8012c8, 0x1c00000e }, + { 0x0f8012d8, 0x1c000038 }, + { 0x0f801312, 0x1c000003 }, + { 0x0f801318, 0x1c000042 }, + { 0x0f00135f, 0x30000000 }, + { 0x0f001360, 0x68000000 }, + { 0x0f801361, 0x54000007 }, + { 0x0f801369, 0x3c000013 }, + { 0x0f801380, 0x1c00000f }, + { 0x0f801390, 0x68000009 }, + { 0x088013a0, 0x1c000054 }, + { 0x07801401, 0x1c00026b }, + { 0x0780166d, 0x54000001 }, + { 0x0780166f, 0x1c000007 }, + { 0x28001680, 0x74000000 }, + { 0x28801681, 0x1c000019 }, + { 0x2800169b, 0x58000000 }, + { 0x2800169c, 0x48000000 }, + { 0x2d8016a0, 0x1c00004a }, + { 0x098016eb, 0x54000002 }, + { 0x2d8016ee, 0x38000002 }, + { 0x32801700, 0x1c00000c }, + { 0x3280170e, 0x1c000003 }, + { 0x32801712, 0x30000002 }, + { 0x18801720, 0x1c000011 }, + { 0x18801732, 0x30000002 }, + { 0x09801735, 0x54000001 }, + { 0x06801740, 0x1c000011 }, + { 0x06801752, 0x30000001 }, + { 0x33801760, 0x1c00000c }, + { 0x3380176e, 0x1c000002 }, + { 0x33801772, 0x30000001 }, + { 0x1f801780, 0x1c000033 }, + { 0x1f8017b4, 0x04000001 }, + { 0x1f0017b6, 0x28000000 }, + { 0x1f8017b7, 0x30000006 }, + { 0x1f8017be, 0x28000007 }, + { 0x1f0017c6, 0x30000000 }, + { 0x1f8017c7, 0x28000001 }, + { 0x1f8017c9, 0x3000000a }, + { 0x1f8017d4, 0x54000002 }, + { 0x1f0017d7, 0x18000000 }, + { 0x1f8017d8, 0x54000002 }, + { 0x1f0017db, 0x5c000000 }, + { 0x1f0017dc, 0x1c000000 }, + { 0x1f0017dd, 0x30000000 }, + { 0x1f8017e0, 0x34000009 }, + { 0x1f8017f0, 0x3c000009 }, + { 0x25801800, 0x54000005 }, + { 0x25001806, 0x44000000 }, + { 0x25801807, 0x54000003 }, + { 0x2580180b, 0x30000002 }, + { 0x2500180e, 0x74000000 }, + { 0x25801810, 0x34000009 }, + { 0x25801820, 0x1c000022 }, + { 0x25001843, 0x18000000 }, + { 0x25801844, 0x1c000033 }, + { 0x25801880, 0x1c000028 }, + { 0x250018a9, 0x30000000 }, + { 0x22801900, 0x1c00001c }, + { 0x22801920, 0x30000002 }, + { 0x22801923, 0x28000003 }, + { 0x22801927, 0x30000001 }, + { 0x22801929, 0x28000002 }, + { 0x22801930, 0x28000001 }, + { 0x22001932, 0x30000000 }, + { 0x22801933, 0x28000005 }, + { 0x22801939, 0x30000002 }, + { 0x22001940, 0x68000000 }, + { 0x22801944, 0x54000001 }, + { 0x22801946, 0x34000009 }, + { 0x34801950, 0x1c00001d }, + { 0x34801970, 0x1c000004 }, + { 0x27801980, 0x1c000029 }, + { 0x278019b0, 0x28000010 }, + { 0x278019c1, 0x1c000006 }, + { 0x278019c8, 0x28000001 }, + { 0x278019d0, 0x34000009 }, + { 0x278019de, 0x54000001 }, + { 0x1f8019e0, 0x6800001f }, + { 0x05801a00, 0x1c000016 }, + { 0x05801a17, 0x30000001 }, + { 0x05801a19, 0x28000002 }, + { 0x05801a1e, 0x54000001 }, + { 0x21801d00, 0x1400002b }, + { 0x21801d2c, 0x18000035 }, + { 0x21801d62, 0x14000015 }, + { 0x0c001d78, 0x18000000 }, + { 0x21801d79, 0x14000021 }, + { 0x21801d9b, 0x18000024 }, + { 0x1b801dc0, 0x30000003 }, + { 0x21001e00, 0x24000001 }, + { 0x21001e01, 0x1400ffff }, + { 0x21001e02, 0x24000001 }, + { 0x21001e03, 0x1400ffff }, + { 0x21001e04, 0x24000001 }, + { 0x21001e05, 0x1400ffff }, + { 0x21001e06, 0x24000001 }, + { 0x21001e07, 0x1400ffff }, + { 0x21001e08, 0x24000001 }, + { 0x21001e09, 0x1400ffff }, + { 0x21001e0a, 0x24000001 }, + { 0x21001e0b, 0x1400ffff }, + { 0x21001e0c, 0x24000001 }, + { 0x21001e0d, 0x1400ffff }, + { 0x21001e0e, 0x24000001 }, + { 0x21001e0f, 0x1400ffff }, + { 0x21001e10, 0x24000001 }, + { 0x21001e11, 0x1400ffff }, + { 0x21001e12, 0x24000001 }, + { 0x21001e13, 0x1400ffff }, + { 0x21001e14, 0x24000001 }, + { 0x21001e15, 0x1400ffff }, + { 0x21001e16, 0x24000001 }, + { 0x21001e17, 0x1400ffff }, + { 0x21001e18, 0x24000001 }, + { 0x21001e19, 0x1400ffff }, + { 0x21001e1a, 0x24000001 }, + { 0x21001e1b, 0x1400ffff }, + { 0x21001e1c, 0x24000001 }, + { 0x21001e1d, 0x1400ffff }, + { 0x21001e1e, 0x24000001 }, + { 0x21001e1f, 0x1400ffff }, + { 0x21001e20, 0x24000001 }, + { 0x21001e21, 0x1400ffff }, + { 0x21001e22, 0x24000001 }, + { 0x21001e23, 0x1400ffff }, + { 0x21001e24, 0x24000001 }, + { 0x21001e25, 0x1400ffff }, + { 0x21001e26, 0x24000001 }, + { 0x21001e27, 0x1400ffff }, + { 0x21001e28, 0x24000001 }, + { 0x21001e29, 0x1400ffff }, + { 0x21001e2a, 0x24000001 }, + { 0x21001e2b, 0x1400ffff }, + { 0x21001e2c, 0x24000001 }, + { 0x21001e2d, 0x1400ffff }, + { 0x21001e2e, 0x24000001 }, + { 0x21001e2f, 0x1400ffff }, + { 0x21001e30, 0x24000001 }, + { 0x21001e31, 0x1400ffff }, + { 0x21001e32, 0x24000001 }, + { 0x21001e33, 0x1400ffff }, + { 0x21001e34, 0x24000001 }, + { 0x21001e35, 0x1400ffff }, + { 0x21001e36, 0x24000001 }, + { 0x21001e37, 0x1400ffff }, + { 0x21001e38, 0x24000001 }, + { 0x21001e39, 0x1400ffff }, + { 0x21001e3a, 0x24000001 }, + { 0x21001e3b, 0x1400ffff }, + { 0x21001e3c, 0x24000001 }, + { 0x21001e3d, 0x1400ffff }, + { 0x21001e3e, 0x24000001 }, + { 0x21001e3f, 0x1400ffff }, + { 0x21001e40, 0x24000001 }, + { 0x21001e41, 0x1400ffff }, + { 0x21001e42, 0x24000001 }, + { 0x21001e43, 0x1400ffff }, + { 0x21001e44, 0x24000001 }, + { 0x21001e45, 0x1400ffff }, + { 0x21001e46, 0x24000001 }, + { 0x21001e47, 0x1400ffff }, + { 0x21001e48, 0x24000001 }, + { 0x21001e49, 0x1400ffff }, + { 0x21001e4a, 0x24000001 }, + { 0x21001e4b, 0x1400ffff }, + { 0x21001e4c, 0x24000001 }, + { 0x21001e4d, 0x1400ffff }, + { 0x21001e4e, 0x24000001 }, + { 0x21001e4f, 0x1400ffff }, + { 0x21001e50, 0x24000001 }, + { 0x21001e51, 0x1400ffff }, + { 0x21001e52, 0x24000001 }, + { 0x21001e53, 0x1400ffff }, + { 0x21001e54, 0x24000001 }, + { 0x21001e55, 0x1400ffff }, + { 0x21001e56, 0x24000001 }, + { 0x21001e57, 0x1400ffff }, + { 0x21001e58, 0x24000001 }, + { 0x21001e59, 0x1400ffff }, + { 0x21001e5a, 0x24000001 }, + { 0x21001e5b, 0x1400ffff }, + { 0x21001e5c, 0x24000001 }, + { 0x21001e5d, 0x1400ffff }, + { 0x21001e5e, 0x24000001 }, + { 0x21001e5f, 0x1400ffff }, + { 0x21001e60, 0x24000001 }, + { 0x21001e61, 0x1400ffff }, + { 0x21001e62, 0x24000001 }, + { 0x21001e63, 0x1400ffff }, + { 0x21001e64, 0x24000001 }, + { 0x21001e65, 0x1400ffff }, + { 0x21001e66, 0x24000001 }, + { 0x21001e67, 0x1400ffff }, + { 0x21001e68, 0x24000001 }, + { 0x21001e69, 0x1400ffff }, + { 0x21001e6a, 0x24000001 }, + { 0x21001e6b, 0x1400ffff }, + { 0x21001e6c, 0x24000001 }, + { 0x21001e6d, 0x1400ffff }, + { 0x21001e6e, 0x24000001 }, + { 0x21001e6f, 0x1400ffff }, + { 0x21001e70, 0x24000001 }, + { 0x21001e71, 0x1400ffff }, + { 0x21001e72, 0x24000001 }, + { 0x21001e73, 0x1400ffff }, + { 0x21001e74, 0x24000001 }, + { 0x21001e75, 0x1400ffff }, + { 0x21001e76, 0x24000001 }, + { 0x21001e77, 0x1400ffff }, + { 0x21001e78, 0x24000001 }, + { 0x21001e79, 0x1400ffff }, + { 0x21001e7a, 0x24000001 }, + { 0x21001e7b, 0x1400ffff }, + { 0x21001e7c, 0x24000001 }, + { 0x21001e7d, 0x1400ffff }, + { 0x21001e7e, 0x24000001 }, + { 0x21001e7f, 0x1400ffff }, + { 0x21001e80, 0x24000001 }, + { 0x21001e81, 0x1400ffff }, + { 0x21001e82, 0x24000001 }, + { 0x21001e83, 0x1400ffff }, + { 0x21001e84, 0x24000001 }, + { 0x21001e85, 0x1400ffff }, + { 0x21001e86, 0x24000001 }, + { 0x21001e87, 0x1400ffff }, + { 0x21001e88, 0x24000001 }, + { 0x21001e89, 0x1400ffff }, + { 0x21001e8a, 0x24000001 }, + { 0x21001e8b, 0x1400ffff }, + { 0x21001e8c, 0x24000001 }, + { 0x21001e8d, 0x1400ffff }, + { 0x21001e8e, 0x24000001 }, + { 0x21001e8f, 0x1400ffff }, + { 0x21001e90, 0x24000001 }, + { 0x21001e91, 0x1400ffff }, + { 0x21001e92, 0x24000001 }, + { 0x21001e93, 0x1400ffff }, + { 0x21001e94, 0x24000001 }, + { 0x21001e95, 0x1400ffff }, + { 0x21801e96, 0x14000004 }, + { 0x21001e9b, 0x1400ffc5 }, + { 0x21001ea0, 0x24000001 }, + { 0x21001ea1, 0x1400ffff }, + { 0x21001ea2, 0x24000001 }, + { 0x21001ea3, 0x1400ffff }, + { 0x21001ea4, 0x24000001 }, + { 0x21001ea5, 0x1400ffff }, + { 0x21001ea6, 0x24000001 }, + { 0x21001ea7, 0x1400ffff }, + { 0x21001ea8, 0x24000001 }, + { 0x21001ea9, 0x1400ffff }, + { 0x21001eaa, 0x24000001 }, + { 0x21001eab, 0x1400ffff }, + { 0x21001eac, 0x24000001 }, + { 0x21001ead, 0x1400ffff }, + { 0x21001eae, 0x24000001 }, + { 0x21001eaf, 0x1400ffff }, + { 0x21001eb0, 0x24000001 }, + { 0x21001eb1, 0x1400ffff }, + { 0x21001eb2, 0x24000001 }, + { 0x21001eb3, 0x1400ffff }, + { 0x21001eb4, 0x24000001 }, + { 0x21001eb5, 0x1400ffff }, + { 0x21001eb6, 0x24000001 }, + { 0x21001eb7, 0x1400ffff }, + { 0x21001eb8, 0x24000001 }, + { 0x21001eb9, 0x1400ffff }, + { 0x21001eba, 0x24000001 }, + { 0x21001ebb, 0x1400ffff }, + { 0x21001ebc, 0x24000001 }, + { 0x21001ebd, 0x1400ffff }, + { 0x21001ebe, 0x24000001 }, + { 0x21001ebf, 0x1400ffff }, + { 0x21001ec0, 0x24000001 }, + { 0x21001ec1, 0x1400ffff }, + { 0x21001ec2, 0x24000001 }, + { 0x21001ec3, 0x1400ffff }, + { 0x21001ec4, 0x24000001 }, + { 0x21001ec5, 0x1400ffff }, + { 0x21001ec6, 0x24000001 }, + { 0x21001ec7, 0x1400ffff }, + { 0x21001ec8, 0x24000001 }, + { 0x21001ec9, 0x1400ffff }, + { 0x21001eca, 0x24000001 }, + { 0x21001ecb, 0x1400ffff }, + { 0x21001ecc, 0x24000001 }, + { 0x21001ecd, 0x1400ffff }, + { 0x21001ece, 0x24000001 }, + { 0x21001ecf, 0x1400ffff }, + { 0x21001ed0, 0x24000001 }, + { 0x21001ed1, 0x1400ffff }, + { 0x21001ed2, 0x24000001 }, + { 0x21001ed3, 0x1400ffff }, + { 0x21001ed4, 0x24000001 }, + { 0x21001ed5, 0x1400ffff }, + { 0x21001ed6, 0x24000001 }, + { 0x21001ed7, 0x1400ffff }, + { 0x21001ed8, 0x24000001 }, + { 0x21001ed9, 0x1400ffff }, + { 0x21001eda, 0x24000001 }, + { 0x21001edb, 0x1400ffff }, + { 0x21001edc, 0x24000001 }, + { 0x21001edd, 0x1400ffff }, + { 0x21001ede, 0x24000001 }, + { 0x21001edf, 0x1400ffff }, + { 0x21001ee0, 0x24000001 }, + { 0x21001ee1, 0x1400ffff }, + { 0x21001ee2, 0x24000001 }, + { 0x21001ee3, 0x1400ffff }, + { 0x21001ee4, 0x24000001 }, + { 0x21001ee5, 0x1400ffff }, + { 0x21001ee6, 0x24000001 }, + { 0x21001ee7, 0x1400ffff }, + { 0x21001ee8, 0x24000001 }, + { 0x21001ee9, 0x1400ffff }, + { 0x21001eea, 0x24000001 }, + { 0x21001eeb, 0x1400ffff }, + { 0x21001eec, 0x24000001 }, + { 0x21001eed, 0x1400ffff }, + { 0x21001eee, 0x24000001 }, + { 0x21001eef, 0x1400ffff }, + { 0x21001ef0, 0x24000001 }, + { 0x21001ef1, 0x1400ffff }, + { 0x21001ef2, 0x24000001 }, + { 0x21001ef3, 0x1400ffff }, + { 0x21001ef4, 0x24000001 }, + { 0x21001ef5, 0x1400ffff }, + { 0x21001ef6, 0x24000001 }, + { 0x21001ef7, 0x1400ffff }, + { 0x21001ef8, 0x24000001 }, + { 0x21001ef9, 0x1400ffff }, + { 0x13001f00, 0x14000008 }, + { 0x13001f01, 0x14000008 }, + { 0x13001f02, 0x14000008 }, + { 0x13001f03, 0x14000008 }, + { 0x13001f04, 0x14000008 }, + { 0x13001f05, 0x14000008 }, + { 0x13001f06, 0x14000008 }, + { 0x13001f07, 0x14000008 }, + { 0x13001f08, 0x2400fff8 }, + { 0x13001f09, 0x2400fff8 }, + { 0x13001f0a, 0x2400fff8 }, + { 0x13001f0b, 0x2400fff8 }, + { 0x13001f0c, 0x2400fff8 }, + { 0x13001f0d, 0x2400fff8 }, + { 0x13001f0e, 0x2400fff8 }, + { 0x13001f0f, 0x2400fff8 }, + { 0x13001f10, 0x14000008 }, + { 0x13001f11, 0x14000008 }, + { 0x13001f12, 0x14000008 }, + { 0x13001f13, 0x14000008 }, + { 0x13001f14, 0x14000008 }, + { 0x13001f15, 0x14000008 }, + { 0x13001f18, 0x2400fff8 }, + { 0x13001f19, 0x2400fff8 }, + { 0x13001f1a, 0x2400fff8 }, + { 0x13001f1b, 0x2400fff8 }, + { 0x13001f1c, 0x2400fff8 }, + { 0x13001f1d, 0x2400fff8 }, + { 0x13001f20, 0x14000008 }, + { 0x13001f21, 0x14000008 }, + { 0x13001f22, 0x14000008 }, + { 0x13001f23, 0x14000008 }, + { 0x13001f24, 0x14000008 }, + { 0x13001f25, 0x14000008 }, + { 0x13001f26, 0x14000008 }, + { 0x13001f27, 0x14000008 }, + { 0x13001f28, 0x2400fff8 }, + { 0x13001f29, 0x2400fff8 }, + { 0x13001f2a, 0x2400fff8 }, + { 0x13001f2b, 0x2400fff8 }, + { 0x13001f2c, 0x2400fff8 }, + { 0x13001f2d, 0x2400fff8 }, + { 0x13001f2e, 0x2400fff8 }, + { 0x13001f2f, 0x2400fff8 }, + { 0x13001f30, 0x14000008 }, + { 0x13001f31, 0x14000008 }, + { 0x13001f32, 0x14000008 }, + { 0x13001f33, 0x14000008 }, + { 0x13001f34, 0x14000008 }, + { 0x13001f35, 0x14000008 }, + { 0x13001f36, 0x14000008 }, + { 0x13001f37, 0x14000008 }, + { 0x13001f38, 0x2400fff8 }, + { 0x13001f39, 0x2400fff8 }, + { 0x13001f3a, 0x2400fff8 }, + { 0x13001f3b, 0x2400fff8 }, + { 0x13001f3c, 0x2400fff8 }, + { 0x13001f3d, 0x2400fff8 }, + { 0x13001f3e, 0x2400fff8 }, + { 0x13001f3f, 0x2400fff8 }, + { 0x13001f40, 0x14000008 }, + { 0x13001f41, 0x14000008 }, + { 0x13001f42, 0x14000008 }, + { 0x13001f43, 0x14000008 }, + { 0x13001f44, 0x14000008 }, + { 0x13001f45, 0x14000008 }, + { 0x13001f48, 0x2400fff8 }, + { 0x13001f49, 0x2400fff8 }, + { 0x13001f4a, 0x2400fff8 }, + { 0x13001f4b, 0x2400fff8 }, + { 0x13001f4c, 0x2400fff8 }, + { 0x13001f4d, 0x2400fff8 }, + { 0x13001f50, 0x14000000 }, + { 0x13001f51, 0x14000008 }, + { 0x13001f52, 0x14000000 }, + { 0x13001f53, 0x14000008 }, + { 0x13001f54, 0x14000000 }, + { 0x13001f55, 0x14000008 }, + { 0x13001f56, 0x14000000 }, + { 0x13001f57, 0x14000008 }, + { 0x13001f59, 0x2400fff8 }, + { 0x13001f5b, 0x2400fff8 }, + { 0x13001f5d, 0x2400fff8 }, + { 0x13001f5f, 0x2400fff8 }, + { 0x13001f60, 0x14000008 }, + { 0x13001f61, 0x14000008 }, + { 0x13001f62, 0x14000008 }, + { 0x13001f63, 0x14000008 }, + { 0x13001f64, 0x14000008 }, + { 0x13001f65, 0x14000008 }, + { 0x13001f66, 0x14000008 }, + { 0x13001f67, 0x14000008 }, + { 0x13001f68, 0x2400fff8 }, + { 0x13001f69, 0x2400fff8 }, + { 0x13001f6a, 0x2400fff8 }, + { 0x13001f6b, 0x2400fff8 }, + { 0x13001f6c, 0x2400fff8 }, + { 0x13001f6d, 0x2400fff8 }, + { 0x13001f6e, 0x2400fff8 }, + { 0x13001f6f, 0x2400fff8 }, + { 0x13001f70, 0x1400004a }, + { 0x13001f71, 0x1400004a }, + { 0x13001f72, 0x14000056 }, + { 0x13001f73, 0x14000056 }, + { 0x13001f74, 0x14000056 }, + { 0x13001f75, 0x14000056 }, + { 0x13001f76, 0x14000064 }, + { 0x13001f77, 0x14000064 }, + { 0x13001f78, 0x14000080 }, + { 0x13001f79, 0x14000080 }, + { 0x13001f7a, 0x14000070 }, + { 0x13001f7b, 0x14000070 }, + { 0x13001f7c, 0x1400007e }, + { 0x13001f7d, 0x1400007e }, + { 0x13001f80, 0x14000008 }, + { 0x13001f81, 0x14000008 }, + { 0x13001f82, 0x14000008 }, + { 0x13001f83, 0x14000008 }, + { 0x13001f84, 0x14000008 }, + { 0x13001f85, 0x14000008 }, + { 0x13001f86, 0x14000008 }, + { 0x13001f87, 0x14000008 }, + { 0x13001f88, 0x2000fff8 }, + { 0x13001f89, 0x2000fff8 }, + { 0x13001f8a, 0x2000fff8 }, + { 0x13001f8b, 0x2000fff8 }, + { 0x13001f8c, 0x2000fff8 }, + { 0x13001f8d, 0x2000fff8 }, + { 0x13001f8e, 0x2000fff8 }, + { 0x13001f8f, 0x2000fff8 }, + { 0x13001f90, 0x14000008 }, + { 0x13001f91, 0x14000008 }, + { 0x13001f92, 0x14000008 }, + { 0x13001f93, 0x14000008 }, + { 0x13001f94, 0x14000008 }, + { 0x13001f95, 0x14000008 }, + { 0x13001f96, 0x14000008 }, + { 0x13001f97, 0x14000008 }, + { 0x13001f98, 0x2000fff8 }, + { 0x13001f99, 0x2000fff8 }, + { 0x13001f9a, 0x2000fff8 }, + { 0x13001f9b, 0x2000fff8 }, + { 0x13001f9c, 0x2000fff8 }, + { 0x13001f9d, 0x2000fff8 }, + { 0x13001f9e, 0x2000fff8 }, + { 0x13001f9f, 0x2000fff8 }, + { 0x13001fa0, 0x14000008 }, + { 0x13001fa1, 0x14000008 }, + { 0x13001fa2, 0x14000008 }, + { 0x13001fa3, 0x14000008 }, + { 0x13001fa4, 0x14000008 }, + { 0x13001fa5, 0x14000008 }, + { 0x13001fa6, 0x14000008 }, + { 0x13001fa7, 0x14000008 }, + { 0x13001fa8, 0x2000fff8 }, + { 0x13001fa9, 0x2000fff8 }, + { 0x13001faa, 0x2000fff8 }, + { 0x13001fab, 0x2000fff8 }, + { 0x13001fac, 0x2000fff8 }, + { 0x13001fad, 0x2000fff8 }, + { 0x13001fae, 0x2000fff8 }, + { 0x13001faf, 0x2000fff8 }, + { 0x13001fb0, 0x14000008 }, + { 0x13001fb1, 0x14000008 }, + { 0x13001fb2, 0x14000000 }, + { 0x13001fb3, 0x14000009 }, + { 0x13001fb4, 0x14000000 }, + { 0x13801fb6, 0x14000001 }, + { 0x13001fb8, 0x2400fff8 }, + { 0x13001fb9, 0x2400fff8 }, + { 0x13001fba, 0x2400ffb6 }, + { 0x13001fbb, 0x2400ffb6 }, + { 0x13001fbc, 0x2000fff7 }, + { 0x13001fbd, 0x60000000 }, + { 0x13001fbe, 0x1400e3db }, + { 0x13801fbf, 0x60000002 }, + { 0x13001fc2, 0x14000000 }, + { 0x13001fc3, 0x14000009 }, + { 0x13001fc4, 0x14000000 }, + { 0x13801fc6, 0x14000001 }, + { 0x13001fc8, 0x2400ffaa }, + { 0x13001fc9, 0x2400ffaa }, + { 0x13001fca, 0x2400ffaa }, + { 0x13001fcb, 0x2400ffaa }, + { 0x13001fcc, 0x2000fff7 }, + { 0x13801fcd, 0x60000002 }, + { 0x13001fd0, 0x14000008 }, + { 0x13001fd1, 0x14000008 }, + { 0x13801fd2, 0x14000001 }, + { 0x13801fd6, 0x14000001 }, + { 0x13001fd8, 0x2400fff8 }, + { 0x13001fd9, 0x2400fff8 }, + { 0x13001fda, 0x2400ff9c }, + { 0x13001fdb, 0x2400ff9c }, + { 0x13801fdd, 0x60000002 }, + { 0x13001fe0, 0x14000008 }, + { 0x13001fe1, 0x14000008 }, + { 0x13801fe2, 0x14000002 }, + { 0x13001fe5, 0x14000007 }, + { 0x13801fe6, 0x14000001 }, + { 0x13001fe8, 0x2400fff8 }, + { 0x13001fe9, 0x2400fff8 }, + { 0x13001fea, 0x2400ff90 }, + { 0x13001feb, 0x2400ff90 }, + { 0x13001fec, 0x2400fff9 }, + { 0x13801fed, 0x60000002 }, + { 0x13001ff2, 0x14000000 }, + { 0x13001ff3, 0x14000009 }, + { 0x13001ff4, 0x14000000 }, + { 0x13801ff6, 0x14000001 }, + { 0x13001ff8, 0x2400ff80 }, + { 0x13001ff9, 0x2400ff80 }, + { 0x13001ffa, 0x2400ff82 }, + { 0x13001ffb, 0x2400ff82 }, + { 0x13001ffc, 0x2000fff7 }, + { 0x13801ffd, 0x60000001 }, + { 0x09802000, 0x7400000a }, + { 0x0980200b, 0x04000004 }, + { 0x09802010, 0x44000005 }, + { 0x09802016, 0x54000001 }, + { 0x09002018, 0x50000000 }, + { 0x09002019, 0x4c000000 }, + { 0x0900201a, 0x58000000 }, + { 0x0980201b, 0x50000001 }, + { 0x0900201d, 0x4c000000 }, + { 0x0900201e, 0x58000000 }, + { 0x0900201f, 0x50000000 }, + { 0x09802020, 0x54000007 }, + { 0x09002028, 0x6c000000 }, + { 0x09002029, 0x70000000 }, + { 0x0980202a, 0x04000004 }, + { 0x0900202f, 0x74000000 }, + { 0x09802030, 0x54000008 }, + { 0x09002039, 0x50000000 }, + { 0x0900203a, 0x4c000000 }, + { 0x0980203b, 0x54000003 }, + { 0x0980203f, 0x40000001 }, + { 0x09802041, 0x54000002 }, + { 0x09002044, 0x64000000 }, + { 0x09002045, 0x58000000 }, + { 0x09002046, 0x48000000 }, + { 0x09802047, 0x5400000a }, + { 0x09002052, 0x64000000 }, + { 0x09002053, 0x54000000 }, + { 0x09002054, 0x40000000 }, + { 0x09802055, 0x54000009 }, + { 0x0900205f, 0x74000000 }, + { 0x09802060, 0x04000003 }, + { 0x0980206a, 0x04000005 }, + { 0x09002070, 0x3c000000 }, + { 0x21002071, 0x14000000 }, + { 0x09802074, 0x3c000005 }, + { 0x0980207a, 0x64000002 }, + { 0x0900207d, 0x58000000 }, + { 0x0900207e, 0x48000000 }, + { 0x2100207f, 0x14000000 }, + { 0x09802080, 0x3c000009 }, + { 0x0980208a, 0x64000002 }, + { 0x0900208d, 0x58000000 }, + { 0x0900208e, 0x48000000 }, + { 0x21802090, 0x18000004 }, + { 0x098020a0, 0x5c000015 }, + { 0x1b8020d0, 0x3000000c }, + { 0x1b8020dd, 0x2c000003 }, + { 0x1b0020e1, 0x30000000 }, + { 0x1b8020e2, 0x2c000002 }, + { 0x1b8020e5, 0x30000006 }, + { 0x09802100, 0x68000001 }, + { 0x09002102, 0x24000000 }, + { 0x09802103, 0x68000003 }, + { 0x09002107, 0x24000000 }, + { 0x09802108, 0x68000001 }, + { 0x0900210a, 0x14000000 }, + { 0x0980210b, 0x24000002 }, + { 0x0980210e, 0x14000001 }, + { 0x09802110, 0x24000002 }, + { 0x09002113, 0x14000000 }, + { 0x09002114, 0x68000000 }, + { 0x09002115, 0x24000000 }, + { 0x09802116, 0x68000002 }, + { 0x09802119, 0x24000004 }, + { 0x0980211e, 0x68000005 }, + { 0x09002124, 0x24000000 }, + { 0x09002125, 0x68000000 }, + { 0x13002126, 0x2400e2a3 }, + { 0x09002127, 0x68000000 }, + { 0x09002128, 0x24000000 }, + { 0x09002129, 0x68000000 }, + { 0x2100212a, 0x2400df41 }, + { 0x2100212b, 0x2400dfba }, + { 0x0980212c, 0x24000001 }, + { 0x0900212e, 0x68000000 }, + { 0x0900212f, 0x14000000 }, + { 0x09802130, 0x24000001 }, + { 0x09002132, 0x68000000 }, + { 0x09002133, 0x24000000 }, + { 0x09002134, 0x14000000 }, + { 0x09802135, 0x1c000003 }, + { 0x09002139, 0x14000000 }, + { 0x0980213a, 0x68000001 }, + { 0x0980213c, 0x14000001 }, + { 0x0980213e, 0x24000001 }, + { 0x09802140, 0x64000004 }, + { 0x09002145, 0x24000000 }, + { 0x09802146, 0x14000003 }, + { 0x0900214a, 0x68000000 }, + { 0x0900214b, 0x64000000 }, + { 0x0900214c, 0x68000000 }, + { 0x09802153, 0x3c00000c }, + { 0x09002160, 0x38000010 }, + { 0x09002161, 0x38000010 }, + { 0x09002162, 0x38000010 }, + { 0x09002163, 0x38000010 }, + { 0x09002164, 0x38000010 }, + { 0x09002165, 0x38000010 }, + { 0x09002166, 0x38000010 }, + { 0x09002167, 0x38000010 }, + { 0x09002168, 0x38000010 }, + { 0x09002169, 0x38000010 }, + { 0x0900216a, 0x38000010 }, + { 0x0900216b, 0x38000010 }, + { 0x0900216c, 0x38000010 }, + { 0x0900216d, 0x38000010 }, + { 0x0900216e, 0x38000010 }, + { 0x0900216f, 0x38000010 }, + { 0x09002170, 0x3800fff0 }, + { 0x09002171, 0x3800fff0 }, + { 0x09002172, 0x3800fff0 }, + { 0x09002173, 0x3800fff0 }, + { 0x09002174, 0x3800fff0 }, + { 0x09002175, 0x3800fff0 }, + { 0x09002176, 0x3800fff0 }, + { 0x09002177, 0x3800fff0 }, + { 0x09002178, 0x3800fff0 }, + { 0x09002179, 0x3800fff0 }, + { 0x0900217a, 0x3800fff0 }, + { 0x0900217b, 0x3800fff0 }, + { 0x0900217c, 0x3800fff0 }, + { 0x0900217d, 0x3800fff0 }, + { 0x0900217e, 0x3800fff0 }, + { 0x0900217f, 0x3800fff0 }, + { 0x09802180, 0x38000003 }, + { 0x09802190, 0x64000004 }, + { 0x09802195, 0x68000004 }, + { 0x0980219a, 0x64000001 }, + { 0x0980219c, 0x68000003 }, + { 0x090021a0, 0x64000000 }, + { 0x098021a1, 0x68000001 }, + { 0x090021a3, 0x64000000 }, + { 0x098021a4, 0x68000001 }, + { 0x090021a6, 0x64000000 }, + { 0x098021a7, 0x68000006 }, + { 0x090021ae, 0x64000000 }, + { 0x098021af, 0x6800001e }, + { 0x098021ce, 0x64000001 }, + { 0x098021d0, 0x68000001 }, + { 0x090021d2, 0x64000000 }, + { 0x090021d3, 0x68000000 }, + { 0x090021d4, 0x64000000 }, + { 0x098021d5, 0x6800001e }, + { 0x098021f4, 0x6400010b }, + { 0x09802300, 0x68000007 }, + { 0x09802308, 0x64000003 }, + { 0x0980230c, 0x68000013 }, + { 0x09802320, 0x64000001 }, + { 0x09802322, 0x68000006 }, + { 0x09002329, 0x58000000 }, + { 0x0900232a, 0x48000000 }, + { 0x0980232b, 0x68000050 }, + { 0x0900237c, 0x64000000 }, + { 0x0980237d, 0x6800001d }, + { 0x0980239b, 0x64000018 }, + { 0x090023b4, 0x58000000 }, + { 0x090023b5, 0x48000000 }, + { 0x090023b6, 0x54000000 }, + { 0x098023b7, 0x68000024 }, + { 0x09802400, 0x68000026 }, + { 0x09802440, 0x6800000a }, + { 0x09802460, 0x3c00003b }, + { 0x0980249c, 0x68000019 }, + { 0x090024b6, 0x6800001a }, + { 0x090024b7, 0x6800001a }, + { 0x090024b8, 0x6800001a }, + { 0x090024b9, 0x6800001a }, + { 0x090024ba, 0x6800001a }, + { 0x090024bb, 0x6800001a }, + { 0x090024bc, 0x6800001a }, + { 0x090024bd, 0x6800001a }, + { 0x090024be, 0x6800001a }, + { 0x090024bf, 0x6800001a }, + { 0x090024c0, 0x6800001a }, + { 0x090024c1, 0x6800001a }, + { 0x090024c2, 0x6800001a }, + { 0x090024c3, 0x6800001a }, + { 0x090024c4, 0x6800001a }, + { 0x090024c5, 0x6800001a }, + { 0x090024c6, 0x6800001a }, + { 0x090024c7, 0x6800001a }, + { 0x090024c8, 0x6800001a }, + { 0x090024c9, 0x6800001a }, + { 0x090024ca, 0x6800001a }, + { 0x090024cb, 0x6800001a }, + { 0x090024cc, 0x6800001a }, + { 0x090024cd, 0x6800001a }, + { 0x090024ce, 0x6800001a }, + { 0x090024cf, 0x6800001a }, + { 0x090024d0, 0x6800ffe6 }, + { 0x090024d1, 0x6800ffe6 }, + { 0x090024d2, 0x6800ffe6 }, + { 0x090024d3, 0x6800ffe6 }, + { 0x090024d4, 0x6800ffe6 }, + { 0x090024d5, 0x6800ffe6 }, + { 0x090024d6, 0x6800ffe6 }, + { 0x090024d7, 0x6800ffe6 }, + { 0x090024d8, 0x6800ffe6 }, + { 0x090024d9, 0x6800ffe6 }, + { 0x090024da, 0x6800ffe6 }, + { 0x090024db, 0x6800ffe6 }, + { 0x090024dc, 0x6800ffe6 }, + { 0x090024dd, 0x6800ffe6 }, + { 0x090024de, 0x6800ffe6 }, + { 0x090024df, 0x6800ffe6 }, + { 0x090024e0, 0x6800ffe6 }, + { 0x090024e1, 0x6800ffe6 }, + { 0x090024e2, 0x6800ffe6 }, + { 0x090024e3, 0x6800ffe6 }, + { 0x090024e4, 0x6800ffe6 }, + { 0x090024e5, 0x6800ffe6 }, + { 0x090024e6, 0x6800ffe6 }, + { 0x090024e7, 0x6800ffe6 }, + { 0x090024e8, 0x6800ffe6 }, + { 0x090024e9, 0x6800ffe6 }, + { 0x098024ea, 0x3c000015 }, + { 0x09802500, 0x680000b6 }, + { 0x090025b7, 0x64000000 }, + { 0x098025b8, 0x68000008 }, + { 0x090025c1, 0x64000000 }, + { 0x098025c2, 0x68000035 }, + { 0x098025f8, 0x64000007 }, + { 0x09802600, 0x6800006e }, + { 0x0900266f, 0x64000000 }, + { 0x09802670, 0x6800002c }, + { 0x098026a0, 0x68000011 }, + { 0x09802701, 0x68000003 }, + { 0x09802706, 0x68000003 }, + { 0x0980270c, 0x6800001b }, + { 0x09802729, 0x68000022 }, + { 0x0900274d, 0x68000000 }, + { 0x0980274f, 0x68000003 }, + { 0x09002756, 0x68000000 }, + { 0x09802758, 0x68000006 }, + { 0x09802761, 0x68000006 }, + { 0x09002768, 0x58000000 }, + { 0x09002769, 0x48000000 }, + { 0x0900276a, 0x58000000 }, + { 0x0900276b, 0x48000000 }, + { 0x0900276c, 0x58000000 }, + { 0x0900276d, 0x48000000 }, + { 0x0900276e, 0x58000000 }, + { 0x0900276f, 0x48000000 }, + { 0x09002770, 0x58000000 }, + { 0x09002771, 0x48000000 }, + { 0x09002772, 0x58000000 }, + { 0x09002773, 0x48000000 }, + { 0x09002774, 0x58000000 }, + { 0x09002775, 0x48000000 }, + { 0x09802776, 0x3c00001d }, + { 0x09002794, 0x68000000 }, + { 0x09802798, 0x68000017 }, + { 0x098027b1, 0x6800000d }, + { 0x098027c0, 0x64000004 }, + { 0x090027c5, 0x58000000 }, + { 0x090027c6, 0x48000000 }, + { 0x098027d0, 0x64000015 }, + { 0x090027e6, 0x58000000 }, + { 0x090027e7, 0x48000000 }, + { 0x090027e8, 0x58000000 }, + { 0x090027e9, 0x48000000 }, + { 0x090027ea, 0x58000000 }, + { 0x090027eb, 0x48000000 }, + { 0x098027f0, 0x6400000f }, + { 0x04802800, 0x680000ff }, + { 0x09802900, 0x64000082 }, + { 0x09002983, 0x58000000 }, + { 0x09002984, 0x48000000 }, + { 0x09002985, 0x58000000 }, + { 0x09002986, 0x48000000 }, + { 0x09002987, 0x58000000 }, + { 0x09002988, 0x48000000 }, + { 0x09002989, 0x58000000 }, + { 0x0900298a, 0x48000000 }, + { 0x0900298b, 0x58000000 }, + { 0x0900298c, 0x48000000 }, + { 0x0900298d, 0x58000000 }, + { 0x0900298e, 0x48000000 }, + { 0x0900298f, 0x58000000 }, + { 0x09002990, 0x48000000 }, + { 0x09002991, 0x58000000 }, + { 0x09002992, 0x48000000 }, + { 0x09002993, 0x58000000 }, + { 0x09002994, 0x48000000 }, + { 0x09002995, 0x58000000 }, + { 0x09002996, 0x48000000 }, + { 0x09002997, 0x58000000 }, + { 0x09002998, 0x48000000 }, + { 0x09802999, 0x6400003e }, + { 0x090029d8, 0x58000000 }, + { 0x090029d9, 0x48000000 }, + { 0x090029da, 0x58000000 }, + { 0x090029db, 0x48000000 }, + { 0x098029dc, 0x6400001f }, + { 0x090029fc, 0x58000000 }, + { 0x090029fd, 0x48000000 }, + { 0x098029fe, 0x64000101 }, + { 0x09802b00, 0x68000013 }, + { 0x11002c00, 0x24000030 }, + { 0x11002c01, 0x24000030 }, + { 0x11002c02, 0x24000030 }, + { 0x11002c03, 0x24000030 }, + { 0x11002c04, 0x24000030 }, + { 0x11002c05, 0x24000030 }, + { 0x11002c06, 0x24000030 }, + { 0x11002c07, 0x24000030 }, + { 0x11002c08, 0x24000030 }, + { 0x11002c09, 0x24000030 }, + { 0x11002c0a, 0x24000030 }, + { 0x11002c0b, 0x24000030 }, + { 0x11002c0c, 0x24000030 }, + { 0x11002c0d, 0x24000030 }, + { 0x11002c0e, 0x24000030 }, + { 0x11002c0f, 0x24000030 }, + { 0x11002c10, 0x24000030 }, + { 0x11002c11, 0x24000030 }, + { 0x11002c12, 0x24000030 }, + { 0x11002c13, 0x24000030 }, + { 0x11002c14, 0x24000030 }, + { 0x11002c15, 0x24000030 }, + { 0x11002c16, 0x24000030 }, + { 0x11002c17, 0x24000030 }, + { 0x11002c18, 0x24000030 }, + { 0x11002c19, 0x24000030 }, + { 0x11002c1a, 0x24000030 }, + { 0x11002c1b, 0x24000030 }, + { 0x11002c1c, 0x24000030 }, + { 0x11002c1d, 0x24000030 }, + { 0x11002c1e, 0x24000030 }, + { 0x11002c1f, 0x24000030 }, + { 0x11002c20, 0x24000030 }, + { 0x11002c21, 0x24000030 }, + { 0x11002c22, 0x24000030 }, + { 0x11002c23, 0x24000030 }, + { 0x11002c24, 0x24000030 }, + { 0x11002c25, 0x24000030 }, + { 0x11002c26, 0x24000030 }, + { 0x11002c27, 0x24000030 }, + { 0x11002c28, 0x24000030 }, + { 0x11002c29, 0x24000030 }, + { 0x11002c2a, 0x24000030 }, + { 0x11002c2b, 0x24000030 }, + { 0x11002c2c, 0x24000030 }, + { 0x11002c2d, 0x24000030 }, + { 0x11002c2e, 0x24000030 }, + { 0x11002c30, 0x1400ffd0 }, + { 0x11002c31, 0x1400ffd0 }, + { 0x11002c32, 0x1400ffd0 }, + { 0x11002c33, 0x1400ffd0 }, + { 0x11002c34, 0x1400ffd0 }, + { 0x11002c35, 0x1400ffd0 }, + { 0x11002c36, 0x1400ffd0 }, + { 0x11002c37, 0x1400ffd0 }, + { 0x11002c38, 0x1400ffd0 }, + { 0x11002c39, 0x1400ffd0 }, + { 0x11002c3a, 0x1400ffd0 }, + { 0x11002c3b, 0x1400ffd0 }, + { 0x11002c3c, 0x1400ffd0 }, + { 0x11002c3d, 0x1400ffd0 }, + { 0x11002c3e, 0x1400ffd0 }, + { 0x11002c3f, 0x1400ffd0 }, + { 0x11002c40, 0x1400ffd0 }, + { 0x11002c41, 0x1400ffd0 }, + { 0x11002c42, 0x1400ffd0 }, + { 0x11002c43, 0x1400ffd0 }, + { 0x11002c44, 0x1400ffd0 }, + { 0x11002c45, 0x1400ffd0 }, + { 0x11002c46, 0x1400ffd0 }, + { 0x11002c47, 0x1400ffd0 }, + { 0x11002c48, 0x1400ffd0 }, + { 0x11002c49, 0x1400ffd0 }, + { 0x11002c4a, 0x1400ffd0 }, + { 0x11002c4b, 0x1400ffd0 }, + { 0x11002c4c, 0x1400ffd0 }, + { 0x11002c4d, 0x1400ffd0 }, + { 0x11002c4e, 0x1400ffd0 }, + { 0x11002c4f, 0x1400ffd0 }, + { 0x11002c50, 0x1400ffd0 }, + { 0x11002c51, 0x1400ffd0 }, + { 0x11002c52, 0x1400ffd0 }, + { 0x11002c53, 0x1400ffd0 }, + { 0x11002c54, 0x1400ffd0 }, + { 0x11002c55, 0x1400ffd0 }, + { 0x11002c56, 0x1400ffd0 }, + { 0x11002c57, 0x1400ffd0 }, + { 0x11002c58, 0x1400ffd0 }, + { 0x11002c59, 0x1400ffd0 }, + { 0x11002c5a, 0x1400ffd0 }, + { 0x11002c5b, 0x1400ffd0 }, + { 0x11002c5c, 0x1400ffd0 }, + { 0x11002c5d, 0x1400ffd0 }, + { 0x11002c5e, 0x1400ffd0 }, + { 0x0a002c80, 0x24000001 }, + { 0x0a002c81, 0x1400ffff }, + { 0x0a002c82, 0x24000001 }, + { 0x0a002c83, 0x1400ffff }, + { 0x0a002c84, 0x24000001 }, + { 0x0a002c85, 0x1400ffff }, + { 0x0a002c86, 0x24000001 }, + { 0x0a002c87, 0x1400ffff }, + { 0x0a002c88, 0x24000001 }, + { 0x0a002c89, 0x1400ffff }, + { 0x0a002c8a, 0x24000001 }, + { 0x0a002c8b, 0x1400ffff }, + { 0x0a002c8c, 0x24000001 }, + { 0x0a002c8d, 0x1400ffff }, + { 0x0a002c8e, 0x24000001 }, + { 0x0a002c8f, 0x1400ffff }, + { 0x0a002c90, 0x24000001 }, + { 0x0a002c91, 0x1400ffff }, + { 0x0a002c92, 0x24000001 }, + { 0x0a002c93, 0x1400ffff }, + { 0x0a002c94, 0x24000001 }, + { 0x0a002c95, 0x1400ffff }, + { 0x0a002c96, 0x24000001 }, + { 0x0a002c97, 0x1400ffff }, + { 0x0a002c98, 0x24000001 }, + { 0x0a002c99, 0x1400ffff }, + { 0x0a002c9a, 0x24000001 }, + { 0x0a002c9b, 0x1400ffff }, + { 0x0a002c9c, 0x24000001 }, + { 0x0a002c9d, 0x1400ffff }, + { 0x0a002c9e, 0x24000001 }, + { 0x0a002c9f, 0x1400ffff }, + { 0x0a002ca0, 0x24000001 }, + { 0x0a002ca1, 0x1400ffff }, + { 0x0a002ca2, 0x24000001 }, + { 0x0a002ca3, 0x1400ffff }, + { 0x0a002ca4, 0x24000001 }, + { 0x0a002ca5, 0x1400ffff }, + { 0x0a002ca6, 0x24000001 }, + { 0x0a002ca7, 0x1400ffff }, + { 0x0a002ca8, 0x24000001 }, + { 0x0a002ca9, 0x1400ffff }, + { 0x0a002caa, 0x24000001 }, + { 0x0a002cab, 0x1400ffff }, + { 0x0a002cac, 0x24000001 }, + { 0x0a002cad, 0x1400ffff }, + { 0x0a002cae, 0x24000001 }, + { 0x0a002caf, 0x1400ffff }, + { 0x0a002cb0, 0x24000001 }, + { 0x0a002cb1, 0x1400ffff }, + { 0x0a002cb2, 0x24000001 }, + { 0x0a002cb3, 0x1400ffff }, + { 0x0a002cb4, 0x24000001 }, + { 0x0a002cb5, 0x1400ffff }, + { 0x0a002cb6, 0x24000001 }, + { 0x0a002cb7, 0x1400ffff }, + { 0x0a002cb8, 0x24000001 }, + { 0x0a002cb9, 0x1400ffff }, + { 0x0a002cba, 0x24000001 }, + { 0x0a002cbb, 0x1400ffff }, + { 0x0a002cbc, 0x24000001 }, + { 0x0a002cbd, 0x1400ffff }, + { 0x0a002cbe, 0x24000001 }, + { 0x0a002cbf, 0x1400ffff }, + { 0x0a002cc0, 0x24000001 }, + { 0x0a002cc1, 0x1400ffff }, + { 0x0a002cc2, 0x24000001 }, + { 0x0a002cc3, 0x1400ffff }, + { 0x0a002cc4, 0x24000001 }, + { 0x0a002cc5, 0x1400ffff }, + { 0x0a002cc6, 0x24000001 }, + { 0x0a002cc7, 0x1400ffff }, + { 0x0a002cc8, 0x24000001 }, + { 0x0a002cc9, 0x1400ffff }, + { 0x0a002cca, 0x24000001 }, + { 0x0a002ccb, 0x1400ffff }, + { 0x0a002ccc, 0x24000001 }, + { 0x0a002ccd, 0x1400ffff }, + { 0x0a002cce, 0x24000001 }, + { 0x0a002ccf, 0x1400ffff }, + { 0x0a002cd0, 0x24000001 }, + { 0x0a002cd1, 0x1400ffff }, + { 0x0a002cd2, 0x24000001 }, + { 0x0a002cd3, 0x1400ffff }, + { 0x0a002cd4, 0x24000001 }, + { 0x0a002cd5, 0x1400ffff }, + { 0x0a002cd6, 0x24000001 }, + { 0x0a002cd7, 0x1400ffff }, + { 0x0a002cd8, 0x24000001 }, + { 0x0a002cd9, 0x1400ffff }, + { 0x0a002cda, 0x24000001 }, + { 0x0a002cdb, 0x1400ffff }, + { 0x0a002cdc, 0x24000001 }, + { 0x0a002cdd, 0x1400ffff }, + { 0x0a002cde, 0x24000001 }, + { 0x0a002cdf, 0x1400ffff }, + { 0x0a002ce0, 0x24000001 }, + { 0x0a002ce1, 0x1400ffff }, + { 0x0a002ce2, 0x24000001 }, + { 0x0a002ce3, 0x1400ffff }, + { 0x0a002ce4, 0x14000000 }, + { 0x0a802ce5, 0x68000005 }, + { 0x0a802cf9, 0x54000003 }, + { 0x0a002cfd, 0x3c000000 }, + { 0x0a802cfe, 0x54000001 }, + { 0x10002d00, 0x1400e3a0 }, + { 0x10002d01, 0x1400e3a0 }, + { 0x10002d02, 0x1400e3a0 }, + { 0x10002d03, 0x1400e3a0 }, + { 0x10002d04, 0x1400e3a0 }, + { 0x10002d05, 0x1400e3a0 }, + { 0x10002d06, 0x1400e3a0 }, + { 0x10002d07, 0x1400e3a0 }, + { 0x10002d08, 0x1400e3a0 }, + { 0x10002d09, 0x1400e3a0 }, + { 0x10002d0a, 0x1400e3a0 }, + { 0x10002d0b, 0x1400e3a0 }, + { 0x10002d0c, 0x1400e3a0 }, + { 0x10002d0d, 0x1400e3a0 }, + { 0x10002d0e, 0x1400e3a0 }, + { 0x10002d0f, 0x1400e3a0 }, + { 0x10002d10, 0x1400e3a0 }, + { 0x10002d11, 0x1400e3a0 }, + { 0x10002d12, 0x1400e3a0 }, + { 0x10002d13, 0x1400e3a0 }, + { 0x10002d14, 0x1400e3a0 }, + { 0x10002d15, 0x1400e3a0 }, + { 0x10002d16, 0x1400e3a0 }, + { 0x10002d17, 0x1400e3a0 }, + { 0x10002d18, 0x1400e3a0 }, + { 0x10002d19, 0x1400e3a0 }, + { 0x10002d1a, 0x1400e3a0 }, + { 0x10002d1b, 0x1400e3a0 }, + { 0x10002d1c, 0x1400e3a0 }, + { 0x10002d1d, 0x1400e3a0 }, + { 0x10002d1e, 0x1400e3a0 }, + { 0x10002d1f, 0x1400e3a0 }, + { 0x10002d20, 0x1400e3a0 }, + { 0x10002d21, 0x1400e3a0 }, + { 0x10002d22, 0x1400e3a0 }, + { 0x10002d23, 0x1400e3a0 }, + { 0x10002d24, 0x1400e3a0 }, + { 0x10002d25, 0x1400e3a0 }, + { 0x3a802d30, 0x1c000035 }, + { 0x3a002d6f, 0x18000000 }, + { 0x0f802d80, 0x1c000016 }, + { 0x0f802da0, 0x1c000006 }, + { 0x0f802da8, 0x1c000006 }, + { 0x0f802db0, 0x1c000006 }, + { 0x0f802db8, 0x1c000006 }, + { 0x0f802dc0, 0x1c000006 }, + { 0x0f802dc8, 0x1c000006 }, + { 0x0f802dd0, 0x1c000006 }, + { 0x0f802dd8, 0x1c000006 }, + { 0x09802e00, 0x54000001 }, + { 0x09002e02, 0x50000000 }, + { 0x09002e03, 0x4c000000 }, + { 0x09002e04, 0x50000000 }, + { 0x09002e05, 0x4c000000 }, + { 0x09802e06, 0x54000002 }, + { 0x09002e09, 0x50000000 }, + { 0x09002e0a, 0x4c000000 }, + { 0x09002e0b, 0x54000000 }, + { 0x09002e0c, 0x50000000 }, + { 0x09002e0d, 0x4c000000 }, + { 0x09802e0e, 0x54000008 }, + { 0x09002e17, 0x44000000 }, + { 0x09002e1c, 0x50000000 }, + { 0x09002e1d, 0x4c000000 }, + { 0x16802e80, 0x68000019 }, + { 0x16802e9b, 0x68000058 }, + { 0x16802f00, 0x680000d5 }, + { 0x09802ff0, 0x6800000b }, + { 0x09003000, 0x74000000 }, + { 0x09803001, 0x54000002 }, + { 0x09003004, 0x68000000 }, + { 0x16003005, 0x18000000 }, + { 0x09003006, 0x1c000000 }, + { 0x16003007, 0x38000000 }, + { 0x09003008, 0x58000000 }, + { 0x09003009, 0x48000000 }, + { 0x0900300a, 0x58000000 }, + { 0x0900300b, 0x48000000 }, + { 0x0900300c, 0x58000000 }, + { 0x0900300d, 0x48000000 }, + { 0x0900300e, 0x58000000 }, + { 0x0900300f, 0x48000000 }, + { 0x09003010, 0x58000000 }, + { 0x09003011, 0x48000000 }, + { 0x09803012, 0x68000001 }, + { 0x09003014, 0x58000000 }, + { 0x09003015, 0x48000000 }, + { 0x09003016, 0x58000000 }, + { 0x09003017, 0x48000000 }, + { 0x09003018, 0x58000000 }, + { 0x09003019, 0x48000000 }, + { 0x0900301a, 0x58000000 }, + { 0x0900301b, 0x48000000 }, + { 0x0900301c, 0x44000000 }, + { 0x0900301d, 0x58000000 }, + { 0x0980301e, 0x48000001 }, + { 0x09003020, 0x68000000 }, + { 0x16803021, 0x38000008 }, + { 0x1b80302a, 0x30000005 }, + { 0x09003030, 0x44000000 }, + { 0x09803031, 0x18000004 }, + { 0x09803036, 0x68000001 }, + { 0x16803038, 0x38000002 }, + { 0x1600303b, 0x18000000 }, + { 0x0900303c, 0x1c000000 }, + { 0x0900303d, 0x54000000 }, + { 0x0980303e, 0x68000001 }, + { 0x1a803041, 0x1c000055 }, + { 0x1b803099, 0x30000001 }, + { 0x0980309b, 0x60000001 }, + { 0x1a80309d, 0x18000001 }, + { 0x1a00309f, 0x1c000000 }, + { 0x090030a0, 0x44000000 }, + { 0x1d8030a1, 0x1c000059 }, + { 0x090030fb, 0x54000000 }, + { 0x098030fc, 0x18000002 }, + { 0x1d0030ff, 0x1c000000 }, + { 0x03803105, 0x1c000027 }, + { 0x17803131, 0x1c00005d }, + { 0x09803190, 0x68000001 }, + { 0x09803192, 0x3c000003 }, + { 0x09803196, 0x68000009 }, + { 0x038031a0, 0x1c000017 }, + { 0x098031c0, 0x6800000f }, + { 0x1d8031f0, 0x1c00000f }, + { 0x17803200, 0x6800001e }, + { 0x09803220, 0x3c000009 }, + { 0x0980322a, 0x68000019 }, + { 0x09003250, 0x68000000 }, + { 0x09803251, 0x3c00000e }, + { 0x17803260, 0x6800001f }, + { 0x09803280, 0x3c000009 }, + { 0x0980328a, 0x68000026 }, + { 0x098032b1, 0x3c00000e }, + { 0x098032c0, 0x6800003e }, + { 0x09803300, 0x680000ff }, + { 0x16803400, 0x1c0019b5 }, + { 0x09804dc0, 0x6800003f }, + { 0x16804e00, 0x1c0051bb }, + { 0x3c80a000, 0x1c000014 }, + { 0x3c00a015, 0x18000000 }, + { 0x3c80a016, 0x1c000476 }, + { 0x3c80a490, 0x68000036 }, + { 0x0980a700, 0x60000016 }, + { 0x3080a800, 0x1c000001 }, + { 0x3000a802, 0x28000000 }, + { 0x3080a803, 0x1c000002 }, + { 0x3000a806, 0x30000000 }, + { 0x3080a807, 0x1c000003 }, + { 0x3000a80b, 0x30000000 }, + { 0x3080a80c, 0x1c000016 }, + { 0x3080a823, 0x28000001 }, + { 0x3080a825, 0x30000001 }, + { 0x3000a827, 0x28000000 }, + { 0x3080a828, 0x68000003 }, + { 0x1780ac00, 0x1c002ba3 }, + { 0x0980d800, 0x1000037f }, + { 0x0980db80, 0x1000007f }, + { 0x0980dc00, 0x100003ff }, + { 0x0980e000, 0x0c0018ff }, + { 0x1680f900, 0x1c00012d }, + { 0x1680fa30, 0x1c00003a }, + { 0x1680fa70, 0x1c000069 }, + { 0x2180fb00, 0x14000006 }, + { 0x0180fb13, 0x14000004 }, + { 0x1900fb1d, 0x1c000000 }, + { 0x1900fb1e, 0x30000000 }, + { 0x1980fb1f, 0x1c000009 }, + { 0x1900fb29, 0x64000000 }, + { 0x1980fb2a, 0x1c00000c }, + { 0x1980fb38, 0x1c000004 }, + { 0x1900fb3e, 0x1c000000 }, + { 0x1980fb40, 0x1c000001 }, + { 0x1980fb43, 0x1c000001 }, + { 0x1980fb46, 0x1c00006b }, + { 0x0080fbd3, 0x1c00016a }, + { 0x0900fd3e, 0x58000000 }, + { 0x0900fd3f, 0x48000000 }, + { 0x0080fd50, 0x1c00003f }, + { 0x0080fd92, 0x1c000035 }, + { 0x0080fdf0, 0x1c00000b }, + { 0x0000fdfc, 0x5c000000 }, + { 0x0900fdfd, 0x68000000 }, + { 0x1b80fe00, 0x3000000f }, + { 0x0980fe10, 0x54000006 }, + { 0x0900fe17, 0x58000000 }, + { 0x0900fe18, 0x48000000 }, + { 0x0900fe19, 0x54000000 }, + { 0x1b80fe20, 0x30000003 }, + { 0x0900fe30, 0x54000000 }, + { 0x0980fe31, 0x44000001 }, + { 0x0980fe33, 0x40000001 }, + { 0x0900fe35, 0x58000000 }, + { 0x0900fe36, 0x48000000 }, + { 0x0900fe37, 0x58000000 }, + { 0x0900fe38, 0x48000000 }, + { 0x0900fe39, 0x58000000 }, + { 0x0900fe3a, 0x48000000 }, + { 0x0900fe3b, 0x58000000 }, + { 0x0900fe3c, 0x48000000 }, + { 0x0900fe3d, 0x58000000 }, + { 0x0900fe3e, 0x48000000 }, + { 0x0900fe3f, 0x58000000 }, + { 0x0900fe40, 0x48000000 }, + { 0x0900fe41, 0x58000000 }, + { 0x0900fe42, 0x48000000 }, + { 0x0900fe43, 0x58000000 }, + { 0x0900fe44, 0x48000000 }, + { 0x0980fe45, 0x54000001 }, + { 0x0900fe47, 0x58000000 }, + { 0x0900fe48, 0x48000000 }, + { 0x0980fe49, 0x54000003 }, + { 0x0980fe4d, 0x40000002 }, + { 0x0980fe50, 0x54000002 }, + { 0x0980fe54, 0x54000003 }, + { 0x0900fe58, 0x44000000 }, + { 0x0900fe59, 0x58000000 }, + { 0x0900fe5a, 0x48000000 }, + { 0x0900fe5b, 0x58000000 }, + { 0x0900fe5c, 0x48000000 }, + { 0x0900fe5d, 0x58000000 }, + { 0x0900fe5e, 0x48000000 }, + { 0x0980fe5f, 0x54000002 }, + { 0x0900fe62, 0x64000000 }, + { 0x0900fe63, 0x44000000 }, + { 0x0980fe64, 0x64000002 }, + { 0x0900fe68, 0x54000000 }, + { 0x0900fe69, 0x5c000000 }, + { 0x0980fe6a, 0x54000001 }, + { 0x0080fe70, 0x1c000004 }, + { 0x0080fe76, 0x1c000086 }, + { 0x0900feff, 0x04000000 }, + { 0x0980ff01, 0x54000002 }, + { 0x0900ff04, 0x5c000000 }, + { 0x0980ff05, 0x54000002 }, + { 0x0900ff08, 0x58000000 }, + { 0x0900ff09, 0x48000000 }, + { 0x0900ff0a, 0x54000000 }, + { 0x0900ff0b, 0x64000000 }, + { 0x0900ff0c, 0x54000000 }, + { 0x0900ff0d, 0x44000000 }, + { 0x0980ff0e, 0x54000001 }, + { 0x0980ff10, 0x34000009 }, + { 0x0980ff1a, 0x54000001 }, + { 0x0980ff1c, 0x64000002 }, + { 0x0980ff1f, 0x54000001 }, + { 0x2100ff21, 0x24000020 }, + { 0x2100ff22, 0x24000020 }, + { 0x2100ff23, 0x24000020 }, + { 0x2100ff24, 0x24000020 }, + { 0x2100ff25, 0x24000020 }, + { 0x2100ff26, 0x24000020 }, + { 0x2100ff27, 0x24000020 }, + { 0x2100ff28, 0x24000020 }, + { 0x2100ff29, 0x24000020 }, + { 0x2100ff2a, 0x24000020 }, + { 0x2100ff2b, 0x24000020 }, + { 0x2100ff2c, 0x24000020 }, + { 0x2100ff2d, 0x24000020 }, + { 0x2100ff2e, 0x24000020 }, + { 0x2100ff2f, 0x24000020 }, + { 0x2100ff30, 0x24000020 }, + { 0x2100ff31, 0x24000020 }, + { 0x2100ff32, 0x24000020 }, + { 0x2100ff33, 0x24000020 }, + { 0x2100ff34, 0x24000020 }, + { 0x2100ff35, 0x24000020 }, + { 0x2100ff36, 0x24000020 }, + { 0x2100ff37, 0x24000020 }, + { 0x2100ff38, 0x24000020 }, + { 0x2100ff39, 0x24000020 }, + { 0x2100ff3a, 0x24000020 }, + { 0x0900ff3b, 0x58000000 }, + { 0x0900ff3c, 0x54000000 }, + { 0x0900ff3d, 0x48000000 }, + { 0x0900ff3e, 0x60000000 }, + { 0x0900ff3f, 0x40000000 }, + { 0x0900ff40, 0x60000000 }, + { 0x2100ff41, 0x1400ffe0 }, + { 0x2100ff42, 0x1400ffe0 }, + { 0x2100ff43, 0x1400ffe0 }, + { 0x2100ff44, 0x1400ffe0 }, + { 0x2100ff45, 0x1400ffe0 }, + { 0x2100ff46, 0x1400ffe0 }, + { 0x2100ff47, 0x1400ffe0 }, + { 0x2100ff48, 0x1400ffe0 }, + { 0x2100ff49, 0x1400ffe0 }, + { 0x2100ff4a, 0x1400ffe0 }, + { 0x2100ff4b, 0x1400ffe0 }, + { 0x2100ff4c, 0x1400ffe0 }, + { 0x2100ff4d, 0x1400ffe0 }, + { 0x2100ff4e, 0x1400ffe0 }, + { 0x2100ff4f, 0x1400ffe0 }, + { 0x2100ff50, 0x1400ffe0 }, + { 0x2100ff51, 0x1400ffe0 }, + { 0x2100ff52, 0x1400ffe0 }, + { 0x2100ff53, 0x1400ffe0 }, + { 0x2100ff54, 0x1400ffe0 }, + { 0x2100ff55, 0x1400ffe0 }, + { 0x2100ff56, 0x1400ffe0 }, + { 0x2100ff57, 0x1400ffe0 }, + { 0x2100ff58, 0x1400ffe0 }, + { 0x2100ff59, 0x1400ffe0 }, + { 0x2100ff5a, 0x1400ffe0 }, + { 0x0900ff5b, 0x58000000 }, + { 0x0900ff5c, 0x64000000 }, + { 0x0900ff5d, 0x48000000 }, + { 0x0900ff5e, 0x64000000 }, + { 0x0900ff5f, 0x58000000 }, + { 0x0900ff60, 0x48000000 }, + { 0x0900ff61, 0x54000000 }, + { 0x0900ff62, 0x58000000 }, + { 0x0900ff63, 0x48000000 }, + { 0x0980ff64, 0x54000001 }, + { 0x1d80ff66, 0x1c000009 }, + { 0x0900ff70, 0x18000000 }, + { 0x1d80ff71, 0x1c00002c }, + { 0x0980ff9e, 0x18000001 }, + { 0x1780ffa0, 0x1c00001e }, + { 0x1780ffc2, 0x1c000005 }, + { 0x1780ffca, 0x1c000005 }, + { 0x1780ffd2, 0x1c000005 }, + { 0x1780ffda, 0x1c000002 }, + { 0x0980ffe0, 0x5c000001 }, + { 0x0900ffe2, 0x64000000 }, + { 0x0900ffe3, 0x60000000 }, + { 0x0900ffe4, 0x68000000 }, + { 0x0980ffe5, 0x5c000001 }, + { 0x0900ffe8, 0x68000000 }, + { 0x0980ffe9, 0x64000003 }, + { 0x0980ffed, 0x68000001 }, + { 0x0980fff9, 0x04000002 }, + { 0x0980fffc, 0x68000001 }, + { 0x23810000, 0x1c00000b }, + { 0x2381000d, 0x1c000019 }, + { 0x23810028, 0x1c000012 }, + { 0x2381003c, 0x1c000001 }, + { 0x2381003f, 0x1c00000e }, + { 0x23810050, 0x1c00000d }, + { 0x23810080, 0x1c00007a }, + { 0x09810100, 0x54000001 }, + { 0x09010102, 0x68000000 }, + { 0x09810107, 0x3c00002c }, + { 0x09810137, 0x68000008 }, + { 0x13810140, 0x38000034 }, + { 0x13810175, 0x3c000003 }, + { 0x13810179, 0x68000010 }, + { 0x1301018a, 0x3c000000 }, + { 0x29810300, 0x1c00001e }, + { 0x29810320, 0x3c000003 }, + { 0x12810330, 0x1c000019 }, + { 0x1201034a, 0x38000000 }, + { 0x3b810380, 0x1c00001d }, + { 0x3b01039f, 0x54000000 }, + { 0x2a8103a0, 0x1c000023 }, + { 0x2a8103c8, 0x1c000007 }, + { 0x2a0103d0, 0x68000000 }, + { 0x2a8103d1, 0x38000004 }, + { 0x0d010400, 0x24000028 }, + { 0x0d010401, 0x24000028 }, + { 0x0d010402, 0x24000028 }, + { 0x0d010403, 0x24000028 }, + { 0x0d010404, 0x24000028 }, + { 0x0d010405, 0x24000028 }, + { 0x0d010406, 0x24000028 }, + { 0x0d010407, 0x24000028 }, + { 0x0d010408, 0x24000028 }, + { 0x0d010409, 0x24000028 }, + { 0x0d01040a, 0x24000028 }, + { 0x0d01040b, 0x24000028 }, + { 0x0d01040c, 0x24000028 }, + { 0x0d01040d, 0x24000028 }, + { 0x0d01040e, 0x24000028 }, + { 0x0d01040f, 0x24000028 }, + { 0x0d010410, 0x24000028 }, + { 0x0d010411, 0x24000028 }, + { 0x0d010412, 0x24000028 }, + { 0x0d010413, 0x24000028 }, + { 0x0d010414, 0x24000028 }, + { 0x0d010415, 0x24000028 }, + { 0x0d010416, 0x24000028 }, + { 0x0d010417, 0x24000028 }, + { 0x0d010418, 0x24000028 }, + { 0x0d010419, 0x24000028 }, + { 0x0d01041a, 0x24000028 }, + { 0x0d01041b, 0x24000028 }, + { 0x0d01041c, 0x24000028 }, + { 0x0d01041d, 0x24000028 }, + { 0x0d01041e, 0x24000028 }, + { 0x0d01041f, 0x24000028 }, + { 0x0d010420, 0x24000028 }, + { 0x0d010421, 0x24000028 }, + { 0x0d010422, 0x24000028 }, + { 0x0d010423, 0x24000028 }, + { 0x0d010424, 0x24000028 }, + { 0x0d010425, 0x24000028 }, + { 0x0d010426, 0x24000028 }, + { 0x0d010427, 0x24000028 }, + { 0x0d010428, 0x1400ffd8 }, + { 0x0d010429, 0x1400ffd8 }, + { 0x0d01042a, 0x1400ffd8 }, + { 0x0d01042b, 0x1400ffd8 }, + { 0x0d01042c, 0x1400ffd8 }, + { 0x0d01042d, 0x1400ffd8 }, + { 0x0d01042e, 0x1400ffd8 }, + { 0x0d01042f, 0x1400ffd8 }, + { 0x0d010430, 0x1400ffd8 }, + { 0x0d010431, 0x1400ffd8 }, + { 0x0d010432, 0x1400ffd8 }, + { 0x0d010433, 0x1400ffd8 }, + { 0x0d010434, 0x1400ffd8 }, + { 0x0d010435, 0x1400ffd8 }, + { 0x0d010436, 0x1400ffd8 }, + { 0x0d010437, 0x1400ffd8 }, + { 0x0d010438, 0x1400ffd8 }, + { 0x0d010439, 0x1400ffd8 }, + { 0x0d01043a, 0x1400ffd8 }, + { 0x0d01043b, 0x1400ffd8 }, + { 0x0d01043c, 0x1400ffd8 }, + { 0x0d01043d, 0x1400ffd8 }, + { 0x0d01043e, 0x1400ffd8 }, + { 0x0d01043f, 0x1400ffd8 }, + { 0x0d010440, 0x1400ffd8 }, + { 0x0d010441, 0x1400ffd8 }, + { 0x0d010442, 0x1400ffd8 }, + { 0x0d010443, 0x1400ffd8 }, + { 0x0d010444, 0x1400ffd8 }, + { 0x0d010445, 0x1400ffd8 }, + { 0x0d010446, 0x1400ffd8 }, + { 0x0d010447, 0x1400ffd8 }, + { 0x0d010448, 0x1400ffd8 }, + { 0x0d010449, 0x1400ffd8 }, + { 0x0d01044a, 0x1400ffd8 }, + { 0x0d01044b, 0x1400ffd8 }, + { 0x0d01044c, 0x1400ffd8 }, + { 0x0d01044d, 0x1400ffd8 }, + { 0x0d01044e, 0x1400ffd8 }, + { 0x0d01044f, 0x1400ffd8 }, + { 0x2e810450, 0x1c00004d }, + { 0x2c8104a0, 0x34000009 }, + { 0x0b810800, 0x1c000005 }, + { 0x0b010808, 0x1c000000 }, + { 0x0b81080a, 0x1c00002b }, + { 0x0b810837, 0x1c000001 }, + { 0x0b01083c, 0x1c000000 }, + { 0x0b01083f, 0x1c000000 }, + { 0x1e010a00, 0x1c000000 }, + { 0x1e810a01, 0x30000002 }, + { 0x1e810a05, 0x30000001 }, + { 0x1e810a0c, 0x30000003 }, + { 0x1e810a10, 0x1c000003 }, + { 0x1e810a15, 0x1c000002 }, + { 0x1e810a19, 0x1c00001a }, + { 0x1e810a38, 0x30000002 }, + { 0x1e010a3f, 0x30000000 }, + { 0x1e810a40, 0x3c000007 }, + { 0x1e810a50, 0x54000008 }, + { 0x0981d000, 0x680000f5 }, + { 0x0981d100, 0x68000026 }, + { 0x0981d12a, 0x6800003a }, + { 0x0981d165, 0x28000001 }, + { 0x1b81d167, 0x30000002 }, + { 0x0981d16a, 0x68000002 }, + { 0x0981d16d, 0x28000005 }, + { 0x0981d173, 0x04000007 }, + { 0x1b81d17b, 0x30000007 }, + { 0x0981d183, 0x68000001 }, + { 0x1b81d185, 0x30000006 }, + { 0x0981d18c, 0x6800001d }, + { 0x1b81d1aa, 0x30000003 }, + { 0x0981d1ae, 0x6800002f }, + { 0x1381d200, 0x68000041 }, + { 0x1381d242, 0x30000002 }, + { 0x1301d245, 0x68000000 }, + { 0x0981d300, 0x68000056 }, + { 0x0981d400, 0x24000019 }, + { 0x0981d41a, 0x14000019 }, + { 0x0981d434, 0x24000019 }, + { 0x0981d44e, 0x14000006 }, + { 0x0981d456, 0x14000011 }, + { 0x0981d468, 0x24000019 }, + { 0x0981d482, 0x14000019 }, + { 0x0901d49c, 0x24000000 }, + { 0x0981d49e, 0x24000001 }, + { 0x0901d4a2, 0x24000000 }, + { 0x0981d4a5, 0x24000001 }, + { 0x0981d4a9, 0x24000003 }, + { 0x0981d4ae, 0x24000007 }, + { 0x0981d4b6, 0x14000003 }, + { 0x0901d4bb, 0x14000000 }, + { 0x0981d4bd, 0x14000006 }, + { 0x0981d4c5, 0x1400000a }, + { 0x0981d4d0, 0x24000019 }, + { 0x0981d4ea, 0x14000019 }, + { 0x0981d504, 0x24000001 }, + { 0x0981d507, 0x24000003 }, + { 0x0981d50d, 0x24000007 }, + { 0x0981d516, 0x24000006 }, + { 0x0981d51e, 0x14000019 }, + { 0x0981d538, 0x24000001 }, + { 0x0981d53b, 0x24000003 }, + { 0x0981d540, 0x24000004 }, + { 0x0901d546, 0x24000000 }, + { 0x0981d54a, 0x24000006 }, + { 0x0981d552, 0x14000019 }, + { 0x0981d56c, 0x24000019 }, + { 0x0981d586, 0x14000019 }, + { 0x0981d5a0, 0x24000019 }, + { 0x0981d5ba, 0x14000019 }, + { 0x0981d5d4, 0x24000019 }, + { 0x0981d5ee, 0x14000019 }, + { 0x0981d608, 0x24000019 }, + { 0x0981d622, 0x14000019 }, + { 0x0981d63c, 0x24000019 }, + { 0x0981d656, 0x14000019 }, + { 0x0981d670, 0x24000019 }, + { 0x0981d68a, 0x1400001b }, + { 0x0981d6a8, 0x24000018 }, + { 0x0901d6c1, 0x64000000 }, + { 0x0981d6c2, 0x14000018 }, + { 0x0901d6db, 0x64000000 }, + { 0x0981d6dc, 0x14000005 }, + { 0x0981d6e2, 0x24000018 }, + { 0x0901d6fb, 0x64000000 }, + { 0x0981d6fc, 0x14000018 }, + { 0x0901d715, 0x64000000 }, + { 0x0981d716, 0x14000005 }, + { 0x0981d71c, 0x24000018 }, + { 0x0901d735, 0x64000000 }, + { 0x0981d736, 0x14000018 }, + { 0x0901d74f, 0x64000000 }, + { 0x0981d750, 0x14000005 }, + { 0x0981d756, 0x24000018 }, + { 0x0901d76f, 0x64000000 }, + { 0x0981d770, 0x14000018 }, + { 0x0901d789, 0x64000000 }, + { 0x0981d78a, 0x14000005 }, + { 0x0981d790, 0x24000018 }, + { 0x0901d7a9, 0x64000000 }, + { 0x0981d7aa, 0x14000018 }, + { 0x0901d7c3, 0x64000000 }, + { 0x0981d7c4, 0x14000005 }, + { 0x0981d7ce, 0x34000031 }, + { 0x16820000, 0x1c00a6d6 }, + { 0x1682f800, 0x1c00021d }, + { 0x090e0001, 0x04000000 }, + { 0x098e0020, 0x0400005f }, + { 0x1b8e0100, 0x300000ef }, + { 0x098f0000, 0x0c00fffd }, + { 0x09900000, 0x0c00fffd }, +}; diff --git a/js/src/yarr/ASCIICType.h b/js/src/yarr/wtf/ASCIICType.h similarity index 81% rename from js/src/yarr/ASCIICType.h rename to js/src/yarr/wtf/ASCIICType.h index a3ae9f4455e2..cf53d9ac0c87 100644 --- a/js/src/yarr/ASCIICType.h +++ b/js/src/yarr/wtf/ASCIICType.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) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +24,12 @@ * 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. - * - * ***** END LICENSE BLOCK ***** */ + */ #ifndef WTF_ASCIICType_h #define WTF_ASCIICType_h -#include "assembler/wtf/Assertions.h" +#include "yarr/jswtfbridge.h" // The behavior of many of the functions in the header is dependent // on the current locale. But in the WebKit project, all uses of those functions @@ -53,7 +49,6 @@ namespace WTF { inline bool isASCII(wchar_t c) { return !(c & ~0x7F); } #endif inline bool isASCII(int c) { return !(c & ~0x7F); } - inline bool isASCII(unsigned c) { return !(c & ~0x7F); } inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } @@ -61,7 +56,6 @@ namespace WTF { inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } #endif inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } - inline bool isASCIIAlpha(unsigned c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } @@ -69,7 +63,6 @@ namespace WTF { inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } #endif inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } - inline bool isASCIIAlphanumeric(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); } inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); } @@ -77,7 +70,6 @@ namespace WTF { inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); } #endif inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); } - inline bool isASCIIDigit(unsigned c) { return (c >= '0') & (c <= '9'); } inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } @@ -85,7 +77,6 @@ namespace WTF { inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } #endif inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } - inline bool isASCIIHexDigit(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); } inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); } @@ -93,7 +84,6 @@ namespace WTF { inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); } #endif inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); } - inline bool isASCIIOctalDigit(unsigned c) { return (c >= '0') & (c <= '7'); } inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; } inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; } @@ -101,7 +91,6 @@ namespace WTF { inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; } #endif inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; } - inline bool isASCIILower(unsigned c) { return c >= 'a' && c <= 'z'; } inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; } inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; } @@ -109,7 +98,6 @@ namespace WTF { inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; } #endif inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; } - inline bool isASCIIUpper(unsigned c) { return c >= 'A' && c <= 'Z'; } /* Statistics from a run of Apple's page load test for callers of isASCIISpace: @@ -130,7 +118,6 @@ namespace WTF { inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } #endif inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } - inline bool isASCIISpace(unsigned c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); } inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); } @@ -138,24 +125,20 @@ namespace WTF { inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); } #endif inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - inline unsigned toASCIILower(unsigned c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - // FIXME: Why do these need static_cast? inline char toASCIIUpper(char c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } inline unsigned short toASCIIUpper(unsigned short c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) inline wchar_t toASCIIUpper(wchar_t c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } #endif inline int toASCIIUpper(int c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline unsigned toASCIIUpper(unsigned c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(char c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(unsigned short c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(wchar_t c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } #endif - inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(int c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; } inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; } @@ -163,7 +146,7 @@ namespace WTF { inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; } #endif inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; } - inline bool isASCIIPrintable(unsigned c) { return c >= ' ' && c <= '~'; } + } using WTF::isASCII; diff --git a/js/src/yarr/wtfbridge.h b/js/src/yarr/wtfbridge.h deleted file mode 100644 index 25a4bc5ee3d9..000000000000 --- a/js/src/yarr/wtfbridge.h +++ /dev/null @@ -1,321 +0,0 @@ -/* -*- 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 ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released - * June 12, 2009. - * - * The Initial Developer of the Original Code is - * the Mozilla Corporation. - * - * Contributor(s): - * David Mandelin - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jswtfbridge_h__ -#define jswtfbridge_h__ - -/* - * WTF compatibility layer. This file provides various type and data - * definitions for use by Yarr. - */ - -#include "jsstr.h" -#include "jsprvtd.h" -#include "jstl.h" -#include "assembler/wtf/Platform.h" -#include "assembler/jit/ExecutableAllocator.h" - -namespace JSC { namespace Yarr { - -/* - * Basic type definitions. - */ - -typedef jschar UChar; -typedef JSLinearString UString; - -class Unicode { - public: - static UChar toUpper(UChar c) { return JS_TOUPPER(c); } - static UChar toLower(UChar c) { return JS_TOLOWER(c); } -}; - -/* - * Do-nothing smart pointer classes. These have a compatible interface - * with the smart pointers used by Yarr, but they don't actually do - * reference counting. - */ -template -class RefCounted { -}; - -template -class RefPtr { - T *ptr; - public: - RefPtr(T *p) { ptr = p; } - operator bool() const { return ptr != NULL; } - const T *operator ->() const { return ptr; } - T *get() { return ptr; } -}; - -template -class PassRefPtr { - T *ptr; - public: - PassRefPtr(T *p) { ptr = p; } - operator T*() { return ptr; } -}; - -template -class PassOwnPtr { - T *ptr; - public: - PassOwnPtr(T *p) { ptr = p; } - - T *get() { return ptr; } -}; - -template -class OwnPtr { - T *ptr; - public: - OwnPtr() : ptr(NULL) { } - OwnPtr(PassOwnPtr p) : ptr(p.get()) { } - - ~OwnPtr() { - if (ptr) - js::Foreground::delete_(ptr); - } - - OwnPtr &operator=(PassOwnPtr p) { - ptr = p.get(); - return *this; - } - - T *operator ->() { return ptr; } - - T *get() { return ptr; } - - T *release() { - T *result = ptr; - ptr = NULL; - return result; - } -}; - -template -PassRefPtr adoptRef(T *p) { return PassRefPtr(p); } - -template -PassOwnPtr adoptPtr(T *p) { return PassOwnPtr(p); } - -#define WTF_MAKE_FAST_ALLOCATED - -/* - * Vector class for Yarr. This wraps js::Vector and provides all - * the API method signatures used by Yarr. - */ -template -class Vector { - public: - js::Vector impl; - public: - Vector() {} - - Vector(const Vector &v) { - // XXX yarr-oom - (void) append(v); - } - - size_t size() const { - return impl.length(); - } - - T &operator[](size_t i) { - return impl[i]; - } - - const T &operator[](size_t i) const { - return impl[i]; - } - - T &at(size_t i) { - return impl[i]; - } - - const T *begin() const { - return impl.begin(); - } - - T &last() { - return impl.back(); - } - - bool isEmpty() const { - return impl.empty(); - } - - template - void append(const U &u) { - // XXX yarr-oom - (void) impl.append(static_cast(u)); - } - - template - void append(const Vector &v) { - // XXX yarr-oom - (void) impl.append(v.impl); - } - - void insert(size_t i, const T& t) { - // XXX yarr-oom - (void) impl.insert(&impl[i], t); - } - - void remove(size_t i) { - impl.erase(&impl[i]); - } - - void clear() { - return impl.clear(); - } - - void shrink(size_t newLength) { - // XXX yarr-oom - JS_ASSERT(newLength <= impl.length()); - (void) impl.resize(newLength); - } - - void deleteAllValues() { - for (T *p = impl.begin(); p != impl.end(); ++p) - js::Foreground::delete_(*p); - } -}; - -template -class Vector > { - public: - js::Vector impl; - public: - Vector() {} - - size_t size() const { - return impl.length(); - } - - void append(T *t) { - // XXX yarr-oom - (void) impl.append(t); - } - - PassOwnPtr operator[](size_t i) { - return PassOwnPtr(impl[i]); - } - - void clear() { - for (T **p = impl.begin(); p != impl.end(); ++p) - js::Foreground::delete_(*p); - return impl.clear(); - } -}; - -template -inline void -deleteAllValues(Vector &v) { - v.deleteAllValues(); -} - -/* - * Minimal JSGlobalData. This used by Yarr to get the allocator. - */ -class JSGlobalData { - public: - ExecutableAllocator *regexAllocator; - - JSGlobalData(ExecutableAllocator *regexAllocator) - : regexAllocator(regexAllocator) { } -}; - -/* - * Sentinel value used in Yarr. - */ -const size_t notFound = size_t(-1); - - /* - * Do-nothing version of a macro used by WTF to avoid unused - * parameter warnings. - */ -#define UNUSED_PARAM(e) - -} /* namespace Yarr */ - -/* - * Replacements for std:: functions used in Yarr. We put them in - * namespace JSC::std so that they can still be called as std::X - * in Yarr. - */ -namespace std { - -/* - * windows.h defines a 'min' macro that would mangle the function - * name. - */ -#if WTF_COMPILER_MSVC -# undef min -# undef max -#endif - -template -inline T -min(T t1, T t2) -{ - return JS_MIN(t1, t2); -} - -template -inline T -max(T t1, T t2) -{ - return JS_MAX(t1, t2); -} - -template -inline void -swap(T &t1, T &t2) -{ - T tmp = t1; - t1 = t2; - t2 = tmp; -} -} /* namespace std */ - -} /* namespace JSC */ - -#endif diff --git a/js/src/yarr/RegExpJitTables.h b/js/src/yarr/yarr/RegExpJitTables.h similarity index 100% rename from js/src/yarr/RegExpJitTables.h rename to js/src/yarr/yarr/RegExpJitTables.h diff --git a/js/src/yarr/YarrSyntaxChecker.cpp b/js/src/yarr/yarr/RegexCommon.h similarity index 52% rename from js/src/yarr/YarrSyntaxChecker.cpp rename to js/src/yarr/yarr/RegexCommon.h index f36ac5a3f5bc..3ae337ea62cc 100644 --- a/js/src/yarr/YarrSyntaxChecker.cpp +++ b/js/src/yarr/yarr/RegexCommon.h @@ -1,8 +1,5 @@ -/* -*- 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) 2011 Apple Inc. All rights reserved. +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,39 +21,30 @@ * 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 ***** */ + */ -#include "YarrSyntaxChecker.h" - -#include "YarrParser.h" +#ifndef RegexCommon_h +#define RegexCommon_h namespace JSC { namespace Yarr { -class SyntaxChecker { -public: - void assertionBOL() {} - void assertionEOL() {} - void assertionWordBoundary(bool) {} - void atomPatternCharacter(UChar) {} - void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) {} - void atomCharacterClassBegin(bool = false) {} - void atomCharacterClassAtom(UChar) {} - void atomCharacterClassRange(UChar, UChar) {} - void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) {} - void atomCharacterClassEnd() {} - void atomParenthesesSubpatternBegin(bool = true) {} - void atomParentheticalAssertionBegin(bool = false) {} - void atomParenthesesEnd() {} - void atomBackReference(unsigned) {} - void quantifyAtom(unsigned, unsigned, bool) {} - void disjunction() {} +enum ErrorCode { + HitRecursionLimit = -2, + NoError = 0, + PatternTooLarge, + QuantifierOutOfOrder, + QuantifierWithoutAtom, + MissingParentheses, + ParenthesesUnmatched, + ParenthesesTypeInvalid, + CharacterClassUnmatched, + CharacterClassOutOfOrder, + CharacterClassRangeSingleChar, + EscapeUnterminated, + QuantifierTooLarge, + NumberOfErrorCodes }; -ErrorCode checkSyntax(const UString& pattern) -{ - SyntaxChecker syntaxChecker; - return parse(syntaxChecker, pattern); -} +}} -}} // JSC::YARR +#endif diff --git a/js/src/yarr/YarrPattern.cpp b/js/src/yarr/yarr/RegexCompiler.cpp similarity index 52% rename from js/src/yarr/YarrPattern.cpp rename to js/src/yarr/yarr/RegexCompiler.cpp index 10b7d8911987..9b60cbd4a78b 100644 --- a/js/src/yarr/YarrPattern.cpp +++ b/js/src/yarr/yarr/RegexCompiler.cpp @@ -1,9 +1,5 @@ -/* -*- 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 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,13 +21,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 ***** */ + */ -#include "YarrPattern.h" +#include "jsinttypes.h" +#include "RegexCompiler.h" -#include "Yarr.h" -#include "YarrParser.h" +#include "RegexPattern.h" using namespace WTF; @@ -39,6 +34,12 @@ namespace JSC { namespace Yarr { #include "RegExpJitTables.h" +#if WTF_CPU_SPARC +#define BASE_FRAME_SIZE 24 +#else +#define BASE_FRAME_SIZE 0 +#endif + class CharacterClassConstructor { public: CharacterClassConstructor(bool isCaseInsensitive = false) @@ -56,13 +57,13 @@ public: void append(const CharacterClass* other) { - for (size_t i = 0; i < other->m_matches.size(); ++i) + for (size_t i = 0; i < other->m_matches.length(); ++i) addSorted(m_matches, other->m_matches[i]); - for (size_t i = 0; i < other->m_ranges.size(); ++i) + for (size_t i = 0; i < other->m_ranges.length(); ++i) addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end); - for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i) + for (size_t i = 0; i < other->m_matchesUnicode.length(); ++i) addSorted(m_matchesUnicode, other->m_matchesUnicode[i]); - for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i) + for (size_t i = 0; i < other->m_rangesUnicode.length(); ++i) addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end); } @@ -100,18 +101,18 @@ public: { if (lo <= 0x7f) { char asciiLo = lo; - char asciiHi = std::min(hi, (UChar)0x7f); + char asciiHi = JS_MIN(hi, (UChar)0x7f); addSortedRange(m_ranges, lo, asciiHi); if (m_isCaseInsensitive) { if ((asciiLo <= 'Z') && (asciiHi >= 'A')) - addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A')); + addSortedRange(m_ranges, JS_MAX(asciiLo, 'A')+('a'-'A'), JS_MIN(asciiHi, 'Z')+('a'-'A')); if ((asciiLo <= 'z') && (asciiHi >= 'a')) - addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a')); + addSortedRange(m_ranges, JS_MAX(asciiLo, 'a')+('A'-'a'), JS_MIN(asciiHi, 'z')+('A'-'a')); } } if (hi >= 0x80) { - uint32_t unicodeCurr = std::max(lo, (UChar)0x80); + uint32 unicodeCurr = JS_MAX(lo, (UChar)0x80); addSortedRange(m_rangesUnicode, unicodeCurr, hi); if (m_isCaseInsensitive) { @@ -121,7 +122,7 @@ public: // (if so we won't re-enter the loop, since the loop condition above // will definitely fail) - but this does mean we cannot use a UChar // to represent unicodeCurr, we must use a 32-bit value instead. - ASSERT(unicodeCurr <= 0xffff); + JS_ASSERT(unicodeCurr <= 0xffff); if (isUnicodeUpper(unicodeCurr)) { UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr); @@ -144,7 +145,8 @@ public: CharacterClass* charClass() { - CharacterClass* characterClass = js::OffTheBooks::new_(PassRefPtr(0)); + // FIXME: bug 574459 -- no NULL check + CharacterClass* characterClass = js::OffTheBooks::new_((CharacterClassTable*)NULL); characterClass->m_matches.append(m_matches); characterClass->m_ranges.append(m_ranges); @@ -157,10 +159,12 @@ public: } private: - void addSorted(Vector& matches, UChar ch) + typedef js::Vector UChars; + typedef js::Vector CharacterRanges; + void addSorted(UChars& matches, UChar ch) { unsigned pos = 0; - unsigned range = matches.size(); + unsigned range = matches.length(); // binary chop, find position to insert char. while (range) { @@ -177,15 +181,15 @@ private: } } - if (pos == matches.size()) + if (pos == matches.length()) matches.append(ch); else - matches.insert(pos, ch); + matches.insert(matches.begin() + pos, ch); } - void addSortedRange(Vector& ranges, UChar lo, UChar hi) + void addSortedRange(CharacterRanges& ranges, UChar lo, UChar hi) { - unsigned end = ranges.size(); + unsigned end = ranges.length(); // Simple linear scan - I doubt there are that many ranges anyway... // feel free to fix this with something faster (eg binary chop). @@ -197,7 +201,7 @@ private: ranges[i].begin = lo; return; } - ranges.insert(i, CharacterRange(lo, hi)); + ranges.insert(ranges.begin() + i, CharacterRange(lo, hi)); return; } // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining @@ -205,17 +209,17 @@ private: // end of the last range they concatenate, which is just as good. if (lo <= (ranges[i].end + 1)) { // found an intersect! we'll replace this entry in the array. - ranges[i].begin = std::min(ranges[i].begin, lo); - ranges[i].end = std::max(ranges[i].end, hi); + ranges[i].begin = JS_MIN(ranges[i].begin, lo); + ranges[i].end = JS_MAX(ranges[i].end, hi); // now check if the new range can subsume any subsequent ranges. unsigned next = i+1; // each iteration of the loop we will either remove something from the list, or break the loop. - while (next < ranges.size()) { + while (next < ranges.length()) { if (ranges[next].begin <= (ranges[i].end + 1)) { // the next entry now overlaps / concatenates this one. - ranges[i].end = std::max(ranges[i].end, ranges[next].end); - ranges.remove(next); + ranges[i].end = JS_MAX(ranges[i].end, ranges[next].end); + ranges.erase(ranges.begin() + next); } else break; } @@ -230,131 +234,21 @@ private: bool m_isCaseInsensitive; - Vector m_matches; - Vector m_ranges; - Vector m_matchesUnicode; - Vector m_rangesUnicode; + UChars m_matches; + CharacterRanges m_ranges; + UChars m_matchesUnicode; + CharacterRanges m_rangesUnicode; }; -struct BeginCharHelper { - BeginCharHelper(Vector* beginChars, bool isCaseInsensitive = false) - : m_beginChars(beginChars) - , m_isCaseInsensitive(isCaseInsensitive) - {} - - void addBeginChar(BeginChar beginChar, Vector* hotTerms, QuantifierType quantityType, unsigned quantityCount) - { - if (quantityType == QuantifierFixedCount && quantityCount > 1) { - // We duplicate the first found character if the quantity of the term is more than one. eg.: /a{3}/ - beginChar.value |= beginChar.value << 16; - beginChar.mask |= beginChar.mask << 16; - addCharacter(beginChar); - } else if (quantityType == QuantifierFixedCount && quantityCount == 1 && hotTerms->size()) - // In case of characters with fixed quantifier we should check the next character as well. - linkHotTerms(beginChar, hotTerms); - else - // In case of greedy matching the next character checking is unnecessary therefore we just store - // the first character. - addCharacter(beginChar); - } - - // Merge two following BeginChars in the vector to reduce the number of character checks. - void merge(unsigned size) - { - for (unsigned i = 0; i < size; i++) { - BeginChar* curr = &m_beginChars->at(i); - BeginChar* next = &m_beginChars->at(i + 1); - - // If the current and the next size of value is different we should skip the merge process - // because the 16bit and 32bit values are unmergable. - if (curr->value <= 0xFFFF && next->value > 0xFFFF) - continue; - - unsigned diff = curr->value ^ next->value; - - curr->mask |= diff; - curr->value |= curr->mask; - - m_beginChars->remove(i + 1); - size--; - } - } - -private: - void addCharacter(BeginChar beginChar) - { - unsigned pos = 0; - unsigned range = m_beginChars->size(); - - // binary chop, find position to insert char. - while (range) { - unsigned index = range >> 1; - - int val = m_beginChars->at(pos+index).value - beginChar.value; - if (!val) - return; - if (val < 0) - range = index; - else { - pos += (index+1); - range -= (index+1); - } - } - - if (pos == m_beginChars->size()) - m_beginChars->append(beginChar); - else - m_beginChars->insert(pos, beginChar); - } - - // Create BeginChar objects by appending each terms from a hotTerms vector to an existing BeginChar object. - void linkHotTerms(BeginChar beginChar, Vector* hotTerms) - { - for (unsigned i = 0; i < hotTerms->size(); i++) { - PatternTerm hotTerm = hotTerms->at(i).term; - ASSERT(hotTerm.type == PatternTerm::TypePatternCharacter); - - UChar characterNext = hotTerm.patternCharacter; - - // Append a character to an existing BeginChar object. - if (characterNext <= 0x7f) { - unsigned mask = 0; - - if (m_isCaseInsensitive && isASCIIAlpha(characterNext)) { - mask = 32; - characterNext = toASCIILower(characterNext); - } - - addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask | (mask << 16))); - } else { - UChar upper, lower; - if (m_isCaseInsensitive && ((upper = Unicode::toUpper(characterNext)) != (lower = Unicode::toLower(characterNext)))) { - addCharacter(BeginChar(beginChar.value | (upper << 16), beginChar.mask)); - addCharacter(BeginChar(beginChar.value | (lower << 16), beginChar.mask)); - } else - addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask)); - } - } - } - - Vector* m_beginChars; - bool m_isCaseInsensitive; -}; - -class YarrPatternConstructor { +class RegexPatternConstructor { public: - YarrPatternConstructor(YarrPattern& pattern) + RegexPatternConstructor(RegexPattern& pattern) : m_pattern(pattern) , m_characterClassConstructor(pattern.m_ignoreCase) - , m_beginCharHelper(&pattern.m_beginChars, pattern.m_ignoreCase) - , m_invertParentheticalAssertion(false) { - m_pattern.m_body = js::OffTheBooks::new_(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); } - ~YarrPatternConstructor() + ~RegexPatternConstructor() { } @@ -362,19 +256,10 @@ public: { m_pattern.reset(); m_characterClassConstructor.reset(); - - m_pattern.m_body = js::OffTheBooks::new_(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); } void assertionBOL() { - if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) { - m_alternative->m_startsWithBOL = true; - m_alternative->m_containsBOL = true; - m_pattern.m_containsBOL = true; - } m_alternative->m_terms.append(PatternTerm::BOL()); } void assertionEOL() @@ -433,7 +318,7 @@ public: void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert) { - ASSERT(classID != NewlineClassID); + JS_ASSERT(classID != NewlineClassID); switch (classID) { case DigitClassID: @@ -449,7 +334,7 @@ public: break; default: - ASSERT_NOT_REACHED(); + JS_NOT_REACHED("Invalid character class."); } } @@ -466,56 +351,36 @@ public: if (capture) m_pattern.m_numSubpatterns++; + // FIXME: bug 574459 -- no NULL check PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative); m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, false)); + m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture)); m_alternative = parenthesesDisjunction->addNewAlternative(); } void atomParentheticalAssertionBegin(bool invert = false) { + // FIXME: bug 574459 -- no NULL check PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative); m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, false, invert)); + m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert)); m_alternative = parenthesesDisjunction->addNewAlternative(); - m_invertParentheticalAssertion = invert; } void atomParenthesesEnd() { - ASSERT(m_alternative->m_parent); - ASSERT(m_alternative->m_parent->m_parent); - - PatternDisjunction* parenthesesDisjunction = m_alternative->m_parent; + JS_ASSERT(m_alternative->m_parent); + JS_ASSERT(m_alternative->m_parent->m_parent); m_alternative = m_alternative->m_parent->m_parent; - - PatternTerm& lastTerm = m_alternative->lastTerm(); - - unsigned numParenAlternatives = parenthesesDisjunction->m_alternatives.size(); - unsigned numBOLAnchoredAlts = 0; - - for (unsigned i = 0; i < numParenAlternatives; i++) { - // Bubble up BOL flags - if (parenthesesDisjunction->m_alternatives[i]->m_startsWithBOL) - numBOLAnchoredAlts++; - } - - if (numBOLAnchoredAlts) { - m_alternative->m_containsBOL = true; - // If all the alternatives in parens start with BOL, then so does this one - if (numBOLAnchoredAlts == numParenAlternatives) - m_alternative->m_startsWithBOL = true; - } - - lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; - m_invertParentheticalAssertion = false; + + m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; } void atomBackReference(unsigned subpatternId) { - ASSERT(subpatternId); + JS_ASSERT(subpatternId); m_pattern.m_containsBackreferences = true; - m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId); + m_pattern.m_maxBackReference = JS_MAX(m_pattern.m_maxBackReference, subpatternId); if (subpatternId > m_pattern.m_numSubpatterns) { m_alternative->m_terms.append(PatternTerm::ForwardReference()); @@ -523,14 +388,14 @@ public: } PatternAlternative* currentAlternative = m_alternative; - ASSERT(currentAlternative); + JS_ASSERT(currentAlternative); // Note to self: if we waited until the AST was baked, we could also remove forwards refs while ((currentAlternative = currentAlternative->m_parent->m_parent)) { PatternTerm& term = currentAlternative->lastTerm(); - ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); + JS_ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); - if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.capture() && (subpatternId == term.parentheses.subpatternId)) { + if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) { m_alternative->m_terms.append(PatternTerm::ForwardReference()); return; } @@ -539,43 +404,37 @@ public: m_alternative->m_terms.append(PatternTerm(subpatternId)); } - // deep copy the argument disjunction. If filterStartsWithBOL is true, - // skip alternatives with m_startsWithBOL set true. - PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false) + PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction) { - PatternDisjunction* newDisjunction = 0; - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + // FIXME: bug 574459 -- no NULL check + PatternDisjunction* newDisjunction = js::OffTheBooks::new_(); + + newDisjunction->m_parent = disjunction->m_parent; + for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) { PatternAlternative* alternative = disjunction->m_alternatives[alt]; - if (!filterStartsWithBOL || !alternative->m_startsWithBOL) { - if (!newDisjunction) { - newDisjunction = new PatternDisjunction(); - newDisjunction->m_parent = disjunction->m_parent; - } - PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) - newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL)); - } + PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); + for (unsigned i = 0; i < alternative->m_terms.length(); ++i) + newAlternative->m_terms.append(copyTerm(alternative->m_terms[i])); } - - if (newDisjunction) - m_pattern.m_disjunctions.append(newDisjunction); + + m_pattern.m_disjunctions.append(newDisjunction); return newDisjunction; } - - PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false) + + PatternTerm copyTerm(PatternTerm& term) { if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion)) return PatternTerm(term); - + PatternTerm termCopy = term; - termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL); + termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction); return termCopy; } - + void quantifyAtom(unsigned min, unsigned max, bool greedy) { - ASSERT(min <= max); - ASSERT(m_alternative->m_terms.size()); + JS_ASSERT(min <= max); + JS_ASSERT(m_alternative->m_terms.length()); if (!max) { m_alternative->removeLastTerm(); @@ -583,8 +442,8 @@ public: } PatternTerm& term = m_alternative->lastTerm(); - ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); - ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); + JS_ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); + JS_ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); // For any assertion with a zero minimum, not matching is valid and has no effect, // remove it. Otherwise, we need to match as least once, but there is no point @@ -605,7 +464,7 @@ public: term.quantify(min, QuantifierFixedCount); m_alternative->m_terms.append(copyTerm(term)); // NOTE: this term is interesting from an analysis perspective, in that it can be ignored..... - m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); + m_alternative->lastTerm().quantify((max == UINT_MAX) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern) m_alternative->lastTerm().parentheses.isCopy = true; } @@ -616,12 +475,26 @@ public: m_alternative = m_alternative->m_parent->addNewAlternative(); } + void regexBegin() + { + // FIXME: bug 574459 -- no NULL check + m_pattern.m_body = js::OffTheBooks::new_(); + m_alternative = m_pattern.m_body->addNewAlternative(); + m_pattern.m_disjunctions.append(m_pattern.m_body); + } + void regexEnd() + { + } + void regexError() + { + } + unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition) { alternative->m_hasFixedSize = true; unsigned currentInputPosition = initialInputPosition; - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { + for (unsigned i = 0; i < alternative->m_terms.length(); ++i) { PatternTerm& term = alternative->m_terms[i]; switch (term.type) { @@ -634,7 +507,7 @@ public: case PatternTerm::TypeBackReference: term.inputPosition = currentInputPosition; term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoBackReference; alternative->m_hasFixedSize = false; break; @@ -645,7 +518,7 @@ public: term.inputPosition = currentInputPosition; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoPatternCharacter; alternative->m_hasFixedSize = false; } else currentInputPosition += term.quantityCount; @@ -655,7 +528,7 @@ public: term.inputPosition = currentInputPosition; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoCharacterClass; alternative->m_hasFixedSize = false; } else currentInputPosition += term.quantityCount; @@ -666,20 +539,20 @@ public: term.frameLocation = currentCallFrameSize; if (term.quantityCount == 1 && !term.parentheses.isCopy) { if (term.quantityType != QuantifierFixedCount) - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesOnce; currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition); // If quantity is fixed, then pre-check its minimum size. if (term.quantityType == QuantifierFixedCount) currentInputPosition += term.parentheses.disjunction->m_minimumSize; term.inputPosition = currentInputPosition; } else if (term.parentheses.isTerminal) { - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesTerminal; currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition); term.inputPosition = currentInputPosition; } else { term.inputPosition = currentInputPosition; setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition); - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParentheses; } // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length. alternative->m_hasFixedSize = false; @@ -688,7 +561,7 @@ public: case PatternTerm::TypeParentheticalAssertion: term.inputPosition = currentInputPosition; term.frameLocation = currentCallFrameSize; - currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition); + currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + RegexStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition); break; } } @@ -699,23 +572,23 @@ public: unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition) { - if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1)) - initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative; + if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.length() > 1)) + initialCallFrameSize += RegexStackSpaceForBackTrackInfoAlternative; unsigned minimumInputSize = UINT_MAX; unsigned maximumCallFrameSize = 0; bool hasFixedSize = true; - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) { PatternAlternative* alternative = disjunction->m_alternatives[alt]; unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition); - minimumInputSize = std::min(minimumInputSize, alternative->m_minimumSize); - maximumCallFrameSize = std::max(maximumCallFrameSize, currentAlternativeCallFrameSize); + minimumInputSize = JS_MIN(minimumInputSize, alternative->m_minimumSize); + maximumCallFrameSize = JS_MAX(maximumCallFrameSize, currentAlternativeCallFrameSize); hasFixedSize &= alternative->m_hasFixedSize; } - ASSERT(minimumInputSize != UINT_MAX); - ASSERT(maximumCallFrameSize >= initialCallFrameSize); + JS_ASSERT(minimumInputSize != UINT_MAX); + JS_ASSERT(maximumCallFrameSize >= initialCallFrameSize); disjunction->m_hasFixedSize = hasFixedSize; disjunction->m_minimumSize = minimumInputSize; @@ -725,14 +598,13 @@ public: void setupOffsets() { - setupDisjunctionOffsets(m_pattern.m_body, 0, 0); + setupDisjunctionOffsets(m_pattern.m_body, BASE_FRAME_SIZE, 0); } // This optimization identifies sets of parentheses that we will never need to backtrack. // In these cases we do not need to store state from prior iterations. // We can presently avoid backtracking for: - // * where the parens are at the end of the regular expression (last term in any of the - // alternatives of the main body disjunction). + // * a set of parens at the end of the regular expression (last term in any of the alternatives of the main body disjunction). // * where the parens are non-capturing, and quantified unbounded greedy (*). // * where the parens do not contain any capturing subpatterns. void checkForTerminalParentheses() @@ -742,239 +614,57 @@ public: if (m_pattern.m_numSubpatterns) return; - Vector& alternatives = m_pattern.m_body->m_alternatives; - for (size_t i = 0; i < alternatives.size(); ++i) { - Vector& terms = alternatives[i]->m_terms; - if (terms.size()) { - PatternTerm& term = terms.last(); + js::Vector& alternatives = m_pattern.m_body->m_alternatives; + for (unsigned i =0; i < alternatives.length(); ++i) { + js::Vector& terms = alternatives[i]->m_terms; + if (terms.length()) { + PatternTerm& term = terms.back(); if (term.type == PatternTerm::TypeParenthesesSubpattern && term.quantityType == QuantifierGreedy - && term.quantityCount == quantifyInfinite + && term.quantityCount == UINT_MAX && !term.capture()) term.parentheses.isTerminal = true; } } } - void optimizeBOL() - { - // Look for expressions containing beginning of line (^) anchoring and unroll them. - // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops - // This code relies on the parsing code tagging alternatives with m_containsBOL and - // m_startsWithBOL and rolling those up to containing alternatives. - // At this point, this is only valid for non-multiline expressions. - PatternDisjunction* disjunction = m_pattern.m_body; - - if (!m_pattern.m_containsBOL || m_pattern.m_multiline) - return; - - PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true); - - // Set alternatives in disjunction to "onceThrough" - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) - disjunction->m_alternatives[alt]->setOnceThrough(); - - if (loopDisjunction) { - // Move alternatives from loopDisjunction to disjunction - for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt) - disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]); - - loopDisjunction->m_alternatives.clear(); - } - } - - // This function collects the terms which are potentially matching the first number of depth characters in the result. - // If this function returns false then it found at least one term which makes the beginning character - // look-up optimization inefficient. - bool setupDisjunctionBeginTerms(PatternDisjunction* disjunction, Vector* beginTerms, unsigned depth) - { - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { - PatternAlternative* alternative = disjunction->m_alternatives[alt]; - - if (!setupAlternativeBeginTerms(alternative, beginTerms, 0, depth)) - return false; - } - - return true; - } - - bool setupAlternativeBeginTerms(PatternAlternative* alternative, Vector* beginTerms, unsigned termIndex, unsigned depth) - { - bool checkNext = true; - unsigned numTerms = alternative->m_terms.size(); - - while (checkNext && termIndex < numTerms) { - PatternTerm term = alternative->m_terms[termIndex]; - checkNext = false; - - switch (term.type) { - case PatternTerm::TypeAssertionBOL: - case PatternTerm::TypeAssertionEOL: - case PatternTerm::TypeAssertionWordBoundary: - return false; - - case PatternTerm::TypeBackReference: - case PatternTerm::TypeForwardReference: - return false; - - case PatternTerm::TypePatternCharacter: - if (termIndex != numTerms - 1) { - beginTerms->append(TermChain(term)); - termIndex++; - checkNext = true; - } else if (term.quantityType == QuantifierFixedCount) { - beginTerms->append(TermChain(term)); - if (depth < 2 && termIndex < numTerms - 1 && term.quantityCount == 1) - if (!setupAlternativeBeginTerms(alternative, &beginTerms->last().hotTerms, termIndex + 1, depth + 1)) - return false; - } - - break; - - case PatternTerm::TypeCharacterClass: - return false; - - case PatternTerm::TypeParentheticalAssertion: - if (term.invert()) - return false; - - case PatternTerm::TypeParenthesesSubpattern: - if (term.quantityType != QuantifierFixedCount) { - if (termIndex == numTerms - 1) - break; - - termIndex++; - checkNext = true; - } - - if (!setupDisjunctionBeginTerms(term.parentheses.disjunction, beginTerms, depth)) - return false; - - break; - } - } - - return true; - } - - void setupBeginChars() - { - Vector beginTerms; - bool containsFixedCharacter = false; - - if ((!m_pattern.m_body->m_hasFixedSize || m_pattern.m_body->m_alternatives.size() > 1) - && setupDisjunctionBeginTerms(m_pattern.m_body, &beginTerms, 0)) { - unsigned size = beginTerms.size(); - - // If we haven't collected any terms we should abort the preparation of beginning character look-up optimization. - if (!size) - return; - - m_pattern.m_containsBeginChars = true; - - for (unsigned i = 0; i < size; i++) { - PatternTerm term = beginTerms[i].term; - - // We have just collected PatternCharacter terms, other terms are not allowed. - ASSERT(term.type == PatternTerm::TypePatternCharacter); - - if (term.quantityType == QuantifierFixedCount) - containsFixedCharacter = true; - - UChar character = term.patternCharacter; - unsigned mask = 0; - - if (character <= 0x7f) { - if (m_pattern.m_ignoreCase && isASCIIAlpha(character)) { - mask = 32; - character = toASCIILower(character); - } - - m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } else { - UChar upper, lower; - if (m_pattern.m_ignoreCase && ((upper = Unicode::toUpper(character)) != (lower = Unicode::toLower(character)))) { - m_beginCharHelper.addBeginChar(BeginChar(upper, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - m_beginCharHelper.addBeginChar(BeginChar(lower, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } else - m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } - } - - // If the pattern doesn't contain terms with fixed quantifiers then the beginning character look-up optimization is inefficient. - if (!containsFixedCharacter) { - m_pattern.m_containsBeginChars = false; - return; - } - - size = m_pattern.m_beginChars.size(); - - if (size > 2) - m_beginCharHelper.merge(size - 1); - else if (size <= 1) - m_pattern.m_containsBeginChars = false; - } - } - private: - YarrPattern& m_pattern; + RegexPattern& m_pattern; PatternAlternative* m_alternative; CharacterClassConstructor m_characterClassConstructor; - BeginCharHelper m_beginCharHelper; bool m_invertCharacterClass; - bool m_invertParentheticalAssertion; }; -ErrorCode YarrPattern::compile(const UString& patternString) -{ - YarrPatternConstructor constructor(*this); - if (ErrorCode error = parse(constructor, patternString)) +int compileRegex(const UString& patternString, RegexPattern& pattern) +{ + RegexPatternConstructor constructor(pattern); + + if (int error = parse(constructor, patternString)) return error; // If the pattern contains illegal backreferences reset & reparse. // Quoting Netscape's "What's new in JavaScript 1.2", // "Note: if the number of left parentheses is less than the number specified // in \#, the \# is taken as an octal escape as described in the next row." - if (containsIllegalBackReference()) { - unsigned numSubpatterns = m_numSubpatterns; + if (pattern.containsIllegalBackReference()) { + unsigned numSubpatterns = pattern.m_numSubpatterns; constructor.reset(); -#if !ASSERT_DISABLED - ErrorCode error = +#ifdef DEBUG + int error = #endif parse(constructor, patternString, numSubpatterns); - ASSERT(!error); - ASSERT(numSubpatterns == m_numSubpatterns); + JS_ASSERT(!error); + JS_ASSERT(numSubpatterns == pattern.m_numSubpatterns); } constructor.checkForTerminalParentheses(); - constructor.optimizeBOL(); - constructor.setupOffsets(); - constructor.setupBeginChars(); - return NoError; + return 0; } -YarrPattern::YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error) - : m_ignoreCase(ignoreCase) - , m_multiline(multiline) - , m_containsBackreferences(false) - , m_containsBeginChars(false) - , m_containsBOL(false) - , m_numSubpatterns(0) - , m_maxBackReference(0) - , newlineCached(0) - , digitsCached(0) - , spacesCached(0) - , wordcharCached(0) - , nondigitsCached(0) - , nonspacesCached(0) - , nonwordcharCached(0) -{ - *error = compile(pattern); -} } } diff --git a/js/src/yarr/YarrSyntaxChecker.h b/js/src/yarr/yarr/RegexCompiler.h similarity index 74% rename from js/src/yarr/YarrSyntaxChecker.h rename to js/src/yarr/yarr/RegexCompiler.h index 87f2ed5093b0..307c15866e59 100644 --- a/js/src/yarr/YarrSyntaxChecker.h +++ b/js/src/yarr/yarr/RegexCompiler.h @@ -1,8 +1,5 @@ -/* -*- 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) 2011 Apple Inc. All rights reserved. +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,20 +21,18 @@ * 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 YarrSyntaxChecker_h -#define YarrSyntaxChecker_h +#ifndef RegexCompiler_h +#define RegexCompiler_h -#include "wtfbridge.h" -#include "YarrParser.h" +#include "RegexParser.h" +#include "RegexPattern.h" namespace JSC { namespace Yarr { -ErrorCode checkSyntax(const UString& pattern); +int compileRegex(const UString& patternString, RegexPattern& pattern); -}} // JSC::YARR - -#endif // YarrSyntaxChecker_h +} } // namespace JSC::Yarr +#endif // RegexCompiler_h diff --git a/js/src/yarr/yarr/RegexJIT.cpp b/js/src/yarr/yarr/RegexJIT.cpp new file mode 100644 index 000000000000..1571c35b7125 --- /dev/null +++ b/js/src/yarr/yarr/RegexJIT.cpp @@ -0,0 +1,1589 @@ +/* + * Copyright (C) 2009 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. + */ + +#include "RegexJIT.h" + +#if ENABLE_ASSEMBLER + +#include "assembler/assembler/LinkBuffer.h" +#include "assembler/assembler/MacroAssembler.h" +#include "RegexCompiler.h" + +#include "yarr/pcre/pcre.h" // temporary, remove when fallback is removed. + +using namespace WTF; + +namespace JSC { namespace Yarr { + +class JSGlobalData; + +class RegexGenerator : private MacroAssembler { + friend void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); + +#if WTF_CPU_ARM + static const RegisterID input = ARMRegisters::r0; + static const RegisterID index = ARMRegisters::r1; + static const RegisterID length = ARMRegisters::r2; + static const RegisterID output = ARMRegisters::r4; + + static const RegisterID regT0 = ARMRegisters::r5; + static const RegisterID regT1 = ARMRegisters::r6; + + static const RegisterID returnRegister = ARMRegisters::r0; +#elif WTF_CPU_MIPS + static const RegisterID input = MIPSRegisters::a0; + static const RegisterID index = MIPSRegisters::a1; + static const RegisterID length = MIPSRegisters::a2; + static const RegisterID output = MIPSRegisters::a3; + + static const RegisterID regT0 = MIPSRegisters::t4; + static const RegisterID regT1 = MIPSRegisters::t5; + + static const RegisterID returnRegister = MIPSRegisters::v0; +#elif WTF_CPU_SPARC + static const RegisterID input = SparcRegisters::i0; + static const RegisterID index = SparcRegisters::i1; + static const RegisterID length = SparcRegisters::i2; + static const RegisterID output = SparcRegisters::i3; + + static const RegisterID regT0 = SparcRegisters::i4; + static const RegisterID regT1 = SparcRegisters::i5; + + static const RegisterID returnRegister = SparcRegisters::i0; +#elif WTF_CPU_X86 + static const RegisterID input = X86Registers::eax; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::ecx; + static const RegisterID output = X86Registers::edi; + + static const RegisterID regT0 = X86Registers::ebx; + static const RegisterID regT1 = X86Registers::esi; + + static const RegisterID returnRegister = X86Registers::eax; +#elif WTF_CPU_X86_64 +#if WTF_PLATFORM_WIN + static const RegisterID input = X86Registers::ecx; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::r8; + static const RegisterID output = X86Registers::r9; +#else + static const RegisterID input = X86Registers::edi; + static const RegisterID index = X86Registers::esi; + static const RegisterID length = X86Registers::edx; + static const RegisterID output = X86Registers::ecx; +#endif + + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::ebx; + + static const RegisterID returnRegister = X86Registers::eax; +#endif + + void optimizeAlternative(PatternAlternative* alternative) + { + if (!alternative->m_terms.length()) + return; + + for (unsigned i = 0; i < alternative->m_terms.length() - 1; ++i) { + PatternTerm& term = alternative->m_terms[i]; + PatternTerm& nextTerm = alternative->m_terms[i + 1]; + + if ((term.type == PatternTerm::TypeCharacterClass) + && (term.quantityType == QuantifierFixedCount) + && (nextTerm.type == PatternTerm::TypePatternCharacter) + && (nextTerm.quantityType == QuantifierFixedCount)) { + PatternTerm termCopy = term; + alternative->m_terms[i] = nextTerm; + alternative->m_terms[i + 1] = termCopy; + } + } + } + + void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) + { + do { + // pick which range we're going to generate + int which = count >> 1; + char lo = ranges[which].begin; + char hi = ranges[which].end; + + // check if there are any ranges or matches below lo. If not, just jl to failure - + // if there is anything else to check, check that first, if it falls through jmp to failure. + if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { + Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); + + // generate code for all ranges before this one + if (which) + matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); + + while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { + matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex]))); + ++*matchIndex; + } + failures.append(jump()); + + loOrAbove.link(this); + } else if (which) { + Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); + + matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); + failures.append(jump()); + + loOrAbove.link(this); + } else + failures.append(branch32(LessThan, character, Imm32((unsigned short)lo))); + + while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) + ++*matchIndex; + + matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi))); + // fall through to here, the value is above hi. + + // shuffle along & loop around if there are any more matches to handle. + unsigned next = which + 1; + ranges += next; + count -= next; + } while (count); + } + + void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass) + { + if (charClass->m_table) { + ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table)); + matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry)); + return; + } + Jump unicodeFail; + if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) { + Jump isAscii = branch32(LessThanOrEqual, character, Imm32(0x7f)); + + if (charClass->m_matchesUnicode.length()) { + for (unsigned i = 0; i < charClass->m_matchesUnicode.length(); ++i) { + UChar ch = charClass->m_matchesUnicode[i]; + matchDest.append(branch32(Equal, character, Imm32(ch))); + } + } + + if (charClass->m_rangesUnicode.length()) { + for (unsigned i = 0; i < charClass->m_rangesUnicode.length(); ++i) { + UChar lo = charClass->m_rangesUnicode[i].begin; + UChar hi = charClass->m_rangesUnicode[i].end; + + Jump below = branch32(LessThan, character, Imm32(lo)); + matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi))); + below.link(this); + } + } + + unicodeFail = jump(); + isAscii.link(this); + } + + if (charClass->m_ranges.length()) { + unsigned matchIndex = 0; + JumpList failures; + matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.length(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.length()); + while (matchIndex < charClass->m_matches.length()) + matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++]))); + + failures.link(this); + } else if (charClass->m_matches.length()) { + // optimization: gather 'a','A' etc back together, can mask & test once. + js::Vector matchesAZaz; + + for (unsigned i = 0; i < charClass->m_matches.length(); ++i) { + char ch = charClass->m_matches[i]; + if (m_pattern.m_ignoreCase) { + if (isASCIILower(ch)) { + matchesAZaz.append(ch); + continue; + } + if (isASCIIUpper(ch)) + continue; + } + matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch))); + } + + if (unsigned countAZaz = matchesAZaz.length()) { + or32(Imm32(32), character); + for (unsigned i = 0; i < countAZaz; ++i) + matchDest.append(branch32(Equal, character, Imm32(matchesAZaz[i]))); + } + } + + if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) + unicodeFail.link(this); + } + + // Jumps if input not available; will have (incorrectly) incremented already! + Jump jumpIfNoAvailableInput(unsigned countToCheck) + { + add32(Imm32(countToCheck), index); + return branch32(Above, index, length); + } + + Jump jumpIfAvailableInput(unsigned countToCheck) + { + add32(Imm32(countToCheck), index); + return branch32(BelowOrEqual, index, length); + } + + Jump checkInput() + { + return branch32(BelowOrEqual, index, length); + } + + Jump atEndOfInput() + { + return branch32(Equal, index, length); + } + + Jump notAtEndOfInput() + { + return branch32(NotEqual, index, length); + } + + Jump jumpIfCharEquals(UChar ch, int inputPosition) + { + return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); + } + + Jump jumpIfCharNotEquals(UChar ch, int inputPosition) + { + return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); + } + + void readCharacter(int inputPosition, RegisterID reg) + { + load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg); + } + + void storeToFrame(RegisterID reg, unsigned frameLocation) + { + poke(reg, frameLocation); + } + + void storeToFrame(Imm32 imm, unsigned frameLocation) + { + poke(imm, frameLocation); + } + + DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) + { + return storePtrWithPatch(ImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*))); + } + + void loadFromFrame(unsigned frameLocation, RegisterID reg) + { + peek(reg, frameLocation); + } + + void loadFromFrameAndJump(unsigned frameLocation) + { + jump(Address(stackPointerRegister, frameLocation * sizeof(void*))); + } + + struct AlternativeBacktrackRecord { + DataLabelPtr dataLabel; + Label backtrackLocation; + + AlternativeBacktrackRecord(DataLabelPtr dataLabel, Label backtrackLocation) + : dataLabel(dataLabel) + , backtrackLocation(backtrackLocation) + { + } + }; + + struct TermGenerationState { + TermGenerationState(PatternDisjunction* disjunction, unsigned checkedTotal) + : disjunction(disjunction) + , checkedTotal(checkedTotal) + { + } + + void resetAlternative() + { + isBackTrackGenerated = false; + alt = 0; + } + bool alternativeValid() + { + return alt < disjunction->m_alternatives.length(); + } + void nextAlternative() + { + ++alt; + } + PatternAlternative* alternative() + { + return disjunction->m_alternatives[alt]; + } + + void resetTerm() + { + ASSERT(alternativeValid()); + t = 0; + } + bool termValid() + { + ASSERT(alternativeValid()); + return t < alternative()->m_terms.length(); + } + void nextTerm() + { + ASSERT(alternativeValid()); + ++t; + } + PatternTerm& term() + { + ASSERT(alternativeValid()); + return alternative()->m_terms[t]; + } + bool isLastTerm() + { + ASSERT(alternativeValid()); + return (t + 1) == alternative()->m_terms.length(); + } + bool isMainDisjunction() + { + return !disjunction->m_parent; + } + + PatternTerm& lookaheadTerm() + { + ASSERT(alternativeValid()); + ASSERT((t + 1) < alternative()->m_terms.length()); + return alternative()->m_terms[t + 1]; + } + bool isSinglePatternCharacterLookaheadTerm() + { + ASSERT(alternativeValid()); + return ((t + 1) < alternative()->m_terms.length()) + && (lookaheadTerm().type == PatternTerm::TypePatternCharacter) + && (lookaheadTerm().quantityType == QuantifierFixedCount) + && (lookaheadTerm().quantityCount == 1); + } + + int inputOffset() + { + return term().inputPosition - checkedTotal; + } + + void jumpToBacktrack(Jump jump, MacroAssembler* masm) + { + if (isBackTrackGenerated) + jump.linkTo(backtrackLabel, masm); + else + backTrackJumps.append(jump); + } + void jumpToBacktrack(JumpList& jumps, MacroAssembler* masm) + { + if (isBackTrackGenerated) + jumps.linkTo(backtrackLabel, masm); + else + backTrackJumps.append(jumps); + } + bool plantJumpToBacktrackIfExists(MacroAssembler* masm) + { + if (isBackTrackGenerated) { + masm->jump(backtrackLabel); + return true; + } + return false; + } + void addBacktrackJump(Jump jump) + { + backTrackJumps.append(jump); + } + void setBacktrackGenerated(Label label) + { + isBackTrackGenerated = true; + backtrackLabel = label; + } + void linkAlternativeBacktracks(MacroAssembler* masm) + { + isBackTrackGenerated = false; + backTrackJumps.link(masm); + } + void linkAlternativeBacktracksTo(Label label, MacroAssembler* masm) + { + isBackTrackGenerated = false; + backTrackJumps.linkTo(label, masm); + } + void propagateBacktrackingFrom(TermGenerationState& nestedParenthesesState, MacroAssembler* masm) + { + jumpToBacktrack(nestedParenthesesState.backTrackJumps, masm); + if (nestedParenthesesState.isBackTrackGenerated) + setBacktrackGenerated(nestedParenthesesState.backtrackLabel); + } + + PatternDisjunction* disjunction; + int checkedTotal; + private: + unsigned alt; + unsigned t; + JumpList backTrackJumps; + Label backtrackLabel; + bool isBackTrackGenerated; + }; + + void generateAssertionBOL(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + if (m_pattern.m_multiline) { + const RegisterID character = regT0; + + JumpList matchDest; + if (!term.inputPosition) + matchDest.append(branch32(Equal, index, Imm32(state.checkedTotal))); + + readCharacter(state.inputOffset() - 1, character); + matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); + state.jumpToBacktrack(jump(), this); + + matchDest.link(this); + } else { + // Erk, really should poison out these alternatives early. :-/ + if (term.inputPosition) + state.jumpToBacktrack(jump(), this); + else + state.jumpToBacktrack(branch32(NotEqual, index, Imm32(state.checkedTotal)), this); + } + } + + void generateAssertionEOL(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + if (m_pattern.m_multiline) { + const RegisterID character = regT0; + + JumpList matchDest; + if (term.inputPosition == state.checkedTotal) + matchDest.append(atEndOfInput()); + + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); + state.jumpToBacktrack(jump(), this); + + matchDest.link(this); + } else { + if (term.inputPosition == state.checkedTotal) + state.jumpToBacktrack(notAtEndOfInput(), this); + // Erk, really should poison out these alternatives early. :-/ + else + state.jumpToBacktrack(jump(), this); + } + } + + // Also falls though on nextIsNotWordChar. + void matchAssertionWordchar(TermGenerationState& state, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + if (term.inputPosition == state.checkedTotal) + nextIsNotWordChar.append(atEndOfInput()); + + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass()); + } + + void generateAssertionWordBoundary(TermGenerationState& state) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + Jump atBegin; + JumpList matchDest; + if (!term.inputPosition) + atBegin = branch32(Equal, index, Imm32(state.checkedTotal)); + readCharacter(state.inputOffset() - 1, character); + matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass()); + if (!term.inputPosition) + atBegin.link(this); + + // We fall through to here if the last character was not a wordchar. + JumpList nonWordCharThenWordChar; + JumpList nonWordCharThenNonWordChar; + if (term.invertOrCapture) { + matchAssertionWordchar(state, nonWordCharThenNonWordChar, nonWordCharThenWordChar); + nonWordCharThenWordChar.append(jump()); + } else { + matchAssertionWordchar(state, nonWordCharThenWordChar, nonWordCharThenNonWordChar); + nonWordCharThenNonWordChar.append(jump()); + } + state.jumpToBacktrack(nonWordCharThenNonWordChar, this); + + // We jump here if the last character was a wordchar. + matchDest.link(this); + JumpList wordCharThenWordChar; + JumpList wordCharThenNonWordChar; + if (term.invertOrCapture) { + matchAssertionWordchar(state, wordCharThenNonWordChar, wordCharThenWordChar); + wordCharThenWordChar.append(jump()); + } else { + matchAssertionWordchar(state, wordCharThenWordChar, wordCharThenNonWordChar); + // This can fall-though! + } + + state.jumpToBacktrack(wordCharThenWordChar, this); + + nonWordCharThenWordChar.link(this); + wordCharThenNonWordChar.link(this); + } + + void generatePatternCharacterSingle(TermGenerationState& state) + { + const RegisterID character = regT0; + UChar ch = state.term().patternCharacter; + + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + state.jumpToBacktrack(jumpIfCharNotEquals(ch, state.inputOffset()), this); + } + } + + void generatePatternCharacterPair(TermGenerationState& state) + { + const RegisterID character = regT0; +#if WTF_CPU_BIG_ENDIAN + UChar ch2 = state.term().patternCharacter; + UChar ch1 = state.lookaheadTerm().patternCharacter; +#else + UChar ch1 = state.term().patternCharacter; + UChar ch2 = state.lookaheadTerm().patternCharacter; +#endif + + int mask = 0; + int chPair = ch1 | (ch2 << 16); + + if (m_pattern.m_ignoreCase) { + if (isASCIIAlpha(ch1)) + mask |= 32; + if (isASCIIAlpha(ch2)) + mask |= 32 << 16; + } + + if (mask) { + load32WithUnalignedHalfWords(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character); + or32(Imm32(mask), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(chPair | mask)), this); + } else + state.jumpToBacktrack(branch32WithUnalignedHalfWords(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this); + } + + void generatePatternCharacterFixed(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(index, countRegister); + sub32(Imm32(term.quantityCount), countRegister); + + Label loop(this); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); + or32(Imm32(32), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + state.jumpToBacktrack(branch16(NotEqual, BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), Imm32(ch)), this); + } + add32(Imm32(1), countRegister); + branch32(NotEqual, countRegister, index).linkTo(loop, this); + } + + void generatePatternCharacterGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(Imm32(0), countRegister); + + JumpList failures; + Label loop(this); + failures.append(atEndOfInput()); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + failures.append(jumpIfCharNotEquals(ch, state.inputOffset())); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + if (term.quantityCount != 0xffffffff) { + branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); + failures.append(jump()); + } else + jump(loop); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + state.jumpToBacktrack(branchTest32(Zero, countRegister), this); + sub32(Imm32(1), countRegister); + sub32(Imm32(1), index); + + failures.link(this); + + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generatePatternCharacterNonGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(Imm32(0), countRegister); + + Jump firstTimeDoNothing = jump(); + + Label hardFail(this); + sub32(countRegister, index); + state.jumpToBacktrack(jump(), this); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + + atEndOfInput().linkTo(hardFail, this); + if (term.quantityCount != 0xffffffff) + branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + branch32(NotEqual, character, Imm32(Unicode::toLower(ch))).linkTo(hardFail, this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + jumpIfCharNotEquals(ch, state.inputOffset()).linkTo(hardFail, this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + + firstTimeDoNothing.link(this); + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateCharacterClassSingle(TermGenerationState& state) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + state.jumpToBacktrack(matchDest, this); + else { + state.jumpToBacktrack(jump(), this); + matchDest.link(this); + } + } + + void generateCharacterClassFixed(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(index, countRegister); + sub32(Imm32(term.quantityCount), countRegister); + + Label loop(this); + JumpList matchDest; + load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + state.jumpToBacktrack(matchDest, this); + else { + state.jumpToBacktrack(jump(), this); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + branch32(NotEqual, countRegister, index).linkTo(loop, this); + } + + void generateCharacterClassGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(Imm32(0), countRegister); + + JumpList failures; + Label loop(this); + failures.append(atEndOfInput()); + + if (term.invertOrCapture) { + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, failures, term.characterClass); + } else { + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + failures.append(jump()); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + if (term.quantityCount != 0xffffffff) { + branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); + failures.append(jump()); + } else + jump(loop); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + state.jumpToBacktrack(branchTest32(Zero, countRegister), this); + sub32(Imm32(1), countRegister); + sub32(Imm32(1), index); + + failures.link(this); + + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateCharacterClassNonGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(Imm32(0), countRegister); + + Jump firstTimeDoNothing = jump(); + + Label hardFail(this); + sub32(countRegister, index); + state.jumpToBacktrack(jump(), this); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + + atEndOfInput().linkTo(hardFail, this); + branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); + + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + matchDest.linkTo(hardFail, this); + else { + jump(hardFail); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + + firstTimeDoNothing.link(this); + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateParenthesesDisjunction(PatternTerm& parenthesesTerm, TermGenerationState& state, unsigned alternativeFrameLocation) + { + ASSERT((parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern) || (parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion)); + ASSERT(parenthesesTerm.quantityCount == 1); + + PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; + unsigned preCheckedCount = ((parenthesesTerm.quantityType == QuantifierFixedCount) && (parenthesesTerm.type != PatternTerm::TypeParentheticalAssertion)) ? disjunction->m_minimumSize : 0; + + if (disjunction->m_alternatives.length() == 1) { + state.resetAlternative(); + ASSERT(state.alternativeValid()); + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + int countToCheck = alternative->m_minimumSize - preCheckedCount; + if (countToCheck) { + ASSERT((parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion) || (parenthesesTerm.quantityType != QuantifierFixedCount)); + + // FIXME: This is quite horrible. The call to 'plantJumpToBacktrackIfExists' + // will be forced to always trampoline into here, just to decrement the index. + // Ick. + Jump skip = jump(); + + Label backtrackBegin(this); + sub32(Imm32(countToCheck), index); + state.addBacktrackJump(jump()); + + skip.link(this); + + state.setBacktrackGenerated(backtrackBegin); + + state.jumpToBacktrack(jumpIfNoAvailableInput(countToCheck), this); + state.checkedTotal += countToCheck; + } + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + state.checkedTotal -= countToCheck; + } else { + JumpList successes; + + for (state.resetAlternative(); state.alternativeValid(); state.nextAlternative()) { + + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + ASSERT(alternative->m_minimumSize >= preCheckedCount); + int countToCheck = alternative->m_minimumSize - preCheckedCount; + if (countToCheck) { + state.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); + state.checkedTotal += countToCheck; + } + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + // Matched an alternative. + DataLabelPtr dataLabel = storeToFrameWithPatch(alternativeFrameLocation); + successes.append(jump()); + + // Alternative did not match. + Label backtrackLocation(this); + + // Can we backtrack the alternative? - if so, do so. If not, just fall through to the next one. + state.plantJumpToBacktrackIfExists(this); + + state.linkAlternativeBacktracks(this); + + if (countToCheck) { + sub32(Imm32(countToCheck), index); + state.checkedTotal -= countToCheck; + } + + m_backtrackRecords.append(AlternativeBacktrackRecord(dataLabel, backtrackLocation)); + } + // We fall through to here when the last alternative fails. + // Add a backtrack out of here for the parenthese handling code to link up. + state.addBacktrackJump(jump()); + + // Generate a trampoline for the parens code to backtrack to, to retry the + // next alternative. + state.setBacktrackGenerated(label()); + loadFromFrameAndJump(alternativeFrameLocation); + + // FIXME: both of the above hooks are a little inefficient, in that you + // may end up trampolining here, just to trampoline back out to the + // parentheses code, or vice versa. We can probably eliminate a jump + // by restructuring, but coding this way for now for simplicity during + // development. + + successes.link(this); + } + } + + void generateParenthesesSingle(TermGenerationState& state) + { + const RegisterID indexTemporary = regT0; + PatternTerm& term = state.term(); + PatternDisjunction* disjunction = term.parentheses.disjunction; + ASSERT(term.quantityCount == 1); + + unsigned preCheckedCount = (term.quantityType == QuantifierFixedCount) ? disjunction->m_minimumSize : 0; + + unsigned parenthesesFrameLocation = term.frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation; + if (term.quantityType != QuantifierFixedCount) + alternativeFrameLocation += RegexStackSpaceForBackTrackInfoParenthesesOnce; + + // optimized case - no capture & no quantifier can be handled in a light-weight manner. + if (!term.invertOrCapture && (term.quantityType == QuantifierFixedCount)) { + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // this expects that any backtracks back out of the parentheses will be in the + // parenthesesState's backTrackJumps vector, and that if they need backtracking + // they will have set an entry point on the parenthesesState's backtrackLabel. + state.propagateBacktrackingFrom(parenthesesState, this); + } else { + Jump nonGreedySkipParentheses; + Label nonGreedyTryParentheses; + if (term.quantityType == QuantifierGreedy) + storeToFrame(index, parenthesesFrameLocation); + else if (term.quantityType == QuantifierNonGreedy) { + storeToFrame(Imm32(-1), parenthesesFrameLocation); + nonGreedySkipParentheses = jump(); + nonGreedyTryParentheses = label(); + storeToFrame(index, parenthesesFrameLocation); + } + + // store the match start index + if (term.invertOrCapture) { + int inputOffset = state.inputOffset() - preCheckedCount; + if (inputOffset) { + move(index, indexTemporary); + add32(Imm32(inputOffset), indexTemporary); + store32(indexTemporary, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); + } else + store32(index, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); + } + + // generate the body of the parentheses + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + + Jump success = (term.quantityType == QuantifierFixedCount) ? + jump() : + branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesFrameLocation * sizeof(void*)))); + + // A failure AFTER the parens jumps here + Label backtrackFromAfterParens(this); + + if (term.quantityType == QuantifierGreedy) { + // If this is -1 we have now tested with both with and without the parens. + loadFromFrame(parenthesesFrameLocation, indexTemporary); + state.jumpToBacktrack(branch32(Equal, indexTemporary, Imm32(-1)), this); + } else if (term.quantityType == QuantifierNonGreedy) { + // If this is -1 we have now tested without the parens, now test with. + loadFromFrame(parenthesesFrameLocation, indexTemporary); + branch32(Equal, indexTemporary, Imm32(-1)).linkTo(nonGreedyTryParentheses, this); + } + + parenthesesState.plantJumpToBacktrackIfExists(this); + // A failure WITHIN the parens jumps here + parenthesesState.linkAlternativeBacktracks(this); + if (term.invertOrCapture) { + store32(Imm32(-1), Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); +#if 0 + store32(Imm32(-1), Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); +#endif + } + + if (term.quantityType == QuantifierGreedy) + storeToFrame(Imm32(-1), parenthesesFrameLocation); + else + state.jumpToBacktrack(jump(), this); + + state.setBacktrackGenerated(backtrackFromAfterParens); + if (term.quantityType == QuantifierNonGreedy) + nonGreedySkipParentheses.link(this); + success.link(this); + + // store the match end index + if (term.invertOrCapture) { + int inputOffset = state.inputOffset(); + if (inputOffset) { + move(index, indexTemporary); + add32(Imm32(state.inputOffset()), indexTemporary); + store32(indexTemporary, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); + } else + store32(index, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); + } + } + } + + void generateParenthesesGreedyNoBacktrack(TermGenerationState& state) + { + PatternTerm& parenthesesTerm = state.term(); + PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; + ASSERT(parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern); + ASSERT(parenthesesTerm.quantityCount != 1); // Handled by generateParenthesesSingle. + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + + Label matchAgain(this); + + storeToFrame(index, parenthesesTerm.frameLocation); // Save the current index to check for zero len matches later. + + for (parenthesesState.resetAlternative(); parenthesesState.alternativeValid(); parenthesesState.nextAlternative()) { + + PatternAlternative* alternative = parenthesesState.alternative(); + optimizeAlternative(alternative); + + int countToCheck = alternative->m_minimumSize; + if (countToCheck) { + parenthesesState.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); + parenthesesState.checkedTotal += countToCheck; + } + + for (parenthesesState.resetTerm(); parenthesesState.termValid(); parenthesesState.nextTerm()) + generateTerm(parenthesesState); + + // If we get here, we matched! If the index advanced then try to match more since limit isn't supported yet. + branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesTerm.frameLocation * sizeof(void*))), matchAgain); + + // If we get here we matched, but we matched "" - cannot accept this alternative as is, so either backtrack, + // or fall through to try the next alternative if no backtrack is available. + parenthesesState.plantJumpToBacktrackIfExists(this); + + parenthesesState.linkAlternativeBacktracks(this); + // We get here if the alternative fails to match - fall through to the next iteration, or out of the loop. + + if (countToCheck) { + sub32(Imm32(countToCheck), index); + parenthesesState.checkedTotal -= countToCheck; + } + } + + // If the last alternative falls through to here, we have a failed match... + // Which means that we match whatever we have matched up to this point (even if nothing). + } + + void generateParentheticalAssertion(TermGenerationState& state) + { + PatternTerm& term = state.term(); + PatternDisjunction* disjunction = term.parentheses.disjunction; + ASSERT(term.quantityCount == 1); + ASSERT(term.quantityType == QuantifierFixedCount); + + unsigned parenthesesFrameLocation = term.frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation + RegexStackSpaceForBackTrackInfoParentheticalAssertion; + + int countCheckedAfterAssertion = state.checkedTotal - term.inputPosition; + + if (term.invertOrCapture) { + // Inverted case + storeToFrame(index, parenthesesFrameLocation); + + state.checkedTotal -= countCheckedAfterAssertion; + if (countCheckedAfterAssertion) + sub32(Imm32(countCheckedAfterAssertion), index); + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // Success! - which means - Fail! + loadFromFrame(parenthesesFrameLocation, index); + state.jumpToBacktrack(jump(), this); + + // And fail means success. + parenthesesState.linkAlternativeBacktracks(this); + loadFromFrame(parenthesesFrameLocation, index); + + state.checkedTotal += countCheckedAfterAssertion; + } else { + // Normal case + storeToFrame(index, parenthesesFrameLocation); + + state.checkedTotal -= countCheckedAfterAssertion; + if (countCheckedAfterAssertion) + sub32(Imm32(countCheckedAfterAssertion), index); + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // Success! - which means - Success! + loadFromFrame(parenthesesFrameLocation, index); + Jump success = jump(); + + parenthesesState.linkAlternativeBacktracks(this); + loadFromFrame(parenthesesFrameLocation, index); + state.jumpToBacktrack(jump(), this); + + success.link(this); + + state.checkedTotal += countCheckedAfterAssertion; + } + } + + void generateTerm(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + switch (term.type) { + case PatternTerm::TypeAssertionBOL: + generateAssertionBOL(state); + break; + + case PatternTerm::TypeAssertionEOL: + generateAssertionEOL(state); + break; + + case PatternTerm::TypeAssertionWordBoundary: + generateAssertionWordBoundary(state); + break; + + case PatternTerm::TypePatternCharacter: + switch (term.quantityType) { + case QuantifierFixedCount: + if (term.quantityCount == 1) { + if (state.isSinglePatternCharacterLookaheadTerm() && (state.lookaheadTerm().inputPosition == (term.inputPosition + 1))) { + generatePatternCharacterPair(state); + state.nextTerm(); + } else + generatePatternCharacterSingle(state); + } else + generatePatternCharacterFixed(state); + break; + case QuantifierGreedy: + generatePatternCharacterGreedy(state); + break; + case QuantifierNonGreedy: + generatePatternCharacterNonGreedy(state); + break; + } + break; + + case PatternTerm::TypeCharacterClass: + switch (term.quantityType) { + case QuantifierFixedCount: + if (term.quantityCount == 1) + generateCharacterClassSingle(state); + else + generateCharacterClassFixed(state); + break; + case QuantifierGreedy: + generateCharacterClassGreedy(state); + break; + case QuantifierNonGreedy: + generateCharacterClassNonGreedy(state); + break; + } + break; + + case PatternTerm::TypeBackReference: + m_shouldFallBack = true; + break; + + case PatternTerm::TypeForwardReference: + break; + + case PatternTerm::TypeParenthesesSubpattern: + if (term.quantityCount == 1 && !term.parentheses.isCopy) + generateParenthesesSingle(state); + else if (term.parentheses.isTerminal) + generateParenthesesGreedyNoBacktrack(state); + else + m_shouldFallBack = true; + break; + + case PatternTerm::TypeParentheticalAssertion: + generateParentheticalAssertion(state); + break; + } + } + + void generateDisjunction(PatternDisjunction* disjunction) + { + TermGenerationState state(disjunction, 0); + state.resetAlternative(); + + // check availability for the next alternative + int countCheckedForCurrentAlternative = 0; + int countToCheckForFirstAlternative = 0; + bool hasShorterAlternatives = false; + bool setRepeatAlternativeLabels = false; + JumpList notEnoughInputForPreviousAlternative; + Label firstAlternative; + Label firstAlternativeInputChecked; + + // The label 'firstAlternative' is used to plant a check to see if there is + // sufficient input available to run the first repeating alternative. + // The label 'firstAlternativeInputChecked' will jump directly to matching + // the first repeating alternative having skipped this check. + + if (state.alternativeValid()) { + PatternAlternative* alternative = state.alternative(); + if (!alternative->onceThrough()) { + firstAlternative = Label(this); + setRepeatAlternativeLabels = true; + } + countToCheckForFirstAlternative = alternative->m_minimumSize; + state.checkedTotal += countToCheckForFirstAlternative; + if (countToCheckForFirstAlternative) + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); + countCheckedForCurrentAlternative = countToCheckForFirstAlternative; + } + + if (setRepeatAlternativeLabels) + firstAlternativeInputChecked = Label(this); + + while (state.alternativeValid()) { + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + // Track whether any alternatives are shorter than the first one. + if (!alternative->onceThrough()) + hasShorterAlternatives = hasShorterAlternatives || (countCheckedForCurrentAlternative < countToCheckForFirstAlternative); + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + // If we get here, the alternative matched. + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + ASSERT(index != returnRegister); + if (m_pattern.m_body->m_hasFixedSize) { + move(index, returnRegister); + if (alternative->m_minimumSize) + sub32(Imm32(alternative->m_minimumSize), returnRegister); + + store32(returnRegister, output); + } else + load32(Address(output), returnRegister); + + store32(index, Address(output, 4)); + + generateReturn(); + + state.nextAlternative(); + + // if there are any more alternatives, plant the check for input before looping. + if (state.alternativeValid()) { + PatternAlternative* nextAlternative = state.alternative(); + if (!setRepeatAlternativeLabels && !nextAlternative->onceThrough()) { + // We have handled non-repeating alternatives, jump to next iteration + // and loop over repeating alternatives. + state.jumpToBacktrack(jump(), this); + + countToCheckForFirstAlternative = nextAlternative->m_minimumSize; + + // If we get here, there the last input checked failed. + notEnoughInputForPreviousAlternative.link(this); + + state.linkAlternativeBacktracks(this); + + // Back up to start the looping alternatives. + if (countCheckedForCurrentAlternative) + sub32(Imm32(countCheckedForCurrentAlternative), index); + + firstAlternative = Label(this); + + state.checkedTotal = countToCheckForFirstAlternative; + if (countToCheckForFirstAlternative) + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); + + countCheckedForCurrentAlternative = countToCheckForFirstAlternative; + + firstAlternativeInputChecked = Label(this); + + setRepeatAlternativeLabels = true; + } else { + int countToCheckForNextAlternative = nextAlternative->m_minimumSize; + + if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one. + // If we get here, then the last input checked failed. + notEnoughInputForPreviousAlternative.link(this); + + // Check if sufficent input available to run the next alternative + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); + // We are now in the correct state to enter the next alternative; this add is only required + // to mirror and revert operation of the sub32, just below. + add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); + + // If we get here, then the last input checked passed. + state.linkAlternativeBacktracks(this); + // No need to check if we can run the next alternative, since it is shorter - + // just update index. + sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); + } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one. + // If we get here, then the last input checked failed. + // If there is insufficient input to run the current alternative, and the next alternative is longer, + // then there is definitely not enough input to run it - don't even check. Just adjust index, as if + // we had checked. + notEnoughInputForPreviousAlternative.link(this); + add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index); + notEnoughInputForPreviousAlternative.append(jump()); + + // The next alternative is longer than the current one; check the difference. + state.linkAlternativeBacktracks(this); + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); + } else { // CASE 3: Both alternatives are the same length. + ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative); + + // If the next alterative is the same length as this one, then no need to check the input - + // if there was sufficent input to run the current alternative then there is sufficient + // input to run the next one; if not, there isn't. + state.linkAlternativeBacktracks(this); + } + state.checkedTotal -= countCheckedForCurrentAlternative; + countCheckedForCurrentAlternative = countToCheckForNextAlternative; + state.checkedTotal += countCheckedForCurrentAlternative; + } + } + } + + // If we get here, all Alternatives failed... + + state.checkedTotal -= countCheckedForCurrentAlternative; + + if (!setRepeatAlternativeLabels) { + // If there are no alternatives that need repeating (all are marked 'onceThrough') then just link + // the match failures to this point, and fall through to the return below. + state.linkAlternativeBacktracks(this); + notEnoughInputForPreviousAlternative.link(this); + } else { + // How much more input need there be to be able to retry from the first alternative? + // examples: + // /yarr_jit/ or /wrec|pcre/ + // In these examples we need check for one more input before looping. + // /yarr_jit|pcre/ + // In this case we need check for 5 more input to loop (+4 to allow for the first alterative + // being four longer than the last alternative checked, and another +1 to effectively move + // the start position along by one). + // /yarr|rules/ or /wrec|notsomuch/ + // In these examples, provided that there was sufficient input to have just been matching for + // the second alternative we can loop without checking for available input (since the second + // alternative is longer than the first). In the latter example we need to decrement index + // (by 4) so the start position is only progressed by 1 from the last iteration. + int incrementForNextIter = (countToCheckForFirstAlternative - countCheckedForCurrentAlternative) + 1; + + // First, deal with the cases where there was sufficient input to try the last alternative. + if (incrementForNextIter > 0) // We need to check for more input anyway, fall through to the checking below. + state.linkAlternativeBacktracks(this); + else if (m_pattern.m_body->m_hasFixedSize && !incrementForNextIter) // No need to update anything, link these backtracks straight to the to pof the loop! + state.linkAlternativeBacktracksTo(firstAlternativeInputChecked, this); + else { // no need to check the input, but we do have some bookkeeping to do first. + state.linkAlternativeBacktracks(this); + + // Where necessary update our preserved start position. + if (!m_pattern.m_body->m_hasFixedSize) { + move(index, regT0); + sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); + store32(regT0, Address(output)); + } + + // Update index if necessary, and loop (without checking). + if (incrementForNextIter) + add32(Imm32(incrementForNextIter), index); + jump().linkTo(firstAlternativeInputChecked, this); + } + + notEnoughInputForPreviousAlternative.link(this); + // Update our idea of the start position, if we're tracking this. + if (!m_pattern.m_body->m_hasFixedSize) { + if (countCheckedForCurrentAlternative - 1) { + move(index, regT0); + sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); + store32(regT0, Address(output)); + } else + store32(index, Address(output)); + } + + // Check if there is sufficent input to run the first alternative again. + jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this); + // No - insufficent input to run the first alteranative, are there any other alternatives we + // might need to check? If so, the last check will have left the index incremented by + // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative + // LESS input is available, to have the effect of just progressing the start position by 1 + // from the last iteration. If this check passes we can just jump up to the check associated + // with the first alternative in the loop. This is a bit sad, since we'll end up trying the + // first alternative again, and this check will fail (otherwise the check planted just above + // here would have passed). This is a bit sad, however it saves trying to do something more + // complex here in compilation, and in the common case we should end up coallescing the checks. + // + // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least + // of the minimum-alternative-lengths. E.g. if I have two alternatives of length 200 and 150, + // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there + // is sufficient input to run either alternative (constantly failing). If there had been only + // one alternative, or if the shorter alternative had come first, we would have terminated + // immediately. :-/ + if (hasShorterAlternatives) + jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this); + // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true, + // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... + // but since we're about to return a failure this doesn't really matter!) + } + + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + move(Imm32(-1), returnRegister); + + generateReturn(); + } + + void generateEnter() + { +#if WTF_CPU_X86_64 + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + push(X86Registers::ebx); +#elif WTF_CPU_X86 + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + // TODO: do we need spill registers to fill the output pointer if there are no sub captures? + push(X86Registers::ebx); + push(X86Registers::edi); + push(X86Registers::esi); + // load output into edi (2 = saved ebp + return address). + #if WTF_COMPILER_MSVC || WTF_COMPILER_SUNPRO + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); + loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); + loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); + loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); + #else + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); + #endif +#elif WTF_CPU_ARM + push(ARMRegisters::r4); + push(ARMRegisters::r5); + push(ARMRegisters::r6); +#if WTF_CPU_ARM_TRADITIONAL + push(ARMRegisters::r8); // scratch register +#endif + move(ARMRegisters::r3, output); +#elif WTF_CPU_SPARC + save(Imm32(-m_pattern.m_body->m_callFrameSize * sizeof(void*))); + // set m_callFrameSize to 0 avoid and stack movement later. + m_pattern.m_body->m_callFrameSize = 0; +#elif WTF_CPU_MIPS + // Do nothing. +#endif + } + + void generateReturn() + { +#if WTF_CPU_X86_64 + pop(X86Registers::ebx); + pop(X86Registers::ebp); +#elif WTF_CPU_X86 + pop(X86Registers::esi); + pop(X86Registers::edi); + pop(X86Registers::ebx); + pop(X86Registers::ebp); +#elif WTF_CPU_ARM +#if WTF_CPU_ARM_TRADITIONAL + pop(ARMRegisters::r8); // scratch register +#endif + pop(ARMRegisters::r6); + pop(ARMRegisters::r5); + pop(ARMRegisters::r4); +#elif WTF_CPU_SPARC + ret_and_restore(); + return; +#elif WTF_CPU_MIPS + // Do nothing +#endif + ret(); + } + +public: + RegexGenerator(RegexPattern& pattern) + : m_pattern(pattern) + , m_shouldFallBack(false) + { + } + + void generate() + { + generateEnter(); + + if (!m_pattern.m_body->m_hasFixedSize) + store32(index, Address(output)); + + if (m_pattern.m_body->m_callFrameSize) + subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + generateDisjunction(m_pattern.m_body); + } + + void compile(ExecutableAllocator& allocator, RegexCodeBlock& jitObject) + { + generate(); + + if (oom()) { + m_shouldFallBack = true; + return; + } + + ExecutablePool *dummy; + bool ok; + LinkBuffer patchBuffer(this, &allocator, &dummy, &ok); + if (!ok) { + m_shouldFallBack = true; + return; + } + + for (unsigned i = 0; i < m_backtrackRecords.length(); ++i) + patchBuffer.patch(m_backtrackRecords[i].dataLabel, patchBuffer.locationOf(m_backtrackRecords[i].backtrackLocation)); + + jitObject.set(patchBuffer.finalizeCode()); + } + + bool shouldFallBack() + { + return m_shouldFallBack; + } + +private: + RegexPattern& m_pattern; + bool m_shouldFallBack; + js::Vector m_backtrackRecords; +}; + +void jitCompileRegex(ExecutableAllocator& allocator, RegexCodeBlock& jitObject, const UString&patternString, unsigned& numSubpatterns, int &error, bool &fellBack, bool ignoreCase, bool multiline +#ifdef ANDROID + , bool forceFallback +#endif +) +{ +#ifdef ANDROID + if (!forceFallback) { +#endif + fellBack = false; + RegexPattern pattern(ignoreCase, multiline); + if ((error = compileRegex(patternString, pattern))) + return; + numSubpatterns = pattern.m_numSubpatterns; + + if (!pattern.m_containsBackreferences) { + RegexGenerator generator(pattern); + generator.compile(allocator, jitObject); + if (!generator.shouldFallBack()) + return; + } +#ifdef ANDROID + } // forceFallback +#endif + + fellBack = true; + JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase; + JSRegExpMultilineOption multilineOption = multiline ? JSRegExpMultiline : JSRegExpSingleLine; + jitObject.setFallback(jsRegExpCompile(reinterpret_cast(const_cast(patternString).chars()), patternString.length(), ignoreCaseOption, multilineOption, &numSubpatterns, &error)); +} + +}} + +#endif diff --git a/js/src/yarr/yarr/RegexJIT.h b/js/src/yarr/yarr/RegexJIT.h new file mode 100644 index 000000000000..60a51b484c02 --- /dev/null +++ b/js/src/yarr/yarr/RegexJIT.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2009 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 RegexJIT_h +#define RegexJIT_h + +#if ENABLE_ASSEMBLER + +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/MacroAssemblerCodeRef.h" +#include "assembler/jit/ExecutableAllocator.h" +#include "RegexPattern.h" +#include "yarr/jswtfbridge.h" + +#include "yarr/pcre/pcre.h" +struct JSRegExp; // temporary, remove when fallback is removed. + +#if WTF_CPU_X86 && !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO +#define YARR_CALL __attribute__ ((regparm (3))) +#else +#define YARR_CALL +#endif + +struct JSContext; + +namespace JSC { + +namespace Yarr { + +class RegexCodeBlock { + typedef int (*RegexJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; + +public: + RegexCodeBlock() + : m_fallback(0) + { + } + + ~RegexCodeBlock() + { + if (m_fallback) + jsRegExpFree(m_fallback); + if (m_ref.m_size) + m_ref.m_executablePool->release(); + } + + JSRegExp* getFallback() { return m_fallback; } + void setFallback(JSRegExp* fallback) { m_fallback = fallback; } + + bool operator!() { return (!m_ref.m_code.executableAddress() && !m_fallback); } + void set(MacroAssembler::CodeRef ref) { m_ref = ref; } + + int execute(const UChar* input, unsigned start, unsigned length, int* output) + { + void *code = m_ref.m_code.executableAddress(); + return JS_EXTENSION((reinterpret_cast(code))(input, start, length, output)); + } + +private: + MacroAssembler::CodeRef m_ref; + JSRegExp* m_fallback; +}; + +void jitCompileRegex(ExecutableAllocator &allocator, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, int& error, bool &fellBack, bool ignoreCase = false, bool multiline = false +#ifdef ANDROID + , bool forceFallback = false +#endif +); + +inline int executeRegex(JSContext *cx, RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize) +{ + if (JSRegExp* fallback = jitObject.getFallback()) { + int result = jsRegExpExecute(cx, fallback, input, length, start, output, outputArraySize); + + if (result == JSRegExpErrorHitLimit) + return HitRecursionLimit; + + // -1 represents no-match for both PCRE and YARR. + JS_ASSERT(result >= -1); + return result; + } + + return jitObject.execute(input, start, length, output); +} + +} } // namespace JSC::Yarr + +#endif /* ENABLE_ASSEMBLER */ + +#endif // RegexJIT_h diff --git a/js/src/yarr/YarrParser.h b/js/src/yarr/yarr/RegexParser.h similarity index 81% rename from js/src/yarr/YarrParser.h rename to js/src/yarr/yarr/RegexParser.h index f2b50dd867e3..1ae2c2fd049b 100644 --- a/js/src/yarr/YarrParser.h +++ b/js/src/yarr/yarr/RegexParser.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. * * Redistribution and use in source and binary forms, with or without @@ -24,18 +21,18 @@ * 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 YarrParser_h -#define YarrParser_h +#ifndef RegexParser_h +#define RegexParser_h -#include "Yarr.h" +#include +#include +#include "yarr/jswtfbridge.h" +#include "yarr/yarr/RegexCommon.h" namespace JSC { namespace Yarr { -#define REGEXP_ERROR_PREFIX "Invalid regular expression: " - enum BuiltInCharacterClassID { DigitClassID, SpaceClassID, @@ -48,7 +45,7 @@ template class Parser { private: template - friend ErrorCode parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit); + friend int parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit); /* * CharacterClassParserDelegate: @@ -64,8 +61,10 @@ private: CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err) : m_delegate(delegate) , m_err(err) - , m_state(Empty) - , m_character(0) + , m_state(empty) +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 5 /* quell GCC overwarning */ + , m_character(0xFFFF) +#endif { } @@ -80,62 +79,56 @@ private: } /* - * atomPatternCharacter(): + * atomPatternCharacterUnescaped(): * - * This method is called either from parseCharacterClass() (for an unescaped - * character in a character class), or from parseEscape(). In the former case - * the value true will be passed for the argument 'hyphenIsRange', and in this - * mode we will allow a hypen to be treated as indicating a range (i.e. /[a-z]/ - * is different to /[a\-z]/). + * This method is called directly from parseCharacterClass(), to report a new + * pattern character token. This method differs from atomPatternCharacter(), + * which will be called from parseEscape(), since a hypen provided via this + * method may be indicating a character range, but a hyphen parsed by + * parseEscape() cannot be interpreted as doing so. */ - void atomPatternCharacter(UChar ch, bool hyphenIsRange = false) + void atomPatternCharacterUnescaped(UChar ch) { switch (m_state) { - case AfterCharacterClass: - // Following a builtin character class we need look out for a hyphen. - // We're looking for invalid ranges, such as /[\d-x]/ or /[\d-\d]/. - // If we see a hyphen following a charater class then unlike usual - // we'll report it to the delegate immediately, and put ourself into - // a poisoned state. Any following calls to add another character or - // character class will result in an error. (A hypen following a - // character-class is itself valid, but only at the end of a regex). - if (hyphenIsRange && ch == '-') { - m_delegate.atomCharacterClassAtom('-'); - m_state = AfterCharacterClassHyphen; - return; - } - // Otherwise just fall through - cached character so treat this as Empty. - - case Empty: + case empty: m_character = ch; - m_state = CachedCharacter; - return; + m_state = cachedCharacter; + break; - case CachedCharacter: - if (hyphenIsRange && ch == '-') - m_state = CachedCharacterHyphen; + case cachedCharacter: + if (ch == '-') + m_state = cachedCharacterHyphen; else { m_delegate.atomCharacterClassAtom(m_character); m_character = ch; } - return; + break; - case CachedCharacterHyphen: - if (ch < m_character) { + case cachedCharacterHyphen: + if (ch >= m_character) + m_delegate.atomCharacterClassRange(m_character, ch); + else m_err = CharacterClassOutOfOrder; - return; - } - m_delegate.atomCharacterClassRange(m_character, ch); - m_state = Empty; - return; - - case AfterCharacterClassHyphen: - m_delegate.atomCharacterClassAtom(ch); - m_state = Empty; - return; + m_state = empty; } } + /* + * atomPatternCharacter(): + * + * Adds a pattern character, called by parseEscape(), as such will not + * interpret a hyphen as indicating a character range. + */ + void atomPatternCharacter(UChar ch) + { + // Flush if a character is already pending to prevent the + // hyphen from begin interpreted as indicating a range. + if((ch == '-') && (m_state == cachedCharacter)) + flush(); + + atomPatternCharacterUnescaped(ch); + } + /* * atomBuiltInCharacterClass(): * @@ -143,28 +136,17 @@ private: */ void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert) { - switch (m_state) { - case CachedCharacter: - // Flush the currently cached character, then fall through. - m_delegate.atomCharacterClassAtom(m_character); - - case Empty: - case AfterCharacterClass: - m_state = AfterCharacterClass; - m_delegate.atomCharacterClassBuiltIn(classID, invert); - return; - - case CachedCharacterHyphen: - // Error! We have a range that looks like [x-\d]. We require - // the end of the range to be a single character. - m_err = CharacterClassInvalidRange; - return; - - case AfterCharacterClassHyphen: - m_delegate.atomCharacterClassBuiltIn(classID, invert); - m_state = Empty; + if (m_state == cachedCharacterHyphen) { + // If the RHS of a range does not contain exacly one character then a SyntaxError + // must be thrown. SpiderMonkey only errors out in the [c-\s] case as an extension. + // (This assumes none of the built in character classes contain a single + // character.) + m_err = CharacterClassRangeSingleChar; + m_state = empty; return; } + flush(); + m_delegate.atomCharacterClassBuiltIn(classID, invert); } /* @@ -174,29 +156,31 @@ private: */ void end() { - if (m_state == CachedCharacter) - m_delegate.atomCharacterClassAtom(m_character); - else if (m_state == CachedCharacterHyphen) { - m_delegate.atomCharacterClassAtom(m_character); - m_delegate.atomCharacterClassAtom('-'); - } + flush(); m_delegate.atomCharacterClassEnd(); } // parseEscape() should never call these delegate methods when // invoked with inCharacterClass set. - void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); } - void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); } + void assertionWordBoundary(bool) { JS_NOT_REACHED("parseEscape() should never call this"); } + void atomBackReference(unsigned) { JS_NOT_REACHED("parseEscape() should never call this"); } private: + void flush() + { + if (m_state != empty) // either cachedCharacter or cachedCharacterHyphen + m_delegate.atomCharacterClassAtom(m_character); + if (m_state == cachedCharacterHyphen) + m_delegate.atomCharacterClassAtom('-'); + m_state = empty; + } + Delegate& m_delegate; ErrorCode& m_err; enum CharacterClassConstructionState { - Empty, - CachedCharacter, - CachedCharacterHyphen, - AfterCharacterClass, - AfterCharacterClassHyphen + empty, + cachedCharacter, + cachedCharacterHyphen } m_state; UChar m_character; }; @@ -205,7 +189,7 @@ private: : m_delegate(delegate) , m_backReferenceLimit(backReferenceLimit) , m_err(NoError) - , m_data(pattern.chars()) + , m_data(const_cast(pattern).chars()) , m_size(pattern.length()) , m_index(0) , m_parenthesesNestingDepth(0) @@ -235,8 +219,8 @@ private: template bool parseEscape(EscapeDelegate& delegate) { - ASSERT(!m_err); - ASSERT(peek() == '\\'); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '\\'); consume(); if (atEndOfPattern()) { @@ -308,7 +292,7 @@ private: unsigned backReference; if (!consumeNumber(backReference)) - break; + return false; if (backReference <= m_backReferenceLimit) { delegate.atomBackReference(backReference); break; @@ -418,14 +402,14 @@ private: /* * parseCharacterClass(): * - * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape) + * Helper for parseTokens(); calls directly and indirectly (via parseCharacterClassEscape) * to an instance of CharacterClassParserDelegate, to describe the character class to the * delegate. */ void parseCharacterClass() { - ASSERT(!m_err); - ASSERT(peek() == '['); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '['); consume(); CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err); @@ -444,7 +428,7 @@ private: break; default: - characterClassConstructor.atomPatternCharacter(consume(), true); + characterClassConstructor.atomPatternCharacterUnescaped(consume()); } if (m_err) @@ -461,8 +445,8 @@ private: */ void parseParenthesesBegin() { - ASSERT(!m_err); - ASSERT(peek() == '('); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '('); consume(); if (tryConsume('?')) { @@ -500,8 +484,8 @@ private: */ void parseParenthesesEnd() { - ASSERT(!m_err); - ASSERT(peek() == ')'); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == ')'); consume(); if (m_parenthesesNestingDepth > 0) @@ -519,8 +503,8 @@ private: */ void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max) { - ASSERT(!m_err); - ASSERT(min <= max); + JS_ASSERT(!m_err); + JS_ASSERT(min <= max); if (lastTokenWasAnAtom) m_delegate.quantifyAtom(min, max, !tryConsume('?')); @@ -588,13 +572,13 @@ private: case '*': consume(); - parseQuantifier(lastTokenWasAnAtom, 0, quantifyInfinite); + parseQuantifier(lastTokenWasAnAtom, 0, UINT_MAX); lastTokenWasAnAtom = false; break; case '+': consume(); - parseQuantifier(lastTokenWasAnAtom, 1, quantifyInfinite); + parseQuantifier(lastTokenWasAnAtom, 1, UINT_MAX); lastTokenWasAnAtom = false; break; @@ -619,7 +603,7 @@ private: if (!consumeNumber(max)) break; } else { - max = quantifyInfinite; + max = UINT_MAX; } } @@ -652,18 +636,26 @@ private: /* * parse(): * - * This method calls parseTokens() to parse over the input and converts any + * This method calls regexBegin(), calls parseTokens() to parse over the input + * patterns, calls regexEnd() or regexError() as appropriate, and converts any * error code to a const char* for a result. */ - ErrorCode parse() + int parse() { + m_delegate.regexBegin(); + if (m_size > MAX_PATTERN_SIZE) m_err = PatternTooLarge; else parseTokens(); - ASSERT(atEndOfPattern() || m_err); + JS_ASSERT(atEndOfPattern() || m_err); - return m_err; + if (m_err) + m_delegate.regexError(); + else + m_delegate.regexEnd(); + + return static_cast(m_err); } @@ -683,13 +675,13 @@ private: bool atEndOfPattern() { - ASSERT(m_index <= m_size); + JS_ASSERT(m_index <= m_size); return m_index == m_size; } int peek() { - ASSERT(m_index < m_size); + JS_ASSERT(m_index < m_size); return m_data[m_index]; } @@ -700,40 +692,40 @@ private: unsigned peekDigit() { - ASSERT(peekIsDigit()); + JS_ASSERT(peekIsDigit()); return peek() - '0'; } int consume() { - ASSERT(m_index < m_size); + JS_ASSERT(m_index < m_size); return m_data[m_index++]; } unsigned consumeDigit() { - ASSERT(peekIsDigit()); + JS_ASSERT(peekIsDigit()); return consume() - '0'; } - bool consumeNumber(unsigned &accum) - { - accum = consumeDigit(); - while (peekIsDigit()) { - unsigned newValue = accum * 10 + peekDigit(); - if (newValue < accum) { /* Overflow check. */ - m_err = QuantifierTooLarge; - return false; - } - accum = newValue; - consume(); - } - return true; + bool consumeNumber(unsigned &accum) + { + accum = consumeDigit(); + while (peekIsDigit()) { + unsigned newValue = accum * 10 + peekDigit(); + if (newValue < accum) { /* Overflow check. */ + m_err = QuantifierTooLarge; + return false; + } + accum = newValue; + consume(); + } + return true; } unsigned consumeOctal() { - ASSERT(WTF::isASCIIOctalDigit(peek())); + JS_ASSERT(WTF::isASCIIOctalDigit(peek())); unsigned n = consumeDigit(); while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek())) @@ -806,6 +798,14 @@ private: * * void disjunction(); * + * void regexBegin(); + * void regexEnd(); + * void regexError(); + * + * Before any call recording tokens are made, regexBegin() will be called on the + * delegate once. Once parsing is complete either regexEnd() or regexError() will + * be called, as appropriate. + * * The regular expression is described by a sequence of assertion*() and atom*() * callbacks to the delegate, describing the terms in the regular expression. * Following an atom a quantifyAtom() call may occur to indicate that the previous @@ -836,11 +836,11 @@ private: */ template -ErrorCode parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = quantifyInfinite) +int parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = UINT_MAX) { return Parser(delegate, pattern, backReferenceLimit).parse(); } } } // namespace JSC::Yarr -#endif // YarrParser_h +#endif // RegexParser_h diff --git a/js/src/yarr/YarrPattern.h b/js/src/yarr/yarr/RegexPattern.h similarity index 70% rename from js/src/yarr/YarrPattern.h rename to js/src/yarr/yarr/RegexPattern.h index 38ae10fcf289..9d9b286a653e 100644 --- a/js/src/yarr/YarrPattern.h +++ b/js/src/yarr/yarr/RegexPattern.h @@ -1,9 +1,5 @@ -/* -*- 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 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,32 +21,26 @@ * 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 YarrPattern_h -#define YarrPattern_h +#ifndef RegexPattern_h +#define RegexPattern_h + +#include "jsvector.h" +#include "yarr/jswtfbridge.h" +#include "yarr/yarr/RegexCommon.h" -#include "wtfbridge.h" -#include "ASCIICType.h" namespace JSC { namespace Yarr { -enum ErrorCode { - NoError, - PatternTooLarge, - QuantifierOutOfOrder, - QuantifierWithoutAtom, - MissingParentheses, - ParenthesesUnmatched, - ParenthesesTypeInvalid, - CharacterClassUnmatched, - CharacterClassInvalidRange, - CharacterClassOutOfOrder, - EscapeUnterminated, - QuantifierTooLarge, - NumberOfErrorCodes -}; +#define RegexStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoBackReference 2 +#define RegexStackSpaceForBackTrackInfoAlternative 1 // One per alternative. +#define RegexStackSpaceForBackTrackInfoParentheticalAssertion 1 +#define RegexStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoParenthesesTerminal 1 +#define RegexStackSpaceForBackTrackInfoParentheses 4 struct PatternDisjunction; @@ -65,42 +55,60 @@ struct CharacterRange { } }; -struct CharacterClassTable : RefCounted { - friend class js::OffTheBooks; +/* + * Wraps a table and indicates inversion. Can be efficiently borrowed + * between character classes, so it's refcounted. + */ +struct CharacterClassTable { + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + const char* m_table; bool m_inverted; - static PassRefPtr create(const char* table, bool inverted) + jsrefcount m_refcount; + + /* Ownership transferred to caller. */ + static CharacterClassTable *create(const char* table, bool inverted) { - return adoptRef(js::OffTheBooks::new_(table, inverted)); + // FIXME: bug 574459 -- no NULL checks done by any of the callers, all + // of which are in RegExpJitTables.h. + return js::OffTheBooks::new_(table, inverted); } + void incref() { JS_ATOMIC_INCREMENT(&m_refcount); } + void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js::Foreground::delete_(this); } + private: CharacterClassTable(const char* table, bool inverted) : m_table(table) , m_inverted(inverted) + , m_refcount(0) { } }; struct CharacterClass { - WTF_MAKE_FAST_ALLOCATED -public: // All CharacterClass instances have to have the full set of matches and ranges, // they may have an optional table for faster lookups (which must match the // specified matches and ranges) - CharacterClass(PassRefPtr table) + CharacterClass(CharacterClassTable *table) : m_table(table) { + if (m_table) + m_table->incref(); } ~CharacterClass() { - js::Foreground::delete_(m_table.get()); + if (m_table) + m_table->decref(); } - Vector m_matches; - Vector m_ranges; - Vector m_matchesUnicode; - Vector m_rangesUnicode; - RefPtr m_table; + typedef js::Vector UChars; + typedef js::Vector CharacterRanges; + UChars m_matches; + CharacterRanges m_ranges; + UChars m_matchesUnicode; + CharacterRanges m_rangesUnicode; + CharacterClassTable *m_table; }; enum QuantifierType { @@ -121,12 +129,11 @@ struct PatternTerm { TypeParenthesesSubpattern, TypeParentheticalAssertion } type; - bool m_capture :1; - bool m_invert :1; + bool invertOrCapture; union { UChar patternCharacter; CharacterClass* characterClass; - unsigned backReferenceSubpatternId; + unsigned subpatternId; struct { PatternDisjunction* disjunction; unsigned subpatternId; @@ -140,21 +147,8 @@ struct PatternTerm { int inputPosition; unsigned frameLocation; - // No-argument constructor for js::Vector. - PatternTerm() - : type(PatternTerm::TypePatternCharacter) - , m_capture(false) - , m_invert(false) - { - patternCharacter = 0; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - PatternTerm(UChar ch) : type(PatternTerm::TypePatternCharacter) - , m_capture(false) - , m_invert(false) { patternCharacter = ch; quantityType = QuantifierFixedCount; @@ -163,18 +157,16 @@ struct PatternTerm { PatternTerm(CharacterClass* charClass, bool invert) : type(PatternTerm::TypeCharacterClass) - , m_capture(false) - , m_invert(invert) + , invertOrCapture(invert) { characterClass = charClass; quantityType = QuantifierFixedCount; quantityCount = 1; } - PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false) + PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool invertOrCapture) : type(type) - , m_capture(capture) - , m_invert(invert) + , invertOrCapture(invertOrCapture) { parentheses.disjunction = disjunction; parentheses.subpatternId = subpatternId; @@ -186,8 +178,7 @@ struct PatternTerm { PatternTerm(Type type, bool invert = false) : type(type) - , m_capture(false) - , m_invert(invert) + , invertOrCapture(invert) { quantityType = QuantifierFixedCount; quantityCount = 1; @@ -195,10 +186,9 @@ struct PatternTerm { PatternTerm(unsigned spatternId) : type(TypeBackReference) - , m_capture(false) - , m_invert(false) + , invertOrCapture(false) { - backReferenceSubpatternId = spatternId; + subpatternId = spatternId; quantityType = QuantifierFixedCount; quantityCount = 1; } @@ -225,12 +215,12 @@ struct PatternTerm { bool invert() { - return m_invert; + return invertOrCapture; } bool capture() { - return m_capture; + return invertOrCapture; } void quantify(unsigned count, QuantifierType type) @@ -241,8 +231,9 @@ struct PatternTerm { }; struct PatternAlternative { - WTF_MAKE_FAST_ALLOCATED -public: + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + PatternAlternative(PatternDisjunction* disjunction) : m_parent(disjunction) , m_onceThrough(false) @@ -254,14 +245,14 @@ public: PatternTerm& lastTerm() { - ASSERT(m_terms.size()); - return m_terms[m_terms.size() - 1]; + JS_ASSERT(m_terms.length()); + return m_terms[m_terms.length() - 1]; } void removeLastTerm() { - ASSERT(m_terms.size()); - m_terms.shrink(m_terms.size() - 1); + JS_ASSERT(m_terms.length()); + m_terms.popBack(); } void setOnceThrough() @@ -274,7 +265,7 @@ public: return m_onceThrough; } - Vector m_terms; + js::Vector m_terms; PatternDisjunction* m_parent; unsigned m_minimumSize; bool m_onceThrough : 1; @@ -283,9 +274,18 @@ public: bool m_containsBOL : 1; }; +template +static inline void +deleteAllValues(js::Vector &vector) +{ + for (T** t = vector.begin(); t < vector.end(); ++t) + js::Foreground::delete_(*t); +} + struct PatternDisjunction { - WTF_MAKE_FAST_ALLOCATED -public: + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + PatternDisjunction(PatternAlternative* parent = 0) : m_parent(parent) , m_hasFixedSize(false) @@ -299,12 +299,13 @@ public: PatternAlternative* addNewAlternative() { + // FIXME: bug 574459 -- no NULL check PatternAlternative* alternative = js::OffTheBooks::new_(this); m_alternatives.append(alternative); return alternative; } - Vector m_alternatives; + js::Vector m_alternatives; PatternAlternative* m_parent; unsigned m_minimumSize; unsigned m_callFrameSize; @@ -313,7 +314,7 @@ public: // You probably don't want to be calling these functions directly // (please to be calling newlineCharacterClass() et al on your -// friendly neighborhood YarrPattern instance to get nicely +// friendly neighborhood RegexPattern instance to get nicely // cached copies). CharacterClass* newlineCreate(); CharacterClass* digitsCreate(); @@ -323,34 +324,25 @@ CharacterClass* nondigitsCreate(); CharacterClass* nonspacesCreate(); CharacterClass* nonwordcharCreate(); -struct TermChain { - TermChain(PatternTerm term) - : term(term) - {} +struct RegexPattern { + RegexPattern(bool ignoreCase, bool multiline) + : m_ignoreCase(ignoreCase) + , m_multiline(multiline) + , m_containsBackreferences(false) + , m_containsBOL(false) + , m_numSubpatterns(0) + , m_maxBackReference(0) + , newlineCached(0) + , digitsCached(0) + , spacesCached(0) + , wordcharCached(0) + , nondigitsCached(0) + , nonspacesCached(0) + , nonwordcharCached(0) + { + } - PatternTerm term; - Vector hotTerms; -}; - -struct BeginChar { - BeginChar() - : value(0) - , mask(0) - {} - - BeginChar(unsigned value, unsigned mask) - : value(value) - , mask(mask) - {} - - unsigned value; - unsigned mask; -}; - -struct YarrPattern { - YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error); - - ~YarrPattern() + ~RegexPattern() { deleteAllValues(m_disjunctions); deleteAllValues(m_userCharacterClasses); @@ -362,7 +354,6 @@ struct YarrPattern { m_maxBackReference = 0; m_containsBackreferences = false; - m_containsBeginChars = false; m_containsBOL = false; newlineCached = 0; @@ -377,7 +368,6 @@ struct YarrPattern { m_disjunctions.clear(); deleteAllValues(m_userCharacterClasses); m_userCharacterClasses.clear(); - m_beginChars.clear(); } bool containsIllegalBackReference() @@ -428,21 +418,19 @@ struct YarrPattern { return nonwordcharCached; } + typedef js::Vector PatternDisjunctions; + typedef js::Vector CharacterClasses; bool m_ignoreCase : 1; bool m_multiline : 1; bool m_containsBackreferences : 1; - bool m_containsBeginChars : 1; bool m_containsBOL : 1; unsigned m_numSubpatterns; unsigned m_maxBackReference; - PatternDisjunction* m_body; - Vector m_disjunctions; - Vector m_userCharacterClasses; - Vector m_beginChars; + PatternDisjunction *m_body; + PatternDisjunctions m_disjunctions; + CharacterClasses m_userCharacterClasses; private: - ErrorCode compile(const UString& patternString); - CharacterClass* newlineCached; CharacterClass* digitsCached; CharacterClass* spacesCached; @@ -454,4 +442,4 @@ private: } } // namespace JSC::Yarr -#endif // YarrPattern_h +#endif // RegexPattern_h diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 7341d40d7f65..50711ae8a547 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -2032,7 +2032,7 @@ POSSIBILITY OF SUCH DAMAGE.

Apple License

-

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr, and widget/src/cocoa.

+

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr/wtf, js/src/yarr/yarr, and widget/src/cocoa.

 Copyright (C) 2008, 2009 Apple Inc. All rights reserved.

From dbf646afbfb803e982ab4fc9a2f2208f2e263dda Mon Sep 17 00:00:00 2001
From: David Mandelin 
Date: Thu, 12 May 2011 18:39:47 -0700
Subject: [PATCH 101/145] Bug 625600: Update Yarr import to WebKit rev 86639,
 r=cdleary,dvander

---
 js/src/Makefile.in                            |   37 +-
 .../assembler/AbstractMacroAssembler.h        |   63 +-
 js/src/assembler/assembler/MacroAssembler.h   |   12 +-
 .../assembler/assembler/MacroAssemblerARM.cpp |    2 +-
 .../assembler/assembler/MacroAssemblerARM.h   |   50 +-
 .../assembler/assembler/MacroAssemblerARMv7.h |   44 +-
 .../assembler/MacroAssemblerCodeRef.h         |   17 +-
 .../assembler/assembler/MacroAssemblerSparc.h |   48 +-
 .../assembler/assembler/MacroAssemblerX86.h   |   14 +-
 .../assembler/MacroAssemblerX86Common.h       |   44 +-
 .../assembler/MacroAssemblerX86_64.h          |   16 +-
 js/src/assembler/jit/ExecutableAllocator.h    |   20 +-
 .../assembler/jit/ExecutableAllocatorOS2.cpp  |    2 +-
 .../jit/ExecutableAllocatorPosix.cpp          |    4 +-
 .../jit/ExecutableAllocatorSymbian.cpp        |    2 +-
 .../assembler/jit/ExecutableAllocatorWin.cpp  |    2 +-
 js/src/assembler/wtf/Platform.h               |  981 ++++--
 .../jit-test/tests/basic/bug632964-regexp.js  |    3 -
 js/src/jscompartment.cpp                      |   11 +-
 js/src/jscompartment.h                        |   10 +-
 js/src/jsregexp.cpp                           |   46 +-
 js/src/jsregexpinlines.h                      |  119 +-
 js/src/jsvector.h                             |   22 +-
 js/src/methodjit/Compiler.cpp                 |   10 +-
 js/src/methodjit/MethodJIT.cpp                |    7 +-
 js/src/methodjit/TrampolineCompiler.cpp       |    2 +-
 js/src/yarr/{wtf => }/ASCIICType.h            |   33 +-
 js/src/yarr/BumpPointerAllocator.h            |  254 ++
 js/src/yarr/Makefile                          |    5 -
 js/src/yarr/OSAllocator.h                     |  103 +
 js/src/yarr/OSAllocatorPosix.cpp              |  129 +
 js/src/yarr/OSAllocatorWin.cpp                |   89 +
 js/src/yarr/PageAllocation.h                  |  131 +
 js/src/yarr/PageBlock.cpp                     |   88 +
 js/src/yarr/PageBlock.h                       |   91 +
 js/src/yarr/{yarr => }/RegExpJitTables.h      |    0
 js/src/yarr/VMTags.h                          |   90 +
 js/src/yarr/Yarr.h                            |   72 +
 js/src/yarr/YarrInterpreter.cpp               | 1914 +++++++++++
 js/src/yarr/YarrInterpreter.h                 |  380 +++
 js/src/yarr/YarrJIT.cpp                       | 2405 +++++++++++++
 js/src/yarr/YarrJIT.h                         |   93 +
 .../yarr/{yarr/RegexParser.h => YarrParser.h} |  262 +-
 .../RegexCompiler.cpp => YarrPattern.cpp}     |  572 +++-
 .../{yarr/RegexPattern.h => YarrPattern.h}    |  218 +-
 .../RegexCommon.h => YarrSyntaxChecker.cpp}   |   56 +-
 .../RegexCompiler.h => YarrSyntaxChecker.h}   |   25 +-
 js/src/yarr/jswtfbridge.h                     |   61 -
 js/src/yarr/pcre/AUTHORS                      |   12 -
 js/src/yarr/pcre/COPYING                      |   35 -
 js/src/yarr/pcre/chartables.c                 |   96 -
 js/src/yarr/pcre/dftables                     |  273 --
 js/src/yarr/pcre/pcre.h                       |   68 -
 js/src/yarr/pcre/pcre.pri                     |   12 -
 js/src/yarr/pcre/pcre_compile.cpp             | 2702 ---------------
 js/src/yarr/pcre/pcre_exec.cpp                | 2193 ------------
 js/src/yarr/pcre/pcre_internal.h              |  434 ---
 js/src/yarr/pcre/pcre_tables.cpp              |   71 -
 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp     |   98 -
 js/src/yarr/pcre/pcre_xclass.cpp              |  114 -
 js/src/yarr/pcre/ucpinternal.h                |  126 -
 js/src/yarr/pcre/ucptable.cpp                 | 2968 -----------------
 js/src/yarr/wtfbridge.h                       |  321 ++
 js/src/yarr/yarr/RegexJIT.cpp                 | 1589 ---------
 js/src/yarr/yarr/RegexJIT.h                   |  112 -
 toolkit/content/license.html                  |    2 +-
 66 files changed, 7862 insertions(+), 12023 deletions(-)
 rename js/src/yarr/{wtf => }/ASCIICType.h (81%)
 create mode 100644 js/src/yarr/BumpPointerAllocator.h
 delete mode 100644 js/src/yarr/Makefile
 create mode 100644 js/src/yarr/OSAllocator.h
 create mode 100644 js/src/yarr/OSAllocatorPosix.cpp
 create mode 100644 js/src/yarr/OSAllocatorWin.cpp
 create mode 100644 js/src/yarr/PageAllocation.h
 create mode 100644 js/src/yarr/PageBlock.cpp
 create mode 100644 js/src/yarr/PageBlock.h
 rename js/src/yarr/{yarr => }/RegExpJitTables.h (100%)
 create mode 100644 js/src/yarr/VMTags.h
 create mode 100644 js/src/yarr/Yarr.h
 create mode 100644 js/src/yarr/YarrInterpreter.cpp
 create mode 100644 js/src/yarr/YarrInterpreter.h
 create mode 100644 js/src/yarr/YarrJIT.cpp
 create mode 100644 js/src/yarr/YarrJIT.h
 rename js/src/yarr/{yarr/RegexParser.h => YarrParser.h} (81%)
 rename js/src/yarr/{yarr/RegexCompiler.cpp => YarrPattern.cpp} (52%)
 rename js/src/yarr/{yarr/RegexPattern.h => YarrPattern.h} (70%)
 rename js/src/yarr/{yarr/RegexCommon.h => YarrSyntaxChecker.cpp} (52%)
 rename js/src/yarr/{yarr/RegexCompiler.h => YarrSyntaxChecker.h} (74%)
 delete mode 100644 js/src/yarr/jswtfbridge.h
 delete mode 100644 js/src/yarr/pcre/AUTHORS
 delete mode 100644 js/src/yarr/pcre/COPYING
 delete mode 100644 js/src/yarr/pcre/chartables.c
 delete mode 100644 js/src/yarr/pcre/dftables
 delete mode 100644 js/src/yarr/pcre/pcre.h
 delete mode 100644 js/src/yarr/pcre/pcre.pri
 delete mode 100644 js/src/yarr/pcre/pcre_compile.cpp
 delete mode 100644 js/src/yarr/pcre/pcre_exec.cpp
 delete mode 100644 js/src/yarr/pcre/pcre_internal.h
 delete mode 100644 js/src/yarr/pcre/pcre_tables.cpp
 delete mode 100644 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp
 delete mode 100644 js/src/yarr/pcre/pcre_xclass.cpp
 delete mode 100644 js/src/yarr/pcre/ucpinternal.h
 delete mode 100644 js/src/yarr/pcre/ucptable.cpp
 create mode 100644 js/src/yarr/wtfbridge.h
 delete mode 100644 js/src/yarr/yarr/RegexJIT.cpp
 delete mode 100644 js/src/yarr/yarr/RegexJIT.h

diff --git a/js/src/Makefile.in b/js/src/Makefile.in
index 8023b1750b05..71f35a53d881 100644
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -362,7 +362,6 @@ CPPSRCS += 	MethodJIT.cpp \
 		Retcon.cpp \
 		TrampolineCompiler.cpp \
 		$(NULL)
-#		PICStubCompiler.cpp \
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
 ifeq (x86_64, $(TARGET_CPU))
@@ -420,14 +419,17 @@ ifeq (,$(filter arm% sparc %86 x86_64,$(TARGET_CPU)))
 
 VPATH +=	$(srcdir)/assembler \
 		$(srcdir)/assembler/wtf \
-		$(srcdir)/yarr/pcre \
+		$(srcdir)/yarr\
 		$(NULL)
 
-CPPSRCS += 	pcre_compile.cpp \
-                pcre_exec.cpp \
-                pcre_tables.cpp \
-                pcre_xclass.cpp \
-                pcre_ucp_searchfuncs.cpp \
+CPPSRCS += \
+		Assertions.cpp \
+		OSAllocatorPosix.cpp \
+		OSAllocatorWin.cpp \
+		PageBlock.cpp \
+		YarrInterpreter.cpp \
+		YarrPattern.cpp \
+		YarrSyntaxChecker.cpp \
 		$(NULL)
 else
 
@@ -440,9 +442,6 @@ VPATH += 	$(srcdir)/assembler \
 		$(srcdir)/assembler/assembler \
 		$(srcdir)/methodjit \
 		$(srcdir)/yarr \
-		$(srcdir)/yarr/yarr \
-		$(srcdir)/yarr/pcre \
-		$(srcdir)/yarr/wtf \
 		$(NONE)
 
 CPPSRCS += 	Assertions.cpp \
@@ -451,16 +450,16 @@ CPPSRCS += 	Assertions.cpp \
 		ExecutableAllocatorOS2.cpp \
 		ExecutableAllocator.cpp \
 		ARMAssembler.cpp \
-                Logging.cpp \
+        Logging.cpp \
 		MacroAssemblerARM.cpp \
 		MacroAssemblerX86Common.cpp \
-		RegexCompiler.cpp \
-		RegexJIT.cpp \
-		pcre_compile.cpp \
-                pcre_exec.cpp \
-                pcre_tables.cpp \
-                pcre_xclass.cpp \
-                pcre_ucp_searchfuncs.cpp \
+		OSAllocatorPosix.cpp \
+		OSAllocatorWin.cpp \
+		PageBlock.cpp \
+		YarrInterpreter.cpp \
+		YarrJIT.cpp \
+		YarrPattern.cpp \
+		YarrSyntaxChecker.cpp \
 		$(NONE)
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
@@ -653,7 +652,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
 
 	# We desire these numbers to go down, not up. See "User guide to memory
 	# management within SpiderMonkey" in jsutil.h.
-	$(srcdir)/config/check_source_count.py OffTheBooks:: 52 \
+	$(srcdir)/config/check_source_count.py OffTheBooks:: 54 \
 		"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
 	# This should go to zero, if possible.
 	$(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \
diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h
index 260380acd307..3c14c80bd4b0 100644
--- a/js/src/assembler/assembler/AbstractMacroAssembler.h
+++ b/js/src/assembler/assembler/AbstractMacroAssembler.h
@@ -166,13 +166,13 @@ public:
         void* m_ptr;
     };
 
-    // ImmPtr:
+    // TrustedImmPtr:
     //
     // A pointer sized immediate operand to an instruction - this is wrapped
     // in a class requiring explicit construction in order to differentiate
     // from pointers used as absolute addresses to memory operations
-    struct ImmPtr {
-        explicit ImmPtr(const void* value)
+    struct TrustedImmPtr {
+        explicit TrustedImmPtr(const void* value)
             : m_value(value)
         {
         }
@@ -185,14 +185,21 @@ public:
         const void* m_value;
     };
 
-    // Imm32:
+    struct ImmPtr : public TrustedImmPtr {
+        explicit ImmPtr(const void* value)
+            : TrustedImmPtr(value)
+        {
+        }
+    };
+ 
+    // TrustedImm32:
     //
     // A 32bit immediate operand to an instruction - this is wrapped in a
     // class requiring explicit construction in order to prevent RegisterIDs
     // (which are implemented as an enum) from accidentally being passed as
     // immediate values.
-    struct Imm32 {
-        explicit Imm32(int32_t value)
+    struct TrustedImm32 {
+        explicit TrustedImm32(int32_t value)
             : m_value(value)
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(false)
@@ -201,7 +208,7 @@ public:
         }
 
 #if !WTF_CPU_X86_64
-        explicit Imm32(ImmPtr ptr)
+        explicit TrustedImm32(TrustedImmPtr ptr)
             : m_value(ptr.asIntptr())
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(true)
@@ -223,6 +230,20 @@ public:
 #endif
     };
 
+
+    struct Imm32 : public TrustedImm32 {
+        explicit Imm32(int32_t value)
+            : TrustedImm32(value)
+        {
+        }
+#if !WTF_CPU_X86_64
+        explicit Imm32(TrustedImmPtr ptr)
+            : TrustedImm32(ptr)
+        {
+        }
+#endif
+    };
+
     struct ImmDouble {
         union {
             struct {
@@ -241,7 +262,6 @@ public:
         }
     };
 
-
     // Section 2: MacroAssembler code buffer handles
     //
     // The following types are used to reference items in the code buffer
@@ -273,7 +293,7 @@ public:
         
         bool isUsed() const { return m_label.isUsed(); }
         void used() { m_label.used(); }
-        bool isValid() const { return m_label.isValid(); }
+        bool isSet() const { return m_label.isValid(); }
     private:
         JmpDst m_label;
     };
@@ -296,6 +316,8 @@ public:
         {
         }
         
+        bool isSet() const { return m_label.isValid(); }
+
     private:
         JmpDst m_label;
     };
@@ -411,6 +433,20 @@ public:
     public:
         typedef js::Vector JumpVector;
 
+        JumpList() {}
+
+        JumpList(const JumpList &other)
+        {
+            m_jumps.append(other.m_jumps);
+        }
+
+        JumpList &operator=(const JumpList &other)
+        {
+            m_jumps.clear();
+            m_jumps.append(other.m_jumps);
+            return *this;
+        }
+
         void link(AbstractMacroAssembler* masm)
         {
             size_t size = m_jumps.length();
@@ -432,17 +468,22 @@ public:
             m_jumps.append(jump);
         }
         
-        void append(JumpList& other)
+        void append(const JumpList& other)
         {
             m_jumps.append(other.m_jumps.begin(), other.m_jumps.length());
         }
 
+        void clear()
+        {
+            m_jumps.clear();
+        }
+
         bool empty()
         {
             return !m_jumps.length();
         }
         
-        const JumpVector& jumps() { return m_jumps; }
+        const JumpVector& jumps() const { return m_jumps; }
 
     private:
         JumpVector m_jumps;
diff --git a/js/src/assembler/assembler/MacroAssembler.h b/js/src/assembler/assembler/MacroAssembler.h
index 73bda22a8ee2..38d5a31a2590 100644
--- a/js/src/assembler/assembler/MacroAssembler.h
+++ b/js/src/assembler/assembler/MacroAssembler.h
@@ -95,12 +95,12 @@ public:
         storePtr(src, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(Imm32 value, int index = 0)
+    void poke(TrustedImm32 value, int index = 0)
     {
         store32(value, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(ImmPtr imm, int index = 0)
+    void poke(TrustedImmPtr imm, int index = 0)
     {
         storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*))));
     }
@@ -117,7 +117,7 @@ public:
         branch32(cond, op1, op2).linkTo(target, this);
     }
 
-    void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target)
+    void branch32(Condition cond, RegisterID op1, TrustedImm32 imm, Label target)
     {
         branch32(cond, op1, imm).linkTo(target, this);
     }
@@ -288,17 +288,17 @@ public:
         store32(src, address);
     }
 
-    void storePtr(ImmPtr imm, ImplicitAddress address)
+    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(ImmPtr imm, BaseIndex address)
+    void storePtr(TrustedImmPtr imm, BaseIndex address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(ImmPtr imm, void* address)
+    void storePtr(TrustedImmPtr imm, void* address)
     {
         store32(Imm32(imm), address);
     }
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.cpp b/js/src/assembler/assembler/MacroAssemblerARM.cpp
index 14b4166b7ea9..065c98197395 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.cpp
+++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp
@@ -34,7 +34,7 @@
 
 #include "MacroAssemblerARM.h"
 
-#if WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID
+#if WTF_OS_LINUX || WTF_OS_ANDROID
 #include 
 #include 
 #include 
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h
index 7413411f4500..2630bce7a909 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -91,14 +91,14 @@ public:
         m_assembler.adds_r(dest, dest, src);
     }
 
-    void add32(Imm32 imm, Address address)
+    void add32(TrustedImm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         add32(imm, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
     }
 
-    void add32(Imm32 imm, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -173,7 +173,7 @@ public:
         m_assembler.orrs_r(dest, dest, src);
     }
 
-    void or32(Imm32 imm, RegisterID dest)
+    void or32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -211,12 +211,12 @@ public:
         m_assembler.subs_r(dest, dest, src);
     }
 
-    void sub32(Imm32 imm, RegisterID dest)
+    void sub32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
 
-    void sub32(Imm32 imm, Address address)
+    void sub32(TrustedImm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         sub32(imm, ARMRegisters::S1);
@@ -240,7 +240,7 @@ public:
         m_assembler.eors_r(dest, dest, src);
     }
 
-    void xor32(Imm32 imm, RegisterID dest)
+    void xor32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -380,7 +380,7 @@ public:
         m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset);
     }
 
-    void store32(Imm32 imm, BaseIndex address)
+    void store32(TrustedImm32 imm, BaseIndex address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -389,7 +389,7 @@ public:
         store32(ARMRegisters::S1, address);
     }
 
-    void store32(Imm32 imm, ImplicitAddress address)
+    void store32(TrustedImm32 imm, ImplicitAddress address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -404,7 +404,7 @@ public:
         m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
     }
 
-    void store32(Imm32 imm, void* address)
+    void store32(TrustedImm32 imm, void* address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address));
         if (imm.m_isPointer)
@@ -436,7 +436,7 @@ public:
         push(ARMRegisters::S0);
     }
 
-    void move(Imm32 imm, RegisterID dest)
+    void move(TrustedImm32 imm, RegisterID dest)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(dest, imm.m_value);
@@ -449,7 +449,7 @@ public:
         m_assembler.mov_r(dest, src);
     }
 
-    void move(ImmPtr imm, RegisterID dest)
+    void move(TrustedImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -485,7 +485,7 @@ public:
         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
     }
 
-    Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
+    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
     {
         ASSERT(left != ARMRegisters::S0);
         if (right.m_isPointer) {
@@ -500,21 +500,21 @@ public:
     // number of instructions emitted is constant, regardless of the argument
     // values. For ARM, this is identical to branch32WithPatch, except that it
     // does not generate a DataLabel32.
-    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
     // As branch32_force32, but allow the value ('right') to be patched.
-    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left != ARMRegisters::S1);
         dataLabel = moveWithPatch(right, ARMRegisters::S1);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left.base != ARMRegisters::S1);
         load32(left, ARMRegisters::S1);
@@ -534,19 +534,19 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, Address left, Imm32 right)
+    Jump branch32(Condition cond, Address left, TrustedImm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -828,7 +828,7 @@ public:
         setTest32(cond, address, mask, dest);
     }
 
-    void add32(Imm32 imm, RegisterID src, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -850,7 +850,7 @@ public:
         move(ARMRegisters::S1, dest);
     }
 
-    void add32(Imm32 imm, AbsoluteAddress address)
+    void add32(TrustedImm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -859,7 +859,7 @@ public:
         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
     }
 
-    void sub32(Imm32 imm, AbsoluteAddress address)
+    void sub32(TrustedImm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -880,7 +880,7 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
     {
         load32(left.m_ptr, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -908,14 +908,14 @@ public:
         return Call::fromTailJump(oldJump);
     }
 
-    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
     {
         DataLabelPtr dataLabel(this);
         m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value));
         return dataLabel;
     }
 
-    DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
+    DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
     {
         DataLabel32 dataLabel(this);
         m_assembler.ldr_un_imm(dest, initialValue.m_value);
@@ -937,7 +937,7 @@ public:
         return jump;
     }
 
-    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h
index 5492f8246a06..c23e9ea6655f 100644
--- a/js/src/assembler/assembler/MacroAssemblerARMv7.h
+++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h
@@ -131,12 +131,12 @@ public:
         m_assembler.add(dest, dest, src);
     }
 
-    void add32(Imm32 imm, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID dest)
     {
         add32(imm, dest, dest);
     }
 
-    void add32(Imm32 imm, RegisterID src, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -147,7 +147,7 @@ public:
         }
     }
 
-    void add32(Imm32 imm, Address address)
+    void add32(TrustedImm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -170,7 +170,7 @@ public:
         add32(dataTempRegister, dest);
     }
 
-    void add32(Imm32 imm, AbsoluteAddress address)
+    void add32(TrustedImm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -239,7 +239,7 @@ public:
         m_assembler.orr(dest, dest, src);
     }
 
-    void or32(Imm32 imm, RegisterID dest)
+    void or32(TrustedImm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -285,7 +285,7 @@ public:
         m_assembler.sub(dest, dest, src);
     }
 
-    void sub32(Imm32 imm, RegisterID dest)
+    void sub32(TrustedImm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -296,7 +296,7 @@ public:
         }
     }
 
-    void sub32(Imm32 imm, Address address)
+    void sub32(TrustedImm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -319,7 +319,7 @@ public:
         sub32(dataTempRegister, dest);
     }
 
-    void sub32(Imm32 imm, AbsoluteAddress address)
+    void sub32(TrustedImm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -341,7 +341,7 @@ public:
         m_assembler.eor(dest, dest, src);
     }
 
-    void xor32(Imm32 imm, RegisterID dest)
+    void xor32(TrustedImm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -486,7 +486,7 @@ public:
         store32(src, setupArmAddress(address));
     }
 
-    void store32(Imm32 imm, ImplicitAddress address)
+    void store32(TrustedImm32 imm, ImplicitAddress address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, setupArmAddress(address));
@@ -498,7 +498,7 @@ public:
         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
     }
 
-    void store32(Imm32 imm, void* address)
+    void store32(TrustedImm32 imm, void* address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, address);
@@ -667,7 +667,7 @@ public:
     //
     // Move values in registers.
 
-    void move(Imm32 imm, RegisterID dest)
+    void move(TrustedImm32 imm, RegisterID dest)
     {
         uint32_t value = imm.m_value;
 
@@ -693,7 +693,7 @@ public:
         m_assembler.mov(dest, src);
     }
 
-    void move(ImmPtr imm, RegisterID dest)
+    void move(TrustedImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -780,7 +780,7 @@ public:
         return Jump(makeBranch(cond));
     }
 
-    Jump branch32(Condition cond, RegisterID left, Imm32 right)
+    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
     {
         compare32(left, right);
         return Jump(makeBranch(cond));
@@ -798,21 +798,21 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, Address left, Imm32 right)
+    Jump branch32(Condition cond, Address left, TrustedImm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32WithUnalignedHalfWords(left, addressTempRegister);
@@ -825,7 +825,7 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left.m_ptr, addressTempRegister);
@@ -1065,13 +1065,13 @@ public:
         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
     }
 
-    DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst)
+    DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
     {
         moveFixedWidthEncoding(imm, dst);
         return DataLabel32(this);
     }
 
-    DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst)
+    DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
     {
         moveFixedWidthEncoding(Imm32(imm), dst);
         return DataLabelPtr(this);
@@ -1090,7 +1090,7 @@ public:
         return branch32(cond, addressTempRegister, dataTempRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
         store32(dataTempRegister, address);
@@ -1179,7 +1179,7 @@ protected:
         return addressTempRegister;
     }
 
-    void moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
+    void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
     {
         uint32_t value = imm.m_value;
         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
diff --git a/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
index 841fa9647128..6acdfd67a74d 100644
--- a/js/src/assembler/assembler/MacroAssemblerCodeRef.h
+++ b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
@@ -180,7 +180,8 @@ private:
 class MacroAssemblerCodeRef {
 public:
     MacroAssemblerCodeRef()
-        : m_size(0)
+        : m_executablePool(NULL),
+          m_size(0)
     {
     }
 
@@ -191,6 +192,20 @@ public:
     {
     }
 
+    // Release the code memory in this code ref.
+    void release()
+    {
+        if (!m_executablePool)
+            return;
+
+#if defined DEBUG && (defined WTF_CPU_X86 || defined WTF_CPU_X86_64) 
+        void *addr = m_code.executableAddress();
+        memset(addr, 0xcc, m_size);
+#endif
+        m_executablePool->release();
+        m_executablePool = NULL;
+    }
+
     MacroAssemblerCodePtr m_code;
     ExecutablePool* m_executablePool;
     size_t m_size;
diff --git a/js/src/assembler/assembler/MacroAssemblerSparc.h b/js/src/assembler/assembler/MacroAssemblerSparc.h
index 3bdd2d871b1b..91a8f0e16163 100644
--- a/js/src/assembler/assembler/MacroAssemblerSparc.h
+++ b/js/src/assembler/assembler/MacroAssemblerSparc.h
@@ -97,14 +97,14 @@ namespace JSC {
             m_assembler.addcc_r(dest, src, dest);
         }
 
-        void add32(Imm32 imm, Address address)
+        void add32(TrustedImm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             add32(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
         }
 
-        void add32(Imm32 imm, RegisterID dest)
+        void add32(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(dest, imm.m_value, dest);
@@ -126,7 +126,7 @@ namespace JSC {
             m_assembler.andcc_r(dest, SparcRegisters::g2, dest);
         }
 
-        void add32(Imm32 imm, RegisterID src, RegisterID dest)
+        void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(src, imm.m_value, dest);
@@ -194,7 +194,7 @@ namespace JSC {
             m_assembler.orcc_r(dest, src, dest);
         }
 
-        void or32(Imm32 imm, RegisterID dest)
+        void or32(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.orcc_imm(dest, imm.m_value, dest);
@@ -240,7 +240,7 @@ namespace JSC {
             m_assembler.subcc_r(dest, src, dest);
         }
 
-        void sub32(Imm32 imm, RegisterID dest)
+        void sub32(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.subcc_imm(dest, imm.m_value, dest);
@@ -250,7 +250,7 @@ namespace JSC {
             }
         }
 
-        void sub32(Imm32 imm, Address address)
+        void sub32(TrustedImm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -268,7 +268,7 @@ namespace JSC {
             m_assembler.xorcc_r(src, dest, dest);
         }
 
-        void xor32(Imm32 imm, RegisterID dest)
+        void xor32(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.xorcc_imm(dest, imm.m_value, dest);
@@ -548,7 +548,7 @@ namespace JSC {
             m_assembler.stw_r(src, address.base, SparcRegisters::g2);
         }
 
-        void store32(Imm32 imm, BaseIndex address)
+        void store32(TrustedImm32 imm, BaseIndex address)
         {
             m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
             add32(Imm32(address.offset), SparcRegisters::g2);
@@ -556,7 +556,7 @@ namespace JSC {
             m_assembler.stw_r(SparcRegisters::g3, SparcRegisters::g2, address.base);
         }
 
-        void store32(Imm32 imm, ImplicitAddress address)
+        void store32(TrustedImm32 imm, ImplicitAddress address)
         {
             m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -568,7 +568,7 @@ namespace JSC {
             m_assembler.stw_r(src, SparcRegisters::g0, SparcRegisters::g3);
         }
 
-        void store32(Imm32 imm, void* address)
+        void store32(TrustedImm32 imm, void* address)
         {
             move(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -598,7 +598,7 @@ namespace JSC {
             push(SparcRegisters::g2);
         }
 
-        void move(Imm32 imm, RegisterID dest)
+        void move(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.or_imm(SparcRegisters::g0, imm.m_value, dest);
@@ -611,7 +611,7 @@ namespace JSC {
             m_assembler.or_r(src, SparcRegisters::g0, dest);
         }
 
-        void move(ImmPtr imm, RegisterID dest)
+        void move(TrustedImmPtr imm, RegisterID dest)
         {
             move(Imm32(imm), dest);
         }
@@ -641,20 +641,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32_force32(Condition cond, RegisterID left, Imm32 right)
+        Jump branch32_force32(Condition cond, RegisterID left, TrustedImm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
             m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
+        Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g2);
             return branch32(cond, left, SparcRegisters::g2);
         }
 
-        Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
+        Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
         {
             // Always use move_nocheck, since the value is to be patched.
             dataLabel = DataLabel32(this);
@@ -669,7 +669,7 @@ namespace JSC {
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32(Condition cond, RegisterID left, Imm32 right)
+        Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
         {
             if (m_assembler.isimm13(right.m_value))
                 m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0);
@@ -692,20 +692,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, Address left, Imm32 right)
+        Jump branch32(Condition cond, Address left, TrustedImm32 right)
         {
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+        Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
         {
 
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
         {
             load32WithUnalignedHalfWords(left, SparcRegisters::g4);
             return branch32(cond, SparcRegisters::g4, right);
@@ -1052,7 +1052,7 @@ namespace JSC {
             store32(SparcRegisters::g2, address.m_ptr);
         }
 
-        void sub32(Imm32 imm, AbsoluteAddress address)
+        void sub32(TrustedImm32 imm, AbsoluteAddress address)
         {
             load32(address.m_ptr, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -1071,7 +1071,7 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+        Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
         {
             load32(left.m_ptr, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
@@ -1099,7 +1099,7 @@ namespace JSC {
             return Call::fromTailJump(oldJump);
         }
 
-        DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+        DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
         {
             DataLabelPtr dataLabel(this);
             Imm32 imm = Imm32(initialValue);
@@ -1107,7 +1107,7 @@ namespace JSC {
             return dataLabel;
         }
 
-        DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
+        DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
         {
             DataLabel32 dataLabel(this);
             m_assembler.move_nocheck(initialValue.m_value, dest);
@@ -1129,7 +1129,7 @@ namespace JSC {
             return jump;
         }
 
-        DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+        DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
         {
             DataLabelPtr dataLabel = moveWithPatch(initialValue, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86.h b/js/src/assembler/assembler/MacroAssemblerX86.h
index ee61b895a8fe..c6ab40f587fa 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(Imm32 imm, RegisterID src, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.leal_mr(imm.m_value, src, dest);
     }
@@ -90,12 +90,12 @@ public:
         m_assembler.andl_im(imm.m_value, address.m_ptr);
     }
     
-    void or32(Imm32 imm, AbsoluteAddress address)
+    void or32(TrustedImm32 imm, AbsoluteAddress address)
     {
         m_assembler.orl_im(imm.m_value, address.m_ptr);
     }
 
-    void sub32(Imm32 imm, AbsoluteAddress address)
+    void sub32(TrustedImm32 imm, AbsoluteAddress address)
     {
         m_assembler.subl_im(imm.m_value, address.m_ptr);
     }
@@ -148,7 +148,7 @@ public:
         addDouble(Address(srcDest), dest);
     }
 
-    void store32(Imm32 imm, void* address)
+    void store32(TrustedImm32 imm, void* address)
     {
         m_assembler.movl_i32m(imm.m_value, address);
     }
@@ -164,7 +164,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.m_ptr);
         return Jump(m_assembler.jCC(x86Condition(cond)));
@@ -186,7 +186,7 @@ public:
     }
 
 
-    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movl_i32r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -206,7 +206,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
     {
         m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base);
         return DataLabelPtr(this);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h
index 1ead9665f4e2..fa1b7ba8cb10 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86Common.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h
@@ -116,12 +116,12 @@ public:
         m_assembler.addl_rr(src, dest);
     }
 
-    void add32(Imm32 imm, Address address)
+    void add32(TrustedImm32 imm, Address address)
     {
         m_assembler.addl_im(imm.m_value, address.offset, address.base);
     }
 
-    void add32(Imm32 imm, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.addl_ir(imm.m_value, dest);
     }
@@ -234,7 +234,7 @@ public:
         m_assembler.orl_rr(src, dest);
     }
 
-    void or32(Imm32 imm, RegisterID dest)
+    void or32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.orl_ir(imm.m_value, dest);
     }
@@ -249,7 +249,7 @@ public:
         m_assembler.orl_mr(src.offset, src.base, dest);
     }
 
-    void or32(Imm32 imm, Address address)
+    void or32(TrustedImm32 imm, Address address)
     {
         m_assembler.orl_im(imm.m_value, address.offset, address.base);
     }
@@ -313,12 +313,12 @@ public:
         m_assembler.subl_rr(src, dest);
     }
     
-    void sub32(Imm32 imm, RegisterID dest)
+    void sub32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.subl_ir(imm.m_value, dest);
     }
     
-    void sub32(Imm32 imm, Address address)
+    void sub32(TrustedImm32 imm, Address address)
     {
         m_assembler.subl_im(imm.m_value, address.offset, address.base);
     }
@@ -339,12 +339,12 @@ public:
         m_assembler.xorl_rr(src, dest);
     }
 
-    void xor32(Imm32 imm, Address dest)
+    void xor32(TrustedImm32 imm, Address dest)
     {
         m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
     }
 
-    void xor32(Imm32 imm, RegisterID dest)
+    void xor32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.xorl_ir(imm.m_value, dest);
     }
@@ -468,7 +468,7 @@ public:
         m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(Imm32 imm, BaseIndex address)
+    void store32(TrustedImm32 imm, BaseIndex address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
@@ -483,7 +483,7 @@ public:
         m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(Imm32 imm, ImplicitAddress address)
+    void store32(TrustedImm32 imm, ImplicitAddress address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
     }
@@ -748,7 +748,7 @@ public:
     //
     // Move values in registers.
 
-    void move(Imm32 imm, RegisterID dest)
+    void move(TrustedImm32 imm, RegisterID dest)
     {
         // Note: on 64-bit the Imm32 value is zero extended into the register, it
         // may be useful to have a separate version that sign extends the value?
@@ -767,7 +767,7 @@ public:
             m_assembler.movq_rr(src, dest);
     }
 
-    void move(ImmPtr imm, RegisterID dest)
+    void move(TrustedImmPtr imm, RegisterID dest)
     {
         m_assembler.movq_i64r(imm.asIntptr(), dest);
     }
@@ -798,7 +798,7 @@ public:
             m_assembler.movl_rr(src, dest);
     }
 
-    void move(ImmPtr imm, RegisterID dest)
+    void move(TrustedImmPtr imm, RegisterID dest)
     {
         m_assembler.movl_i32r(imm.asIntptr(), dest);
     }
@@ -852,7 +852,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, RegisterID left, Imm32 right)
+    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
     {
         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
             m_assembler.testl_rr(left, left);
@@ -864,14 +864,14 @@ public:
     // Branch based on a 32-bit comparison, forcing the size of the
     // immediate operand to 32 bits in the native code stream to ensure that
     // the length of code emitted by this instruction is consistent.
-    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
     {
         m_assembler.cmpl_ir_force32(right.m_value, left);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
     // Branch and record a label after the comparison.
-    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
     {
         // Always use cmpl, since the value is to be patched.
         m_assembler.cmpl_ir_force32(right.m_value, left);
@@ -879,7 +879,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
     {
         m_assembler.cmpl_im_force32(right.m_value, left.offset, left.base);
         dataLabel = DataLabel32(this);
@@ -898,19 +898,19 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, Address left, Imm32 right)
+    Jump branch32(Condition cond, Address left, TrustedImm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         return branch32(cond, left, right);
     }
@@ -1369,7 +1369,7 @@ private:
     }
 
 #if WTF_CPU_X86
-#if WTF_PLATFORM_MAC
+#if WTF_OS_MAC_OS_X
 
     // All X86 Macs are guaranteed to support at least SSE2
     static bool isSSEPresent()
@@ -1382,7 +1382,7 @@ private:
         return true;
     }
 
-#else // PLATFORM(MAC)
+#else // OS(MAC_OS_X)
 
     static bool isSSEPresent()
     {
diff --git a/js/src/assembler/assembler/MacroAssemblerX86_64.h b/js/src/assembler/assembler/MacroAssemblerX86_64.h
index 7dadc6bcaf2e..a5038a930e56 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86_64.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(Imm32 imm, AbsoluteAddress address)
+    void add32(TrustedImm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         add32(imm, Address(scratchRegister));
@@ -72,13 +72,13 @@ public:
         and32(imm, Address(scratchRegister));
     }
     
-    void or32(Imm32 imm, AbsoluteAddress address)
+    void or32(TrustedImm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         or32(imm, Address(scratchRegister));
     }
 
-    void sub32(Imm32 imm, AbsoluteAddress address)
+    void sub32(TrustedImm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         sub32(imm, Address(scratchRegister));
@@ -114,7 +114,7 @@ public:
         m_assembler.cvtsq2sd_rr(srcDest, dest);
     }
 
-    void store32(Imm32 imm, void* address)
+    void store32(TrustedImm32 imm, void* address)
     {
         move(X86Registers::eax, scratchRegister);
         move(imm, X86Registers::eax);
@@ -311,7 +311,7 @@ public:
         m_assembler.movq_rm(src, address.offset, address.base);
     }
 
-    void storePtr(ImmPtr imm, BaseIndex address)
+    void storePtr(TrustedImmPtr imm, BaseIndex address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -341,7 +341,7 @@ public:
         }
     }
 
-    void storePtr(ImmPtr imm, ImplicitAddress address)
+    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -487,7 +487,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -505,7 +505,7 @@ public:
         return branchPtr(cond, left, scratchRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
         storePtr(scratchRegister, address);
diff --git a/js/src/assembler/jit/ExecutableAllocator.h b/js/src/assembler/jit/ExecutableAllocator.h
index a54a4dab143b..9cca26f48c99 100644
--- a/js/src/assembler/jit/ExecutableAllocator.h
+++ b/js/src/assembler/jit/ExecutableAllocator.h
@@ -52,16 +52,16 @@ extern  "C" void sync_instruction_memory(caddr_t v, u_int len);
 #endif
 #endif
 
-#if WTF_PLATFORM_IPHONE
+#if WTF_OS_IOS
 #include 
 #include 
 #endif
 
-#if WTF_PLATFORM_SYMBIAN
+#if WTF_OS_SYMBIAN
 #include 
 #endif
 
-#if WTF_CPU_MIPS && WTF_PLATFORM_LINUX
+#if WTF_CPU_MIPS && WTF_OS_LINUX
 #include 
 #endif
 
@@ -90,7 +90,7 @@ private:
     struct Allocation {
         char* pages;
         size_t size;
-#if WTF_PLATFORM_SYMBIAN
+#if WTF_OS_SYMBIAN
         RChunk* chunk;
 #endif
     };
@@ -269,6 +269,7 @@ private:
         return pool;
     }
 
+public:
     ExecutablePool* poolForSize(size_t n)
     {
 #ifndef DEBUG_STRESS_JSC_ALLOCATOR
@@ -327,7 +328,6 @@ private:
         return pool;
     }
 
-public:
 #if ENABLE_ASSEMBLER_WX_EXCLUSIVE
     static void makeWritable(void* start, size_t size)
     {
@@ -374,13 +374,13 @@ public:
         _flush_cache(reinterpret_cast(code), size, BCACHE);
 #endif
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
+#elif WTF_CPU_ARM_THUMB2 && WTF_OS_IOS
     static void cacheFlush(void* code, size_t size)
     {
         sys_dcache_flush(code, size);
         sys_icache_invalidate(code, size);
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_LINUX
+#elif WTF_CPU_ARM_THUMB2 && WTF_IOS
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
@@ -396,14 +396,14 @@ public:
             : "r" (code), "r" (reinterpret_cast(code) + size)
             : "r0", "r1", "r2");
     }
-#elif WTF_PLATFORM_SYMBIAN
+#elif WTF_OS_SYMBIAN
     static void cacheFlush(void* code, size_t size)
     {
         User::IMB_Range(code, static_cast(code) + size);
     }
-#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
     static __asm void cacheFlush(void* code, size_t size);
-#elif WTF_CPU_ARM_TRADITIONAL && (WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID) && WTF_COMPILER_GCC
+#elif WTF_CPU_ARM_TRADITIONAL && (WTF_OS_LINUX || WTF_OS_ANDROID) && WTF_COMPILER_GCC
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
diff --git a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
index ef9e27d92b47..675b604ae914 100644
--- a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_PLATFORM_OS2
+#if ENABLE_ASSEMBLER && WTF_OS_OS2
 
 #define INCL_DOS
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
index 50efd932e02a..e334626ccc2f 100644
--- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
@@ -25,7 +25,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
 
 #include 
 #include 
@@ -74,7 +74,7 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe
 }
 #endif
 
-#if WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
+#if WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
 __asm void ExecutableAllocator::cacheFlush(void* code, size_t size)
 {
     ARM
diff --git a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
index c66fa80fff12..f51c0d507877 100644
--- a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
@@ -22,7 +22,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_PLATFORM_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_OS_SYMBIAN
 
 #include 
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorWin.cpp b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
index f5775608f36f..da6e756cfa66 100644
--- a/js/src/assembler/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_PLATFORM_WIN_OS
+#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
 
 #include "jswin.h"
 
diff --git a/js/src/assembler/wtf/Platform.h b/js/src/assembler/wtf/Platform.h
index 68713cd4c810..217c9b8a1eec 100644
--- a/js/src/assembler/wtf/Platform.h
+++ b/js/src/assembler/wtf/Platform.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc.  All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,206 +28,267 @@
 #ifndef WTF_Platform_h
 #define WTF_Platform_h
 
-/* Either XX(YY) --> WTF_XX_YY  or  XX(YY) --> XX_YY, depending on XX
-
-   PLATFORM(YY) --> WTF_PLATFORM_YY
-   COMPILER(YY) --> WTF_COMPILER_YY
-   CPU(YY)      --> WTF_CPU_YY
-   OS(YY)       --> WTF_OS_YY
-   USE(YY)      --> WTF_USE_YY
-
-   HAVE(YY)     --> HAVE_YY
-   ENABLE(YY)   --> ENABLE_YY
-*/
-
 /* ==== PLATFORM handles OS, operating environment, graphics API, and
    CPU. This macro will be phased out in favor of platform adaptation
    macros, policy decision macros, and top-level port definitions. ==== */
-//#define PLATFORM(WTF_FEATURE) (defined(WTF_PLATFORM_##WTF_FEATURE)  && WTF_PLATFORM_##WTF_FEATURE)
+#define PLATFORM(WTF_FEATURE) (defined WTF_PLATFORM_##WTF_FEATURE  && WTF_PLATFORM_##WTF_FEATURE)
 
 
 /* ==== Platform adaptation macros: these describe properties of the target environment. ==== */
 
 /* COMPILER() - the compiler being used to build the project */
-//#define COMPILER(WTF_FEATURE) (defined(WTF_COMPILER_##WTF_FEATURE)  && WTF_COMPILER_##WTF_FEATURE)
+#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE  && WTF_COMPILER_##WTF_FEATURE)
 /* CPU() - the target CPU architecture */
-//#define CPU(WTF_FEATURE) (defined(WTF_CPU_##WTF_FEATURE)  && WTF_CPU_##WTF_FEATURE)
+#define CPU(WTF_FEATURE) (defined WTF_CPU_##WTF_FEATURE  && WTF_CPU_##WTF_FEATURE)
 /* HAVE() - specific system features (headers, functions or similar) that are present or not */
-//#define HAVE(WTF_FEATURE) (defined(HAVE_##WTF_FEATURE)  && HAVE_##WTF_FEATURE)
+#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE  && HAVE_##WTF_FEATURE)
 /* OS() - underlying operating system; only to be used for mandated low-level services like 
    virtual memory, not to choose a GUI toolkit */
-//#define OS(WTF_FEATURE) (defined(WTF_OS_##WTF_FEATURE)  && WTF_OS_##WTF_FEATURE)
+#define OS(WTF_FEATURE) (defined WTF_OS_##WTF_FEATURE  && WTF_OS_##WTF_FEATURE)
 
 
 /* ==== Policy decision macros: these define policy choices for a particular port. ==== */
 
 /* USE() - use a particular third-party library or optional OS service */
-//#define USE(WTF_FEATURE) (defined(WTF_USE_##WTF_FEATURE)  && WTF_USE_##WTF_FEATURE)
+#define USE(WTF_FEATURE) (defined WTF_USE_##WTF_FEATURE  && WTF_USE_##WTF_FEATURE)
 /* ENABLE() - turn on a specific feature of WebKit */
-//#define ENABLE(WTF_FEATURE) (defined(ENABLE_##WTF_FEATURE)  && ENABLE_##WTF_FEATURE)
+#define ENABLE(WTF_FEATURE) (defined ENABLE_##WTF_FEATURE  && ENABLE_##WTF_FEATURE)
 
 
 
 /* ==== COMPILER() - the compiler being used to build the project ==== */
 
-/* COMPILER(MSVC) Microsoft Visual C++ */
-/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/
+/* WTF_COMPILER_MSVC Microsoft Visual C++ */
+/* WTF_COMPILER_MSVC7_OR_LOWER Microsoft Visual C++ 2003 or lower*/
+/* WTF_COMPILER_MSVC9_OR_LOWER Microsoft Visual C++ 2008 or lower*/
 #if defined(_MSC_VER)
 #define WTF_COMPILER_MSVC 1
 #if _MSC_VER < 1400
-#define WTF_COMPILER_MSVC7 1
+#define WTF_COMPILER_MSVC7_OR_LOWER 1
+#elif _MSC_VER < 1600
+#define WTF_COMPILER_MSVC9_OR_LOWER 1
 #endif
 #endif
 
-/* COMPILER(RVCT)  - ARM RealView Compilation Tools */
+/* WTF_COMPILER_RVCT  - ARM RealView Compilation Tools */
+/* WTF_COMPILER_RVCT4_OR_GREATER - ARM RealView Compilation Tools 4.0 or greater */
 #if defined(__CC_ARM) || defined(__ARMCC__)
 #define WTF_COMPILER_RVCT 1
+#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) (__ARMCC_VERSION >= (major * 100000 + minor * 10000 + patch * 1000 + build))
+#else
+/* Define this for !RVCT compilers, just so we can write things like RVCT_VERSION_AT_LEAST(3, 0, 0, 0). */
+#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) 0
 #endif
 
-/* COMPILER(GCC) - GNU Compiler Collection */
+/* WTF_COMPILER_GCC - GNU Compiler Collection */
 /* --gnu option of the RVCT compiler also defines __GNUC__ */
 #if defined(__GNUC__) && !WTF_COMPILER_RVCT
 #define WTF_COMPILER_GCC 1
 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch))
+#else
+/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */
+#define GCC_VERSION_AT_LEAST(major, minor, patch) 0
 #endif
 
-/* COMPILER(MINGW) - MinGW GCC */
-#if defined(MINGW) || defined(__MINGW32__)
+/* WTF_COMPILER_MINGW - MinGW GCC */
+/* WTF_COMPILER_MINGW64 - mingw-w64 GCC - only used as additional check to exclude mingw.org specific functions */
+#if defined(__MINGW32__)
 #define WTF_COMPILER_MINGW 1
-#endif
+#include <_mingw.h> /* private MinGW header */
+    #if defined(__MINGW64_VERSION_MAJOR) /* best way to check for mingw-w64 vs mingw.org */
+        #define WTF_COMPILER_MINGW64 1
+    #endif /* __MINGW64_VERSION_MAJOR */
+#endif /* __MINGW32__ */
 
-/* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */
+/* WTF_COMPILER_WINSCW - CodeWarrior for Symbian emulator */
 #if defined(__WINSCW__)
 #define WTF_COMPILER_WINSCW 1
+/* cross-compiling, it is not really windows */
+#undef WIN32
+#undef _WIN32
 #endif
 
-/* COMPILER(SUNPRO) - Sun Studio for Solaris */
-#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-#define WTF_COMPILER_SUNPRO 1
+/* WTF_COMPILER_INTEL - Intel C++ Compiler */
+#if defined(__INTEL_COMPILER)
+#define WTF_COMPILER_INTEL 1
 #endif
 
+/* WTF_COMPILER_SUNCC */
+#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
+#define WTF_COMPILER_SUNCC 1
+#endif
 
 /* ==== CPU() - the target CPU architecture ==== */
 
-/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */
+/* This also defines WTF_CPU_BIG_ENDIAN or WTF_CPU_MIDDLE_ENDIAN or neither, as appropriate. */
 
-
-/* CPU(ALPHA) - DEC Alpha */
+/* WTF_CPU_ALPHA - DEC Alpha */
 #if defined(__alpha__)
 #define WTF_CPU_ALPHA 1
 #endif
 
-/* CPU(IA64) - Itanium / IA-64 */
+/* WTF_CPU_IA64 - Itanium / IA-64 */
 #if defined(__ia64__)
 #define WTF_CPU_IA64 1
+/* 32-bit mode on Itanium */
+#if !defined(__LP64__)
+#define WTF_CPU_IA64_32 1
+#endif
 #endif
 
-/* CPU(PPC) - PowerPC 32-bit */
+/* WTF_CPU_MIPS - MIPS 32-bit */
+/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now.  */
+#if (defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_)) \
+    && defined(_ABIO32)
+#define WTF_CPU_MIPS 1
+#if defined(__MIPSEB__)
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+#define WTF_MIPS_PIC (defined __PIC__)
+#define WTF_MIPS_ARCH __mips
+#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v)
+#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v)
+#define WTF_MIPS_ARCH_REV __mips_isa_rev
+#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
+#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float)
+#define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64)
+/* MIPS requires allocators to use aligned memory */
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
+#endif /* MIPS */
+
+/* WTF_CPU_PPC - PowerPC 32-bit */
 #if   defined(__ppc__)     \
-   || defined(__PPC__)     \
-   || defined(__powerpc__) \
-   || defined(__powerpc)   \
-   || defined(__POWERPC__) \
-   || defined(_M_PPC)      \
-   || defined(__PPC)
+    || defined(__PPC__)     \
+    || defined(__powerpc__) \
+    || defined(__powerpc)   \
+    || defined(__POWERPC__) \
+    || defined(_M_PPC)      \
+    || defined(__PPC)
 #define WTF_CPU_PPC 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* CPU(PPC64) - PowerPC 64-bit */
+/* WTF_CPU_PPC64 - PowerPC 64-bit */
 #if   defined(__ppc64__) \
-   || defined(__PPC64__)
+    || defined(__PPC64__)
 #define WTF_CPU_PPC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* CPU(SH4) - SuperH SH-4 */
+/* WTF_CPU_SH4 - SuperH SH-4 */
 #if defined(__SH4__)
 #define WTF_CPU_SH4 1
 #endif
 
-/* CPU(SPARC32) - SPARC 32-bit */
+/* WTF_CPU_SPARC32 - SPARC 32-bit */
 #if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8)
 #define WTF_CPU_SPARC32 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* CPU(SPARC64) - SPARC 64-bit */
+/* WTF_CPU_SPARC64 - SPARC 64-bit */
 #if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)
 #define WTF_CPU_SPARC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */
+/* WTF_CPU_SPARC - any SPARC, true for WTF_CPU_SPARC32 and WTF_CPU_SPARC64 */
 #if WTF_CPU_SPARC32 || WTF_CPU_SPARC64
 #define WTF_CPU_SPARC 1
 #endif
 
-/* CPU(X86) - i386 / x86 32-bit */
+/* WTF_CPU_S390X - S390 64-bit */
+#if defined(__s390x__)
+#define WTF_CPU_S390X 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* WTF_CPU_S390 - S390 32-bit */
+#if defined(__s390__)
+#define WTF_CPU_S390 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* WTF_CPU_X86 - i386 / x86 32-bit */
 #if   defined(__i386__) \
-   || defined(i386)     \
-   || defined(_M_IX86)  \
-   || defined(_X86_)    \
-   || defined(__THW_INTEL)
+    || defined(i386)     \
+    || defined(_M_IX86)  \
+    || defined(_X86_)    \
+    || defined(__THW_INTEL)
 #define WTF_CPU_X86 1
 #endif
 
-/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */
+/* WTF_CPU_X86_64 - AMD64 / Intel64 / x86_64 64-bit */
 #if   defined(__x86_64__) \
-   || defined(_M_X64)
+    || defined(_M_X64)
 #define WTF_CPU_X86_64 1
 #endif
 
-/* CPU(ARM) - ARM, any version*/
+/* WTF_CPU_ARM - ARM, any version*/
 #if   defined(arm) \
-   || defined(__arm__)
+    || defined(__arm__) \
+    || defined(ARM) \
+    || defined(_ARM_)
 #define WTF_CPU_ARM 1
 
-#if defined(__ARMEB__)
+#if defined(__ARMEB__) || (WTF_COMPILER_RVCT && defined(__BIG_ENDIAN))
 #define WTF_CPU_BIG_ENDIAN 1
 
 #elif !defined(__ARM_EABI__) \
-   && !defined(__EABI__) \
-   && !defined(__VFP_FP__) \
-   && !defined(ANDROID)
+    && !defined(__EABI__) \
+    && !defined(__VFP_FP__) \
+    && !defined(_WIN32_WCE) \
+    && !defined(ANDROID)
 #define WTF_CPU_MIDDLE_ENDIAN 1
 
 #endif
 
-#define WTF_ARM_ARCH_AT_LEAST(N) (WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= N)
+#define WTF_ARM_ARCH_AT_LEAST(N) (CPU(ARM) && WTF_ARM_ARCH_VERSION >= N)
 
 /* Set WTF_ARM_ARCH_VERSION */
 #if   defined(__ARM_ARCH_4__) \
-   || defined(__ARM_ARCH_4T__) \
-   || defined(__MARM_ARMV4__) \
-   || defined(_ARMV4I_)
+    || defined(__ARM_ARCH_4T__) \
+    || defined(__MARM_ARMV4__) \
+    || defined(_ARMV4I_)
 #define WTF_ARM_ARCH_VERSION 4
 
 #elif defined(__ARM_ARCH_5__) \
-   || defined(__ARM_ARCH_5T__) \
-   || defined(__ARM_ARCH_5E__) \
-   || defined(__ARM_ARCH_5TE__) \
-   || defined(__ARM_ARCH_5TEJ__) \
-   || defined(__MARM_ARMV5__)
+    || defined(__ARM_ARCH_5T__) \
+    || defined(__MARM_ARMV5__)
 #define WTF_ARM_ARCH_VERSION 5
 
+#elif defined(__ARM_ARCH_5E__) \
+    || defined(__ARM_ARCH_5TE__) \
+    || defined(__ARM_ARCH_5TEJ__)
+#define WTF_ARM_ARCH_VERSION 5
+/*ARMv5TE requires allocators to use aligned memory*/
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
+
 #elif defined(__ARM_ARCH_6__) \
-   || defined(__ARM_ARCH_6J__) \
-   || defined(__ARM_ARCH_6K__) \
-   || defined(__ARM_ARCH_6Z__) \
-   || defined(__ARM_ARCH_6ZK__) \
-   || defined(__ARM_ARCH_6T2__) \
-   || defined(__ARMV6__)
+    || defined(__ARM_ARCH_6J__) \
+    || defined(__ARM_ARCH_6K__) \
+    || defined(__ARM_ARCH_6Z__) \
+    || defined(__ARM_ARCH_6ZK__) \
+    || defined(__ARM_ARCH_6T2__) \
+    || defined(__ARMV6__)
 #define WTF_ARM_ARCH_VERSION 6
 
 #elif defined(__ARM_ARCH_7A__) \
-   || defined(__ARM_ARCH_7R__)
+    || defined(__ARM_ARCH_7R__)
 #define WTF_ARM_ARCH_VERSION 7
 
 /* RVCT sets _TARGET_ARCH_ARM */
 #elif defined(__TARGET_ARCH_ARM)
 #define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM
 
+#if defined(__TARGET_ARCH_5E) \
+    || defined(__TARGET_ARCH_5TE) \
+    || defined(__TARGET_ARCH_5TEJ)
+/*ARMv5TE requires allocators to use aligned memory*/
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
+#endif
+
 #else
 #define WTF_ARM_ARCH_VERSION 0
 
@@ -237,22 +299,22 @@
 #define WTF_THUMB_ARCH_VERSION 1
 
 #elif defined(__ARM_ARCH_5T__) \
-   || defined(__ARM_ARCH_5TE__) \
-   || defined(__ARM_ARCH_5TEJ__)
+    || defined(__ARM_ARCH_5TE__) \
+    || defined(__ARM_ARCH_5TEJ__)
 #define WTF_THUMB_ARCH_VERSION 2
 
 #elif defined(__ARM_ARCH_6J__) \
-   || defined(__ARM_ARCH_6K__) \
-   || defined(__ARM_ARCH_6Z__) \
-   || defined(__ARM_ARCH_6ZK__) \
-   || defined(__ARM_ARCH_6M__)
+    || defined(__ARM_ARCH_6K__) \
+    || defined(__ARM_ARCH_6Z__) \
+    || defined(__ARM_ARCH_6ZK__) \
+    || defined(__ARM_ARCH_6M__)
 #define WTF_THUMB_ARCH_VERSION 3
 
 #elif defined(__ARM_ARCH_6T2__) \
-   || defined(__ARM_ARCH_7__) \
-   || defined(__ARM_ARCH_7A__) \
-   || defined(__ARM_ARCH_7R__) \
-   || defined(__ARM_ARCH_7M__)
+    || defined(__ARM_ARCH_7__) \
+    || defined(__ARM_ARCH_7A__) \
+    || defined(__ARM_ARCH_7R__) \
+    || defined(__ARM_ARCH_7M__)
 #define WTF_THUMB_ARCH_VERSION 4
 
 /* RVCT sets __TARGET_ARCH_THUMB */
@@ -264,22 +326,22 @@
 #endif
 
 
-/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */
+/* WTF_CPU_ARMV5_OR_LOWER - ARM instruction set v5 or earlier */
 /* On ARMv5 and below the natural alignment is required. 
    And there are some other differences for v5 or earlier. */
-#if !defined(ARMV5_OR_LOWER) /* && !CPU_ARM_ARCH_AT_LEAST(6) */
+#if !defined(ARMV5_OR_LOWER) && !WTF_ARM_ARCH_AT_LEAST(6)
 #define WTF_CPU_ARMV5_OR_LOWER 1
 #endif
 
 
-/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */
-/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */
+/* WTF_CPU_ARM_TRADITIONAL - Thumb2 is not available, only traditional ARM (v4 or greater) */
+/* WTF_CPU_ARM_THUMB2 - Thumb2 instruction set is available */
 /* Only one of these will be defined. */
 #if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
 #  if defined(thumb2) || defined(__thumb2__) \
-  || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
-#    define WTF_CPU_ARM_TRADITIONAL 1
-#    define WTF_CPU_ARM_THUMB2 0
+    || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
+#    define WTF_CPU_ARM_TRADITIONAL 0
+#    define WTF_CPU_ARM_THUMB2 1
 #  elif WTF_ARM_ARCH_AT_LEAST(4)
 #    define WTF_CPU_ARM_TRADITIONAL 1
 #    define WTF_CPU_ARM_THUMB2 0
@@ -288,19 +350,36 @@
 #  endif
 #elif WTF_CPU_ARM_TRADITIONAL && WTF_CPU_ARM_THUMB2 /* Sanity Check */
 #  error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms"
-#endif // !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
+#endif /* !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) */
+
+#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON)
+#define WTF_CPU_ARM_NEON 1
+#endif
 
 #endif /* ARM */
 
+#if WTF_CPU_ARM || WTF_CPU_MIPS
+#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
+#endif
 
+/* ==== OS() - underlying operating system; only to be used for mandated low-level services like 
+   virtual memory, not to choose a GUI toolkit ==== */
 
-/* Operating systems - low-level dependencies */
+/* WTF_OS_ANDROID - Android */
+#ifdef ANDROID
+#define WTF_OS_ANDROID 1
+#endif
 
-/* PLATFORM(DARWIN) */
-/* Operating system level dependencies for Mac OS X / Darwin that should */
-/* be used regardless of operating environment */
+/* WTF_OS_AIX - AIX */
+#ifdef _AIX
+#define WTF_OS_AIX 1
+#endif
+
+/* WTF_OS_DARWIN - Any Darwin-based OS, including Mac OS X and iPhone OS */
 #ifdef __APPLE__
-#define WTF_PLATFORM_DARWIN 1
+#define WTF_OS_DARWIN 1
+
+/* FIXME: BUILDING_ON_.., and TARGETING... macros should be folded into the OS() system */
 #include 
 #if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
 #define BUILDING_ON_TIGER 1
@@ -317,98 +396,97 @@
 #define TARGETING_SNOW_LEOPARD 1
 #endif
 #include 
+
 #endif
 
-/* PLATFORM(WIN_OS) */
-/* Operating system level dependencies for Windows that should be used */
-/* regardless of operating environment */
-#if defined(WIN32) || defined(_WIN32)
-#define WTF_PLATFORM_WIN_OS 1
+/* WTF_OS_IOS - iOS */
+/* WTF_OS_MAC_OS_X - Mac OS X (not including iOS) */
+#if WTF_OS_DARWIN && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED)  \
+    || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)                   \
+    || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR))
+#define WTF_OS_IOS 1
+#elif WTF_OS_DARWIN && defined(TARGET_OS_MAC) && TARGET_OS_MAC
+#define WTF_OS_MAC_OS_X 1
 #endif
 
-/* PLATFORM(LINUX) */
-/* Operating system level dependencies for Linux-like systems that */
-/* should be used regardless of operating environment */
+/* WTF_OS_FREEBSD - FreeBSD */
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#define WTF_OS_FREEBSD 1
+#endif
+
+/* WTF_OS_HAIKU - Haiku */
+#ifdef __HAIKU__
+#define WTF_OS_HAIKU 1
+#endif
+
+/* WTF_OS_LINUX - Linux */
 #ifdef __linux__
-#define WTF_PLATFORM_LINUX 1
+#define WTF_OS_LINUX 1
 #endif
 
-/* PLATFORM(FREEBSD) */
-/* Operating system level dependencies for FreeBSD-like systems that */
-/* should be used regardless of operating environment */
-#ifdef __FreeBSD__
-#define WTF_PLATFORM_FREEBSD 1
-#endif
-
-/* PLATFORM(OPENBSD) */
-/* Operating system level dependencies for OpenBSD systems that */
-/* should be used regardless of operating environment */
-#ifdef __OpenBSD__
-#define WTF_PLATFORM_OPENBSD 1
-#endif
-
-/* PLATFORM(SOLARIS) */
-/* Operating system level dependencies for Solaris that should be used */
-/* regardless of operating environment */
-#if defined(sun) || defined(__sun)
-#define WTF_PLATFORM_SOLARIS 1
-#endif
-
-/* PLATFORM(OS2) */
-/* Operating system level dependencies for OS/2 that should be used */
-/* regardless of operating environment */
-#if defined(OS2) || defined(__OS2__)
-#define WTF_PLATFORM_OS2 1
-#endif
-
-#if defined (__SYMBIAN32__)
-/* we are cross-compiling, it is not really windows */
-#undef WTF_PLATFORM_WIN_OS
-#undef WTF_PLATFORM_WIN
-#define WTF_PLATFORM_SYMBIAN 1
-#endif
-
-
-/* PLATFORM(NETBSD) */
-/* Operating system level dependencies for NetBSD that should be used */
-/* regardless of operating environment */
+/* WTF_OS_NETBSD - NetBSD */
 #if defined(__NetBSD__)
-#define WTF_PLATFORM_NETBSD 1
+#define WTF_OS_NETBSD 1
 #endif
 
-/* PLATFORM(QNX) */
-/* Operating system level dependencies for QNX that should be used */
-/* regardless of operating environment */
+/* WTF_OS_OPENBSD - OpenBSD */
+#ifdef __OpenBSD__
+#define WTF_OS_OPENBSD 1
+#endif
+
+/* WTF_OS_QNX - QNX */
 #if defined(__QNXNTO__)
-#define WTF_PLATFORM_QNX 1
+#define WTF_OS_QNX 1
 #endif
 
-/* PLATFORM(UNIX) */
-/* Operating system level dependencies for Unix-like systems that */
-/* should be used regardless of operating environment */
-#if   WTF_PLATFORM_DARWIN     \
-   || WTF_PLATFORM_FREEBSD    \
-   || WTF_PLATFORM_SYMBIAN    \
-   || WTF_PLATFORM_NETBSD     \
-   || defined(unix)        \
-   || defined(__unix)      \
-   || defined(__unix__)    \
-   || defined(_AIX)        \
-   || defined(__HAIKU__)   \
-   || defined(__QNXNTO__)  \
-   || defined(ANDROID)
-#define WTF_PLATFORM_UNIX 1
+/* WTF_OS_SOLARIS - Solaris */
+#if defined(sun) || defined(__sun)
+#define WTF_OS_SOLARIS 1
+#endif
+
+/* WTF_OS_WINCE - Windows CE; note that for this platform WTF_OS_WINDOWS is also defined */
+#if defined(_WIN32_WCE)
+#define WTF_OS_WINCE 1
+#endif
+
+/* WTF_OS_WINDOWS - Any version of Windows */
+#if defined(WIN32) || defined(_WIN32)
+#define WTF_OS_WINDOWS 1
+#endif
+
+/* WTF_OS_SYMBIAN - Symbian */
+#if defined (__SYMBIAN32__)
+#define WTF_OS_SYMBIAN 1
+#endif
+
+/* WTF_OS_UNIX - Any Unix-like system */
+#if   WTF_OS_AIX              \
+    || WTF_OS_ANDROID          \
+    || WTF_OS_DARWIN           \
+    || WTF_OS_FREEBSD          \
+    || WTF_OS_HAIKU            \
+    || WTF_OS_LINUX            \
+    || WTF_OS_NETBSD           \
+    || WTF_OS_OPENBSD          \
+    || WTF_OS_QNX              \
+    || WTF_OS_SOLARIS          \
+    || WTF_OS_SYMBIAN          \
+    || defined(unix)        \
+    || defined(__unix)      \
+    || defined(__unix__)
+#define WTF_OS_UNIX 1
 #endif
 
 /* Operating environments */
 
-/* PLATFORM(CHROMIUM) */
-/* PLATFORM(QT) */
-/* PLATFORM(WX) */
-/* PLATFORM(GTK) */
-/* PLATFORM(HAIKU) */
-/* PLATFORM(MAC) */
-/* PLATFORM(WIN) */
+/* FIXME: these are all mixes of OS, operating environment and policy choices. */
+/* WTF_PLATFORM_CHROMIUM */
+/* WTF_PLATFORM_QT */
+/* WTF_PLATFORM_WX */
+/* WTF_PLATFORM_GTK */
+/* WTF_PLATFORM_HAIKU */
+/* WTF_PLATFORM_MAC */
+/* WTF_PLATFORM_WIN */
 #if defined(BUILDING_CHROMIUM__)
 #define WTF_PLATFORM_CHROMIUM 1
 #elif defined(BUILDING_QT__)
@@ -419,142 +497,229 @@
 #define WTF_PLATFORM_GTK 1
 #elif defined(BUILDING_HAIKU__)
 #define WTF_PLATFORM_HAIKU 1
-#elif WTF_PLATFORM_DARWIN
+#elif defined(BUILDING_BREWMP__)
+#define WTF_PLATFORM_BREWMP 1
+#if defined(AEE_SIMULATOR)
+#define WTF_PLATFORM_BREWMP_SIMULATOR 1
+#else
+#define WTF_PLATFORM_BREWMP_SIMULATOR 0
+#endif
+#undef WTF_OS_WINDOWS
+#undef WTF_PLATFORM_WIN
+#elif WTF_OS_DARWIN
 #define WTF_PLATFORM_MAC 1
-#elif WTF_PLATFORM_WIN_OS
+#elif WTF_OS_WINDOWS
 #define WTF_PLATFORM_WIN 1
 #endif
 
-/* PLATFORM(IPHONE) */
+/* WTF_PLATFORM_IOS */
+/* FIXME: this is sometimes used as an OS switch and sometimes for higher-level things */
 #if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
-#define WTF_PLATFORM_IPHONE 1
+#define WTF_PLATFORM_IOS 1
 #endif
 
-/* PLATFORM(IPHONE_SIMULATOR) */
+/* WTF_PLATFORM_IOS_SIMULATOR */
 #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
-#define WTF_PLATFORM_IPHONE 1
-#define WTF_PLATFORM_IPHONE_SIMULATOR 1
+#define WTF_PLATFORM_IOS 1
+#define WTF_PLATFORM_IOS_SIMULATOR 1
 #else
-#define WTF_PLATFORM_IPHONE_SIMULATOR 0
+#define WTF_PLATFORM_IOS_SIMULATOR 0
 #endif
 
-#if !defined(WTF_PLATFORM_IPHONE)
-#define WTF_PLATFORM_IPHONE 0
+#if !defined(WTF_PLATFORM_IOS)
+#define WTF_PLATFORM_IOS 0
 #endif
 
-/* PLATFORM(ANDROID) */
+/* WTF_PLATFORM_ANDROID */
+/* FIXME: this is sometimes used as an OS() switch, and other times to drive
+   policy choices */
 #if defined(ANDROID)
 #define WTF_PLATFORM_ANDROID 1
 #endif
 
 /* Graphics engines */
 
-/* PLATFORM(CG) and PLATFORM(CI) */
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_IPHONE
-#define WTF_PLATFORM_CG 1
+/* WTF_USE_CG and WTF_PLATFORM_CI */
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS
+#define WTF_USE_CG 1
 #endif
-#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
-#define WTF_PLATFORM_CI 1
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS || (WTF_PLATFORM_WIN && WTF_USE_CG)
+#define WTF_USE_CA 1
 #endif
 
-/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */
+/* WTF_USE_SKIA for Win/Linux, CG for Mac */
 #if WTF_PLATFORM_CHROMIUM
-#if WTF_PLATFORM_DARWIN
-#define WTF_PLATFORM_CG 1
-#define WTF_PLATFORM_CI 1
+#if WTF_OS_DARWIN
+#define WTF_USE_CG 1
 #define WTF_USE_ATSUI 1
 #define WTF_USE_CORE_TEXT 1
+#define WTF_USE_ICCJPEG 1
 #else
-#define WTF_PLATFORM_SKIA 1
+#define WTF_USE_SKIA 1
+#define WTF_USE_CHROMIUM_NET 1
 #endif
 #endif
 
+#if WTF_PLATFORM_BREWMP
+#define WTF_USE_SKIA 1
+#endif
+
 #if WTF_PLATFORM_GTK
-#define WTF_PLATFORM_CAIRO 1
+#define WTF_USE_CAIRO 1
 #endif
 
 
-#if (WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_OS2 || (WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
+#if WTF_OS_WINCE
+#include 
+#define WTF_USE_MERSENNE_TWISTER_19937 1
+#endif
+
+#if WTF_PLATFORM_QT && WTF_OS_UNIX && !WTF_OS_SYMBIAN && !WTF_OS_DARWIN
+#define WTF_USE_PTHREAD_BASED_QT 1
+#endif
+
+#if (WTF_PLATFORM_GTK || WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || (WTF_PLATFORM_QT && (WTF_OS_DARWIN || WTF_USE_PTHREAD_BASED_QT) && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
 #define ENABLE_JSC_MULTIPLE_THREADS 1
 #endif
 
+#if ENABLE_JSC_MULTIPLE_THREADS
+#define ENABLE_WTF_MULTIPLE_THREADS 1
+#endif
+
 /* On Windows, use QueryPerformanceCounter by default */
-#if WTF_PLATFORM_WIN_OS
+#if WTF_OS_WINDOWS
 #define WTF_USE_QUERY_PERFORMANCE_COUNTER  1
 #endif
 
+#if WTF_OS_WINCE && !WTF_PLATFORM_QT
+#define NOMINMAX       /* Windows min and max conflict with standard macros */
+#define NOSHLWAPI      /* shlwapi.h not available on WinCe */
+
+/* MSDN documentation says these functions are provided with uspce.lib.  But we cannot find this file. */
+#define __usp10__      /* disable "usp10.h" */
+
+#define _INC_ASSERT    /* disable "assert.h" */
+#define assert(x)
+
+#endif  /* WTF_OS_WINCE && !WTF_PLATFORM_QT */
+
 #if WTF_PLATFORM_QT
 #define WTF_USE_QT4_UNICODE 1
+#elif WTF_OS_WINCE
+#define WTF_USE_WINCE_UNICODE 1
+#elif WTF_PLATFORM_BREWMP
+#define WTF_USE_BREWMP_UNICODE 1
 #elif WTF_PLATFORM_GTK
 /* The GTK+ Unicode backend is configurable */
 #else
 #define WTF_USE_ICU_UNICODE 1
 #endif
 
-#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
-#define WTF_PLATFORM_CF 1
-#define WTF_USE_PTHREADS 1
-#define HAVE_PTHREAD_RWLOCK 1
+#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && WTF_CPU_X86_64
 #define WTF_USE_PLUGIN_HOST_PROCESS 1
 #endif
-#if !defined(ENABLE_MAC_JAVA_BRIDGE)
-#define ENABLE_MAC_JAVA_BRIDGE 1
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#define ENABLE_GESTURE_EVENTS 1
+#define ENABLE_RUBBER_BANDING 1
+#define WTF_USE_WK_SCROLLBAR_PAINTER 1
+#endif
+#if !defined(ENABLE_JAVA_BRIDGE)
+#define ENABLE_JAVA_BRIDGE 1
 #endif
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 1
 #endif
+#define WTF_USE_CF 1
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
 #define HAVE_READLINE 1
 #define HAVE_RUNLOOP_TIMER 1
-#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */
+#define ENABLE_FULLSCREEN_API 1
+#define ENABLE_SMOOTH_SCROLLING 1
+#define ENABLE_WEB_ARCHIVE 1
+#endif /* WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS */
 
-#if WTF_PLATFORM_CHROMIUM && WTF_PLATFORM_DARWIN
-#define WTF_PLATFORM_CF 1
+#if WTF_PLATFORM_CHROMIUM && WTF_OS_DARWIN
+#define WTF_USE_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
 #endif
 
-#if WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN
-#define WTF_PLATFORM_CF 1
+#if WTF_PLATFORM_BREWMP
+#define ENABLE_SINGLE_THREADED 1
 #endif
 
-#if WTF_PLATFORM_IPHONE
+#if WTF_PLATFORM_QT && WTF_OS_DARWIN
+#define WTF_USE_CF 1
+#endif
+
+#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER) && !WTF_PLATFORM_GTK && !WTF_PLATFORM_QT
+#define ENABLE_PURGEABLE_MEMORY 1
+#endif
+
+#if WTF_PLATFORM_IOS
 #define ENABLE_CONTEXT_MENUS 0
 #define ENABLE_DRAG_SUPPORT 0
+#define ENABLE_DATA_TRANSFER_ITEMS 0
 #define ENABLE_FTPDIR 1
 #define ENABLE_GEOLOCATION 1
 #define ENABLE_ICONDATABASE 0
 #define ENABLE_INSPECTOR 0
-#define ENABLE_MAC_JAVA_BRIDGE 0
+#define ENABLE_JAVA_BRIDGE 0
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #define ENABLE_ORIENTATION_EVENTS 1
 #define ENABLE_REPAINT_THROTTLING 1
 #define HAVE_READLINE 1
-#define WTF_PLATFORM_CF 1
+#define WTF_USE_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
+#define ENABLE_WEB_ARCHIVE 1
 #endif
 
 #if WTF_PLATFORM_ANDROID
 #define WTF_USE_PTHREADS 1
-#define WTF_PLATFORM_SGL 1
 #define USE_SYSTEM_MALLOC 1
-#define ENABLE_MAC_JAVA_BRIDGE 1
+#define ENABLE_JAVA_BRIDGE 1
 #define LOG_DISABLED 1
-// Prevents Webkit from drawing the caret in textfields and textareas
-// This prevents unnecessary invals.
+/* Prevents Webkit from drawing the caret in textfields and textareas
+   This prevents unnecessary invals. */
 #define ENABLE_TEXT_CARET 1
 #define ENABLE_JAVASCRIPT_DEBUGGER 0
+#if !defined(ENABLE_JIT) && !ENABLE_ANDROID_JSC_JIT
+#define ENABLE_JIT 0
+#endif
 #endif
 
-#if WTF_PLATFORM_WIN
-#define WTF_USE_WININET 1
+#if WTF_PLATFORM_WIN && !WTF_OS_WINCE
+#define WTF_USE_CF 1
+#define WTF_USE_PTHREADS 0
+#endif
+
+#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !defined(WIN_CAIRO)
+#define WTF_USE_CFNETWORK 1
+#endif
+
+#if WTF_USE_CFNETWORK || WTF_PLATFORM_MAC
+#define WTF_USE_CFURLCACHE 1
+#define WTF_USE_CFURLSTORAGESESSIONS 1
+#endif
+
+#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !WTF_PLATFORM_QT
+#define ENABLE_WEB_ARCHIVE 1
 #endif
 
 #if WTF_PLATFORM_WX
 #define ENABLE_ASSEMBLER 1
-#if WTF_PLATFORM_DARWIN
-#define WTF_PLATFORM_CF 1
+#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
+#if WTF_OS_DARWIN
+#define WTF_USE_CF 1
+#ifndef BUILDING_ON_TIGER
+#define WTF_USE_CORE_TEXT 1
+#define ENABLE_WEB_ARCHIVE 1
+#else
+#define WTF_USE_ATSUI 1
+#endif
 #endif
 #endif
 
@@ -574,25 +739,39 @@
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #endif
 
+#if WTF_PLATFORM_BREWMP
+#define USE_SYSTEM_MALLOC 1
+#endif
+
+#if WTF_PLATFORM_BREWMP_SIMULATOR
+#define ENABLE_JIT 0
+#endif
+
 #if !defined(HAVE_ACCESSIBILITY)
-#if WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
+#if WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
 #define HAVE_ACCESSIBILITY 1
 #endif
 #endif /* !defined(HAVE_ACCESSIBILITY) */
 
-#if WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
+#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
 #define HAVE_SIGNAL_H 1
 #endif
 
-#if !WTF_PLATFORM_WIN_OS && !WTF_PLATFORM_SOLARIS && !WTF_PLATFORM_QNX \
-    && !WTF_PLATFORM_SYMBIAN && !WTF_PLATFORM_HAIKU && !WTF_COMPILER_RVCT \
-    && !WTF_PLATFORM_ANDROID && !WTF_PLATFORM_OS2
+#if !defined(HAVE_STRNSTR)
+#if WTF_OS_DARWIN || WTF_OS_FREEBSD
+#define HAVE_STRNSTR 1
+#endif
+#endif
+
+#if !WTF_OS_WINDOWS && !WTF_OS_SOLARIS && !WTF_OS_QNX \
+    && !WTF_OS_SYMBIAN && !WTF_OS_HAIKU && !WTF_OS_RVCT \
+    && !WTF_OS_ANDROID && !WTF_PLATFORM_BREWMP
 #define HAVE_TM_GMTOFF 1
 #define HAVE_TM_ZONE 1
 #define HAVE_TIMEGM 1
-#endif     
+#endif
 
-#if WTF_PLATFORM_DARWIN
+#if WTF_OS_DARWIN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 1
@@ -603,23 +782,37 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 #define HAVE_SYS_TIMEB_H 1
+#define WTF_USE_ACCELERATE 1
 
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !WTF_PLATFORM_IPHONE && !WTF_PLATFORM_QT
+#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD)
+
+#define HAVE_DISPATCH_H 1
+#define HAVE_HOSTED_CORE_ANIMATION 1
+
+#if !WTF_PLATFORM_IOS
 #define HAVE_MADV_FREE_REUSE 1
 #define HAVE_MADV_FREE 1
 #define HAVE_PTHREAD_SETNAME_NP 1
 #endif
 
-#if WTF_PLATFORM_IPHONE
+#endif
+
+#if WTF_PLATFORM_IOS
 #define HAVE_MADV_FREE 1
 #endif
 
-#elif WTF_PLATFORM_WIN_OS
+#elif WTF_OS_WINDOWS
 
+#if WTF_OS_WINCE
+#define HAVE_ERRNO_H 0
+#else
 #define HAVE_SYS_TIMEB_H 1
+#define HAVE_ALIGNED_MALLOC 1
+#define HAVE_ISDEBUGGERPRESENT 1
+#endif
 #define HAVE_VIRTUALALLOC 1
 
-#elif WTF_PLATFORM_SYMBIAN
+#elif WTF_OS_SYMBIAN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 0
@@ -632,7 +825,11 @@
 #define HAVE_SYS_PARAM_H 1
 #endif
 
-#elif WTF_PLATFORM_QNX
+#elif WTF_PLATFORM_BREWMP
+
+#define HAVE_ERRNO_H 1
+
+#elif WTF_OS_QNX
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 1
@@ -641,7 +838,7 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
-#elif WTF_PLATFORM_ANDROID
+#elif WTF_OS_ANDROID
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 0
@@ -651,23 +848,13 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
-#elif WTF_PLATFORM_OS2
-
-#define HAVE_MMAP 1
-#define ENABLE_ASSEMBLER 1
-#define HAVE_ERRNO_H 1
-#define HAVE_STRINGS_H 1
-#define HAVE_SYS_PARAM_H 1
-#define HAVE_SYS_TIME_H 1
-#define HAVE_SYS_TIMEB_H 1
-
 #else
 
 /* FIXME: is this actually used or do other platforms generate their own config.h? */
 
 #define HAVE_ERRNO_H 1
 /* As long as Haiku doesn't have a complete support of locale this will be disabled. */
-#if !WTF_PLATFORM_HAIKU
+#if !WTF_OS_HAIKU
 #define HAVE_LANGINFO_H 1
 #endif
 #define HAVE_MMAP 1
@@ -680,6 +867,14 @@
 
 /* ENABLE macro defaults */
 
+#if WTF_PLATFORM_QT
+/* We must not customize the global operator new and delete for the Qt port. */
+#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
+#if !WTF_OS_UNIX || WTF_OS_SYMBIAN
+#define USE_SYSTEM_MALLOC 1
+#endif
+#endif
+
 /* fastMalloc match validation allows for runtime verification that
    new is matched by delete, fastMalloc is matched by fastFree, etc. */
 #if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION)
@@ -710,6 +905,10 @@
 #define ENABLE_DRAG_SUPPORT 1
 #endif
 
+#if !defined(ENABLE_DATA_TRANSFER_ITEMS)
+#define ENABLE_DATA_TRANSFER_ITEMS 0
+#endif
+
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 0
 #endif
@@ -718,14 +917,22 @@
 #define ENABLE_INSPECTOR 1
 #endif
 
-#if !defined(ENABLE_MAC_JAVA_BRIDGE)
-#define ENABLE_MAC_JAVA_BRIDGE 0
+#if !defined(ENABLE_JAVA_BRIDGE)
+#define ENABLE_JAVA_BRIDGE 0
 #endif
 
 #if !defined(ENABLE_NETSCAPE_PLUGIN_API)
 #define ENABLE_NETSCAPE_PLUGIN_API 1
 #endif
 
+#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE)
+#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0
+#endif
+
+#if !defined(ENABLE_PURGEABLE_MEMORY)
+#define ENABLE_PURGEABLE_MEMORY 0
+#endif
+
 #if !defined(WTF_USE_PLUGIN_HOST_PROCESS)
 #define WTF_USE_PLUGIN_HOST_PROCESS 0
 #endif
@@ -738,6 +945,11 @@
 #define ENABLE_OPCODE_STATS 0
 #endif
 
+#if !defined(ENABLE_GLOBAL_FASTMALLOC_NEW)
+#define ENABLE_GLOBAL_FASTMALLOC_NEW 1
+#endif
+
+#define ENABLE_DEBUG_WITH_BREAKPOINT 0
 #define ENABLE_SAMPLING_COUNTERS 0
 #define ENABLE_SAMPLING_FLAGS 0
 #define ENABLE_OPCODE_SAMPLING 0
@@ -753,10 +965,18 @@
 #define ENABLE_GEOLOCATION 0
 #endif
 
+#if !defined(ENABLE_GESTURE_RECOGNIZER)
+#define ENABLE_GESTURE_RECOGNIZER 0
+#endif
+
 #if !defined(ENABLE_NOTIFICATIONS)
 #define ENABLE_NOTIFICATIONS 0
 #endif
 
+#if WTF_PLATFORM_IOS
+#define ENABLE_TEXT_CARET 0
+#endif
+
 #if !defined(ENABLE_TEXT_CARET)
 #define ENABLE_TEXT_CARET 1
 #endif
@@ -765,80 +985,88 @@
 #define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0
 #endif
 
-#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
-#if (WTF_CPU_X86_64 && (WTF_PLATFORM_UNIX || WTF_PLATFORM_WIN_OS)) || WTF_CPU_IA64 || WTF_CPU_ALPHA
+#if !defined(ENABLE_FULLSCREEN_API)
+#define ENABLE_FULLSCREEN_API 0
+#endif
+
+#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64)
+#if (WTF_CPU_X86_64 && (WTF_OS_UNIX || WTF_OS_WINDOWS)) \
+    || (WTF_CPU_IA64 && !WTF_CPU_IA64_32) \
+    || WTF_CPU_ALPHA \
+    || WTF_CPU_SPARC64 \
+    || WTF_CPU_S390X \
+    || WTF_CPU_PPC64
 #define WTF_USE_JSVALUE64 1
-#elif WTF_CPU_ARM || WTF_CPU_PPC64
-#define WTF_USE_JSVALUE32 1
-#elif WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW
-/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
-on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
-#define WTF_USE_JSVALUE32 1
 #else
 #define WTF_USE_JSVALUE32_64 1
 #endif
-#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */
+#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */
 
 #if !defined(ENABLE_REPAINT_THROTTLING)
 #define ENABLE_REPAINT_THROTTLING 0
 #endif
 
-#if !defined(ENABLE_JIT)
-
-/* The JIT is tested & working on x86_64 Mac */
-#if WTF_CPU_X86_64 && WTF_PLATFORM_MAC
-    #define ENABLE_JIT 1
-/* The JIT is tested & working on x86 Mac */
-#elif WTF_CPU_X86 && WTF_PLATFORM_MAC
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
-    #define ENABLE_JIT 1
-/* The JIT is tested & working on x86 OS/2 */
-#elif WTF_CPU_X86 && WTF_PLATFORM_OS2
-    #define ENABLE_JIT 1
-/* The JIT is tested & working on x86 Windows */
-#elif WTF_CPU_X86 && WTF_PLATFORM_WIN
-    #define ENABLE_JIT 1
-#elif WTF_CPU_SPARC
-    #define ENABLE_JIT 1
+/* Disable the JIT on versions of GCC prior to 4.1 */
+#if !defined(ENABLE_JIT) && WTF_COMPILER_GCC && !GCC_VERSION_AT_LEAST(4, 1, 0)
+#define ENABLE_JIT 0
 #endif
 
-#if WTF_PLATFORM_QT
-#if WTF_CPU_X86_64 && WTF_PLATFORM_DARWIN
-    #define ENABLE_JIT 1
-#elif WTF_CPU_X86 && WTF_PLATFORM_DARWIN
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
-#elif WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX
-    #define ENABLE_JIT 1
+/* JIT is not implemented for 64 bit on MSVC */
+#if !defined(ENABLE_JIT) && WTF_COMPILER_MSVC && WTF_CPU_X86_64
+#define ENABLE_JIT 0
 #endif
-#endif /* PLATFORM(QT) */
 
-#endif /* !defined(ENABLE_JIT) */
+/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */
+#if !defined(ENABLE_JIT) \
+    && (WTF_CPU_X86 || WTF_CPU_X86_64 || WTF_CPU_ARM || WTF_CPU_MIPS) \
+    && (WTF_OS_DARWIN || !WTF_COMPILER_GCC || GCC_VERSION_AT_LEAST(4, 1, 0)) \
+    && !WTF_OS_WINCE
+#define ENABLE_JIT 1
+#endif
 
+/* Currently only implemented for JSVALUE64, only tested on WTF_PLATFORM_MAC */
+#if ENABLE_JIT && WTF_USE_JSVALUE64 && WTF_PLATFORM_MAC
+#define ENABLE_DFG_JIT 1
+/* Enabled with restrictions to circumvent known performance regressions. */
+#define ENABLE_DFG_JIT_RESTRICTIONS 1
+#endif
+
+/* Ensure that either the JIT or the interpreter has been enabled. */
+#if !defined(ENABLE_INTERPRETER) && !ENABLE_JIT
+#define ENABLE_INTERPRETER 1
+#endif
+#if !(ENABLE_JIT || ENABLE_INTERPRETER)
+#error You have to have at least one execution model enabled to build JSC
+#endif
+
+#if WTF_CPU_SH4 && WTF_PLATFORM_QT
+#define ENABLE_JIT 1
+#define ENABLE_YARR 1
+#define ENABLE_YARR_JIT 1
+#define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
+#define ENABLE_ASSEMBLER 1
+#endif
+
+/* Configure the JIT */
 #if ENABLE_JIT
-#ifndef ENABLE_JIT_OPTIMIZE_CALL
-#define ENABLE_JIT_OPTIMIZE_CALL 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
-#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
-#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
-#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
-#endif
+    #if WTF_CPU_ARM
+    #if !defined(ENABLE_JIT_USE_SOFT_MODULO) && WTF_ARM_ARCH_AT_LEAST(5)
+    #define ENABLE_JIT_USE_SOFT_MODULO 1
+    #endif
+    #endif
+
+    #ifndef ENABLE_JIT_OPTIMIZE_CALL
+    #define ENABLE_JIT_OPTIMIZE_CALL 1
+    #endif
+    #ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
+    #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
+    #endif
+    #ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
+    #define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
+    #endif
+    #ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
+    #define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
+    #endif
 #endif
 
 #if WTF_CPU_X86 && WTF_COMPILER_MSVC
@@ -849,80 +1077,89 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
 #define JSC_HOST_CALL
 #endif
 
-#if WTF_COMPILER_GCC && !ENABLE_JIT
+/* Configure the interpreter */
+#if WTF_COMPILER_GCC || (RVCT_VERSION_AT_LEAST(4, 0, 0, 0) && defined(__GNUC__))
 #define HAVE_COMPUTED_GOTO 1
 #endif
-
-#if ENABLE_JIT && defined(COVERAGE)
-    #define WTF_USE_INTERPRETER 0
-#else
-    #define WTF_USE_INTERPRETER 1
+#if HAVE_COMPUTED_GOTO && ENABLE_INTERPRETER
+#define ENABLE_COMPUTED_GOTO_INTERPRETER 1
 #endif
 
-/* Yet Another Regex Runtime. */
-#if !defined(ENABLE_YARR_JIT)
+/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc.  Results dumped at exit */
+#define ENABLE_REGEXP_TRACING 0
 
-/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */
-#if (WTF_CPU_X86 \
- || WTF_CPU_X86_64 \
- || WTF_CPU_SPARC \
- || WTF_CPU_ARM_TRADITIONAL \
- || WTF_CPU_ARM_THUMB2 \
- || WTF_CPU_X86)
-#define ENABLE_YARR_JIT 1
-#else
+/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */
+#if WTF_PLATFORM_CHROMIUM
 #define ENABLE_YARR_JIT 0
+
+#elif ENABLE_JIT && !defined(ENABLE_YARR_JIT)
+#define ENABLE_YARR_JIT 1
+
+/* Setting this flag compares JIT results with interpreter results. */
+#define ENABLE_YARR_JIT_DEBUG 0
 #endif
 
-#endif /* !defined(ENABLE_YARR_JIT) */
-
-#if (ENABLE_JIT || ENABLE_YARR_JIT)
+#if ENABLE_JIT || ENABLE_YARR_JIT
 #define ENABLE_ASSEMBLER 1
 #endif
 /* Setting this flag prevents the assembler from using RWX memory; this may improve
    security but currectly comes at a significant performance cost. */
-#if WTF_PLATFORM_IPHONE
+#if WTF_PLATFORM_IOS
 #define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1
-#else
-#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0
 #endif
 
-#if !defined(ENABLE_PAN_SCROLLING) && WTF_PLATFORM_WIN_OS
+/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in.
+   On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */
+#if ENABLE_ASSEMBLER
+#if WTF_CPU_X86_64
+#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1
+#else
+#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1
+#endif
+#endif
+
+#if !defined(ENABLE_PAN_SCROLLING) && WTF_OS_WINDOWS
 #define ENABLE_PAN_SCROLLING 1
 #endif
 
-/* Use the QXmlStreamReader implementation for XMLTokenizer */
+#if !defined(ENABLE_SMOOTH_SCROLLING)
+#define ENABLE_SMOOTH_SCROLLING 0
+#endif
+
+#if !defined(ENABLE_WEB_ARCHIVE)
+#define ENABLE_WEB_ARCHIVE 0
+#endif
+
+/* Use the QXmlStreamReader implementation for XMLDocumentParser */
 /* Use the QXmlQuery implementation for XSLTProcessor */
 #if WTF_PLATFORM_QT
 #define WTF_USE_QXMLSTREAM 1
 #define WTF_USE_QXMLQUERY 1
 #endif
 
-#if !WTF_PLATFORM_QT
-#define WTF_USE_FONT_FAST_PATH 1
+#if WTF_PLATFORM_MAC
+/* Complex text framework */
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#define WTF_USE_ATSUI 0
+#define WTF_USE_CORE_TEXT 1
+#else
+#define WTF_USE_ATSUI 1
+#define WTF_USE_CORE_TEXT 0
+#endif
 #endif
 
 /* Accelerated compositing */
-#if WTF_PLATFORM_MAC
-#if !defined(BUILDING_ON_TIGER)
-#define WTF_USE_ACCELERATED_COMPOSITING 1
-#endif
-#endif
-
-#if WTF_PLATFORM_IPHONE
+#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER)) || WTF_PLATFORM_IOS || WTF_PLATFORM_QT || (WTF_PLATFORM_WIN && !WTF_OS_WINCE &&!defined(WIN_CAIRO))
 #define WTF_USE_ACCELERATED_COMPOSITING 1
 #endif
 
-/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with
-   with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and
-   off in one place. */
-//#if WTF_PLATFORM_WIN
-//#include "QuartzCorePresent.h"
-//#if QUARTZCORE_PRESENT
-//#define WTF_USE_ACCELERATED_COMPOSITING 1
-//#define ENABLE_3D_RENDERING 1
-//#endif
-//#endif
+#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || WTF_PLATFORM_IOS
+#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1
+#endif
+
+#if WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#define WTF_USE_AVFOUNDATION 1
+#endif
 
 #if WTF_COMPILER_GCC
 #define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result))
@@ -930,7 +1167,7 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
 #define WARN_UNUSED_RETURN
 #endif
 
-#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_PLATFORM_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
+#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
 
@@ -939,4 +1176,46 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
 
 #define ENABLE_JSC_ZOMBIES 0
 
+/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_QT
+#define WTF_USE_PLATFORM_STRATEGIES 1
+#endif
+
+#if WTF_PLATFORM_WIN
+#define WTF_USE_CROSS_PLATFORM_CONTEXT_MENUS 1
+#endif
+
+/* Geolocation request policy. pre-emptive policy is to acquire user permission before acquiring location.
+   Client based implementations will have option to choose between pre-emptive and nonpre-emptive permission policy.
+   pre-emptive permission policy is enabled by default for all client-based implementations. */
+#if ENABLE_CLIENT_BASED_GEOLOCATION
+#define WTF_USE_PREEMPT_GEOLOCATION_PERMISSION 1
+#endif
+
+#if WTF_CPU_ARM_THUMB2
+#define ENABLE_BRANCH_COMPACTION 1
+#endif
+
+#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
+#define ENABLE_THREADING_OPENMP 1
+#endif
+
+#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE_SINGLE_THREADED && (ENABLE_THREADING_GENERIC || ENABLE_THREADING_LIBDISPATCH || ENABLE_THREADING_OPENMP)
+#define ENABLE_PARALLEL_JOBS 1
+#endif
+
+#if ENABLE_GLIB_SUPPORT
+#include "GTypedefs.h"
+#endif
+
+/* FIXME: This define won't be needed once #27551 is fully landed. However, 
+   since most ports try to support sub-project independence, adding new headers
+   to WTF causes many ports to break, and so this way we can address the build
+   breakages one port at a time. */
+#define WTF_USE_EXPORT_MACROS 0
+
+#if WTF_PLATFORM_QT || WTF_PLATFORM_GTK
+#define WTF_USE_UNIX_DOMAIN_SOCKETS 1
+#endif
+
 #endif /* WTF_Platform_h */
diff --git a/js/src/jit-test/tests/basic/bug632964-regexp.js b/js/src/jit-test/tests/basic/bug632964-regexp.js
index 7151d3713647..75612dbc735d 100644
--- a/js/src/jit-test/tests/basic/bug632964-regexp.js
+++ b/js/src/jit-test/tests/basic/bug632964-regexp.js
@@ -1,5 +1,3 @@
-// |jit-test| error: InternalError: regular expression too complex
-
 var sText = "s";
 
 for (var i = 0; i < 250000; ++i)
@@ -12,6 +10,5 @@ var match = sText.match(/s(\s|.)*?e/gi);
 //var match = sText.match(/s([\s\S]*?)e/gi);
 //var match = sText.match(/s(?:[\s\S]*?)e/gi);
 var end = new Date();
-print(end - start);
 
 assertEq(match.length, 1);
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index ecc336cdc4c3..c88fae9fdaf0 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -48,6 +48,7 @@
 #include "jstracer.h"
 #include "jswrapper.h"
 #include "assembler/wtf/Platform.h"
+#include "yarr/BumpPointerAllocator.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
@@ -73,6 +74,9 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     active(false),
 #ifdef JS_METHODJIT
     jaegerCompartment(NULL),
+#endif
+#if ENABLE_YARR_JIT
+    regExpAllocator(NULL),
 #endif
     propertyTree(thisForCtor()),
     emptyArgumentsShape(NULL),
@@ -84,9 +88,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     initialRegExpShape(NULL),
     initialStringShape(NULL),
     debugMode(rt->debugMode),
-#if ENABLE_YARR_JIT
-    regExpAllocator(NULL),
-#endif
     mathCache(NULL)
 {
     JS_INIT_CLIST(&scripts);
@@ -135,11 +136,9 @@ JSCompartment::init()
         return false;
 #endif
 
-#if ENABLE_YARR_JIT
-    regExpAllocator = rt->new_();
+    regExpAllocator = rt->new_();
     if (!regExpAllocator)
         return false;
-#endif
 
     if (!backEdgeTable.init())
         return false;
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 5b3f16643050..8827a275f796 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -54,11 +54,8 @@
 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
 #endif
 
-namespace JSC {
-
-class ExecutableAllocator;
-
-}
+namespace JSC { class ExecutableAllocator; }
+namespace WTF { class BumpPointerAllocator; }
 
 namespace js {
 
@@ -420,6 +417,7 @@ struct JS_FRIEND_API(JSCompartment) {
      */
     size_t getMjitCodeSize() const;
 #endif
+    WTF::BumpPointerAllocator    *regExpAllocator;
 
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
@@ -466,8 +464,6 @@ struct JS_FRIEND_API(JSCompartment) {
     bool                         debugMode;  // true iff debug mode on
     JSCList                      scripts;    // scripts in this compartment
 
-    JSC::ExecutableAllocator     *regExpAllocator;
-
     js::NativeIterCache          nativeIterCache;
 
     typedef js::Maybe LazyToSourceCache;
diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp
index 0df8ae536a47..3d9f09f56559 100644
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -59,8 +59,6 @@
 #include "jsobjinlines.h"
 #include "jsregexpinlines.h"
 
-#include "yarr/RegexParser.h"
-
 #ifdef JS_TRACER
 #include "jstracer.h"
 using namespace nanojit;
@@ -193,11 +191,11 @@ js_ObjectIsRegExp(JSObject *obj)
  */
 
 void
-RegExp::handleYarrError(JSContext *cx, int error)
+RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error)
 {
     switch (error) {
       case JSC::Yarr::NoError:
-        JS_NOT_REACHED("Precondition violation: an error must have occurred.");
+        JS_NOT_REACHED("Called reportYarrError with value for no error");
         return;
 #define COMPILE_EMSG(__code, __msg) \
       case JSC::Yarr::__code: \
@@ -210,49 +208,16 @@ RegExp::handleYarrError(JSContext *cx, int error)
       COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN);
       COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */
       COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE);
+      COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE);
       COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(CharacterClassRangeSingleChar, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
       COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
-      COMPILE_EMSG(HitRecursionLimit, JSMSG_REGEXP_TOO_COMPLEX);
+      COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
 #undef COMPILE_EMSG
       default:
-        JS_NOT_REACHED("Precondition violation: unknown Yarr error code.");
+        JS_NOT_REACHED("Unknown Yarr error code");
     }
 }
 
-void
-RegExp::handlePCREError(JSContext *cx, int error)
-{
-#define REPORT(msg_) \
-    JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \
-    return
-    switch (error) {
-      case -2: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 0: JS_NOT_REACHED("Precondition violation: an error must have occurred.");
-      case 1: REPORT(JSMSG_TRAILING_SLASH);
-      case 2: REPORT(JSMSG_TRAILING_SLASH);
-      case 3: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 4: REPORT(JSMSG_BAD_QUANTIFIER);
-      case 5: REPORT(JSMSG_BAD_QUANTIFIER);
-      case 6: REPORT(JSMSG_BAD_CLASS_RANGE);
-      case 7: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 8: REPORT(JSMSG_BAD_CLASS_RANGE);
-      case 9: REPORT(JSMSG_BAD_QUANTIFIER);
-      case 10: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
-      case 11: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 12: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
-      case 13: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 14: REPORT(JSMSG_MISSING_PAREN);
-      case 15: REPORT(JSMSG_BAD_BACKREF);
-      case 16: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 17: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      default:
-        JS_NOT_REACHED("Precondition violation: unknown PCRE error code.");
-    }
-#undef REPORT
-}
-
 bool
 RegExp::parseFlags(JSContext *cx, JSString *flagStr, uintN *flagsOut)
 {
@@ -929,3 +894,4 @@ js_InitRegExpClass(JSContext *cx, JSObject *global)
 
     return proto;
 }
+
diff --git a/js/src/jsregexpinlines.h b/js/src/jsregexpinlines.h
index 70db45413e1d..305cf1590462 100644
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -48,12 +48,13 @@
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
+#include "methodjit/MethodJIT.h"
 #include "assembler/wtf/Platform.h"
+#include "yarr/BumpPointerAllocator.h"
 
+#include "yarr/Yarr.h"
 #if ENABLE_YARR_JIT
-#include "yarr/yarr/RegexJIT.h"
-#else
-#include "yarr/pcre/pcre.h"
+#include "yarr/YarrJIT.h"
 #endif
 
 namespace js {
@@ -95,10 +96,10 @@ regexp_statics_construct(JSContext *cx, GlobalObject *parent)
 class RegExp
 {
 #if ENABLE_YARR_JIT
-    JSC::Yarr::RegexCodeBlock   compiled;
-#else
-    JSRegExp                    *compiled;
+    /* native code is valid only if codeBlock.isFallBack() == false */
+    JSC::Yarr::YarrCodeBlock    codeBlock;
 #endif
+    JSC::Yarr::BytecodePattern  *byteCode;
     JSLinearString              *source;
     size_t                      refCount;
     unsigned                    parenCount; /* Must be |unsigned| to interface with YARR. */
@@ -111,7 +112,11 @@ class RegExp
 #endif
 
     RegExp(JSLinearString *source, uint32 flags, JSCompartment *compartment)
-      : compiled(), source(source), refCount(1), parenCount(0), flags(flags)
+      :
+#if ENABLE_YARR_JIT
+        codeBlock(),
+#endif
+        byteCode(NULL), source(source), refCount(1), parenCount(0), flags(flags)
 #ifdef DEBUG
         , compartment(compartment)
 #endif
@@ -120,17 +125,18 @@ class RegExp
     JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
 
     ~RegExp() {
-#if !ENABLE_YARR_JIT
-        if (compiled)
-            jsRegExpFree(compiled);
+#if ENABLE_YARR_JIT
+        codeBlock.release();
 #endif
+        // YYY
+        if (byteCode)
+            delete byteCode;
     }
 
     bool compileHelper(JSContext *cx, JSLinearString &pattern);
     bool compile(JSContext *cx);
     static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
-    void handlePCREError(JSContext *cx, int error);
-    void handleYarrError(JSContext *cx, int error);
+    void reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error);
     static inline bool initArena(JSContext *cx);
     static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
     static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
@@ -318,9 +324,6 @@ inline bool
 RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
                         size_t *lastIndex, bool test, Value *rval)
 {
-#if !ENABLE_YARR_JIT
-    JS_ASSERT(compiled);
-#endif
     const size_t pairCount = parenCount + 1;
     const size_t bufCount = pairCount * 3; /* Should be x2, but PCRE has... needs. */
     const size_t matchItemCount = pairCount * 2;
@@ -360,27 +363,20 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
         inputOffset = *lastIndex;
     }
 
+    int result;
 #if ENABLE_YARR_JIT
-    int result = JSC::Yarr::executeRegex(cx, compiled, chars, *lastIndex - inputOffset, len, buf,
-                                         bufCount);
+    if (!codeBlock.isFallBack())
+        result = JSC::Yarr::execute(codeBlock, chars, *lastIndex - inputOffset, len, buf);
+    else
+        result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
 #else
-    int result = jsRegExpExecute(cx, compiled, chars, len, *lastIndex - inputOffset, buf, 
-                                 bufCount);
+    result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
 #endif
     if (result == -1) {
         *rval = NullValue();
         return true;
     }
 
-    if (result < 0) {
-#if ENABLE_YARR_JIT
-        handleYarrError(cx, result);
-#else
-        handlePCREError(cx, result);
-#endif
-        return false;
-    }
-
     /* 
      * Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so
      * just do another pass.
@@ -460,53 +456,44 @@ RegExp::createObjectNoStatics(JSContext *cx, const jschar *chars, size_t length,
     return obj;
 }
 
-#ifdef ANDROID
-static bool
-YarrJITIsBroken(JSContext *cx)
+/*
+ * This function should be deleted once we can. See bug 604774.
+ */
+static inline bool
+EnableYarrJIT(JSContext *cx)
 {
-#if defined(JS_TRACER) && defined(JS_METHODJIT)
-    /* FIXME/bug 604774: dead code walking.
-     *
-     * If both JITs are disabled, assume they were disabled because
-     * we're running on a blacklisted device.
-     */
-    return !cx->traceJitEnabled && !cx->methodJitEnabled;
+#if defined ANDROID && defined(JS_TRACER) && defined(JS_METHODJIT)
+    return cx->traceJitEnabled || cx->methodJitEnabled;
 #else
-    return false;
+    return true;
 #endif
 }
-#endif  /* ANDROID */
 
 inline bool
 RegExp::compileHelper(JSContext *cx, JSLinearString &pattern)
 {
-#if ENABLE_YARR_JIT
-    bool fellBack = false;
-    int error = 0;
-    jitCompileRegex(*cx->compartment->regExpAllocator, compiled, pattern, parenCount, error, fellBack, ignoreCase(), multiline()
-#ifdef ANDROID
-                    /* Temporary gross hack to work around buggy kernels. */
-                    , YarrJITIsBroken(cx)
-#endif
-);
-    if (!error)
-        return true;
-    if (fellBack)
-        handlePCREError(cx, error);
-    else
-        handleYarrError(cx, error);
-    return false;
-#else
-    int error = 0;
-    compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
-                               ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
-                               multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
-                               &parenCount, &error);
-    if (!error)
-        return true;
-    handlePCREError(cx, error);
-    return false;
+    JSC::Yarr::ErrorCode yarrError;
+    JSC::Yarr::YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError);
+    if (yarrError) {
+        reportYarrError(cx, yarrError);
+        return false;
+    }
+    parenCount = yarrPattern.m_numSubpatterns;
+
+#if ENABLE_YARR_JIT && defined(JS_METHODJIT)
+    if (EnableYarrJIT(cx) && !yarrPattern.m_containsBackreferences) {
+        JSC::Yarr::JSGlobalData globalData(cx->compartment->jaegerCompartment->execAlloc());
+        JSC::Yarr::jitCompile(yarrPattern, &globalData, codeBlock);
+        if (!codeBlock.isFallBack())
+            return true;
+    } else {
+        codeBlock.setFallBack(true);
+    }
 #endif
+
+    byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
+
+    return true;
 }
 
 inline bool
diff --git a/js/src/jsvector.h b/js/src/jsvector.h
index 3d413c1f64b6..4eaf58b6a4e7 100644
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -208,12 +208,30 @@ class Vector : private AllocPolicy
 
     /* compute constants */
 
+    /*
+     * Consider element size to be 1 for buffer sizing if there are
+     * 0 inline elements. This allows us to compile when the definition
+     * of the element type is not visible here.
+     *
+     * Explicit specialization is only allowed at namespace scope, so
+     * in order to keep everything here, we use a dummy template
+     * parameter with partial specialization.
+     */
+    template 
+    struct ElemSize {
+        static const size_t result = sizeof(T);
+    };
+    template 
+    struct ElemSize<0, Dummy> {
+        static const size_t result = 1;
+    };
+
     static const size_t sInlineCapacity =
-        tl::Min::result;
+        tl::Min::result>::result;
 
     /* Calculate inline buffer size; avoid 0-sized array. */
     static const size_t sInlineBytes =
-        tl::Max<1, sInlineCapacity * sizeof(T)>::result;
+        tl::Max<1, sInlineCapacity * ElemSize::result>::result;
 
     /* member data */
 
diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp
index 603d76a59c88..b03c6afa0990 100644
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -503,7 +503,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             analyze::Bytecode *opinfo = analysis->maybeCode(i);
             if (opinfo && opinfo->safePoint) {
                 Label L = jumpMap[i];
-                JS_ASSERT(L.isValid());
+                JS_ASSERT(L.isSet());
                 jitNmap[ix].bcOff = i;
                 jitNmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L));
                 ix++;
@@ -625,7 +625,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
     cursor += sizeof(ic::EqualityICInfo) * jit->nEqualityICs;
     for (size_t i = 0; i < jit->nEqualityICs; i++) {
         uint32 offs = uint32(equalityICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isValid());
+        JS_ASSERT(jumpMap[offs].isSet());
         jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]);
         jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry);
         jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall);
@@ -650,7 +650,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             continue;
 
         uint32 offs = uint32(traceICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isValid());
+        JS_ASSERT(jumpMap[offs].isSet());
         jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint);
         jitTraceICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]);
         jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
@@ -800,7 +800,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
 
     for (size_t i = 0; i < jumpTableOffsets.length(); i++) {
         uint32 offset = jumpTableOffsets[i];
-        JS_ASSERT(jumpMap[offset].isValid());
+        JS_ASSERT(jumpMap[offset].isSet());
         jumpVec[i] = (void *)(result + masm.distanceOf(jumpMap[offset]));
     }
 
@@ -2089,7 +2089,7 @@ JSC::MacroAssembler::Label
 mjit::Compiler::labelOf(jsbytecode *pc)
 {
     uint32 offs = uint32(pc - script->code);
-    JS_ASSERT(jumpMap[offs].isValid());
+    JS_ASSERT(jumpMap[offs].isSet());
     return jumpMap[offs];
 }
 
diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp
index bd738b92ba2b..b55b0dba48a5 100644
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -846,12 +846,7 @@ static inline void Destroy(T &t)
 
 mjit::JITScript::~JITScript()
 {
-#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) 
-    void *addr = code.m_code.executableAddress();
-    memset(addr, 0xcc, code.m_size);
-#endif
-
-    code.m_executablePool->release();
+    code.release();
 
 #if defined JS_POLYIC
     ic::GetElementIC *getElems_ = getElems();
diff --git a/js/src/methodjit/TrampolineCompiler.cpp b/js/src/methodjit/TrampolineCompiler.cpp
index a6ac9d709f0e..77bb148ba311 100644
--- a/js/src/methodjit/TrampolineCompiler.cpp
+++ b/js/src/methodjit/TrampolineCompiler.cpp
@@ -93,7 +93,7 @@ TrampolineCompiler::compileTrampoline(Trampolines::TrampolinePtr *where,
 
     Label entry = masm.label();
     CHECK_RESULT(generator(masm));
-    JS_ASSERT(entry.isValid());
+    JS_ASSERT(entry.isSet());
 
     bool ok;
     JSC::LinkBuffer buffer(&masm, execAlloc, poolp, &ok);
diff --git a/js/src/yarr/wtf/ASCIICType.h b/js/src/yarr/ASCIICType.h
similarity index 81%
rename from js/src/yarr/wtf/ASCIICType.h
rename to js/src/yarr/ASCIICType.h
index cf53d9ac0c87..a3ae9f4455e2 100644
--- a/js/src/yarr/wtf/ASCIICType.h
+++ b/js/src/yarr/ASCIICType.h
@@ -1,4 +1,7 @@
-/*
+/* -*- 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) 2007, 2008, 2009 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -24,12 +27,13 @@
  * 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.
- */
+ *
+ * ***** END LICENSE BLOCK ***** */
 
 #ifndef WTF_ASCIICType_h
 #define WTF_ASCIICType_h
 
-#include "yarr/jswtfbridge.h"
+#include "assembler/wtf/Assertions.h"
 
 // The behavior of many of the functions in the  header is dependent
 // on the current locale. But in the WebKit project, all uses of those functions
@@ -49,6 +53,7 @@ namespace WTF {
     inline bool isASCII(wchar_t c) { return !(c & ~0x7F); }
 #endif
     inline bool isASCII(int c) { return !(c & ~0x7F); }
+    inline bool isASCII(unsigned c) { return !(c & ~0x7F); }
 
     inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
     inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
@@ -56,6 +61,7 @@ namespace WTF {
     inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
 #endif
     inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+    inline bool isASCIIAlpha(unsigned c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
 
     inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
     inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
@@ -63,6 +69,7 @@ namespace WTF {
     inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
 #endif
     inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
+    inline bool isASCIIAlphanumeric(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
 
     inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); }
     inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); }
@@ -70,6 +77,7 @@ namespace WTF {
     inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); }
 #endif
     inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); }
+    inline bool isASCIIDigit(unsigned c) { return (c >= '0') & (c <= '9'); }
 
     inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
     inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
@@ -77,6 +85,7 @@ namespace WTF {
     inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
 #endif
     inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
+    inline bool isASCIIHexDigit(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
 
     inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); }
     inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); }
@@ -84,6 +93,7 @@ namespace WTF {
     inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); }
 #endif
     inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); }
+    inline bool isASCIIOctalDigit(unsigned c) { return (c >= '0') & (c <= '7'); }
 
     inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; }
     inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; }
@@ -91,6 +101,7 @@ namespace WTF {
     inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; }
 #endif
     inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; }
+    inline bool isASCIILower(unsigned c) { return c >= 'a' && c <= 'z'; }
 
     inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; }
     inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; }
@@ -98,6 +109,7 @@ namespace WTF {
     inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; }
 #endif
     inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; }
+    inline bool isASCIIUpper(unsigned c) { return c >= 'A' && c <= 'Z'; }
 
     /*
         Statistics from a run of Apple's page load test for callers of isASCIISpace:
@@ -118,6 +130,7 @@ namespace WTF {
     inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
 #endif
     inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
+    inline bool isASCIISpace(unsigned c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
 
     inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
     inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
@@ -125,20 +138,24 @@ namespace WTF {
     inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
 #endif
     inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
+    inline unsigned toASCIILower(unsigned c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
 
+    // FIXME: Why do these need static_cast?
     inline char toASCIIUpper(char c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
     inline unsigned short toASCIIUpper(unsigned short c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
 #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
     inline wchar_t toASCIIUpper(wchar_t c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
 #endif
     inline int toASCIIUpper(int c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
+    inline unsigned toASCIIUpper(unsigned c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
 
-    inline int toASCIIHexValue(char c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
-    inline int toASCIIHexValue(unsigned short c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
 #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
-    inline int toASCIIHexValue(wchar_t c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
 #endif
-    inline int toASCIIHexValue(int c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(unsigned c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
 
     inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; }
     inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; }
@@ -146,7 +163,7 @@ namespace WTF {
     inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; }
 #endif
     inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; }
-
+    inline bool isASCIIPrintable(unsigned c) { return c >= ' ' && c <= '~'; }
 }
 
 using WTF::isASCII;
diff --git a/js/src/yarr/BumpPointerAllocator.h b/js/src/yarr/BumpPointerAllocator.h
new file mode 100644
index 000000000000..8ef5a780f9d8
--- /dev/null
+++ b/js/src/yarr/BumpPointerAllocator.h
@@ -0,0 +1,254 @@
+/* -*- 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) 2010 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef BumpPointerAllocator_h
+#define BumpPointerAllocator_h
+
+#include "PageAllocation.h"
+
+namespace WTF {
+
+#define MINIMUM_BUMP_POOL_SIZE 0x1000
+
+class BumpPointerPool {
+public:
+    // ensureCapacity will check whether the current pool has capacity to
+    // allocate 'size' bytes of memory  If it does not, it will attempt to
+    // allocate a new pool (which will be added to this one in a chain).
+    //
+    // If allocation fails (out of memory) this method will return null.
+    // If the return value is non-null, then callers should update any
+    // references they have to this current (possibly full) BumpPointerPool
+    // to instead point to the newly returned BumpPointerPool.
+    BumpPointerPool* ensureCapacity(size_t size)
+    {
+        void* allocationEnd = static_cast(m_current) + size;
+        ASSERT(allocationEnd > m_current); // check for overflow
+        if (allocationEnd <= static_cast(this))
+            return this;
+        return ensureCapacityCrossPool(this, size);
+    }
+
+    // alloc should only be called after calling ensureCapacity; as such
+    // alloc will never fail.
+    void* alloc(size_t size)
+    {
+        void* current = m_current;
+        void* allocationEnd = static_cast(current) + size;
+        ASSERT(allocationEnd > current); // check for overflow
+        ASSERT(allocationEnd <= static_cast(this));
+        m_current = allocationEnd;
+        return current;
+    }
+
+    // The dealloc method releases memory allocated using alloc.  Memory
+    // must be released in a LIFO fashion, e.g. if the client calls alloc
+    // four times, returning pointer A, B, C, D, then the only valid order
+    // in which these may be deallocaed is D, C, B, A.
+    //
+    // The client may optionally skip some deallocations.  In the example
+    // above, it would be valid to only explicitly dealloc C, A (D being
+    // dealloced along with C, B along with A).
+    //
+    // If pointer was not allocated from this pool (or pools) then dealloc
+    // will CRASH().  Callers should update any references they have to
+    // this current BumpPointerPool to instead point to the returned
+    // BumpPointerPool.
+    BumpPointerPool* dealloc(void* position)
+    {
+        if ((position >= m_start) && (position <= static_cast(this))) {
+            ASSERT(position <= m_current);
+            m_current = position;
+            return this;
+        }
+        return deallocCrossPool(this, position);
+    }
+
+private:
+    // Placement operator new, returns the last 'size' bytes of allocation for use as this.
+    void* operator new(size_t size, const PageAllocation& allocation)
+    {
+        ASSERT(size < allocation.size());
+        return reinterpret_cast(reinterpret_cast(allocation.base()) + allocation.size()) - size;
+    }
+
+    BumpPointerPool(const PageAllocation& allocation)
+        : m_current(allocation.base())
+        , m_start(allocation.base())
+        , m_next(0)
+        , m_previous(0)
+        , m_allocation(allocation)
+    {
+    }
+
+    static BumpPointerPool* create(size_t minimumCapacity = 0)
+    {
+        // Add size of BumpPointerPool object, check for overflow.
+        minimumCapacity += sizeof(BumpPointerPool);
+        if (minimumCapacity < sizeof(BumpPointerPool))
+            return 0;
+
+        size_t poolSize = MINIMUM_BUMP_POOL_SIZE;
+        while (poolSize < minimumCapacity) {
+            poolSize <<= 1;
+            // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2!
+            ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1)));
+            if (!poolSize)
+                return 0;
+        }
+
+        PageAllocation allocation = PageAllocation::allocate(poolSize);
+        if (!!allocation)
+            return new(allocation) BumpPointerPool(allocation);
+        return 0;
+    }
+
+    void shrink()
+    {
+        ASSERT(!m_previous);
+        m_current = m_start;
+        while (m_next) {
+            BumpPointerPool* nextNext = m_next->m_next;
+            m_next->destroy();
+            m_next = nextNext;
+        }
+    }
+
+    void destroy()
+    {
+        m_allocation.deallocate();
+    }
+
+    static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size)
+    {
+        // The pool passed should not have capacity, so we'll start with the next one.
+        ASSERT(previousPool);
+        ASSERT((static_cast(previousPool->m_current) + size) > previousPool->m_current); // check for overflow
+        ASSERT((static_cast(previousPool->m_current) + size) > static_cast(previousPool));
+        BumpPointerPool* pool = previousPool->m_next;
+
+        while (true) {
+            if (!pool) {
+                // We've run to the end; allocate a new pool.
+                pool = BumpPointerPool::create(size);
+                previousPool->m_next = pool;
+                pool->m_previous = previousPool;
+                return pool;
+            }
+
+            // 
+            void* current = pool->m_current;
+            void* allocationEnd = static_cast(current) + size;
+            ASSERT(allocationEnd > current); // check for overflow
+            if (allocationEnd <= static_cast(pool))
+                return pool;
+        }
+    }
+
+    static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position)
+    {
+        // Should only be called if position is not in the current pool.
+        ASSERT((position < pool->m_start) || (position > static_cast(pool)));
+
+        while (true) {
+            // Unwind the current pool to the start, move back in the chain to the previous pool.
+            pool->m_current = pool->m_start;
+            pool = pool->m_previous;
+
+            // position was nowhere in the chain!
+            if (!pool)
+                CRASH();
+
+            if ((position >= pool->m_start) && (position <= static_cast(pool))) {
+                ASSERT(position <= pool->m_current);
+                pool->m_current = position;
+                return pool;
+            }
+        }
+    }
+
+    void* m_current;
+    void* m_start;
+    BumpPointerPool* m_next;
+    BumpPointerPool* m_previous;
+    PageAllocation m_allocation;
+
+    friend class BumpPointerAllocator;
+};
+
+// A BumpPointerAllocator manages a set of BumpPointerPool objects, which
+// can be used for LIFO (stack like) allocation.
+//
+// To begin allocating using this class call startAllocator().  The result
+// of this method will be null if the initial pool allocation fails, or a
+// pointer to a BumpPointerPool object that can be used to perform
+// allocations.  Whilst running no memory will be released until
+// stopAllocator() is called.  At this point all allocations made through
+// this allocator will be reaped, and underlying memory may be freed.
+//
+// (In practice we will still hold on to the initial pool to allow allocation
+// to be quickly restared, but aditional pools will be freed).
+//
+// This allocator is non-renetrant, it is encumbant on the clients to ensure
+// startAllocator() is not called again until stopAllocator() has been called.
+class BumpPointerAllocator {
+public:
+    BumpPointerAllocator()
+        : m_head(0)
+    {
+    }
+
+    ~BumpPointerAllocator()
+    {
+        if (m_head)
+            m_head->destroy();
+    }
+
+    BumpPointerPool* startAllocator()
+    {
+        if (!m_head)
+            m_head = BumpPointerPool::create();
+        return m_head;
+    }
+
+    void stopAllocator()
+    {
+        if (m_head)
+            m_head->shrink();
+    }
+
+private:
+    BumpPointerPool* m_head;
+};
+
+}
+
+using WTF::BumpPointerAllocator;
+
+#endif // BumpPointerAllocator_h
diff --git a/js/src/yarr/Makefile b/js/src/yarr/Makefile
deleted file mode 100644
index c824cdb96b6c..000000000000
--- a/js/src/yarr/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-INCLUDES := -I. -Iyarr -Iwtf -I../assembler/assembler -I../assembler
-
-all: 
-	$(CXX) -g3 -c $(INCLUDES) yarr/*.cpp
-	$(CXX) -g3 $(INCLUDES) TestMain.cpp *.o
diff --git a/js/src/yarr/OSAllocator.h b/js/src/yarr/OSAllocator.h
new file mode 100644
index 000000000000..ecfdc3b042ec
--- /dev/null
+++ b/js/src/yarr/OSAllocator.h
@@ -0,0 +1,103 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef OSAllocator_h
+#define OSAllocator_h
+
+#include 
+#include "wtfbridge.h"
+#include "assembler/wtf/VMTags.h"
+#include "assembler/wtf/Assertions.h"
+
+namespace WTF {
+
+class OSAllocator {
+public:
+    enum Usage {
+        UnknownUsage = -1,
+        FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY,
+        JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY,
+        JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY,
+        JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY
+    };
+
+    // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state,
+    // releaseDecommitted should be called on a region of VM allocated by a single reservation,
+    // the memory must all currently be in a decommitted state.
+    static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
+    static void releaseDecommitted(void*, size_t);
+
+    // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should
+    // never be accessed, since the OS may not have attached physical memory for these regions).
+    // Clients should only call commit on uncommitted regions and decommit on committed regions.
+    static void commit(void*, size_t, bool writable, bool executable);
+    static void decommit(void*, size_t);
+
+    // These methods are symmetric; reserveAndCommit allocates VM in an committed state,
+    // decommitAndRelease should be called on a region of VM allocated by a single reservation,
+    // the memory must all currently be in a committed state.
+    static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
+    static void decommitAndRelease(void* base, size_t size);
+
+    // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than
+    // committing/decommitting the entire region additional parameters allow a subregion to be
+    // specified.
+    static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false);
+    static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize);
+};
+
+inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable)
+{
+    void* base = reserveUncommitted(reserveSize, usage, writable, executable);
+    commit(base, commitSize, writable, executable);
+    return base;
+}
+
+inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize)
+{
+    ASSERT(decommitBase >= releaseBase && (static_cast(decommitBase) + decommitSize) <= (static_cast(releaseBase) + releaseSize));
+#if WTF_OS_WINCE || WTF_OS_SYMBIAN
+    // On most platforms we can actually skip this final decommit; releasing the VM will
+    // implicitly decommit any physical memory in the region. This is not true on WINCE.
+    // On Symbian, this makes implementation simpler and better aligned with the RChunk API
+    decommit(decommitBase, decommitSize);
+#endif
+    releaseDecommitted(releaseBase, releaseSize);
+}
+
+inline void OSAllocator::decommitAndRelease(void* base, size_t size)
+{
+    decommitAndRelease(base, size, base, size);
+}
+
+} // namespace WTF
+
+using WTF::OSAllocator;
+
+#endif // OSAllocator_h
diff --git a/js/src/yarr/OSAllocatorPosix.cpp b/js/src/yarr/OSAllocatorPosix.cpp
new file mode 100644
index 000000000000..57c240b22fe5
--- /dev/null
+++ b/js/src/yarr/OSAllocatorPosix.cpp
@@ -0,0 +1,129 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assembler/wtf/Platform.h"
+
+#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
+
+#include "OSAllocator.h"
+
+#include 
+#include 
+#include "wtf/Assertions.h"
+
+namespace WTF {
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
+{
+    void* result = reserveAndCommit(bytes, usage, writable, executable);
+#if HAVE_MADV_FREE_REUSE
+    // To support the "reserve then commit" model, we have to initially decommit.
+    while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+#endif
+    return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable)
+{
+    // All POSIX reservations start out logically committed.
+    int protection = PROT_READ;
+    if (writable)
+        protection |= PROT_WRITE;
+    if (executable)
+        protection |= PROT_EXEC;
+
+    int flags = MAP_PRIVATE | MAP_ANON;
+
+#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER)
+    int fd = usage;
+#else
+    int fd = -1;
+#endif
+
+    void* result = 0;
+#if (WTF_OS_DARWIN && WTF_CPU_X86_64)
+    if (executable) {
+        // Cook up an address to allocate at, using the following recipe:
+        //   17 bits of zero, stay in userspace kids.
+        //   26 bits of randomness for ASLR.
+        //   21 bits of zero, at least stay aligned within one level of the pagetables.
+        //
+        // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
+        // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus
+        // 2^24, which should put up somewhere in the middle of userspace (in the address range
+        // 0x200000000000 .. 0x5fffffffffff).
+        intptr_t randomLocation = 0;
+        randomLocation = arc4random() & ((1 << 25) - 1);
+        randomLocation += (1 << 24);
+        randomLocation <<= 21;
+        result = reinterpret_cast(randomLocation);
+    }
+#endif
+
+    result = mmap(result, bytes, protection, flags, fd, 0);
+    if (result == MAP_FAILED)
+        CRASH();
+    return result;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool, bool)
+{
+#if HAVE_MADV_FREE_REUSE
+    while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
+#else
+    // Non-MADV_FREE_REUSE reservations automatically commit on demand.
+    UNUSED_PARAM(address);
+    UNUSED_PARAM(bytes);
+#endif
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+#if HAVE_MADV_FREE_REUSE
+    while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+#elif HAVE_MADV_FREE
+    while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { }
+#elif HAVE_MADV_DONTNEED
+    while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
+#else
+    UNUSED_PARAM(address);
+    UNUSED_PARAM(bytes);
+#endif
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+    int result = munmap(address, bytes);
+    if (result == -1)
+        CRASH();
+}
+
+} // namespace WTF
+
+#endif
diff --git a/js/src/yarr/OSAllocatorWin.cpp b/js/src/yarr/OSAllocatorWin.cpp
new file mode 100644
index 000000000000..08df9e98aefb
--- /dev/null
+++ b/js/src/yarr/OSAllocatorWin.cpp
@@ -0,0 +1,89 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assembler/wtf/Platform.h"
+
+#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
+
+#include "windows.h"
+#include "wtf/Assertions.h"
+
+#include "OSAllocator.h"
+
+namespace WTF {
+
+static inline DWORD protection(bool writable, bool executable)
+{
+    return executable ?
+        (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) :
+        (writable ? PAGE_READWRITE : PAGE_READONLY);
+}
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable)
+{
+    void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable));
+    if (!result)
+        CRASH();
+    return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable)
+{
+    void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable));
+    if (!result)
+        CRASH();
+    return result;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
+{
+    void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable));
+    if (!result)
+        CRASH();
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+    bool result = VirtualFree(address, bytes, MEM_DECOMMIT);
+    if (!result)
+        CRASH();
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+    // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx,
+    // dwSize must be 0 if dwFreeType is MEM_RELEASE.
+    bool result = VirtualFree(address, 0, MEM_RELEASE);
+    if (!result)
+        CRASH();
+}
+
+} // namespace WTF
+
+#endif
diff --git a/js/src/yarr/PageAllocation.h b/js/src/yarr/PageAllocation.h
new file mode 100644
index 000000000000..a86f37116e50
--- /dev/null
+++ b/js/src/yarr/PageAllocation.h
@@ -0,0 +1,131 @@
+/* -*- 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) 2010 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PageAllocation_h
+#define PageAllocation_h
+
+#include "wtfbridge.h"
+#include "OSAllocator.h"
+#include "PageBlock.h"
+#include "assembler/wtf/VMTags.h"
+
+#if WTF_OS_DARWIN
+#include 
+#include 
+#endif
+
+#if WTF_OS_HAIKU
+#include 
+#endif
+
+#if WTF_OS_WINDOWS
+#include 
+#include 
+#endif
+
+#if WTF_OS_SYMBIAN
+#include 
+#include 
+#endif
+
+#if WTF_HAVE_ERRNO_H
+#include 
+#endif
+
+#if WTF_HAVE_MMAP
+#include 
+#include 
+#endif
+
+namespace WTF {
+
+/*
+    PageAllocation
+
+    The PageAllocation class provides a cross-platform memory allocation interface
+    with similar capabilities to posix mmap/munmap.  Memory is allocated by calling
+    PageAllocation::allocate, and deallocated by calling deallocate on the
+    PageAllocation object.  The PageAllocation holds the allocation's base pointer
+    and size.
+
+    The allocate method is passed the size required (which must be a multiple of
+    the system page size, which can be accessed using PageAllocation::pageSize).
+    Callers may also optinally provide a flag indicating the usage (for use by
+    system memory usage tracking tools, where implemented), and boolean values
+    specifying the required protection (defaulting to writable, non-executable).
+*/
+
+class PageAllocation : private PageBlock {
+public:
+    PageAllocation()
+    {
+    }
+
+    using PageBlock::size;
+    using PageBlock::base;
+
+#ifndef __clang__
+    using PageBlock::operator bool;
+#else
+    // FIXME: This is a workaround for , wherein Clang incorrectly emits an access
+    // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
+    operator bool() const { return PageBlock::operator bool(); }
+#endif
+
+    static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
+    {
+        ASSERT(isPageAligned(size));
+        return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size);
+    }
+
+    void deallocate()
+    {
+        // Clear base & size before calling release; if this is *inside* allocation
+        // then we won't be able to clear then after deallocating the memory.
+        PageAllocation tmp;
+        JSC::std::swap(tmp, *this);
+
+        ASSERT(tmp);
+        ASSERT(!*this);
+
+        OSAllocator::decommitAndRelease(tmp.base(), tmp.size());
+    }
+
+private:
+    PageAllocation(void* base, size_t size)
+        : PageBlock(base, size)
+    {
+    }
+};
+
+} // namespace WTF
+
+using WTF::PageAllocation;
+
+#endif // PageAllocation_h
diff --git a/js/src/yarr/PageBlock.cpp b/js/src/yarr/PageBlock.cpp
new file mode 100644
index 000000000000..0f435b772860
--- /dev/null
+++ b/js/src/yarr/PageBlock.cpp
@@ -0,0 +1,88 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "PageBlock.h"
+#include "wtf/Assertions.h"
+
+#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
+#include 
+#endif
+
+#if WTF_OS_WINDOWS
+#include 
+#include 
+#endif
+
+#if WTF_OS_SYMBIAN
+#include 
+#include 
+#endif
+
+namespace WTF {
+
+static size_t s_pageSize;
+
+#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
+
+inline size_t systemPageSize()
+{
+    return getpagesize();
+}
+
+#elif WTF_OS_WINDOWS
+
+inline size_t systemPageSize()
+{
+    static size_t size = 0;
+    SYSTEM_INFO system_info;
+    GetSystemInfo(&system_info);
+    size = system_info.dwPageSize;
+    return size;
+}
+
+#elif WTF_OS_SYMBIAN
+
+inline size_t systemPageSize()
+{
+    static TInt page_size = 0;
+    UserHal::PageSizeInBytes(page_size);
+    return page_size;
+}
+
+#endif
+
+size_t pageSize()
+{
+    if (!s_pageSize)
+        s_pageSize = systemPageSize();
+    ASSERT(isPowerOfTwo(s_pageSize));
+    return s_pageSize;
+}
+
+} // namespace WTF
diff --git a/js/src/yarr/PageBlock.h b/js/src/yarr/PageBlock.h
new file mode 100644
index 000000000000..33751315e049
--- /dev/null
+++ b/js/src/yarr/PageBlock.h
@@ -0,0 +1,91 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PageBlock_h
+#define PageBlock_h
+
+#include 
+#include "jsstdint.h"
+#include "assembler/wtf/Platform.h"
+
+namespace WTF {
+
+size_t pageSize();
+inline bool isPageAligned(void* address) { return !(reinterpret_cast(address) & (pageSize() - 1)); }
+inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
+inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
+
+class PageBlock {
+public:
+    PageBlock();
+    PageBlock(const PageBlock&);
+    PageBlock(void*, size_t);
+    
+    void* base() const { return m_base; }
+    size_t size() const { return m_size; }
+
+    operator bool() const { return !!m_base; }
+
+    bool contains(void* containedBase, size_t containedSize)
+    {
+        return containedBase >= m_base
+            && (static_cast(containedBase) + containedSize) <= (static_cast(m_base) + m_size);
+    }
+
+private:
+    void* m_base;
+    size_t m_size;
+};
+
+inline PageBlock::PageBlock()
+    : m_base(0)
+    , m_size(0)
+{
+}
+
+inline PageBlock::PageBlock(const PageBlock& other)
+    : m_base(other.m_base)
+    , m_size(other.m_size)
+{
+}
+
+inline PageBlock::PageBlock(void* base, size_t size)
+    : m_base(base)
+    , m_size(size)
+{
+}
+
+} // namespace WTF
+
+using WTF::pageSize;
+using WTF::isPageAligned;
+using WTF::isPageAligned;
+using WTF::isPowerOfTwo;
+
+#endif // PageBlock_h
diff --git a/js/src/yarr/yarr/RegExpJitTables.h b/js/src/yarr/RegExpJitTables.h
similarity index 100%
rename from js/src/yarr/yarr/RegExpJitTables.h
rename to js/src/yarr/RegExpJitTables.h
diff --git a/js/src/yarr/VMTags.h b/js/src/yarr/VMTags.h
new file mode 100644
index 000000000000..fe6a006d3601
--- /dev/null
+++ b/js/src/yarr/VMTags.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 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 VMTags_h
+#define VMTags_h
+
+// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map
+// in order to aid tools that inspect system memory use. 
+#if WTF_OS_DARWIN
+
+#include 
+
+#if !defined(TARGETING_TIGER)
+
+#if defined(VM_MEMORY_TCMALLOC)
+#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
+#else
+#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53)
+#endif // defined(VM_MEMORY_TCMALLOC)
+
+#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
+#else
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64)
+#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
+
+#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
+#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
+#else
+#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65)
+#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
+
+#else // !defined(TARGETING_TIGER)
+
+// mmap on Tiger fails with tags that work on Leopard, so fall
+// back to Tiger-compatible tags (that also work on Leopard)
+// when targeting Tiger.
+#define VM_TAG_FOR_TCMALLOC_MEMORY -1
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
+#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
+
+#endif // !defined(TARGETING_TIGER)
+
+// Tags for vm_map and vm_allocate work on both Tiger and Leopard.
+
+#if defined(VM_MEMORY_JAVASCRIPT_CORE)
+#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE)
+#else
+#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63)
+#endif // defined(VM_MEMORY_JAVASCRIPT_CORE)
+
+#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
+#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
+#else
+#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69)
+#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
+
+#else // OS(DARWIN)
+
+#define VM_TAG_FOR_TCMALLOC_MEMORY -1
+#define VM_TAG_FOR_COLLECTOR_MEMORY -1
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
+#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
+#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1
+
+#endif // OS(DARWIN)
+
+#endif // VMTags_h
diff --git a/js/src/yarr/Yarr.h b/js/src/yarr/Yarr.h
new file mode 100644
index 000000000000..40ebcca096af
--- /dev/null
+++ b/js/src/yarr/Yarr.h
@@ -0,0 +1,72 @@
+/* -*- 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.
+ *
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef Yarr_h
+#define Yarr_h
+
+#include 
+
+#include "YarrInterpreter.h"
+#include "YarrPattern.h"
+
+namespace JSC { namespace Yarr {
+
+#define YarrStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoBackReference 2
+#define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
+#define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1
+#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1
+#define YarrStackSpaceForBackTrackInfoParentheses 2
+
+static const unsigned quantifyInfinite = UINT_MAX;
+
+// The below limit restricts the number of "recursive" match calls in order to
+// avoid spending exponential time on complex regular expressions.
+static const unsigned matchLimit = 1000000;
+
+enum JSRegExpResult {
+    JSRegExpMatch = 1,
+    JSRegExpNoMatch = 0,
+    JSRegExpErrorNoMatch = -1,
+    JSRegExpErrorHitLimit = -2,
+    JSRegExpErrorNoMemory = -3,
+    JSRegExpErrorInternal = -4
+};
+
+PassOwnPtr byteCompile(YarrPattern&, BumpPointerAllocator*);
+int interpret(BytecodePattern*, const UChar* input, unsigned start, unsigned length, int* output);
+
+} } // namespace JSC::Yarr
+
+#endif // Yarr_h
+
diff --git a/js/src/yarr/YarrInterpreter.cpp b/js/src/yarr/YarrInterpreter.cpp
new file mode 100644
index 000000000000..2be8240efe60
--- /dev/null
+++ b/js/src/yarr/YarrInterpreter.cpp
@@ -0,0 +1,1914 @@
+/* -*- 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
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "YarrInterpreter.h"
+
+#include "Yarr.h"
+#include "BumpPointerAllocator.h"
+
+#ifndef NDEBUG
+#include 
+#endif
+
+using namespace WTF;
+
+namespace JSC { namespace Yarr {
+
+class Interpreter {
+public:
+    struct ParenthesesDisjunctionContext;
+
+    struct BackTrackInfoPatternCharacter {
+        uintptr_t matchAmount;
+    };
+    struct BackTrackInfoCharacterClass {
+        uintptr_t matchAmount;
+    };
+    struct BackTrackInfoBackReference {
+        uintptr_t begin; // Not really needed for greedy quantifiers.
+        uintptr_t matchAmount; // Not really needed for fixed quantifiers.
+    };
+    struct BackTrackInfoAlternative {
+        uintptr_t offset;
+    };
+    struct BackTrackInfoParentheticalAssertion {
+        uintptr_t begin;
+    };
+    struct BackTrackInfoParenthesesOnce {
+        uintptr_t begin;
+    };
+    struct BackTrackInfoParenthesesTerminal {
+        uintptr_t begin;
+    };
+    struct BackTrackInfoParentheses {
+        uintptr_t matchAmount;
+        ParenthesesDisjunctionContext* lastContext;
+    };
+
+    static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context)
+    {
+        context->next = backTrack->lastContext;
+        backTrack->lastContext = context;
+        ++backTrack->matchAmount;
+    }
+
+    static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack)
+    {
+        ASSERT(backTrack->matchAmount);
+        ASSERT(backTrack->lastContext);
+        backTrack->lastContext = backTrack->lastContext->next;
+        --backTrack->matchAmount;
+    }
+
+    struct DisjunctionContext
+    {
+        DisjunctionContext()
+            : term(0)
+        {
+        }
+
+        void* operator new(size_t, void* where)
+        {
+            return where;
+        }
+
+        int term;
+        unsigned matchBegin;
+        unsigned matchEnd;
+        uintptr_t frame[1];
+    };
+
+    DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction)
+    {
+        size_t size = sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
+        allocatorPool = allocatorPool->ensureCapacity(size);
+        if (!allocatorPool)
+            CRASH();
+        return new(allocatorPool->alloc(size)) DisjunctionContext();
+    }
+
+    void freeDisjunctionContext(DisjunctionContext* context)
+    {
+        allocatorPool = allocatorPool->dealloc(context);
+    }
+
+    struct ParenthesesDisjunctionContext
+    {
+        ParenthesesDisjunctionContext(int* output, ByteTerm& term)
+            : next(0)
+        {
+            unsigned firstSubpatternId = term.atom.subpatternId;
+            unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns;
+
+            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) {
+                subpatternBackup[i] = output[(firstSubpatternId << 1) + i];
+                output[(firstSubpatternId << 1) + i] = -1;
+            }
+
+            new(getDisjunctionContext(term)) DisjunctionContext();
+        }
+
+        void* operator new(size_t, void* where)
+        {
+            return where;
+        }
+
+        void restoreOutput(int* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns)
+        {
+            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i)
+                output[(firstSubpatternId << 1) + i] = subpatternBackup[i];
+        }
+
+        DisjunctionContext* getDisjunctionContext(ByteTerm& term)
+        {
+            return reinterpret_cast(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1]));
+        }
+
+        ParenthesesDisjunctionContext* next;
+        int subpatternBackup[1];
+    };
+
+    ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, int* output, ByteTerm& term)
+    {
+        size_t size = sizeof(ParenthesesDisjunctionContext) - sizeof(int) + (term.atom.parenthesesDisjunction->m_numSubpatterns << 1) * sizeof(int) + sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
+        allocatorPool = allocatorPool->ensureCapacity(size);
+        if (!allocatorPool)
+            CRASH();
+        return new(allocatorPool->alloc(size)) ParenthesesDisjunctionContext(output, term);
+    }
+
+    void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context)
+    {
+        allocatorPool = allocatorPool->dealloc(context);
+    }
+
+    class InputStream {
+    public:
+        InputStream(const UChar* input, unsigned start, unsigned length)
+            : input(input)
+            , pos(start)
+            , length(length)
+        {
+        }
+
+        void next()
+        {
+            ++pos;
+        }
+
+        void rewind(unsigned amount)
+        {
+            ASSERT(pos >= amount);
+            pos -= amount;
+        }
+
+        int read()
+        {
+            ASSERT(pos < length);
+            if (pos < length)
+                return input[pos];
+            return -1;
+        }
+
+        int readPair()
+        {
+            ASSERT(pos + 1 < length);
+            return input[pos] | input[pos + 1] << 16;
+        }
+
+        int readChecked(int position)
+        {
+            ASSERT(position < 0);
+            ASSERT(static_cast(-position) <= pos);
+            unsigned p = pos + position;
+            ASSERT(p < length);
+            return input[p];
+        }
+
+        int reread(unsigned from)
+        {
+            ASSERT(from < length);
+            return input[from];
+        }
+
+        int prev()
+        {
+            ASSERT(!(pos > length));
+            if (pos && length)
+                return input[pos - 1];
+            return -1;
+        }
+
+        unsigned getPos()
+        {
+            return pos;
+        }
+
+        void setPos(unsigned p)
+        {
+            pos = p;
+        }
+
+        bool atStart()
+        {
+            return pos == 0;
+        }
+
+        bool atEnd()
+        {
+            return pos == length;
+        }
+
+        bool checkInput(int count)
+        {
+            if ((pos + count) <= length) {
+                pos += count;
+                return true;
+            }
+            return false;
+        }
+
+        void uncheckInput(int count)
+        {
+            pos -= count;
+        }
+
+        bool atStart(int position)
+        {
+            return (pos + position) == 0;
+        }
+
+        bool atEnd(int position)
+        {
+            return (pos + position) == length;
+        }
+
+        bool isNotAvailableInput(int position)
+        {
+            return (pos + position) > length;
+        }
+
+    private:
+        const UChar* input;
+        unsigned pos;
+        unsigned length;
+    };
+
+    bool testCharacterClass(CharacterClass* characterClass, int ch)
+    {
+        if (ch & 0xFF80) {
+            for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i)
+                if (ch == characterClass->m_matchesUnicode[i])
+                    return true;
+            for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i)
+                if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end))
+                    return true;
+        } else {
+            for (unsigned i = 0; i < characterClass->m_matches.size(); ++i)
+                if (ch == characterClass->m_matches[i])
+                    return true;
+            for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i)
+                if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end))
+                    return true;
+        }
+
+        return false;
+    }
+
+    bool checkCharacter(int testChar, int inputPosition)
+    {
+        return testChar == input.readChecked(inputPosition);
+    }
+
+    bool checkCasedCharacter(int loChar, int hiChar, int inputPosition)
+    {
+        int ch = input.readChecked(inputPosition);
+        return (loChar == ch) || (hiChar == ch);
+    }
+
+    bool checkCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition)
+    {
+        bool match = testCharacterClass(characterClass, input.readChecked(inputPosition));
+        return invert ? !match : match;
+    }
+
+    bool tryConsumeBackReference(int matchBegin, int matchEnd, int inputOffset)
+    {
+        int matchSize = matchEnd - matchBegin;
+
+        if (!input.checkInput(matchSize))
+            return false;
+
+        if (pattern->m_ignoreCase) {
+            for (int i = 0; i < matchSize; ++i) {
+                int ch = input.reread(matchBegin + i);
+
+                int lo = Unicode::toLower(ch);
+                int hi = Unicode::toUpper(ch);
+
+                if ((lo != hi) ? (!checkCasedCharacter(lo, hi, inputOffset - matchSize + i)) : (!checkCharacter(ch, inputOffset - matchSize + i))) {
+                    input.uncheckInput(matchSize);
+                    return false;
+                }
+            }
+        } else {
+            for (int i = 0; i < matchSize; ++i) {
+                if (!checkCharacter(input.reread(matchBegin + i), inputOffset - matchSize + i)) {
+                    input.uncheckInput(matchSize);
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    bool matchAssertionBOL(ByteTerm& term)
+    {
+        return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition - 1)));
+    }
+
+    bool matchAssertionEOL(ByteTerm& term)
+    {
+        if (term.inputPosition)
+            return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition)));
+
+        return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read()));
+    }
+
+    bool matchAssertionWordBoundary(ByteTerm& term)
+    {
+        bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition - 1));
+        bool readIsWordchar;
+        if (term.inputPosition)
+            readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition));
+        else
+            readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read());
+
+        bool wordBoundary = prevIsWordchar != readIsWordchar;
+        return term.invert() ? !wordBoundary : wordBoundary;
+    }
+
+    bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context)
+    {
+        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount:
+            break;
+
+        case QuantifierGreedy:
+            if (backTrack->matchAmount) {
+                --backTrack->matchAmount;
+                input.uncheckInput(1);
+                return true;
+            }
+            break;
+
+        case QuantifierNonGreedy:
+            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+                ++backTrack->matchAmount;
+                if (checkCharacter(term.atom.patternCharacter, term.inputPosition - 1))
+                    return true;
+            }
+            input.uncheckInput(backTrack->matchAmount);
+            break;
+        }
+
+        return false;
+    }
+
+    bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context)
+    {
+        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount:
+            break;
+
+        case QuantifierGreedy:
+            if (backTrack->matchAmount) {
+                --backTrack->matchAmount;
+                input.uncheckInput(1);
+                return true;
+            }
+            break;
+
+        case QuantifierNonGreedy:
+            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+                ++backTrack->matchAmount;
+                if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition - 1))
+                    return true;
+            }
+            input.uncheckInput(backTrack->matchAmount);
+            break;
+        }
+
+        return false;
+    }
+
+    bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeCharacterClass);
+        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + matchAmount))
+                    return false;
+            }
+            return true;
+        }
+
+        case QuantifierGreedy: {
+            unsigned matchAmount = 0;
+            while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) {
+                    input.uncheckInput(1);
+                    break;
+                }
+                ++matchAmount;
+            }
+            backTrack->matchAmount = matchAmount;
+
+            return true;
+        }
+
+        case QuantifierNonGreedy:
+            backTrack->matchAmount = 0;
+            return true;
+        }
+
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+
+    bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeCharacterClass);
+        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount:
+            break;
+
+        case QuantifierGreedy:
+            if (backTrack->matchAmount) {
+                --backTrack->matchAmount;
+                input.uncheckInput(1);
+                return true;
+            }
+            break;
+
+        case QuantifierNonGreedy:
+            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+                ++backTrack->matchAmount;
+                if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1))
+                    return true;
+            }
+            input.uncheckInput(backTrack->matchAmount);
+            break;
+        }
+
+        return false;
+    }
+
+    bool matchBackReference(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeBackReference);
+        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        int matchBegin = output[(term.atom.subpatternId << 1)];
+        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
+
+        // If the end position of the referenced match hasn't set yet then the backreference in the same parentheses where it references to that.
+        // In this case the result of match is empty string like when it references to a parentheses with zero-width match.
+        // Eg.: /(a\1)/
+        if (matchEnd == -1)
+            return true;
+
+        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
+
+        if (matchBegin == matchEnd)
+            return true;
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            backTrack->begin = input.getPos();
+            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+                if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
+                    input.setPos(backTrack->begin);
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        case QuantifierGreedy: {
+            unsigned matchAmount = 0;
+            while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
+                ++matchAmount;
+            backTrack->matchAmount = matchAmount;
+            return true;
+        }
+
+        case QuantifierNonGreedy:
+            backTrack->begin = input.getPos();
+            backTrack->matchAmount = 0;
+            return true;
+        }
+
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+
+    bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeBackReference);
+        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        int matchBegin = output[(term.atom.subpatternId << 1)];
+        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
+        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
+
+        if (matchBegin == matchEnd)
+            return false;
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount:
+            // for quantityCount == 1, could rewind.
+            input.setPos(backTrack->begin);
+            break;
+
+        case QuantifierGreedy:
+            if (backTrack->matchAmount) {
+                --backTrack->matchAmount;
+                input.rewind(matchEnd - matchBegin);
+                return true;
+            }
+            break;
+
+        case QuantifierNonGreedy:
+            if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
+                ++backTrack->matchAmount;
+                return true;
+            }
+            input.setPos(backTrack->begin);
+            break;
+        }
+
+        return false;
+    }
+
+    void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context)
+    {
+        if (term.capture()) {
+            unsigned subpatternId = term.atom.subpatternId;
+            output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition;
+            output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition;
+        }
+    }
+    void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context)
+    {
+        unsigned firstSubpatternId = term.atom.subpatternId;
+        unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns;
+        context->restoreOutput(output, firstSubpatternId, count);
+    }
+    JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack)
+    {
+        while (backTrack->matchAmount) {
+            ParenthesesDisjunctionContext* context = backTrack->lastContext;
+
+            JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true);
+            if (result == JSRegExpMatch)
+                return JSRegExpMatch;
+
+            resetMatches(term, context);
+            popParenthesesDisjunctionContext(backTrack);
+            freeParenthesesDisjunctionContext(context);
+
+            if (result != JSRegExpNoMatch)
+                return result;
+        }
+
+        return JSRegExpNoMatch;
+    }
+
+    bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierGreedy: {
+            // set this speculatively; if we get to the parens end this will be true.
+            backTrack->begin = input.getPos();
+            break;
+        }
+        case QuantifierNonGreedy: {
+            backTrack->begin = notFound;
+            context->term += term.atom.parenthesesWidth;
+            return true;
+        }
+        case QuantifierFixedCount:
+            break;
+        }
+
+        if (term.capture()) {
+            unsigned subpatternId = term.atom.subpatternId;
+            output[(subpatternId << 1)] = input.getPos() + term.inputPosition;
+        }
+
+        return true;
+    }
+
+    bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
+        ASSERT(term.atom.quantityCount == 1);
+
+        if (term.capture()) {
+            unsigned subpatternId = term.atom.subpatternId;
+            output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
+        }
+
+        if (term.atom.quantityType == QuantifierFixedCount)
+            return true;
+
+        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        return backTrack->begin != input.getPos();
+    }
+
+    bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        if (term.capture()) {
+            unsigned subpatternId = term.atom.subpatternId;
+            output[(subpatternId << 1)] = -1;
+            output[(subpatternId << 1) + 1] = -1;
+        }
+
+        switch (term.atom.quantityType) {
+        case QuantifierGreedy:
+            // if we backtrack to this point, there is another chance - try matching nothing.
+            ASSERT(backTrack->begin != notFound);
+            backTrack->begin = notFound;
+            context->term += term.atom.parenthesesWidth;
+            return true;
+        case QuantifierNonGreedy:
+            ASSERT(backTrack->begin != notFound);
+        case QuantifierFixedCount:
+            break;
+        }
+
+        return false;
+    }
+
+    bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierGreedy:
+            if (backTrack->begin == notFound) {
+                context->term -= term.atom.parenthesesWidth;
+                return false;
+            }
+        case QuantifierNonGreedy:
+            if (backTrack->begin == notFound) {
+                backTrack->begin = input.getPos();
+                if (term.capture()) {
+                    // Technically this access to inputPosition should be accessing the begin term's
+                    // inputPosition, but for repeats other than fixed these values should be
+                    // the same anyway! (We don't pre-check for greedy or non-greedy matches.)
+                    ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+                    ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition);
+                    unsigned subpatternId = term.atom.subpatternId;
+                    output[subpatternId << 1] = input.getPos() + term.inputPosition;
+                }
+                context->term -= term.atom.parenthesesWidth;
+                return true;
+            }
+        case QuantifierFixedCount:
+            break;
+        }
+
+        return false;
+    }
+
+    bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+        ASSERT(term.atom.quantityType == QuantifierGreedy);
+        ASSERT(term.atom.quantityCount == quantifyInfinite);
+        ASSERT(!term.capture());
+
+        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        backTrack->begin = input.getPos();
+        return true;
+    }
+
+    bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd);
+
+        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        // Empty match is a failed match.
+        if (backTrack->begin == input.getPos())
+            return false;
+
+        // Successful match! Okay, what's next? - loop around and try to match moar!
+        context->term -= (term.atom.parenthesesWidth + 1);
+        return true;
+    }
+
+    bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+        ASSERT(term.atom.quantityType == QuantifierGreedy);
+        ASSERT(term.atom.quantityCount == quantifyInfinite);
+        ASSERT(!term.capture());
+
+        // If we backtrack to this point, we have failed to match this iteration of the parens.
+        // Since this is greedy / zero minimum a failed is also accepted as a match!
+        context->term += term.atom.parenthesesWidth;
+        return true;
+    }
+
+    bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*)
+    {
+        // 'Terminal' parentheses are at the end of the regex, and as such a match past end
+        // should always be returned as a successful match - we should never backtrack to here.
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+
+    bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        backTrack->begin = input.getPos();
+        return true;
+    }
+
+    bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        input.setPos(backTrack->begin);
+
+        // We've reached the end of the parens; if they are inverted, this is failure.
+        if (term.invert()) {
+            context->term -= term.atom.parenthesesWidth;
+            return false;
+        }
+
+        return true;
+    }
+
+    bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
+        ASSERT(term.atom.quantityCount == 1);
+
+        // We've failed to match parens; if they are inverted, this is win!
+        if (term.invert()) {
+            context->term += term.atom.parenthesesWidth;
+            return true;
+        }
+
+        return false;
+    }
+
+    bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        input.setPos(backTrack->begin);
+
+        context->term -= term.atom.parenthesesWidth;
+        return false;
+    }
+
+    JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
+
+        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
+
+        backTrack->matchAmount = 0;
+        backTrack->lastContext = 0;
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            // While we haven't yet reached our fixed limit,
+            while (backTrack->matchAmount < term.atom.quantityCount) {
+                // Try to do a match, and it it succeeds, add it to the list.
+                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                if (result == JSRegExpMatch)
+                    appendParenthesesDisjunctionContext(backTrack, context);
+                else {
+                    // The match failed; try to find an alternate point to carry on from.
+                    resetMatches(term, context);
+                    freeParenthesesDisjunctionContext(context);
+
+                    if (result == JSRegExpNoMatch) {
+                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
+                        if (backtrackResult != JSRegExpMatch)
+                            return backtrackResult;
+                    } else
+                        return result;
+                }
+            }
+
+            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+            ParenthesesDisjunctionContext* context = backTrack->lastContext;
+            recordParenthesesMatch(term, context);
+            return JSRegExpMatch;
+        }
+
+        case QuantifierGreedy: {
+            while (backTrack->matchAmount < term.atom.quantityCount) {
+                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                if (result == JSRegExpMatch)
+                    appendParenthesesDisjunctionContext(backTrack, context);
+                else {
+                    resetMatches(term, context);
+                    freeParenthesesDisjunctionContext(context);
+
+                    if (result != JSRegExpNoMatch)
+                        return result;
+
+                    break;
+                }
+            }
+
+            if (backTrack->matchAmount) {
+                ParenthesesDisjunctionContext* context = backTrack->lastContext;
+                recordParenthesesMatch(term, context);
+            }
+            return JSRegExpMatch;
+        }
+
+        case QuantifierNonGreedy:
+            return JSRegExpMatch;
+        }
+
+        ASSERT_NOT_REACHED();
+        return JSRegExpErrorNoMatch;
+    }
+
+    // Rules for backtracking differ depending on whether this is greedy or non-greedy.
+    //
+    // Greedy matches never should try just adding more - you should already have done
+    // the 'more' cases.  Always backtrack, at least a leetle bit.  However cases where
+    // you backtrack an item off the list needs checking, since we'll never have matched
+    // the one less case.  Tracking forwards, still add as much as possible.
+    //
+    // Non-greedy, we've already done the one less case, so don't match on popping.
+    // We haven't done the one more case, so always try to add that.
+    //
+    JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
+
+        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+
+            ParenthesesDisjunctionContext* context = 0;
+            JSRegExpResult result = parenthesesDoBacktrack(term, backTrack);
+
+            if (result != JSRegExpMatch)
+                return result;
+
+            // While we haven't yet reached our fixed limit,
+            while (backTrack->matchAmount < term.atom.quantityCount) {
+                // Try to do a match, and it it succeeds, add it to the list.
+                context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+
+                if (result == JSRegExpMatch)
+                    appendParenthesesDisjunctionContext(backTrack, context);
+                else {
+                    // The match failed; try to find an alternate point to carry on from.
+                    resetMatches(term, context);
+                    freeParenthesesDisjunctionContext(context);
+
+                    if (result == JSRegExpNoMatch) {
+                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
+                        if (backtrackResult != JSRegExpMatch)
+                            return backtrackResult;
+                    } else
+                        return result;
+                }
+            }
+
+            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+            context = backTrack->lastContext;
+            recordParenthesesMatch(term, context);
+            return JSRegExpMatch;
+        }
+
+        case QuantifierGreedy: {
+            if (!backTrack->matchAmount)
+                return JSRegExpNoMatch;
+
+            ParenthesesDisjunctionContext* context = backTrack->lastContext;
+            JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
+            if (result == JSRegExpMatch) {
+                while (backTrack->matchAmount < term.atom.quantityCount) {
+                    ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                    JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                    if (parenthesesResult == JSRegExpMatch)
+                        appendParenthesesDisjunctionContext(backTrack, context);
+                    else {
+                        resetMatches(term, context);
+                        freeParenthesesDisjunctionContext(context);
+
+                        if (parenthesesResult != JSRegExpNoMatch)
+                            return parenthesesResult;
+
+                        break;
+                    }
+                }
+            } else {
+                resetMatches(term, context);
+                popParenthesesDisjunctionContext(backTrack);
+                freeParenthesesDisjunctionContext(context);
+
+                if (result != JSRegExpNoMatch)
+                    return result;
+            }
+
+            if (backTrack->matchAmount) {
+                ParenthesesDisjunctionContext* context = backTrack->lastContext;
+                recordParenthesesMatch(term, context);
+            }
+            return JSRegExpMatch;
+        }
+
+        case QuantifierNonGreedy: {
+            // If we've not reached the limit, try to add one more match.
+            if (backTrack->matchAmount < term.atom.quantityCount) {
+                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                if (result == JSRegExpMatch) {
+                    appendParenthesesDisjunctionContext(backTrack, context);
+                    recordParenthesesMatch(term, context);
+                    return JSRegExpMatch;
+                }
+
+                resetMatches(term, context);
+                freeParenthesesDisjunctionContext(context);
+
+                if (result != JSRegExpNoMatch)
+                    return result;
+            }
+
+            // Nope - okay backtrack looking for an alternative.
+            while (backTrack->matchAmount) {
+                ParenthesesDisjunctionContext* context = backTrack->lastContext;
+                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
+                if (result == JSRegExpMatch) {
+                    // successful backtrack! we're back in the game!
+                    if (backTrack->matchAmount) {
+                        context = backTrack->lastContext;
+                        recordParenthesesMatch(term, context);
+                    }
+                    return JSRegExpMatch;
+                }
+
+                // pop a match off the stack
+                resetMatches(term, context);
+                popParenthesesDisjunctionContext(backTrack);
+                freeParenthesesDisjunctionContext(context);
+
+                return result;
+            }
+
+            return JSRegExpNoMatch;
+        }
+        }
+
+        ASSERT_NOT_REACHED();
+        return JSRegExpErrorNoMatch;
+    }
+
+    void lookupForBeginChars()
+    {
+        int character;
+        bool firstSingleCharFound;
+
+        while (true) {
+            if (input.isNotAvailableInput(2))
+                return;
+
+            firstSingleCharFound = false;
+
+            character = input.readPair();
+
+            for (unsigned i = 0; i < pattern->m_beginChars.size(); ++i) {
+                BeginChar bc = pattern->m_beginChars[i];
+
+                if (!firstSingleCharFound && bc.value <= 0xFFFF) {
+                    firstSingleCharFound = true;
+                    character &= 0xFFFF;
+                }
+
+                if ((character | bc.mask) == bc.value)
+                    return;
+            }
+
+            input.next();
+        }
+    }
+
+#define MATCH_NEXT() { ++context->term; goto matchAgain; }
+#define BACKTRACK() { --context->term; goto backtrack; }
+#define currentTerm() (disjunction->terms[context->term])
+    JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false, bool isBody = false)
+    {
+        if (!--remainingMatchCount)
+            return JSRegExpErrorHitLimit;
+
+        if (btrack)
+            BACKTRACK();
+
+        if (pattern->m_containsBeginChars && isBody)
+            lookupForBeginChars();
+
+        context->matchBegin = input.getPos();
+        context->term = 0;
+
+    matchAgain:
+        ASSERT(context->term < static_cast(disjunction->terms.size()));
+
+        switch (currentTerm().type) {
+        case ByteTerm::TypeSubpatternBegin:
+            MATCH_NEXT();
+        case ByteTerm::TypeSubpatternEnd:
+            context->matchEnd = input.getPos();
+            return JSRegExpMatch;
+
+        case ByteTerm::TypeBodyAlternativeBegin:
+            MATCH_NEXT();
+        case ByteTerm::TypeBodyAlternativeDisjunction:
+        case ByteTerm::TypeBodyAlternativeEnd:
+            context->matchEnd = input.getPos();
+            return JSRegExpMatch;
+
+        case ByteTerm::TypeAlternativeBegin:
+            MATCH_NEXT();
+        case ByteTerm::TypeAlternativeDisjunction:
+        case ByteTerm::TypeAlternativeEnd: {
+            int offset = currentTerm().alternative.end;
+            BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            backTrack->offset = offset;
+            context->term += offset;
+            MATCH_NEXT();
+        }
+
+        case ByteTerm::TypeAssertionBOL:
+            if (matchAssertionBOL(currentTerm()))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeAssertionEOL:
+            if (matchAssertionEOL(currentTerm()))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeAssertionWordBoundary:
+            if (matchAssertionWordBoundary(currentTerm()))
+                MATCH_NEXT();
+            BACKTRACK();
+
+        case ByteTerm::TypePatternCharacterOnce:
+        case ByteTerm::TypePatternCharacterFixed: {
+            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + matchAmount))
+                    BACKTRACK();
+            }
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypePatternCharacterGreedy: {
+            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            unsigned matchAmount = 0;
+            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
+                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 1)) {
+                    input.uncheckInput(1);
+                    break;
+                }
+                ++matchAmount;
+            }
+            backTrack->matchAmount = matchAmount;
+
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypePatternCharacterNonGreedy: {
+            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            backTrack->matchAmount = 0;
+            MATCH_NEXT();
+        }
+
+        case ByteTerm::TypePatternCasedCharacterOnce:
+        case ByteTerm::TypePatternCasedCharacterFixed: {
+            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + matchAmount))
+                    BACKTRACK();
+            }
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypePatternCasedCharacterGreedy: {
+            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            unsigned matchAmount = 0;
+            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
+                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - 1)) {
+                    input.uncheckInput(1);
+                    break;
+                }
+                ++matchAmount;
+            }
+            backTrack->matchAmount = matchAmount;
+
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypePatternCasedCharacterNonGreedy: {
+            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            backTrack->matchAmount = 0;
+            MATCH_NEXT();
+        }
+
+        case ByteTerm::TypeCharacterClass:
+            if (matchCharacterClass(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeBackReference:
+            if (matchBackReference(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParenthesesSubpattern: {
+            JSRegExpResult result = matchParentheses(currentTerm(), context);
+
+            if (result == JSRegExpMatch) {
+                MATCH_NEXT();
+            }  else if (result != JSRegExpNoMatch)
+                return result;
+
+            BACKTRACK();
+        }
+        case ByteTerm::TypeParenthesesSubpatternOnceBegin:
+            if (matchParenthesesOnceBegin(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParenthesesSubpatternOnceEnd:
+            if (matchParenthesesOnceEnd(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
+            if (matchParenthesesTerminalBegin(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
+            if (matchParenthesesTerminalEnd(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParentheticalAssertionBegin:
+            if (matchParentheticalAssertionBegin(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParentheticalAssertionEnd:
+            if (matchParentheticalAssertionEnd(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+
+        case ByteTerm::TypeCheckInput:
+            if (input.checkInput(currentTerm().checkInputCount))
+                MATCH_NEXT();
+            BACKTRACK();
+
+            case ByteTerm::TypeUncheckInput:
+                input.uncheckInput(currentTerm().checkInputCount);
+                MATCH_NEXT();
+        }
+
+        // We should never fall-through to here.
+        ASSERT_NOT_REACHED();
+
+    backtrack:
+        ASSERT(context->term < static_cast(disjunction->terms.size()));
+
+        switch (currentTerm().type) {
+        case ByteTerm::TypeSubpatternBegin:
+            return JSRegExpNoMatch;
+        case ByteTerm::TypeSubpatternEnd:
+            ASSERT_NOT_REACHED();
+
+        case ByteTerm::TypeBodyAlternativeBegin:
+        case ByteTerm::TypeBodyAlternativeDisjunction: {
+            int offset = currentTerm().alternative.next;
+            context->term += offset;
+            if (offset > 0)
+                MATCH_NEXT();
+
+            if (input.atEnd())
+                return JSRegExpNoMatch;
+
+            input.next();
+
+            if (pattern->m_containsBeginChars && isBody)
+                lookupForBeginChars();
+
+            context->matchBegin = input.getPos();
+
+            if (currentTerm().alternative.onceThrough)
+                context->term += currentTerm().alternative.next;
+
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypeBodyAlternativeEnd:
+            ASSERT_NOT_REACHED();
+
+            case ByteTerm::TypeAlternativeBegin:
+            case ByteTerm::TypeAlternativeDisjunction: {
+                int offset = currentTerm().alternative.next;
+                context->term += offset;
+                if (offset > 0)
+                    MATCH_NEXT();
+                BACKTRACK();
+            }
+            case ByteTerm::TypeAlternativeEnd: {
+                // We should never backtrack back into an alternative of the main body of the regex.
+                BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+                unsigned offset = backTrack->offset;
+                context->term -= offset;
+                BACKTRACK();
+            }
+
+            case ByteTerm::TypeAssertionBOL:
+            case ByteTerm::TypeAssertionEOL:
+            case ByteTerm::TypeAssertionWordBoundary:
+                BACKTRACK();
+
+            case ByteTerm::TypePatternCharacterOnce:
+            case ByteTerm::TypePatternCharacterFixed:
+            case ByteTerm::TypePatternCharacterGreedy:
+            case ByteTerm::TypePatternCharacterNonGreedy:
+                if (backtrackPatternCharacter(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypePatternCasedCharacterOnce:
+            case ByteTerm::TypePatternCasedCharacterFixed:
+            case ByteTerm::TypePatternCasedCharacterGreedy:
+            case ByteTerm::TypePatternCasedCharacterNonGreedy:
+                if (backtrackPatternCasedCharacter(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeCharacterClass:
+                if (backtrackCharacterClass(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeBackReference:
+                if (backtrackBackReference(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParenthesesSubpattern: {
+                JSRegExpResult result = backtrackParentheses(currentTerm(), context);
+
+                if (result == JSRegExpMatch) {
+                    MATCH_NEXT();
+                } else if (result != JSRegExpNoMatch)
+                    return result;
+
+                BACKTRACK();
+            }
+            case ByteTerm::TypeParenthesesSubpatternOnceBegin:
+                if (backtrackParenthesesOnceBegin(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParenthesesSubpatternOnceEnd:
+                if (backtrackParenthesesOnceEnd(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
+                if (backtrackParenthesesTerminalBegin(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
+                if (backtrackParenthesesTerminalEnd(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParentheticalAssertionBegin:
+                if (backtrackParentheticalAssertionBegin(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParentheticalAssertionEnd:
+                if (backtrackParentheticalAssertionEnd(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+
+            case ByteTerm::TypeCheckInput:
+                input.uncheckInput(currentTerm().checkInputCount);
+                BACKTRACK();
+
+            case ByteTerm::TypeUncheckInput:
+                input.checkInput(currentTerm().checkInputCount);
+                BACKTRACK();
+        }
+
+        ASSERT_NOT_REACHED();
+        return JSRegExpErrorNoMatch;
+    }
+
+    JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
+    {
+        JSRegExpResult result = matchDisjunction(disjunction, context, btrack);
+
+        if (result == JSRegExpMatch) {
+            while (context->matchBegin == context->matchEnd) {
+                result = matchDisjunction(disjunction, context, true);
+                if (result != JSRegExpMatch)
+                    return result;
+            }
+            return JSRegExpMatch;
+        }
+
+        return result;
+    }
+
+    int interpret()
+    {
+        allocatorPool = pattern->m_allocator->startAllocator();
+        if (!allocatorPool)
+            CRASH();
+
+        for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i)
+            output[i] = -1;
+
+        DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get());
+
+        JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false, true);
+        if (result == JSRegExpMatch) {
+            output[0] = context->matchBegin;
+            output[1] = context->matchEnd;
+        }
+
+        freeDisjunctionContext(context);
+
+        pattern->m_allocator->stopAllocator();
+
+        // RegExp.cpp currently expects all error to be converted to -1.
+        ASSERT((result == JSRegExpMatch) == (output[0] != -1));
+        return output[0];
+    }
+
+    Interpreter(BytecodePattern* pattern, int* output, const UChar* inputChar, unsigned start, unsigned length)
+        : pattern(pattern)
+        , output(output)
+        , input(inputChar, start, length)
+        , allocatorPool(0)
+        , remainingMatchCount(matchLimit)
+    {
+    }
+
+private:
+    BytecodePattern* pattern;
+    int* output;
+    InputStream input;
+    BumpPointerPool* allocatorPool;
+    unsigned remainingMatchCount;
+};
+
+
+
+class ByteCompiler {
+    struct ParenthesesStackEntry {
+        unsigned beginTerm;
+        unsigned savedAlternativeIndex;
+        // For js::Vector. Does not create a valid object.
+        ParenthesesStackEntry() {}
+        ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/)
+            : beginTerm(beginTerm)
+            , savedAlternativeIndex(savedAlternativeIndex)
+        {
+        }
+    };
+
+public:
+    ByteCompiler(YarrPattern& pattern)
+        : m_pattern(pattern)
+    {
+        m_currentAlternativeIndex = 0;
+    }
+
+    PassOwnPtr compile(BumpPointerAllocator* allocator)
+    {
+        regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough());
+        emitDisjunction(m_pattern.m_body);
+        regexEnd();
+
+        return adoptPtr(js::OffTheBooks::new_(m_bodyDisjunction.release(), m_allParenthesesInfo, m_pattern, allocator));
+    }
+
+    void checkInput(unsigned count)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count));
+    }
+
+    void uncheckInput(unsigned count)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::UncheckInput(count));
+    }
+    
+    void assertionBOL(int inputPosition)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition));
+    }
+
+    void assertionEOL(int inputPosition)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition));
+    }
+
+    void assertionWordBoundary(bool invert, int inputPosition)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition));
+    }
+
+    void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        if (m_pattern.m_ignoreCase) {
+            UChar lo = Unicode::toLower(ch);
+            UChar hi = Unicode::toUpper(ch);
+
+            if (lo != hi) {
+                m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType));
+                return;
+            }
+        }
+
+        m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType));
+    }
+
+    void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition));
+
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+    }
+
+    void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        ASSERT(subpatternId);
+
+        m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition));
+
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+    }
+
+    void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+    {
+        int beginTerm = m_bodyDisjunction->terms.size();
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+        m_currentAlternativeIndex = beginTerm + 1;
+    }
+
+    void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+    {
+        int beginTerm = m_bodyDisjunction->terms.size();
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+        m_currentAlternativeIndex = beginTerm + 1;
+    }
+
+    void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+    {
+        // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin,
+        // then fix this up at the end! - simplifying this should make it much clearer.
+        // https://bugs.webkit.org/show_bug.cgi?id=50136
+
+        int beginTerm = m_bodyDisjunction->terms.size();
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+        m_currentAlternativeIndex = beginTerm + 1;
+    }
+
+    void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation)
+    {
+        int beginTerm = m_bodyDisjunction->terms.size();
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, false, invert, 0));
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+        m_currentAlternativeIndex = beginTerm + 1;
+    }
+
+    void atomParentheticalAssertionEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        unsigned beginTerm = popParenthesesStack();
+        closeAlternative(beginTerm + 1);
+        unsigned endTerm = m_bodyDisjunction->terms.size();
+
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin);
+
+        bool invert = m_bodyDisjunction->terms[beginTerm].invert();
+        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, false, invert, inputPosition));
+        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+    }
+
+    unsigned popParenthesesStack()
+    {
+        ASSERT(m_parenthesesStack.size());
+        int stackEnd = m_parenthesesStack.size() - 1;
+        unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm;
+        m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex;
+        m_parenthesesStack.shrink(stackEnd);
+
+        ASSERT(beginTerm < m_bodyDisjunction->terms.size());
+        ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size());
+
+        return beginTerm;
+    }
+
+#ifndef NDEBUG
+    void dumpDisjunction(ByteDisjunction* disjunction)
+    {
+        printf("ByteDisjunction(%p):\n\t", disjunction);
+        for (unsigned i = 0; i < disjunction->terms.size(); ++i)
+            printf("{ %d } ", disjunction->terms[i].type);
+        printf("\n");
+    }
+#endif
+
+    void closeAlternative(int beginTerm)
+    {
+        int origBeginTerm = beginTerm;
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin);
+        int endIndex = m_bodyDisjunction->terms.size();
+
+        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
+
+        if (!m_bodyDisjunction->terms[beginTerm].alternative.next)
+            m_bodyDisjunction->terms.remove(beginTerm);
+        else {
+            while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
+                beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
+                ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction);
+                m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
+                m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+            }
+
+            m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
+
+            m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd());
+            m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
+        }
+    }
+
+    void closeBodyAlternative()
+    {
+        int beginTerm = 0;
+        int origBeginTerm = 0;
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin);
+        int endIndex = m_bodyDisjunction->terms.size();
+
+        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
+
+        while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
+            beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
+            ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction);
+            m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
+            m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+        }
+
+        m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
+
+        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd());
+        m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
+    }
+
+    void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
+    {
+        unsigned beginTerm = popParenthesesStack();
+        closeAlternative(beginTerm + 1);
+        unsigned endTerm = m_bodyDisjunction->terms.size();
+
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+
+        ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
+
+        bool capture = parenthesesBegin.capture();
+        unsigned subpatternId = parenthesesBegin.atom.subpatternId;
+
+        unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
+        ByteDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(numSubpatterns, callFrameSize);
+
+        parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
+        for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
+            parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
+        parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
+
+        m_bodyDisjunction->terms.shrink(beginTerm);
+
+        m_allParenthesesInfo.append(parenthesesDisjunction);
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, inputPosition));
+
+        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+    }
+
+    void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        unsigned beginTerm = popParenthesesStack();
+        closeAlternative(beginTerm + 1);
+        unsigned endTerm = m_bodyDisjunction->terms.size();
+
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+
+        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
+        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+    }
+
+    void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        unsigned beginTerm = popParenthesesStack();
+        closeAlternative(beginTerm + 1);
+        unsigned endTerm = m_bodyDisjunction->terms.size();
+
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+
+        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
+        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+    }
+
+    void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough)
+    {
+        m_bodyDisjunction = adoptPtr(js::OffTheBooks::new_(numSubpatterns, callFrameSize));
+        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough));
+        m_bodyDisjunction->terms[0].frameLocation = 0;
+        m_currentAlternativeIndex = 0;
+    }
+
+    void regexEnd()
+    {
+        closeBodyAlternative();
+    }
+
+    void alternativeBodyDisjunction(bool onceThrough)
+    {
+        int newAlternativeIndex = m_bodyDisjunction->terms.size();
+        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
+        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough));
+
+        m_currentAlternativeIndex = newAlternativeIndex;
+    }
+
+    void alternativeDisjunction()
+    {
+        int newAlternativeIndex = m_bodyDisjunction->terms.size();
+        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction());
+
+        m_currentAlternativeIndex = newAlternativeIndex;
+    }
+
+    void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0)
+    {
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
+            unsigned currentCountAlreadyChecked = inputCountAlreadyChecked;
+
+            PatternAlternative* alternative = disjunction->m_alternatives[alt];
+
+            if (alt) {
+                if (disjunction == m_pattern.m_body)
+                    alternativeBodyDisjunction(alternative->onceThrough());
+                else
+                    alternativeDisjunction();
+            }
+
+            unsigned minimumSize = alternative->m_minimumSize;
+            int countToCheck = minimumSize - parenthesesInputCountAlreadyChecked;
+
+            ASSERT(countToCheck >= 0);
+            if (countToCheck) {
+                checkInput(countToCheck);
+                currentCountAlreadyChecked += countToCheck;
+            }
+
+            for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
+                PatternTerm& term = alternative->m_terms[i];
+
+                switch (term.type) {
+                case PatternTerm::TypeAssertionBOL:
+                    assertionBOL(term.inputPosition - currentCountAlreadyChecked);
+                    break;
+
+                case PatternTerm::TypeAssertionEOL:
+                    assertionEOL(term.inputPosition - currentCountAlreadyChecked);
+                    break;
+
+                case PatternTerm::TypeAssertionWordBoundary:
+                    assertionWordBoundary(term.invert(), term.inputPosition - currentCountAlreadyChecked);
+                    break;
+
+                case PatternTerm::TypePatternCharacter:
+                    atomPatternCharacter(term.patternCharacter, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+                    break;
+
+                case PatternTerm::TypeCharacterClass:
+                    atomCharacterClass(term.characterClass, term.invert(), term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+                    break;
+
+                case PatternTerm::TypeBackReference:
+                    atomBackReference(term.backReferenceSubpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+                        break;
+
+                case PatternTerm::TypeForwardReference:
+                    break;
+
+                case PatternTerm::TypeParenthesesSubpattern: {
+                    unsigned disjunctionAlreadyCheckedCount = 0;
+                    if (term.quantityCount == 1 && !term.parentheses.isCopy) {
+                        unsigned alternativeFrameLocation = term.frameLocation;
+                        // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame.
+                        if (term.quantityType == QuantifierFixedCount)
+                            disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize;
+                        else
+                            alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+                        atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, alternativeFrameLocation);
+                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
+                        atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
+                    } else if (term.parentheses.isTerminal) {
+                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+                        atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce);
+                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
+                        atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
+                    } else {
+                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+                        atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0);
+                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
+                        atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
+                    }
+                    break;
+                }
+
+                case PatternTerm::TypeParentheticalAssertion: {
+                    unsigned alternativeFrameLocation = term.frameLocation + YarrStackSpaceForBackTrackInfoParentheticalAssertion;
+
+                    ASSERT(currentCountAlreadyChecked >= static_cast(term.inputPosition));
+                    int positiveInputOffset = currentCountAlreadyChecked - term.inputPosition;
+                    int uncheckAmount = positiveInputOffset - term.parentheses.disjunction->m_minimumSize;
+
+                    if (uncheckAmount > 0) {
+                        uncheckInput(uncheckAmount);
+                        currentCountAlreadyChecked -= uncheckAmount;
+                    } else
+                        uncheckAmount = 0;
+
+                    atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation);
+                    emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount);
+                    atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType);
+                    if (uncheckAmount) {
+                        checkInput(uncheckAmount);
+                        currentCountAlreadyChecked += uncheckAmount;
+                    }
+                    break;
+                }
+                }
+            }
+        }
+    }
+
+private:
+    YarrPattern& m_pattern;
+    OwnPtr m_bodyDisjunction;
+    unsigned m_currentAlternativeIndex;
+    Vector m_parenthesesStack;
+    Vector m_allParenthesesInfo;
+};
+
+PassOwnPtr byteCompile(YarrPattern& pattern, BumpPointerAllocator* allocator)
+{
+    return ByteCompiler(pattern).compile(allocator);
+}
+
+int interpret(BytecodePattern* bytecode, const UChar* input, unsigned start, unsigned length, int* output)
+{
+    return Interpreter(bytecode, output, input, start, length).interpret();
+}
+
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoPatternCharacter);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoCharacterClass);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoBackReference);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);
+
+
+} }
diff --git a/js/src/yarr/YarrInterpreter.h b/js/src/yarr/YarrInterpreter.h
new file mode 100644
index 000000000000..32b72858cad1
--- /dev/null
+++ b/js/src/yarr/YarrInterpreter.h
@@ -0,0 +1,380 @@
+/* -*- 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, 2010 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef YarrInterpreter_h
+#define YarrInterpreter_h
+
+#include "YarrPattern.h"
+
+namespace WTF {
+class BumpPointerAllocator;
+}
+using WTF::BumpPointerAllocator;
+
+namespace JSC { namespace Yarr {
+
+class ByteDisjunction;
+
+struct ByteTerm {
+    enum Type {
+        TypeBodyAlternativeBegin,
+        TypeBodyAlternativeDisjunction,
+        TypeBodyAlternativeEnd,
+        TypeAlternativeBegin,
+        TypeAlternativeDisjunction,
+        TypeAlternativeEnd,
+        TypeSubpatternBegin,
+        TypeSubpatternEnd,
+        TypeAssertionBOL,
+        TypeAssertionEOL,
+        TypeAssertionWordBoundary,
+        TypePatternCharacterOnce,
+        TypePatternCharacterFixed,
+        TypePatternCharacterGreedy,
+        TypePatternCharacterNonGreedy,
+        TypePatternCasedCharacterOnce,
+        TypePatternCasedCharacterFixed,
+        TypePatternCasedCharacterGreedy,
+        TypePatternCasedCharacterNonGreedy,
+        TypeCharacterClass,
+        TypeBackReference,
+        TypeParenthesesSubpattern,
+        TypeParenthesesSubpatternOnceBegin,
+        TypeParenthesesSubpatternOnceEnd,
+        TypeParenthesesSubpatternTerminalBegin,
+        TypeParenthesesSubpatternTerminalEnd,
+        TypeParentheticalAssertionBegin,
+        TypeParentheticalAssertionEnd,
+        TypeCheckInput,
+        TypeUncheckInput
+    } type;
+    union {
+        struct {
+            union {
+                UChar patternCharacter;
+                struct {
+                    UChar lo;
+                    UChar hi;
+                } casedCharacter;
+                CharacterClass* characterClass;
+                unsigned subpatternId;
+            };
+            union {
+                ByteDisjunction* parenthesesDisjunction;
+                unsigned parenthesesWidth;
+            };
+            QuantifierType quantityType;
+            unsigned quantityCount;
+        } atom;
+        struct {
+            int next;
+            int end;
+            bool onceThrough;
+        } alternative;
+        unsigned checkInputCount;
+    };
+    unsigned frameLocation;
+    bool m_capture : 1;
+    bool m_invert : 1;
+    int inputPosition;
+
+    // For js::Vector. Does not create a valid object.
+    ByteTerm()
+    {
+    }
+
+    ByteTerm(UChar ch, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+        : frameLocation(frameLocation)
+        , m_capture(false)
+        , m_invert(false)
+    {
+        switch (quantityType) {
+        case QuantifierFixedCount:
+            type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed;
+            break;
+        case QuantifierGreedy:
+            type = ByteTerm::TypePatternCharacterGreedy;
+            break;
+        case QuantifierNonGreedy:
+            type = ByteTerm::TypePatternCharacterNonGreedy;
+            break;
+        }
+
+        atom.patternCharacter = ch;
+        atom.quantityType = quantityType;
+        atom.quantityCount = quantityCount;
+        inputPosition = inputPos;
+    }
+
+    ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+        : frameLocation(frameLocation)
+        , m_capture(false)
+        , m_invert(false)
+    {
+        switch (quantityType) {
+        case QuantifierFixedCount:
+            type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed;
+            break;
+        case QuantifierGreedy:
+            type = ByteTerm::TypePatternCasedCharacterGreedy;
+            break;
+        case QuantifierNonGreedy:
+            type = ByteTerm::TypePatternCasedCharacterNonGreedy;
+            break;
+        }
+
+        atom.casedCharacter.lo = lo;
+        atom.casedCharacter.hi = hi;
+        atom.quantityType = quantityType;
+        atom.quantityCount = quantityCount;
+        inputPosition = inputPos;
+    }
+
+    ByteTerm(CharacterClass* characterClass, bool invert, int inputPos)
+        : type(ByteTerm::TypeCharacterClass)
+        , m_capture(false)
+        , m_invert(invert)
+    {
+        atom.characterClass = characterClass;
+        atom.quantityType = QuantifierFixedCount;
+        atom.quantityCount = 1;
+        inputPosition = inputPos;
+    }
+
+    ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool capture, int inputPos)
+        : type(type)
+        , m_capture(capture)
+        , m_invert(false)
+    {
+        atom.subpatternId = subpatternId;
+        atom.parenthesesDisjunction = parenthesesInfo;
+        atom.quantityType = QuantifierFixedCount;
+        atom.quantityCount = 1;
+        inputPosition = inputPos;
+    }
+    
+    ByteTerm(Type type, bool invert = false)
+        : type(type)
+        , m_capture(false)
+        , m_invert(invert)
+    {
+        atom.quantityType = QuantifierFixedCount;
+        atom.quantityCount = 1;
+    }
+
+    ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, int inputPos)
+        : type(type)
+        , m_capture(capture)
+        , m_invert(invert)
+    {
+        atom.subpatternId = subpatternId;
+        atom.quantityType = QuantifierFixedCount;
+        atom.quantityCount = 1;
+        inputPosition = inputPos;
+    }
+
+    static ByteTerm BOL(int inputPos)
+    {
+        ByteTerm term(TypeAssertionBOL);
+        term.inputPosition = inputPos;
+        return term;
+    }
+
+    static ByteTerm CheckInput(unsigned count)
+    {
+        ByteTerm term(TypeCheckInput);
+        term.checkInputCount = count;
+        return term;
+    }
+
+    static ByteTerm UncheckInput(unsigned count)
+    {
+        ByteTerm term(TypeUncheckInput);
+        term.checkInputCount = count;
+        return term;
+    }
+    
+    static ByteTerm EOL(int inputPos)
+    {
+        ByteTerm term(TypeAssertionEOL);
+        term.inputPosition = inputPos;
+        return term;
+    }
+
+    static ByteTerm WordBoundary(bool invert, int inputPos)
+    {
+        ByteTerm term(TypeAssertionWordBoundary, invert);
+        term.inputPosition = inputPos;
+        return term;
+    }
+    
+    static ByteTerm BackReference(unsigned subpatternId, int inputPos)
+    {
+        return ByteTerm(TypeBackReference, subpatternId, false, false, inputPos);
+    }
+
+    static ByteTerm BodyAlternativeBegin(bool onceThrough)
+    {
+        ByteTerm term(TypeBodyAlternativeBegin);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = onceThrough;
+        return term;
+    }
+
+    static ByteTerm BodyAlternativeDisjunction(bool onceThrough)
+    {
+        ByteTerm term(TypeBodyAlternativeDisjunction);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = onceThrough;
+        return term;
+    }
+
+    static ByteTerm BodyAlternativeEnd()
+    {
+        ByteTerm term(TypeBodyAlternativeEnd);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = false;
+        return term;
+    }
+
+    static ByteTerm AlternativeBegin()
+    {
+        ByteTerm term(TypeAlternativeBegin);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = false;
+        return term;
+    }
+
+    static ByteTerm AlternativeDisjunction()
+    {
+        ByteTerm term(TypeAlternativeDisjunction);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = false;
+        return term;
+    }
+
+    static ByteTerm AlternativeEnd()
+    {
+        ByteTerm term(TypeAlternativeEnd);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = false;
+        return term;
+    }
+
+    static ByteTerm SubpatternBegin()
+    {
+        return ByteTerm(TypeSubpatternBegin);
+    }
+
+    static ByteTerm SubpatternEnd()
+    {
+        return ByteTerm(TypeSubpatternEnd);
+    }
+
+    bool invert()
+    {
+        return m_invert;
+    }
+
+    bool capture()
+    {
+        return m_capture;
+    }
+};
+
+class ByteDisjunction {
+    WTF_MAKE_FAST_ALLOCATED
+public:
+    ByteDisjunction(unsigned numSubpatterns, unsigned frameSize)
+        : m_numSubpatterns(numSubpatterns)
+        , m_frameSize(frameSize)
+    {
+    }
+
+    Vector terms;
+    unsigned m_numSubpatterns;
+    unsigned m_frameSize;
+};
+
+struct BytecodePattern {
+    WTF_MAKE_FAST_ALLOCATED
+public:
+    BytecodePattern(PassOwnPtr body, Vector allParenthesesInfo, YarrPattern& pattern, BumpPointerAllocator* allocator)
+        : m_body(body)
+        , m_ignoreCase(pattern.m_ignoreCase)
+        , m_multiline(pattern.m_multiline)
+        , m_containsBeginChars(pattern.m_containsBeginChars)
+        , m_allocator(allocator)
+    {
+        newlineCharacterClass = pattern.newlineCharacterClass();
+        wordcharCharacterClass = pattern.wordcharCharacterClass();
+
+        m_allParenthesesInfo.append(allParenthesesInfo);
+        m_userCharacterClasses.append(pattern.m_userCharacterClasses);
+        // 'Steal' the YarrPattern's CharacterClasses!  We clear its
+        // array, so that it won't delete them on destruction.  We'll
+        // take responsibility for that.
+        pattern.m_userCharacterClasses.clear();
+
+        m_beginChars.append(pattern.m_beginChars);
+    }
+
+    ~BytecodePattern()
+    {
+        deleteAllValues(m_allParenthesesInfo);
+        deleteAllValues(m_userCharacterClasses);
+    }
+
+    OwnPtr m_body;
+    bool m_ignoreCase;
+    bool m_multiline;
+    bool m_containsBeginChars;
+    // Each BytecodePattern is associated with a RegExp, each RegExp is associated
+    // with a JSGlobalData.  Cache a pointer to out JSGlobalData's m_regExpAllocator.
+    BumpPointerAllocator* m_allocator;
+
+    CharacterClass* newlineCharacterClass;
+    CharacterClass* wordcharCharacterClass;
+
+    Vector m_beginChars;
+
+private:
+    Vector m_allParenthesesInfo;
+    Vector m_userCharacterClasses;
+};
+
+} } // namespace JSC::Yarr
+
+#endif // YarrInterpreter_h
diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp
new file mode 100644
index 000000000000..c0187f240b6d
--- /dev/null
+++ b/js/src/yarr/YarrJIT.cpp
@@ -0,0 +1,2405 @@
+/* -*- 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.
+ *
+ * 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "YarrJIT.h"
+
+#include "assembler/assembler/LinkBuffer.h"
+#include "Yarr.h"
+
+#if ENABLE_YARR_JIT
+
+using namespace WTF;
+
+namespace JSC { namespace Yarr {
+
+class YarrGenerator : private MacroAssembler {
+    friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
+
+#if WTF_CPU_ARM
+    static const RegisterID input = ARMRegisters::r0;
+    static const RegisterID index = ARMRegisters::r1;
+    static const RegisterID length = ARMRegisters::r2;
+    static const RegisterID output = ARMRegisters::r4;
+
+    static const RegisterID regT0 = ARMRegisters::r5;
+    static const RegisterID regT1 = ARMRegisters::r6;
+
+    static const RegisterID returnRegister = ARMRegisters::r0;
+#elif WTF_CPU_MIPS
+    static const RegisterID input = MIPSRegisters::a0;
+    static const RegisterID index = MIPSRegisters::a1;
+    static const RegisterID length = MIPSRegisters::a2;
+    static const RegisterID output = MIPSRegisters::a3;
+
+    static const RegisterID regT0 = MIPSRegisters::t4;
+    static const RegisterID regT1 = MIPSRegisters::t5;
+
+    static const RegisterID returnRegister = MIPSRegisters::v0;
+#elif WTF_CPU_SH4
+    static const RegisterID input = SH4Registers::r4;
+    static const RegisterID index = SH4Registers::r5;
+    static const RegisterID length = SH4Registers::r6;
+    static const RegisterID output = SH4Registers::r7;
+
+    static const RegisterID regT0 = SH4Registers::r0;
+    static const RegisterID regT1 = SH4Registers::r1;
+
+    static const RegisterID returnRegister = SH4Registers::r0;
+#elif WTF_CPU_X86
+    static const RegisterID input = X86Registers::eax;
+    static const RegisterID index = X86Registers::edx;
+    static const RegisterID length = X86Registers::ecx;
+    static const RegisterID output = X86Registers::edi;
+
+    static const RegisterID regT0 = X86Registers::ebx;
+    static const RegisterID regT1 = X86Registers::esi;
+
+    static const RegisterID returnRegister = X86Registers::eax;
+#elif WTF_CPU_X86_64
+    static const RegisterID input = X86Registers::edi;
+    static const RegisterID index = X86Registers::esi;
+    static const RegisterID length = X86Registers::edx;
+    static const RegisterID output = X86Registers::ecx;
+
+    static const RegisterID regT0 = X86Registers::eax;
+    static const RegisterID regT1 = X86Registers::ebx;
+
+    static const RegisterID returnRegister = X86Registers::eax;
+#endif
+
+    void optimizeAlternative(PatternAlternative* alternative)
+    {
+        if (!alternative->m_terms.size())
+            return;
+
+        for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) {
+            PatternTerm& term = alternative->m_terms[i];
+            PatternTerm& nextTerm = alternative->m_terms[i + 1];
+
+            if ((term.type == PatternTerm::TypeCharacterClass)
+                && (term.quantityType == QuantifierFixedCount)
+                && (nextTerm.type == PatternTerm::TypePatternCharacter)
+                && (nextTerm.quantityType == QuantifierFixedCount)) {
+                PatternTerm termCopy = term;
+                alternative->m_terms[i] = nextTerm;
+                alternative->m_terms[i + 1] = termCopy;
+            }
+        }
+    }
+
+    void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount)
+    {
+        do {
+            // pick which range we're going to generate
+            int which = count >> 1;
+            char lo = ranges[which].begin;
+            char hi = ranges[which].end;
+
+            // check if there are any ranges or matches below lo.  If not, just jl to failure -
+            // if there is anything else to check, check that first, if it falls through jmp to failure.
+            if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
+                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
+
+                // generate code for all ranges before this one
+                if (which)
+                    matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
+
+                while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
+                    matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex])));
+                    ++*matchIndex;
+                }
+                failures.append(jump());
+
+                loOrAbove.link(this);
+            } else if (which) {
+                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
+
+                matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
+                failures.append(jump());
+
+                loOrAbove.link(this);
+            } else
+                failures.append(branch32(LessThan, character, Imm32((unsigned short)lo)));
+
+            while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi))
+                ++*matchIndex;
+
+            matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi)));
+            // fall through to here, the value is above hi.
+
+            // shuffle along & loop around if there are any more matches to handle.
+            unsigned next = which + 1;
+            ranges += next;
+            count -= next;
+        } while (count);
+    }
+
+    void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass)
+    {
+        if (charClass->m_table) {
+            ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table));
+            matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry));
+            return;
+        }
+        Jump unicodeFail;
+        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) {
+            Jump isAscii = branch32(LessThanOrEqual, character, TrustedImm32(0x7f));
+
+            if (charClass->m_matchesUnicode.size()) {
+                for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) {
+                    UChar ch = charClass->m_matchesUnicode[i];
+                    matchDest.append(branch32(Equal, character, Imm32(ch)));
+                }
+            }
+
+            if (charClass->m_rangesUnicode.size()) {
+                for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) {
+                    UChar lo = charClass->m_rangesUnicode[i].begin;
+                    UChar hi = charClass->m_rangesUnicode[i].end;
+
+                    Jump below = branch32(LessThan, character, Imm32(lo));
+                    matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi)));
+                    below.link(this);
+                }
+            }
+
+            unicodeFail = jump();
+            isAscii.link(this);
+        }
+
+        if (charClass->m_ranges.size()) {
+            unsigned matchIndex = 0;
+            JumpList failures;
+            matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size());
+            while (matchIndex < charClass->m_matches.size())
+                matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++])));
+
+            failures.link(this);
+        } else if (charClass->m_matches.size()) {
+            // optimization: gather 'a','A' etc back together, can mask & test once.
+            Vector matchesAZaz;
+
+            for (unsigned i = 0; i < charClass->m_matches.size(); ++i) {
+                char ch = charClass->m_matches[i];
+                if (m_pattern.m_ignoreCase) {
+                    if (isASCIILower(ch)) {
+                        matchesAZaz.append(ch);
+                        continue;
+                    }
+                    if (isASCIIUpper(ch))
+                        continue;
+                }
+                matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch)));
+            }
+
+            if (unsigned countAZaz = matchesAZaz.size()) {
+                or32(TrustedImm32(32), character);
+                for (unsigned i = 0; i < countAZaz; ++i)
+                    matchDest.append(branch32(Equal, character, TrustedImm32(matchesAZaz[i])));
+            }
+        }
+
+        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size())
+            unicodeFail.link(this);
+    }
+
+    // Jumps if input not available; will have (incorrectly) incremented already!
+    Jump jumpIfNoAvailableInput(unsigned countToCheck = 0)
+    {
+        if (countToCheck)
+            add32(Imm32(countToCheck), index);
+        return branch32(Above, index, length);
+    }
+
+    Jump jumpIfAvailableInput(unsigned countToCheck)
+    {
+        add32(Imm32(countToCheck), index);
+        return branch32(BelowOrEqual, index, length);
+    }
+
+    Jump checkInput()
+    {
+        return branch32(BelowOrEqual, index, length);
+    }
+
+    Jump atEndOfInput()
+    {
+        return branch32(Equal, index, length);
+    }
+
+    Jump notAtEndOfInput()
+    {
+        return branch32(NotEqual, index, length);
+    }
+
+    Jump jumpIfCharEquals(UChar ch, int inputPosition)
+    {
+        return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
+    }
+
+    Jump jumpIfCharNotEquals(UChar ch, int inputPosition)
+    {
+        return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
+    }
+
+    void readCharacter(int inputPosition, RegisterID reg)
+    {
+        load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg);
+    }
+
+    void storeToFrame(RegisterID reg, unsigned frameLocation)
+    {
+        poke(reg, frameLocation);
+    }
+
+    void storeToFrame(TrustedImm32 imm, unsigned frameLocation)
+    {
+        poke(imm, frameLocation);
+    }
+
+    DataLabelPtr storeToFrameWithPatch(unsigned frameLocation)
+    {
+        return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*)));
+    }
+
+    void loadFromFrame(unsigned frameLocation, RegisterID reg)
+    {
+        peek(reg, frameLocation);
+    }
+
+    void loadFromFrameAndJump(unsigned frameLocation)
+    {
+        jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
+    }
+
+    enum YarrOpCode {
+        // These nodes wrap body alternatives - those in the main disjunction,
+        // rather than subpatterns or assertions. These are chained together in
+        // a doubly linked list, with a 'begin' node for the first alternative,
+        // a 'next' node for each subsequent alternative, and an 'end' node at
+        // the end. In the case of repeating alternatives, the 'end' node also
+        // has a reference back to 'begin'.
+        OpBodyAlternativeBegin,
+        OpBodyAlternativeNext,
+        OpBodyAlternativeEnd,
+        // Similar to the body alternatives, but used for subpatterns with two
+        // or more alternatives.
+        OpNestedAlternativeBegin,
+        OpNestedAlternativeNext,
+        OpNestedAlternativeEnd,
+        // Used for alternatives in subpatterns where there is only a single
+        // alternative (backtrackingis easier in these cases), or for alternatives
+        // which never need to be backtracked (those in parenthetical assertions,
+        // terminal subpatterns).
+        OpSimpleNestedAlternativeBegin,
+        OpSimpleNestedAlternativeNext,
+        OpSimpleNestedAlternativeEnd,
+        // Used to wrap 'Once' subpattern matches (quantityCount == 1).
+        OpParenthesesSubpatternOnceBegin,
+        OpParenthesesSubpatternOnceEnd,
+        // Used to wrap 'Terminal' subpattern matches (at the end of the regexp).
+        OpParenthesesSubpatternTerminalBegin,
+        OpParenthesesSubpatternTerminalEnd,
+        // Used to wrap parenthetical assertions.
+        OpParentheticalAssertionBegin,
+        OpParentheticalAssertionEnd,
+        // Wraps all simple terms (pattern characters, character classes).
+        OpTerm,
+        // Where an expression contains only 'once through' body alternatives
+        // and no repeating ones, this op is used to return match failure.
+        OpMatchFailed
+    };
+
+    // This structure is used to hold the compiled opcode information,
+    // including reference back to the original PatternTerm/PatternAlternatives,
+    // and JIT compilation data structures.
+    struct YarrOp {
+        explicit YarrOp(PatternTerm* term)
+            : m_op(OpTerm)
+            , m_term(term)
+            , m_isDeadCode(false)
+        {
+        }
+
+        explicit YarrOp(YarrOpCode op)
+            : m_op(op)
+            , m_isDeadCode(false)
+        {
+        }
+
+        // The operation, as a YarrOpCode, and also a reference to the PatternTerm.
+        YarrOpCode m_op;
+        PatternTerm* m_term;
+
+        // For alternatives, this holds the PatternAlternative and doubly linked
+        // references to this alternative's siblings. In the case of the
+        // OpBodyAlternativeEnd node at the end of a section of repeating nodes,
+        // m_nextOp will reference the OpBodyAlternativeBegin node of the first
+        // repeating alternative.
+        PatternAlternative* m_alternative;
+        size_t m_previousOp;
+        size_t m_nextOp;
+
+        // Used to record a set of Jumps out of the generated code, typically
+        // used for jumps out to backtracking code, and a single reentry back
+        // into the code for a node (likely where a backtrack will trigger
+        // rematching).
+        Label m_reentry;
+        JumpList m_jumps;
+
+        // This flag is used to null out the second pattern character, when
+        // two are fused to match a pair together.
+        bool m_isDeadCode;
+
+        // Currently used in the case of some of the more complex management of
+        // 'm_checked', to cache the offset used in this alternative, to avoid
+        // recalculating it.
+        int m_checkAdjust;
+
+        // Used by OpNestedAlternativeNext/End to hold the pointer to the
+        // value that will be pushed into the pattern's frame to return to,
+        // upon backtracking back into the disjunction.
+        DataLabelPtr m_returnAddress;
+    };
+
+    // BacktrackingState
+    // This class encapsulates information about the state of code generation
+    // whilst generating the code for backtracking, when a term fails to match.
+    // Upon entry to code generation of the backtracking code for a given node,
+    // the Backtracking state will hold references to all control flow sources
+    // that are outputs in need of further backtracking from the prior node
+    // generated (which is the subsequent operation in the regular expression,
+    // and in the m_ops Vector, since we generated backtracking backwards).
+    // These references to control flow take the form of:
+    //  - A jump list of jumps, to be linked to code that will backtrack them
+    //    further.
+    //  - A set of DataLabelPtr values, to be populated with values to be
+    //    treated effectively as return addresses backtracking into complex
+    //    subpatterns.
+    //  - A flag indicating that the current sequence of generated code up to
+    //    this point requires backtracking.
+    class BacktrackingState {
+    public:
+        BacktrackingState()
+            : m_pendingFallthrough(false)
+        {
+        }
+
+        // Add a jump or jumps, a return address, or set the flag indicating
+        // that the current 'fallthrough' control flow requires backtracking.
+        void append(const Jump& jump)
+        {
+            m_laterFailures.append(jump);
+        }
+        void append(JumpList& jumpList)
+        {
+            m_laterFailures.append(jumpList);
+        }
+        void append(const DataLabelPtr& returnAddress)
+        {
+            m_pendingReturns.append(returnAddress);
+        }
+        void fallthrough()
+        {
+            ASSERT(!m_pendingFallthrough);
+            m_pendingFallthrough = true;
+        }
+
+        // These methods clear the backtracking state, either linking to the
+        // current location, a provided label, or copying the backtracking out
+        // to a JumpList. All actions may require code generation to take place,
+        // and as such are passed a pointer to the assembler.
+        void link(MacroAssembler* assembler)
+        {
+            if (m_pendingReturns.size()) {
+                Label here(assembler);
+                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
+                m_pendingReturns.clear();
+            }
+            m_laterFailures.link(assembler);
+            m_laterFailures.clear();
+            m_pendingFallthrough = false;
+        }
+        void linkTo(Label label, MacroAssembler* assembler)
+        {
+            if (m_pendingReturns.size()) {
+                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], label));
+                m_pendingReturns.clear();
+            }
+            if (m_pendingFallthrough)
+                assembler->jump(label);
+            m_laterFailures.linkTo(label, assembler);
+            m_laterFailures.clear();
+            m_pendingFallthrough = false;
+        }
+        void takeBacktracksToJumpList(JumpList& jumpList, MacroAssembler* assembler)
+        {
+            if (m_pendingReturns.size()) {
+                Label here(assembler);
+                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
+                m_pendingReturns.clear();
+                m_pendingFallthrough = true;
+            }
+            if (m_pendingFallthrough)
+                jumpList.append(assembler->jump());
+            jumpList.append(m_laterFailures);
+            m_laterFailures.clear();
+            m_pendingFallthrough = false;
+        }
+
+        bool isEmpty()
+        {
+            return m_laterFailures.empty() && m_pendingReturns.isEmpty() && !m_pendingFallthrough;
+        }
+
+        // Called at the end of code generation to link all return addresses.
+        void linkDataLabels(LinkBuffer& linkBuffer)
+        {
+            ASSERT(isEmpty());
+            for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
+                linkBuffer.patch(m_backtrackRecords[i].m_dataLabel, linkBuffer.locationOf(m_backtrackRecords[i].m_backtrackLocation));
+        }
+
+    private:
+        struct ReturnAddressRecord {
+            ReturnAddressRecord(DataLabelPtr dataLabel, Label backtrackLocation)
+                : m_dataLabel(dataLabel)
+                , m_backtrackLocation(backtrackLocation)
+            {
+            }
+
+            DataLabelPtr m_dataLabel;
+            Label m_backtrackLocation;
+        };
+
+        JumpList m_laterFailures;
+        bool m_pendingFallthrough;
+        Vector m_pendingReturns;
+        Vector m_backtrackRecords;
+    };
+
+    // Generation methods:
+    // ===================
+
+    // This method provides a default implementation of backtracking common
+    // to many terms; terms commonly jump out of the forwards  matching path
+    // on any failed conditions, and add these jumps to the m_jumps list. If
+    // no special handling is required we can often just backtrack to m_jumps.
+    void backtrackTermDefault(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        m_backtrackingState.append(op.m_jumps);
+    }
+
+    void generateAssertionBOL(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        if (m_pattern.m_multiline) {
+            const RegisterID character = regT0;
+
+            JumpList matchDest;
+            if (!term->inputPosition)
+                matchDest.append(branch32(Equal, index, Imm32(m_checked)));
+
+            readCharacter((term->inputPosition - m_checked) - 1, character);
+            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
+            op.m_jumps.append(jump());
+
+            matchDest.link(this);
+        } else {
+            // Erk, really should poison out these alternatives early. :-/
+            if (term->inputPosition)
+                op.m_jumps.append(jump());
+            else
+                op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked)));
+        }
+    }
+    void backtrackAssertionBOL(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generateAssertionEOL(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        if (m_pattern.m_multiline) {
+            const RegisterID character = regT0;
+
+            JumpList matchDest;
+            if (term->inputPosition == m_checked)
+                matchDest.append(atEndOfInput());
+
+            readCharacter((term->inputPosition - m_checked), character);
+            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
+            op.m_jumps.append(jump());
+
+            matchDest.link(this);
+        } else {
+            if (term->inputPosition == m_checked)
+                op.m_jumps.append(notAtEndOfInput());
+            // Erk, really should poison out these alternatives early. :-/
+            else
+                op.m_jumps.append(jump());
+        }
+    }
+    void backtrackAssertionEOL(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    // Also falls though on nextIsNotWordChar.
+    void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+
+        if (term->inputPosition == m_checked)
+            nextIsNotWordChar.append(atEndOfInput());
+
+        readCharacter((term->inputPosition - m_checked), character);
+        matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass());
+    }
+
+    void generateAssertionWordBoundary(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+
+        Jump atBegin;
+        JumpList matchDest;
+        if (!term->inputPosition)
+            atBegin = branch32(Equal, index, Imm32(m_checked));
+        readCharacter((term->inputPosition - m_checked) - 1, character);
+        matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass());
+        if (!term->inputPosition)
+            atBegin.link(this);
+
+        // We fall through to here if the last character was not a wordchar.
+        JumpList nonWordCharThenWordChar;
+        JumpList nonWordCharThenNonWordChar;
+        if (term->invert()) {
+            matchAssertionWordchar(opIndex, nonWordCharThenNonWordChar, nonWordCharThenWordChar);
+            nonWordCharThenWordChar.append(jump());
+        } else {
+            matchAssertionWordchar(opIndex, nonWordCharThenWordChar, nonWordCharThenNonWordChar);
+            nonWordCharThenNonWordChar.append(jump());
+        }
+        op.m_jumps.append(nonWordCharThenNonWordChar);
+
+        // We jump here if the last character was a wordchar.
+        matchDest.link(this);
+        JumpList wordCharThenWordChar;
+        JumpList wordCharThenNonWordChar;
+        if (term->invert()) {
+            matchAssertionWordchar(opIndex, wordCharThenNonWordChar, wordCharThenWordChar);
+            wordCharThenWordChar.append(jump());
+        } else {
+            matchAssertionWordchar(opIndex, wordCharThenWordChar, wordCharThenNonWordChar);
+            // This can fall-though!
+        }
+
+        op.m_jumps.append(wordCharThenWordChar);
+
+        nonWordCharThenWordChar.link(this);
+        wordCharThenNonWordChar.link(this);
+    }
+    void backtrackAssertionWordBoundary(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generatePatternCharacterOnce(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+
+        // m_ops always ends with a OpBodyAlternativeEnd or OpMatchFailed
+        // node, so there must always be at least one more node.
+        ASSERT(opIndex + 1 < m_ops.size());
+        YarrOp& nextOp = m_ops[opIndex + 1];
+
+        if (op.m_isDeadCode)
+            return;
+
+        PatternTerm* term = op.m_term;
+        UChar ch = term->patternCharacter;
+
+        const RegisterID character = regT0;
+
+        if (nextOp.m_op == OpTerm) {
+            PatternTerm* nextTerm = nextOp.m_term;
+            if (nextTerm->type == PatternTerm::TypePatternCharacter
+                && nextTerm->quantityType == QuantifierFixedCount
+                && nextTerm->quantityCount == 1
+                && nextTerm->inputPosition == (term->inputPosition + 1)) {
+
+                UChar ch2 = nextTerm->patternCharacter;
+
+                int mask = 0;
+                int chPair = ch | (ch2 << 16);
+
+                if (m_pattern.m_ignoreCase) {
+                    if (isASCIIAlpha(ch))
+                        mask |= 32;
+                    if (isASCIIAlpha(ch2))
+                        mask |= 32 << 16;
+                }
+
+                BaseIndex address(input, index, TimesTwo, (term->inputPosition - m_checked) * sizeof(UChar));
+                if (mask) {
+                    load32WithUnalignedHalfWords(address, character);
+                    or32(Imm32(mask), character);
+                    op.m_jumps.append(branch32(NotEqual, character, Imm32(chPair | mask)));
+                } else
+                    op.m_jumps.append(branch32WithUnalignedHalfWords(NotEqual, address, Imm32(chPair)));
+
+                nextOp.m_isDeadCode = true;
+                return;
+            }
+        }
+
+        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+            readCharacter(term->inputPosition - m_checked, character);
+            or32(TrustedImm32(32), character);
+            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+        } else {
+            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+            op.m_jumps.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+        }
+    }
+    void backtrackPatternCharacterOnce(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generatePatternCharacterFixed(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+        UChar ch = term->patternCharacter;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        move(index, countRegister);
+        sub32(Imm32(term->quantityCount), countRegister);
+
+        Label loop(this);
+        BaseIndex address(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar));
+
+        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+            load16(address, character);
+            or32(TrustedImm32(32), character);
+            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+        } else {
+            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+            op.m_jumps.append(branch16(NotEqual, address, Imm32(ch)));
+        }
+        add32(TrustedImm32(1), countRegister);
+        branch32(NotEqual, countRegister, index).linkTo(loop, this);
+    }
+    void backtrackPatternCharacterFixed(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generatePatternCharacterGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+        UChar ch = term->patternCharacter;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        move(TrustedImm32(0), countRegister);
+
+        JumpList failures;
+        Label loop(this);
+        failures.append(atEndOfInput());
+        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+            readCharacter(term->inputPosition - m_checked, character);
+            or32(TrustedImm32(32), character);
+            failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+        } else {
+            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+            failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        add32(TrustedImm32(1), index);
+        if (term->quantityCount == quantifyInfinite)
+            jump(loop);
+        else
+            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
+
+        failures.link(this);
+        op.m_reentry = label();
+
+        storeToFrame(countRegister, term->frameLocation);
+
+    }
+    void backtrackPatternCharacterGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID countRegister = regT1;
+
+        m_backtrackingState.link(this);
+
+        loadFromFrame(term->frameLocation, countRegister);
+        m_backtrackingState.append(branchTest32(Zero, countRegister));
+        sub32(TrustedImm32(1), countRegister);
+        sub32(TrustedImm32(1), index);
+        jump(op.m_reentry);
+    }
+
+    void generatePatternCharacterNonGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID countRegister = regT1;
+
+        move(TrustedImm32(0), countRegister);
+        op.m_reentry = label();
+        storeToFrame(countRegister, term->frameLocation);
+    }
+    void backtrackPatternCharacterNonGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+        UChar ch = term->patternCharacter;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        JumpList nonGreedyFailures;
+
+        m_backtrackingState.link(this);
+
+        loadFromFrame(term->frameLocation, countRegister);
+
+        nonGreedyFailures.append(atEndOfInput());
+        if (term->quantityCount != quantifyInfinite)
+            nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
+        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+            readCharacter(term->inputPosition - m_checked, character);
+            or32(TrustedImm32(32), character);
+            nonGreedyFailures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+        } else {
+            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+            nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        add32(TrustedImm32(1), index);
+
+        jump(op.m_reentry);
+
+        nonGreedyFailures.link(this);
+        sub32(countRegister, index);
+        m_backtrackingState.fallthrough();
+    }
+
+    void generateCharacterClassOnce(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+
+        JumpList matchDest;
+        readCharacter((term->inputPosition - m_checked), character);
+        matchCharacterClass(character, matchDest, term->characterClass);
+
+        if (term->invert())
+            op.m_jumps.append(matchDest);
+        else {
+            op.m_jumps.append(jump());
+            matchDest.link(this);
+        }
+    }
+    void backtrackCharacterClassOnce(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generateCharacterClassFixed(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        move(index, countRegister);
+        sub32(Imm32(term->quantityCount), countRegister);
+
+        Label loop(this);
+        JumpList matchDest;
+        load16(BaseIndex(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar)), character);
+        matchCharacterClass(character, matchDest, term->characterClass);
+
+        if (term->invert())
+            op.m_jumps.append(matchDest);
+        else {
+            op.m_jumps.append(jump());
+            matchDest.link(this);
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        branch32(NotEqual, countRegister, index).linkTo(loop, this);
+    }
+    void backtrackCharacterClassFixed(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generateCharacterClassGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        move(TrustedImm32(0), countRegister);
+
+        JumpList failures;
+        Label loop(this);
+        failures.append(atEndOfInput());
+
+        if (term->invert()) {
+            readCharacter(term->inputPosition - m_checked, character);
+            matchCharacterClass(character, failures, term->characterClass);
+        } else {
+            JumpList matchDest;
+            readCharacter(term->inputPosition - m_checked, character);
+            matchCharacterClass(character, matchDest, term->characterClass);
+            failures.append(jump());
+            matchDest.link(this);
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        add32(TrustedImm32(1), index);
+        if (term->quantityCount != quantifyInfinite) {
+            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
+            failures.append(jump());
+        } else
+            jump(loop);
+
+        failures.link(this);
+        op.m_reentry = label();
+
+        storeToFrame(countRegister, term->frameLocation);
+    }
+    void backtrackCharacterClassGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID countRegister = regT1;
+
+        m_backtrackingState.link(this);
+
+        loadFromFrame(term->frameLocation, countRegister);
+        m_backtrackingState.append(branchTest32(Zero, countRegister));
+        sub32(TrustedImm32(1), countRegister);
+        sub32(TrustedImm32(1), index);
+        jump(op.m_reentry);
+    }
+
+    void generateCharacterClassNonGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID countRegister = regT1;
+
+        move(TrustedImm32(0), countRegister);
+        op.m_reentry = label();
+        storeToFrame(countRegister, term->frameLocation);
+    }
+    void backtrackCharacterClassNonGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        JumpList nonGreedyFailures;
+
+        m_backtrackingState.link(this);
+
+        Label backtrackBegin(this);
+        loadFromFrame(term->frameLocation, countRegister);
+
+        nonGreedyFailures.append(atEndOfInput());
+        nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
+
+        JumpList matchDest;
+        readCharacter(term->inputPosition - m_checked, character);
+        matchCharacterClass(character, matchDest, term->characterClass);
+
+        if (term->invert())
+            nonGreedyFailures.append(matchDest);
+        else {
+            nonGreedyFailures.append(jump());
+            matchDest.link(this);
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        add32(TrustedImm32(1), index);
+
+        jump(op.m_reentry);
+
+        nonGreedyFailures.link(this);
+        sub32(countRegister, index);
+        m_backtrackingState.fallthrough();
+    }
+
+    // Code generation/backtracking for simple terms
+    // (pattern characters, character classes, and assertions).
+    // These methods farm out work to the set of functions above.
+    void generateTerm(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        switch (term->type) {
+        case PatternTerm::TypePatternCharacter:
+            switch (term->quantityType) {
+            case QuantifierFixedCount:
+                if (term->quantityCount == 1)
+                    generatePatternCharacterOnce(opIndex);
+                else
+                    generatePatternCharacterFixed(opIndex);
+                break;
+            case QuantifierGreedy:
+                generatePatternCharacterGreedy(opIndex);
+                break;
+            case QuantifierNonGreedy:
+                generatePatternCharacterNonGreedy(opIndex);
+                break;
+            }
+            break;
+
+        case PatternTerm::TypeCharacterClass:
+            switch (term->quantityType) {
+            case QuantifierFixedCount:
+                if (term->quantityCount == 1)
+                    generateCharacterClassOnce(opIndex);
+                else
+                    generateCharacterClassFixed(opIndex);
+                break;
+            case QuantifierGreedy:
+                generateCharacterClassGreedy(opIndex);
+                break;
+            case QuantifierNonGreedy:
+                generateCharacterClassNonGreedy(opIndex);
+                break;
+            }
+            break;
+
+        case PatternTerm::TypeAssertionBOL:
+            generateAssertionBOL(opIndex);
+            break;
+
+        case PatternTerm::TypeAssertionEOL:
+            generateAssertionEOL(opIndex);
+            break;
+
+        case PatternTerm::TypeAssertionWordBoundary:
+            generateAssertionWordBoundary(opIndex);
+            break;
+
+        case PatternTerm::TypeForwardReference:
+            break;
+
+        case PatternTerm::TypeParenthesesSubpattern:
+        case PatternTerm::TypeParentheticalAssertion:
+            ASSERT_NOT_REACHED();
+        case PatternTerm::TypeBackReference:
+            m_shouldFallBack = true;
+            break;
+        }
+    }
+    void backtrackTerm(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        switch (term->type) {
+        case PatternTerm::TypePatternCharacter:
+            switch (term->quantityType) {
+            case QuantifierFixedCount:
+                if (term->quantityCount == 1)
+                    backtrackPatternCharacterOnce(opIndex);
+                else
+                    backtrackPatternCharacterFixed(opIndex);
+                break;
+            case QuantifierGreedy:
+                backtrackPatternCharacterGreedy(opIndex);
+                break;
+            case QuantifierNonGreedy:
+                backtrackPatternCharacterNonGreedy(opIndex);
+                break;
+            }
+            break;
+
+        case PatternTerm::TypeCharacterClass:
+            switch (term->quantityType) {
+            case QuantifierFixedCount:
+                if (term->quantityCount == 1)
+                    backtrackCharacterClassOnce(opIndex);
+                else
+                    backtrackCharacterClassFixed(opIndex);
+                break;
+            case QuantifierGreedy:
+                backtrackCharacterClassGreedy(opIndex);
+                break;
+            case QuantifierNonGreedy:
+                backtrackCharacterClassNonGreedy(opIndex);
+                break;
+            }
+            break;
+
+        case PatternTerm::TypeAssertionBOL:
+            backtrackAssertionBOL(opIndex);
+            break;
+
+        case PatternTerm::TypeAssertionEOL:
+            backtrackAssertionEOL(opIndex);
+            break;
+
+        case PatternTerm::TypeAssertionWordBoundary:
+            backtrackAssertionWordBoundary(opIndex);
+            break;
+
+        case PatternTerm::TypeForwardReference:
+            break;
+
+        case PatternTerm::TypeParenthesesSubpattern:
+        case PatternTerm::TypeParentheticalAssertion:
+            ASSERT_NOT_REACHED();
+        case PatternTerm::TypeBackReference:
+            m_shouldFallBack = true;
+            break;
+        }
+    }
+
+    void generate()
+    {
+        // Forwards generate the matching code.
+        ASSERT(m_ops.size());
+        size_t opIndex = 0;
+
+        do {
+            YarrOp& op = m_ops[opIndex];
+            switch (op.m_op) {
+
+            case OpTerm:
+                generateTerm(opIndex);
+                break;
+
+            // OpBodyAlternativeBegin/Next/End
+            //
+            // These nodes wrap the set of alternatives in the body of the regular expression.
+            // There may be either one or two chains of OpBodyAlternative nodes, one representing
+            // the 'once through' sequence of alternatives (if any exist), and one representing
+            // the repeating alternatives (again, if any exist).
+            //
+            // Upon normal entry to the Begin alternative, we will check that input is available.
+            // Reentry to the Begin alternative will take place after the check has taken place,
+            // and will assume that the input position has already been progressed as appropriate.
+            //
+            // Entry to subsequent Next/End alternatives occurs when the prior alternative has
+            // successfully completed a match - return a success state from JIT code.
+            //
+            // Next alternatives allow for reentry optimized to suit backtracking from its
+            // preceding alternative. It expects the input position to still be set to a position
+            // appropriate to its predecessor, and it will only perform an input check if the
+            // predecessor had a minimum size less than its own.
+            //
+            // In the case 'once through' expressions, the End node will also have a reentry
+            // point to jump to when the last alternative fails. Again, this expects the input
+            // position to still reflect that expected by the prior alternative.
+            case OpBodyAlternativeBegin: {
+                PatternAlternative* alternative = op.m_alternative;
+
+                // Upon entry at the head of the set of alternatives, check if input is available
+                // to run the first alternative. (This progresses the input position).
+                op.m_jumps.append(jumpIfNoAvailableInput(alternative->m_minimumSize));
+                // We will reenter after the check, and assume the input position to have been
+                // set as appropriate to this alternative.
+                op.m_reentry = label();
+
+                m_checked += alternative->m_minimumSize;
+                break;
+            }
+            case OpBodyAlternativeNext:
+            case OpBodyAlternativeEnd: {
+                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+                PatternAlternative* alternative = op.m_alternative;
+
+                // If we get here, the prior alternative matched - return success.
+                
+                // Adjust the stack pointer to remove the pattern's frame.
+                if (m_pattern.m_body->m_callFrameSize)
+                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+
+                // Load appropriate values into the return register and the first output
+                // slot, and return. In the case of pattern with a fixed size, we will
+                // not have yet set the value in the first 
+                ASSERT(index != returnRegister);
+                if (m_pattern.m_body->m_hasFixedSize) {
+                    move(index, returnRegister);
+                    if (priorAlternative->m_minimumSize)
+                        sub32(Imm32(priorAlternative->m_minimumSize), returnRegister);
+                    store32(returnRegister, output);
+                } else
+                    load32(Address(output), returnRegister);
+                store32(index, Address(output, 4));
+                generateReturn();
+
+                // This is the divide between the tail of the prior alternative, above, and
+                // the head of the subsequent alternative, below.
+
+                if (op.m_op == OpBodyAlternativeNext) {
+                    // This is the reentry point for the Next alternative. We expect any code
+                    // that jumps here to do so with the input position matching that of the
+                    // PRIOR alteranative, and we will only check input availability if we
+                    // need to progress it forwards.
+                    op.m_reentry = label();
+                    if (int delta = alternative->m_minimumSize - priorAlternative->m_minimumSize) {
+                        add32(Imm32(delta), index);
+                        if (delta > 0)
+                            op.m_jumps.append(jumpIfNoAvailableInput());
+                    }
+                } else if (op.m_nextOp == notFound) {
+                    // This is the reentry point for the End of 'once through' alternatives,
+                    // jumped to when the las alternative fails to match.
+                    op.m_reentry = label();
+                    sub32(Imm32(priorAlternative->m_minimumSize), index);
+                }
+
+                if (op.m_op == OpBodyAlternativeNext)
+                    m_checked += alternative->m_minimumSize;
+                m_checked -= priorAlternative->m_minimumSize;
+                break;
+            }
+
+            // OpSimpleNestedAlternativeBegin/Next/End
+            // OpNestedAlternativeBegin/Next/End
+            //
+            // These nodes are used to handle sets of alternatives that are nested within
+            // subpatterns and parenthetical assertions. The 'simple' forms are used where
+            // we do not need to be able to backtrack back into any alternative other than
+            // the last, the normal forms allow backtracking into any alternative.
+            //
+            // Each Begin/Next node is responsible for planting an input check to ensure
+            // sufficient input is available on entry. Next nodes additionally need to
+            // jump to the end - Next nodes use the End node's m_jumps list to hold this
+            // set of jumps.
+            //
+            // In the non-simple forms, successful alternative matches must store a
+            // 'return address' using a DataLabelPtr, used to store the address to jump
+            // to when backtracking, to get to the code for the appropriate alternative.
+            case OpSimpleNestedAlternativeBegin:
+            case OpNestedAlternativeBegin: {
+                PatternTerm* term = op.m_term;
+                PatternAlternative* alternative = op.m_alternative;
+                PatternDisjunction* disjunction = term->parentheses.disjunction;
+
+                // Calculate how much input we need to check for, and if non-zero check.
+                op.m_checkAdjust = alternative->m_minimumSize;
+                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
+                    op.m_checkAdjust -= disjunction->m_minimumSize;
+                if (op.m_checkAdjust)
+                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
+ 
+                m_checked += op.m_checkAdjust;
+                break;
+            }
+            case OpSimpleNestedAlternativeNext:
+            case OpNestedAlternativeNext: {
+                PatternTerm* term = op.m_term;
+                PatternAlternative* alternative = op.m_alternative;
+                PatternDisjunction* disjunction = term->parentheses.disjunction;
+
+                // In the non-simple case, store a 'return address' so we can backtrack correctly.
+                if (op.m_op == OpNestedAlternativeNext) {
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
+                    if (term->quantityType != QuantifierFixedCount)
+                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
+                }
+
+                // If we reach here then the last alternative has matched - jump to the
+                // End node, to skip over any further alternatives.
+                //
+                // FIXME: this is logically O(N^2) (though N can be expected to be very
+                // small). We could avoid this either by adding an extra jump to the JIT
+                // data structures, or by making backtracking code that jumps to Next
+                // alternatives are responsible for checking that input is available (if
+                // we didn't need to plant the input checks, then m_jumps would be free).
+                YarrOp* endOp = &m_ops[op.m_nextOp];
+                while (endOp->m_nextOp != notFound) {
+                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
+                    endOp = &m_ops[endOp->m_nextOp];
+                }
+                ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
+                endOp->m_jumps.append(jump());
+
+                // This is the entry point for the next alternative.
+                op.m_reentry = label();
+
+                // Calculate how much input we need to check for, and if non-zero check.
+                op.m_checkAdjust = alternative->m_minimumSize;
+                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
+                    op.m_checkAdjust -= disjunction->m_minimumSize;
+                if (op.m_checkAdjust)
+                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked -= lastOp.m_checkAdjust;
+                m_checked += op.m_checkAdjust;
+                break;
+            }
+            case OpSimpleNestedAlternativeEnd:
+            case OpNestedAlternativeEnd: {
+                PatternTerm* term = op.m_term;
+
+                // In the non-simple case, store a 'return address' so we can backtrack correctly.
+                if (op.m_op == OpNestedAlternativeEnd) {
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
+                    if (term->quantityType != QuantifierFixedCount)
+                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
+                }
+
+                // If this set of alternatives contains more than one alternative,
+                // then the Next nodes will have planted jumps to the End, and added
+                // them to this node's m_jumps list.
+                op.m_jumps.link(this);
+                op.m_jumps.clear();
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked -= lastOp.m_checkAdjust;
+                break;
+            }
+
+            // OpParenthesesSubpatternOnceBegin/End
+            //
+            // These nodes support (optionally) capturing subpatterns, that have a
+            // quantity count of 1 (this covers fixed once, and ?/?? quantifiers). 
+            case OpParenthesesSubpatternOnceBegin: {
+                PatternTerm* term = op.m_term;
+                unsigned parenthesesFrameLocation = term->frameLocation;
+                const RegisterID indexTemporary = regT0;
+                ASSERT(term->quantityCount == 1);
+
+                // Upon entry to a Greedy quantified set of parenthese store the index.
+                // We'll use this for two purposes:
+                //  - To indicate which iteration we are on of mathing the remainder of
+                //    the expression after the parentheses - the first, including the
+                //    match within the parentheses, or the second having skipped over them.
+                //  - To check for empty matches, which must be rejected.
+                //
+                // At the head of a NonGreedy set of parentheses we'll immediately set the
+                // value on the stack to -1 (indicating a match skipping the subpattern),
+                // and plant a jump to the end. We'll also plant a label to backtrack to
+                // to reenter the subpattern later, with a store to set up index on the
+                // second iteration.
+                //
+                // FIXME: for capturing parens, could use the index in the capture array?
+                if (term->quantityType == QuantifierGreedy)
+                    storeToFrame(index, parenthesesFrameLocation);
+                else if (term->quantityType == QuantifierNonGreedy) {
+                    storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
+                    op.m_jumps.append(jump());
+                    op.m_reentry = label();
+                    storeToFrame(index, parenthesesFrameLocation);
+                }
+
+                // If the parenthese are capturing, store the starting index value to the
+                // captures array, offsetting as necessary.
+                //
+                // FIXME: could avoid offsetting this value in JIT code, apply
+                // offsets only afterwards, at the point the results array is
+                // being accessed.
+                if (term->capture()) {
+                    int offsetId = term->parentheses.subpatternId << 1;
+                    int inputOffset = term->inputPosition - m_checked;
+                    if (term->quantityType == QuantifierFixedCount)
+                        inputOffset -= term->parentheses.disjunction->m_minimumSize;
+                    if (inputOffset) {
+                        move(index, indexTemporary);
+                        add32(Imm32(inputOffset), indexTemporary);
+                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
+                    } else
+                        store32(index, Address(output, offsetId * sizeof(int)));
+                }
+                break;
+            }
+            case OpParenthesesSubpatternOnceEnd: {
+                PatternTerm* term = op.m_term;
+                unsigned parenthesesFrameLocation = term->frameLocation;
+                const RegisterID indexTemporary = regT0;
+                ASSERT(term->quantityCount == 1);
+
+                // For Greedy/NonGreedy quantified parentheses, we must reject zero length
+                // matches. If the minimum size is know to be non-zero we need not check.
+                if (term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize)
+                    op.m_jumps.append(branch32(Equal, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*))));
+
+                // If the parenthese are capturing, store the ending index value to the
+                // captures array, offsetting as necessary.
+                //
+                // FIXME: could avoid offsetting this value in JIT code, apply
+                // offsets only afterwards, at the point the results array is
+                // being accessed.
+                if (term->capture()) {
+                    int offsetId = (term->parentheses.subpatternId << 1) + 1;
+                    int inputOffset = term->inputPosition - m_checked;
+                    if (inputOffset) {
+                        move(index, indexTemporary);
+                        add32(Imm32(inputOffset), indexTemporary);
+                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
+                    } else
+                        store32(index, Address(output, offsetId * sizeof(int)));
+                }
+
+                // If the parentheses are quantified Greedy then add a label to jump back
+                // to if get a failed match from after the parentheses. For NonGreedy
+                // parentheses, link the jump from before the subpattern to here.
+                if (term->quantityType == QuantifierGreedy)
+                    op.m_reentry = label();
+                else if (term->quantityType == QuantifierNonGreedy) {
+                    YarrOp& beginOp = m_ops[op.m_previousOp];
+                    beginOp.m_jumps.link(this);
+                }
+                break;
+            }
+
+            // OpParenthesesSubpatternTerminalBegin/End
+            case OpParenthesesSubpatternTerminalBegin: {
+                PatternTerm* term = op.m_term;
+                ASSERT(term->quantityType == QuantifierGreedy);
+                ASSERT(term->quantityCount == quantifyInfinite);
+                ASSERT(!term->capture());
+
+                // Upon entry set a label to loop back to.
+                op.m_reentry = label();
+
+                // Store the start index of the current match; we need to reject zero
+                // length matches.
+                storeToFrame(index, term->frameLocation);
+                break;
+            }
+            case OpParenthesesSubpatternTerminalEnd: {
+                PatternTerm* term = op.m_term;
+
+                // Check for zero length matches - if the match is non-zero, then we
+                // can accept it & loop back up to the head of the subpattern.
+                YarrOp& beginOp = m_ops[op.m_previousOp];
+                branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*)), beginOp.m_reentry);
+
+                // Reject the match - backtrack back into the subpattern.
+                op.m_jumps.append(jump());
+
+                // This is the entry point to jump to when we stop matching - we will
+                // do so once the subpattern cannot match any more.
+                op.m_reentry = label();
+                break;
+            }
+
+            // OpParentheticalAssertionBegin/End
+            case OpParentheticalAssertionBegin: {
+                PatternTerm* term = op.m_term;
+
+                // Store the current index - assertions should not update index, so
+                // we will need to restore it upon a successful match.
+                unsigned parenthesesFrameLocation = term->frameLocation;
+                storeToFrame(index, parenthesesFrameLocation);
+
+                // Check 
+                op.m_checkAdjust = m_checked - term->inputPosition;
+                if (op.m_checkAdjust)
+                    sub32(Imm32(op.m_checkAdjust), index);
+
+                m_checked -= op.m_checkAdjust;
+                break;
+            }
+            case OpParentheticalAssertionEnd: {
+                PatternTerm* term = op.m_term;
+
+                // Restore the input index value.
+                unsigned parenthesesFrameLocation = term->frameLocation;
+                loadFromFrame(parenthesesFrameLocation, index);
+
+                // If inverted, a successful match of the assertion must be treated
+                // as a failure, so jump to backtracking.
+                if (term->invert()) {
+                    op.m_jumps.append(jump());
+                    op.m_reentry = label();
+                }
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked += lastOp.m_checkAdjust;
+                break;
+            }
+
+            case OpMatchFailed:
+                if (m_pattern.m_body->m_callFrameSize)
+                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+                move(TrustedImm32(-1), returnRegister);
+                generateReturn();
+                break;
+            }
+
+            ++opIndex;
+        } while (opIndex < m_ops.size());
+    }
+
+    void backtrack()
+    {
+        // Backwards generate the backtracking code.
+        size_t opIndex = m_ops.size();
+        ASSERT(opIndex);
+
+        do {
+            --opIndex;
+            YarrOp& op = m_ops[opIndex];
+            switch (op.m_op) {
+
+            case OpTerm:
+                backtrackTerm(opIndex);
+                break;
+
+            // OpBodyAlternativeBegin/Next/End
+            //
+            // For each Begin/Next node representing an alternative, we need to decide what to do
+            // in two circumstances:
+            //  - If we backtrack back into this node, from within the alternative.
+            //  - If the input check at the head of the alternative fails (if this exists).
+            //
+            // We treat these two cases differently since in the former case we have slightly
+            // more information - since we are backtracking out of a prior alternative we know
+            // that at least enough input was available to run it. For example, given the regular
+            // expression /a|b/, if we backtrack out of the first alternative (a failed pattern
+            // character match of 'a'), then we need not perform an additional input availability
+            // check before running the second alternative.
+            //
+            // Backtracking required differs for the last alternative, which in the case of the
+            // repeating set of alternatives must loop. The code generated for the last alternative
+            // will also be used to handle all input check failures from any prior alternatives -
+            // these require similar functionality, in seeking the next available alternative for
+            // which there is sufficient input.
+            //
+            // Since backtracking of all other alternatives simply requires us to link backtracks
+            // to the reentry point for the subsequent alternative, we will only be generating any
+            // code when backtracking the last alternative.
+            case OpBodyAlternativeBegin:
+            case OpBodyAlternativeNext: {
+                PatternAlternative* alternative = op.m_alternative;
+
+                if (op.m_op == OpBodyAlternativeNext) {
+                    PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+                    m_checked += priorAlternative->m_minimumSize;
+                }
+                m_checked -= alternative->m_minimumSize;
+
+                // Is this the last alternative? If not, then if we backtrack to this point we just
+                // need to jump to try to match the next alternative.
+                if (m_ops[op.m_nextOp].m_op != OpBodyAlternativeEnd) {
+                    m_backtrackingState.linkTo(m_ops[op.m_nextOp].m_reentry, this);
+                    break;
+                }
+                YarrOp& endOp = m_ops[op.m_nextOp];
+
+                YarrOp* beginOp = &op;
+                while (beginOp->m_op != OpBodyAlternativeBegin) {
+                    ASSERT(beginOp->m_op == OpBodyAlternativeNext);
+                    beginOp = &m_ops[beginOp->m_previousOp];
+                }
+
+                bool onceThrough = endOp.m_nextOp == notFound;
+
+                // First, generate code to handle cases where we backtrack out of an attempted match
+                // of the last alternative. If this is a 'once through' set of alternatives then we
+                // have nothing to do - link this straight through to the End.
+                if (onceThrough)
+                    m_backtrackingState.linkTo(endOp.m_reentry, this);
+                else {
+                    // Okay, we're going to need to loop. Calculate the delta between where the input
+                    // position was, and where we want it to be allowing for the fact that we need to
+                    // increment by 1. E.g. for the regexp /a|x/ we need to increment the position by
+                    // 1 between loop iterations, but for /abcd|xyz/ we need to increment by two when
+                    // looping from the last alternative to the first, for /a|xyz/ we need to decrement
+                    // by 1, and for /a|xy/ we don't need to move the input position at all.
+                    int deltaLastAlternativeToFirstAlternativePlusOne = (beginOp->m_alternative->m_minimumSize - alternative->m_minimumSize) + 1;
+
+                    // If we don't need to move the input poistion, and the pattern has a fixed size
+                    // (in which case we omit the store of the start index until the pattern has matched)
+                    // then we can just link the backtrack out of the last alternative straight to the
+                    // head of the first alternative.
+                    if (!deltaLastAlternativeToFirstAlternativePlusOne && m_pattern.m_body->m_hasFixedSize)
+                        m_backtrackingState.linkTo(beginOp->m_reentry, this);
+                    else {
+                        // We need to generate a trampoline of code to execute before looping back
+                        // around to the first alternative.
+                        m_backtrackingState.link(this);
+
+                        // If the pattern size is not fixed, then store the start index, for use if we match.
+                        if (!m_pattern.m_body->m_hasFixedSize) {
+                            if (alternative->m_minimumSize == 1)
+                                store32(index, Address(output));
+                            else {
+                                move(index, regT0);
+                                if (alternative->m_minimumSize)
+                                    sub32(Imm32(alternative->m_minimumSize - 1), regT0);
+                                else
+                                    add32(Imm32(1), regT0);
+                                store32(regT0, Address(output));
+                            }
+                        }
+
+                        if (deltaLastAlternativeToFirstAlternativePlusOne)
+                            add32(Imm32(deltaLastAlternativeToFirstAlternativePlusOne), index);
+
+                        // Loop. Since this code is only reached when we backtrack out of the last
+                        // alternative (and NOT linked to from the input check upon entry to the
+                        // last alternative) we know that there must be at least enough input as
+                        // required by the last alternative. As such, we only need to check if the
+                        // first will require more to run - if the same or less is required we can
+                        // unconditionally jump.
+                        if (deltaLastAlternativeToFirstAlternativePlusOne > 0)
+                            checkInput().linkTo(beginOp->m_reentry, this);
+                        else
+                            jump(beginOp->m_reentry);
+                    }
+                }
+
+                // We can reach this point in the code in two ways:
+                //  - Fallthrough from the code above (a repeating alternative backtracked out of its
+                //    last alternative, and did not have sufficent input to run the first).
+                //  - We will loop back up to the following label when a releating alternative loops,
+                //    following a failed input check.
+                //
+                // Either way, we have just failed the input check for the first alternative.
+                Label firstInputCheckFailed(this);
+
+                // Generate code to handle input check failures from alternatives except the last.
+                // prevOp is the alternative we're handling a bail out from (initially Begin), and
+                // nextOp is the alternative we will be attempting to reenter into.
+                // 
+                // We will link input check failures from the forwards matching path back to the code
+                // that can handle them.
+                YarrOp* prevOp = beginOp;
+                YarrOp* nextOp = &m_ops[beginOp->m_nextOp];
+                while (nextOp->m_op != OpBodyAlternativeEnd) {
+                    prevOp->m_jumps.link(this);
+
+                    int delta = nextOp->m_alternative->m_minimumSize - prevOp->m_alternative->m_minimumSize;
+                    if (delta)
+                        add32(Imm32(delta), index);
+
+                    // We only get here if an input check fails, it is only worth checking again
+                    // if the next alternative has a minimum size less than the last.
+                    if (delta < 0) {
+                        // FIXME: if we added an extra label to YarrOp, we could avoid needing to
+                        // subtract delta back out, and reduce this code. Should performance test
+                        // the benefit of this.
+                        Jump fail = jumpIfNoAvailableInput();
+                        sub32(Imm32(delta), index);
+                        jump(nextOp->m_reentry);
+                        fail.link(this);
+                    }
+                    prevOp = nextOp;
+                    nextOp = &m_ops[nextOp->m_nextOp];
+                }
+
+                // We fall through to here if there is insufficient input to run the last alternative.
+
+                // If there is insufficient input to run the last alternative, then for 'once through'
+                // alternatives we are done - just jump back up into the forwards matching path at the End.
+                if (onceThrough) {
+                    op.m_jumps.linkTo(endOp.m_reentry, this);
+                    jump(endOp.m_reentry);
+                    break;
+                }
+
+                // For repeating alternatives, link any input check failure from the last alternative to
+                // this point.
+                op.m_jumps.link(this);
+
+                bool needsToUpdateMatchStart = !m_pattern.m_body->m_hasFixedSize;
+
+                // Check for cases where input position is already incremented by 1 for the last
+                // alternative (this is particularly useful where the minimum size of the body
+                // disjunction is 0, e.g. /a*|b/).
+                if (needsToUpdateMatchStart && alternative->m_minimumSize == 1) {
+                    // index is already incremented by 1, so just store it now!
+                    store32(index, Address(output));
+                    needsToUpdateMatchStart = false;
+                }
+
+                // Check whether there is sufficient input to loop. Increment the input position by
+                // one, and check. Also add in the minimum disjunction size before checking - there
+                // is no point in looping if we're just going to fail all the input checks around
+                // the next iteration.
+                int deltaLastAlternativeToBodyMinimumPlusOne = (m_pattern.m_body->m_minimumSize + 1) - alternative->m_minimumSize;
+                if (deltaLastAlternativeToBodyMinimumPlusOne)
+                    add32(Imm32(deltaLastAlternativeToBodyMinimumPlusOne), index);
+                Jump matchFailed = jumpIfNoAvailableInput();
+
+                if (needsToUpdateMatchStart) {
+                    if (!m_pattern.m_body->m_minimumSize)
+                        store32(index, Address(output));
+                    else {
+                        move(index, regT0);
+                        sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0);
+                        store32(regT0, Address(output));
+                    }
+                }
+
+                // Calculate how much more input the first alternative requires than the minimum
+                // for the body as a whole. If no more is needed then we dont need an additional
+                // input check here - jump straight back up to the start of the first alternative.
+                int deltaBodyMinimumToFirstAlternative = beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize;
+                if (!deltaBodyMinimumToFirstAlternative)
+                    jump(beginOp->m_reentry);
+                else {
+                    add32(Imm32(deltaBodyMinimumToFirstAlternative), index);
+                    checkInput().linkTo(beginOp->m_reentry, this);
+                    jump(firstInputCheckFailed);
+                }
+
+                // We jump to here if we iterate to the point that there is insufficient input to
+                // run any matches, and need to return a failure state from JIT code.
+                matchFailed.link(this);
+
+                if (m_pattern.m_body->m_callFrameSize)
+                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+                move(TrustedImm32(-1), returnRegister);
+                generateReturn();
+                break;
+            }
+            case OpBodyAlternativeEnd: {
+                // We should never backtrack back into a body disjunction.
+                ASSERT(m_backtrackingState.isEmpty());
+
+                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+                m_checked += priorAlternative->m_minimumSize;
+                break;
+            }
+
+            // OpSimpleNestedAlternativeBegin/Next/End
+            // OpNestedAlternativeBegin/Next/End
+            //
+            // Generate code for when we backtrack back out of an alternative into
+            // a Begin or Next node, or when the entry input count check fails. If
+            // there are more alternatives we need to jump to the next alternative,
+            // if not we backtrack back out of the current set of parentheses.
+            //
+            // In the case of non-simple nested assertions we need to also link the
+            // 'return address' appropriately to backtrack back out into the correct
+            // alternative.
+            case OpSimpleNestedAlternativeBegin:
+            case OpSimpleNestedAlternativeNext:
+            case OpNestedAlternativeBegin:
+            case OpNestedAlternativeNext: {
+                YarrOp& nextOp = m_ops[op.m_nextOp];
+                bool isBegin = op.m_previousOp == notFound;
+                bool isLastAlternative = nextOp.m_nextOp == notFound;
+                ASSERT(isBegin == (op.m_op == OpSimpleNestedAlternativeBegin || op.m_op == OpNestedAlternativeBegin));
+                ASSERT(isLastAlternative == (nextOp.m_op == OpSimpleNestedAlternativeEnd || nextOp.m_op == OpNestedAlternativeEnd));
+
+                // Treat an input check failure the same as a failed match.
+                m_backtrackingState.append(op.m_jumps);
+
+                // Set the backtracks to jump to the appropriate place. We may need
+                // to link the backtracks in one of three different way depending on
+                // the type of alternative we are dealing with:
+                //  - A single alternative, with no simplings.
+                //  - The last alternative of a set of two or more.
+                //  - An alternative other than the last of a set of two or more.
+                //
+                // In the case of a single alternative on its own, we don't need to
+                // jump anywhere - if the alternative fails to match we can just
+                // continue to backtrack out of the parentheses without jumping.
+                //
+                // In the case of the last alternative in a set of more than one, we
+                // need to jump to return back out to the beginning. We'll do so by
+                // adding a jump to the End node's m_jumps list, and linking this
+                // when we come to generate the Begin node. For alternatives other
+                // than the last, we need to jump to the next alternative.
+                //
+                // If the alternative had adjusted the input position we must link
+                // backtracking to here, correct, and then jump on. If not we can
+                // link the backtracks directly to their destination.
+                if (op.m_checkAdjust) {
+                    // Handle the cases where we need to link the backtracks here.
+                    m_backtrackingState.link(this);
+                    sub32(Imm32(op.m_checkAdjust), index);
+                    if (!isLastAlternative) {
+                        // An alternative that is not the last should jump to its successor.
+                        jump(nextOp.m_reentry);
+                    } else if (!isBegin) {
+                        // The last of more than one alternatives must jump back to the begnning.
+                        nextOp.m_jumps.append(jump());
+                    } else {
+                        // A single alternative on its own can fall through.
+                        m_backtrackingState.fallthrough();
+                    }
+                } else {
+                    // Handle the cases where we can link the backtracks directly to their destinations.
+                    if (!isLastAlternative) {
+                        // An alternative that is not the last should jump to its successor.
+                        m_backtrackingState.linkTo(nextOp.m_reentry, this);
+                    } else if (!isBegin) {
+                        // The last of more than one alternatives must jump back to the begnning.
+                        m_backtrackingState.takeBacktracksToJumpList(nextOp.m_jumps, this);
+                    }
+                    // In the case of a single alternative on its own do nothing - it can fall through.
+                }
+
+                // At this point we've handled the backtracking back into this node.
+                // Now link any backtracks that need to jump to here.
+
+                // For non-simple alternatives, link the alternative's 'return address'
+                // so that we backtrack back out into the previous alternative.
+                if (op.m_op == OpNestedAlternativeNext)
+                    m_backtrackingState.append(op.m_returnAddress);
+
+                // If there is more than one alternative, then the last alternative will
+                // have planted a jump to be linked to the end. This jump was added to the
+                // End node's m_jumps list. If we are back at the beginning, link it here.
+                if (isBegin) {
+                    YarrOp* endOp = &m_ops[op.m_nextOp];
+                    while (endOp->m_nextOp != notFound) {
+                        ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
+                        endOp = &m_ops[endOp->m_nextOp];
+                    }
+                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
+                    m_backtrackingState.append(endOp->m_jumps);
+                }
+
+                if (!isBegin) {
+                    YarrOp& lastOp = m_ops[op.m_previousOp];
+                    m_checked += lastOp.m_checkAdjust;
+                }
+                m_checked -= op.m_checkAdjust;
+                break;
+            }
+            case OpSimpleNestedAlternativeEnd:
+            case OpNestedAlternativeEnd: {
+                PatternTerm* term = op.m_term;
+
+                // If we backtrack into the end of a simple subpattern do nothing;
+                // just continue through into the last alternative. If we backtrack
+                // into the end of a non-simple set of alterntives we need to jump
+                // to the backtracking return address set up during generation.
+                if (op.m_op == OpNestedAlternativeEnd) {
+                    m_backtrackingState.link(this);
+
+                    // Plant a jump to the return address.
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
+                    if (term->quantityType != QuantifierFixedCount)
+                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+                    loadFromFrameAndJump(alternativeFrameLocation);
+
+                    // Link the DataLabelPtr associated with the end of the last
+                    // alternative to this point.
+                    m_backtrackingState.append(op.m_returnAddress);
+                }
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked += lastOp.m_checkAdjust;
+                break;
+            }
+
+            // OpParenthesesSubpatternOnceBegin/End
+            //
+            // When we are backtracking back out of a capturing subpattern we need
+            // to clear the start index in the matches output array, to record that
+            // this subpattern has not been captured.
+            //
+            // When backtracking back out of a Greedy quantified subpattern we need
+            // to catch this, and try running the remainder of the alternative after
+            // the subpattern again, skipping the parentheses.
+            //
+            // Upon backtracking back into a quantified set of parentheses we need to
+            // check whether we were currently skipping the subpattern. If not, we
+            // can backtrack into them, if we were we need to either backtrack back
+            // out of the start of the parentheses, or jump back to the forwards
+            // matching start, depending of whether the match is Greedy or NonGreedy.
+            case OpParenthesesSubpatternOnceBegin: {
+                PatternTerm* term = op.m_term;
+                ASSERT(term->quantityCount == 1);
+
+                // We only need to backtrack to thispoint if capturing or greedy.
+                if (term->capture() || term->quantityType == QuantifierGreedy) {
+                    m_backtrackingState.link(this);
+
+                    // If capturing, clear the capture (we only need to reset start).
+                    if (term->capture())
+                        store32(TrustedImm32(-1), Address(output, (term->parentheses.subpatternId << 1) * sizeof(int)));
+
+                    // If Greedy, jump to the end.
+                    if (term->quantityType == QuantifierGreedy) {
+                        // Clear the flag in the stackframe indicating we ran through the subpattern.
+                        unsigned parenthesesFrameLocation = term->frameLocation;
+                        storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
+                        // Jump to after the parentheses, skipping the subpattern.
+                        jump(m_ops[op.m_nextOp].m_reentry);
+                        // A backtrack from after the parentheses, when skipping the subpattern,
+                        // will jump back to here.
+                        op.m_jumps.link(this);
+                    }
+
+                    m_backtrackingState.fallthrough();
+                }
+                break;
+            }
+            case OpParenthesesSubpatternOnceEnd: {
+                PatternTerm* term = op.m_term;
+
+                if (term->quantityType != QuantifierFixedCount) {
+                    m_backtrackingState.link(this);
+
+                    // Check whether we should backtrack back into the parentheses, or if we
+                    // are currently in a state where we had skipped over the subpattern
+                    // (in which case the flag value on the stack will be -1).
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1));
+
+                    if (term->quantityType == QuantifierGreedy) {
+                        // For Greedy parentheses, we skip after having already tried going
+                        // through the subpattern, so if we get here we're done.
+                        YarrOp& beginOp = m_ops[op.m_previousOp];
+                        beginOp.m_jumps.append(hadSkipped);
+                    } else {
+                        // For NonGreedy parentheses, we try skipping the subpattern first,
+                        // so if we get here we need to try running through the subpattern
+                        // next. Jump back to the start of the parentheses in the forwards
+                        // matching path.
+                        ASSERT(term->quantityType == QuantifierNonGreedy);
+                        YarrOp& beginOp = m_ops[op.m_previousOp];
+                        hadSkipped.linkTo(beginOp.m_reentry, this);
+                    }
+
+                    m_backtrackingState.fallthrough();
+                }
+
+                m_backtrackingState.append(op.m_jumps);
+                break;
+            }
+
+            // OpParenthesesSubpatternTerminalBegin/End
+            //
+            // Terminal subpatterns will always match - there is nothing after them to
+            // force a backtrack, and they have a minimum count of 0, and as such will
+            // always produce an acceptable result.
+            case OpParenthesesSubpatternTerminalBegin: {
+                // We will backtrack to this point once the subpattern cannot match any
+                // more. Since no match is accepted as a successful match (we are Greedy
+                // quantified with a minimum of zero) jump back to the forwards matching
+                // path at the end.
+                YarrOp& endOp = m_ops[op.m_nextOp];
+                m_backtrackingState.linkTo(endOp.m_reentry, this);
+                break;
+            }
+            case OpParenthesesSubpatternTerminalEnd:
+                // We should never be backtracking to here (hence the 'terminal' in the name).
+                ASSERT(m_backtrackingState.isEmpty());
+                m_backtrackingState.append(op.m_jumps);
+                break;
+
+            // OpParentheticalAssertionBegin/End
+            case OpParentheticalAssertionBegin: {
+                PatternTerm* term = op.m_term;
+                YarrOp& endOp = m_ops[op.m_nextOp];
+
+                // We need to handle the backtracks upon backtracking back out
+                // of a parenthetical assertion if either we need to correct
+                // the input index, or the assertion was inverted.
+                if (op.m_checkAdjust || term->invert()) {
+                     m_backtrackingState.link(this);
+
+                    if (op.m_checkAdjust)
+                        add32(Imm32(op.m_checkAdjust), index);
+
+                    // In an inverted assertion failure to match the subpattern
+                    // is treated as a successful match - jump to the end of the
+                    // subpattern. We already have adjusted the input position
+                    // back to that before the assertion, which is correct.
+                    if (term->invert())
+                        jump(endOp.m_reentry);
+
+                    m_backtrackingState.fallthrough();
+                }
+
+                // The End node's jump list will contain any backtracks into
+                // the end of the assertion. Also, if inverted, we will have
+                // added the failure caused by a successful match to this.
+                m_backtrackingState.append(endOp.m_jumps);
+
+                m_checked += op.m_checkAdjust;
+                break;
+            }
+            case OpParentheticalAssertionEnd: {
+                // FIXME: We should really be clearing any nested subpattern
+                // matches on bailing out from after the pattern. Firefox has
+                // this bug too (presumably because they use YARR!)
+
+                // Never backtrack into an assertion; later failures bail to before the begin.
+                m_backtrackingState.takeBacktracksToJumpList(op.m_jumps, this);
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked -= lastOp.m_checkAdjust;
+                break;
+            }
+
+            case OpMatchFailed:
+                break;
+            }
+
+        } while (opIndex);
+    }
+
+    // Compilation methods:
+    // ====================
+
+    // opCompileParenthesesSubpattern
+    // Emits ops for a subpattern (set of parentheses). These consist
+    // of a set of alternatives wrapped in an outer set of nodes for
+    // the parentheses.
+    // Supported types of parentheses are 'Once' (quantityCount == 1)
+    // and 'Terminal' (non-capturing parentheses quantified as greedy
+    // and infinite).
+    // Alternatives will use the 'Simple' set of ops if either the
+    // subpattern is terminal (in which case we will never need to
+    // backtrack), or if the subpattern only contains one alternative.
+    void opCompileParenthesesSubpattern(PatternTerm* term)
+    {
+        YarrOpCode parenthesesBeginOpCode;
+        YarrOpCode parenthesesEndOpCode;
+        YarrOpCode alternativeBeginOpCode = OpSimpleNestedAlternativeBegin;
+        YarrOpCode alternativeNextOpCode = OpSimpleNestedAlternativeNext;
+        YarrOpCode alternativeEndOpCode = OpSimpleNestedAlternativeEnd;
+
+        // We can currently only compile quantity 1 subpatterns that are
+        // not copies. We generate a copy in the case of a range quantifier,
+        // e.g. /(?:x){3,9}/, or /(?:x)+/ (These are effectively expanded to
+        // /(?:x){3,3}(?:x){0,6}/ and /(?:x)(?:x)*/ repectively). The problem
+        // comes where the subpattern is capturing, in which case we would
+        // need to restore the capture from the first subpattern upon a
+        // failure in the second.
+        if (term->quantityCount == 1 && !term->parentheses.isCopy) {
+            // Select the 'Once' nodes.
+            parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin;
+            parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd;
+
+            // If there is more than one alternative we cannot use the 'simple' nodes.
+            if (term->parentheses.disjunction->m_alternatives.size() != 1) {
+                alternativeBeginOpCode = OpNestedAlternativeBegin;
+                alternativeNextOpCode = OpNestedAlternativeNext;
+                alternativeEndOpCode = OpNestedAlternativeEnd;
+            }
+        } else if (term->parentheses.isTerminal) {
+            // Select the 'Terminal' nodes.
+            parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin;
+            parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd;
+        } else {
+            // This subpattern is not supported by the JIT.
+            m_shouldFallBack = true;
+            return;
+        }
+
+        size_t parenBegin = m_ops.size();
+        m_ops.append(parenthesesBeginOpCode);
+
+        m_ops.append(alternativeBeginOpCode);
+        m_ops.last().m_previousOp = notFound;
+        m_ops.last().m_term = term;
+        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
+        for (unsigned i = 0; i < alternatives.size(); ++i) {
+            size_t lastOpIndex = m_ops.size() - 1;
+
+            PatternAlternative* nestedAlternative = alternatives[i];
+            opCompileAlternative(nestedAlternative);
+
+            size_t thisOpIndex = m_ops.size();
+            m_ops.append(YarrOp(alternativeNextOpCode));
+
+            YarrOp& lastOp = m_ops[lastOpIndex];
+            YarrOp& thisOp = m_ops[thisOpIndex];
+
+            lastOp.m_alternative = nestedAlternative;
+            lastOp.m_nextOp = thisOpIndex;
+            thisOp.m_previousOp = lastOpIndex;
+            thisOp.m_term = term;
+        }
+        YarrOp& lastOp = m_ops.last();
+        ASSERT(lastOp.m_op == alternativeNextOpCode);
+        lastOp.m_op = alternativeEndOpCode;
+        lastOp.m_alternative = 0;
+        lastOp.m_nextOp = notFound;
+
+        size_t parenEnd = m_ops.size();
+        m_ops.append(parenthesesEndOpCode);
+
+        m_ops[parenBegin].m_term = term;
+        m_ops[parenBegin].m_previousOp = notFound;
+        m_ops[parenBegin].m_nextOp = parenEnd;
+        m_ops[parenEnd].m_term = term;
+        m_ops[parenEnd].m_previousOp = parenBegin;
+        m_ops[parenEnd].m_nextOp = notFound;
+    }
+
+    // opCompileParentheticalAssertion
+    // Emits ops for a parenthetical assertion. These consist of an
+    // OpSimpleNestedAlternativeBegin/Next/End set of nodes wrapping
+    // the alternatives, with these wrapped by an outer pair of
+    // OpParentheticalAssertionBegin/End nodes.
+    // We can always use the OpSimpleNestedAlternative nodes in the
+    // case of parenthetical assertions since these only ever match
+    // once, and will never backtrack back into the assertion.
+    void opCompileParentheticalAssertion(PatternTerm* term)
+    {
+        size_t parenBegin = m_ops.size();
+        m_ops.append(OpParentheticalAssertionBegin);
+
+        m_ops.append(OpSimpleNestedAlternativeBegin);
+        m_ops.last().m_previousOp = notFound;
+        m_ops.last().m_term = term;
+        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
+        for (unsigned i = 0; i < alternatives.size(); ++i) {
+            size_t lastOpIndex = m_ops.size() - 1;
+
+            PatternAlternative* nestedAlternative = alternatives[i];
+            opCompileAlternative(nestedAlternative);
+
+            size_t thisOpIndex = m_ops.size();
+            m_ops.append(YarrOp(OpSimpleNestedAlternativeNext));
+
+            YarrOp& lastOp = m_ops[lastOpIndex];
+            YarrOp& thisOp = m_ops[thisOpIndex];
+
+            lastOp.m_alternative = nestedAlternative;
+            lastOp.m_nextOp = thisOpIndex;
+            thisOp.m_previousOp = lastOpIndex;
+            thisOp.m_term = term;
+        }
+        YarrOp& lastOp = m_ops.last();
+        ASSERT(lastOp.m_op == OpSimpleNestedAlternativeNext);
+        lastOp.m_op = OpSimpleNestedAlternativeEnd;
+        lastOp.m_alternative = 0;
+        lastOp.m_nextOp = notFound;
+
+        size_t parenEnd = m_ops.size();
+        m_ops.append(OpParentheticalAssertionEnd);
+
+        m_ops[parenBegin].m_term = term;
+        m_ops[parenBegin].m_previousOp = notFound;
+        m_ops[parenBegin].m_nextOp = parenEnd;
+        m_ops[parenEnd].m_term = term;
+        m_ops[parenEnd].m_previousOp = parenBegin;
+        m_ops[parenEnd].m_nextOp = notFound;
+    }
+
+    // opCompileAlternative
+    // Called to emit nodes for all terms in an alternative.
+    void opCompileAlternative(PatternAlternative* alternative)
+    {
+        optimizeAlternative(alternative);
+
+        for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
+            PatternTerm* term = &alternative->m_terms[i];
+
+            switch (term->type) {
+            case PatternTerm::TypeParenthesesSubpattern:
+                opCompileParenthesesSubpattern(term);
+                break;
+
+            case PatternTerm::TypeParentheticalAssertion:
+                opCompileParentheticalAssertion(term);
+                break;
+
+            default:
+                m_ops.append(term);
+            }
+        }
+    }
+
+    // opCompileBody
+    // This method compiles the body disjunction of the regular expression.
+    // The body consists of two sets of alternatives - zero or more 'once
+    // through' (BOL anchored) alternatives, followed by zero or more
+    // repeated alternatives.
+    // For each of these two sets of alteratives, if not empty they will be
+    // wrapped in a set of OpBodyAlternativeBegin/Next/End nodes (with the
+    // 'begin' node referencing the first alternative, and 'next' nodes
+    // referencing any further alternatives. The begin/next/end nodes are
+    // linked together in a doubly linked list. In the case of repeating
+    // alternatives, the end node is also linked back to the beginning.
+    // If no repeating alternatives exist, then a OpMatchFailed node exists
+    // to return the failing result.
+    void opCompileBody(PatternDisjunction* disjunction)
+    {
+        Vector& alternatives =  disjunction->m_alternatives;
+        size_t currentAlternativeIndex = 0;
+
+        // Emit the 'once through' alternatives.
+        if (alternatives.size() && alternatives[0]->onceThrough()) {
+            m_ops.append(YarrOp(OpBodyAlternativeBegin));
+            m_ops.last().m_previousOp = notFound;
+
+            do {
+                size_t lastOpIndex = m_ops.size() - 1;
+                PatternAlternative* alternative = alternatives[currentAlternativeIndex];
+                opCompileAlternative(alternative);
+
+                size_t thisOpIndex = m_ops.size();
+                m_ops.append(YarrOp(OpBodyAlternativeNext));
+
+                YarrOp& lastOp = m_ops[lastOpIndex];
+                YarrOp& thisOp = m_ops[thisOpIndex];
+
+                lastOp.m_alternative = alternative;
+                lastOp.m_nextOp = thisOpIndex;
+                thisOp.m_previousOp = lastOpIndex;
+                
+                ++currentAlternativeIndex;
+            } while (currentAlternativeIndex < alternatives.size() && alternatives[currentAlternativeIndex]->onceThrough());
+
+            YarrOp& lastOp = m_ops.last();
+
+            ASSERT(lastOp.m_op == OpBodyAlternativeNext);
+            lastOp.m_op = OpBodyAlternativeEnd;
+            lastOp.m_alternative = 0;
+            lastOp.m_nextOp = notFound;
+        }
+
+        if (currentAlternativeIndex == alternatives.size()) {
+            m_ops.append(YarrOp(OpMatchFailed));
+            return;
+        }
+
+        // Emit the repeated alternatives.
+        size_t repeatLoop = m_ops.size();
+        m_ops.append(YarrOp(OpBodyAlternativeBegin));
+        m_ops.last().m_previousOp = notFound;
+        do {
+            size_t lastOpIndex = m_ops.size() - 1;
+            PatternAlternative* alternative = alternatives[currentAlternativeIndex];
+            ASSERT(!alternative->onceThrough());
+            opCompileAlternative(alternative);
+
+            size_t thisOpIndex = m_ops.size();
+            m_ops.append(YarrOp(OpBodyAlternativeNext));
+
+            YarrOp& lastOp = m_ops[lastOpIndex];
+            YarrOp& thisOp = m_ops[thisOpIndex];
+
+            lastOp.m_alternative = alternative;
+            lastOp.m_nextOp = thisOpIndex;
+            thisOp.m_previousOp = lastOpIndex;
+            
+            ++currentAlternativeIndex;
+        } while (currentAlternativeIndex < alternatives.size());
+        YarrOp& lastOp = m_ops.last();
+        ASSERT(lastOp.m_op == OpBodyAlternativeNext);
+        lastOp.m_op = OpBodyAlternativeEnd;
+        lastOp.m_alternative = 0;
+        lastOp.m_nextOp = repeatLoop;
+    }
+
+    void generateEnter()
+    {
+#if WTF_CPU_X86_64
+        push(X86Registers::ebp);
+        move(stackPointerRegister, X86Registers::ebp);
+        push(X86Registers::ebx);
+#elif WTF_CPU_X86
+        push(X86Registers::ebp);
+        move(stackPointerRegister, X86Registers::ebp);
+        // TODO: do we need spill registers to fill the output pointer if there are no sub captures?
+        push(X86Registers::ebx);
+        push(X86Registers::edi);
+        push(X86Registers::esi);
+        // load output into edi (2 = saved ebp + return address).
+    #if WTF_COMPILER_MSVC
+        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input);
+        loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index);
+        loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length);
+        loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output);
+    #else
+        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
+    #endif
+#elif WTF_CPU_ARM
+        push(ARMRegisters::r4);
+        push(ARMRegisters::r5);
+        push(ARMRegisters::r6);
+#if WTF_CPU_ARM_TRADITIONAL
+        push(ARMRegisters::r8); // scratch register
+#endif
+        move(ARMRegisters::r3, output);
+#elif WTF_CPU_SH4
+        push(SH4Registers::r11);
+        push(SH4Registers::r13);
+#elif WTF_CPU_MIPS
+        // Do nothing.
+#endif
+    }
+
+    void generateReturn()
+    {
+#if WTF_CPU_X86_64
+        pop(X86Registers::ebx);
+        pop(X86Registers::ebp);
+#elif WTF_CPU_X86
+        pop(X86Registers::esi);
+        pop(X86Registers::edi);
+        pop(X86Registers::ebx);
+        pop(X86Registers::ebp);
+#elif WTF_CPU_ARM
+#if WTF_CPU_ARM_TRADITIONAL
+        pop(ARMRegisters::r8); // scratch register
+#endif
+        pop(ARMRegisters::r6);
+        pop(ARMRegisters::r5);
+        pop(ARMRegisters::r4);
+#elif WTF_CPU_SH4
+        pop(SH4Registers::r13);
+        pop(SH4Registers::r11);
+#elif WTF_CPU_MIPS
+        // Do nothing
+#endif
+        ret();
+    }
+
+public:
+    YarrGenerator(YarrPattern& pattern)
+        : m_pattern(pattern)
+        , m_shouldFallBack(false)
+        , m_checked(0)
+    {
+    }
+
+    void compile(JSGlobalData* globalData, YarrCodeBlock& jitObject)
+    {
+        generateEnter();
+
+        if (!m_pattern.m_body->m_hasFixedSize)
+            store32(index, Address(output));
+
+        if (m_pattern.m_body->m_callFrameSize)
+            subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+
+        // Compile the pattern to the internal 'YarrOp' representation.
+        opCompileBody(m_pattern.m_body);
+
+        // If we encountered anything we can't handle in the JIT code
+        // (e.g. backreferences) then return early.
+        if (m_shouldFallBack) {
+            jitObject.setFallBack(true);
+            return;
+        }
+
+        generate();
+        backtrack();
+
+        // Link & finalize the code.
+        // XXX yarr-oom
+        ExecutablePool *pool;
+        bool ok;
+        LinkBuffer linkBuffer(this, globalData->regexAllocator, &pool, &ok);
+        m_backtrackingState.linkDataLabels(linkBuffer);
+        jitObject.set(linkBuffer.finalizeCode());
+        jitObject.setFallBack(m_shouldFallBack);
+    }
+
+private:
+    YarrPattern& m_pattern;
+
+    // Used to detect regular expression constructs that are not currently
+    // supported in the JIT; fall back to the interpreter when this is detected.
+    bool m_shouldFallBack;
+
+    // The regular expression expressed as a linear sequence of operations.
+    Vector m_ops;
+
+    // This records the current input offset being applied due to the current
+    // set of alternatives we are nested within. E.g. when matching the
+    // character 'b' within the regular expression /abc/, we will know that
+    // the minimum size for the alternative is 3, checked upon entry to the
+    // alternative, and that 'b' is at offset 1 from the start, and as such
+    // when matching 'b' we need to apply an offset of -2 to the load.
+    //
+    // FIXME: This should go away. Rather than tracking this value throughout
+    // code generation, we should gather this information up front & store it
+    // on the YarrOp structure.
+    int m_checked;
+
+    // This class records state whilst generating the backtracking path of code.
+    BacktrackingState m_backtrackingState;
+};
+
+void jitCompile(YarrPattern& pattern, JSGlobalData* globalData, YarrCodeBlock& jitObject)
+{
+    YarrGenerator(pattern).compile(globalData, jitObject);
+}
+
+int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output)
+{
+    return jitObject.execute(input, start, length, output);
+}
+
+}}
+
+#endif
diff --git a/js/src/yarr/YarrJIT.h b/js/src/yarr/YarrJIT.h
new file mode 100644
index 000000000000..4f0f47f8c548
--- /dev/null
+++ b/js/src/yarr/YarrJIT.h
@@ -0,0 +1,93 @@
+/* -*- 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.
+ *
+ * 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef YarrJIT_h
+#define YarrJIT_h
+
+#include "assembler/wtf/Platform.h"
+
+#if ENABLE_YARR_JIT
+
+#include "assembler/assembler/MacroAssembler.h"
+#include "YarrPattern.h"
+
+#if WTF_CPU_X86 && !WTF_COMPILER_MSVC
+#define YARR_CALL __attribute__ ((regparm (3)))
+#else
+#define YARR_CALL
+#endif
+
+namespace JSC {
+
+class JSGlobalData;
+class ExecutablePool;
+
+namespace Yarr {
+
+class YarrCodeBlock {
+    typedef int (*YarrJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
+
+public:
+    YarrCodeBlock()
+        : m_needFallBack(false)
+    {
+    }
+
+    ~YarrCodeBlock()
+    {
+    }
+
+    void setFallBack(bool fallback) { m_needFallBack = fallback; }
+    bool isFallBack() { return m_needFallBack; }
+    void set(MacroAssembler::CodeRef ref) { m_ref = ref; }
+
+    int execute(const UChar* input, unsigned start, unsigned length, int* output)
+    {
+        return JS_EXTENSION((reinterpret_cast(m_ref.m_code.executableAddress()))(input, start, length, output));
+    }
+
+#if ENABLE_REGEXP_TRACING
+    void *getAddr() { return m_ref.m_code.executableAddress(); }
+#endif
+
+    void release() { m_ref.release(); }
+
+private:
+    MacroAssembler::CodeRef m_ref;
+    bool m_needFallBack;
+};
+
+void jitCompile(YarrPattern&, JSGlobalData*, YarrCodeBlock& jitObject);
+int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output);
+
+} } // namespace JSC::Yarr
+
+#endif
+
+#endif // YarrJIT_h
diff --git a/js/src/yarr/yarr/RegexParser.h b/js/src/yarr/YarrParser.h
similarity index 81%
rename from js/src/yarr/yarr/RegexParser.h
rename to js/src/yarr/YarrParser.h
index 1ae2c2fd049b..f2b50dd867e3 100644
--- a/js/src/yarr/yarr/RegexParser.h
+++ b/js/src/yarr/YarrParser.h
@@ -1,4 +1,7 @@
-/*
+/* -*- 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.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -21,18 +24,18 @@
  * 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 RegexParser_h
-#define RegexParser_h
+#ifndef YarrParser_h
+#define YarrParser_h
 
-#include 
-#include 
-#include "yarr/jswtfbridge.h"
-#include "yarr/yarr/RegexCommon.h"
+#include "Yarr.h"
 
 namespace JSC { namespace Yarr {
 
+#define REGEXP_ERROR_PREFIX "Invalid regular expression: "
+
 enum BuiltInCharacterClassID {
     DigitClassID,
     SpaceClassID,
@@ -45,7 +48,7 @@ template
 class Parser {
 private:
     template
-    friend int parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit);
+    friend ErrorCode parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit);
 
     /*
      * CharacterClassParserDelegate:
@@ -61,10 +64,8 @@ private:
         CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err)
             : m_delegate(delegate)
             , m_err(err)
-            , m_state(empty)
-#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 5 /* quell GCC overwarning */
-            , m_character(0xFFFF)
-#endif
+            , m_state(Empty)
+            , m_character(0)
         {
         }
 
@@ -79,56 +80,62 @@ private:
         }
 
         /*
-         * atomPatternCharacterUnescaped():
+         * atomPatternCharacter():
          *
-         * This method is called directly from parseCharacterClass(), to report a new
-         * pattern character token.  This method differs from atomPatternCharacter(),
-         * which will be called from parseEscape(), since a hypen provided via this
-         * method may be indicating a character range, but a hyphen parsed by
-         * parseEscape() cannot be interpreted as doing so.
+         * This method is called either from parseCharacterClass() (for an unescaped
+         * character in a character class), or from parseEscape(). In the former case
+         * the value true will be passed for the argument 'hyphenIsRange', and in this
+         * mode we will allow a hypen to be treated as indicating a range (i.e. /[a-z]/
+         * is different to /[a\-z]/).
          */
-        void atomPatternCharacterUnescaped(UChar ch)
+        void atomPatternCharacter(UChar ch, bool hyphenIsRange = false)
         {
             switch (m_state) {
-            case empty:
-                m_character = ch;
-                m_state = cachedCharacter;
-                break;
+            case AfterCharacterClass:
+                // Following a builtin character class we need look out for a hyphen.
+                // We're looking for invalid ranges, such as /[\d-x]/ or /[\d-\d]/.
+                // If we see a hyphen following a charater class then unlike usual
+                // we'll report it to the delegate immediately, and put ourself into
+                // a poisoned state. Any following calls to add another character or
+                // character class will result in an error. (A hypen following a
+                // character-class is itself valid, but only  at the end of a regex).
+                if (hyphenIsRange && ch == '-') {
+                    m_delegate.atomCharacterClassAtom('-');
+                    m_state = AfterCharacterClassHyphen;
+                    return;
+                }
+                // Otherwise just fall through - cached character so treat this as Empty.
 
-            case cachedCharacter:
-                if (ch == '-')
-                    m_state = cachedCharacterHyphen;
+            case Empty:
+                m_character = ch;
+                m_state = CachedCharacter;
+                return;
+
+            case CachedCharacter:
+                if (hyphenIsRange && ch == '-')
+                    m_state = CachedCharacterHyphen;
                 else {
                     m_delegate.atomCharacterClassAtom(m_character);
                     m_character = ch;
                 }
-                break;
+                return;
 
-            case cachedCharacterHyphen:
-                if (ch >= m_character)
-                    m_delegate.atomCharacterClassRange(m_character, ch);
-                else
+            case CachedCharacterHyphen:
+                if (ch < m_character) {
                     m_err = CharacterClassOutOfOrder;
-                m_state = empty;
+                    return;
+                }
+                m_delegate.atomCharacterClassRange(m_character, ch);
+                m_state = Empty;
+                return;
+
+            case AfterCharacterClassHyphen:
+                m_delegate.atomCharacterClassAtom(ch);
+                m_state = Empty;
+                return;
             }
         }
 
-        /*
-         * atomPatternCharacter():
-         *
-         * Adds a pattern character, called by parseEscape(), as such will not
-         * interpret a hyphen as indicating a character range.
-         */
-        void atomPatternCharacter(UChar ch)
-        {
-            // Flush if a character is already pending to prevent the
-            // hyphen from begin interpreted as indicating a range.
-            if((ch == '-') && (m_state == cachedCharacter))
-                flush();
-
-            atomPatternCharacterUnescaped(ch);
-        }
-
         /*
          * atomBuiltInCharacterClass():
          *
@@ -136,17 +143,28 @@ private:
          */
         void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert)
         {
-            if (m_state == cachedCharacterHyphen) {
-                // If the RHS of a range does not contain exacly one character then a SyntaxError
-                // must be thrown. SpiderMonkey only errors out in the [c-\s] case as an extension.
-                // (This assumes none of the built in character classes contain a single
-                // character.)
-                m_err = CharacterClassRangeSingleChar;
-                m_state = empty;
+            switch (m_state) {
+            case CachedCharacter:
+                // Flush the currently cached character, then fall through.
+                m_delegate.atomCharacterClassAtom(m_character);
+
+            case Empty:
+            case AfterCharacterClass:
+                m_state = AfterCharacterClass;
+                m_delegate.atomCharacterClassBuiltIn(classID, invert);
+                return;
+
+            case CachedCharacterHyphen:
+                // Error! We have a range that looks like [x-\d]. We require
+                // the end of the range to be a single character.
+                m_err = CharacterClassInvalidRange;
+                return;
+
+            case AfterCharacterClassHyphen:
+                m_delegate.atomCharacterClassBuiltIn(classID, invert);
+                m_state = Empty;
                 return;
             }
-            flush();
-            m_delegate.atomCharacterClassBuiltIn(classID, invert);
         }
 
         /*
@@ -156,31 +174,29 @@ private:
          */
         void end()
         {
-            flush();
+            if (m_state == CachedCharacter)
+                m_delegate.atomCharacterClassAtom(m_character);
+            else if (m_state == CachedCharacterHyphen) {
+                m_delegate.atomCharacterClassAtom(m_character);
+                m_delegate.atomCharacterClassAtom('-');
+            }
             m_delegate.atomCharacterClassEnd();
         }
 
         // parseEscape() should never call these delegate methods when
         // invoked with inCharacterClass set.
-        void assertionWordBoundary(bool) { JS_NOT_REACHED("parseEscape() should never call this"); }
-        void atomBackReference(unsigned) { JS_NOT_REACHED("parseEscape() should never call this"); }
+        void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); }
+        void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); }
 
     private:
-        void flush()
-        {
-            if (m_state != empty) // either cachedCharacter or cachedCharacterHyphen
-                m_delegate.atomCharacterClassAtom(m_character);
-            if (m_state == cachedCharacterHyphen)
-                m_delegate.atomCharacterClassAtom('-');
-            m_state = empty;
-        }
-    
         Delegate& m_delegate;
         ErrorCode& m_err;
         enum CharacterClassConstructionState {
-            empty,
-            cachedCharacter,
-            cachedCharacterHyphen
+            Empty,
+            CachedCharacter,
+            CachedCharacterHyphen,
+            AfterCharacterClass,
+            AfterCharacterClassHyphen
         } m_state;
         UChar m_character;
     };
@@ -189,7 +205,7 @@ private:
         : m_delegate(delegate)
         , m_backReferenceLimit(backReferenceLimit)
         , m_err(NoError)
-        , m_data(const_cast(pattern).chars())
+        , m_data(pattern.chars())
         , m_size(pattern.length())
         , m_index(0)
         , m_parenthesesNestingDepth(0)
@@ -219,8 +235,8 @@ private:
     template
     bool parseEscape(EscapeDelegate& delegate)
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(peek() == '\\');
+        ASSERT(!m_err);
+        ASSERT(peek() == '\\');
         consume();
 
         if (atEndOfPattern()) {
@@ -292,7 +308,7 @@ private:
 
                 unsigned backReference;
                 if (!consumeNumber(backReference))
-                    return false;
+                    break;
                 if (backReference <= m_backReferenceLimit) {
                     delegate.atomBackReference(backReference);
                     break;
@@ -402,14 +418,14 @@ private:
     /*
      * parseCharacterClass():
      *
-     * Helper for parseTokens(); calls directly and indirectly (via parseCharacterClassEscape)
+     * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape)
      * to an instance of CharacterClassParserDelegate, to describe the character class to the
      * delegate.
      */
     void parseCharacterClass()
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(peek() == '[');
+        ASSERT(!m_err);
+        ASSERT(peek() == '[');
         consume();
 
         CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err);
@@ -428,7 +444,7 @@ private:
                 break;
 
             default:
-                characterClassConstructor.atomPatternCharacterUnescaped(consume());
+                characterClassConstructor.atomPatternCharacter(consume(), true);
             }
 
             if (m_err)
@@ -445,8 +461,8 @@ private:
      */
     void parseParenthesesBegin()
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(peek() == '(');
+        ASSERT(!m_err);
+        ASSERT(peek() == '(');
         consume();
 
         if (tryConsume('?')) {
@@ -484,8 +500,8 @@ private:
      */
     void parseParenthesesEnd()
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(peek() == ')');
+        ASSERT(!m_err);
+        ASSERT(peek() == ')');
         consume();
 
         if (m_parenthesesNestingDepth > 0)
@@ -503,8 +519,8 @@ private:
      */
     void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max)
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(min <= max);
+        ASSERT(!m_err);
+        ASSERT(min <= max);
 
         if (lastTokenWasAnAtom)
             m_delegate.quantifyAtom(min, max, !tryConsume('?'));
@@ -572,13 +588,13 @@ private:
 
             case '*':
                 consume();
-                parseQuantifier(lastTokenWasAnAtom, 0, UINT_MAX);
+                parseQuantifier(lastTokenWasAnAtom, 0, quantifyInfinite);
                 lastTokenWasAnAtom = false;
                 break;
 
             case '+':
                 consume();
-                parseQuantifier(lastTokenWasAnAtom, 1, UINT_MAX);
+                parseQuantifier(lastTokenWasAnAtom, 1, quantifyInfinite);
                 lastTokenWasAnAtom = false;
                 break;
 
@@ -603,7 +619,7 @@ private:
                             if (!consumeNumber(max))
                                 break;
                         } else {
-                            max = UINT_MAX;
+                            max = quantifyInfinite;
                         }
                     }
 
@@ -636,26 +652,18 @@ private:
     /*
      * parse():
      *
-     * This method calls regexBegin(), calls parseTokens() to parse over the input
-     * patterns, calls regexEnd() or regexError() as appropriate, and converts any
+     * This method calls parseTokens() to parse over the input and converts any
      * error code to a const char* for a result.
      */
-    int parse()
+    ErrorCode parse()
     {
-        m_delegate.regexBegin();
-
         if (m_size > MAX_PATTERN_SIZE)
             m_err = PatternTooLarge;
         else
             parseTokens();
-        JS_ASSERT(atEndOfPattern() || m_err);
+        ASSERT(atEndOfPattern() || m_err);
 
-        if (m_err)
-            m_delegate.regexError();
-        else
-            m_delegate.regexEnd();
-
-        return static_cast(m_err);
+        return m_err;
     }
 
 
@@ -675,13 +683,13 @@ private:
 
     bool atEndOfPattern()
     {
-        JS_ASSERT(m_index <= m_size);
+        ASSERT(m_index <= m_size);
         return m_index == m_size;
     }
 
     int peek()
     {
-        JS_ASSERT(m_index < m_size);
+        ASSERT(m_index < m_size);
         return m_data[m_index];
     }
 
@@ -692,40 +700,40 @@ private:
 
     unsigned peekDigit()
     {
-        JS_ASSERT(peekIsDigit());
+        ASSERT(peekIsDigit());
         return peek() - '0';
     }
 
     int consume()
     {
-        JS_ASSERT(m_index < m_size);
+        ASSERT(m_index < m_size);
         return m_data[m_index++];
     }
 
     unsigned consumeDigit()
     {
-        JS_ASSERT(peekIsDigit());
+        ASSERT(peekIsDigit());
         return consume() - '0';
     }
 
-    bool consumeNumber(unsigned &accum)
-    {
-        accum = consumeDigit();
-        while (peekIsDigit()) {
-            unsigned newValue = accum * 10 + peekDigit();
-            if (newValue < accum) { /* Overflow check. */
-                m_err = QuantifierTooLarge;
-                return false;
-            }
-            accum = newValue;
-            consume();
-        }
-        return true;
+    bool consumeNumber(unsigned &accum)
+    {
+        accum = consumeDigit();
+        while (peekIsDigit()) {
+            unsigned newValue = accum * 10 + peekDigit();
+            if (newValue < accum) { /* Overflow check. */
+                m_err = QuantifierTooLarge;
+                return false;
+            }
+            accum = newValue;
+            consume();
+        }
+        return true;
     }
 
     unsigned consumeOctal()
     {
-        JS_ASSERT(WTF::isASCIIOctalDigit(peek()));
+        ASSERT(WTF::isASCIIOctalDigit(peek()));
 
         unsigned n = consumeDigit();
         while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek()))
@@ -798,14 +806,6 @@ private:
  *
  *    void disjunction();
  *
- *    void regexBegin();
- *    void regexEnd();
- *    void regexError();
- *
- * Before any call recording tokens are made, regexBegin() will be called on the
- * delegate once.  Once parsing is complete either regexEnd() or regexError() will
- * be called, as appropriate.
- *
  * The regular expression is described by a sequence of assertion*() and atom*()
  * callbacks to the delegate, describing the terms in the regular expression.
  * Following an atom a quantifyAtom() call may occur to indicate that the previous
@@ -836,11 +836,11 @@ private:
  */
 
 template
-int parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = UINT_MAX)
+ErrorCode parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = quantifyInfinite)
 {
     return Parser(delegate, pattern, backReferenceLimit).parse();
 }
 
 } } // namespace JSC::Yarr
 
-#endif // RegexParser_h
+#endif // YarrParser_h
diff --git a/js/src/yarr/yarr/RegexCompiler.cpp b/js/src/yarr/YarrPattern.cpp
similarity index 52%
rename from js/src/yarr/yarr/RegexCompiler.cpp
rename to js/src/yarr/YarrPattern.cpp
index 9b60cbd4a78b..10b7d8911987 100644
--- a/js/src/yarr/yarr/RegexCompiler.cpp
+++ b/js/src/yarr/YarrPattern.cpp
@@ -1,5 +1,9 @@
-/*
+/* -*- 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
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -21,12 +25,13 @@
  * 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 ***** */
 
-#include "jsinttypes.h"
-#include "RegexCompiler.h"
+#include "YarrPattern.h"
 
-#include "RegexPattern.h"
+#include "Yarr.h"
+#include "YarrParser.h"
 
 using namespace WTF;
 
@@ -34,12 +39,6 @@ namespace JSC { namespace Yarr {
 
 #include "RegExpJitTables.h"
 
-#if WTF_CPU_SPARC
-#define BASE_FRAME_SIZE 24
-#else
-#define BASE_FRAME_SIZE 0
-#endif
-
 class CharacterClassConstructor {
 public:
     CharacterClassConstructor(bool isCaseInsensitive = false)
@@ -57,13 +56,13 @@ public:
 
     void append(const CharacterClass* other)
     {
-        for (size_t i = 0; i < other->m_matches.length(); ++i)
+        for (size_t i = 0; i < other->m_matches.size(); ++i)
             addSorted(m_matches, other->m_matches[i]);
-        for (size_t i = 0; i < other->m_ranges.length(); ++i)
+        for (size_t i = 0; i < other->m_ranges.size(); ++i)
             addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end);
-        for (size_t i = 0; i < other->m_matchesUnicode.length(); ++i)
+        for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i)
             addSorted(m_matchesUnicode, other->m_matchesUnicode[i]);
-        for (size_t i = 0; i < other->m_rangesUnicode.length(); ++i)
+        for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i)
             addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end);
     }
 
@@ -101,18 +100,18 @@ public:
     {
         if (lo <= 0x7f) {
             char asciiLo = lo;
-            char asciiHi = JS_MIN(hi, (UChar)0x7f);
+            char asciiHi = std::min(hi, (UChar)0x7f);
             addSortedRange(m_ranges, lo, asciiHi);
             
             if (m_isCaseInsensitive) {
                 if ((asciiLo <= 'Z') && (asciiHi >= 'A'))
-                    addSortedRange(m_ranges, JS_MAX(asciiLo, 'A')+('a'-'A'), JS_MIN(asciiHi, 'Z')+('a'-'A'));
+                    addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A'));
                 if ((asciiLo <= 'z') && (asciiHi >= 'a'))
-                    addSortedRange(m_ranges, JS_MAX(asciiLo, 'a')+('A'-'a'), JS_MIN(asciiHi, 'z')+('A'-'a'));
+                    addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a'));
             }
         }
         if (hi >= 0x80) {
-            uint32 unicodeCurr = JS_MAX(lo, (UChar)0x80);
+            uint32_t unicodeCurr = std::max(lo, (UChar)0x80);
             addSortedRange(m_rangesUnicode, unicodeCurr, hi);
             
             if (m_isCaseInsensitive) {
@@ -122,7 +121,7 @@ public:
                     // (if so we won't re-enter the loop, since the loop condition above
                     // will definitely fail) - but this does mean we cannot use a UChar
                     // to represent unicodeCurr, we must use a 32-bit value instead.
-                    JS_ASSERT(unicodeCurr <= 0xffff);
+                    ASSERT(unicodeCurr <= 0xffff);
 
                     if (isUnicodeUpper(unicodeCurr)) {
                         UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr);
@@ -145,8 +144,7 @@ public:
 
     CharacterClass* charClass()
     {
-        // FIXME: bug 574459 -- no NULL check
-        CharacterClass* characterClass = js::OffTheBooks::new_((CharacterClassTable*)NULL);
+        CharacterClass* characterClass = js::OffTheBooks::new_(PassRefPtr(0));
 
         characterClass->m_matches.append(m_matches);
         characterClass->m_ranges.append(m_ranges);
@@ -159,12 +157,10 @@ public:
     }
 
 private:
-    typedef js::Vector UChars;
-    typedef js::Vector CharacterRanges;
-    void addSorted(UChars& matches, UChar ch)
+    void addSorted(Vector& matches, UChar ch)
     {
         unsigned pos = 0;
-        unsigned range = matches.length();
+        unsigned range = matches.size();
 
         // binary chop, find position to insert char.
         while (range) {
@@ -181,15 +177,15 @@ private:
             }
         }
         
-        if (pos == matches.length())
+        if (pos == matches.size())
             matches.append(ch);
         else
-            matches.insert(matches.begin() + pos, ch);
+            matches.insert(pos, ch);
     }
 
-    void addSortedRange(CharacterRanges& ranges, UChar lo, UChar hi)
+    void addSortedRange(Vector& ranges, UChar lo, UChar hi)
     {
-        unsigned end = ranges.length();
+        unsigned end = ranges.size();
         
         // Simple linear scan - I doubt there are that many ranges anyway...
         // feel free to fix this with something faster (eg binary chop).
@@ -201,7 +197,7 @@ private:
                     ranges[i].begin = lo;
                     return;
                 }
-                ranges.insert(ranges.begin() + i, CharacterRange(lo, hi));
+                ranges.insert(i, CharacterRange(lo, hi));
                 return;
             }
             // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining
@@ -209,17 +205,17 @@ private:
             // end of the last range they concatenate, which is just as good.
             if (lo <= (ranges[i].end + 1)) {
                 // found an intersect! we'll replace this entry in the array.
-                ranges[i].begin = JS_MIN(ranges[i].begin, lo);
-                ranges[i].end = JS_MAX(ranges[i].end, hi);
+                ranges[i].begin = std::min(ranges[i].begin, lo);
+                ranges[i].end = std::max(ranges[i].end, hi);
 
                 // now check if the new range can subsume any subsequent ranges.
                 unsigned next = i+1;
                 // each iteration of the loop we will either remove something from the list, or break the loop.
-                while (next < ranges.length()) {
+                while (next < ranges.size()) {
                     if (ranges[next].begin <= (ranges[i].end + 1)) {
                         // the next entry now overlaps / concatenates this one.
-                        ranges[i].end = JS_MAX(ranges[i].end, ranges[next].end);
-                        ranges.erase(ranges.begin() + next);
+                        ranges[i].end = std::max(ranges[i].end, ranges[next].end);
+                        ranges.remove(next);
                     } else
                         break;
                 }
@@ -234,21 +230,131 @@ private:
 
     bool m_isCaseInsensitive;
 
-    UChars m_matches;
-    CharacterRanges m_ranges;
-    UChars m_matchesUnicode;
-    CharacterRanges m_rangesUnicode;
+    Vector m_matches;
+    Vector m_ranges;
+    Vector m_matchesUnicode;
+    Vector m_rangesUnicode;
 };
 
-class RegexPatternConstructor {
-public:
-    RegexPatternConstructor(RegexPattern& pattern)
-        : m_pattern(pattern)
-        , m_characterClassConstructor(pattern.m_ignoreCase)
+struct BeginCharHelper {
+    BeginCharHelper(Vector* beginChars, bool isCaseInsensitive = false)
+        : m_beginChars(beginChars)
+        , m_isCaseInsensitive(isCaseInsensitive)
+    {}
+
+    void addBeginChar(BeginChar beginChar, Vector* hotTerms, QuantifierType quantityType, unsigned quantityCount)
     {
+        if (quantityType == QuantifierFixedCount && quantityCount > 1) {
+            // We duplicate the first found character if the quantity of the term is more than one. eg.: /a{3}/
+            beginChar.value |= beginChar.value << 16;
+            beginChar.mask |= beginChar.mask << 16;
+            addCharacter(beginChar);
+        } else if (quantityType == QuantifierFixedCount && quantityCount == 1 && hotTerms->size())
+            // In case of characters with fixed quantifier we should check the next character as well.
+            linkHotTerms(beginChar, hotTerms);
+        else
+            // In case of greedy matching the next character checking is unnecessary therefore we just store
+            // the first character.
+            addCharacter(beginChar);
     }
 
-    ~RegexPatternConstructor()
+    // Merge two following BeginChars in the vector to reduce the number of character checks.
+    void merge(unsigned size)
+    {
+        for (unsigned i = 0; i < size; i++) {
+            BeginChar* curr = &m_beginChars->at(i);
+            BeginChar* next = &m_beginChars->at(i + 1);
+
+            // If the current and the next size of value is different we should skip the merge process
+            // because the 16bit and 32bit values are unmergable.
+            if (curr->value <= 0xFFFF && next->value > 0xFFFF)
+                continue;
+
+            unsigned diff = curr->value ^ next->value;
+
+            curr->mask |= diff;
+            curr->value |= curr->mask;
+
+            m_beginChars->remove(i + 1);
+            size--;
+        }
+    }
+
+private:
+    void addCharacter(BeginChar beginChar)
+    {
+        unsigned pos = 0;
+        unsigned range = m_beginChars->size();
+
+        // binary chop, find position to insert char.
+        while (range) {
+            unsigned index = range >> 1;
+
+            int val = m_beginChars->at(pos+index).value - beginChar.value;
+            if (!val)
+                return;
+            if (val < 0)
+                range = index;
+            else {
+                pos += (index+1);
+                range -= (index+1);
+            }
+        }
+
+        if (pos == m_beginChars->size())
+            m_beginChars->append(beginChar);
+        else
+            m_beginChars->insert(pos, beginChar);
+    }
+
+    // Create BeginChar objects by appending each terms from a hotTerms vector to an existing BeginChar object.
+    void linkHotTerms(BeginChar beginChar, Vector* hotTerms)
+    {
+        for (unsigned i = 0; i < hotTerms->size(); i++) {
+            PatternTerm hotTerm = hotTerms->at(i).term;
+            ASSERT(hotTerm.type == PatternTerm::TypePatternCharacter);
+
+            UChar characterNext = hotTerm.patternCharacter;
+
+            // Append a character to an existing BeginChar object.
+            if (characterNext <= 0x7f) {
+                unsigned mask = 0;
+
+                if (m_isCaseInsensitive && isASCIIAlpha(characterNext)) {
+                    mask = 32;
+                    characterNext = toASCIILower(characterNext);
+                }
+
+                addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask | (mask << 16)));
+            } else {
+                UChar upper, lower;
+                if (m_isCaseInsensitive && ((upper = Unicode::toUpper(characterNext)) != (lower = Unicode::toLower(characterNext)))) {
+                    addCharacter(BeginChar(beginChar.value | (upper << 16), beginChar.mask));
+                    addCharacter(BeginChar(beginChar.value | (lower << 16), beginChar.mask));
+                } else
+                    addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask));
+            }
+        }
+    }
+
+    Vector* m_beginChars;
+    bool m_isCaseInsensitive;
+};
+
+class YarrPatternConstructor {
+public:
+    YarrPatternConstructor(YarrPattern& pattern)
+        : m_pattern(pattern)
+        , m_characterClassConstructor(pattern.m_ignoreCase)
+        , m_beginCharHelper(&pattern.m_beginChars, pattern.m_ignoreCase)
+        , m_invertParentheticalAssertion(false)
+    {
+        m_pattern.m_body = js::OffTheBooks::new_();
+        m_alternative = m_pattern.m_body->addNewAlternative();
+        m_pattern.m_disjunctions.append(m_pattern.m_body);
+    }
+
+    ~YarrPatternConstructor()
     {
     }
 
@@ -256,10 +362,19 @@ public:
     {
         m_pattern.reset();
         m_characterClassConstructor.reset();
+
+        m_pattern.m_body = js::OffTheBooks::new_();
+        m_alternative = m_pattern.m_body->addNewAlternative();
+        m_pattern.m_disjunctions.append(m_pattern.m_body);
     }
     
     void assertionBOL()
     {
+        if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) {
+            m_alternative->m_startsWithBOL = true;
+            m_alternative->m_containsBOL = true;
+            m_pattern.m_containsBOL = true;
+        }
         m_alternative->m_terms.append(PatternTerm::BOL());
     }
     void assertionEOL()
@@ -318,7 +433,7 @@ public:
 
     void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert)
     {
-        JS_ASSERT(classID != NewlineClassID);
+        ASSERT(classID != NewlineClassID);
 
         switch (classID) {
         case DigitClassID:
@@ -334,7 +449,7 @@ public:
             break;
         
         default:
-            JS_NOT_REACHED("Invalid character class.");
+            ASSERT_NOT_REACHED();
         }
     }
 
@@ -351,36 +466,56 @@ public:
         if (capture)
             m_pattern.m_numSubpatterns++;
 
-        // FIXME: bug 574459 -- no NULL check
         PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative);
         m_pattern.m_disjunctions.append(parenthesesDisjunction);
-        m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture));
+        m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, false));
         m_alternative = parenthesesDisjunction->addNewAlternative();
     }
 
     void atomParentheticalAssertionBegin(bool invert = false)
     {
-        // FIXME: bug 574459 -- no NULL check
         PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative);
         m_pattern.m_disjunctions.append(parenthesesDisjunction);
-        m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert));
+        m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, false, invert));
         m_alternative = parenthesesDisjunction->addNewAlternative();
+        m_invertParentheticalAssertion = invert;
     }
 
     void atomParenthesesEnd()
     {
-        JS_ASSERT(m_alternative->m_parent);
-        JS_ASSERT(m_alternative->m_parent->m_parent);
+        ASSERT(m_alternative->m_parent);
+        ASSERT(m_alternative->m_parent->m_parent);
+
+        PatternDisjunction* parenthesesDisjunction = m_alternative->m_parent;
         m_alternative = m_alternative->m_parent->m_parent;
-        
-        m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
+
+        PatternTerm& lastTerm = m_alternative->lastTerm();
+
+        unsigned numParenAlternatives = parenthesesDisjunction->m_alternatives.size();
+        unsigned numBOLAnchoredAlts = 0;
+
+        for (unsigned i = 0; i < numParenAlternatives; i++) {
+            // Bubble up BOL flags
+            if (parenthesesDisjunction->m_alternatives[i]->m_startsWithBOL)
+                numBOLAnchoredAlts++;
+        }
+
+        if (numBOLAnchoredAlts) {
+            m_alternative->m_containsBOL = true;
+            // If all the alternatives in parens start with BOL, then so does this one
+            if (numBOLAnchoredAlts == numParenAlternatives)
+                m_alternative->m_startsWithBOL = true;
+        }
+
+        lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
+        m_invertParentheticalAssertion = false;
     }
 
     void atomBackReference(unsigned subpatternId)
     {
-        JS_ASSERT(subpatternId);
+        ASSERT(subpatternId);
         m_pattern.m_containsBackreferences = true;
-        m_pattern.m_maxBackReference = JS_MAX(m_pattern.m_maxBackReference, subpatternId);
+        m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId);
 
         if (subpatternId > m_pattern.m_numSubpatterns) {
             m_alternative->m_terms.append(PatternTerm::ForwardReference());
@@ -388,14 +523,14 @@ public:
         }
 
         PatternAlternative* currentAlternative = m_alternative;
-        JS_ASSERT(currentAlternative);
+        ASSERT(currentAlternative);
 
         // Note to self: if we waited until the AST was baked, we could also remove forwards refs 
         while ((currentAlternative = currentAlternative->m_parent->m_parent)) {
             PatternTerm& term = currentAlternative->lastTerm();
-            JS_ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion));
+            ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion));
 
-            if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) {
+            if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.capture() && (subpatternId == term.parentheses.subpatternId)) {
                 m_alternative->m_terms.append(PatternTerm::ForwardReference());
                 return;
             }
@@ -404,37 +539,43 @@ public:
         m_alternative->m_terms.append(PatternTerm(subpatternId));
     }
 
-    PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction)
+    // deep copy the argument disjunction.  If filterStartsWithBOL is true, 
+    // skip alternatives with m_startsWithBOL set true.
+    PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false)
     {
-        // FIXME: bug 574459 -- no NULL check
-        PatternDisjunction* newDisjunction = js::OffTheBooks::new_();
-
-        newDisjunction->m_parent = disjunction->m_parent;
-        for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) {
+        PatternDisjunction* newDisjunction = 0;
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
             PatternAlternative* alternative = disjunction->m_alternatives[alt];
-            PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
-            for (unsigned i = 0; i < alternative->m_terms.length(); ++i)
-                newAlternative->m_terms.append(copyTerm(alternative->m_terms[i]));
+            if (!filterStartsWithBOL || !alternative->m_startsWithBOL) {
+                if (!newDisjunction) {
+                    newDisjunction = new PatternDisjunction();
+                    newDisjunction->m_parent = disjunction->m_parent;
+                }
+                PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
+                for (unsigned i = 0; i < alternative->m_terms.size(); ++i)
+                    newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL));
+            }
         }
-
-        m_pattern.m_disjunctions.append(newDisjunction);
+        
+        if (newDisjunction)
+            m_pattern.m_disjunctions.append(newDisjunction);
         return newDisjunction;
     }
-
-    PatternTerm copyTerm(PatternTerm& term)
+    
+    PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false)
     {
         if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion))
             return PatternTerm(term);
-
+        
         PatternTerm termCopy = term;
-        termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction);
+        termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL);
         return termCopy;
     }
-
+    
     void quantifyAtom(unsigned min, unsigned max, bool greedy)
     {
-        JS_ASSERT(min <= max);
-        JS_ASSERT(m_alternative->m_terms.length());
+        ASSERT(min <= max);
+        ASSERT(m_alternative->m_terms.size());
 
         if (!max) {
             m_alternative->removeLastTerm();
@@ -442,8 +583,8 @@ public:
         }
 
         PatternTerm& term = m_alternative->lastTerm();
-        JS_ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary);
-        JS_ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount));
+        ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary);
+        ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount));
 
         // For any assertion with a zero minimum, not matching is valid and has no effect,
         // remove it.  Otherwise, we need to match as least once, but there is no point
@@ -464,7 +605,7 @@ public:
             term.quantify(min, QuantifierFixedCount);
             m_alternative->m_terms.append(copyTerm(term));
             // NOTE: this term is interesting from an analysis perspective, in that it can be ignored.....
-            m_alternative->lastTerm().quantify((max == UINT_MAX) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy);
+            m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy);
             if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern)
                 m_alternative->lastTerm().parentheses.isCopy = true;
         }
@@ -475,26 +616,12 @@ public:
         m_alternative = m_alternative->m_parent->addNewAlternative();
     }
 
-    void regexBegin()
-    {
-        // FIXME: bug 574459 -- no NULL check
-        m_pattern.m_body = js::OffTheBooks::new_();
-        m_alternative = m_pattern.m_body->addNewAlternative();
-        m_pattern.m_disjunctions.append(m_pattern.m_body);
-    }
-    void regexEnd()
-    {
-    }
-    void regexError()
-    {
-    }
-
     unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition)
     {
         alternative->m_hasFixedSize = true;
         unsigned currentInputPosition = initialInputPosition;
 
-        for (unsigned i = 0; i < alternative->m_terms.length(); ++i) {
+        for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
             PatternTerm& term = alternative->m_terms[i];
 
             switch (term.type) {
@@ -507,7 +634,7 @@ public:
             case PatternTerm::TypeBackReference:
                 term.inputPosition = currentInputPosition;
                 term.frameLocation = currentCallFrameSize;
-                currentCallFrameSize += RegexStackSpaceForBackTrackInfoBackReference;
+                currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference;
                 alternative->m_hasFixedSize = false;
                 break;
 
@@ -518,7 +645,7 @@ public:
                 term.inputPosition = currentInputPosition;
                 if (term.quantityType != QuantifierFixedCount) {
                     term.frameLocation = currentCallFrameSize;
-                    currentCallFrameSize += RegexStackSpaceForBackTrackInfoPatternCharacter;
+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter;
                     alternative->m_hasFixedSize = false;
                 } else
                     currentInputPosition += term.quantityCount;
@@ -528,7 +655,7 @@ public:
                 term.inputPosition = currentInputPosition;
                 if (term.quantityType != QuantifierFixedCount) {
                     term.frameLocation = currentCallFrameSize;
-                    currentCallFrameSize += RegexStackSpaceForBackTrackInfoCharacterClass;
+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass;
                     alternative->m_hasFixedSize = false;
                 } else
                     currentInputPosition += term.quantityCount;
@@ -539,20 +666,20 @@ public:
                 term.frameLocation = currentCallFrameSize;
                 if (term.quantityCount == 1 && !term.parentheses.isCopy) {
                     if (term.quantityType != QuantifierFixedCount)
-                        currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesOnce;
+                        currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce;
                     currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
                     // If quantity is fixed, then pre-check its minimum size.
                     if (term.quantityType == QuantifierFixedCount)
                         currentInputPosition += term.parentheses.disjunction->m_minimumSize;
                     term.inputPosition = currentInputPosition;
                 } else if (term.parentheses.isTerminal) {
-                    currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesTerminal;
+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal;
                     currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
                     term.inputPosition = currentInputPosition;
                 } else {
                     term.inputPosition = currentInputPosition;
                     setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition);
-                    currentCallFrameSize += RegexStackSpaceForBackTrackInfoParentheses;
+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses;
                 }
                 // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length.
                 alternative->m_hasFixedSize = false;
@@ -561,7 +688,7 @@ public:
             case PatternTerm::TypeParentheticalAssertion:
                 term.inputPosition = currentInputPosition;
                 term.frameLocation = currentCallFrameSize;
-                currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + RegexStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition);
+                currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition);
                 break;
             }
         }
@@ -572,23 +699,23 @@ public:
 
     unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition)
     {
-        if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.length() > 1))
-            initialCallFrameSize += RegexStackSpaceForBackTrackInfoAlternative;
+        if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1))
+            initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative;
 
         unsigned minimumInputSize = UINT_MAX;
         unsigned maximumCallFrameSize = 0;
         bool hasFixedSize = true;
 
-        for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) {
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
             PatternAlternative* alternative = disjunction->m_alternatives[alt];
             unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition);
-            minimumInputSize = JS_MIN(minimumInputSize, alternative->m_minimumSize);
-            maximumCallFrameSize = JS_MAX(maximumCallFrameSize, currentAlternativeCallFrameSize);
+            minimumInputSize = std::min(minimumInputSize, alternative->m_minimumSize);
+            maximumCallFrameSize = std::max(maximumCallFrameSize, currentAlternativeCallFrameSize);
             hasFixedSize &= alternative->m_hasFixedSize;
         }
         
-        JS_ASSERT(minimumInputSize != UINT_MAX);
-        JS_ASSERT(maximumCallFrameSize >= initialCallFrameSize);
+        ASSERT(minimumInputSize != UINT_MAX);
+        ASSERT(maximumCallFrameSize >= initialCallFrameSize);
 
         disjunction->m_hasFixedSize = hasFixedSize;
         disjunction->m_minimumSize = minimumInputSize;
@@ -598,13 +725,14 @@ public:
 
     void setupOffsets()
     {
-        setupDisjunctionOffsets(m_pattern.m_body, BASE_FRAME_SIZE, 0);
+        setupDisjunctionOffsets(m_pattern.m_body, 0, 0);
     }
 
     // This optimization identifies sets of parentheses that we will never need to backtrack.
     // In these cases we do not need to store state from prior iterations.
     // We can presently avoid backtracking for:
-    //   * a set of parens at the end of the regular expression (last term in any of the alternatives of the main body disjunction).
+    //   * where the parens are at the end of the regular expression (last term in any of the
+    //     alternatives of the main body disjunction).
     //   * where the parens are non-capturing, and quantified unbounded greedy (*).
     //   * where the parens do not contain any capturing subpatterns.
     void checkForTerminalParentheses()
@@ -614,57 +742,239 @@ public:
         if (m_pattern.m_numSubpatterns)
             return;
 
-        js::Vector& alternatives = m_pattern.m_body->m_alternatives;
-        for (unsigned i =0; i < alternatives.length(); ++i) {
-            js::Vector& terms = alternatives[i]->m_terms;
-            if (terms.length()) {
-                PatternTerm& term = terms.back();
+        Vector& alternatives = m_pattern.m_body->m_alternatives;
+        for (size_t i = 0; i < alternatives.size(); ++i) {
+            Vector& terms = alternatives[i]->m_terms;
+            if (terms.size()) {
+                PatternTerm& term = terms.last();
                 if (term.type == PatternTerm::TypeParenthesesSubpattern
                     && term.quantityType == QuantifierGreedy
-                    && term.quantityCount == UINT_MAX
+                    && term.quantityCount == quantifyInfinite
                     && !term.capture())
                     term.parentheses.isTerminal = true;
             }
         }
     }
 
+    void optimizeBOL()
+    {
+        // Look for expressions containing beginning of line (^) anchoring and unroll them.
+        // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops
+        // This code relies on the parsing code tagging alternatives with m_containsBOL and
+        // m_startsWithBOL and rolling those up to containing alternatives.
+        // At this point, this is only valid for non-multiline expressions.
+        PatternDisjunction* disjunction = m_pattern.m_body;
+        
+        if (!m_pattern.m_containsBOL || m_pattern.m_multiline)
+            return;
+        
+        PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true);
+
+        // Set alternatives in disjunction to "onceThrough"
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt)
+            disjunction->m_alternatives[alt]->setOnceThrough();
+
+        if (loopDisjunction) {
+            // Move alternatives from loopDisjunction to disjunction
+            for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt)
+                disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]);
+                
+            loopDisjunction->m_alternatives.clear();
+        }
+    }
+
+    // This function collects the terms which are potentially matching the first number of depth characters in the result.
+    // If this function returns false then it found at least one term which makes the beginning character
+    // look-up optimization inefficient.
+    bool setupDisjunctionBeginTerms(PatternDisjunction* disjunction, Vector* beginTerms, unsigned depth)
+    {
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
+            PatternAlternative* alternative = disjunction->m_alternatives[alt];
+
+            if (!setupAlternativeBeginTerms(alternative, beginTerms, 0, depth))
+                return false;
+        }
+
+        return true;
+    }
+
+    bool setupAlternativeBeginTerms(PatternAlternative* alternative, Vector* beginTerms, unsigned termIndex, unsigned depth)
+    {
+        bool checkNext = true;
+        unsigned numTerms = alternative->m_terms.size();
+
+        while (checkNext && termIndex < numTerms) {
+            PatternTerm term = alternative->m_terms[termIndex];
+            checkNext = false;
+
+            switch (term.type) {
+            case PatternTerm::TypeAssertionBOL:
+            case PatternTerm::TypeAssertionEOL:
+            case PatternTerm::TypeAssertionWordBoundary:
+                return false;
+
+            case PatternTerm::TypeBackReference:
+            case PatternTerm::TypeForwardReference:
+                return false;
+
+            case PatternTerm::TypePatternCharacter:
+                if (termIndex != numTerms - 1) {
+                    beginTerms->append(TermChain(term));
+                    termIndex++;
+                    checkNext = true;
+                } else if (term.quantityType == QuantifierFixedCount) {
+                    beginTerms->append(TermChain(term));
+                    if (depth < 2 && termIndex < numTerms - 1 && term.quantityCount == 1)
+                        if (!setupAlternativeBeginTerms(alternative, &beginTerms->last().hotTerms, termIndex + 1, depth + 1))
+                            return false;
+                }
+
+                break;
+
+            case PatternTerm::TypeCharacterClass:
+                return false;
+
+            case PatternTerm::TypeParentheticalAssertion:
+                if (term.invert())
+                    return false;
+
+            case PatternTerm::TypeParenthesesSubpattern:
+                if (term.quantityType != QuantifierFixedCount) {
+                    if (termIndex == numTerms - 1)
+                        break;
+
+                    termIndex++;
+                    checkNext = true;
+                }
+
+                if (!setupDisjunctionBeginTerms(term.parentheses.disjunction, beginTerms, depth))
+                    return false;
+
+                break;
+            }
+        }
+
+        return true;
+    }
+
+    void setupBeginChars()
+    {
+        Vector beginTerms;
+        bool containsFixedCharacter = false;
+
+        if ((!m_pattern.m_body->m_hasFixedSize || m_pattern.m_body->m_alternatives.size() > 1)
+                && setupDisjunctionBeginTerms(m_pattern.m_body, &beginTerms, 0)) {
+            unsigned size = beginTerms.size();
+
+            // If we haven't collected any terms we should abort the preparation of beginning character look-up optimization.
+            if (!size)
+                return;
+
+            m_pattern.m_containsBeginChars = true;
+
+            for (unsigned i = 0; i < size; i++) {
+                PatternTerm term = beginTerms[i].term;
+
+                // We have just collected PatternCharacter terms, other terms are not allowed.
+                ASSERT(term.type == PatternTerm::TypePatternCharacter);
+
+                if (term.quantityType == QuantifierFixedCount)
+                    containsFixedCharacter = true;
+
+                UChar character = term.patternCharacter;
+                unsigned mask = 0;
+
+                if (character <= 0x7f) {
+                    if (m_pattern.m_ignoreCase && isASCIIAlpha(character)) {
+                        mask = 32;
+                        character = toASCIILower(character);
+                    }
+
+                    m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount);
+                } else {
+                    UChar upper, lower;
+                    if (m_pattern.m_ignoreCase && ((upper = Unicode::toUpper(character)) != (lower = Unicode::toLower(character)))) {
+                        m_beginCharHelper.addBeginChar(BeginChar(upper, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount);
+                        m_beginCharHelper.addBeginChar(BeginChar(lower, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount);
+                    } else
+                        m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount);
+                }
+            }
+
+            // If the pattern doesn't contain terms with fixed quantifiers then the beginning character look-up optimization is inefficient.
+            if (!containsFixedCharacter) {
+                m_pattern.m_containsBeginChars = false;
+                return;
+            }
+
+            size = m_pattern.m_beginChars.size();
+
+            if (size > 2)
+                m_beginCharHelper.merge(size - 1);
+            else if (size <= 1)
+                m_pattern.m_containsBeginChars = false;
+        }
+    }
+
 private:
-    RegexPattern& m_pattern;
+    YarrPattern& m_pattern;
     PatternAlternative* m_alternative;
     CharacterClassConstructor m_characterClassConstructor;
+    BeginCharHelper m_beginCharHelper;
     bool m_invertCharacterClass;
+    bool m_invertParentheticalAssertion;
 };
 
-
-int compileRegex(const UString& patternString, RegexPattern& pattern)
+ErrorCode YarrPattern::compile(const UString& patternString)
 {
-    RegexPatternConstructor constructor(pattern);
+    YarrPatternConstructor constructor(*this);
 
-    if (int error = parse(constructor, patternString))
+    if (ErrorCode error = parse(constructor, patternString))
         return error;
     
     // If the pattern contains illegal backreferences reset & reparse.
     // Quoting Netscape's "What's new in JavaScript 1.2",
     //      "Note: if the number of left parentheses is less than the number specified
     //       in \#, the \# is taken as an octal escape as described in the next row."
-    if (pattern.containsIllegalBackReference()) {
-        unsigned numSubpatterns = pattern.m_numSubpatterns;
+    if (containsIllegalBackReference()) {
+        unsigned numSubpatterns = m_numSubpatterns;
 
         constructor.reset();
-#ifdef DEBUG
-        int error =
+#if !ASSERT_DISABLED
+        ErrorCode error =
 #endif
             parse(constructor, patternString, numSubpatterns);
 
-        JS_ASSERT(!error);
-        JS_ASSERT(numSubpatterns == pattern.m_numSubpatterns);
+        ASSERT(!error);
+        ASSERT(numSubpatterns == m_numSubpatterns);
     }
 
     constructor.checkForTerminalParentheses();
+    constructor.optimizeBOL();
+        
     constructor.setupOffsets();
+    constructor.setupBeginChars();
 
-    return 0;
+    return NoError;
 }
 
+YarrPattern::YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error)
+    : m_ignoreCase(ignoreCase)
+    , m_multiline(multiline)
+    , m_containsBackreferences(false)
+    , m_containsBeginChars(false)
+    , m_containsBOL(false)
+    , m_numSubpatterns(0)
+    , m_maxBackReference(0)
+    , newlineCached(0)
+    , digitsCached(0)
+    , spacesCached(0)
+    , wordcharCached(0)
+    , nondigitsCached(0)
+    , nonspacesCached(0)
+    , nonwordcharCached(0)
+{
+    *error = compile(pattern);
+}
 
 } }
diff --git a/js/src/yarr/yarr/RegexPattern.h b/js/src/yarr/YarrPattern.h
similarity index 70%
rename from js/src/yarr/yarr/RegexPattern.h
rename to js/src/yarr/YarrPattern.h
index 9d9b286a653e..38ae10fcf289 100644
--- a/js/src/yarr/yarr/RegexPattern.h
+++ b/js/src/yarr/YarrPattern.h
@@ -1,5 +1,9 @@
-/*
+/* -*- 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
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -21,26 +25,32 @@
  * 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 RegexPattern_h
-#define RegexPattern_h
-
-#include "jsvector.h"
-#include "yarr/jswtfbridge.h"
-#include "yarr/yarr/RegexCommon.h"
+#ifndef YarrPattern_h
+#define YarrPattern_h
 
+#include "wtfbridge.h"
+#include "ASCIICType.h"
 
 namespace JSC { namespace Yarr {
 
-#define RegexStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoBackReference 2
-#define RegexStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
-#define RegexStackSpaceForBackTrackInfoParentheticalAssertion 1
-#define RegexStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoParenthesesTerminal 1
-#define RegexStackSpaceForBackTrackInfoParentheses 4
+enum ErrorCode {
+    NoError,
+    PatternTooLarge,
+    QuantifierOutOfOrder,
+    QuantifierWithoutAtom,
+    MissingParentheses,
+    ParenthesesUnmatched,
+    ParenthesesTypeInvalid,
+    CharacterClassUnmatched,
+    CharacterClassInvalidRange,
+    CharacterClassOutOfOrder,
+    EscapeUnterminated,
+    QuantifierTooLarge,
+    NumberOfErrorCodes
+};
 
 struct PatternDisjunction;
 
@@ -55,60 +65,42 @@ struct CharacterRange {
     }
 };
 
-/*
- * Wraps a table and indicates inversion. Can be efficiently borrowed
- * between character classes, so it's refcounted.
- */
-struct CharacterClassTable {
-
-    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
-
+struct CharacterClassTable : RefCounted {
+    friend class js::OffTheBooks;
     const char* m_table;
     bool m_inverted;
-    jsrefcount m_refcount;
-
-    /* Ownership transferred to caller. */
-    static CharacterClassTable *create(const char* table, bool inverted)
+    static PassRefPtr create(const char* table, bool inverted)
     {
-        // FIXME: bug 574459 -- no NULL checks done by any of the callers, all
-        // of which are in RegExpJitTables.h.
-        return js::OffTheBooks::new_(table, inverted);
+        return adoptRef(js::OffTheBooks::new_(table, inverted));
     }
 
-    void incref() { JS_ATOMIC_INCREMENT(&m_refcount); }
-    void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js::Foreground::delete_(this); }
-
 private:
     CharacterClassTable(const char* table, bool inverted)
         : m_table(table)
         , m_inverted(inverted)
-        , m_refcount(0)
     {
     }
 };
 
 struct CharacterClass {
+    WTF_MAKE_FAST_ALLOCATED
+public:
     // All CharacterClass instances have to have the full set of matches and ranges,
     // they may have an optional table for faster lookups (which must match the
     // specified matches and ranges)
-    CharacterClass(CharacterClassTable *table)
+    CharacterClass(PassRefPtr table)
         : m_table(table)
     {
-        if (m_table)
-            m_table->incref();
     }
     ~CharacterClass()
     {
-        if (m_table)
-            m_table->decref();
+        js::Foreground::delete_(m_table.get());
     }
-    typedef js::Vector UChars;
-    typedef js::Vector CharacterRanges;
-    UChars m_matches;
-    CharacterRanges m_ranges;
-    UChars m_matchesUnicode;
-    CharacterRanges m_rangesUnicode;
-    CharacterClassTable *m_table;
+    Vector m_matches;
+    Vector m_ranges;
+    Vector m_matchesUnicode;
+    Vector m_rangesUnicode;
+    RefPtr m_table;
 };
 
 enum QuantifierType {
@@ -129,11 +121,12 @@ struct PatternTerm {
         TypeParenthesesSubpattern,
         TypeParentheticalAssertion
     } type;
-    bool invertOrCapture;
+    bool m_capture :1;
+    bool m_invert :1;
     union {
         UChar patternCharacter;
         CharacterClass* characterClass;
-        unsigned subpatternId;
+        unsigned backReferenceSubpatternId;
         struct {
             PatternDisjunction* disjunction;
             unsigned subpatternId;
@@ -147,8 +140,21 @@ struct PatternTerm {
     int inputPosition;
     unsigned frameLocation;
 
+    // No-argument constructor for js::Vector.
+    PatternTerm()
+        : type(PatternTerm::TypePatternCharacter)
+        , m_capture(false)
+        , m_invert(false)
+    {
+        patternCharacter = 0;
+        quantityType = QuantifierFixedCount;
+        quantityCount = 1;
+    }
+
     PatternTerm(UChar ch)
         : type(PatternTerm::TypePatternCharacter)
+        , m_capture(false)
+        , m_invert(false)
     {
         patternCharacter = ch;
         quantityType = QuantifierFixedCount;
@@ -157,16 +163,18 @@ struct PatternTerm {
 
     PatternTerm(CharacterClass* charClass, bool invert)
         : type(PatternTerm::TypeCharacterClass)
-        , invertOrCapture(invert)
+        , m_capture(false)
+        , m_invert(invert)
     {
         characterClass = charClass;
         quantityType = QuantifierFixedCount;
         quantityCount = 1;
     }
 
-    PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool invertOrCapture)
+    PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false)
         : type(type)
-        , invertOrCapture(invertOrCapture)
+        , m_capture(capture)
+        , m_invert(invert)
     {
         parentheses.disjunction = disjunction;
         parentheses.subpatternId = subpatternId;
@@ -178,7 +186,8 @@ struct PatternTerm {
     
     PatternTerm(Type type, bool invert = false)
         : type(type)
-        , invertOrCapture(invert)
+        , m_capture(false)
+        , m_invert(invert)
     {
         quantityType = QuantifierFixedCount;
         quantityCount = 1;
@@ -186,9 +195,10 @@ struct PatternTerm {
 
     PatternTerm(unsigned spatternId)
         : type(TypeBackReference)
-        , invertOrCapture(false)
+        , m_capture(false)
+        , m_invert(false)
     {
-        subpatternId = spatternId;
+        backReferenceSubpatternId = spatternId;
         quantityType = QuantifierFixedCount;
         quantityCount = 1;
     }
@@ -215,12 +225,12 @@ struct PatternTerm {
     
     bool invert()
     {
-        return invertOrCapture;
+        return m_invert;
     }
 
     bool capture()
     {
-        return invertOrCapture;
+        return m_capture;
     }
     
     void quantify(unsigned count, QuantifierType type)
@@ -231,9 +241,8 @@ struct PatternTerm {
 };
 
 struct PatternAlternative {
-
-    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
-
+    WTF_MAKE_FAST_ALLOCATED
+public:
     PatternAlternative(PatternDisjunction* disjunction)
         : m_parent(disjunction)
         , m_onceThrough(false)
@@ -245,14 +254,14 @@ struct PatternAlternative {
 
     PatternTerm& lastTerm()
     {
-        JS_ASSERT(m_terms.length());
-        return m_terms[m_terms.length() - 1];
+        ASSERT(m_terms.size());
+        return m_terms[m_terms.size() - 1];
     }
     
     void removeLastTerm()
     {
-        JS_ASSERT(m_terms.length());
-        m_terms.popBack();
+        ASSERT(m_terms.size());
+        m_terms.shrink(m_terms.size() - 1);
     }
     
     void setOnceThrough()
@@ -265,7 +274,7 @@ struct PatternAlternative {
         return m_onceThrough;
     }
 
-    js::Vector m_terms;
+    Vector m_terms;
     PatternDisjunction* m_parent;
     unsigned m_minimumSize;
     bool m_onceThrough : 1;
@@ -274,18 +283,9 @@ struct PatternAlternative {
     bool m_containsBOL : 1;
 };
 
-template
-static inline void
-deleteAllValues(js::Vector &vector)
-{
-    for (T** t = vector.begin(); t < vector.end(); ++t)
-        js::Foreground::delete_(*t);
-}
-
 struct PatternDisjunction {
-
-    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
-
+    WTF_MAKE_FAST_ALLOCATED
+public:
     PatternDisjunction(PatternAlternative* parent = 0)
         : m_parent(parent)
         , m_hasFixedSize(false)
@@ -299,13 +299,12 @@ struct PatternDisjunction {
 
     PatternAlternative* addNewAlternative()
     {
-        // FIXME: bug 574459 -- no NULL check
         PatternAlternative* alternative = js::OffTheBooks::new_(this);
         m_alternatives.append(alternative);
         return alternative;
     }
 
-    js::Vector m_alternatives;
+    Vector m_alternatives;
     PatternAlternative* m_parent;
     unsigned m_minimumSize;
     unsigned m_callFrameSize;
@@ -314,7 +313,7 @@ struct PatternDisjunction {
 
 // You probably don't want to be calling these functions directly
 // (please to be calling newlineCharacterClass() et al on your
-// friendly neighborhood RegexPattern instance to get nicely
+// friendly neighborhood YarrPattern instance to get nicely
 // cached copies).
 CharacterClass* newlineCreate();
 CharacterClass* digitsCreate();
@@ -324,25 +323,34 @@ CharacterClass* nondigitsCreate();
 CharacterClass* nonspacesCreate();
 CharacterClass* nonwordcharCreate();
 
-struct RegexPattern {
-    RegexPattern(bool ignoreCase, bool multiline)
-        : m_ignoreCase(ignoreCase)
-        , m_multiline(multiline)
-        , m_containsBackreferences(false)
-        , m_containsBOL(false)
-        , m_numSubpatterns(0)
-        , m_maxBackReference(0)
-        , newlineCached(0)
-        , digitsCached(0)
-        , spacesCached(0)
-        , wordcharCached(0)
-        , nondigitsCached(0)
-        , nonspacesCached(0)
-        , nonwordcharCached(0)
-    {
-    }
+struct TermChain {
+    TermChain(PatternTerm term)
+        : term(term)
+    {}
 
-    ~RegexPattern()
+    PatternTerm term;
+    Vector hotTerms;
+};
+
+struct BeginChar {
+    BeginChar()
+        : value(0)
+        , mask(0)
+    {}
+
+    BeginChar(unsigned value, unsigned mask)
+        : value(value)
+        , mask(mask)
+    {}
+
+    unsigned value;
+    unsigned mask;
+};
+
+struct YarrPattern {
+    YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error);
+
+    ~YarrPattern()
     {
         deleteAllValues(m_disjunctions);
         deleteAllValues(m_userCharacterClasses);
@@ -354,6 +362,7 @@ struct RegexPattern {
         m_maxBackReference = 0;
 
         m_containsBackreferences = false;
+        m_containsBeginChars = false;
         m_containsBOL = false;
 
         newlineCached = 0;
@@ -368,6 +377,7 @@ struct RegexPattern {
         m_disjunctions.clear();
         deleteAllValues(m_userCharacterClasses);
         m_userCharacterClasses.clear();
+        m_beginChars.clear();
     }
 
     bool containsIllegalBackReference()
@@ -418,19 +428,21 @@ struct RegexPattern {
         return nonwordcharCached;
     }
 
-    typedef js::Vector PatternDisjunctions;
-    typedef js::Vector CharacterClasses;
     bool m_ignoreCase : 1;
     bool m_multiline : 1;
     bool m_containsBackreferences : 1;
+    bool m_containsBeginChars : 1;
     bool m_containsBOL : 1;
     unsigned m_numSubpatterns;
     unsigned m_maxBackReference;
-    PatternDisjunction *m_body;
-    PatternDisjunctions m_disjunctions;
-    CharacterClasses m_userCharacterClasses;
+    PatternDisjunction* m_body;
+    Vector m_disjunctions;
+    Vector m_userCharacterClasses;
+    Vector m_beginChars;
 
 private:
+    ErrorCode compile(const UString& patternString);
+
     CharacterClass* newlineCached;
     CharacterClass* digitsCached;
     CharacterClass* spacesCached;
@@ -442,4 +454,4 @@ private:
 
 } } // namespace JSC::Yarr
 
-#endif // RegexPattern_h
+#endif // YarrPattern_h
diff --git a/js/src/yarr/yarr/RegexCommon.h b/js/src/yarr/YarrSyntaxChecker.cpp
similarity index 52%
rename from js/src/yarr/yarr/RegexCommon.h
rename to js/src/yarr/YarrSyntaxChecker.cpp
index 3ae337ea62cc..f36ac5a3f5bc 100644
--- a/js/src/yarr/yarr/RegexCommon.h
+++ b/js/src/yarr/YarrSyntaxChecker.cpp
@@ -1,5 +1,8 @@
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+/* -*- 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) 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
@@ -21,30 +24,39 @@
  * 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 RegexCommon_h
-#define RegexCommon_h
+#include "YarrSyntaxChecker.h"
+
+#include "YarrParser.h"
 
 namespace JSC { namespace Yarr {
 
-enum ErrorCode {
-    HitRecursionLimit = -2,
-    NoError = 0,
-    PatternTooLarge,
-    QuantifierOutOfOrder,
-    QuantifierWithoutAtom,
-    MissingParentheses,
-    ParenthesesUnmatched,
-    ParenthesesTypeInvalid,
-    CharacterClassUnmatched,
-    CharacterClassOutOfOrder,
-    CharacterClassRangeSingleChar,
-    EscapeUnterminated,
-    QuantifierTooLarge,
-    NumberOfErrorCodes
+class SyntaxChecker {
+public:
+    void assertionBOL() {}
+    void assertionEOL() {}
+    void assertionWordBoundary(bool) {}
+    void atomPatternCharacter(UChar) {}
+    void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) {}
+    void atomCharacterClassBegin(bool = false) {}
+    void atomCharacterClassAtom(UChar) {}
+    void atomCharacterClassRange(UChar, UChar) {}
+    void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) {}
+    void atomCharacterClassEnd() {}
+    void atomParenthesesSubpatternBegin(bool = true) {}
+    void atomParentheticalAssertionBegin(bool = false) {}
+    void atomParenthesesEnd() {}
+    void atomBackReference(unsigned) {}
+    void quantifyAtom(unsigned, unsigned, bool) {}
+    void disjunction() {}
 };
 
-}}
+ErrorCode checkSyntax(const UString& pattern)
+{
+    SyntaxChecker syntaxChecker;
+    return parse(syntaxChecker, pattern);
+}
 
-#endif
+}} // JSC::YARR
diff --git a/js/src/yarr/yarr/RegexCompiler.h b/js/src/yarr/YarrSyntaxChecker.h
similarity index 74%
rename from js/src/yarr/yarr/RegexCompiler.h
rename to js/src/yarr/YarrSyntaxChecker.h
index 307c15866e59..87f2ed5093b0 100644
--- a/js/src/yarr/yarr/RegexCompiler.h
+++ b/js/src/yarr/YarrSyntaxChecker.h
@@ -1,5 +1,8 @@
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+/* -*- 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) 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
@@ -21,18 +24,20 @@
  * 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 RegexCompiler_h
-#define RegexCompiler_h
+#ifndef YarrSyntaxChecker_h
+#define YarrSyntaxChecker_h
 
-#include "RegexParser.h"
-#include "RegexPattern.h"
+#include "wtfbridge.h"
+#include "YarrParser.h"
 
 namespace JSC { namespace Yarr {
 
-int compileRegex(const UString& patternString, RegexPattern& pattern);
+ErrorCode checkSyntax(const UString& pattern);
 
-} } // namespace JSC::Yarr
+}} // JSC::YARR
+
+#endif // YarrSyntaxChecker_h
 
-#endif // RegexCompiler_h
diff --git a/js/src/yarr/jswtfbridge.h b/js/src/yarr/jswtfbridge.h
deleted file mode 100644
index b38f76ead5a8..000000000000
--- a/js/src/yarr/jswtfbridge.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- 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 *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
- * June 12, 2009.
- *
- * The Initial Developer of the Original Code is
- *   the Mozilla Corporation.
- *
- * Contributor(s):
- *   Chris Leary 
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef jswtfbridge_h__
-#define jswtfbridge_h__
-
-/*
- * The JS/WTF Bridge to Bona-fide Quality.
- */
-
-#include "assembler/wtf/Platform.h"
-#include "jsstr.h"
-#include "jsprvtd.h"
-#include "jstl.h"
-
-typedef jschar UChar;
-typedef JSLinearString UString;
-
-class Unicode {
-  public:
-    static UChar toUpper(UChar c) { return JS_TOUPPER(c); }
-    static UChar toLower(UChar c) { return JS_TOLOWER(c); }
-};
-
-#endif
diff --git a/js/src/yarr/pcre/AUTHORS b/js/src/yarr/pcre/AUTHORS
deleted file mode 100644
index dbac2a54834b..000000000000
--- a/js/src/yarr/pcre/AUTHORS
+++ /dev/null
@@ -1,12 +0,0 @@
-Originally written by:  Philip Hazel
-Email local part:       ph10
-Email domain:           cam.ac.uk
-
-University of Cambridge Computing Service,
-Cambridge, England. Phone: +44 1223 334714.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Adapted for JavaScriptCore and WebKit by Apple Inc.
-
-Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/js/src/yarr/pcre/COPYING b/js/src/yarr/pcre/COPYING
deleted file mode 100644
index 6ffdc24342d5..000000000000
--- a/js/src/yarr/pcre/COPYING
+++ /dev/null
@@ -1,35 +0,0 @@
-PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
-This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-    * Redistributions of source code must retain the above copyright notice,
-      this list of conditions and the following disclaimer.
-
-    * 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.
-
-    * Neither the name of the University of Cambridge nor the name of Apple
-      Inc. nor the names of their contributors may be used to endorse or
-      promote products derived from this software without specific prior
-      written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
diff --git a/js/src/yarr/pcre/chartables.c b/js/src/yarr/pcre/chartables.c
deleted file mode 100644
index 5c99db0b980f..000000000000
--- a/js/src/yarr/pcre/chartables.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*************************************************
-*      Perl-Compatible Regular Expressions       *
-*************************************************/
-
-/* This file is automatically written by the dftables auxiliary 
-program. If you edit it by hand, you might like to edit the Makefile to 
-prevent its ever being regenerated.
-
-This file contains the default tables for characters with codes less than
-128 (ASCII characters). These tables are used when no external tables are
-passed to PCRE. */
-
-const unsigned char jsc_pcre_default_tables[480] = {
-
-/* This table is a lower casing table. */
-
-  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
-  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
-  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
-  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
-  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
-  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
-  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
-  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
-  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
-  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
-  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
-  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
-  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
-  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
-  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
-  0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
-
-/* This table is a case flipping table. */
-
-  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
-  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
-  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
-  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
-  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
-  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
-  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
-  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
-  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
-  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
-  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
-  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
-  0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
-  0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 
-  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
-  0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
-
-/* This table contains bit maps for various character classes.
-Each map is 32 bytes long and the bits run from the least
-significant end of each byte. The classes are: space, digit, word. */
-
-  0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
-  0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-/* This table identifies various classes of character by individual bits:
-  0x01   white space character
-  0x08   hexadecimal digit
-  0x10   alphanumeric or '_'
-*/
-
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*   0-  7 */
-  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /*   8- 15 */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  16- 23 */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  24- 31 */
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*    - '  */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  ( - /  */
-  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,  /*  0 - 7  */
-  0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  8 - ?  */
-  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  @ - G  */
-  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  H - O  */
-  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  P - W  */
-  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,  /*  X - _  */
-  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  ` - g  */
-  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  h - o  */
-  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  p - w  */
-  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /*  x -127 */
-
-
-/* End of chartables.c */
diff --git a/js/src/yarr/pcre/dftables b/js/src/yarr/pcre/dftables
deleted file mode 100644
index 669b948ffc91..000000000000
--- a/js/src/yarr/pcre/dftables
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/usr/bin/perl -w
-#
-# This is JavaScriptCore's variant of the PCRE library. While this library
-# started out as a copy of PCRE, many of the features of PCRE have been
-# removed. This library now supports only the regular expression features
-# required by the JavaScript language specification, and has only the functions
-# needed by JavaScriptCore and the rest of WebKit.
-# 
-#                  Originally written by Philip Hazel
-#            Copyright (c) 1997-2006 University of Cambridge
-#  Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
-# 
-#     * Redistributions of source code must retain the above copyright notice,
-#       this list of conditions and the following disclaimer.
-# 
-#     * 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.
-# 
-#     * Neither the name of the University of Cambridge nor the names of its
-#       contributors may be used to endorse or promote products derived from
-#       this software without specific prior written permission.
-# 
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
-# -----------------------------------------------------------------------------
-
-# This is a freestanding support program to generate a file containing
-# character tables. The tables are built according to the default C
-# locale.
-
-use strict;
-
-use File::Basename;
-use File::Spec;
-use File::Temp qw(tempfile);
-use Getopt::Long;
-
-sub readHeaderValues();
-
-my %pcre_internal;
-
-if (scalar(@ARGV) < 1) {
-    print STDERR "Usage: ", basename($0), " [--preprocessor=program] output-file\n";
-    exit 1;
-}
-
-my $outputFile;
-my $preprocessor;
-GetOptions('preprocessor=s' => \$preprocessor);
-if (not $preprocessor) {
-    $preprocessor = "cpp";
-}
-
-$outputFile = $ARGV[0];
-die('Must specify output file.') unless defined($outputFile);
-
-readHeaderValues();
-
-open(OUT, ">", $outputFile) or die "$!";
-binmode(OUT);
-
-printf(OUT
-    "/*************************************************\n" .
-    "*      Perl-Compatible Regular Expressions       *\n" .
-    "*************************************************/\n\n" .
-    "/* This file is automatically written by the dftables auxiliary \n" .
-    "program. If you edit it by hand, you might like to edit the Makefile to \n" .
-    "prevent its ever being regenerated.\n\n");
-printf(OUT
-    "This file contains the default tables for characters with codes less than\n" .
-    "128 (ASCII characters). These tables are used when no external tables are\n" .
-    "passed to PCRE. */\n\n" .
-    "const unsigned char jsc_pcre_default_tables[%d] = {\n\n" .
-    "/* This table is a lower casing table. */\n\n", $pcre_internal{tables_length});
-
-if ($pcre_internal{lcc_offset} != 0) {
-    die "lcc_offset != 0";
-}
-
-printf(OUT "  ");
-for (my $i = 0; $i < 128; $i++) {
-    if (($i & 7) == 0 && $i != 0) {
-        printf(OUT "\n  ");
-    }
-    printf(OUT "0x%02X", ord(lc(chr($i))));
-    if ($i != 127) {
-        printf(OUT ", ");
-    }
-}
-printf(OUT ",\n\n");
-
-printf(OUT "/* This table is a case flipping table. */\n\n");
-
-if ($pcre_internal{fcc_offset} != 128) {
-  die "fcc_offset != 128";
-}
-
-printf(OUT "  ");
-for (my $i = 0; $i < 128; $i++) {
-    if (($i & 7) == 0 && $i != 0) {
-        printf(OUT "\n  ");
-    }
-    my $c = chr($i);
-    printf(OUT "0x%02X", $c =~ /[[:lower:]]/ ? ord(uc($c)) : ord(lc($c)));
-    if ($i != 127) {
-        printf(OUT ", ");
-    }
-}
-printf(OUT ",\n\n");
-
-printf(OUT
-    "/* This table contains bit maps for various character classes.\n" .
-    "Each map is 32 bytes long and the bits run from the least\n" .
-    "significant end of each byte. The classes are: space, digit, word. */\n\n");
-
-if ($pcre_internal{cbits_offset} != $pcre_internal{fcc_offset} + 128) {
-    die "cbits_offset != fcc_offset + 128";
-}
-
-my @cbit_table = (0) x $pcre_internal{cbit_length};
-for (my $i = ord('0'); $i <= ord('9'); $i++) {
-    $cbit_table[$pcre_internal{cbit_digit} + $i / 8] |= 1 << ($i & 7);
-}
-$cbit_table[$pcre_internal{cbit_word} + ord('_') / 8] |= 1 << (ord('_') & 7);
-for (my $i = 0; $i < 128; $i++) {
-    my $c = chr($i);
-    if ($c =~ /[[:alnum:]]/) {
-        $cbit_table[$pcre_internal{cbit_word} + $i / 8] |= 1 << ($i & 7);
-    }
-    if ($c =~ /[[:space:]]/) {
-        $cbit_table[$pcre_internal{cbit_space} + $i / 8] |= 1 << ($i & 7);
-    }
-}
-
-printf(OUT "  ");
-for (my $i = 0; $i < $pcre_internal{cbit_length}; $i++) {
-    if (($i & 7) == 0 && $i != 0) {
-        if (($i & 31) == 0) {
-            printf(OUT "\n");
-        }
-        printf(OUT "\n  ");
-    }
-    printf(OUT "0x%02X", $cbit_table[$i]);
-    if ($i != $pcre_internal{cbit_length} - 1) {
-        printf(OUT ", ");
-    }
-}
-printf(OUT ",\n\n");
-
-printf(OUT
-    "/* This table identifies various classes of character by individual bits:\n" .
-    "  0x%02x   white space character\n" .
-    "  0x%02x   hexadecimal digit\n" .
-    "  0x%02x   alphanumeric or '_'\n*/\n\n",
-    $pcre_internal{ctype_space}, $pcre_internal{ctype_xdigit}, $pcre_internal{ctype_word});
-
-if ($pcre_internal{ctypes_offset} != $pcre_internal{cbits_offset} + $pcre_internal{cbit_length}) {
-    die "ctypes_offset != cbits_offset + cbit_length";
-}
-
-printf(OUT "  ");
-for (my $i = 0; $i < 128; $i++) {
-    my $x = 0;
-    my $c = chr($i);
-    if ($c =~ /[[:space:]]/) {
-        $x += $pcre_internal{ctype_space};
-    }
-    if ($c =~ /[[:xdigit:]]/) {
-        $x += $pcre_internal{ctype_xdigit};
-    }
-    if ($c =~ /[[:alnum:]_]/) {
-        $x += $pcre_internal{ctype_word};
-    }
-    printf(OUT "0x%02X", $x);
-    if ($i != 127) {
-        printf(OUT ", ");
-    } else {
-        printf(OUT "};");
-    }
-    if (($i & 7) == 7) {
-        printf(OUT " /* ");
-        my $d = chr($i - 7);
-        if ($d =~ /[[:print:]]/) {
-            printf(OUT " %c -", $i - 7);
-        } else {
-            printf(OUT "%3d-", $i - 7);
-        }
-        if ($c =~ m/[[:print:]]/) {
-            printf(OUT " %c ", $i);
-        } else {
-            printf(OUT "%3d", $i);
-        }
-        printf(OUT " */\n");
-        if ($i != 127) {
-            printf(OUT "  ");
-        }
-    }
-}
-
-if ($pcre_internal{tables_length} != $pcre_internal{ctypes_offset} + 128) {
-    die "tables_length != ctypes_offset + 128";
-}
-
-printf(OUT "\n\n/* End of chartables.c */\n");
-
-close(OUT);
-
-exit 0;
-
-sub readHeaderValues()
-{
-    my @variables = qw(
-        cbit_digit
-        cbit_length
-        cbit_space
-        cbit_word
-        cbits_offset
-        ctype_space
-        ctype_word
-        ctype_xdigit
-        ctypes_offset
-        fcc_offset
-        lcc_offset
-        tables_length
-    );
-
-    local $/ = undef;
-
-    my $headerPath = File::Spec->catfile(dirname($0), "pcre_internal.h");
- 
-    my ($fh, $tempFile) = tempfile(
-        basename($0) . "-XXXXXXXX",
-        DIR => File::Spec->tmpdir(),
-        SUFFIX => ".in",
-        UNLINK => 0,
-    );
-
-    print $fh "#define DFTABLES\n\n";
-
-    open(HEADER, "<", $headerPath) or die "$!";
-    print $fh 
; - close(HEADER); - - print $fh "\n\n"; - - for my $v (@variables) { - print $fh "\$pcre_internal{\"$v\"} = $v;\n"; - } - - close($fh); - - open(CPP, "$preprocessor \"$tempFile\" |") or die "$!"; - my $content = ; - close(CPP); - - eval $content; - die "$@" if $@; - unlink $tempFile; -} diff --git a/js/src/yarr/pcre/pcre.h b/js/src/yarr/pcre/pcre.h deleted file mode 100644 index 91d96b784905..000000000000 --- a/js/src/yarr/pcre/pcre.h +++ /dev/null @@ -1,68 +0,0 @@ -/* This is the public header file for JavaScriptCore's variant of the PCRE -library. While this library started out as a copy of PCRE, many of the -features of PCRE have been removed. This library now supports only the -regular expression features required by the JavaScript language -specification, and has only the functions needed by JavaScriptCore and the -rest of WebKit. - - Copyright (c) 1997-2005 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE. - -#ifndef JSRegExp_h -#define JSRegExp_h - -#include "yarr/jswtfbridge.h" - -struct JSRegExp; -struct JSContext; - -enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase }; -enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline }; - -/* jsRegExpExecute error codes */ -const int JSRegExpErrorNoMatch = -1; -const int JSRegExpErrorHitLimit = -2; -const int JSRegExpErrorInternal = -4; - -JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, - JSRegExpIgnoreCaseOption, JSRegExpMultilineOption, - unsigned* numSubpatterns, int *error); - -int jsRegExpExecute(JSContext *, const JSRegExp*, - const UChar* subject, int subjectLength, int startOffset, - int* offsetsVector, int offsetsVectorLength); - -void jsRegExpFree(JSRegExp*); - -#endif diff --git a/js/src/yarr/pcre/pcre.pri b/js/src/yarr/pcre/pcre.pri deleted file mode 100644 index 4f59e17f4d91..000000000000 --- a/js/src/yarr/pcre/pcre.pri +++ /dev/null @@ -1,12 +0,0 @@ -# Perl Compatible Regular Expressions - Qt4 build info -VPATH += $$PWD -INCLUDEPATH += $$PWD $$OUTPUT_DIR/JavaScriptCore/tmp -DEPENDPATH += $$PWD - -SOURCES += \ - pcre_compile.cpp \ - pcre_exec.cpp \ - pcre_tables.cpp \ - pcre_ucp_searchfuncs.cpp \ - pcre_xclass.cpp - diff --git a/js/src/yarr/pcre/pcre_compile.cpp b/js/src/yarr/pcre/pcre_compile.cpp deleted file mode 100644 index 8d273bcbe5a6..000000000000 --- a/js/src/yarr/pcre/pcre_compile.cpp +++ /dev/null @@ -1,2702 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - Copyright (C) 2007 Eric Seidel - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains the external function jsRegExpExecute(), along with -supporting internal functions that are not used by other modules. */ - -#include "pcre_internal.h" - -#include -#include "yarr/wtf/ASCIICType.h" -#include "jsvector.h" - -using namespace WTF; - -/* Negative values for the firstchar and reqchar variables */ - -#define REQ_UNSET (-2) -#define REQ_NONE (-1) - -/************************************************* -* Code parameters and static tables * -*************************************************/ - -/* Maximum number of items on the nested bracket stacks at compile time. This -applies to the nesting of all kinds of parentheses. It does not limit -un-nested, non-capturing parentheses. This number can be made bigger if -necessary - it is used to dimension one int and one unsigned char vector at -compile time. */ - -#define BRASTACK_SIZE 200 - -/* Table for handling escaped characters in the range '0'-'z'. Positive returns -are simple data values; negative values are for special things like \d and so -on. Zero means further processing is needed (for things like \x), or the escape -is invalid. */ - -static const short escapes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ - 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ - '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ - 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ - 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ - 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */ - '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */ - 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */ - 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */ - 0, 0, 0 /* x - z */ -}; -static const unsigned OPCODE_LEN = 1; -static const unsigned BRAZERO_LEN = OPCODE_LEN; -static const unsigned BRA_NEST_SIZE = 2; -static const unsigned BRA_LEN = OPCODE_LEN + LINK_SIZE + BRA_NEST_SIZE; -static const unsigned KET_LEN = OPCODE_LEN + LINK_SIZE; - -/* Error code numbers. They are given names so that they can more easily be -tracked. */ - -enum ErrorCode { - ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, - ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17 -}; - -/* These are the error texts that correspond to the above error codes: - // 1 - "\\ at end of pattern\0" - "\\c at end of pattern\0" - "character value in \\x{...} sequence is too large\0" - "numbers out of order in {} quantifier\0" - // 5 - "number too big in {} quantifier\0" - "missing terminating ] for character class\0" - "internal error: code overflow\0" - "range out of order in character class\0" - "nothing to repeat\0" - // 10 - "unmatched parentheses\0" - "internal error: unexpected repeat\0" - "unrecognized character after (?\0" - "failed to get memory\0" - "missing )\0" - // 15 - "reference to non-existent subpattern\0" - "regular expression too large\0" - "parentheses nested too deeply" */ - -/* Structure for passing "static" information around between the functions -doing the compiling. */ - -struct CompileData { - CompileData() { - topBackref = 0; - backrefMap = 0; - reqVaryOpt = 0; - needOuterBracket = false; - numCapturingBrackets = 0; - } - int topBackref; /* Maximum back reference */ - unsigned backrefMap; /* Bitmap of low back refs */ - int reqVaryOpt; /* "After variable item" flag for reqByte */ - bool needOuterBracket; - int numCapturingBrackets; -}; - -/* Definitions to allow mutual recursion */ - -static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&); -static bool bracketIsAnchored(const unsigned char* code); -static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap); -static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert); - -/************************************************* -* Handle escapes * -*************************************************/ - -/* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \n, or a negative value which -encodes one of the more complicated things such as \d. When UTF-8 is enabled, -a positive value greater than 255 may be returned. On entry, ptr is pointing at -the \. On exit, it is on the final character of the escape sequence. - -Arguments: - ptrPtr points to the pattern position pointer - errorCodePtr points to the errorcode variable - bracount number of previous extracting brackets - options the options bits - isClass true if inside a character class - -Returns: zero or positive => a data character - negative => a special escape sequence - on error, error is set -*/ - -static int checkEscape(const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int bracount, bool isClass) -{ - const UChar* ptr = *ptrPtr + 1; - - /* If backslash is at the end of the pattern, it's an error. */ - if (ptr == patternEnd) { - *errorCodePtr = ERR1; - *ptrPtr = ptr; - return 0; - } - - int c = *ptr; - - /* Non-alphamerics are literals. For digits or letters, do an initial lookup in - a table. A non-zero result is something that can be returned immediately. - Otherwise further processing may be required. */ - - if (c < '0' || c > 'z') { /* Not alphameric */ - } else if (int escapeValue = escapes[c - '0']) { - c = escapeValue; - if (isClass) { - if (-c == ESC_b) - c = '\b'; /* \b is backslash in a class */ - else if (-c == ESC_B) - c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */ - } - /* Escapes that need further processing, or are illegal. */ - - } else { - switch (c) { - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - /* Escape sequences starting with a non-zero digit are backreferences, - unless there are insufficient brackets, in which case they are octal - escape sequences. Those sequences end on the first non-octal character - or when we overflow 0-255, whichever comes first. */ - - if (!isClass) { - const UChar* oldptr = ptr; - c -= '0'; - while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount) - c = c * 10 + *(++ptr) - '0'; - if (c <= bracount) { - c = -(ESC_REF + c); - break; - } - ptr = oldptr; /* Put the pointer back and fall through */ - } - - /* Handle an octal number following \. If the first digit is 8 or 9, - this is not octal. */ - - if ((c = *ptr) >= '8') { - c = '\\'; - ptr -= 1; - break; - } - - /* \0 always starts an octal number, but we may drop through to here with a - larger first octal digit. */ - - case '0': { - c -= '0'; - int i; - for (i = 1; i <= 2; ++i) { - if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7') - break; - int cc = c * 8 + ptr[i] - '0'; - if (cc > 255) - break; - c = cc; - } - ptr += i - 1; - break; - } - - case 'x': { - c = 0; - int i; - for (i = 1; i <= 2; ++i) { - if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { - c = 'x'; - i = 1; - break; - } - int cc = ptr[i]; - if (cc >= 'a') - cc -= 32; /* Convert to upper case */ - c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); - } - ptr += i - 1; - break; - } - - case 'u': { - c = 0; - int i; - for (i = 1; i <= 4; ++i) { - if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { - c = 'u'; - i = 1; - break; - } - int cc = ptr[i]; - if (cc >= 'a') - cc -= 32; /* Convert to upper case */ - c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); - } - ptr += i - 1; - break; - } - - case 'c': - if (++ptr == patternEnd) { - *errorCodePtr = ERR2; - return 0; - } - - c = *ptr; - - /* To match Firefox, inside a character class, we also accept - numbers and '_' as control characters */ - if ((!isClass && !isASCIIAlpha(c)) || (!isASCIIAlphanumeric(c) && c != '_')) { - c = '\\'; - ptr -= 2; - break; - } - - /* A letter is upper-cased; then the 0x40 bit is flipped. This coding - is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ - c = toASCIIUpper(c) ^ 0x40; - break; - } - } - - *ptrPtr = ptr; - return c; -} - -/************************************************* -* Check for counted repeat * -*************************************************/ - -/* This function is called when a '{' is encountered in a place where it might -start a quantifier. It looks ahead to see if it really is a quantifier or not. -It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} -where the ddds are digits. - -Arguments: - p pointer to the first char after '{' - -Returns: true or false -*/ - -static bool isCountedRepeat(const UChar* p, const UChar* patternEnd) -{ - if (p >= patternEnd || !isASCIIDigit(*p)) - return false; - p++; - while (p < patternEnd && isASCIIDigit(*p)) - p++; - if (p < patternEnd && *p == '}') - return true; - - if (p >= patternEnd || *p++ != ',') - return false; - if (p < patternEnd && *p == '}') - return true; - - if (p >= patternEnd || !isASCIIDigit(*p)) - return false; - p++; - while (p < patternEnd && isASCIIDigit(*p)) - p++; - - return (p < patternEnd && *p == '}'); -} - -/************************************************* -* Read repeat counts * -*************************************************/ - -/* Read an item of the form {n,m} and return the values. This is called only -after isCountedRepeat() has confirmed that a repeat-count quantifier exists, -so the syntax is guaranteed to be correct, but we need to check the values. - -Arguments: - p pointer to first char after '{' - minp pointer to int for min - maxp pointer to int for max - returned as -1 if no max - errorCodePtr points to error code variable - -Returns: pointer to '}' on success; - current ptr on error, with errorCodePtr set non-zero -*/ - -static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorCodePtr) -{ - int min = 0; - int max = -1; - - /* Read the minimum value and do a paranoid check: a negative value indicates - an integer overflow. */ - - while (isASCIIDigit(*p)) - min = min * 10 + *p++ - '0'; - if (min < 0 || min > 65535) { - *errorCodePtr = ERR5; - return p; - } - - /* Read the maximum value if there is one, and again do a paranoid on its size. - Also, max must not be less than min. */ - - if (*p == '}') - max = min; - else { - if (*(++p) != '}') { - max = 0; - while (isASCIIDigit(*p)) - max = max * 10 + *p++ - '0'; - if (max < 0 || max > 65535) { - *errorCodePtr = ERR5; - return p; - } - if (max < min) { - *errorCodePtr = ERR4; - return p; - } - } - } - - /* Fill in the required variables, and pass back the pointer to the terminating - '}'. */ - - *minp = min; - *maxp = max; - return p; -} - -/************************************************* -* Find first significant op code * -*************************************************/ - -/* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring op code etc. It skips over things -that do not influence this. - -Arguments: - code pointer to the start of the group -Returns: pointer to the first significant opcode -*/ - -static const unsigned char* firstSignificantOpcode(const unsigned char* code) -{ - while (*code == OP_BRANUMBER) - code += 3; - return code; -} - -static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code) -{ - while (true) { - switch (*code) { - case OP_ASSERT_NOT: - advanceToEndOfBracket(code); - code += 1 + LINK_SIZE; - break; - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - ++code; - break; - case OP_BRANUMBER: - code += 3; - break; - default: - return code; - } - } -} - -/************************************************* -* Get othercase range * -*************************************************/ - -/* This function is passed the start and end of a class range, in UTF-8 mode -with UCP support. It searches up the characters, looking for internal ranges of -characters in the "other" case. Each call returns the next one, updating the -start address. - -Arguments: - cptr points to starting character value; updated - d end value - ocptr where to put start of othercase range - odptr where to put end of othercase range - -Yield: true when range returned; false when no more -*/ - -static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr) -{ - int c, othercase = 0; - - for (c = *cptr; c <= d; c++) { - if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) - break; - } - - if (c > d) - return false; - - *ocptr = othercase; - int next = othercase + 1; - - for (++c; c <= d; c++) { - if (jsc_pcre_ucp_othercase(c) != next) - break; - next++; - } - - *odptr = next - 1; - *cptr = c; - - return true; -} - -/************************************************* - * Convert character value to UTF-8 * - *************************************************/ - -/* This function takes an integer value in the range 0 - 0x7fffffff - and encodes it as a UTF-8 character in 0 to 6 bytes. - - Arguments: - cvalue the character value - buffer pointer to buffer for result - at least 6 bytes long - - Returns: number of characters placed in the buffer - */ - -static int encodeUTF8(int cvalue, unsigned char *buffer) -{ - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (cvalue <= jsc_pcre_utf8_table1[i]) - break; - buffer += i; - for (int j = i; j > 0; j--) { - *buffer-- = 0x80 | (cvalue & 0x3f); - cvalue >>= 6; - } - *buffer = jsc_pcre_utf8_table2[i] | cvalue; - return i + 1; -} - -/************************************************* -* Compile one branch * -*************************************************/ - -/* Scan the pattern, compiling it into the code vector. - -Arguments: - options the option bits - brackets points to number of extracting brackets used - codePtr points to the pointer to the current code point - ptrPtr points to the current pattern pointer - errorCodePtr points to error code variable - firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) - reqbyteptr set to the last literal character required, else < 0 - cd contains pointers to tables etc. - -Returns: true on success - false, with *errorCodePtr set non-zero on error -*/ - -static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected) -{ - return ((ptr + 1 < patternEnd) && ptr[1] == expected); -} - -static bool -compileBranch(int options, int* brackets, unsigned char** codePtr, - const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int *firstbyteptr, - int* reqbyteptr, CompileData& cd) -{ - int repeatType, opType; - int repeatMin = 0, repeat_max = 0; /* To please picky compilers */ - int bravalue = 0; - int reqvary, tempreqvary; - int c; - unsigned char* code = *codePtr; - unsigned char* tempcode; - bool didGroupSetFirstByte = false; - const UChar* ptr = *ptrPtr; - const UChar* tempptr; - unsigned char* previous = NULL; - unsigned char classbits[32]; - - bool class_utf8; - unsigned char* class_utf8data; - unsigned char utf8_char[6]; - - /* Initialize no first byte, no required byte. REQ_UNSET means "no char - matching encountered yet". It gets changed to REQ_NONE if we hit something that - matches a non-fixed char first char; reqByte just remains unset if we never - find one. - - When we hit a repeat whose minimum is zero, we may have to adjust these values - to take the zero repeat into account. This is implemented by setting them to - zeroFirstByte and zeroReqByte when such a repeat is encountered. The individual - item types that can be repeated set these backoff variables appropriately. */ - - int firstByte = REQ_UNSET; - int reqByte = REQ_UNSET; - int zeroReqByte = REQ_UNSET; - int zeroFirstByte = REQ_UNSET; - - /* The variable reqCaseOpt contains either the REQ_IGNORE_CASE value or zero, - according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit - value > 255. It is added into the firstByte or reqByte variables to record the - case status of the value. This is used only for ASCII characters. */ - - int reqCaseOpt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0; - - /* Switch on next character until the end of the branch */ - - for (;; ptr++) { - bool negateClass; - bool shouldFlipNegation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */ - int classCharCount; - int classLastChar; - int skipBytes; - int subReqByte; - int subFirstByte; - int mcLength; - unsigned char mcbuffer[8]; - - /* Next byte in the pattern */ - - c = ptr < patternEnd ? *ptr : 0; - - /* Fill in length of a previous callout, except when the next thing is - a quantifier. */ - - bool isQuantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd)); - - switch (c) { - /* The branch terminates at end of string, |, or ). */ - - case 0: - if (ptr < patternEnd) - goto NORMAL_CHAR; - // End of string; fall through - case '|': - case ')': - *firstbyteptr = firstByte; - *reqbyteptr = reqByte; - *codePtr = code; - *ptrPtr = ptr; - return true; - - /* Handle single-character metacharacters. In multiline mode, ^ disables - the setting of any following char as a first character. */ - - case '^': - if (options & MatchAcrossMultipleLinesOption) { - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - *code++ = OP_BOL; - } else - *code++ = OP_CIRC; - previous = NULL; - break; - - case '$': - previous = NULL; - if (options & MatchAcrossMultipleLinesOption) - *code++ = OP_EOL; - else - *code++ = OP_DOLL; - break; - - /* There can never be a first char if '.' is first, whatever happens about - repeats. The value of reqByte doesn't change either. */ - - case '.': - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - previous = code; - *code++ = OP_NOT_NEWLINE; - break; - - /* Character classes. If the included characters are all < 256, we build a - 32-byte bitmap of the permitted characters, except in the special case - where there is only one such character. For negated classes, we build the - map as usual, then invert it at the end. However, we use a different opcode - so that data characters > 255 can be handled correctly. - - If the class contains characters outside the 0-255 range, a different - opcode is compiled. It may optionally have a bit map for characters < 256, - but those above are are explicitly listed afterwards. A flag byte tells - whether the bitmap is present, and whether this is a negated class or not. - */ - - case '[': { - previous = code; - shouldFlipNegation = false; - - /* PCRE supports POSIX class stuff inside a class. Perl gives an error if - they are encountered at the top level, so we'll do that too. */ - - /* If the first character is '^', set the negation flag and skip it. */ - - if (ptr + 1 >= patternEnd) { - *errorCodePtr = ERR6; - return false; - } - - if (ptr[1] == '^') { - negateClass = true; - ++ptr; - } else - negateClass = false; - - /* Keep a count of chars with values < 256 so that we can optimize the case - of just a single character (as long as it's < 256). For higher valued UTF-8 - characters, we don't yet do any optimization. */ - - classCharCount = 0; - classLastChar = -1; - - class_utf8 = false; /* No chars >= 256 */ - class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ - - /* Initialize the 32-char bit map to all zeros. We have to build the - map in a temporary bit of store, in case the class contains only 1 - character (< 256), because in that case the compiled code doesn't use the - bit map. */ - - memset(classbits, 0, 32 * sizeof(unsigned char)); - - /* Process characters until ] is reached. The first pass - through the regex checked the overall syntax, so we don't need to be very - strict here. At the start of the loop, c contains the first byte of the - character. */ - - while ((++ptr < patternEnd) && (c = *ptr) != ']') { - /* Backslash may introduce a single character, or it may introduce one - of the specials, which just set a flag. Escaped items are checked for - validity in the pre-compiling pass. The sequence \b is a special case. - Inside a class (and only there) it is treated as backspace. Elsewhere - it marks a word boundary. Other escapes have preset maps ready to - or into the one we are building. We assume they have more than one - character in them, so set classCharCount bigger than one. */ - - if (c == '\\') { - c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); - if (c < 0) { - classCharCount += 2; /* Greater than 1 is what matters */ - switch (-c) { - case ESC_d: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_digit); - continue; - - case ESC_D: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_digit); - continue; - - case ESC_w: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_word); - continue; - - case ESC_W: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_word); - continue; - - case ESC_s: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_space); - continue; - - case ESC_S: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_space); - continue; - - /* Unrecognized escapes are faulted if PCRE is running in its - strict mode. By default, for compatibility with Perl, they are - treated as literals. */ - - default: - c = *ptr; /* The final character */ - classCharCount -= 2; /* Undo the default count from above */ - } - } - - /* Fall through if we have a single character (c >= 0). This may be - > 256 in UTF-8 mode. */ - - } /* End of backslash handling */ - - /* A single character may be followed by '-' to form a range. However, - Perl does not permit ']' to be the end of the range. A '-' character - here is treated as a literal. */ - - if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') { - ptr += 2; - - int d = *ptr; - - /* The second part of a range can be a single-character escape, but - not any of the other escapes. Perl 5.6 treats a hyphen as a literal - in such circumstances. */ - - if (d == '\\') { - const UChar* oldptr = ptr; - d = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); - - /* \X is literal X; any other special means the '-' was literal */ - if (d < 0) { - ptr = oldptr - 2; - goto LONE_SINGLE_CHARACTER; /* A few lines below */ - } - } - - /* The check that the two values are in the correct order happens in - the pre-pass. Optimize one-character ranges */ - - if (d == c) - goto LONE_SINGLE_CHARACTER; /* A few lines below */ - - /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless - matching, we have to use an XCLASS with extra data items. Caseless - matching for characters > 127 is available only if UCP support is - available. */ - - if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) { - class_utf8 = true; - - /* With UCP support, we can find the other case equivalents of - the relevant characters. There may be several ranges. Optimize how - they fit with the basic range. */ - - if (options & IgnoreCaseOption) { - int occ, ocd; - int cc = c; - int origd = d; - while (getOthercaseRange(&cc, origd, &occ, &ocd)) { - if (occ >= c && ocd <= d) - continue; /* Skip embedded ranges */ - - if (occ < c && ocd >= c - 1) /* Extend the basic range */ - { /* if there is overlap, */ - c = occ; /* noting that if occ < c */ - continue; /* we can't have ocd > d */ - } /* because a subrange is */ - if (ocd > d && occ <= d + 1) /* always shorter than */ - { /* the basic range. */ - d = ocd; - continue; - } - - if (occ == ocd) - *class_utf8data++ = XCL_SINGLE; - else { - *class_utf8data++ = XCL_RANGE; - class_utf8data += encodeUTF8(occ, class_utf8data); - } - class_utf8data += encodeUTF8(ocd, class_utf8data); - } - } - - /* Now record the original range, possibly modified for UCP caseless - overlapping ranges. */ - - *class_utf8data++ = XCL_RANGE; - class_utf8data += encodeUTF8(c, class_utf8data); - class_utf8data += encodeUTF8(d, class_utf8data); - - /* With UCP support, we are done. Without UCP support, there is no - caseless matching for UTF-8 characters > 127; we can use the bit map - for the smaller ones. */ - - continue; /* With next character in the class */ - } - - /* We use the bit map for all cases when not in UTF-8 mode; else - ranges that lie entirely within 0-127 when there is UCP support; else - for partial ranges without UCP support. */ - - for (; c <= d; c++) { - classbits[c/8] |= (1 << (c&7)); - if (options & IgnoreCaseOption) { - int uc = flipCase(c); - classbits[uc/8] |= (1 << (uc&7)); - } - classCharCount++; /* in case a one-char range */ - classLastChar = c; - } - - continue; /* Go get the next char in the class */ - } - - /* Handle a lone single character - we can get here for a normal - non-escape char, or after \ that introduces a single character or for an - apparent range that isn't. */ - - LONE_SINGLE_CHARACTER: - - /* Handle a character that cannot go in the bit map */ - - if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) { - class_utf8 = true; - *class_utf8data++ = XCL_SINGLE; - class_utf8data += encodeUTF8(c, class_utf8data); - - if (options & IgnoreCaseOption) { - int othercase; - if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) { - *class_utf8data++ = XCL_SINGLE; - class_utf8data += encodeUTF8(othercase, class_utf8data); - } - } - } else { - /* Handle a single-byte character */ - classbits[c/8] |= (1 << (c&7)); - if (options & IgnoreCaseOption) { - c = flipCase(c); - classbits[c/8] |= (1 << (c&7)); - } - classCharCount++; - classLastChar = c; - } - } - - /* If classCharCount is 1, we saw precisely one character whose value is - less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we - can optimize the negative case only if there were no characters >= 128 - because OP_NOT and the related opcodes like OP_NOTSTAR operate on - single-bytes only. This is an historical hangover. Maybe one day we can - tidy these opcodes to handle multi-byte characters. - - The optimization throws away the bit map. We turn the item into a - 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note - that OP_NOT does not support multibyte characters. In the positive case, it - can cause firstByte to be set. Otherwise, there can be no first char if - this item is first, whatever repeat count may follow. In the case of - reqByte, save the previous value for reinstating. */ - - if (classCharCount == 1 && (!class_utf8 && (!negateClass || classLastChar < 128))) { - zeroReqByte = reqByte; - - /* The OP_NOT opcode works on one-byte characters only. */ - - if (negateClass) { - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - zeroFirstByte = firstByte; - *code++ = OP_NOT; - *code++ = classLastChar; - break; - } - - /* For a single, positive character, get the value into c, and - then we can handle this with the normal one-character code. */ - - c = classLastChar; - goto NORMAL_CHAR; - } /* End of 1-char optimization */ - - /* The general case - not the one-char optimization. If this is the first - thing in the branch, there can be no first char setting, whatever the - repeat count. Any reqByte setting must remain unchanged after any kind of - repeat. */ - - if (firstByte == REQ_UNSET) firstByte = REQ_NONE; - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - - /* If there are characters with values > 255, we have to compile an - extended class, with its own opcode. If there are no characters < 256, - we can omit the bitmap. */ - - if (class_utf8 && !shouldFlipNegation) { - *class_utf8data++ = XCL_END; /* Marks the end of extra data */ - *code++ = OP_XCLASS; - code += LINK_SIZE; - *code = negateClass? XCL_NOT : 0; - - /* If the map is required, install it, and move on to the end of - the extra data */ - - if (classCharCount > 0) { - *code++ |= XCL_MAP; - memcpy(code, classbits, 32); - code = class_utf8data; - } - - /* If the map is not required, slide down the extra data. */ - - else { - int len = class_utf8data - (code + 33); - memmove(code + 1, code + 33, len); - code += len + 1; - } - - /* Now fill in the complete length of the item */ - - putLinkValue(previous + 1, code - previous); - break; /* End of class handling */ - } - - /* If there are no characters > 255, negate the 32-byte map if necessary, - and copy it into the code vector. If this is the first thing in the branch, - there can be no first char setting, whatever the repeat count. Any reqByte - setting must remain unchanged after any kind of repeat. */ - - *code++ = (negateClass == shouldFlipNegation) ? OP_CLASS : OP_NCLASS; - if (negateClass) - for (c = 0; c < 32; c++) - code[c] = ~classbits[c]; - else - memcpy(code, classbits, 32); - code += 32; - break; - } - - /* Various kinds of repeat; '{' is not necessarily a quantifier, but this - has been tested above. */ - - case '{': - if (!isQuantifier) - goto NORMAL_CHAR; - ptr = readRepeatCounts(ptr + 1, &repeatMin, &repeat_max, errorCodePtr); - if (*errorCodePtr) - goto FAILED; - goto REPEAT; - - case '*': - repeatMin = 0; - repeat_max = -1; - goto REPEAT; - - case '+': - repeatMin = 1; - repeat_max = -1; - goto REPEAT; - - case '?': - repeatMin = 0; - repeat_max = 1; - - REPEAT: - if (!previous) { - *errorCodePtr = ERR9; - goto FAILED; - } - - if (repeatMin == 0) { - firstByte = zeroFirstByte; /* Adjust for zero repeat */ - reqByte = zeroReqByte; /* Ditto */ - } - - /* Remember whether this is a variable length repeat */ - - reqvary = (repeatMin == repeat_max) ? 0 : REQ_VARY; - - opType = 0; /* Default single-char op codes */ - - /* Save start of previous item, in case we have to move it up to make space - for an inserted OP_ONCE for the additional '+' extension. */ - /* FIXME: Probably don't need this because we don't use OP_ONCE. */ - - tempcode = previous; - - /* If the next character is '+', we have a possessive quantifier. This - implies greediness, whatever the setting of the PCRE_UNGREEDY option. - If the next character is '?' this is a minimizing repeat, by default, - but if PCRE_UNGREEDY is set, it works the other way round. We change the - repeat type to the non-default. */ - - if (safelyCheckNextChar(ptr, patternEnd, '?')) { - repeatType = 1; - ptr++; - } else - repeatType = 0; - - /* If previous was a character match, abolish the item and generate a - repeat item instead. If a char item has a minumum of more than one, ensure - that it is set in reqByte - it might not be if a sequence such as x{3} is - the first thing in a branch because the x will have gone into firstByte - instead. */ - - if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) { - /* Deal with UTF-8 characters that take up more than one byte. It's - easier to write this out separately than try to macrify it. Use c to - hold the length of the character in bytes, plus 0x80 to flag that it's a - length rather than a small character. */ - - if (code[-1] & 0x80) { - unsigned char *lastchar = code - 1; - while((*lastchar & 0xc0) == 0x80) - lastchar--; - c = code - lastchar; /* Length of UTF-8 character */ - memcpy(utf8_char, lastchar, c); /* Save the char */ - c |= 0x80; /* Flag c as a length */ - } - else { - c = code[-1]; - if (repeatMin > 1) - reqByte = c | reqCaseOpt | cd.reqVaryOpt; - } - - goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ - } - - else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) { - c = previous[1]; - if (repeatMin > 1) - reqByte = c | reqCaseOpt | cd.reqVaryOpt; - goto OUTPUT_SINGLE_REPEAT; - } - - /* If previous was a single negated character ([^a] or similar), we use - one of the special opcodes, replacing it. The code is shared with single- - character repeats by setting opt_type to add a suitable offset into - repeatType. OP_NOT is currently used only for single-byte chars. */ - - else if (*previous == OP_NOT) { - opType = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ - c = previous[1]; - goto OUTPUT_SINGLE_REPEAT; - } - - /* If previous was a character type match (\d or similar), abolish it and - create a suitable repeat item. The code is shared with single-character - repeats by setting opType to add a suitable offset into repeatType. */ - - else if (*previous <= OP_NOT_NEWLINE) { - opType = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ - c = *previous; - - OUTPUT_SINGLE_REPEAT: - int prop_type = -1; - int prop_value = -1; - - unsigned char* oldcode = code; - code = previous; /* Usually overwrite previous item */ - - /* If the maximum is zero then the minimum must also be zero; Perl allows - this case, so we do too - by simply omitting the item altogether. */ - - if (repeat_max == 0) - goto END_REPEAT; - - /* Combine the opType with the repeatType */ - - repeatType += opType; - - /* A minimum of zero is handled either as the special case * or ?, or as - an UPTO, with the maximum given. */ - - if (repeatMin == 0) { - if (repeat_max == -1) - *code++ = OP_STAR + repeatType; - else if (repeat_max == 1) - *code++ = OP_QUERY + repeatType; - else { - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* A repeat minimum of 1 is optimized into some special cases. If the - maximum is unlimited, we use OP_PLUS. Otherwise, the original item it - left in place and, if the maximum is greater than 1, we use OP_UPTO with - one less than the maximum. */ - - else if (repeatMin == 1) { - if (repeat_max == -1) - *code++ = OP_PLUS + repeatType; - else { - code = oldcode; /* leave previous item in place */ - if (repeat_max == 1) - goto END_REPEAT; - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max - 1); - } - } - - /* The case {n,n} is just an EXACT, while the general case {n,m} is - handled as an EXACT followed by an UPTO. */ - - else { - *code++ = OP_EXACT + opType; /* NB EXACT doesn't have repeatType */ - put2ByteValueAndAdvance(code, repeatMin); - - /* If the maximum is unlimited, insert an OP_STAR. Before doing so, - we have to insert the character for the previous code. For a repeated - Unicode property match, there are two extra bytes that define the - required property. In UTF-8 mode, long characters have their length in - c, with the 0x80 bit as a flag. */ - - if (repeat_max < 0) { - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else { - *code++ = c; - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - } - *code++ = OP_STAR + repeatType; - } - - /* Else insert an UPTO if the max is greater than the min, again - preceded by the character, for the previously inserted code. */ - - else if (repeat_max != repeatMin) { - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else - *code++ = c; - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - repeat_max -= repeatMin; - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* The character or character type itself comes last in all cases. */ - - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else - *code++ = c; - - /* For a repeated Unicode property match, there are two extra bytes that - define the required property. */ - - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - } - - /* If previous was a character class or a back reference, we put the repeat - stuff after it, but just skip the item if the repeat was {0,0}. */ - - else if (*previous == OP_CLASS || - *previous == OP_NCLASS || - *previous == OP_XCLASS || - *previous == OP_REF) - { - if (repeat_max == 0) { - code = previous; - goto END_REPEAT; - } - - if (repeatMin == 0 && repeat_max == -1) - *code++ = OP_CRSTAR + repeatType; - else if (repeatMin == 1 && repeat_max == -1) - *code++ = OP_CRPLUS + repeatType; - else if (repeatMin == 0 && repeat_max == 1) - *code++ = OP_CRQUERY + repeatType; - else { - *code++ = OP_CRRANGE + repeatType; - put2ByteValueAndAdvance(code, repeatMin); - if (repeat_max == -1) - repeat_max = 0; /* 2-byte encoding for max */ - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* If previous was a bracket group, we may have to replicate it in certain - cases. */ - - else if (*previous >= OP_BRA) { - int ketoffset = 0; - int len = code - previous; - unsigned char* bralink = NULL; - int nested = get2ByteValue(previous + 1 + LINK_SIZE); - - /* If the maximum repeat count is unlimited, find the end of the bracket - by scanning through from the start, and compute the offset back to it - from the current code pointer. There may be an OP_OPT setting following - the final KET, so we can't find the end just by going back from the code - pointer. */ - - if (repeat_max == -1) { - const unsigned char* ket = previous; - advanceToEndOfBracket(ket); - ketoffset = code - ket; - } - - /* The case of a zero minimum is special because of the need to stick - OP_BRAZERO in front of it, and because the group appears once in the - data, whereas in other cases it appears the minimum number of times. For - this reason, it is simplest to treat this case separately, as otherwise - the code gets far too messy. There are several special subcases when the - minimum is zero. */ - - if (repeatMin == 0) { - /* If the maximum is also zero, we just omit the group from the output - altogether. */ - - if (repeat_max == 0) { - code = previous; - goto END_REPEAT; - } - - /* If the maximum is 1 or unlimited, we just have to stick in the - BRAZERO and do no more at this point. However, we do need to adjust - any OP_RECURSE calls inside the group that refer to the group itself or - any internal group, because the offset is from the start of the whole - regex. Temporarily terminate the pattern while doing this. */ - - if (repeat_max <= 1) { - *code = OP_END; - memmove(previous+1, previous, len); - code++; - *previous++ = OP_BRAZERO + repeatType; - } - - /* If the maximum is greater than 1 and limited, we have to replicate - in a nested fashion, sticking OP_BRAZERO before each set of brackets. - The first one has to be handled carefully because it's the original - copy, which has to be moved up. The remainder can be handled by code - that is common with the non-zero minimum case below. We have to - adjust the value of repeat_max, since one less copy is required. */ - - else { - *code = OP_END; - memmove(previous + 4 + LINK_SIZE, previous, len); - code += 4 + LINK_SIZE; - *previous++ = OP_BRAZERO + repeatType; - *previous++ = OP_BRA; - - /* We chain together the bracket offset fields that have to be - filled in later when the ends of the brackets are reached. */ - - int offset = (!bralink) ? 0 : previous - bralink; - bralink = previous; - putLinkValueAllowZeroAndAdvance(previous, offset); - put2ByteValueAndAdvance(previous, nested); - } - - repeat_max--; - } - - /* If the minimum is greater than zero, replicate the group as many - times as necessary, and adjust the maximum to the number of subsequent - copies that we need. If we set a first char from the group, and didn't - set a required char, copy the latter from the former. */ - - else { - if (repeatMin > 1) { - if (didGroupSetFirstByte && reqByte < 0) - reqByte = firstByte; - for (int i = 1; i < repeatMin; i++) { - memcpy(code, previous, len); - code += len; - } - } - if (repeat_max > 0) - repeat_max -= repeatMin; - } - - /* This code is common to both the zero and non-zero minimum cases. If - the maximum is limited, it replicates the group in a nested fashion, - remembering the bracket starts on a stack. In the case of a zero minimum, - the first one was set up above. In all cases the repeat_max now specifies - the number of additional copies needed. */ - - if (repeat_max >= 0) { - for (int i = repeat_max - 1; i >= 0; i--) { - *code++ = OP_BRAZERO + repeatType; - - /* All but the final copy start a new nesting, maintaining the - chain of brackets outstanding. */ - - if (i != 0) { - *code++ = OP_BRA; - int offset = (!bralink) ? 0 : code - bralink; - bralink = code; - putLinkValueAllowZeroAndAdvance(code, offset); - put2ByteValueAndAdvance(code, nested); - } - - memcpy(code, previous, len); - code += len; - } - - /* Now chain through the pending brackets, and fill in their length - fields (which are holding the chain links pro tem). */ - - while (bralink) { - int offset = code - bralink + 1; - unsigned char* bra = code - offset; - int oldlinkoffset = getLinkValueAllowZero(bra + 1); - bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset; - *code++ = OP_KET; - putLinkValueAndAdvance(code, offset); - putLinkValue(bra + 1, offset); - } - } - - /* If the maximum is unlimited, set a repeater in the final copy. We - can't just offset backwards from the current code point, because we - don't know if there's been an options resetting after the ket. The - correct offset was computed above. */ - - else - code[-ketoffset] = OP_KETRMAX + repeatType; - } - - // A quantifier after an assertion is mostly meaningless, but it - // can nullify the assertion if it has a 0 minimum. - else if (*previous == OP_ASSERT || *previous == OP_ASSERT_NOT) { - if (repeatMin == 0) { - code = previous; - goto END_REPEAT; - } - } - - /* Else there's some kind of shambles */ - - else { - *errorCodePtr = ERR11; - goto FAILED; - } - - /* In all case we no longer have a previous item. We also set the - "follows varying string" flag for subsequently encountered reqbytes if - it isn't already set and we have just passed a varying length item. */ - - END_REPEAT: - previous = NULL; - cd.reqVaryOpt |= reqvary; - break; - - /* Start of nested bracket sub-expression, or comment or lookahead or - lookbehind or option setting or condition. First deal with special things - that can come after a bracket; all are introduced by ?, and the appearance - of any of them means that this is not a referencing group. They were - checked for validity in the first pass over the string, so we don't have to - check for syntax errors here. */ - - case '(': - { - skipBytes = 2; - unsigned minBracket = *brackets + 1; - if (*(++ptr) == '?') { - switch (*(++ptr)) { - case ':': /* Non-extracting bracket */ - bravalue = OP_BRA; - ptr++; - break; - - case '=': /* Positive lookahead */ - bravalue = OP_ASSERT; - ptr++; - break; - - case '!': /* Negative lookahead */ - bravalue = OP_ASSERT_NOT; - ptr++; - break; - - /* Character after (? not specially recognized */ - - default: - *errorCodePtr = ERR12; - goto FAILED; - } - } - - /* Else we have a referencing group; adjust the opcode. If the bracket - number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and - arrange for the true number to follow later, in an OP_BRANUMBER item. */ - - else { - if (++(*brackets) > EXTRACT_BASIC_MAX) { - bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; - code[3 + LINK_SIZE] = OP_BRANUMBER; - put2ByteValue(code + 4 + LINK_SIZE, *brackets); - skipBytes = 5; - } - else - bravalue = OP_BRA + *brackets; - } - - /* Process nested bracketed re. We copy code into a non-variable - in order to be able to pass its address because some compilers - complain otherwise. Pass in a new setting for the ims options - if they have changed. */ - - previous = code; - *code = bravalue; - tempcode = code; - tempreqvary = cd.reqVaryOpt; /* Save value before bracket */ - { - unsigned bracketsBeforeRecursion = *brackets; - if (!compileBracket( - options, - brackets, /* Extracting bracket count */ - &tempcode, /* Where to put code (updated) */ - &ptr, /* Input pointer (updated) */ - patternEnd, - errorCodePtr, /* Where to put an error message */ - skipBytes, /* Skip over OP_BRANUMBER */ - &subFirstByte, /* For possible first char */ - &subReqByte, /* For possible last char */ - cd)) /* Tables block */ - goto FAILED; - unsigned enclosedBrackets = (*brackets - bracketsBeforeRecursion); - unsigned limitBracket = minBracket + enclosedBrackets + (bravalue > OP_BRA); - if (!((minBracket & 0xff) == minBracket && (limitBracket & 0xff) == limitBracket)) { - *errorCodePtr = ERR17; - return false; - } - JS_ASSERT(minBracket <= limitBracket); - put2ByteValue(code + 1 + LINK_SIZE, minBracket << 8 | limitBracket); - } - - /* At the end of compiling, code is still pointing to the start of the - group, while tempcode has been updated to point past the end of the group - and any option resetting that may follow it. The pattern pointer (ptr) - is on the bracket. */ - - /* Handle updating of the required and first characters. Update for normal - brackets of all kinds, and conditions with two branches (see code above). - If the bracket is followed by a quantifier with zero repeat, we have to - back off. Hence the definition of zeroReqByte and zeroFirstByte outside the - main loop so that they can be accessed for the back off. */ - - zeroReqByte = reqByte; - zeroFirstByte = firstByte; - didGroupSetFirstByte = false; - - if (bravalue >= OP_BRA) { - /* If we have not yet set a firstByte in this branch, take it from the - subpattern, remembering that it was set here so that a repeat of more - than one can replicate it as reqByte if necessary. If the subpattern has - no firstByte, set "none" for the whole branch. In both cases, a zero - repeat forces firstByte to "none". */ - - if (firstByte == REQ_UNSET) { - if (subFirstByte >= 0) { - firstByte = subFirstByte; - didGroupSetFirstByte = true; - } - else - firstByte = REQ_NONE; - zeroFirstByte = REQ_NONE; - } - - /* If firstByte was previously set, convert the subpattern's firstByte - into reqByte if there wasn't one, using the vary flag that was in - existence beforehand. */ - - else if (subFirstByte >= 0 && subReqByte < 0) - subReqByte = subFirstByte | tempreqvary; - - /* If the subpattern set a required byte (or set a first byte that isn't - really the first byte - see above), set it. */ - - if (subReqByte >= 0) - reqByte = subReqByte; - } - - /* For a forward assertion, we take the reqByte, if set. This can be - helpful if the pattern that follows the assertion doesn't set a different - char. For example, it's useful for /(?=abcde).+/. We can't set firstByte - for an assertion, however because it leads to incorrect effect for patterns - such as /(?=a)a.+/ when the "real" "a" would then become a reqByte instead - of a firstByte. This is overcome by a scan at the end if there's no - firstByte, looking for an asserted first char. */ - - else if (bravalue == OP_ASSERT && subReqByte >= 0) - reqByte = subReqByte; - - /* Now update the main code pointer to the end of the group. */ - - code = tempcode; - - /* Error if hit end of pattern */ - - if (ptr >= patternEnd || *ptr != ')') { - *errorCodePtr = ERR14; - goto FAILED; - } - break; - - } - /* Check \ for being a real metacharacter; if not, fall through and handle - it as a data character at the start of a string. Escape items are checked - for validity in the pre-compiling pass. */ - - case '\\': - tempptr = ptr; - c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, false); - - /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values - are arranged to be the negation of the corresponding OP_values. For the - back references, the values are ESC_REF plus the reference number. Only - back references and those types that consume a character may be repeated. - We can test for values between ESC_b and ESC_w for the latter; this may - have to change if any new ones are ever created. */ - - if (c < 0) { - /* For metasequences that actually match a character, we disable the - setting of a first character if it hasn't already been set. */ - - if (firstByte == REQ_UNSET && -c > ESC_b && -c <= ESC_w) - firstByte = REQ_NONE; - - /* Set values to reset to if this is followed by a zero repeat. */ - - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - - /* Back references are handled specially */ - - if (-c >= ESC_REF) { - int number = -c - ESC_REF; - previous = code; - *code++ = OP_REF; - put2ByteValueAndAdvance(code, number); - } - - /* For the rest, we can obtain the OP value by negating the escape - value */ - - else { - previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL; - *code++ = -c; - } - continue; - } - - /* Fall through. */ - - /* Handle a literal character. It is guaranteed not to be whitespace or # - when the extended flag is set. If we are in UTF-8 mode, it may be a - multi-byte literal character. */ - - default: - NORMAL_CHAR: - - previous = code; - - if (c < 128) { - mcLength = 1; - mcbuffer[0] = c; - - if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') { - *code++ = OP_ASCII_LETTER_IGNORING_CASE; - *code++ = c | 0x20; - } else { - *code++ = OP_ASCII_CHAR; - *code++ = c; - } - } else { - mcLength = encodeUTF8(c, mcbuffer); - - *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR; - for (c = 0; c < mcLength; c++) - *code++ = mcbuffer[c]; - } - - /* Set the first and required bytes appropriately. If no previous first - byte, set it from this character, but revert to none on a zero repeat. - Otherwise, leave the firstByte value alone, and don't change it on a zero - repeat. */ - - if (firstByte == REQ_UNSET) { - zeroFirstByte = REQ_NONE; - zeroReqByte = reqByte; - - /* If the character is more than one byte long, we can set firstByte - only if it is not to be matched caselessly. */ - - if (mcLength == 1 || reqCaseOpt == 0) { - firstByte = mcbuffer[0] | reqCaseOpt; - if (mcLength != 1) - reqByte = code[-1] | cd.reqVaryOpt; - } - else - firstByte = reqByte = REQ_NONE; - } - - /* firstByte was previously set; we can set reqByte only the length is - 1 or the matching is caseful. */ - - else { - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - if (mcLength == 1 || reqCaseOpt == 0) - reqByte = code[-1] | reqCaseOpt | cd.reqVaryOpt; - } - - break; /* End of literal character handling */ - } - } /* end of big loop */ - - /* Control never reaches here by falling through, only by a goto for all the - error states. Pass back the position in the pattern so that it can be displayed - to the user for diagnosing the error. */ - -FAILED: - *ptrPtr = ptr; - return false; -} - -/************************************************* -* Compile sequence of alternatives * -*************************************************/ - -/* On entry, ptr is pointing past the bracket character, but on return -it points to the closing bracket, or vertical bar, or end of string. -The code variable is pointing at the byte into which the BRA operator has been -stored. If the ims options are changed at the start (for a (?ims: group) or -during any branch, we need to insert an OP_OPT item at the start of every -following branch to ensure they get set correctly at run time, and also pass -the new options into every subsequent branch compile. - -Argument: - options option bits, including any changes for this subpattern - brackets -> int containing the number of extracting brackets used - codePtr -> the address of the current code pointer - ptrPtr -> the address of the current pattern pointer - errorCodePtr -> pointer to error code variable - skipBytes skip this many bytes at start (for OP_BRANUMBER) - firstbyteptr place to put the first required character, or a negative number - reqbyteptr place to put the last required character, or a negative number - cd points to the data block with tables pointers etc. - -Returns: true on success -*/ - -static bool -compileBracket(int options, int* brackets, unsigned char** codePtr, - const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int skipBytes, - int* firstbyteptr, int* reqbyteptr, CompileData& cd) -{ - const UChar* ptr = *ptrPtr; - unsigned char* code = *codePtr; - unsigned char* lastBranch = code; - unsigned char* start_bracket = code; - int firstByte = REQ_UNSET; - int reqByte = REQ_UNSET; - - /* Offset is set zero to mark that this bracket is still open */ - - putLinkValueAllowZero(code + 1, 0); - code += 1 + LINK_SIZE + skipBytes; - - /* Loop for each alternative branch */ - - while (true) { - /* Now compile the branch */ - - int branchFirstByte; - int branchReqByte; - if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorCodePtr, - &branchFirstByte, &branchReqByte, cd)) { - *ptrPtr = ptr; - return false; - } - - /* If this is the first branch, the firstByte and reqByte values for the - branch become the values for the regex. */ - - if (*lastBranch != OP_ALT) { - firstByte = branchFirstByte; - reqByte = branchReqByte; - } - - /* If this is not the first branch, the first char and reqByte have to - match the values from all the previous branches, except that if the previous - value for reqByte didn't have REQ_VARY set, it can still match, and we set - REQ_VARY for the regex. */ - - else { - /* If we previously had a firstByte, but it doesn't match the new branch, - we have to abandon the firstByte for the regex, but if there was previously - no reqByte, it takes on the value of the old firstByte. */ - - if (firstByte >= 0 && firstByte != branchFirstByte) { - if (reqByte < 0) - reqByte = firstByte; - firstByte = REQ_NONE; - } - - /* If we (now or from before) have no firstByte, a firstByte from the - branch becomes a reqByte if there isn't a branch reqByte. */ - - if (firstByte < 0 && branchFirstByte >= 0 && branchReqByte < 0) - branchReqByte = branchFirstByte; - - /* Now ensure that the reqbytes match */ - - if ((reqByte & ~REQ_VARY) != (branchReqByte & ~REQ_VARY)) - reqByte = REQ_NONE; - else - reqByte |= branchReqByte; /* To "or" REQ_VARY */ - } - - /* Reached end of expression, either ')' or end of pattern. Go back through - the alternative branches and reverse the chain of offsets, with the field in - the BRA item now becoming an offset to the first alternative. If there are - no alternatives, it points to the end of the group. The length in the - terminating ket is always the length of the whole bracketed item. - Return leaving the pointer at the terminating char. */ - - if (ptr >= patternEnd || *ptr != '|') { - int length = code - lastBranch; - do { - int prevLength = getLinkValueAllowZero(lastBranch + 1); - putLinkValue(lastBranch + 1, length); - length = prevLength; - lastBranch -= length; - } while (length > 0); - - /* Fill in the ket */ - - *code = OP_KET; - putLinkValue(code + 1, code - start_bracket); - code += 1 + LINK_SIZE; - - /* Set values to pass back */ - - *codePtr = code; - *ptrPtr = ptr; - *firstbyteptr = firstByte; - *reqbyteptr = reqByte; - return true; - } - - /* Another branch follows; insert an "or" node. Its length field points back - to the previous branch while the bracket remains open. At the end the chain - is reversed. It's done like this so that the start of the bracket has a - zero offset until it is closed, making it possible to detect recursion. */ - - *code = OP_ALT; - putLinkValue(code + 1, code - lastBranch); - lastBranch = code; - code += 1 + LINK_SIZE; - ptr++; - } - JS_NOT_REACHED("No fallthru."); -} - -/************************************************* -* Check for anchored expression * -*************************************************/ - -/* Try to find out if this is an anchored regular expression. Consider each -alternative branch. If they all start OP_CIRC, or with a bracket -all of whose alternatives start OP_CIRC (recurse ad lib), then -it's anchored. - -Arguments: - code points to start of expression (the bracket) - captureMap a bitmap of which brackets we are inside while testing; this - handles up to substring 31; all brackets after that share - the zero bit - backrefMap the back reference bitmap -*/ - -static bool branchIsAnchored(const unsigned char* code) -{ - const unsigned char* scode = firstSignificantOpcode(code); - int op = *scode; - - /* Brackets */ - if (op >= OP_BRA || op == OP_ASSERT) - return bracketIsAnchored(scode); - - /* Check for explicit anchoring */ - return op == OP_CIRC; -} - -static bool bracketIsAnchored(const unsigned char* code) -{ - do { - if (!branchIsAnchored(code + 1 + LINK_SIZE)) - return false; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); /* Loop for each alternative */ - return true; -} - -/************************************************* -* Check for starting with ^ or .* * -*************************************************/ - -/* This is called to find out if every branch starts with ^ or .* so that -"first char" processing can be done to speed things up in multiline -matching and for non-DOTALL patterns that start with .* (which must start at -the beginning or after \n) - -Except when the .* appears inside capturing parentheses, and there is a -subsequent back reference to those parentheses. By keeping a bitmap of the -first 31 back references, we can catch some of the more common cases more -precisely; all the greater back references share a single bit. - -Arguments: - code points to start of expression (the bracket) - captureMap a bitmap of which brackets we are inside while testing; this - handles up to substring 31; all brackets after that share - the zero bit - backrefMap the back reference bitmap -*/ - -static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) -{ - const unsigned char* scode = firstSignificantOpcode(code); - int op = *scode; - - /* Capturing brackets */ - if (op > OP_BRA) { - int captureNum = op - OP_BRA; - if (captureNum > EXTRACT_BASIC_MAX) - captureNum = get2ByteValue(scode + 2 + LINK_SIZE); - int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1; - return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap); - } - - /* Other brackets */ - if (op == OP_BRA || op == OP_ASSERT) - return bracketNeedsLineStart(scode, captureMap, backrefMap); - - /* .* means "start at start or after \n" if it isn't in brackets that - may be referenced. */ - - if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) - return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap); - - /* Explicit ^ */ - return op == OP_CIRC || op == OP_BOL; -} - -static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) -{ - do { - if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap)) - return false; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); /* Loop for each alternative */ - return true; -} - -/************************************************* -* Check for asserted fixed first char * -*************************************************/ - -/* During compilation, the "first char" settings from forward assertions are -discarded, because they can cause conflicts with actual literals that follow. -However, if we end up without a first char setting for an unanchored pattern, -it is worth scanning the regex to see if there is an initial asserted first -char. If all branches start with the same asserted char, or with a bracket all -of whose alternatives start with the same asserted char (recurse ad lib), then -we return that char, otherwise -1. - -Arguments: - code points to start of expression (the bracket) - options pointer to the options (used to check casing changes) - inassert true if in an assertion - -Returns: -1 or the fixed first char -*/ - -static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert) -{ - const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code); - int op = *scode; - - if (op >= OP_BRA) - op = OP_BRA; - - switch (op) { - default: - return -1; - - case OP_BRA: - case OP_ASSERT: - return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT); - - case OP_EXACT: - scode += 2; - /* Fall through */ - - case OP_CHAR: - case OP_CHAR_IGNORING_CASE: - case OP_ASCII_CHAR: - case OP_ASCII_LETTER_IGNORING_CASE: - case OP_PLUS: - case OP_MINPLUS: - if (!inassert) - return -1; - return scode[1]; - } -} - -static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert) -{ - int c = -1; - do { - int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert); - if (d < 0) - return -1; - if (c < 0) - c = d; - else if (c != d) - return -1; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); - return c; -} - -static inline int multiplyWithOverflowCheck(int a, int b) -{ - if (!a || !b) - return 0; - if (a > MAX_PATTERN_SIZE / b) - return -1; - return a * b; -} - -static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase, - CompileData& cd, ErrorCode& errorcode) -{ - /* Make a pass over the pattern to compute the - amount of store required to hold the compiled code. This does not have to be - perfect as long as errors are overestimates. */ - - if (patternLength > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - - int length = BRA_LEN; /* For initial BRA. */ - int branch_extra = 0; - int lastitemlength = 0; - unsigned brastackptr = 0; - int brastack[BRASTACK_SIZE]; - unsigned char bralenstack[BRASTACK_SIZE]; - int bracount = 0; - - const UChar* ptr = (const UChar*)(pattern - 1); - const UChar* patternEnd = (const UChar*)(pattern + patternLength); - - while (++ptr < patternEnd) { - int minRepeats = 0, maxRepeats = 0; - int c = *ptr; - - switch (c) { - /* A backslashed item may be an escaped data character or it may be a - character type. */ - - case '\\': - c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false); - if (errorcode != 0) - return -1; - - lastitemlength = 1; /* Default length of last item for repeats */ - - if (c >= 0) { /* Data character */ - length += 2; /* For a one-byte character */ - - if (c > 127) { - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (c <= jsc_pcre_utf8_table1[i]) break; - length += i; - lastitemlength += i; - } - - continue; - } - - /* Other escapes need one byte */ - - length++; - - /* A back reference needs an additional 2 bytes, plus either one or 5 - bytes for a repeat. We also need to keep the value of the highest - back reference. */ - - if (c <= -ESC_REF) { - int refnum = -c - ESC_REF; - cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1; - if (refnum > cd.topBackref) - cd.topBackref = refnum; - length += 2; /* For single back reference */ - if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode) - return -1; - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - else - length += 5; - if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; - } - } - continue; - - case '^': /* Single-byte metacharacters */ - case '.': - case '$': - length++; - lastitemlength = 1; - continue; - - case '*': /* These repeats won't be after brackets; */ - case '+': /* those are handled separately */ - case '?': - length++; - goto POSSESSIVE; - - /* This covers the cases of braced repeats after a single char, metachar, - class, or back reference. */ - - case '{': - if (!isCountedRepeat(ptr + 1, patternEnd)) - goto NORMAL_CHAR; - ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode); - if (errorcode != 0) - return -1; - - /* These special cases just insert one extra opcode */ - - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - - /* These cases might insert additional copies of a preceding character. */ - - else { - if (minRepeats != 1) { - length -= lastitemlength; /* Uncount the original char or metachar */ - if (minRepeats > 0) - length += 5 + lastitemlength; - } - length += lastitemlength + ((maxRepeats > 0) ? 5 : 1); - } - - if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; /* Needs no extra length */ - - POSSESSIVE: /* Test for possessive quantifier */ - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */ - } - continue; - - /* An alternation contains an offset to the next branch or ket. If any ims - options changed in the previous branch(es), and/or if we are in a - lookbehind assertion, extra space will be needed at the start of the - branch. This is handled by branch_extra. */ - - case '|': - if (brastackptr == 0) - cd.needOuterBracket = true; - length += 1 + LINK_SIZE + branch_extra; - continue; - - /* A character class uses 33 characters provided that all the character - values are less than 256. Otherwise, it uses a bit map for low valued - characters, and individual items for others. Don't worry about character - types that aren't allowed in classes - they'll get picked up during the - compile. A character class that contains only one single-byte character - uses 2 or 3 bytes, depending on whether it is negated or not. Notice this - where we can. (In UTF-8 mode we can do this only for chars < 128.) */ - - case '[': { - int class_optcount; - if (*(++ptr) == '^') { - class_optcount = 10; /* Greater than one */ - ptr++; - } - else - class_optcount = 0; - - bool class_utf8 = false; - - for (; ptr < patternEnd && *ptr != ']'; ++ptr) { - /* Check for escapes */ - - if (*ptr == '\\') { - c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); - if (errorcode != 0) - return -1; - - /* Handle escapes that turn into characters */ - - if (c >= 0) - goto NON_SPECIAL_CHARACTER; - - /* Escapes that are meta-things. The normal ones just affect the - bit map, but Unicode properties require an XCLASS extended item. */ - - else - class_optcount = 10; /* \d, \s etc; make sure > 1 */ - } - - /* Anything else increments the possible optimization count. We have to - detect ranges here so that we can compute the number of extra ranges for - caseless wide characters when UCP support is available. If there are wide - characters, we are going to have to use an XCLASS, even for single - characters. */ - - else { - c = *ptr; - - /* Come here from handling \ above when it escapes to a char value */ - - NON_SPECIAL_CHARACTER: - class_optcount++; - - int d = -1; - if (safelyCheckNextChar(ptr, patternEnd, '-')) { - const UChar* hyptr = ptr++; - if (safelyCheckNextChar(ptr, patternEnd, '\\')) { - ptr++; - d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); - if (errorcode != 0) - return -1; - } - else if ((ptr + 1 < patternEnd) && ptr[1] != ']') - d = *++ptr; - if (d < 0) - ptr = hyptr; /* go back to hyphen as data */ - } - - /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or > - 127 for caseless matching, we will need to use an XCLASS. */ - - if (d >= 0) { - class_optcount = 10; /* Ensure > 1 */ - if (d < c) { - errorcode = ERR8; - return -1; - } - - if ((d > 255 || (ignoreCase && d > 127))) { - unsigned char buffer[6]; - if (!class_utf8) /* Allow for XCLASS overhead */ - { - class_utf8 = true; - length += LINK_SIZE + 2; - } - - /* If we have UCP support, find out how many extra ranges are - needed to map the other case of characters within this range. We - have to mimic the range optimization here, because extending the - range upwards might push d over a boundary that makes it use - another byte in the UTF-8 representation. */ - - if (ignoreCase) { - int occ, ocd; - int cc = c; - int origd = d; - while (getOthercaseRange(&cc, origd, &occ, &ocd)) { - if (occ >= c && ocd <= d) - continue; /* Skip embedded */ - - if (occ < c && ocd >= c - 1) /* Extend the basic range */ - { /* if there is overlap, */ - c = occ; /* noting that if occ < c */ - continue; /* we can't have ocd > d */ - } /* because a subrange is */ - if (ocd > d && occ <= d + 1) /* always shorter than */ - { /* the basic range. */ - d = ocd; - continue; - } - - /* An extra item is needed */ - - length += 1 + encodeUTF8(occ, buffer) + - ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer)); - } - } - - /* The length of the (possibly extended) range */ - - length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer); - } - - } - - /* We have a single character. There is nothing to be done unless we - are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must - allow for an XCL_SINGLE item, doubled for caselessness if there is UCP - support. */ - - else { - if ((c > 255 || (ignoreCase && c > 127))) { - unsigned char buffer[6]; - class_optcount = 10; /* Ensure > 1 */ - if (!class_utf8) /* Allow for XCLASS overhead */ - { - class_utf8 = true; - length += LINK_SIZE + 2; - } - length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer)); - } - } - } - } - - if (ptr >= patternEnd) { /* Missing terminating ']' */ - errorcode = ERR6; - return -1; - } - - /* We can optimize when there was only one optimizable character. - Note that this does not detect the case of a negated single character. - In that case we do an incorrect length computation, but it's not a serious - problem because the computed length is too large rather than too small. */ - - if (class_optcount == 1) - goto NORMAL_CHAR; - - /* Here, we handle repeats for the class opcodes. */ - { - length += 33; - - /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, - we also need extra for wrapping the whole thing in a sub-pattern. */ - - if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode != 0) - return -1; - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - else - length += 5; - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; - } else if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; - } - } - continue; - } - - /* Brackets may be genuine groups or special things */ - - case '(': { - int branch_newextra = 0; - int bracket_length = BRA_LEN; - bool capturing = false; - - /* Handle special forms of bracket, which all start (? */ - - if (safelyCheckNextChar(ptr, patternEnd, '?')) { - switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) { - /* Non-referencing groups and lookaheads just move the pointer on, and - then behave like a non-special bracket, except that they don't increment - the count of extracting brackets. Ditto for the "once only" bracket, - which is in Perl from version 5.005. */ - - case ':': - case '=': - case '!': - ptr += 2; - break; - - /* Else loop checking valid options until ) is met. Anything else is an - error. If we are without any brackets, i.e. at top level, the settings - act as if specified in the options, so massage the options immediately. - This is for backward compatibility with Perl 5.004. */ - - default: - errorcode = ERR12; - return -1; - } - } else - capturing = true; - - /* Capturing brackets must be counted so we can process escapes in a - Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need - an additional 3 bytes of memory per capturing bracket. */ - - if (capturing) { - bracount++; - if (bracount > EXTRACT_BASIC_MAX) - bracket_length += 3; - } - - /* Save length for computing whole length at end if there's a repeat that - requires duplication of the group. Also save the current value of - branch_extra, and start the new group with the new value. If non-zero, this - will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ - - if (brastackptr >= sizeof(brastack)/sizeof(int)) { - errorcode = ERR17; - return -1; - } - - bralenstack[brastackptr] = branch_extra; - branch_extra = branch_newextra; - - brastack[brastackptr++] = length; - length += bracket_length; - continue; - } - - /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we - have to replicate this bracket up to that many times. If brastackptr is - 0 this is an unmatched bracket which will generate an error, but take care - not to try to access brastack[-1] when computing the length and restoring - the branch_extra value. */ - - case ')': { - int duplength; - length += KET_LEN; - if (brastackptr > 0) { - duplength = length - brastack[--brastackptr]; - branch_extra = bralenstack[brastackptr]; - } - else - duplength = 0; - - /* Leave ptr at the final char; for readRepeatCounts this happens - automatically; for the others we need an increment. */ - - if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode) - return -1; - } else if (c == '*') { - minRepeats = 0; - maxRepeats = -1; - ptr++; - } else if (c == '+') { - minRepeats = 1; - maxRepeats = -1; - ptr++; - } else if (c == '?') { - minRepeats = 0; - maxRepeats = 1; - ptr++; - } else { - minRepeats = 1; - maxRepeats = 1; - } - - /* If the minimum is zero, we have to allow for an OP_BRAZERO before the - group, and if the maximum is greater than zero, we have to replicate - maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting - bracket set. */ - - int repeatsLength; - if (minRepeats == 0) { - length++; - if (maxRepeats > 0) { - repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + BRA_LEN + KET_LEN + OPCODE_LEN); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength; - if (length > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - } - } - - /* When the minimum is greater than zero, we have to replicate up to - minval-1 times, with no additions required in the copies. Then, if there - is a limited maximum we have to replicate up to maxval-1 times allowing - for a BRAZERO item before each optional copy and nesting brackets for all - but one of the optional copies. */ - - else { - repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength; - if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */ - repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + BRAZERO_LEN + BRA_LEN + KET_LEN); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength - (2 + 2 * LINK_SIZE); - } - if (length > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - } - - /* Allow space for once brackets for "possessive quantifier" */ - - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; - } - continue; - } - - /* Non-special character. It won't be space or # in extended mode, so it is - always a genuine character. If we are in a \Q...\E sequence, check for the - end; if not, we have a literal. */ - - default: - NORMAL_CHAR: - length += 2; /* For a one-byte character */ - lastitemlength = 1; /* Default length of last item for repeats */ - - if (c > 127) { - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (c <= jsc_pcre_utf8_table1[i]) - break; - length += i; - lastitemlength += i; - } - - continue; - } - } - - length += KET_LEN + OPCODE_LEN; /* For final KET and END */ - - cd.numCapturingBrackets = bracount; - return length; -} - -/************************************************* -* Compile a Regular Expression * -*************************************************/ - -/* This function takes a string and returns a pointer to a block of store -holding a compiled version of the expression. The original API for this -function had no error code return variable; it is retained for backwards -compatibility. The new function is given a new name. - -Arguments: - pattern the regular expression - options various option bits - errorCodePtr pointer to error code variable (pcre_compile2() only) - can be NULL if you don't want a code value - error pointer to pointer to error text - erroroffset ptr offset in pattern where error was detected - tables pointer to character tables or NULL - -Returns: pointer to compiled data block, or NULL on error, - with error and erroroffset set -*/ - -static inline JSRegExp* returnError(ErrorCode errorcode, int *error) -{ - *error = static_cast(errorcode); - return 0; -} - -JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, - JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline, - unsigned* numSubpatterns, int *error) -{ - /* We can't pass back an error message if error is NULL; I guess the best we - can do is just return NULL, but we can set a code value if there is a code pointer. */ - if (!error) - return 0; - *error = 0; - - CompileData cd; - - ErrorCode errorcode = ERR0; - /* Call this once just to count the brackets. */ - calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); - /* Call it again to compute the length. */ - int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); - if (errorcode) - return returnError(errorcode, error); - - if (length > MAX_PATTERN_SIZE) - return returnError(ERR16, error); - - size_t size = length + sizeof(JSRegExp); - JSRegExp* re = reinterpret_cast(js::OffTheBooks::array_new(size)); - if (!re) - return returnError(ERR13, error); - - re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0); - - /* The starting points of the name/number translation table and of the code are - passed around in the compile data block. */ - - const unsigned char* codeStart = (const unsigned char*)(re + 1); - - /* Set up a starting, non-extracting bracket, then compile the expression. On - error, errorcode will be set non-zero, so we don't need to look at the result - of the function here. */ - - const UChar* ptr = (const UChar*)pattern; - const UChar* patternEnd = pattern + patternLength; - unsigned char* code = const_cast(codeStart); - int firstByte, reqByte; - int bracketCount = 0; - if (!cd.needOuterBracket) - compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstByte, &reqByte, cd); - else { - *code = OP_BRA; - unsigned char * const codeBefore = code; - compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 2, &firstByte, &reqByte, cd); - JS_ASSERT((bracketCount & 0xff) == bracketCount); - put2ByteValue(codeBefore + 1 + LINK_SIZE, 0 << 8 | (bracketCount & 0xff)); - } - re->topBracket = bracketCount; - re->topBackref = cd.topBackref; - - /* If not reached end of pattern on success, there's an excess bracket. */ - - if (errorcode == 0 && ptr < patternEnd) - errorcode = ERR10; - - /* Fill in the terminating state and check for disastrous overflow, but - if debugging, leave the test till after things are printed out. */ - - *code++ = OP_END; - - JS_ASSERT(code - codeStart <= length); - if (code - codeStart > length) - errorcode = ERR7; - - /* Give an error if there's back reference to a non-existent capturing - subpattern. */ - - if (re->topBackref > re->topBracket) - errorcode = ERR15; - - /* Failed to compile, or error while post-processing */ - - if (errorcode != ERR0) { - js::Foreground::array_delete(reinterpret_cast(re)); - return returnError(errorcode, error); - } - - /* If the anchored option was not passed, set the flag if we can determine that - the pattern is anchored by virtue of ^ characters or \A or anything else (such - as starting with .* when DOTALL is set). - - Otherwise, if we know what the first character has to be, save it, because that - speeds up unanchored matches no end. If not, see if we can set the - UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches - start with ^. and also when all branches start with .* for non-DOTALL matches. - */ - - if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart)) - re->options |= IsAnchoredOption; - else { - if (firstByte < 0) { - firstByte = (cd.needOuterBracket - ? bracketFindFirstAssertedCharacter(codeStart, false) - : branchFindFirstAssertedCharacter(codeStart, false)) - | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0); - } - if (firstByte >= 0) { - int ch = firstByte & 255; - if (ch < 127) { - re->firstByte = ((firstByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstByte; - re->options |= UseFirstByteOptimizationOption; - } - } else { - if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap)) - re->options |= UseMultiLineFirstByteOptimizationOption; - } - } - - /* For an anchored pattern, we use the "required byte" only if it follows a - variable length item in the regex. Remove the caseless flag for non-caseable - bytes. */ - - if (reqByte >= 0 && (!(re->options & IsAnchoredOption) || (reqByte & REQ_VARY))) { - int ch = reqByte & 255; - if (ch < 127) { - re->reqByte = ((reqByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqByte & ~REQ_IGNORE_CASE) : reqByte; - re->options |= UseRequiredByteOptimizationOption; - } - } - - if (numSubpatterns) - *numSubpatterns = re->topBracket; - - return re; -} - -void jsRegExpFree(JSRegExp* re) -{ - js::Foreground::array_delete(reinterpret_cast(re)); -} diff --git a/js/src/yarr/pcre/pcre_exec.cpp b/js/src/yarr/pcre/pcre_exec.cpp deleted file mode 100644 index c2d154d67b8e..000000000000 --- a/js/src/yarr/pcre/pcre_exec.cpp +++ /dev/null @@ -1,2193 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - Copyright (C) 2007 Eric Seidel - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains jsRegExpExecute(), the externally visible function -that does pattern matching using an NFA algorithm, following the rules from -the JavaScript specification. There are also some supporting functions. */ - -#include "pcre_internal.h" - -#include -#include "yarr/jswtfbridge.h" -#include "yarr/wtf/ASCIICType.h" -#include "jsarena.h" -#include "jscntxt.h" - -using namespace WTF; - -#if !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO -#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION -#endif - -/* Note: Webkit sources have USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP disabled. */ -/* Note: There are hardcoded constants all over the place, but in the port of - Yarr to TraceMonkey two bytes are added to the OP_BRA* opcodes, so the - instruction stream now looks like this at the start of a bracket group: - - OP_BRA* [link:LINK_SIZE] [minNestedBracket,maxNestedBracket:2] - - Both capturing and non-capturing brackets encode this information. */ - -/* Avoid warnings on Windows. */ -#undef min -#undef max - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION -typedef int ReturnLocation; -#else -typedef void* ReturnLocation; -#endif - -/* Node on a stack of brackets. This is used to detect and reject - matches of the empty string per ECMAScript repeat match rules. This - also prevents infinite loops on quantified empty matches. One node - represents the start state at the start of this bracket group. */ -struct BracketChainNode { - BracketChainNode* previousBracket; - const UChar* bracketStart; - /* True if the minimum number of matches was already satisfied - when we started matching this group. */ - bool minSatisfied; -}; - -struct MatchFrame { - ReturnLocation returnLocation; - struct MatchFrame* previousFrame; - int *savedOffsets; - /* The frame allocates saved offsets into the regular expression arena pool so - that they can be restored during backtracking. */ - size_t savedOffsetsSize; - JSArenaPool *regExpPool; - - MatchFrame() : savedOffsetsSize(0), regExpPool(0) {} - void init(JSArenaPool *regExpPool) { this->regExpPool = regExpPool; } - - /* Function arguments that may change */ - struct { - const UChar* subjectPtr; - const unsigned char* instructionPtr; - int offsetTop; - BracketChainNode* bracketChain; - } args; - - - /* PCRE uses "fake" recursion built off of gotos, thus - stack-based local variables are not safe to use. Instead we have to - store local variables on the current MatchFrame. */ - struct { - const unsigned char* data; - const unsigned char* startOfRepeatingBracket; - const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare - const unsigned char* instructionPtrAtStartOfOnce; - - int repeatOthercase; - int savedSubjectOffset; - - int ctype; - int fc; - int fi; - int length; - int max; - int number; - int offset; - int skipBytes; - int minBracket; - int limitBracket; - int bracketsBefore; - bool minSatisfied; - - BracketChainNode bracketChainNode; - } locals; - - void saveOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - JS_ASSERT(regExpPool); - JS_ASSERT(minBracket >= 0); - JS_ASSERT(limitBracket >= minBracket); - JS_ASSERT(offsetEnd >= 0); - if (minBracket == limitBracket) - return; - const size_t newSavedOffsetCount = 3 * (limitBracket - minBracket); - /* Increase saved offset space if necessary. */ - { - size_t targetSize = sizeof(*savedOffsets) * newSavedOffsetCount; - if (savedOffsetsSize < targetSize) { - JS_ARENA_ALLOCATE_CAST(savedOffsets, int *, regExpPool, targetSize); - JS_ASSERT(savedOffsets); /* FIXME: error code, bug 574459. */ - savedOffsetsSize = targetSize; - } - } - for (unsigned i = 0; i < unsigned(limitBracket - minBracket); ++i) { - int bracketIter = minBracket + i; - JS_ASSERT(2 * bracketIter + 1 <= offsetEnd); - int start = offsets[2 * bracketIter]; - int end = offsets[2 * bracketIter + 1]; - JS_ASSERT(bracketIter <= offsetEnd); - int offset = offsets[offsetEnd - bracketIter]; - DPRINTF(("saving bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); - JS_ASSERT(start <= end); - JS_ASSERT(i * 3 + 2 < newSavedOffsetCount); - savedOffsets[i * 3 + 0] = start; - savedOffsets[i * 3 + 1] = end; - savedOffsets[i * 3 + 2] = offset; - } - } - - void clobberOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - for (int i = 0; i < limitBracket - minBracket; ++i) { - int bracketIter = minBracket + i; - JS_ASSERT(2 * bracketIter + 1 < offsetEnd); - offsets[2 * bracketIter + 0] = -1; - offsets[2 * bracketIter + 1] = -1; - } - } - - void restoreOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - JS_ASSERT(regExpPool); - JS_ASSERT_IF(limitBracket > minBracket, savedOffsets); - for (int i = 0; i < limitBracket - minBracket; ++i) { - int bracketIter = minBracket + i; - int start = savedOffsets[i * 3 + 0]; - int end = savedOffsets[i * 3 + 1]; - int offset = savedOffsets[i * 3 + 2]; - DPRINTF(("restoring bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); - JS_ASSERT(start <= end); - offsets[2 * bracketIter + 0] = start; - offsets[2 * bracketIter + 1] = end; - offsets[offsetEnd - bracketIter] = offset; - } - } - - /* Extract the bracket data after the current opcode/link at |instructionPtr| into the locals. */ - void extractBrackets(const unsigned char *instructionPtr) { - uint16 bracketMess = get2ByteValue(instructionPtr + 1 + LINK_SIZE); - locals.minBracket = (bracketMess >> 8) & 0xff; - locals.limitBracket = (bracketMess & 0xff); - JS_ASSERT(locals.minBracket <= locals.limitBracket); - } - - /* At the start of a bracketed group, add the current subject pointer to the - stack of such pointers, to be re-instated at the end of the group when we hit - the closing ket. When match() is called in other circumstances, we don't add to - this stack. */ - void startNewGroup(bool minSatisfied) { - locals.bracketChainNode.previousBracket = args.bracketChain; - locals.bracketChainNode.bracketStart = args.subjectPtr; - locals.bracketChainNode.minSatisfied = minSatisfied; - args.bracketChain = &locals.bracketChainNode; - } -}; - -/* Structure for passing "static" information around between the functions -doing traditional NFA matching, so that they are thread-safe. */ - -struct MatchData { - int *offsetVector; /* Offset vector */ - int offsetEnd; /* One past the end */ - int offsetMax; /* The maximum usable for return data */ - bool offsetOverflow; /* Set if too many extractions */ - const UChar *startSubject; /* Start of the subject string */ - const UChar *endSubject; /* End of the subject string */ - const UChar *endMatchPtr; /* Subject position at end match */ - int endOffsetTop; /* Highwater mark at end of match */ - bool multiline; - bool ignoreCase; - - void setOffsetPair(size_t pairNum, int start, int end) { - JS_ASSERT(int(2 * pairNum + 1) < offsetEnd && int(pairNum) < offsetEnd); - JS_ASSERT(start <= end); - JS_ASSERT_IF(start < 0, start == end && start == -1); - DPRINTF(("setting offset pair at %u (%d, %d)\n", pairNum, start, end)); - offsetVector[2 * pairNum + 0] = start; - offsetVector[2 * pairNum + 1] = end; - } -}; - -/* The maximum remaining length of subject we are prepared to search for a -reqByte match. */ - -#define REQ_BYTE_MAX 1000 - -/* The below limit restricts the number of "recursive" match calls in order to -avoid spending exponential time on complex regular expressions. */ - -static const unsigned matchLimit = 1000000; - -/************************************************* -* Match a back-reference * -*************************************************/ - -/* If a back reference hasn't been set, the length that is passed is greater -than the number of characters left in the string, so the match fails. - -Arguments: - offset index into the offset vector - subjectPtr points into the subject - length length to be matched - md points to match data block - -Returns: true if matched -*/ - -static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md) -{ - const UChar* p = md.startSubject + md.offsetVector[offset]; - - /* Always fail if not enough characters left */ - - if (length > md.endSubject - subjectPtr) - return false; - - /* Separate the caselesss case for speed */ - - if (md.ignoreCase) { - while (length-- > 0) { - UChar c = *p++; - int othercase = jsc_pcre_ucp_othercase(c); - UChar d = *subjectPtr++; - if (c != d && othercase != d) - return false; - } - } - else { - while (length-- > 0) - if (*p++ != *subjectPtr++) - return false; - } - - return true; -} - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - -/* Use numbered labels and switch statement at the bottom of the match function. */ - -#define RMATCH_WHERE(num) num -#define RRETURN_LABEL RRETURN_SWITCH - -#else - -/* Use GCC's computed goto extension. */ - -/* For one test case this is more than 40% faster than the switch statement. -We could avoid the use of the num argument entirely by using local labels, -but using it for the GCC case as well as the non-GCC case allows us to share -a bit more code and notice if we use conflicting numbers.*/ - -#define RMATCH_WHERE(num) JS_EXTENSION(&&RRETURN_##num) -#define RRETURN_LABEL *stack.currentFrame->returnLocation - -#endif - -#define RECURSIVE_MATCH_COMMON(num) \ - goto RECURSE;\ - RRETURN_##num: \ - stack.popCurrentFrame(); - -#define RECURSIVE_MATCH(num, ra, rb) \ - do { \ - stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ - RECURSIVE_MATCH_COMMON(num) \ - } while (0) - -#define RECURSIVE_MATCH_NEW_GROUP(num, ra, rb, gm) \ - do { \ - stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ - stack.currentFrame->startNewGroup(gm); \ - RECURSIVE_MATCH_COMMON(num) \ - } while (0) - -#define RRETURN do { JS_EXTENSION_(goto RRETURN_LABEL); } while (0) - -#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0) - -/************************************************* -* Match from current position * -*************************************************/ - -/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character -in the subject string, while substringStart holds the value of subjectPtr at the start of the -last bracketed group - used for breaking infinite loops matching zero-length -strings. This function is called recursively in many circumstances. Whenever it -returns a negative (error) response, the outer match() call must also return the -same response. - -Arguments: - subjectPtr pointer in subject - instructionPtr position in code - offsetTop current top pointer - md pointer to "static" info for the match - -Returns: 1 if matched ) these values are >= 0 - 0 if failed to match ) - a negative error value if aborted by an error condition - (e.g. stopped by repeated call or recursion limit) -*/ - -static const unsigned numFramesOnStack = 16; - -struct MatchStack { - JSArenaPool *regExpPool; - void *regExpPoolMark; - - MatchStack(JSArenaPool *regExpPool) - : regExpPool(regExpPool) - , regExpPoolMark(JS_ARENA_MARK(regExpPool)) - , framesEnd(frames + numFramesOnStack) - , currentFrame(frames) - , size(1) // match() creates accesses the first frame w/o calling pushNewFrame - { - JS_ASSERT((sizeof(frames) / sizeof(frames[0])) == numFramesOnStack); - JS_ASSERT(regExpPool); - for (size_t i = 0; i < numFramesOnStack; ++i) - frames[i].init(regExpPool); - } - - ~MatchStack() { JS_ARENA_RELEASE(regExpPool, regExpPoolMark); } - - MatchFrame frames[numFramesOnStack]; - MatchFrame* framesEnd; - MatchFrame* currentFrame; - unsigned size; - - bool canUseStackBufferForNextFrame() { - return size < numFramesOnStack; - } - - MatchFrame* allocateNextFrame() { - if (canUseStackBufferForNextFrame()) - return currentFrame + 1; - // FIXME: bug 574459 -- no NULL check - MatchFrame *frame = js::OffTheBooks::new_(); - frame->init(regExpPool); - return frame; - } - - void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation) { - MatchFrame* newframe = allocateNextFrame(); - newframe->previousFrame = currentFrame; - - newframe->args.subjectPtr = currentFrame->args.subjectPtr; - newframe->args.offsetTop = currentFrame->args.offsetTop; - newframe->args.instructionPtr = instructionPtr; - newframe->args.bracketChain = bracketChain; - newframe->returnLocation = returnLocation; - size++; - - currentFrame = newframe; - } - - void popCurrentFrame() { - MatchFrame* oldFrame = currentFrame; - currentFrame = currentFrame->previousFrame; - if (size > numFramesOnStack) - js::Foreground::delete_(oldFrame); - size--; - } - - void popAllFrames() { - while (size) - popCurrentFrame(); - } -}; - -static int matchError(int errorCode, MatchStack& stack) -{ - stack.popAllFrames(); - return errorCode; -} - -/* Get the next UTF-8 character, not advancing the pointer, incrementing length - if there are extra bytes. This is called when we know we are in UTF-8 mode. */ - -static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len) -{ - c = *subjectPtr; - if ((c & 0xc0) == 0xc0) { - int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ - int gcss = 6 * gcaa; - c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; - for (int gcii = 1; gcii <= gcaa; gcii++) { - gcss -= 6; - c |= (subjectPtr[gcii] & 0x3f) << gcss; - } - len += gcaa; - } -} - -static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats) -{ - // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR - static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 }; - static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 }; - - JS_ASSERT(instructionOffset >= 0); - JS_ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR)); - - minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2 - minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset]; - maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset]; -} - -/* Helper class for passing a flag value from one op to the next that runs. - This allows us to set the flag in certain ops. When the flag is read, it - will be true only if the previous op set the flag, otherwise it is false. */ -class LinearFlag { -public: - LinearFlag() : flag(false) {} - - bool readAndClear() { - bool rv = flag; - flag = false; - return rv; - } - - void set() { - flag = true; - } - -private: - bool flag; -}; - -static int -match(JSArenaPool *regExpPool, const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md) -{ - bool isMatch = false; - int min; - bool minimize = false; /* Initialization not really needed, but some compilers think so. */ - unsigned remainingMatchCount = matchLimit; - int othercase; /* Declare here to avoid errors during jumps */ - bool minSatisfied; - - MatchStack stack(regExpPool); - LinearFlag minSatNextBracket; - - /* The opcode jump table. */ -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP -#define EMIT_JUMP_TABLE_ENTRY(opcode) JS_EXTENSION(&&LABEL_OP_##opcode) - static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) }; -#undef EMIT_JUMP_TABLE_ENTRY -#endif - - /* One-time setup of the opcode jump table. */ -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - for (int i = 255; !opcodeJumpTable[i]; i--) - opcodeJumpTable[i] = &&CAPTURING_BRACKET; -#endif - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - // Shark shows this as a hot line - // Using a static const here makes this line disappear, but makes later access hotter (not sure why) - stack.currentFrame->returnLocation = JS_EXTENSION(&&RETURN); -#else - stack.currentFrame->returnLocation = 0; -#endif - stack.currentFrame->args.subjectPtr = subjectPtr; - stack.currentFrame->args.instructionPtr = instructionPtr; - stack.currentFrame->args.offsetTop = offsetTop; - stack.currentFrame->args.bracketChain = 0; - stack.currentFrame->startNewGroup(false); - - /* This is where control jumps back to to effect "recursion" */ - -RECURSE: - if (!--remainingMatchCount) - return matchError(JSRegExpErrorHitLimit, stack); - - /* Now start processing the operations. */ - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - while (true) -#endif - { - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP -#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode -#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr] -#else -#define BEGIN_OPCODE(opcode) case OP_##opcode -#define NEXT_OPCODE continue -#endif -#define LOCALS(__ident) (stack.currentFrame->locals.__ident) - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - NEXT_OPCODE; -#else - switch (*stack.currentFrame->args.instructionPtr) -#endif - { - /* Non-capturing bracket: optimized */ - - BEGIN_OPCODE(BRA): - NON_CAPTURING_BRACKET: - DPRINTF(("start non-capturing bracket\n")); - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); - /* If we see no ALT, we have to skip three bytes of bracket data (link plus nested - bracket data. */ - stack.currentFrame->locals.skipBytes = 3; - /* We must compute this value at the top, before we move the instruction pointer. */ - stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); - do { - /* We need to extract this into a variable so we can correctly pass it by value - through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ - minSatisfied = stack.currentFrame->locals.minSatisfied; - RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); - if (isMatch) { - DPRINTF(("non-capturing bracket succeeded\n")); - RRETURN; - } - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - DPRINTF(("non-capturing bracket failed\n")); - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - RRETURN; - - /* Skip over large extraction number data if encountered. */ - - BEGIN_OPCODE(BRANUMBER): - stack.currentFrame->args.instructionPtr += 3; - NEXT_OPCODE; - - /* End of the pattern. */ - - BEGIN_OPCODE(END): - md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */ - md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */ - isMatch = true; - RRETURN; - - /* Assertion brackets. Check the alternative branches in turn - the - matching won't pass the KET for an assertion. If any one branch matches, - the assertion is true. Lookbehind assertions have an OP_REVERSE item at the - start of each branch to move the current point backwards, so the code at - this level is identical to the lookahead case. */ - - BEGIN_OPCODE(ASSERT): - { - uint16 bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); - LOCALS(minBracket) = (bracketMess >> 8) & 0xff; - LOCALS(limitBracket) = bracketMess & 0xff; - JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); - } - stack.currentFrame->locals.skipBytes = 3; - do { - RECURSIVE_MATCH_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); - if (isMatch) - break; - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - if (*stack.currentFrame->args.instructionPtr == OP_KET) { - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - RRETURN_NO_MATCH; - } - - /* Continue from after the assertion, updating the offsets high water - mark, since extracts may have been taken during the assertion. */ - - advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); - stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; - stack.currentFrame->args.offsetTop = md.endOffsetTop; - NEXT_OPCODE; - - /* Negative assertion: all branches must fail to match */ - - BEGIN_OPCODE(ASSERT_NOT): - stack.currentFrame->locals.skipBytes = 3; - { - unsigned bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); - LOCALS(minBracket) = (bracketMess >> 8) & 0xff; - LOCALS(limitBracket) = bracketMess & 0xff; - } - JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); - do { - RECURSIVE_MATCH_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); - if (isMatch) - RRETURN_NO_MATCH; - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.skipBytes + LINK_SIZE; - NEXT_OPCODE; - - /* An alternation is the end of a branch; scan along to find the end of the - bracketed group and go to there. */ - - BEGIN_OPCODE(ALT): - advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); - NEXT_OPCODE; - - /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating - that it may occur zero times. It may repeat infinitely, or not at all - - i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper - repeat limits are compiled as a number of copies, with the optional ones - preceded by BRAZERO or BRAMINZERO. */ - - BEGIN_OPCODE(BRAZERO): { - stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain, true); - if (isMatch) - RRETURN; - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); - stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE; - NEXT_OPCODE; - } - - BEGIN_OPCODE(BRAMINZERO): { - stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; - advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); - RECURSIVE_MATCH_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain, false); - if (isMatch) - RRETURN; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - } - - /* End of a group, repeated or non-repeating. If we are at the end of - an assertion "group", stop matching and return 1, but record the - current high water mark for use by positive assertions. Do this also - for the "once" (not-backup up) groups. */ - - BEGIN_OPCODE(KET): - BEGIN_OPCODE(KETRMIN): - BEGIN_OPCODE(KETRMAX): - stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart; - stack.currentFrame->locals.minSatisfied = stack.currentFrame->args.bracketChain->minSatisfied; - - /* Back up the stack of bracket start pointers. */ - - stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket; - - if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) { - md.endOffsetTop = stack.currentFrame->args.offsetTop; - isMatch = true; - RRETURN; - } - - /* In all other cases except a conditional group we have to check the - group number back at the start and if necessary complete handling an - extraction by setting the offsets and bumping the high water mark. */ - - stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA; - - /* For extended extraction brackets (large number), we have to fish out - the number from a dummy opcode at the start. */ - - if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) - stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 4 + LINK_SIZE); - stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; - - DPRINTF(("end bracket %d\n", stack.currentFrame->locals.number)); - - /* Test for a numbered group. This includes groups called as a result - of recursion. Note that whole-pattern recursion is coded as a recurse - into group 0, so it won't be picked up here. Instead, we catch it when - the OP_END is reached. */ - - if (stack.currentFrame->locals.number > 0) { - if (stack.currentFrame->locals.offset >= md.offsetMax) - md.offsetOverflow = true; - else { - int start = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; - int end = stack.currentFrame->args.subjectPtr - md.startSubject; - if (start == end && stack.currentFrame->locals.minSatisfied) { - DPRINTF(("empty string while group already matched; bailing")); - RRETURN_NO_MATCH; - } - DPRINTF(("saving; start: %d; end: %d\n", start, end)); - JS_ASSERT(start <= end); - md.setOffsetPair(stack.currentFrame->locals.number, start, end); - if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset) - stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2; - } - } - - /* For a non-repeating ket, just continue at this level. This also - happens for a repeating ket if no characters were matched in the group. - This is the forcible breaking of infinite loops as implemented in Perl - 5.005. If there is an options reset, it will get obeyed in the normal - course of events. */ - - if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - DPRINTF(("non-repeating ket or empty match\n")); - if (stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction && stack.currentFrame->locals.minSatisfied) { - DPRINTF(("empty string while group already matched; bailing")); - RRETURN_NO_MATCH; - } - stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; - NEXT_OPCODE; - } - - /* The repeating kets try the rest of the pattern or restart from the - preceding bracket, in the appropriate order. */ - - stack.currentFrame->extractBrackets(LOCALS(instructionPtrAtStartOfOnce)); - JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); - if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) { - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - else - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - DPRINTF(("recursively matching lazy group\n")); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(17, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); - } else { /* OP_KETRMAX */ - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - stack.currentFrame->clobberOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - DPRINTF(("recursively matching greedy group\n")); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(18, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); - if (isMatch) - RRETURN; - else - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); - } - RRETURN; - - /* Start of subject. */ - - BEGIN_OPCODE(CIRC): - if (stack.currentFrame->args.subjectPtr != md.startSubject) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* After internal newline if multiline. */ - - BEGIN_OPCODE(BOL): - if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1])) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* End of subject. */ - - BEGIN_OPCODE(DOLL): - if (stack.currentFrame->args.subjectPtr < md.endSubject) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Before internal newline if multiline. */ - - BEGIN_OPCODE(EOL): - if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Word boundary assertions */ - - BEGIN_OPCODE(NOT_WORD_BOUNDARY): - BEGIN_OPCODE(WORD_BOUNDARY): { - bool currentCharIsWordChar = false; - bool previousCharIsWordChar = false; - - if (stack.currentFrame->args.subjectPtr > md.startSubject) - previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]); - if (stack.currentFrame->args.subjectPtr < md.endSubject) - currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr); - - /* Now see if the situation is what we want */ - bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY); - if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar) - RRETURN_NO_MATCH; - NEXT_OPCODE; - } - - /* Match a single character type; inline for speed */ - - BEGIN_OPCODE(NOT_NEWLINE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isNewline(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_DIGIT): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(DIGIT): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_WHITESPACE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isSpaceChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(WHITESPACE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_WORDCHAR): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isWordChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(WORDCHAR): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isWordChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Match a back reference, possibly repeatedly. Look past the end of the - item to see if there is repeat information following. The code is similar - to that for character classes, but repeated for efficiency. Then obey - similar code to character type repeats - written out again for speed. - However, if the referenced string is the empty string, always treat - it as matched, any number of times (otherwise there could be infinite - loops). */ - - BEGIN_OPCODE(REF): - stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */ - stack.currentFrame->args.instructionPtr += 3; /* Advance past item */ - - /* If the reference is unset, set the length to be longer than the amount - of subject left; this ensures that every attempt at a match fails. We - can't just fail here, because of the possibility of quantifiers with zero - minima. */ - - if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0) - stack.currentFrame->locals.length = 0; - else - stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset]; - - /* Set up for repetition, or handle the non-repeated case */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - NEXT_OPCODE; - } - - /* If the length of the reference is zero, just continue with the - main loop. */ - - if (stack.currentFrame->locals.length == 0) - NEXT_OPCODE; - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - - /* If min = max, continue at the same level without recursion. - They are not both allowed to be zero. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep trying and advancing the pointer */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - /* Control never reaches here */ - } - - /* If maximizing, find the longest string and work backwards */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - break; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - - /* Match a bit-mapped character class, possibly repeatedly. This op code is - used when all the characters in the class have values in the range 0-255, - and either the matching is caseful, or the characters are in the range - 0-127 when UTF-8 processing is enabled. The only difference between - OP_CLASS and OP_NCLASS occurs when a data character outside the range is - encountered. - - First, look past the end of the item to see if there is repeat information - following. Then obey similar code to character type repeats - written out - again for speed. */ - - BEGIN_OPCODE(NCLASS): - BEGIN_OPCODE(CLASS): - stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */ - stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - min = stack.currentFrame->locals.max = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int c = *stack.currentFrame->args.subjectPtr++; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - RRETURN_NO_MATCH; - } else { - if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) - RRETURN_NO_MATCH; - } - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - int c = *stack.currentFrame->args.subjectPtr++; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - RRETURN; - } else { - if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0) - RRETURN; - } - } - /* Control never reaches here */ - } - /* If maximizing, find the longest possible run, then work backwards. */ - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - break; - } else { - if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) - break; - } - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - /* Control never reaches here */ - - /* Match an extended character class. */ - - BEGIN_OPCODE(XCLASS): - stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */ - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - min = stack.currentFrame->locals.max = 1; - } - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int c = *stack.currentFrame->args.subjectPtr++; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - RRETURN_NO_MATCH; - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - int c = *stack.currentFrame->args.subjectPtr++; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - RRETURN; - } - /* Control never reaches here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - break; - ++stack.currentFrame->args.subjectPtr; - } - for(;;) { - RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - RRETURN; - } - - /* Control never reaches here */ - - /* Match a single character, casefully */ - - BEGIN_OPCODE(CHAR): - stack.currentFrame->locals.length = 1; - stack.currentFrame->args.instructionPtr++; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++) - RRETURN_NO_MATCH; - NEXT_OPCODE; - - /* Match a single character, caselessly */ - - BEGIN_OPCODE(CHAR_IGNORING_CASE): { - stack.currentFrame->locals.length = 1; - stack.currentFrame->args.instructionPtr++; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int dc = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fc != dc && jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc) - RRETURN_NO_MATCH; - NEXT_OPCODE; - } - - /* Match a single ASCII character. */ - - BEGIN_OPCODE(ASCII_CHAR): - if (md.endSubject == stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1]) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - stack.currentFrame->args.instructionPtr += 2; - NEXT_OPCODE; - - /* Match one of two cases of an ASCII letter. */ - - BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE): - if (md.endSubject == stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1]) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - stack.currentFrame->args.instructionPtr += 2; - NEXT_OPCODE; - - /* Match a single character repeatedly; different opcodes share code. */ - - BEGIN_OPCODE(EXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = false; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATCHAR; - - BEGIN_OPCODE(UPTO): - BEGIN_OPCODE(MINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATCHAR; - - BEGIN_OPCODE(STAR): - BEGIN_OPCODE(MINSTAR): - BEGIN_OPCODE(PLUS): - BEGIN_OPCODE(MINPLUS): - BEGIN_OPCODE(QUERY): - BEGIN_OPCODE(MINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single-character matches. We can give - up quickly if there are fewer than the minimum number of characters left in - the subject. */ - - REPEATCHAR: - - stack.currentFrame->locals.length = 1; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - - if (stack.currentFrame->locals.fc <= 0xFFFF) { - othercase = md.ignoreCase ? jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1; - - for (int i = 1; i <= min; i++) { - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - stack.currentFrame->locals.repeatOthercase = othercase; - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase) - RRETURN; - ++stack.currentFrame->args.subjectPtr; - } - /* Control never reaches here */ - } else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) - break; - ++stack.currentFrame->args.subjectPtr; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - --stack.currentFrame->args.subjectPtr; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - } else { - /* No case on surrogate pairs, so no need to bother with "othercase". */ - - for (int i = 1; i <= min; i++) { - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += 2; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - RRETURN; - stack.currentFrame->args.subjectPtr += 2; - } - /* Control never reaches here */ - } else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr > md.endSubject - 2) - break; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - break; - stack.currentFrame->args.subjectPtr += 2; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - stack.currentFrame->args.subjectPtr -= 2; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - } - /* Control never reaches here */ - - /* Match a negated single one-byte character. */ - - BEGIN_OPCODE(NOT): { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int b = stack.currentFrame->args.instructionPtr[1]; - int c = *stack.currentFrame->args.subjectPtr++; - stack.currentFrame->args.instructionPtr += 2; - if (md.ignoreCase) { - if (c < 128) - c = toLowerCase(c); - if (toLowerCase(b) == c) - RRETURN_NO_MATCH; - } else { - if (b == c) - RRETURN_NO_MATCH; - } - NEXT_OPCODE; - } - - /* Match a negated single one-byte character repeatedly. This is almost a - repeat of the code for a repeated single character, but I haven't found a - nice way of commoning these up that doesn't require a test of the - positive/negative option for each character match. Maybe that wouldn't add - very much to the time taken, but character matching *is* what this is all - about... */ - - BEGIN_OPCODE(NOTEXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = false; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATNOTCHAR; - - BEGIN_OPCODE(NOTUPTO): - BEGIN_OPCODE(NOTMINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATNOTCHAR; - - BEGIN_OPCODE(NOTSTAR): - BEGIN_OPCODE(NOTMINSTAR): - BEGIN_OPCODE(NOTPLUS): - BEGIN_OPCODE(NOTMINPLUS): - BEGIN_OPCODE(NOTQUERY): - BEGIN_OPCODE(NOTMINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single-byte matches. We can give up quickly - if there are fewer than the minimum number of bytes left in the - subject. */ - - REPEATNOTCHAR: - if (min > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++; - - /* The code is duplicated for the caseless and caseful cases, for speed, - since matching characters is likely to be quite common. First, ensure the - minimum number of matches are present. If min = max, continue at the same - level without recursing. Otherwise, if minimizing, keep trying the rest of - the expression and advancing one matching character if failing, up to the - maximum. Alternatively, if maximizing, find the maximum number of - characters and work backwards. */ - - DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max)); - - if (md.ignoreCase) { - if (stack.currentFrame->locals.fc < 128) - stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc); - - for (int i = 1; i <= min; i++) { - int d = *stack.currentFrame->args.subjectPtr++; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fc == d) - RRETURN_NO_MATCH; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - int d = *stack.currentFrame->args.subjectPtr++; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) - RRETURN; - } - /* Control never reaches here */ - } - - /* Maximize case */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int d = *stack.currentFrame->args.subjectPtr; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fc == d) - break; - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - /* Control never reaches here */ - } - - /* Caseful comparisons */ - - else { - for (int i = 1; i <= min; i++) { - int d = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fc == d) - RRETURN_NO_MATCH; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - int d = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) - RRETURN; - } - /* Control never reaches here */ - } - - /* Maximize case */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int d = *stack.currentFrame->args.subjectPtr; - if (stack.currentFrame->locals.fc == d) - break; - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - } - /* Control never reaches here */ - - /* Match a single character type repeatedly; several different opcodes - share code. This is very similar to the code for single characters, but we - repeat it in the interests of efficiency. */ - - BEGIN_OPCODE(TYPEEXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = true; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATTYPE; - - BEGIN_OPCODE(TYPEUPTO): - BEGIN_OPCODE(TYPEMINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATTYPE; - - BEGIN_OPCODE(TYPESTAR): - BEGIN_OPCODE(TYPEMINSTAR): - BEGIN_OPCODE(TYPEPLUS): - BEGIN_OPCODE(TYPEMINPLUS): - BEGIN_OPCODE(TYPEQUERY): - BEGIN_OPCODE(TYPEMINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single character type matches. Note that - in UTF-8 mode, '.' matches a character of any length, but for the other - character types, the valid characters are all one-byte long. */ - - REPEATTYPE: - stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */ - - /* First, ensure the minimum number of matches are present. Use inline - code for maximizing the speed, and do the type test once at the start - (i.e. keep it out of the loop). Also we can test that there are at least - the minimum number of characters before we start. */ - - if (min > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if (min > 0) { - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - for (int i = 1; i <= min; i++) { - if (isNewline(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_DIGIT: - for (int i = 1; i <= min; i++) { - if (isASCIIDigit(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_DIGIT: - for (int i = 1; i <= min; i++) { - if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WHITESPACE: - for (int i = 1; i <= min; i++) { - if (isSpaceChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WHITESPACE: - for (int i = 1; i <= min; i++) { - if (!isSpaceChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WORDCHAR: - for (int i = 1; i <= min; i++) { - if (isWordChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WORDCHAR: - for (int i = 1; i <= min; i++) { - if (!isWordChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } /* End switch(stack.currentFrame->locals.ctype) */ - } - - /* If min = max, continue at the same level without recursing */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, we have to test the rest of the pattern before each - subsequent match. */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - - int c = *stack.currentFrame->args.subjectPtr++; - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - if (isNewline(c)) - RRETURN; - break; - - case OP_NOT_DIGIT: - if (isASCIIDigit(c)) - RRETURN; - break; - - case OP_DIGIT: - if (!isASCIIDigit(c)) - RRETURN; - break; - - case OP_NOT_WHITESPACE: - if (isSpaceChar(c)) - RRETURN; - break; - - case OP_WHITESPACE: - if (!isSpaceChar(c)) - RRETURN; - break; - - case OP_NOT_WORDCHAR: - if (isWordChar(c)) - RRETURN; - break; - - case OP_WORDCHAR: - if (!isWordChar(c)) - RRETURN; - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } - } - /* Control never reaches here */ - } - - /* If maximizing it is worth using inline code for speed, doing the type - test once at the start (i.e. keep it out of the loop). */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */ - - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr)) - break; - stack.currentFrame->args.subjectPtr++; - } - break; - - case OP_NOT_DIGIT: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isASCIIDigit(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_DIGIT: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isASCIIDigit(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WHITESPACE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isSpaceChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WHITESPACE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isSpaceChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WORDCHAR: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isWordChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WORDCHAR: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isWordChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } - - /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */ - - for (;;) { - RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - /* Get here if we can't make it match with any permitted repetitions */ - - RRETURN; - } - /* Control never reaches here */ - - BEGIN_OPCODE(CRMINPLUS): - BEGIN_OPCODE(CRMINQUERY): - BEGIN_OPCODE(CRMINRANGE): - BEGIN_OPCODE(CRMINSTAR): - BEGIN_OPCODE(CRPLUS): - BEGIN_OPCODE(CRQUERY): - BEGIN_OPCODE(CRRANGE): - BEGIN_OPCODE(CRSTAR): - JS_NOT_REACHED("Invalid opcode."); - return matchError(JSRegExpErrorInternal, stack); - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - CAPTURING_BRACKET: -#else - default: -#endif - /* Opening capturing bracket. If there is space in the offset vector, save - the current subject position in the working slot at the top of the vector. We - mustn't change the current values of the data slot, because they may be set - from a previous iteration of this group, and be referred to by a reference - inside the group. - - If the bracket fails to match, we need to restore this value and also the - values of the final offsets, in case they were set by a previous iteration of - the same bracket. - - If there isn't enough space in the offset vector, treat this as if it were a - non-capturing bracket. Don't worry about setting the flag for the error case - here; that is handled in the code for KET. */ - - JS_ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA); - - LOCALS(number) = *stack.currentFrame->args.instructionPtr - OP_BRA; - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); - DPRINTF(("opening capturing bracket %d\n", stack.currentFrame->locals.number)); - - /* For extended extraction brackets (large number), we have to fish out the - number from a dummy opcode at the start. */ - - if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) - stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 4 + LINK_SIZE); - stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; - - JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); - - if (stack.currentFrame->locals.offset < md.offsetMax) { - stack.currentFrame->locals.savedSubjectOffset = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; - DPRINTF(("setting subject offset for bracket to %d\n", stack.currentFrame->args.subjectPtr - md.startSubject)); - md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject; - stack.currentFrame->locals.skipBytes = 3; /* For OP_BRAs. */ - - /* We must compute this value at the top, before we move the instruction pointer. */ - stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); - do { - /* We need to extract this into a variable so we can correctly pass it by value - through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ - minSatisfied = stack.currentFrame->locals.minSatisfied; - RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); - if (isMatch) - RRETURN; - stack.currentFrame->locals.skipBytes = 1; /* For OP_ALTs. */ - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - - DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number)); - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - DPRINTF(("restoring subject offset for bracket to %d\n", stack.currentFrame->locals.savedSubjectOffset)); - md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.savedSubjectOffset; - - RRETURN; - } - - /* Insufficient room for saving captured contents */ - - goto NON_CAPTURING_BRACKET; - } - - /* Do not stick any code in here without much thought; it is assumed - that "continue" in the code above comes out to here to repeat the main - loop. */ - - } /* End of main loop */ - - JS_NOT_REACHED("Loop does not fallthru."); - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - -RRETURN_SWITCH: - switch (stack.currentFrame->returnLocation) { - case 0: goto RETURN; - case 1: goto RRETURN_1; - case 2: goto RRETURN_2; - case 6: goto RRETURN_6; - case 7: goto RRETURN_7; - case 14: goto RRETURN_14; - case 15: goto RRETURN_15; - case 16: goto RRETURN_16; - case 17: goto RRETURN_17; - case 18: goto RRETURN_18; - case 19: goto RRETURN_19; - case 20: goto RRETURN_20; - case 21: goto RRETURN_21; - case 22: goto RRETURN_22; - case 24: goto RRETURN_24; - case 26: goto RRETURN_26; - case 27: goto RRETURN_27; - case 28: goto RRETURN_28; - case 29: goto RRETURN_29; - case 30: goto RRETURN_30; - case 31: goto RRETURN_31; - case 38: goto RRETURN_38; - case 40: goto RRETURN_40; - case 42: goto RRETURN_42; - case 44: goto RRETURN_44; - case 48: goto RRETURN_48; - case 52: goto RRETURN_52; - } - - JS_NOT_REACHED("Bad computed return location."); - return matchError(JSRegExpErrorInternal, stack); - -#endif - -RETURN: - return isMatch; -} - - -/************************************************* -* Execute a Regular Expression * -*************************************************/ - -/* This function applies a compiled re to a subject string and picks out -portions of the string if it matches. Two elements in the vector are set for -each substring: the offsets to the start and end of the substring. - -Arguments: - re points to the compiled expression - extra_data points to extra data or is NULL - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - offsets points to a vector of ints to be filled in with offsets - offsetCount the number of elements in the vector - -Returns: > 0 => success; value is the number of elements filled in - = 0 => success, but offsets is not big enough - -1 => failed to match - < -1 => some kind of unexpected problem -*/ - -static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int firstByte, bool firstByteIsCaseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart) -{ - // If firstByte is set, try scanning to the first instance of that byte - // no need to try and match against any earlier part of the subject string. - if (firstByte >= 0) { - UChar firstChar = firstByte; - if (firstByteIsCaseless) - while (subjectPtr < endSubject) { - int c = *subjectPtr; - if (c > 127) - break; - if (toLowerCase(c) == firstChar) - break; - subjectPtr++; - } - else { - while (subjectPtr < endSubject && *subjectPtr != firstChar) - subjectPtr++; - } - } else if (useMultiLineFirstCharOptimization) { - /* Or to just after \n for a multiline match if possible */ - // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07 - if (subjectPtr > originalSubjectStart) { - while (subjectPtr < endSubject && !isNewline(subjectPtr[-1])) - subjectPtr++; - } - } -} - -static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int reqByte, int reqByte2, bool reqByteIsCaseless, bool hasFirstByte, const UChar*& reqBytePtr) -{ - /* If reqByte is set, we know that that character must appear in the subject - for the match to succeed. If the first character is set, reqByte must be - later in the subject; otherwise the test starts at the match point. This - optimization can save a huge amount of backtracking in patterns with nested - unlimited repeats that aren't going to match. Writing separate code for - cased/caseless versions makes it go faster, as does using an autoincrement - and backing off on a match. - - HOWEVER: when the subject string is very, very long, searching to its end can - take a long time, and give bad performance on quite ordinary patterns. This - showed up when somebody was matching /^C/ on a 32-megabyte string... so we - don't do this when the string is sufficiently long. - */ - - if (reqByte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) { - const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0); - - /* We don't need to repeat the search if we haven't yet reached the - place we found it at last time. */ - - if (p > reqBytePtr) { - if (reqByteIsCaseless) { - while (p < endSubject) { - int pp = *p++; - if (pp == reqByte || pp == reqByte2) { - p--; - break; - } - } - } else { - while (p < endSubject) { - if (*p++ == reqByte) { - p--; - break; - } - } - } - - /* If we can't find the required character, break the matching loop */ - - if (p >= endSubject) - return true; - - /* If we have found the required character, save the point where we - found it, so that we don't search again next time round the loop if - the start hasn't passed this character yet. */ - - reqBytePtr = p; - } - } - return false; -} - -int jsRegExpExecute(JSContext *cx, const JSRegExp* re, - const UChar* subject, int length, int start_offset, int* offsets, - int offsetCount) -{ - JS_ASSERT(re); - JS_ASSERT(subject || !length); - JS_ASSERT(offsetCount >= 0); - JS_ASSERT(offsets || offsetCount == 0); - - MatchData matchBlock; - matchBlock.startSubject = subject; - matchBlock.endSubject = matchBlock.startSubject + length; - const UChar* endSubject = matchBlock.endSubject; - - matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption); - matchBlock.ignoreCase = (re->options & IgnoreCaseOption); - - /* Use the vector supplied, rounding down its size to a multiple of 3. */ - int ocount = offsetCount - (offsetCount % 3); - - matchBlock.offsetVector = offsets; - matchBlock.offsetEnd = ocount; - matchBlock.offsetMax = (2*ocount)/3; - matchBlock.offsetOverflow = false; - - /* Compute the minimum number of offsets that we need to reset each time. Doing - this makes a huge difference to execution time when there aren't many brackets - in the pattern. */ - - int resetCount = 2 + re->topBracket * 2; - if (resetCount > offsetCount) - resetCount = ocount; - - /* Reset the working variable associated with each extraction. These should - never be used unless previously set, but they get saved and restored, and so we - initialize them to avoid reading uninitialized locations. */ - - if (matchBlock.offsetVector) { - int* iptr = matchBlock.offsetVector + ocount; - int* iend = iptr - resetCount/2 + 1; - while (--iptr >= iend) - *iptr = -1; - } - - /* Set up the first character to match, if available. The firstByte value is - never set for an anchored regular expression, but the anchoring may be forced - at run time, so we have to test for anchoring. The first char may be unset for - an unanchored pattern, of course. If there's no first char and the pattern was - studied, there may be a bitmap of possible first characters. */ - - bool firstByteIsCaseless = false; - int firstByte = -1; - if (re->options & UseFirstByteOptimizationOption) { - firstByte = re->firstByte & 255; - if ((firstByteIsCaseless = (re->firstByte & REQ_IGNORE_CASE))) - firstByte = toLowerCase(firstByte); - } - - /* For anchored or unanchored matches, there may be a "last known required - character" set. */ - - bool reqByteIsCaseless = false; - int reqByte = -1; - int reqByte2 = -1; - if (re->options & UseRequiredByteOptimizationOption) { - reqByte = re->reqByte & 255; - reqByteIsCaseless = (re->reqByte & REQ_IGNORE_CASE); - reqByte2 = flipCase(reqByte); - } - - /* Loop for handling unanchored repeated matching attempts; for anchored regexs - the loop runs just once. */ - - const UChar* startMatch = subject + start_offset; - const UChar* reqBytePtr = startMatch - 1; - bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption; - - do { - /* Reset the maximum number of extractions we might see. */ - if (matchBlock.offsetVector) { - int* iptr = matchBlock.offsetVector; - int* iend = iptr + resetCount; - while (iptr < iend) - *iptr++ = -1; - } - - tryFirstByteOptimization(startMatch, endSubject, firstByte, firstByteIsCaseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset); - if (tryRequiredByteOptimization(startMatch, endSubject, reqByte, reqByte2, reqByteIsCaseless, firstByte >= 0, reqBytePtr)) - break; - - /* When a match occurs, substrings will be set for all internal extractions; - we just need to set up the whole thing as substring 0 before returning. If - there were too many extractions, set the return code to zero. In the case - where we had to get some local store to hold offsets for backreferences, copy - those back references that we can. In this case there need not be overflow - if certain parts of the pattern were not used. */ - - /* The code starts after the JSRegExp block and the capture name table. */ - const unsigned char* start_code = (const unsigned char*)(re + 1); - - int returnCode = match(&cx->regExpPool, startMatch, start_code, 2, matchBlock); - - /* When the result is no match, advance the pointer to the next character - and continue. */ - if (returnCode == 0) { - startMatch++; - continue; - } - - if (returnCode != 1) { - JS_ASSERT(returnCode == JSRegExpErrorHitLimit); - DPRINTF((">>>> error: returning %d\n", returnCode)); - return returnCode; - } - - /* We have a match! */ - - returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2; - - if (offsetCount < 2) - returnCode = 0; - else { - offsets[0] = startMatch - matchBlock.startSubject; - offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject; - } - - JS_ASSERT(returnCode >= 0); - DPRINTF((">>>> returning %d\n", returnCode)); - return returnCode; - } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject); - - DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); - return JSRegExpErrorNoMatch; -} diff --git a/js/src/yarr/pcre/pcre_internal.h b/js/src/yarr/pcre/pcre_internal.h deleted file mode 100644 index d677cfcfa255..000000000000 --- a/js/src/yarr/pcre/pcre_internal.h +++ /dev/null @@ -1,434 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This header contains definitions that are shared between the different -modules, but which are not relevant to the exported API. This includes some -functions whose names all begin with "_pcre_". */ - -#ifndef PCRE_INTERNAL_H -#define PCRE_INTERNAL_H - -/* Bit definitions for entries in the pcre_ctypes table. */ - -#define ctype_space 0x01 -#define ctype_xdigit 0x08 -#define ctype_word 0x10 /* alphameric or '_' */ - -/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set -of bits for a class map. Some classes are built by combining these tables. */ - -#define cbit_space 0 /* \s */ -#define cbit_digit 32 /* \d */ -#define cbit_word 64 /* \w */ -#define cbit_length 96 /* Length of the cbits table */ - -/* Offsets of the various tables from the base tables pointer, and -total length. */ - -#define lcc_offset 0 -#define fcc_offset 128 -#define cbits_offset 256 -#define ctypes_offset (cbits_offset + cbit_length) -#define tables_length (ctypes_offset + 128) - -#ifndef DFTABLES - -#include "pcre.h" - -/* The value of LINK_SIZE determines the number of bytes used to store links as -offsets within the compiled regex. The default is 2, which allows for compiled -patterns up to 64K long. */ - -#define LINK_SIZE 3 - -/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef -inline, and there are *still* stupid compilers about that don't like indented -pre-processor statements, or at least there were when I first wrote this. After -all, it had only been about 10 years then... */ - -#ifdef DEBUG -#define DPRINTF(p) /*printf p; fflush(stdout);*/ -#else -#define DPRINTF(p) /*nothing*/ -#endif - -/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored -in big-endian order) by default. These are used, for example, to link from the -start of a subpattern to its alternatives and its end. The use of 2 bytes per -offset limits the size of the compiled regex to around 64K, which is big enough -for almost everybody. However, I received a request for an even bigger limit. -For this reason, and also to make the code easier to maintain, the storing and -loading of offsets from the byte string is now handled by the functions that are -defined here. */ - -/* PCRE uses some other 2-byte quantities that do not change when the size of -offsets changes. There are used for repeat counts and for other things such as -capturing parenthesis numbers in back references. */ - -static inline void put2ByteValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value >= 0 && value <= 0xFFFF); - opcodePtr[0] = value >> 8; - opcodePtr[1] = value; -} - -static inline void put3ByteValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value >= 0 && value <= 0xFFFFFF); - opcodePtr[0] = value >> 16; - opcodePtr[1] = value >> 8; - opcodePtr[2] = value; -} - -static inline int get2ByteValue(const unsigned char* opcodePtr) -{ - return (opcodePtr[0] << 8) | opcodePtr[1]; -} - -static inline int get3ByteValue(const unsigned char* opcodePtr) -{ - return (opcodePtr[0] << 16) | (opcodePtr[1] << 8) | opcodePtr[2]; -} - -static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - put2ByteValue(opcodePtr, value); - opcodePtr += 2; -} - -static inline void put3ByteValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - put3ByteValue(opcodePtr, value); - opcodePtr += 3; -} - -static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value) -{ -#if LINK_SIZE == 3 - put3ByteValue(opcodePtr, value); -#elif LINK_SIZE == 2 - put2ByteValue(opcodePtr, value); -#else -# error LINK_SIZE not supported. -#endif -} - -static inline int getLinkValueAllowZero(const unsigned char* opcodePtr) -{ -#if LINK_SIZE == 3 - return get3ByteValue(opcodePtr); -#elif LINK_SIZE == 2 - return get2ByteValue(opcodePtr); -#else -# error LINK_SIZE not supported. -#endif -} - -#define MAX_PATTERN_SIZE 1024 * 1024 // Derived by empirical testing of compile time in PCRE and WREC. -JS_STATIC_ASSERT(MAX_PATTERN_SIZE < (1 << (8 * LINK_SIZE))); - -static inline void putLinkValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value); - putLinkValueAllowZero(opcodePtr, value); -} - -static inline int getLinkValue(const unsigned char* opcodePtr) -{ - int value = getLinkValueAllowZero(opcodePtr); - JS_ASSERT(value); - return value; -} - -static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - putLinkValue(opcodePtr, value); - opcodePtr += LINK_SIZE; -} - -static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value) -{ - putLinkValueAllowZero(opcodePtr, value); - opcodePtr += LINK_SIZE; -} - -// FIXME: These are really more of a "compiled regexp state" than "regexp options" -enum RegExpOptions { - UseFirstByteOptimizationOption = 0x40000000, /* firstByte is set */ - UseRequiredByteOptimizationOption = 0x20000000, /* reqByte is set */ - UseMultiLineFirstByteOptimizationOption = 0x10000000, /* start after \n for multiline */ - IsAnchoredOption = 0x02000000, /* can't use partial with this regex */ - IgnoreCaseOption = 0x00000001, - MatchAcrossMultipleLinesOption = 0x00000002 -}; - -/* Flags added to firstByte or reqByte; a "non-literal" item is either a -variable-length repeat, or a anything other than literal characters. */ - -#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */ -#define REQ_VARY 0x0200 /* reqByte followed non-literal item */ - -/* Miscellaneous definitions */ - -/* Flag bits and data types for the extended class (OP_XCLASS) for classes that -contain UTF-8 characters with values greater than 255. */ - -#define XCL_NOT 0x01 /* Flag: this is a negative class */ -#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ - -#define XCL_END 0 /* Marks end of individual items */ -#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ -#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ - -/* These are escaped items that aren't just an encoding of a particular data -value such as \n. They must have non-zero values, as check_escape() returns -their negation. Also, they must appear in the same order as in the opcode -definitions below, up to ESC_w. The final one must be -ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two -tests in the code for an escape > ESC_b and <= ESC_w to -detect the types that may be repeated. These are the types that consume -characters. If any new escapes are put in between that don't consume a -character, that code will have to change. */ - -enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF }; - -/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets -that extract substrings. Starting from 1 (i.e. after OP_END), the values up to -OP_EOD must correspond in order to the list of escapes immediately above. -Note that whenever this list is updated, the two macro definitions that follow -must also be updated to match. */ - -#define FOR_EACH_OPCODE(macro) \ - macro(END) \ - \ - , macro(NOT_WORD_BOUNDARY) \ - , macro(WORD_BOUNDARY) \ - , macro(NOT_DIGIT) \ - , macro(DIGIT) \ - , macro(NOT_WHITESPACE) \ - , macro(WHITESPACE) \ - , macro(NOT_WORDCHAR) \ - , macro(WORDCHAR) \ - \ - , macro(NOT_NEWLINE) \ - \ - , macro(CIRC) \ - , macro(DOLL) \ - , macro(BOL) \ - , macro(EOL) \ - , macro(CHAR) \ - , macro(CHAR_IGNORING_CASE) \ - , macro(ASCII_CHAR) \ - , macro(ASCII_LETTER_IGNORING_CASE) \ - , macro(NOT) \ - \ - , macro(STAR) \ - , macro(MINSTAR) \ - , macro(PLUS) \ - , macro(MINPLUS) \ - , macro(QUERY) \ - , macro(MINQUERY) \ - , macro(UPTO) \ - , macro(MINUPTO) \ - , macro(EXACT) \ - \ - , macro(NOTSTAR) \ - , macro(NOTMINSTAR) \ - , macro(NOTPLUS) \ - , macro(NOTMINPLUS) \ - , macro(NOTQUERY) \ - , macro(NOTMINQUERY) \ - , macro(NOTUPTO) \ - , macro(NOTMINUPTO) \ - , macro(NOTEXACT) \ - \ - , macro(TYPESTAR) \ - , macro(TYPEMINSTAR) \ - , macro(TYPEPLUS) \ - , macro(TYPEMINPLUS) \ - , macro(TYPEQUERY) \ - , macro(TYPEMINQUERY) \ - , macro(TYPEUPTO) \ - , macro(TYPEMINUPTO) \ - , macro(TYPEEXACT) \ - \ - , macro(CRSTAR) \ - , macro(CRMINSTAR) \ - , macro(CRPLUS) \ - , macro(CRMINPLUS) \ - , macro(CRQUERY) \ - , macro(CRMINQUERY) \ - , macro(CRRANGE) \ - , macro(CRMINRANGE) \ - \ - , macro(CLASS) \ - , macro(NCLASS) \ - , macro(XCLASS) \ - \ - , macro(REF) \ - \ - , macro(ALT) \ - , macro(KET) \ - , macro(KETRMAX) \ - , macro(KETRMIN) \ - \ - , macro(ASSERT) \ - , macro(ASSERT_NOT) \ - \ - , macro(BRAZERO) \ - , macro(BRAMINZERO) \ - , macro(BRANUMBER) \ - , macro(BRA) - -#define OPCODE_ENUM_VALUE(opcode) OP_##opcode -enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) }; - -/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and -study.c that all opcodes are less than 128 in value. This makes handling UTF-8 -character sequences easier. */ - -/* The highest extraction number before we have to start using additional -bytes. (Originally PCRE didn't have support for extraction counts higher than -this number.) The value is limited by the number of opcodes left after OP_BRA, -i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional -opcodes. */ - -/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above -are in conflict! */ - -#define EXTRACT_BASIC_MAX 100 - -/* The code vector runs on as long as necessary after the end. */ - -struct JSRegExp { - unsigned options; - - unsigned short topBracket; - unsigned short topBackref; - - unsigned short firstByte; - unsigned short reqByte; -}; - -/* Internal shared data tables. These are tables that are used by more than one - of the exported public functions. They have to be "external" in the C sense, - but are not part of the PCRE public API. The data for these tables is in the - pcre_tables.c module. */ - -#define jsc_pcre_utf8_table1_size 6 - -extern const int jsc_pcre_utf8_table1[6]; -extern const int jsc_pcre_utf8_table2[6]; -extern const int jsc_pcre_utf8_table3[6]; -extern const unsigned char jsc_pcre_utf8_table4[0x40]; - -extern const unsigned char jsc_pcre_default_tables[tables_length]; - -static inline unsigned char toLowerCase(unsigned char c) -{ - static const unsigned char* lowerCaseChars = jsc_pcre_default_tables + lcc_offset; - return lowerCaseChars[c]; -} - -static inline unsigned char flipCase(unsigned char c) -{ - static const unsigned char* flippedCaseChars = jsc_pcre_default_tables + fcc_offset; - return flippedCaseChars[c]; -} - -static inline unsigned char classBitmapForChar(unsigned char c) -{ - static const unsigned char* charClassBitmaps = jsc_pcre_default_tables + cbits_offset; - return charClassBitmaps[c]; -} - -static inline unsigned char charTypeForChar(unsigned char c) -{ - const unsigned char* charTypeMap = jsc_pcre_default_tables + ctypes_offset; - return charTypeMap[c]; -} - -static inline bool isWordChar(UChar c) -{ - return c < 128 && (charTypeForChar(c) & ctype_word); -} - -static inline bool isSpaceChar(UChar c) -{ - return (c < 128 && (charTypeForChar(c) & ctype_space)) || c == 0x00A0; -} - -static inline bool isNewline(UChar nl) -{ - return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029); -} - -static inline bool isBracketStartOpcode(unsigned char opcode) -{ - if (opcode >= OP_BRA) - return true; - switch (opcode) { - case OP_ASSERT: - case OP_ASSERT_NOT: - return true; - default: - return false; - } -} - -static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr) -{ - JS_ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT); - do - opcodePtr += getLinkValue(opcodePtr + 1); - while (*opcodePtr == OP_ALT); -} - -/* Internal shared functions. These are functions that are used in more -that one of the source files. They have to have external linkage, but -but are not part of the public API and so not exported from the library. */ - -extern int jsc_pcre_ucp_othercase(unsigned); -extern bool jsc_pcre_xclass(int, const unsigned char*); - -#endif - -#endif - -/* End of pcre_internal.h */ diff --git a/js/src/yarr/pcre/pcre_tables.cpp b/js/src/yarr/pcre/pcre_tables.cpp deleted file mode 100644 index b1ac229d5912..000000000000 --- a/js/src/yarr/pcre/pcre_tables.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains some fixed tables that are used by more than one of the -PCRE code modules. */ - -#include "pcre_internal.h" - -/************************************************* -* Tables for UTF-8 support * -*************************************************/ - -/* These are the breakpoints for different numbers of bytes in a UTF-8 -character. */ - -const int jsc_pcre_utf8_table1[6] = - { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; - -/* These are the indicator bits and the mask for the data bits to set in the -first byte of a character, indexed by the number of additional bytes. */ - -const int jsc_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; -const int jsc_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; - -/* Table of the number of extra characters, indexed by the first character -masked with 0x3f. The highest number for a valid UTF-8 character is in fact -0x3d. */ - -const unsigned char jsc_pcre_utf8_table4[0x40] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; - -#include "chartables.c" diff --git a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp deleted file mode 100644 index b97db921c981..000000000000 --- a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains code for searching the table of Unicode character -properties. */ - -#include "pcre_internal.h" - -#include "ucpinternal.h" /* Internal table details */ -#include "ucptable.cpp" /* The table itself */ - -/************************************************* -* Search table and return other case * -*************************************************/ - -/* If the given character is a letter, and there is another case for the -letter, return the other case. Otherwise, return -1. - -Arguments: - c the character value - -Returns: the other case or -1 if none -*/ - -int jsc_pcre_ucp_othercase(unsigned c) -{ - int bot = 0; - int top = sizeof(ucp_table) / sizeof(cnode); - int mid; - - /* The table is searched using a binary chop. You might think that using - intermediate variables to hold some of the common expressions would speed - things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it - makes things a lot slower. */ - - for (;;) { - if (top <= bot) - return -1; - mid = (bot + top) >> 1; - if (c == (ucp_table[mid].f0 & f0_charmask)) - break; - if (c < (ucp_table[mid].f0 & f0_charmask)) - top = mid; - else { - if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask))) - break; - bot = mid + 1; - } - } - - /* Found an entry in the table. Return -1 for a range entry. Otherwise return - the other case if there is one, else -1. */ - - if (ucp_table[mid].f0 & f0_rangeflag) - return -1; - - int offset = ucp_table[mid].f1 & f1_casemask; - if (offset & f1_caseneg) - offset |= f1_caseneg; - return !offset ? -1 : c + offset; -} diff --git a/js/src/yarr/pcre/pcre_xclass.cpp b/js/src/yarr/pcre/pcre_xclass.cpp deleted file mode 100644 index 8e59018ead0c..000000000000 --- a/js/src/yarr/pcre/pcre_xclass.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains an internal function that is used to match an extended -class (one that contains characters whose values are > 255). */ - -#include "pcre_internal.h" - -/************************************************* -* Match character against an XCLASS * -*************************************************/ - -/* This function is called to match a character against an extended class that -might contain values > 255. - -Arguments: - c the character - data points to the flag byte of the XCLASS data - -Returns: true if character matches, else false -*/ - -/* Get the next UTF-8 character, advancing the pointer. This is called when we - know we are in UTF-8 mode. */ - -static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr) -{ - c = *subjectPtr++; - if ((c & 0xc0) == 0xc0) { - int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ - int gcss = 6 * gcaa; - c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; - while (gcaa-- > 0) { - gcss -= 6; - c |= (*subjectPtr++ & 0x3f) << gcss; - } - } -} - -bool jsc_pcre_xclass(int c, const unsigned char* data) -{ - bool negated = (*data & XCL_NOT); - - /* Character values < 256 are matched against a bitmap, if one is present. If - not, we still carry on, because there may be ranges that start below 256 in the - additional data. */ - - if (c < 256) { - if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) - return !negated; /* char found */ - } - - /* First skip the bit map if present. Then match against the list of Unicode - properties or large chars or ranges that end with a large char. We won't ever - encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ - - if ((*data++ & XCL_MAP) != 0) - data += 32; - - int t; - while ((t = *data++) != XCL_END) { - if (t == XCL_SINGLE) { - int x; - getUTF8CharAndAdvancePointer(x, data); - if (c == x) - return !negated; - } - else if (t == XCL_RANGE) { - int x, y; - getUTF8CharAndAdvancePointer(x, data); - getUTF8CharAndAdvancePointer(y, data); - if (c >= x && c <= y) - return !negated; - } - } - - return negated; /* char did not match */ -} diff --git a/js/src/yarr/pcre/ucpinternal.h b/js/src/yarr/pcre/ucpinternal.h deleted file mode 100644 index c8bc4aab679c..000000000000 --- a/js/src/yarr/pcre/ucpinternal.h +++ /dev/null @@ -1,126 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/************************************************* -* Unicode Property Table handler * -*************************************************/ - -/* Internal header file defining the layout of the bits in each pair of 32-bit -words that form a data item in the table. */ - -typedef struct cnode { - unsigned f0; - unsigned f1; -} cnode; - -/* Things for the f0 field */ - -#define f0_scriptmask 0xff000000 /* Mask for script field */ -#define f0_scriptshift 24 /* Shift for script value */ -#define f0_rangeflag 0x00f00000 /* Flag for a range item */ -#define f0_charmask 0x001fffff /* Mask for code point value */ - -/* Things for the f1 field */ - -#define f1_typemask 0xfc000000 /* Mask for char type field */ -#define f1_typeshift 26 /* Shift for the type field */ -#define f1_rangemask 0x0000ffff /* Mask for a range offset */ -#define f1_casemask 0x0000ffff /* Mask for a case offset */ -#define f1_caseneg 0xffff8000 /* Bits for negation */ - -/* The data consists of a vector of structures of type cnode. The two unsigned -32-bit integers are used as follows: - -(f0) (1) The most significant byte holds the script number. The numbers are - defined by the enum in ucp.h. - - (2) The 0x00800000 bit is set if this entry defines a range of characters. - It is not set if this entry defines a single character - - (3) The 0x00600000 bits are spare. - - (4) The 0x001fffff bits contain the code point. No Unicode code point will - ever be greater than 0x0010ffff, so this should be OK for ever. - -(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are - defined by an enum in ucp.h. - - (2) The 0x03ff0000 bits are spare. - - (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of - range if this entry defines a range, OR the *signed* offset to the - character's "other case" partner if this entry defines a single - character. There is no partner if the value is zero. - -------------------------------------------------------------------------------- -| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) | -------------------------------------------------------------------------------- - | | | | | - | | |-> spare | |-> spare - | | | - | |-> spare |-> spare - | - |-> range flag - -The upper/lower casing information is set only for characters that come in -pairs. The non-one-to-one mappings in the Unicode data are ignored. - -When searching the data, proceed as follows: - -(1) Set up for a binary chop search. - -(2) If the top is not greater than the bottom, the character is not in the - table. Its type must therefore be "Cn" ("Undefined"). - -(3) Find the middle vector element. - -(4) Extract the code point and compare. If equal, we are done. - -(5) If the test character is smaller, set the top to the current point, and - goto (2). - -(6) If the current entry defines a range, compute the last character by adding - the offset, and see if the test character is within the range. If it is, - we are done. - -(7) Otherwise, set the bottom to one element past the current point and goto - (2). -*/ - -/* End of ucpinternal.h */ diff --git a/js/src/yarr/pcre/ucptable.cpp b/js/src/yarr/pcre/ucptable.cpp deleted file mode 100644 index 011f7f572443..000000000000 --- a/js/src/yarr/pcre/ucptable.cpp +++ /dev/null @@ -1,2968 +0,0 @@ -/* This source module is automatically generated from the Unicode -property table. See ucpinternal.h for a description of the layout. */ - -static const cnode ucp_table[] = { - { 0x09800000, 0x0000001f }, - { 0x09000020, 0x74000000 }, - { 0x09800021, 0x54000002 }, - { 0x09000024, 0x5c000000 }, - { 0x09800025, 0x54000002 }, - { 0x09000028, 0x58000000 }, - { 0x09000029, 0x48000000 }, - { 0x0900002a, 0x54000000 }, - { 0x0900002b, 0x64000000 }, - { 0x0900002c, 0x54000000 }, - { 0x0900002d, 0x44000000 }, - { 0x0980002e, 0x54000001 }, - { 0x09800030, 0x34000009 }, - { 0x0980003a, 0x54000001 }, - { 0x0980003c, 0x64000002 }, - { 0x0980003f, 0x54000001 }, - { 0x21000041, 0x24000020 }, - { 0x21000042, 0x24000020 }, - { 0x21000043, 0x24000020 }, - { 0x21000044, 0x24000020 }, - { 0x21000045, 0x24000020 }, - { 0x21000046, 0x24000020 }, - { 0x21000047, 0x24000020 }, - { 0x21000048, 0x24000020 }, - { 0x21000049, 0x24000020 }, - { 0x2100004a, 0x24000020 }, - { 0x2100004b, 0x24000020 }, - { 0x2100004c, 0x24000020 }, - { 0x2100004d, 0x24000020 }, - { 0x2100004e, 0x24000020 }, - { 0x2100004f, 0x24000020 }, - { 0x21000050, 0x24000020 }, - { 0x21000051, 0x24000020 }, - { 0x21000052, 0x24000020 }, - { 0x21000053, 0x24000020 }, - { 0x21000054, 0x24000020 }, - { 0x21000055, 0x24000020 }, - { 0x21000056, 0x24000020 }, - { 0x21000057, 0x24000020 }, - { 0x21000058, 0x24000020 }, - { 0x21000059, 0x24000020 }, - { 0x2100005a, 0x24000020 }, - { 0x0900005b, 0x58000000 }, - { 0x0900005c, 0x54000000 }, - { 0x0900005d, 0x48000000 }, - { 0x0900005e, 0x60000000 }, - { 0x0900005f, 0x40000000 }, - { 0x09000060, 0x60000000 }, - { 0x21000061, 0x1400ffe0 }, - { 0x21000062, 0x1400ffe0 }, - { 0x21000063, 0x1400ffe0 }, - { 0x21000064, 0x1400ffe0 }, - { 0x21000065, 0x1400ffe0 }, - { 0x21000066, 0x1400ffe0 }, - { 0x21000067, 0x1400ffe0 }, - { 0x21000068, 0x1400ffe0 }, - { 0x21000069, 0x1400ffe0 }, - { 0x2100006a, 0x1400ffe0 }, - { 0x2100006b, 0x1400ffe0 }, - { 0x2100006c, 0x1400ffe0 }, - { 0x2100006d, 0x1400ffe0 }, - { 0x2100006e, 0x1400ffe0 }, - { 0x2100006f, 0x1400ffe0 }, - { 0x21000070, 0x1400ffe0 }, - { 0x21000071, 0x1400ffe0 }, - { 0x21000072, 0x1400ffe0 }, - { 0x21000073, 0x1400ffe0 }, - { 0x21000074, 0x1400ffe0 }, - { 0x21000075, 0x1400ffe0 }, - { 0x21000076, 0x1400ffe0 }, - { 0x21000077, 0x1400ffe0 }, - { 0x21000078, 0x1400ffe0 }, - { 0x21000079, 0x1400ffe0 }, - { 0x2100007a, 0x1400ffe0 }, - { 0x0900007b, 0x58000000 }, - { 0x0900007c, 0x64000000 }, - { 0x0900007d, 0x48000000 }, - { 0x0900007e, 0x64000000 }, - { 0x0980007f, 0x00000020 }, - { 0x090000a0, 0x74000000 }, - { 0x090000a1, 0x54000000 }, - { 0x098000a2, 0x5c000003 }, - { 0x098000a6, 0x68000001 }, - { 0x090000a8, 0x60000000 }, - { 0x090000a9, 0x68000000 }, - { 0x210000aa, 0x14000000 }, - { 0x090000ab, 0x50000000 }, - { 0x090000ac, 0x64000000 }, - { 0x090000ad, 0x04000000 }, - { 0x090000ae, 0x68000000 }, - { 0x090000af, 0x60000000 }, - { 0x090000b0, 0x68000000 }, - { 0x090000b1, 0x64000000 }, - { 0x098000b2, 0x3c000001 }, - { 0x090000b4, 0x60000000 }, - { 0x090000b5, 0x140002e7 }, - { 0x090000b6, 0x68000000 }, - { 0x090000b7, 0x54000000 }, - { 0x090000b8, 0x60000000 }, - { 0x090000b9, 0x3c000000 }, - { 0x210000ba, 0x14000000 }, - { 0x090000bb, 0x4c000000 }, - { 0x098000bc, 0x3c000002 }, - { 0x090000bf, 0x54000000 }, - { 0x210000c0, 0x24000020 }, - { 0x210000c1, 0x24000020 }, - { 0x210000c2, 0x24000020 }, - { 0x210000c3, 0x24000020 }, - { 0x210000c4, 0x24000020 }, - { 0x210000c5, 0x24000020 }, - { 0x210000c6, 0x24000020 }, - { 0x210000c7, 0x24000020 }, - { 0x210000c8, 0x24000020 }, - { 0x210000c9, 0x24000020 }, - { 0x210000ca, 0x24000020 }, - { 0x210000cb, 0x24000020 }, - { 0x210000cc, 0x24000020 }, - { 0x210000cd, 0x24000020 }, - { 0x210000ce, 0x24000020 }, - { 0x210000cf, 0x24000020 }, - { 0x210000d0, 0x24000020 }, - { 0x210000d1, 0x24000020 }, - { 0x210000d2, 0x24000020 }, - { 0x210000d3, 0x24000020 }, - { 0x210000d4, 0x24000020 }, - { 0x210000d5, 0x24000020 }, - { 0x210000d6, 0x24000020 }, - { 0x090000d7, 0x64000000 }, - { 0x210000d8, 0x24000020 }, - { 0x210000d9, 0x24000020 }, - { 0x210000da, 0x24000020 }, - { 0x210000db, 0x24000020 }, - { 0x210000dc, 0x24000020 }, - { 0x210000dd, 0x24000020 }, - { 0x210000de, 0x24000020 }, - { 0x210000df, 0x14000000 }, - { 0x210000e0, 0x1400ffe0 }, - { 0x210000e1, 0x1400ffe0 }, - { 0x210000e2, 0x1400ffe0 }, - { 0x210000e3, 0x1400ffe0 }, - { 0x210000e4, 0x1400ffe0 }, - { 0x210000e5, 0x1400ffe0 }, - { 0x210000e6, 0x1400ffe0 }, - { 0x210000e7, 0x1400ffe0 }, - { 0x210000e8, 0x1400ffe0 }, - { 0x210000e9, 0x1400ffe0 }, - { 0x210000ea, 0x1400ffe0 }, - { 0x210000eb, 0x1400ffe0 }, - { 0x210000ec, 0x1400ffe0 }, - { 0x210000ed, 0x1400ffe0 }, - { 0x210000ee, 0x1400ffe0 }, - { 0x210000ef, 0x1400ffe0 }, - { 0x210000f0, 0x1400ffe0 }, - { 0x210000f1, 0x1400ffe0 }, - { 0x210000f2, 0x1400ffe0 }, - { 0x210000f3, 0x1400ffe0 }, - { 0x210000f4, 0x1400ffe0 }, - { 0x210000f5, 0x1400ffe0 }, - { 0x210000f6, 0x1400ffe0 }, - { 0x090000f7, 0x64000000 }, - { 0x210000f8, 0x1400ffe0 }, - { 0x210000f9, 0x1400ffe0 }, - { 0x210000fa, 0x1400ffe0 }, - { 0x210000fb, 0x1400ffe0 }, - { 0x210000fc, 0x1400ffe0 }, - { 0x210000fd, 0x1400ffe0 }, - { 0x210000fe, 0x1400ffe0 }, - { 0x210000ff, 0x14000079 }, - { 0x21000100, 0x24000001 }, - { 0x21000101, 0x1400ffff }, - { 0x21000102, 0x24000001 }, - { 0x21000103, 0x1400ffff }, - { 0x21000104, 0x24000001 }, - { 0x21000105, 0x1400ffff }, - { 0x21000106, 0x24000001 }, - { 0x21000107, 0x1400ffff }, - { 0x21000108, 0x24000001 }, - { 0x21000109, 0x1400ffff }, - { 0x2100010a, 0x24000001 }, - { 0x2100010b, 0x1400ffff }, - { 0x2100010c, 0x24000001 }, - { 0x2100010d, 0x1400ffff }, - { 0x2100010e, 0x24000001 }, - { 0x2100010f, 0x1400ffff }, - { 0x21000110, 0x24000001 }, - { 0x21000111, 0x1400ffff }, - { 0x21000112, 0x24000001 }, - { 0x21000113, 0x1400ffff }, - { 0x21000114, 0x24000001 }, - { 0x21000115, 0x1400ffff }, - { 0x21000116, 0x24000001 }, - { 0x21000117, 0x1400ffff }, - { 0x21000118, 0x24000001 }, - { 0x21000119, 0x1400ffff }, - { 0x2100011a, 0x24000001 }, - { 0x2100011b, 0x1400ffff }, - { 0x2100011c, 0x24000001 }, - { 0x2100011d, 0x1400ffff }, - { 0x2100011e, 0x24000001 }, - { 0x2100011f, 0x1400ffff }, - { 0x21000120, 0x24000001 }, - { 0x21000121, 0x1400ffff }, - { 0x21000122, 0x24000001 }, - { 0x21000123, 0x1400ffff }, - { 0x21000124, 0x24000001 }, - { 0x21000125, 0x1400ffff }, - { 0x21000126, 0x24000001 }, - { 0x21000127, 0x1400ffff }, - { 0x21000128, 0x24000001 }, - { 0x21000129, 0x1400ffff }, - { 0x2100012a, 0x24000001 }, - { 0x2100012b, 0x1400ffff }, - { 0x2100012c, 0x24000001 }, - { 0x2100012d, 0x1400ffff }, - { 0x2100012e, 0x24000001 }, - { 0x2100012f, 0x1400ffff }, - { 0x21000130, 0x2400ff39 }, - { 0x21000131, 0x1400ff18 }, - { 0x21000132, 0x24000001 }, - { 0x21000133, 0x1400ffff }, - { 0x21000134, 0x24000001 }, - { 0x21000135, 0x1400ffff }, - { 0x21000136, 0x24000001 }, - { 0x21000137, 0x1400ffff }, - { 0x21000138, 0x14000000 }, - { 0x21000139, 0x24000001 }, - { 0x2100013a, 0x1400ffff }, - { 0x2100013b, 0x24000001 }, - { 0x2100013c, 0x1400ffff }, - { 0x2100013d, 0x24000001 }, - { 0x2100013e, 0x1400ffff }, - { 0x2100013f, 0x24000001 }, - { 0x21000140, 0x1400ffff }, - { 0x21000141, 0x24000001 }, - { 0x21000142, 0x1400ffff }, - { 0x21000143, 0x24000001 }, - { 0x21000144, 0x1400ffff }, - { 0x21000145, 0x24000001 }, - { 0x21000146, 0x1400ffff }, - { 0x21000147, 0x24000001 }, - { 0x21000148, 0x1400ffff }, - { 0x21000149, 0x14000000 }, - { 0x2100014a, 0x24000001 }, - { 0x2100014b, 0x1400ffff }, - { 0x2100014c, 0x24000001 }, - { 0x2100014d, 0x1400ffff }, - { 0x2100014e, 0x24000001 }, - { 0x2100014f, 0x1400ffff }, - { 0x21000150, 0x24000001 }, - { 0x21000151, 0x1400ffff }, - { 0x21000152, 0x24000001 }, - { 0x21000153, 0x1400ffff }, - { 0x21000154, 0x24000001 }, - { 0x21000155, 0x1400ffff }, - { 0x21000156, 0x24000001 }, - { 0x21000157, 0x1400ffff }, - { 0x21000158, 0x24000001 }, - { 0x21000159, 0x1400ffff }, - { 0x2100015a, 0x24000001 }, - { 0x2100015b, 0x1400ffff }, - { 0x2100015c, 0x24000001 }, - { 0x2100015d, 0x1400ffff }, - { 0x2100015e, 0x24000001 }, - { 0x2100015f, 0x1400ffff }, - { 0x21000160, 0x24000001 }, - { 0x21000161, 0x1400ffff }, - { 0x21000162, 0x24000001 }, - { 0x21000163, 0x1400ffff }, - { 0x21000164, 0x24000001 }, - { 0x21000165, 0x1400ffff }, - { 0x21000166, 0x24000001 }, - { 0x21000167, 0x1400ffff }, - { 0x21000168, 0x24000001 }, - { 0x21000169, 0x1400ffff }, - { 0x2100016a, 0x24000001 }, - { 0x2100016b, 0x1400ffff }, - { 0x2100016c, 0x24000001 }, - { 0x2100016d, 0x1400ffff }, - { 0x2100016e, 0x24000001 }, - { 0x2100016f, 0x1400ffff }, - { 0x21000170, 0x24000001 }, - { 0x21000171, 0x1400ffff }, - { 0x21000172, 0x24000001 }, - { 0x21000173, 0x1400ffff }, - { 0x21000174, 0x24000001 }, - { 0x21000175, 0x1400ffff }, - { 0x21000176, 0x24000001 }, - { 0x21000177, 0x1400ffff }, - { 0x21000178, 0x2400ff87 }, - { 0x21000179, 0x24000001 }, - { 0x2100017a, 0x1400ffff }, - { 0x2100017b, 0x24000001 }, - { 0x2100017c, 0x1400ffff }, - { 0x2100017d, 0x24000001 }, - { 0x2100017e, 0x1400ffff }, - { 0x2100017f, 0x1400fed4 }, - { 0x21000180, 0x14000000 }, - { 0x21000181, 0x240000d2 }, - { 0x21000182, 0x24000001 }, - { 0x21000183, 0x1400ffff }, - { 0x21000184, 0x24000001 }, - { 0x21000185, 0x1400ffff }, - { 0x21000186, 0x240000ce }, - { 0x21000187, 0x24000001 }, - { 0x21000188, 0x1400ffff }, - { 0x21000189, 0x240000cd }, - { 0x2100018a, 0x240000cd }, - { 0x2100018b, 0x24000001 }, - { 0x2100018c, 0x1400ffff }, - { 0x2100018d, 0x14000000 }, - { 0x2100018e, 0x2400004f }, - { 0x2100018f, 0x240000ca }, - { 0x21000190, 0x240000cb }, - { 0x21000191, 0x24000001 }, - { 0x21000192, 0x1400ffff }, - { 0x21000193, 0x240000cd }, - { 0x21000194, 0x240000cf }, - { 0x21000195, 0x14000061 }, - { 0x21000196, 0x240000d3 }, - { 0x21000197, 0x240000d1 }, - { 0x21000198, 0x24000001 }, - { 0x21000199, 0x1400ffff }, - { 0x2100019a, 0x140000a3 }, - { 0x2100019b, 0x14000000 }, - { 0x2100019c, 0x240000d3 }, - { 0x2100019d, 0x240000d5 }, - { 0x2100019e, 0x14000082 }, - { 0x2100019f, 0x240000d6 }, - { 0x210001a0, 0x24000001 }, - { 0x210001a1, 0x1400ffff }, - { 0x210001a2, 0x24000001 }, - { 0x210001a3, 0x1400ffff }, - { 0x210001a4, 0x24000001 }, - { 0x210001a5, 0x1400ffff }, - { 0x210001a6, 0x240000da }, - { 0x210001a7, 0x24000001 }, - { 0x210001a8, 0x1400ffff }, - { 0x210001a9, 0x240000da }, - { 0x218001aa, 0x14000001 }, - { 0x210001ac, 0x24000001 }, - { 0x210001ad, 0x1400ffff }, - { 0x210001ae, 0x240000da }, - { 0x210001af, 0x24000001 }, - { 0x210001b0, 0x1400ffff }, - { 0x210001b1, 0x240000d9 }, - { 0x210001b2, 0x240000d9 }, - { 0x210001b3, 0x24000001 }, - { 0x210001b4, 0x1400ffff }, - { 0x210001b5, 0x24000001 }, - { 0x210001b6, 0x1400ffff }, - { 0x210001b7, 0x240000db }, - { 0x210001b8, 0x24000001 }, - { 0x210001b9, 0x1400ffff }, - { 0x210001ba, 0x14000000 }, - { 0x210001bb, 0x1c000000 }, - { 0x210001bc, 0x24000001 }, - { 0x210001bd, 0x1400ffff }, - { 0x210001be, 0x14000000 }, - { 0x210001bf, 0x14000038 }, - { 0x218001c0, 0x1c000003 }, - { 0x210001c4, 0x24000002 }, - { 0x210001c5, 0x2000ffff }, - { 0x210001c6, 0x1400fffe }, - { 0x210001c7, 0x24000002 }, - { 0x210001c8, 0x2000ffff }, - { 0x210001c9, 0x1400fffe }, - { 0x210001ca, 0x24000002 }, - { 0x210001cb, 0x2000ffff }, - { 0x210001cc, 0x1400fffe }, - { 0x210001cd, 0x24000001 }, - { 0x210001ce, 0x1400ffff }, - { 0x210001cf, 0x24000001 }, - { 0x210001d0, 0x1400ffff }, - { 0x210001d1, 0x24000001 }, - { 0x210001d2, 0x1400ffff }, - { 0x210001d3, 0x24000001 }, - { 0x210001d4, 0x1400ffff }, - { 0x210001d5, 0x24000001 }, - { 0x210001d6, 0x1400ffff }, - { 0x210001d7, 0x24000001 }, - { 0x210001d8, 0x1400ffff }, - { 0x210001d9, 0x24000001 }, - { 0x210001da, 0x1400ffff }, - { 0x210001db, 0x24000001 }, - { 0x210001dc, 0x1400ffff }, - { 0x210001dd, 0x1400ffb1 }, - { 0x210001de, 0x24000001 }, - { 0x210001df, 0x1400ffff }, - { 0x210001e0, 0x24000001 }, - { 0x210001e1, 0x1400ffff }, - { 0x210001e2, 0x24000001 }, - { 0x210001e3, 0x1400ffff }, - { 0x210001e4, 0x24000001 }, - { 0x210001e5, 0x1400ffff }, - { 0x210001e6, 0x24000001 }, - { 0x210001e7, 0x1400ffff }, - { 0x210001e8, 0x24000001 }, - { 0x210001e9, 0x1400ffff }, - { 0x210001ea, 0x24000001 }, - { 0x210001eb, 0x1400ffff }, - { 0x210001ec, 0x24000001 }, - { 0x210001ed, 0x1400ffff }, - { 0x210001ee, 0x24000001 }, - { 0x210001ef, 0x1400ffff }, - { 0x210001f0, 0x14000000 }, - { 0x210001f1, 0x24000002 }, - { 0x210001f2, 0x2000ffff }, - { 0x210001f3, 0x1400fffe }, - { 0x210001f4, 0x24000001 }, - { 0x210001f5, 0x1400ffff }, - { 0x210001f6, 0x2400ff9f }, - { 0x210001f7, 0x2400ffc8 }, - { 0x210001f8, 0x24000001 }, - { 0x210001f9, 0x1400ffff }, - { 0x210001fa, 0x24000001 }, - { 0x210001fb, 0x1400ffff }, - { 0x210001fc, 0x24000001 }, - { 0x210001fd, 0x1400ffff }, - { 0x210001fe, 0x24000001 }, - { 0x210001ff, 0x1400ffff }, - { 0x21000200, 0x24000001 }, - { 0x21000201, 0x1400ffff }, - { 0x21000202, 0x24000001 }, - { 0x21000203, 0x1400ffff }, - { 0x21000204, 0x24000001 }, - { 0x21000205, 0x1400ffff }, - { 0x21000206, 0x24000001 }, - { 0x21000207, 0x1400ffff }, - { 0x21000208, 0x24000001 }, - { 0x21000209, 0x1400ffff }, - { 0x2100020a, 0x24000001 }, - { 0x2100020b, 0x1400ffff }, - { 0x2100020c, 0x24000001 }, - { 0x2100020d, 0x1400ffff }, - { 0x2100020e, 0x24000001 }, - { 0x2100020f, 0x1400ffff }, - { 0x21000210, 0x24000001 }, - { 0x21000211, 0x1400ffff }, - { 0x21000212, 0x24000001 }, - { 0x21000213, 0x1400ffff }, - { 0x21000214, 0x24000001 }, - { 0x21000215, 0x1400ffff }, - { 0x21000216, 0x24000001 }, - { 0x21000217, 0x1400ffff }, - { 0x21000218, 0x24000001 }, - { 0x21000219, 0x1400ffff }, - { 0x2100021a, 0x24000001 }, - { 0x2100021b, 0x1400ffff }, - { 0x2100021c, 0x24000001 }, - { 0x2100021d, 0x1400ffff }, - { 0x2100021e, 0x24000001 }, - { 0x2100021f, 0x1400ffff }, - { 0x21000220, 0x2400ff7e }, - { 0x21000221, 0x14000000 }, - { 0x21000222, 0x24000001 }, - { 0x21000223, 0x1400ffff }, - { 0x21000224, 0x24000001 }, - { 0x21000225, 0x1400ffff }, - { 0x21000226, 0x24000001 }, - { 0x21000227, 0x1400ffff }, - { 0x21000228, 0x24000001 }, - { 0x21000229, 0x1400ffff }, - { 0x2100022a, 0x24000001 }, - { 0x2100022b, 0x1400ffff }, - { 0x2100022c, 0x24000001 }, - { 0x2100022d, 0x1400ffff }, - { 0x2100022e, 0x24000001 }, - { 0x2100022f, 0x1400ffff }, - { 0x21000230, 0x24000001 }, - { 0x21000231, 0x1400ffff }, - { 0x21000232, 0x24000001 }, - { 0x21000233, 0x1400ffff }, - { 0x21800234, 0x14000005 }, - { 0x2100023a, 0x24000000 }, - { 0x2100023b, 0x24000001 }, - { 0x2100023c, 0x1400ffff }, - { 0x2100023d, 0x2400ff5d }, - { 0x2100023e, 0x24000000 }, - { 0x2180023f, 0x14000001 }, - { 0x21000241, 0x24000053 }, - { 0x21800250, 0x14000002 }, - { 0x21000253, 0x1400ff2e }, - { 0x21000254, 0x1400ff32 }, - { 0x21000255, 0x14000000 }, - { 0x21000256, 0x1400ff33 }, - { 0x21000257, 0x1400ff33 }, - { 0x21000258, 0x14000000 }, - { 0x21000259, 0x1400ff36 }, - { 0x2100025a, 0x14000000 }, - { 0x2100025b, 0x1400ff35 }, - { 0x2180025c, 0x14000003 }, - { 0x21000260, 0x1400ff33 }, - { 0x21800261, 0x14000001 }, - { 0x21000263, 0x1400ff31 }, - { 0x21800264, 0x14000003 }, - { 0x21000268, 0x1400ff2f }, - { 0x21000269, 0x1400ff2d }, - { 0x2180026a, 0x14000004 }, - { 0x2100026f, 0x1400ff2d }, - { 0x21800270, 0x14000001 }, - { 0x21000272, 0x1400ff2b }, - { 0x21800273, 0x14000001 }, - { 0x21000275, 0x1400ff2a }, - { 0x21800276, 0x14000009 }, - { 0x21000280, 0x1400ff26 }, - { 0x21800281, 0x14000001 }, - { 0x21000283, 0x1400ff26 }, - { 0x21800284, 0x14000003 }, - { 0x21000288, 0x1400ff26 }, - { 0x21000289, 0x14000000 }, - { 0x2100028a, 0x1400ff27 }, - { 0x2100028b, 0x1400ff27 }, - { 0x2180028c, 0x14000005 }, - { 0x21000292, 0x1400ff25 }, - { 0x21000293, 0x14000000 }, - { 0x21000294, 0x1400ffad }, - { 0x21800295, 0x1400001a }, - { 0x218002b0, 0x18000011 }, - { 0x098002c2, 0x60000003 }, - { 0x098002c6, 0x1800000b }, - { 0x098002d2, 0x6000000d }, - { 0x218002e0, 0x18000004 }, - { 0x098002e5, 0x60000008 }, - { 0x090002ee, 0x18000000 }, - { 0x098002ef, 0x60000010 }, - { 0x1b800300, 0x30000044 }, - { 0x1b000345, 0x30000054 }, - { 0x1b800346, 0x30000029 }, - { 0x13800374, 0x60000001 }, - { 0x1300037a, 0x18000000 }, - { 0x0900037e, 0x54000000 }, - { 0x13800384, 0x60000001 }, - { 0x13000386, 0x24000026 }, - { 0x09000387, 0x54000000 }, - { 0x13000388, 0x24000025 }, - { 0x13000389, 0x24000025 }, - { 0x1300038a, 0x24000025 }, - { 0x1300038c, 0x24000040 }, - { 0x1300038e, 0x2400003f }, - { 0x1300038f, 0x2400003f }, - { 0x13000390, 0x14000000 }, - { 0x13000391, 0x24000020 }, - { 0x13000392, 0x24000020 }, - { 0x13000393, 0x24000020 }, - { 0x13000394, 0x24000020 }, - { 0x13000395, 0x24000020 }, - { 0x13000396, 0x24000020 }, - { 0x13000397, 0x24000020 }, - { 0x13000398, 0x24000020 }, - { 0x13000399, 0x24000020 }, - { 0x1300039a, 0x24000020 }, - { 0x1300039b, 0x24000020 }, - { 0x1300039c, 0x24000020 }, - { 0x1300039d, 0x24000020 }, - { 0x1300039e, 0x24000020 }, - { 0x1300039f, 0x24000020 }, - { 0x130003a0, 0x24000020 }, - { 0x130003a1, 0x24000020 }, - { 0x130003a3, 0x24000020 }, - { 0x130003a4, 0x24000020 }, - { 0x130003a5, 0x24000020 }, - { 0x130003a6, 0x24000020 }, - { 0x130003a7, 0x24000020 }, - { 0x130003a8, 0x24000020 }, - { 0x130003a9, 0x24000020 }, - { 0x130003aa, 0x24000020 }, - { 0x130003ab, 0x24000020 }, - { 0x130003ac, 0x1400ffda }, - { 0x130003ad, 0x1400ffdb }, - { 0x130003ae, 0x1400ffdb }, - { 0x130003af, 0x1400ffdb }, - { 0x130003b0, 0x14000000 }, - { 0x130003b1, 0x1400ffe0 }, - { 0x130003b2, 0x1400ffe0 }, - { 0x130003b3, 0x1400ffe0 }, - { 0x130003b4, 0x1400ffe0 }, - { 0x130003b5, 0x1400ffe0 }, - { 0x130003b6, 0x1400ffe0 }, - { 0x130003b7, 0x1400ffe0 }, - { 0x130003b8, 0x1400ffe0 }, - { 0x130003b9, 0x1400ffe0 }, - { 0x130003ba, 0x1400ffe0 }, - { 0x130003bb, 0x1400ffe0 }, - { 0x130003bc, 0x1400ffe0 }, - { 0x130003bd, 0x1400ffe0 }, - { 0x130003be, 0x1400ffe0 }, - { 0x130003bf, 0x1400ffe0 }, - { 0x130003c0, 0x1400ffe0 }, - { 0x130003c1, 0x1400ffe0 }, - { 0x130003c2, 0x1400ffe1 }, - { 0x130003c3, 0x1400ffe0 }, - { 0x130003c4, 0x1400ffe0 }, - { 0x130003c5, 0x1400ffe0 }, - { 0x130003c6, 0x1400ffe0 }, - { 0x130003c7, 0x1400ffe0 }, - { 0x130003c8, 0x1400ffe0 }, - { 0x130003c9, 0x1400ffe0 }, - { 0x130003ca, 0x1400ffe0 }, - { 0x130003cb, 0x1400ffe0 }, - { 0x130003cc, 0x1400ffc0 }, - { 0x130003cd, 0x1400ffc1 }, - { 0x130003ce, 0x1400ffc1 }, - { 0x130003d0, 0x1400ffc2 }, - { 0x130003d1, 0x1400ffc7 }, - { 0x138003d2, 0x24000002 }, - { 0x130003d5, 0x1400ffd1 }, - { 0x130003d6, 0x1400ffca }, - { 0x130003d7, 0x14000000 }, - { 0x130003d8, 0x24000001 }, - { 0x130003d9, 0x1400ffff }, - { 0x130003da, 0x24000001 }, - { 0x130003db, 0x1400ffff }, - { 0x130003dc, 0x24000001 }, - { 0x130003dd, 0x1400ffff }, - { 0x130003de, 0x24000001 }, - { 0x130003df, 0x1400ffff }, - { 0x130003e0, 0x24000001 }, - { 0x130003e1, 0x1400ffff }, - { 0x0a0003e2, 0x24000001 }, - { 0x0a0003e3, 0x1400ffff }, - { 0x0a0003e4, 0x24000001 }, - { 0x0a0003e5, 0x1400ffff }, - { 0x0a0003e6, 0x24000001 }, - { 0x0a0003e7, 0x1400ffff }, - { 0x0a0003e8, 0x24000001 }, - { 0x0a0003e9, 0x1400ffff }, - { 0x0a0003ea, 0x24000001 }, - { 0x0a0003eb, 0x1400ffff }, - { 0x0a0003ec, 0x24000001 }, - { 0x0a0003ed, 0x1400ffff }, - { 0x0a0003ee, 0x24000001 }, - { 0x0a0003ef, 0x1400ffff }, - { 0x130003f0, 0x1400ffaa }, - { 0x130003f1, 0x1400ffb0 }, - { 0x130003f2, 0x14000007 }, - { 0x130003f3, 0x14000000 }, - { 0x130003f4, 0x2400ffc4 }, - { 0x130003f5, 0x1400ffa0 }, - { 0x130003f6, 0x64000000 }, - { 0x130003f7, 0x24000001 }, - { 0x130003f8, 0x1400ffff }, - { 0x130003f9, 0x2400fff9 }, - { 0x130003fa, 0x24000001 }, - { 0x130003fb, 0x1400ffff }, - { 0x130003fc, 0x14000000 }, - { 0x138003fd, 0x24000002 }, - { 0x0c000400, 0x24000050 }, - { 0x0c000401, 0x24000050 }, - { 0x0c000402, 0x24000050 }, - { 0x0c000403, 0x24000050 }, - { 0x0c000404, 0x24000050 }, - { 0x0c000405, 0x24000050 }, - { 0x0c000406, 0x24000050 }, - { 0x0c000407, 0x24000050 }, - { 0x0c000408, 0x24000050 }, - { 0x0c000409, 0x24000050 }, - { 0x0c00040a, 0x24000050 }, - { 0x0c00040b, 0x24000050 }, - { 0x0c00040c, 0x24000050 }, - { 0x0c00040d, 0x24000050 }, - { 0x0c00040e, 0x24000050 }, - { 0x0c00040f, 0x24000050 }, - { 0x0c000410, 0x24000020 }, - { 0x0c000411, 0x24000020 }, - { 0x0c000412, 0x24000020 }, - { 0x0c000413, 0x24000020 }, - { 0x0c000414, 0x24000020 }, - { 0x0c000415, 0x24000020 }, - { 0x0c000416, 0x24000020 }, - { 0x0c000417, 0x24000020 }, - { 0x0c000418, 0x24000020 }, - { 0x0c000419, 0x24000020 }, - { 0x0c00041a, 0x24000020 }, - { 0x0c00041b, 0x24000020 }, - { 0x0c00041c, 0x24000020 }, - { 0x0c00041d, 0x24000020 }, - { 0x0c00041e, 0x24000020 }, - { 0x0c00041f, 0x24000020 }, - { 0x0c000420, 0x24000020 }, - { 0x0c000421, 0x24000020 }, - { 0x0c000422, 0x24000020 }, - { 0x0c000423, 0x24000020 }, - { 0x0c000424, 0x24000020 }, - { 0x0c000425, 0x24000020 }, - { 0x0c000426, 0x24000020 }, - { 0x0c000427, 0x24000020 }, - { 0x0c000428, 0x24000020 }, - { 0x0c000429, 0x24000020 }, - { 0x0c00042a, 0x24000020 }, - { 0x0c00042b, 0x24000020 }, - { 0x0c00042c, 0x24000020 }, - { 0x0c00042d, 0x24000020 }, - { 0x0c00042e, 0x24000020 }, - { 0x0c00042f, 0x24000020 }, - { 0x0c000430, 0x1400ffe0 }, - { 0x0c000431, 0x1400ffe0 }, - { 0x0c000432, 0x1400ffe0 }, - { 0x0c000433, 0x1400ffe0 }, - { 0x0c000434, 0x1400ffe0 }, - { 0x0c000435, 0x1400ffe0 }, - { 0x0c000436, 0x1400ffe0 }, - { 0x0c000437, 0x1400ffe0 }, - { 0x0c000438, 0x1400ffe0 }, - { 0x0c000439, 0x1400ffe0 }, - { 0x0c00043a, 0x1400ffe0 }, - { 0x0c00043b, 0x1400ffe0 }, - { 0x0c00043c, 0x1400ffe0 }, - { 0x0c00043d, 0x1400ffe0 }, - { 0x0c00043e, 0x1400ffe0 }, - { 0x0c00043f, 0x1400ffe0 }, - { 0x0c000440, 0x1400ffe0 }, - { 0x0c000441, 0x1400ffe0 }, - { 0x0c000442, 0x1400ffe0 }, - { 0x0c000443, 0x1400ffe0 }, - { 0x0c000444, 0x1400ffe0 }, - { 0x0c000445, 0x1400ffe0 }, - { 0x0c000446, 0x1400ffe0 }, - { 0x0c000447, 0x1400ffe0 }, - { 0x0c000448, 0x1400ffe0 }, - { 0x0c000449, 0x1400ffe0 }, - { 0x0c00044a, 0x1400ffe0 }, - { 0x0c00044b, 0x1400ffe0 }, - { 0x0c00044c, 0x1400ffe0 }, - { 0x0c00044d, 0x1400ffe0 }, - { 0x0c00044e, 0x1400ffe0 }, - { 0x0c00044f, 0x1400ffe0 }, - { 0x0c000450, 0x1400ffb0 }, - { 0x0c000451, 0x1400ffb0 }, - { 0x0c000452, 0x1400ffb0 }, - { 0x0c000453, 0x1400ffb0 }, - { 0x0c000454, 0x1400ffb0 }, - { 0x0c000455, 0x1400ffb0 }, - { 0x0c000456, 0x1400ffb0 }, - { 0x0c000457, 0x1400ffb0 }, - { 0x0c000458, 0x1400ffb0 }, - { 0x0c000459, 0x1400ffb0 }, - { 0x0c00045a, 0x1400ffb0 }, - { 0x0c00045b, 0x1400ffb0 }, - { 0x0c00045c, 0x1400ffb0 }, - { 0x0c00045d, 0x1400ffb0 }, - { 0x0c00045e, 0x1400ffb0 }, - { 0x0c00045f, 0x1400ffb0 }, - { 0x0c000460, 0x24000001 }, - { 0x0c000461, 0x1400ffff }, - { 0x0c000462, 0x24000001 }, - { 0x0c000463, 0x1400ffff }, - { 0x0c000464, 0x24000001 }, - { 0x0c000465, 0x1400ffff }, - { 0x0c000466, 0x24000001 }, - { 0x0c000467, 0x1400ffff }, - { 0x0c000468, 0x24000001 }, - { 0x0c000469, 0x1400ffff }, - { 0x0c00046a, 0x24000001 }, - { 0x0c00046b, 0x1400ffff }, - { 0x0c00046c, 0x24000001 }, - { 0x0c00046d, 0x1400ffff }, - { 0x0c00046e, 0x24000001 }, - { 0x0c00046f, 0x1400ffff }, - { 0x0c000470, 0x24000001 }, - { 0x0c000471, 0x1400ffff }, - { 0x0c000472, 0x24000001 }, - { 0x0c000473, 0x1400ffff }, - { 0x0c000474, 0x24000001 }, - { 0x0c000475, 0x1400ffff }, - { 0x0c000476, 0x24000001 }, - { 0x0c000477, 0x1400ffff }, - { 0x0c000478, 0x24000001 }, - { 0x0c000479, 0x1400ffff }, - { 0x0c00047a, 0x24000001 }, - { 0x0c00047b, 0x1400ffff }, - { 0x0c00047c, 0x24000001 }, - { 0x0c00047d, 0x1400ffff }, - { 0x0c00047e, 0x24000001 }, - { 0x0c00047f, 0x1400ffff }, - { 0x0c000480, 0x24000001 }, - { 0x0c000481, 0x1400ffff }, - { 0x0c000482, 0x68000000 }, - { 0x0c800483, 0x30000003 }, - { 0x0c800488, 0x2c000001 }, - { 0x0c00048a, 0x24000001 }, - { 0x0c00048b, 0x1400ffff }, - { 0x0c00048c, 0x24000001 }, - { 0x0c00048d, 0x1400ffff }, - { 0x0c00048e, 0x24000001 }, - { 0x0c00048f, 0x1400ffff }, - { 0x0c000490, 0x24000001 }, - { 0x0c000491, 0x1400ffff }, - { 0x0c000492, 0x24000001 }, - { 0x0c000493, 0x1400ffff }, - { 0x0c000494, 0x24000001 }, - { 0x0c000495, 0x1400ffff }, - { 0x0c000496, 0x24000001 }, - { 0x0c000497, 0x1400ffff }, - { 0x0c000498, 0x24000001 }, - { 0x0c000499, 0x1400ffff }, - { 0x0c00049a, 0x24000001 }, - { 0x0c00049b, 0x1400ffff }, - { 0x0c00049c, 0x24000001 }, - { 0x0c00049d, 0x1400ffff }, - { 0x0c00049e, 0x24000001 }, - { 0x0c00049f, 0x1400ffff }, - { 0x0c0004a0, 0x24000001 }, - { 0x0c0004a1, 0x1400ffff }, - { 0x0c0004a2, 0x24000001 }, - { 0x0c0004a3, 0x1400ffff }, - { 0x0c0004a4, 0x24000001 }, - { 0x0c0004a5, 0x1400ffff }, - { 0x0c0004a6, 0x24000001 }, - { 0x0c0004a7, 0x1400ffff }, - { 0x0c0004a8, 0x24000001 }, - { 0x0c0004a9, 0x1400ffff }, - { 0x0c0004aa, 0x24000001 }, - { 0x0c0004ab, 0x1400ffff }, - { 0x0c0004ac, 0x24000001 }, - { 0x0c0004ad, 0x1400ffff }, - { 0x0c0004ae, 0x24000001 }, - { 0x0c0004af, 0x1400ffff }, - { 0x0c0004b0, 0x24000001 }, - { 0x0c0004b1, 0x1400ffff }, - { 0x0c0004b2, 0x24000001 }, - { 0x0c0004b3, 0x1400ffff }, - { 0x0c0004b4, 0x24000001 }, - { 0x0c0004b5, 0x1400ffff }, - { 0x0c0004b6, 0x24000001 }, - { 0x0c0004b7, 0x1400ffff }, - { 0x0c0004b8, 0x24000001 }, - { 0x0c0004b9, 0x1400ffff }, - { 0x0c0004ba, 0x24000001 }, - { 0x0c0004bb, 0x1400ffff }, - { 0x0c0004bc, 0x24000001 }, - { 0x0c0004bd, 0x1400ffff }, - { 0x0c0004be, 0x24000001 }, - { 0x0c0004bf, 0x1400ffff }, - { 0x0c0004c0, 0x24000000 }, - { 0x0c0004c1, 0x24000001 }, - { 0x0c0004c2, 0x1400ffff }, - { 0x0c0004c3, 0x24000001 }, - { 0x0c0004c4, 0x1400ffff }, - { 0x0c0004c5, 0x24000001 }, - { 0x0c0004c6, 0x1400ffff }, - { 0x0c0004c7, 0x24000001 }, - { 0x0c0004c8, 0x1400ffff }, - { 0x0c0004c9, 0x24000001 }, - { 0x0c0004ca, 0x1400ffff }, - { 0x0c0004cb, 0x24000001 }, - { 0x0c0004cc, 0x1400ffff }, - { 0x0c0004cd, 0x24000001 }, - { 0x0c0004ce, 0x1400ffff }, - { 0x0c0004d0, 0x24000001 }, - { 0x0c0004d1, 0x1400ffff }, - { 0x0c0004d2, 0x24000001 }, - { 0x0c0004d3, 0x1400ffff }, - { 0x0c0004d4, 0x24000001 }, - { 0x0c0004d5, 0x1400ffff }, - { 0x0c0004d6, 0x24000001 }, - { 0x0c0004d7, 0x1400ffff }, - { 0x0c0004d8, 0x24000001 }, - { 0x0c0004d9, 0x1400ffff }, - { 0x0c0004da, 0x24000001 }, - { 0x0c0004db, 0x1400ffff }, - { 0x0c0004dc, 0x24000001 }, - { 0x0c0004dd, 0x1400ffff }, - { 0x0c0004de, 0x24000001 }, - { 0x0c0004df, 0x1400ffff }, - { 0x0c0004e0, 0x24000001 }, - { 0x0c0004e1, 0x1400ffff }, - { 0x0c0004e2, 0x24000001 }, - { 0x0c0004e3, 0x1400ffff }, - { 0x0c0004e4, 0x24000001 }, - { 0x0c0004e5, 0x1400ffff }, - { 0x0c0004e6, 0x24000001 }, - { 0x0c0004e7, 0x1400ffff }, - { 0x0c0004e8, 0x24000001 }, - { 0x0c0004e9, 0x1400ffff }, - { 0x0c0004ea, 0x24000001 }, - { 0x0c0004eb, 0x1400ffff }, - { 0x0c0004ec, 0x24000001 }, - { 0x0c0004ed, 0x1400ffff }, - { 0x0c0004ee, 0x24000001 }, - { 0x0c0004ef, 0x1400ffff }, - { 0x0c0004f0, 0x24000001 }, - { 0x0c0004f1, 0x1400ffff }, - { 0x0c0004f2, 0x24000001 }, - { 0x0c0004f3, 0x1400ffff }, - { 0x0c0004f4, 0x24000001 }, - { 0x0c0004f5, 0x1400ffff }, - { 0x0c0004f6, 0x24000001 }, - { 0x0c0004f7, 0x1400ffff }, - { 0x0c0004f8, 0x24000001 }, - { 0x0c0004f9, 0x1400ffff }, - { 0x0c000500, 0x24000001 }, - { 0x0c000501, 0x1400ffff }, - { 0x0c000502, 0x24000001 }, - { 0x0c000503, 0x1400ffff }, - { 0x0c000504, 0x24000001 }, - { 0x0c000505, 0x1400ffff }, - { 0x0c000506, 0x24000001 }, - { 0x0c000507, 0x1400ffff }, - { 0x0c000508, 0x24000001 }, - { 0x0c000509, 0x1400ffff }, - { 0x0c00050a, 0x24000001 }, - { 0x0c00050b, 0x1400ffff }, - { 0x0c00050c, 0x24000001 }, - { 0x0c00050d, 0x1400ffff }, - { 0x0c00050e, 0x24000001 }, - { 0x0c00050f, 0x1400ffff }, - { 0x01000531, 0x24000030 }, - { 0x01000532, 0x24000030 }, - { 0x01000533, 0x24000030 }, - { 0x01000534, 0x24000030 }, - { 0x01000535, 0x24000030 }, - { 0x01000536, 0x24000030 }, - { 0x01000537, 0x24000030 }, - { 0x01000538, 0x24000030 }, - { 0x01000539, 0x24000030 }, - { 0x0100053a, 0x24000030 }, - { 0x0100053b, 0x24000030 }, - { 0x0100053c, 0x24000030 }, - { 0x0100053d, 0x24000030 }, - { 0x0100053e, 0x24000030 }, - { 0x0100053f, 0x24000030 }, - { 0x01000540, 0x24000030 }, - { 0x01000541, 0x24000030 }, - { 0x01000542, 0x24000030 }, - { 0x01000543, 0x24000030 }, - { 0x01000544, 0x24000030 }, - { 0x01000545, 0x24000030 }, - { 0x01000546, 0x24000030 }, - { 0x01000547, 0x24000030 }, - { 0x01000548, 0x24000030 }, - { 0x01000549, 0x24000030 }, - { 0x0100054a, 0x24000030 }, - { 0x0100054b, 0x24000030 }, - { 0x0100054c, 0x24000030 }, - { 0x0100054d, 0x24000030 }, - { 0x0100054e, 0x24000030 }, - { 0x0100054f, 0x24000030 }, - { 0x01000550, 0x24000030 }, - { 0x01000551, 0x24000030 }, - { 0x01000552, 0x24000030 }, - { 0x01000553, 0x24000030 }, - { 0x01000554, 0x24000030 }, - { 0x01000555, 0x24000030 }, - { 0x01000556, 0x24000030 }, - { 0x01000559, 0x18000000 }, - { 0x0180055a, 0x54000005 }, - { 0x01000561, 0x1400ffd0 }, - { 0x01000562, 0x1400ffd0 }, - { 0x01000563, 0x1400ffd0 }, - { 0x01000564, 0x1400ffd0 }, - { 0x01000565, 0x1400ffd0 }, - { 0x01000566, 0x1400ffd0 }, - { 0x01000567, 0x1400ffd0 }, - { 0x01000568, 0x1400ffd0 }, - { 0x01000569, 0x1400ffd0 }, - { 0x0100056a, 0x1400ffd0 }, - { 0x0100056b, 0x1400ffd0 }, - { 0x0100056c, 0x1400ffd0 }, - { 0x0100056d, 0x1400ffd0 }, - { 0x0100056e, 0x1400ffd0 }, - { 0x0100056f, 0x1400ffd0 }, - { 0x01000570, 0x1400ffd0 }, - { 0x01000571, 0x1400ffd0 }, - { 0x01000572, 0x1400ffd0 }, - { 0x01000573, 0x1400ffd0 }, - { 0x01000574, 0x1400ffd0 }, - { 0x01000575, 0x1400ffd0 }, - { 0x01000576, 0x1400ffd0 }, - { 0x01000577, 0x1400ffd0 }, - { 0x01000578, 0x1400ffd0 }, - { 0x01000579, 0x1400ffd0 }, - { 0x0100057a, 0x1400ffd0 }, - { 0x0100057b, 0x1400ffd0 }, - { 0x0100057c, 0x1400ffd0 }, - { 0x0100057d, 0x1400ffd0 }, - { 0x0100057e, 0x1400ffd0 }, - { 0x0100057f, 0x1400ffd0 }, - { 0x01000580, 0x1400ffd0 }, - { 0x01000581, 0x1400ffd0 }, - { 0x01000582, 0x1400ffd0 }, - { 0x01000583, 0x1400ffd0 }, - { 0x01000584, 0x1400ffd0 }, - { 0x01000585, 0x1400ffd0 }, - { 0x01000586, 0x1400ffd0 }, - { 0x01000587, 0x14000000 }, - { 0x09000589, 0x54000000 }, - { 0x0100058a, 0x44000000 }, - { 0x19800591, 0x30000028 }, - { 0x198005bb, 0x30000002 }, - { 0x190005be, 0x54000000 }, - { 0x190005bf, 0x30000000 }, - { 0x190005c0, 0x54000000 }, - { 0x198005c1, 0x30000001 }, - { 0x190005c3, 0x54000000 }, - { 0x198005c4, 0x30000001 }, - { 0x190005c6, 0x54000000 }, - { 0x190005c7, 0x30000000 }, - { 0x198005d0, 0x1c00001a }, - { 0x198005f0, 0x1c000002 }, - { 0x198005f3, 0x54000001 }, - { 0x09800600, 0x04000003 }, - { 0x0000060b, 0x5c000000 }, - { 0x0980060c, 0x54000001 }, - { 0x0080060e, 0x68000001 }, - { 0x00800610, 0x30000005 }, - { 0x0900061b, 0x54000000 }, - { 0x0080061e, 0x54000001 }, - { 0x00800621, 0x1c000019 }, - { 0x09000640, 0x18000000 }, - { 0x00800641, 0x1c000009 }, - { 0x1b80064b, 0x30000013 }, - { 0x09800660, 0x34000009 }, - { 0x0080066a, 0x54000003 }, - { 0x0080066e, 0x1c000001 }, - { 0x1b000670, 0x30000000 }, - { 0x00800671, 0x1c000062 }, - { 0x000006d4, 0x54000000 }, - { 0x000006d5, 0x1c000000 }, - { 0x008006d6, 0x30000006 }, - { 0x090006dd, 0x04000000 }, - { 0x000006de, 0x2c000000 }, - { 0x008006df, 0x30000005 }, - { 0x008006e5, 0x18000001 }, - { 0x008006e7, 0x30000001 }, - { 0x000006e9, 0x68000000 }, - { 0x008006ea, 0x30000003 }, - { 0x008006ee, 0x1c000001 }, - { 0x008006f0, 0x34000009 }, - { 0x008006fa, 0x1c000002 }, - { 0x008006fd, 0x68000001 }, - { 0x000006ff, 0x1c000000 }, - { 0x31800700, 0x5400000d }, - { 0x3100070f, 0x04000000 }, - { 0x31000710, 0x1c000000 }, - { 0x31000711, 0x30000000 }, - { 0x31800712, 0x1c00001d }, - { 0x31800730, 0x3000001a }, - { 0x3180074d, 0x1c000020 }, - { 0x37800780, 0x1c000025 }, - { 0x378007a6, 0x3000000a }, - { 0x370007b1, 0x1c000000 }, - { 0x0e800901, 0x30000001 }, - { 0x0e000903, 0x28000000 }, - { 0x0e800904, 0x1c000035 }, - { 0x0e00093c, 0x30000000 }, - { 0x0e00093d, 0x1c000000 }, - { 0x0e80093e, 0x28000002 }, - { 0x0e800941, 0x30000007 }, - { 0x0e800949, 0x28000003 }, - { 0x0e00094d, 0x30000000 }, - { 0x0e000950, 0x1c000000 }, - { 0x0e800951, 0x30000003 }, - { 0x0e800958, 0x1c000009 }, - { 0x0e800962, 0x30000001 }, - { 0x09800964, 0x54000001 }, - { 0x0e800966, 0x34000009 }, - { 0x09000970, 0x54000000 }, - { 0x0e00097d, 0x1c000000 }, - { 0x02000981, 0x30000000 }, - { 0x02800982, 0x28000001 }, - { 0x02800985, 0x1c000007 }, - { 0x0280098f, 0x1c000001 }, - { 0x02800993, 0x1c000015 }, - { 0x028009aa, 0x1c000006 }, - { 0x020009b2, 0x1c000000 }, - { 0x028009b6, 0x1c000003 }, - { 0x020009bc, 0x30000000 }, - { 0x020009bd, 0x1c000000 }, - { 0x028009be, 0x28000002 }, - { 0x028009c1, 0x30000003 }, - { 0x028009c7, 0x28000001 }, - { 0x028009cb, 0x28000001 }, - { 0x020009cd, 0x30000000 }, - { 0x020009ce, 0x1c000000 }, - { 0x020009d7, 0x28000000 }, - { 0x028009dc, 0x1c000001 }, - { 0x028009df, 0x1c000002 }, - { 0x028009e2, 0x30000001 }, - { 0x028009e6, 0x34000009 }, - { 0x028009f0, 0x1c000001 }, - { 0x028009f2, 0x5c000001 }, - { 0x028009f4, 0x3c000005 }, - { 0x020009fa, 0x68000000 }, - { 0x15800a01, 0x30000001 }, - { 0x15000a03, 0x28000000 }, - { 0x15800a05, 0x1c000005 }, - { 0x15800a0f, 0x1c000001 }, - { 0x15800a13, 0x1c000015 }, - { 0x15800a2a, 0x1c000006 }, - { 0x15800a32, 0x1c000001 }, - { 0x15800a35, 0x1c000001 }, - { 0x15800a38, 0x1c000001 }, - { 0x15000a3c, 0x30000000 }, - { 0x15800a3e, 0x28000002 }, - { 0x15800a41, 0x30000001 }, - { 0x15800a47, 0x30000001 }, - { 0x15800a4b, 0x30000002 }, - { 0x15800a59, 0x1c000003 }, - { 0x15000a5e, 0x1c000000 }, - { 0x15800a66, 0x34000009 }, - { 0x15800a70, 0x30000001 }, - { 0x15800a72, 0x1c000002 }, - { 0x14800a81, 0x30000001 }, - { 0x14000a83, 0x28000000 }, - { 0x14800a85, 0x1c000008 }, - { 0x14800a8f, 0x1c000002 }, - { 0x14800a93, 0x1c000015 }, - { 0x14800aaa, 0x1c000006 }, - { 0x14800ab2, 0x1c000001 }, - { 0x14800ab5, 0x1c000004 }, - { 0x14000abc, 0x30000000 }, - { 0x14000abd, 0x1c000000 }, - { 0x14800abe, 0x28000002 }, - { 0x14800ac1, 0x30000004 }, - { 0x14800ac7, 0x30000001 }, - { 0x14000ac9, 0x28000000 }, - { 0x14800acb, 0x28000001 }, - { 0x14000acd, 0x30000000 }, - { 0x14000ad0, 0x1c000000 }, - { 0x14800ae0, 0x1c000001 }, - { 0x14800ae2, 0x30000001 }, - { 0x14800ae6, 0x34000009 }, - { 0x14000af1, 0x5c000000 }, - { 0x2b000b01, 0x30000000 }, - { 0x2b800b02, 0x28000001 }, - { 0x2b800b05, 0x1c000007 }, - { 0x2b800b0f, 0x1c000001 }, - { 0x2b800b13, 0x1c000015 }, - { 0x2b800b2a, 0x1c000006 }, - { 0x2b800b32, 0x1c000001 }, - { 0x2b800b35, 0x1c000004 }, - { 0x2b000b3c, 0x30000000 }, - { 0x2b000b3d, 0x1c000000 }, - { 0x2b000b3e, 0x28000000 }, - { 0x2b000b3f, 0x30000000 }, - { 0x2b000b40, 0x28000000 }, - { 0x2b800b41, 0x30000002 }, - { 0x2b800b47, 0x28000001 }, - { 0x2b800b4b, 0x28000001 }, - { 0x2b000b4d, 0x30000000 }, - { 0x2b000b56, 0x30000000 }, - { 0x2b000b57, 0x28000000 }, - { 0x2b800b5c, 0x1c000001 }, - { 0x2b800b5f, 0x1c000002 }, - { 0x2b800b66, 0x34000009 }, - { 0x2b000b70, 0x68000000 }, - { 0x2b000b71, 0x1c000000 }, - { 0x35000b82, 0x30000000 }, - { 0x35000b83, 0x1c000000 }, - { 0x35800b85, 0x1c000005 }, - { 0x35800b8e, 0x1c000002 }, - { 0x35800b92, 0x1c000003 }, - { 0x35800b99, 0x1c000001 }, - { 0x35000b9c, 0x1c000000 }, - { 0x35800b9e, 0x1c000001 }, - { 0x35800ba3, 0x1c000001 }, - { 0x35800ba8, 0x1c000002 }, - { 0x35800bae, 0x1c00000b }, - { 0x35800bbe, 0x28000001 }, - { 0x35000bc0, 0x30000000 }, - { 0x35800bc1, 0x28000001 }, - { 0x35800bc6, 0x28000002 }, - { 0x35800bca, 0x28000002 }, - { 0x35000bcd, 0x30000000 }, - { 0x35000bd7, 0x28000000 }, - { 0x35800be6, 0x34000009 }, - { 0x35800bf0, 0x3c000002 }, - { 0x35800bf3, 0x68000005 }, - { 0x35000bf9, 0x5c000000 }, - { 0x35000bfa, 0x68000000 }, - { 0x36800c01, 0x28000002 }, - { 0x36800c05, 0x1c000007 }, - { 0x36800c0e, 0x1c000002 }, - { 0x36800c12, 0x1c000016 }, - { 0x36800c2a, 0x1c000009 }, - { 0x36800c35, 0x1c000004 }, - { 0x36800c3e, 0x30000002 }, - { 0x36800c41, 0x28000003 }, - { 0x36800c46, 0x30000002 }, - { 0x36800c4a, 0x30000003 }, - { 0x36800c55, 0x30000001 }, - { 0x36800c60, 0x1c000001 }, - { 0x36800c66, 0x34000009 }, - { 0x1c800c82, 0x28000001 }, - { 0x1c800c85, 0x1c000007 }, - { 0x1c800c8e, 0x1c000002 }, - { 0x1c800c92, 0x1c000016 }, - { 0x1c800caa, 0x1c000009 }, - { 0x1c800cb5, 0x1c000004 }, - { 0x1c000cbc, 0x30000000 }, - { 0x1c000cbd, 0x1c000000 }, - { 0x1c000cbe, 0x28000000 }, - { 0x1c000cbf, 0x30000000 }, - { 0x1c800cc0, 0x28000004 }, - { 0x1c000cc6, 0x30000000 }, - { 0x1c800cc7, 0x28000001 }, - { 0x1c800cca, 0x28000001 }, - { 0x1c800ccc, 0x30000001 }, - { 0x1c800cd5, 0x28000001 }, - { 0x1c000cde, 0x1c000000 }, - { 0x1c800ce0, 0x1c000001 }, - { 0x1c800ce6, 0x34000009 }, - { 0x24800d02, 0x28000001 }, - { 0x24800d05, 0x1c000007 }, - { 0x24800d0e, 0x1c000002 }, - { 0x24800d12, 0x1c000016 }, - { 0x24800d2a, 0x1c00000f }, - { 0x24800d3e, 0x28000002 }, - { 0x24800d41, 0x30000002 }, - { 0x24800d46, 0x28000002 }, - { 0x24800d4a, 0x28000002 }, - { 0x24000d4d, 0x30000000 }, - { 0x24000d57, 0x28000000 }, - { 0x24800d60, 0x1c000001 }, - { 0x24800d66, 0x34000009 }, - { 0x2f800d82, 0x28000001 }, - { 0x2f800d85, 0x1c000011 }, - { 0x2f800d9a, 0x1c000017 }, - { 0x2f800db3, 0x1c000008 }, - { 0x2f000dbd, 0x1c000000 }, - { 0x2f800dc0, 0x1c000006 }, - { 0x2f000dca, 0x30000000 }, - { 0x2f800dcf, 0x28000002 }, - { 0x2f800dd2, 0x30000002 }, - { 0x2f000dd6, 0x30000000 }, - { 0x2f800dd8, 0x28000007 }, - { 0x2f800df2, 0x28000001 }, - { 0x2f000df4, 0x54000000 }, - { 0x38800e01, 0x1c00002f }, - { 0x38000e31, 0x30000000 }, - { 0x38800e32, 0x1c000001 }, - { 0x38800e34, 0x30000006 }, - { 0x09000e3f, 0x5c000000 }, - { 0x38800e40, 0x1c000005 }, - { 0x38000e46, 0x18000000 }, - { 0x38800e47, 0x30000007 }, - { 0x38000e4f, 0x54000000 }, - { 0x38800e50, 0x34000009 }, - { 0x38800e5a, 0x54000001 }, - { 0x20800e81, 0x1c000001 }, - { 0x20000e84, 0x1c000000 }, - { 0x20800e87, 0x1c000001 }, - { 0x20000e8a, 0x1c000000 }, - { 0x20000e8d, 0x1c000000 }, - { 0x20800e94, 0x1c000003 }, - { 0x20800e99, 0x1c000006 }, - { 0x20800ea1, 0x1c000002 }, - { 0x20000ea5, 0x1c000000 }, - { 0x20000ea7, 0x1c000000 }, - { 0x20800eaa, 0x1c000001 }, - { 0x20800ead, 0x1c000003 }, - { 0x20000eb1, 0x30000000 }, - { 0x20800eb2, 0x1c000001 }, - { 0x20800eb4, 0x30000005 }, - { 0x20800ebb, 0x30000001 }, - { 0x20000ebd, 0x1c000000 }, - { 0x20800ec0, 0x1c000004 }, - { 0x20000ec6, 0x18000000 }, - { 0x20800ec8, 0x30000005 }, - { 0x20800ed0, 0x34000009 }, - { 0x20800edc, 0x1c000001 }, - { 0x39000f00, 0x1c000000 }, - { 0x39800f01, 0x68000002 }, - { 0x39800f04, 0x5400000e }, - { 0x39800f13, 0x68000004 }, - { 0x39800f18, 0x30000001 }, - { 0x39800f1a, 0x68000005 }, - { 0x39800f20, 0x34000009 }, - { 0x39800f2a, 0x3c000009 }, - { 0x39000f34, 0x68000000 }, - { 0x39000f35, 0x30000000 }, - { 0x39000f36, 0x68000000 }, - { 0x39000f37, 0x30000000 }, - { 0x39000f38, 0x68000000 }, - { 0x39000f39, 0x30000000 }, - { 0x39000f3a, 0x58000000 }, - { 0x39000f3b, 0x48000000 }, - { 0x39000f3c, 0x58000000 }, - { 0x39000f3d, 0x48000000 }, - { 0x39800f3e, 0x28000001 }, - { 0x39800f40, 0x1c000007 }, - { 0x39800f49, 0x1c000021 }, - { 0x39800f71, 0x3000000d }, - { 0x39000f7f, 0x28000000 }, - { 0x39800f80, 0x30000004 }, - { 0x39000f85, 0x54000000 }, - { 0x39800f86, 0x30000001 }, - { 0x39800f88, 0x1c000003 }, - { 0x39800f90, 0x30000007 }, - { 0x39800f99, 0x30000023 }, - { 0x39800fbe, 0x68000007 }, - { 0x39000fc6, 0x30000000 }, - { 0x39800fc7, 0x68000005 }, - { 0x39000fcf, 0x68000000 }, - { 0x39800fd0, 0x54000001 }, - { 0x26801000, 0x1c000021 }, - { 0x26801023, 0x1c000004 }, - { 0x26801029, 0x1c000001 }, - { 0x2600102c, 0x28000000 }, - { 0x2680102d, 0x30000003 }, - { 0x26001031, 0x28000000 }, - { 0x26001032, 0x30000000 }, - { 0x26801036, 0x30000001 }, - { 0x26001038, 0x28000000 }, - { 0x26001039, 0x30000000 }, - { 0x26801040, 0x34000009 }, - { 0x2680104a, 0x54000005 }, - { 0x26801050, 0x1c000005 }, - { 0x26801056, 0x28000001 }, - { 0x26801058, 0x30000001 }, - { 0x100010a0, 0x24001c60 }, - { 0x100010a1, 0x24001c60 }, - { 0x100010a2, 0x24001c60 }, - { 0x100010a3, 0x24001c60 }, - { 0x100010a4, 0x24001c60 }, - { 0x100010a5, 0x24001c60 }, - { 0x100010a6, 0x24001c60 }, - { 0x100010a7, 0x24001c60 }, - { 0x100010a8, 0x24001c60 }, - { 0x100010a9, 0x24001c60 }, - { 0x100010aa, 0x24001c60 }, - { 0x100010ab, 0x24001c60 }, - { 0x100010ac, 0x24001c60 }, - { 0x100010ad, 0x24001c60 }, - { 0x100010ae, 0x24001c60 }, - { 0x100010af, 0x24001c60 }, - { 0x100010b0, 0x24001c60 }, - { 0x100010b1, 0x24001c60 }, - { 0x100010b2, 0x24001c60 }, - { 0x100010b3, 0x24001c60 }, - { 0x100010b4, 0x24001c60 }, - { 0x100010b5, 0x24001c60 }, - { 0x100010b6, 0x24001c60 }, - { 0x100010b7, 0x24001c60 }, - { 0x100010b8, 0x24001c60 }, - { 0x100010b9, 0x24001c60 }, - { 0x100010ba, 0x24001c60 }, - { 0x100010bb, 0x24001c60 }, - { 0x100010bc, 0x24001c60 }, - { 0x100010bd, 0x24001c60 }, - { 0x100010be, 0x24001c60 }, - { 0x100010bf, 0x24001c60 }, - { 0x100010c0, 0x24001c60 }, - { 0x100010c1, 0x24001c60 }, - { 0x100010c2, 0x24001c60 }, - { 0x100010c3, 0x24001c60 }, - { 0x100010c4, 0x24001c60 }, - { 0x100010c5, 0x24001c60 }, - { 0x108010d0, 0x1c00002a }, - { 0x090010fb, 0x54000000 }, - { 0x100010fc, 0x18000000 }, - { 0x17801100, 0x1c000059 }, - { 0x1780115f, 0x1c000043 }, - { 0x178011a8, 0x1c000051 }, - { 0x0f801200, 0x1c000048 }, - { 0x0f80124a, 0x1c000003 }, - { 0x0f801250, 0x1c000006 }, - { 0x0f001258, 0x1c000000 }, - { 0x0f80125a, 0x1c000003 }, - { 0x0f801260, 0x1c000028 }, - { 0x0f80128a, 0x1c000003 }, - { 0x0f801290, 0x1c000020 }, - { 0x0f8012b2, 0x1c000003 }, - { 0x0f8012b8, 0x1c000006 }, - { 0x0f0012c0, 0x1c000000 }, - { 0x0f8012c2, 0x1c000003 }, - { 0x0f8012c8, 0x1c00000e }, - { 0x0f8012d8, 0x1c000038 }, - { 0x0f801312, 0x1c000003 }, - { 0x0f801318, 0x1c000042 }, - { 0x0f00135f, 0x30000000 }, - { 0x0f001360, 0x68000000 }, - { 0x0f801361, 0x54000007 }, - { 0x0f801369, 0x3c000013 }, - { 0x0f801380, 0x1c00000f }, - { 0x0f801390, 0x68000009 }, - { 0x088013a0, 0x1c000054 }, - { 0x07801401, 0x1c00026b }, - { 0x0780166d, 0x54000001 }, - { 0x0780166f, 0x1c000007 }, - { 0x28001680, 0x74000000 }, - { 0x28801681, 0x1c000019 }, - { 0x2800169b, 0x58000000 }, - { 0x2800169c, 0x48000000 }, - { 0x2d8016a0, 0x1c00004a }, - { 0x098016eb, 0x54000002 }, - { 0x2d8016ee, 0x38000002 }, - { 0x32801700, 0x1c00000c }, - { 0x3280170e, 0x1c000003 }, - { 0x32801712, 0x30000002 }, - { 0x18801720, 0x1c000011 }, - { 0x18801732, 0x30000002 }, - { 0x09801735, 0x54000001 }, - { 0x06801740, 0x1c000011 }, - { 0x06801752, 0x30000001 }, - { 0x33801760, 0x1c00000c }, - { 0x3380176e, 0x1c000002 }, - { 0x33801772, 0x30000001 }, - { 0x1f801780, 0x1c000033 }, - { 0x1f8017b4, 0x04000001 }, - { 0x1f0017b6, 0x28000000 }, - { 0x1f8017b7, 0x30000006 }, - { 0x1f8017be, 0x28000007 }, - { 0x1f0017c6, 0x30000000 }, - { 0x1f8017c7, 0x28000001 }, - { 0x1f8017c9, 0x3000000a }, - { 0x1f8017d4, 0x54000002 }, - { 0x1f0017d7, 0x18000000 }, - { 0x1f8017d8, 0x54000002 }, - { 0x1f0017db, 0x5c000000 }, - { 0x1f0017dc, 0x1c000000 }, - { 0x1f0017dd, 0x30000000 }, - { 0x1f8017e0, 0x34000009 }, - { 0x1f8017f0, 0x3c000009 }, - { 0x25801800, 0x54000005 }, - { 0x25001806, 0x44000000 }, - { 0x25801807, 0x54000003 }, - { 0x2580180b, 0x30000002 }, - { 0x2500180e, 0x74000000 }, - { 0x25801810, 0x34000009 }, - { 0x25801820, 0x1c000022 }, - { 0x25001843, 0x18000000 }, - { 0x25801844, 0x1c000033 }, - { 0x25801880, 0x1c000028 }, - { 0x250018a9, 0x30000000 }, - { 0x22801900, 0x1c00001c }, - { 0x22801920, 0x30000002 }, - { 0x22801923, 0x28000003 }, - { 0x22801927, 0x30000001 }, - { 0x22801929, 0x28000002 }, - { 0x22801930, 0x28000001 }, - { 0x22001932, 0x30000000 }, - { 0x22801933, 0x28000005 }, - { 0x22801939, 0x30000002 }, - { 0x22001940, 0x68000000 }, - { 0x22801944, 0x54000001 }, - { 0x22801946, 0x34000009 }, - { 0x34801950, 0x1c00001d }, - { 0x34801970, 0x1c000004 }, - { 0x27801980, 0x1c000029 }, - { 0x278019b0, 0x28000010 }, - { 0x278019c1, 0x1c000006 }, - { 0x278019c8, 0x28000001 }, - { 0x278019d0, 0x34000009 }, - { 0x278019de, 0x54000001 }, - { 0x1f8019e0, 0x6800001f }, - { 0x05801a00, 0x1c000016 }, - { 0x05801a17, 0x30000001 }, - { 0x05801a19, 0x28000002 }, - { 0x05801a1e, 0x54000001 }, - { 0x21801d00, 0x1400002b }, - { 0x21801d2c, 0x18000035 }, - { 0x21801d62, 0x14000015 }, - { 0x0c001d78, 0x18000000 }, - { 0x21801d79, 0x14000021 }, - { 0x21801d9b, 0x18000024 }, - { 0x1b801dc0, 0x30000003 }, - { 0x21001e00, 0x24000001 }, - { 0x21001e01, 0x1400ffff }, - { 0x21001e02, 0x24000001 }, - { 0x21001e03, 0x1400ffff }, - { 0x21001e04, 0x24000001 }, - { 0x21001e05, 0x1400ffff }, - { 0x21001e06, 0x24000001 }, - { 0x21001e07, 0x1400ffff }, - { 0x21001e08, 0x24000001 }, - { 0x21001e09, 0x1400ffff }, - { 0x21001e0a, 0x24000001 }, - { 0x21001e0b, 0x1400ffff }, - { 0x21001e0c, 0x24000001 }, - { 0x21001e0d, 0x1400ffff }, - { 0x21001e0e, 0x24000001 }, - { 0x21001e0f, 0x1400ffff }, - { 0x21001e10, 0x24000001 }, - { 0x21001e11, 0x1400ffff }, - { 0x21001e12, 0x24000001 }, - { 0x21001e13, 0x1400ffff }, - { 0x21001e14, 0x24000001 }, - { 0x21001e15, 0x1400ffff }, - { 0x21001e16, 0x24000001 }, - { 0x21001e17, 0x1400ffff }, - { 0x21001e18, 0x24000001 }, - { 0x21001e19, 0x1400ffff }, - { 0x21001e1a, 0x24000001 }, - { 0x21001e1b, 0x1400ffff }, - { 0x21001e1c, 0x24000001 }, - { 0x21001e1d, 0x1400ffff }, - { 0x21001e1e, 0x24000001 }, - { 0x21001e1f, 0x1400ffff }, - { 0x21001e20, 0x24000001 }, - { 0x21001e21, 0x1400ffff }, - { 0x21001e22, 0x24000001 }, - { 0x21001e23, 0x1400ffff }, - { 0x21001e24, 0x24000001 }, - { 0x21001e25, 0x1400ffff }, - { 0x21001e26, 0x24000001 }, - { 0x21001e27, 0x1400ffff }, - { 0x21001e28, 0x24000001 }, - { 0x21001e29, 0x1400ffff }, - { 0x21001e2a, 0x24000001 }, - { 0x21001e2b, 0x1400ffff }, - { 0x21001e2c, 0x24000001 }, - { 0x21001e2d, 0x1400ffff }, - { 0x21001e2e, 0x24000001 }, - { 0x21001e2f, 0x1400ffff }, - { 0x21001e30, 0x24000001 }, - { 0x21001e31, 0x1400ffff }, - { 0x21001e32, 0x24000001 }, - { 0x21001e33, 0x1400ffff }, - { 0x21001e34, 0x24000001 }, - { 0x21001e35, 0x1400ffff }, - { 0x21001e36, 0x24000001 }, - { 0x21001e37, 0x1400ffff }, - { 0x21001e38, 0x24000001 }, - { 0x21001e39, 0x1400ffff }, - { 0x21001e3a, 0x24000001 }, - { 0x21001e3b, 0x1400ffff }, - { 0x21001e3c, 0x24000001 }, - { 0x21001e3d, 0x1400ffff }, - { 0x21001e3e, 0x24000001 }, - { 0x21001e3f, 0x1400ffff }, - { 0x21001e40, 0x24000001 }, - { 0x21001e41, 0x1400ffff }, - { 0x21001e42, 0x24000001 }, - { 0x21001e43, 0x1400ffff }, - { 0x21001e44, 0x24000001 }, - { 0x21001e45, 0x1400ffff }, - { 0x21001e46, 0x24000001 }, - { 0x21001e47, 0x1400ffff }, - { 0x21001e48, 0x24000001 }, - { 0x21001e49, 0x1400ffff }, - { 0x21001e4a, 0x24000001 }, - { 0x21001e4b, 0x1400ffff }, - { 0x21001e4c, 0x24000001 }, - { 0x21001e4d, 0x1400ffff }, - { 0x21001e4e, 0x24000001 }, - { 0x21001e4f, 0x1400ffff }, - { 0x21001e50, 0x24000001 }, - { 0x21001e51, 0x1400ffff }, - { 0x21001e52, 0x24000001 }, - { 0x21001e53, 0x1400ffff }, - { 0x21001e54, 0x24000001 }, - { 0x21001e55, 0x1400ffff }, - { 0x21001e56, 0x24000001 }, - { 0x21001e57, 0x1400ffff }, - { 0x21001e58, 0x24000001 }, - { 0x21001e59, 0x1400ffff }, - { 0x21001e5a, 0x24000001 }, - { 0x21001e5b, 0x1400ffff }, - { 0x21001e5c, 0x24000001 }, - { 0x21001e5d, 0x1400ffff }, - { 0x21001e5e, 0x24000001 }, - { 0x21001e5f, 0x1400ffff }, - { 0x21001e60, 0x24000001 }, - { 0x21001e61, 0x1400ffff }, - { 0x21001e62, 0x24000001 }, - { 0x21001e63, 0x1400ffff }, - { 0x21001e64, 0x24000001 }, - { 0x21001e65, 0x1400ffff }, - { 0x21001e66, 0x24000001 }, - { 0x21001e67, 0x1400ffff }, - { 0x21001e68, 0x24000001 }, - { 0x21001e69, 0x1400ffff }, - { 0x21001e6a, 0x24000001 }, - { 0x21001e6b, 0x1400ffff }, - { 0x21001e6c, 0x24000001 }, - { 0x21001e6d, 0x1400ffff }, - { 0x21001e6e, 0x24000001 }, - { 0x21001e6f, 0x1400ffff }, - { 0x21001e70, 0x24000001 }, - { 0x21001e71, 0x1400ffff }, - { 0x21001e72, 0x24000001 }, - { 0x21001e73, 0x1400ffff }, - { 0x21001e74, 0x24000001 }, - { 0x21001e75, 0x1400ffff }, - { 0x21001e76, 0x24000001 }, - { 0x21001e77, 0x1400ffff }, - { 0x21001e78, 0x24000001 }, - { 0x21001e79, 0x1400ffff }, - { 0x21001e7a, 0x24000001 }, - { 0x21001e7b, 0x1400ffff }, - { 0x21001e7c, 0x24000001 }, - { 0x21001e7d, 0x1400ffff }, - { 0x21001e7e, 0x24000001 }, - { 0x21001e7f, 0x1400ffff }, - { 0x21001e80, 0x24000001 }, - { 0x21001e81, 0x1400ffff }, - { 0x21001e82, 0x24000001 }, - { 0x21001e83, 0x1400ffff }, - { 0x21001e84, 0x24000001 }, - { 0x21001e85, 0x1400ffff }, - { 0x21001e86, 0x24000001 }, - { 0x21001e87, 0x1400ffff }, - { 0x21001e88, 0x24000001 }, - { 0x21001e89, 0x1400ffff }, - { 0x21001e8a, 0x24000001 }, - { 0x21001e8b, 0x1400ffff }, - { 0x21001e8c, 0x24000001 }, - { 0x21001e8d, 0x1400ffff }, - { 0x21001e8e, 0x24000001 }, - { 0x21001e8f, 0x1400ffff }, - { 0x21001e90, 0x24000001 }, - { 0x21001e91, 0x1400ffff }, - { 0x21001e92, 0x24000001 }, - { 0x21001e93, 0x1400ffff }, - { 0x21001e94, 0x24000001 }, - { 0x21001e95, 0x1400ffff }, - { 0x21801e96, 0x14000004 }, - { 0x21001e9b, 0x1400ffc5 }, - { 0x21001ea0, 0x24000001 }, - { 0x21001ea1, 0x1400ffff }, - { 0x21001ea2, 0x24000001 }, - { 0x21001ea3, 0x1400ffff }, - { 0x21001ea4, 0x24000001 }, - { 0x21001ea5, 0x1400ffff }, - { 0x21001ea6, 0x24000001 }, - { 0x21001ea7, 0x1400ffff }, - { 0x21001ea8, 0x24000001 }, - { 0x21001ea9, 0x1400ffff }, - { 0x21001eaa, 0x24000001 }, - { 0x21001eab, 0x1400ffff }, - { 0x21001eac, 0x24000001 }, - { 0x21001ead, 0x1400ffff }, - { 0x21001eae, 0x24000001 }, - { 0x21001eaf, 0x1400ffff }, - { 0x21001eb0, 0x24000001 }, - { 0x21001eb1, 0x1400ffff }, - { 0x21001eb2, 0x24000001 }, - { 0x21001eb3, 0x1400ffff }, - { 0x21001eb4, 0x24000001 }, - { 0x21001eb5, 0x1400ffff }, - { 0x21001eb6, 0x24000001 }, - { 0x21001eb7, 0x1400ffff }, - { 0x21001eb8, 0x24000001 }, - { 0x21001eb9, 0x1400ffff }, - { 0x21001eba, 0x24000001 }, - { 0x21001ebb, 0x1400ffff }, - { 0x21001ebc, 0x24000001 }, - { 0x21001ebd, 0x1400ffff }, - { 0x21001ebe, 0x24000001 }, - { 0x21001ebf, 0x1400ffff }, - { 0x21001ec0, 0x24000001 }, - { 0x21001ec1, 0x1400ffff }, - { 0x21001ec2, 0x24000001 }, - { 0x21001ec3, 0x1400ffff }, - { 0x21001ec4, 0x24000001 }, - { 0x21001ec5, 0x1400ffff }, - { 0x21001ec6, 0x24000001 }, - { 0x21001ec7, 0x1400ffff }, - { 0x21001ec8, 0x24000001 }, - { 0x21001ec9, 0x1400ffff }, - { 0x21001eca, 0x24000001 }, - { 0x21001ecb, 0x1400ffff }, - { 0x21001ecc, 0x24000001 }, - { 0x21001ecd, 0x1400ffff }, - { 0x21001ece, 0x24000001 }, - { 0x21001ecf, 0x1400ffff }, - { 0x21001ed0, 0x24000001 }, - { 0x21001ed1, 0x1400ffff }, - { 0x21001ed2, 0x24000001 }, - { 0x21001ed3, 0x1400ffff }, - { 0x21001ed4, 0x24000001 }, - { 0x21001ed5, 0x1400ffff }, - { 0x21001ed6, 0x24000001 }, - { 0x21001ed7, 0x1400ffff }, - { 0x21001ed8, 0x24000001 }, - { 0x21001ed9, 0x1400ffff }, - { 0x21001eda, 0x24000001 }, - { 0x21001edb, 0x1400ffff }, - { 0x21001edc, 0x24000001 }, - { 0x21001edd, 0x1400ffff }, - { 0x21001ede, 0x24000001 }, - { 0x21001edf, 0x1400ffff }, - { 0x21001ee0, 0x24000001 }, - { 0x21001ee1, 0x1400ffff }, - { 0x21001ee2, 0x24000001 }, - { 0x21001ee3, 0x1400ffff }, - { 0x21001ee4, 0x24000001 }, - { 0x21001ee5, 0x1400ffff }, - { 0x21001ee6, 0x24000001 }, - { 0x21001ee7, 0x1400ffff }, - { 0x21001ee8, 0x24000001 }, - { 0x21001ee9, 0x1400ffff }, - { 0x21001eea, 0x24000001 }, - { 0x21001eeb, 0x1400ffff }, - { 0x21001eec, 0x24000001 }, - { 0x21001eed, 0x1400ffff }, - { 0x21001eee, 0x24000001 }, - { 0x21001eef, 0x1400ffff }, - { 0x21001ef0, 0x24000001 }, - { 0x21001ef1, 0x1400ffff }, - { 0x21001ef2, 0x24000001 }, - { 0x21001ef3, 0x1400ffff }, - { 0x21001ef4, 0x24000001 }, - { 0x21001ef5, 0x1400ffff }, - { 0x21001ef6, 0x24000001 }, - { 0x21001ef7, 0x1400ffff }, - { 0x21001ef8, 0x24000001 }, - { 0x21001ef9, 0x1400ffff }, - { 0x13001f00, 0x14000008 }, - { 0x13001f01, 0x14000008 }, - { 0x13001f02, 0x14000008 }, - { 0x13001f03, 0x14000008 }, - { 0x13001f04, 0x14000008 }, - { 0x13001f05, 0x14000008 }, - { 0x13001f06, 0x14000008 }, - { 0x13001f07, 0x14000008 }, - { 0x13001f08, 0x2400fff8 }, - { 0x13001f09, 0x2400fff8 }, - { 0x13001f0a, 0x2400fff8 }, - { 0x13001f0b, 0x2400fff8 }, - { 0x13001f0c, 0x2400fff8 }, - { 0x13001f0d, 0x2400fff8 }, - { 0x13001f0e, 0x2400fff8 }, - { 0x13001f0f, 0x2400fff8 }, - { 0x13001f10, 0x14000008 }, - { 0x13001f11, 0x14000008 }, - { 0x13001f12, 0x14000008 }, - { 0x13001f13, 0x14000008 }, - { 0x13001f14, 0x14000008 }, - { 0x13001f15, 0x14000008 }, - { 0x13001f18, 0x2400fff8 }, - { 0x13001f19, 0x2400fff8 }, - { 0x13001f1a, 0x2400fff8 }, - { 0x13001f1b, 0x2400fff8 }, - { 0x13001f1c, 0x2400fff8 }, - { 0x13001f1d, 0x2400fff8 }, - { 0x13001f20, 0x14000008 }, - { 0x13001f21, 0x14000008 }, - { 0x13001f22, 0x14000008 }, - { 0x13001f23, 0x14000008 }, - { 0x13001f24, 0x14000008 }, - { 0x13001f25, 0x14000008 }, - { 0x13001f26, 0x14000008 }, - { 0x13001f27, 0x14000008 }, - { 0x13001f28, 0x2400fff8 }, - { 0x13001f29, 0x2400fff8 }, - { 0x13001f2a, 0x2400fff8 }, - { 0x13001f2b, 0x2400fff8 }, - { 0x13001f2c, 0x2400fff8 }, - { 0x13001f2d, 0x2400fff8 }, - { 0x13001f2e, 0x2400fff8 }, - { 0x13001f2f, 0x2400fff8 }, - { 0x13001f30, 0x14000008 }, - { 0x13001f31, 0x14000008 }, - { 0x13001f32, 0x14000008 }, - { 0x13001f33, 0x14000008 }, - { 0x13001f34, 0x14000008 }, - { 0x13001f35, 0x14000008 }, - { 0x13001f36, 0x14000008 }, - { 0x13001f37, 0x14000008 }, - { 0x13001f38, 0x2400fff8 }, - { 0x13001f39, 0x2400fff8 }, - { 0x13001f3a, 0x2400fff8 }, - { 0x13001f3b, 0x2400fff8 }, - { 0x13001f3c, 0x2400fff8 }, - { 0x13001f3d, 0x2400fff8 }, - { 0x13001f3e, 0x2400fff8 }, - { 0x13001f3f, 0x2400fff8 }, - { 0x13001f40, 0x14000008 }, - { 0x13001f41, 0x14000008 }, - { 0x13001f42, 0x14000008 }, - { 0x13001f43, 0x14000008 }, - { 0x13001f44, 0x14000008 }, - { 0x13001f45, 0x14000008 }, - { 0x13001f48, 0x2400fff8 }, - { 0x13001f49, 0x2400fff8 }, - { 0x13001f4a, 0x2400fff8 }, - { 0x13001f4b, 0x2400fff8 }, - { 0x13001f4c, 0x2400fff8 }, - { 0x13001f4d, 0x2400fff8 }, - { 0x13001f50, 0x14000000 }, - { 0x13001f51, 0x14000008 }, - { 0x13001f52, 0x14000000 }, - { 0x13001f53, 0x14000008 }, - { 0x13001f54, 0x14000000 }, - { 0x13001f55, 0x14000008 }, - { 0x13001f56, 0x14000000 }, - { 0x13001f57, 0x14000008 }, - { 0x13001f59, 0x2400fff8 }, - { 0x13001f5b, 0x2400fff8 }, - { 0x13001f5d, 0x2400fff8 }, - { 0x13001f5f, 0x2400fff8 }, - { 0x13001f60, 0x14000008 }, - { 0x13001f61, 0x14000008 }, - { 0x13001f62, 0x14000008 }, - { 0x13001f63, 0x14000008 }, - { 0x13001f64, 0x14000008 }, - { 0x13001f65, 0x14000008 }, - { 0x13001f66, 0x14000008 }, - { 0x13001f67, 0x14000008 }, - { 0x13001f68, 0x2400fff8 }, - { 0x13001f69, 0x2400fff8 }, - { 0x13001f6a, 0x2400fff8 }, - { 0x13001f6b, 0x2400fff8 }, - { 0x13001f6c, 0x2400fff8 }, - { 0x13001f6d, 0x2400fff8 }, - { 0x13001f6e, 0x2400fff8 }, - { 0x13001f6f, 0x2400fff8 }, - { 0x13001f70, 0x1400004a }, - { 0x13001f71, 0x1400004a }, - { 0x13001f72, 0x14000056 }, - { 0x13001f73, 0x14000056 }, - { 0x13001f74, 0x14000056 }, - { 0x13001f75, 0x14000056 }, - { 0x13001f76, 0x14000064 }, - { 0x13001f77, 0x14000064 }, - { 0x13001f78, 0x14000080 }, - { 0x13001f79, 0x14000080 }, - { 0x13001f7a, 0x14000070 }, - { 0x13001f7b, 0x14000070 }, - { 0x13001f7c, 0x1400007e }, - { 0x13001f7d, 0x1400007e }, - { 0x13001f80, 0x14000008 }, - { 0x13001f81, 0x14000008 }, - { 0x13001f82, 0x14000008 }, - { 0x13001f83, 0x14000008 }, - { 0x13001f84, 0x14000008 }, - { 0x13001f85, 0x14000008 }, - { 0x13001f86, 0x14000008 }, - { 0x13001f87, 0x14000008 }, - { 0x13001f88, 0x2000fff8 }, - { 0x13001f89, 0x2000fff8 }, - { 0x13001f8a, 0x2000fff8 }, - { 0x13001f8b, 0x2000fff8 }, - { 0x13001f8c, 0x2000fff8 }, - { 0x13001f8d, 0x2000fff8 }, - { 0x13001f8e, 0x2000fff8 }, - { 0x13001f8f, 0x2000fff8 }, - { 0x13001f90, 0x14000008 }, - { 0x13001f91, 0x14000008 }, - { 0x13001f92, 0x14000008 }, - { 0x13001f93, 0x14000008 }, - { 0x13001f94, 0x14000008 }, - { 0x13001f95, 0x14000008 }, - { 0x13001f96, 0x14000008 }, - { 0x13001f97, 0x14000008 }, - { 0x13001f98, 0x2000fff8 }, - { 0x13001f99, 0x2000fff8 }, - { 0x13001f9a, 0x2000fff8 }, - { 0x13001f9b, 0x2000fff8 }, - { 0x13001f9c, 0x2000fff8 }, - { 0x13001f9d, 0x2000fff8 }, - { 0x13001f9e, 0x2000fff8 }, - { 0x13001f9f, 0x2000fff8 }, - { 0x13001fa0, 0x14000008 }, - { 0x13001fa1, 0x14000008 }, - { 0x13001fa2, 0x14000008 }, - { 0x13001fa3, 0x14000008 }, - { 0x13001fa4, 0x14000008 }, - { 0x13001fa5, 0x14000008 }, - { 0x13001fa6, 0x14000008 }, - { 0x13001fa7, 0x14000008 }, - { 0x13001fa8, 0x2000fff8 }, - { 0x13001fa9, 0x2000fff8 }, - { 0x13001faa, 0x2000fff8 }, - { 0x13001fab, 0x2000fff8 }, - { 0x13001fac, 0x2000fff8 }, - { 0x13001fad, 0x2000fff8 }, - { 0x13001fae, 0x2000fff8 }, - { 0x13001faf, 0x2000fff8 }, - { 0x13001fb0, 0x14000008 }, - { 0x13001fb1, 0x14000008 }, - { 0x13001fb2, 0x14000000 }, - { 0x13001fb3, 0x14000009 }, - { 0x13001fb4, 0x14000000 }, - { 0x13801fb6, 0x14000001 }, - { 0x13001fb8, 0x2400fff8 }, - { 0x13001fb9, 0x2400fff8 }, - { 0x13001fba, 0x2400ffb6 }, - { 0x13001fbb, 0x2400ffb6 }, - { 0x13001fbc, 0x2000fff7 }, - { 0x13001fbd, 0x60000000 }, - { 0x13001fbe, 0x1400e3db }, - { 0x13801fbf, 0x60000002 }, - { 0x13001fc2, 0x14000000 }, - { 0x13001fc3, 0x14000009 }, - { 0x13001fc4, 0x14000000 }, - { 0x13801fc6, 0x14000001 }, - { 0x13001fc8, 0x2400ffaa }, - { 0x13001fc9, 0x2400ffaa }, - { 0x13001fca, 0x2400ffaa }, - { 0x13001fcb, 0x2400ffaa }, - { 0x13001fcc, 0x2000fff7 }, - { 0x13801fcd, 0x60000002 }, - { 0x13001fd0, 0x14000008 }, - { 0x13001fd1, 0x14000008 }, - { 0x13801fd2, 0x14000001 }, - { 0x13801fd6, 0x14000001 }, - { 0x13001fd8, 0x2400fff8 }, - { 0x13001fd9, 0x2400fff8 }, - { 0x13001fda, 0x2400ff9c }, - { 0x13001fdb, 0x2400ff9c }, - { 0x13801fdd, 0x60000002 }, - { 0x13001fe0, 0x14000008 }, - { 0x13001fe1, 0x14000008 }, - { 0x13801fe2, 0x14000002 }, - { 0x13001fe5, 0x14000007 }, - { 0x13801fe6, 0x14000001 }, - { 0x13001fe8, 0x2400fff8 }, - { 0x13001fe9, 0x2400fff8 }, - { 0x13001fea, 0x2400ff90 }, - { 0x13001feb, 0x2400ff90 }, - { 0x13001fec, 0x2400fff9 }, - { 0x13801fed, 0x60000002 }, - { 0x13001ff2, 0x14000000 }, - { 0x13001ff3, 0x14000009 }, - { 0x13001ff4, 0x14000000 }, - { 0x13801ff6, 0x14000001 }, - { 0x13001ff8, 0x2400ff80 }, - { 0x13001ff9, 0x2400ff80 }, - { 0x13001ffa, 0x2400ff82 }, - { 0x13001ffb, 0x2400ff82 }, - { 0x13001ffc, 0x2000fff7 }, - { 0x13801ffd, 0x60000001 }, - { 0x09802000, 0x7400000a }, - { 0x0980200b, 0x04000004 }, - { 0x09802010, 0x44000005 }, - { 0x09802016, 0x54000001 }, - { 0x09002018, 0x50000000 }, - { 0x09002019, 0x4c000000 }, - { 0x0900201a, 0x58000000 }, - { 0x0980201b, 0x50000001 }, - { 0x0900201d, 0x4c000000 }, - { 0x0900201e, 0x58000000 }, - { 0x0900201f, 0x50000000 }, - { 0x09802020, 0x54000007 }, - { 0x09002028, 0x6c000000 }, - { 0x09002029, 0x70000000 }, - { 0x0980202a, 0x04000004 }, - { 0x0900202f, 0x74000000 }, - { 0x09802030, 0x54000008 }, - { 0x09002039, 0x50000000 }, - { 0x0900203a, 0x4c000000 }, - { 0x0980203b, 0x54000003 }, - { 0x0980203f, 0x40000001 }, - { 0x09802041, 0x54000002 }, - { 0x09002044, 0x64000000 }, - { 0x09002045, 0x58000000 }, - { 0x09002046, 0x48000000 }, - { 0x09802047, 0x5400000a }, - { 0x09002052, 0x64000000 }, - { 0x09002053, 0x54000000 }, - { 0x09002054, 0x40000000 }, - { 0x09802055, 0x54000009 }, - { 0x0900205f, 0x74000000 }, - { 0x09802060, 0x04000003 }, - { 0x0980206a, 0x04000005 }, - { 0x09002070, 0x3c000000 }, - { 0x21002071, 0x14000000 }, - { 0x09802074, 0x3c000005 }, - { 0x0980207a, 0x64000002 }, - { 0x0900207d, 0x58000000 }, - { 0x0900207e, 0x48000000 }, - { 0x2100207f, 0x14000000 }, - { 0x09802080, 0x3c000009 }, - { 0x0980208a, 0x64000002 }, - { 0x0900208d, 0x58000000 }, - { 0x0900208e, 0x48000000 }, - { 0x21802090, 0x18000004 }, - { 0x098020a0, 0x5c000015 }, - { 0x1b8020d0, 0x3000000c }, - { 0x1b8020dd, 0x2c000003 }, - { 0x1b0020e1, 0x30000000 }, - { 0x1b8020e2, 0x2c000002 }, - { 0x1b8020e5, 0x30000006 }, - { 0x09802100, 0x68000001 }, - { 0x09002102, 0x24000000 }, - { 0x09802103, 0x68000003 }, - { 0x09002107, 0x24000000 }, - { 0x09802108, 0x68000001 }, - { 0x0900210a, 0x14000000 }, - { 0x0980210b, 0x24000002 }, - { 0x0980210e, 0x14000001 }, - { 0x09802110, 0x24000002 }, - { 0x09002113, 0x14000000 }, - { 0x09002114, 0x68000000 }, - { 0x09002115, 0x24000000 }, - { 0x09802116, 0x68000002 }, - { 0x09802119, 0x24000004 }, - { 0x0980211e, 0x68000005 }, - { 0x09002124, 0x24000000 }, - { 0x09002125, 0x68000000 }, - { 0x13002126, 0x2400e2a3 }, - { 0x09002127, 0x68000000 }, - { 0x09002128, 0x24000000 }, - { 0x09002129, 0x68000000 }, - { 0x2100212a, 0x2400df41 }, - { 0x2100212b, 0x2400dfba }, - { 0x0980212c, 0x24000001 }, - { 0x0900212e, 0x68000000 }, - { 0x0900212f, 0x14000000 }, - { 0x09802130, 0x24000001 }, - { 0x09002132, 0x68000000 }, - { 0x09002133, 0x24000000 }, - { 0x09002134, 0x14000000 }, - { 0x09802135, 0x1c000003 }, - { 0x09002139, 0x14000000 }, - { 0x0980213a, 0x68000001 }, - { 0x0980213c, 0x14000001 }, - { 0x0980213e, 0x24000001 }, - { 0x09802140, 0x64000004 }, - { 0x09002145, 0x24000000 }, - { 0x09802146, 0x14000003 }, - { 0x0900214a, 0x68000000 }, - { 0x0900214b, 0x64000000 }, - { 0x0900214c, 0x68000000 }, - { 0x09802153, 0x3c00000c }, - { 0x09002160, 0x38000010 }, - { 0x09002161, 0x38000010 }, - { 0x09002162, 0x38000010 }, - { 0x09002163, 0x38000010 }, - { 0x09002164, 0x38000010 }, - { 0x09002165, 0x38000010 }, - { 0x09002166, 0x38000010 }, - { 0x09002167, 0x38000010 }, - { 0x09002168, 0x38000010 }, - { 0x09002169, 0x38000010 }, - { 0x0900216a, 0x38000010 }, - { 0x0900216b, 0x38000010 }, - { 0x0900216c, 0x38000010 }, - { 0x0900216d, 0x38000010 }, - { 0x0900216e, 0x38000010 }, - { 0x0900216f, 0x38000010 }, - { 0x09002170, 0x3800fff0 }, - { 0x09002171, 0x3800fff0 }, - { 0x09002172, 0x3800fff0 }, - { 0x09002173, 0x3800fff0 }, - { 0x09002174, 0x3800fff0 }, - { 0x09002175, 0x3800fff0 }, - { 0x09002176, 0x3800fff0 }, - { 0x09002177, 0x3800fff0 }, - { 0x09002178, 0x3800fff0 }, - { 0x09002179, 0x3800fff0 }, - { 0x0900217a, 0x3800fff0 }, - { 0x0900217b, 0x3800fff0 }, - { 0x0900217c, 0x3800fff0 }, - { 0x0900217d, 0x3800fff0 }, - { 0x0900217e, 0x3800fff0 }, - { 0x0900217f, 0x3800fff0 }, - { 0x09802180, 0x38000003 }, - { 0x09802190, 0x64000004 }, - { 0x09802195, 0x68000004 }, - { 0x0980219a, 0x64000001 }, - { 0x0980219c, 0x68000003 }, - { 0x090021a0, 0x64000000 }, - { 0x098021a1, 0x68000001 }, - { 0x090021a3, 0x64000000 }, - { 0x098021a4, 0x68000001 }, - { 0x090021a6, 0x64000000 }, - { 0x098021a7, 0x68000006 }, - { 0x090021ae, 0x64000000 }, - { 0x098021af, 0x6800001e }, - { 0x098021ce, 0x64000001 }, - { 0x098021d0, 0x68000001 }, - { 0x090021d2, 0x64000000 }, - { 0x090021d3, 0x68000000 }, - { 0x090021d4, 0x64000000 }, - { 0x098021d5, 0x6800001e }, - { 0x098021f4, 0x6400010b }, - { 0x09802300, 0x68000007 }, - { 0x09802308, 0x64000003 }, - { 0x0980230c, 0x68000013 }, - { 0x09802320, 0x64000001 }, - { 0x09802322, 0x68000006 }, - { 0x09002329, 0x58000000 }, - { 0x0900232a, 0x48000000 }, - { 0x0980232b, 0x68000050 }, - { 0x0900237c, 0x64000000 }, - { 0x0980237d, 0x6800001d }, - { 0x0980239b, 0x64000018 }, - { 0x090023b4, 0x58000000 }, - { 0x090023b5, 0x48000000 }, - { 0x090023b6, 0x54000000 }, - { 0x098023b7, 0x68000024 }, - { 0x09802400, 0x68000026 }, - { 0x09802440, 0x6800000a }, - { 0x09802460, 0x3c00003b }, - { 0x0980249c, 0x68000019 }, - { 0x090024b6, 0x6800001a }, - { 0x090024b7, 0x6800001a }, - { 0x090024b8, 0x6800001a }, - { 0x090024b9, 0x6800001a }, - { 0x090024ba, 0x6800001a }, - { 0x090024bb, 0x6800001a }, - { 0x090024bc, 0x6800001a }, - { 0x090024bd, 0x6800001a }, - { 0x090024be, 0x6800001a }, - { 0x090024bf, 0x6800001a }, - { 0x090024c0, 0x6800001a }, - { 0x090024c1, 0x6800001a }, - { 0x090024c2, 0x6800001a }, - { 0x090024c3, 0x6800001a }, - { 0x090024c4, 0x6800001a }, - { 0x090024c5, 0x6800001a }, - { 0x090024c6, 0x6800001a }, - { 0x090024c7, 0x6800001a }, - { 0x090024c8, 0x6800001a }, - { 0x090024c9, 0x6800001a }, - { 0x090024ca, 0x6800001a }, - { 0x090024cb, 0x6800001a }, - { 0x090024cc, 0x6800001a }, - { 0x090024cd, 0x6800001a }, - { 0x090024ce, 0x6800001a }, - { 0x090024cf, 0x6800001a }, - { 0x090024d0, 0x6800ffe6 }, - { 0x090024d1, 0x6800ffe6 }, - { 0x090024d2, 0x6800ffe6 }, - { 0x090024d3, 0x6800ffe6 }, - { 0x090024d4, 0x6800ffe6 }, - { 0x090024d5, 0x6800ffe6 }, - { 0x090024d6, 0x6800ffe6 }, - { 0x090024d7, 0x6800ffe6 }, - { 0x090024d8, 0x6800ffe6 }, - { 0x090024d9, 0x6800ffe6 }, - { 0x090024da, 0x6800ffe6 }, - { 0x090024db, 0x6800ffe6 }, - { 0x090024dc, 0x6800ffe6 }, - { 0x090024dd, 0x6800ffe6 }, - { 0x090024de, 0x6800ffe6 }, - { 0x090024df, 0x6800ffe6 }, - { 0x090024e0, 0x6800ffe6 }, - { 0x090024e1, 0x6800ffe6 }, - { 0x090024e2, 0x6800ffe6 }, - { 0x090024e3, 0x6800ffe6 }, - { 0x090024e4, 0x6800ffe6 }, - { 0x090024e5, 0x6800ffe6 }, - { 0x090024e6, 0x6800ffe6 }, - { 0x090024e7, 0x6800ffe6 }, - { 0x090024e8, 0x6800ffe6 }, - { 0x090024e9, 0x6800ffe6 }, - { 0x098024ea, 0x3c000015 }, - { 0x09802500, 0x680000b6 }, - { 0x090025b7, 0x64000000 }, - { 0x098025b8, 0x68000008 }, - { 0x090025c1, 0x64000000 }, - { 0x098025c2, 0x68000035 }, - { 0x098025f8, 0x64000007 }, - { 0x09802600, 0x6800006e }, - { 0x0900266f, 0x64000000 }, - { 0x09802670, 0x6800002c }, - { 0x098026a0, 0x68000011 }, - { 0x09802701, 0x68000003 }, - { 0x09802706, 0x68000003 }, - { 0x0980270c, 0x6800001b }, - { 0x09802729, 0x68000022 }, - { 0x0900274d, 0x68000000 }, - { 0x0980274f, 0x68000003 }, - { 0x09002756, 0x68000000 }, - { 0x09802758, 0x68000006 }, - { 0x09802761, 0x68000006 }, - { 0x09002768, 0x58000000 }, - { 0x09002769, 0x48000000 }, - { 0x0900276a, 0x58000000 }, - { 0x0900276b, 0x48000000 }, - { 0x0900276c, 0x58000000 }, - { 0x0900276d, 0x48000000 }, - { 0x0900276e, 0x58000000 }, - { 0x0900276f, 0x48000000 }, - { 0x09002770, 0x58000000 }, - { 0x09002771, 0x48000000 }, - { 0x09002772, 0x58000000 }, - { 0x09002773, 0x48000000 }, - { 0x09002774, 0x58000000 }, - { 0x09002775, 0x48000000 }, - { 0x09802776, 0x3c00001d }, - { 0x09002794, 0x68000000 }, - { 0x09802798, 0x68000017 }, - { 0x098027b1, 0x6800000d }, - { 0x098027c0, 0x64000004 }, - { 0x090027c5, 0x58000000 }, - { 0x090027c6, 0x48000000 }, - { 0x098027d0, 0x64000015 }, - { 0x090027e6, 0x58000000 }, - { 0x090027e7, 0x48000000 }, - { 0x090027e8, 0x58000000 }, - { 0x090027e9, 0x48000000 }, - { 0x090027ea, 0x58000000 }, - { 0x090027eb, 0x48000000 }, - { 0x098027f0, 0x6400000f }, - { 0x04802800, 0x680000ff }, - { 0x09802900, 0x64000082 }, - { 0x09002983, 0x58000000 }, - { 0x09002984, 0x48000000 }, - { 0x09002985, 0x58000000 }, - { 0x09002986, 0x48000000 }, - { 0x09002987, 0x58000000 }, - { 0x09002988, 0x48000000 }, - { 0x09002989, 0x58000000 }, - { 0x0900298a, 0x48000000 }, - { 0x0900298b, 0x58000000 }, - { 0x0900298c, 0x48000000 }, - { 0x0900298d, 0x58000000 }, - { 0x0900298e, 0x48000000 }, - { 0x0900298f, 0x58000000 }, - { 0x09002990, 0x48000000 }, - { 0x09002991, 0x58000000 }, - { 0x09002992, 0x48000000 }, - { 0x09002993, 0x58000000 }, - { 0x09002994, 0x48000000 }, - { 0x09002995, 0x58000000 }, - { 0x09002996, 0x48000000 }, - { 0x09002997, 0x58000000 }, - { 0x09002998, 0x48000000 }, - { 0x09802999, 0x6400003e }, - { 0x090029d8, 0x58000000 }, - { 0x090029d9, 0x48000000 }, - { 0x090029da, 0x58000000 }, - { 0x090029db, 0x48000000 }, - { 0x098029dc, 0x6400001f }, - { 0x090029fc, 0x58000000 }, - { 0x090029fd, 0x48000000 }, - { 0x098029fe, 0x64000101 }, - { 0x09802b00, 0x68000013 }, - { 0x11002c00, 0x24000030 }, - { 0x11002c01, 0x24000030 }, - { 0x11002c02, 0x24000030 }, - { 0x11002c03, 0x24000030 }, - { 0x11002c04, 0x24000030 }, - { 0x11002c05, 0x24000030 }, - { 0x11002c06, 0x24000030 }, - { 0x11002c07, 0x24000030 }, - { 0x11002c08, 0x24000030 }, - { 0x11002c09, 0x24000030 }, - { 0x11002c0a, 0x24000030 }, - { 0x11002c0b, 0x24000030 }, - { 0x11002c0c, 0x24000030 }, - { 0x11002c0d, 0x24000030 }, - { 0x11002c0e, 0x24000030 }, - { 0x11002c0f, 0x24000030 }, - { 0x11002c10, 0x24000030 }, - { 0x11002c11, 0x24000030 }, - { 0x11002c12, 0x24000030 }, - { 0x11002c13, 0x24000030 }, - { 0x11002c14, 0x24000030 }, - { 0x11002c15, 0x24000030 }, - { 0x11002c16, 0x24000030 }, - { 0x11002c17, 0x24000030 }, - { 0x11002c18, 0x24000030 }, - { 0x11002c19, 0x24000030 }, - { 0x11002c1a, 0x24000030 }, - { 0x11002c1b, 0x24000030 }, - { 0x11002c1c, 0x24000030 }, - { 0x11002c1d, 0x24000030 }, - { 0x11002c1e, 0x24000030 }, - { 0x11002c1f, 0x24000030 }, - { 0x11002c20, 0x24000030 }, - { 0x11002c21, 0x24000030 }, - { 0x11002c22, 0x24000030 }, - { 0x11002c23, 0x24000030 }, - { 0x11002c24, 0x24000030 }, - { 0x11002c25, 0x24000030 }, - { 0x11002c26, 0x24000030 }, - { 0x11002c27, 0x24000030 }, - { 0x11002c28, 0x24000030 }, - { 0x11002c29, 0x24000030 }, - { 0x11002c2a, 0x24000030 }, - { 0x11002c2b, 0x24000030 }, - { 0x11002c2c, 0x24000030 }, - { 0x11002c2d, 0x24000030 }, - { 0x11002c2e, 0x24000030 }, - { 0x11002c30, 0x1400ffd0 }, - { 0x11002c31, 0x1400ffd0 }, - { 0x11002c32, 0x1400ffd0 }, - { 0x11002c33, 0x1400ffd0 }, - { 0x11002c34, 0x1400ffd0 }, - { 0x11002c35, 0x1400ffd0 }, - { 0x11002c36, 0x1400ffd0 }, - { 0x11002c37, 0x1400ffd0 }, - { 0x11002c38, 0x1400ffd0 }, - { 0x11002c39, 0x1400ffd0 }, - { 0x11002c3a, 0x1400ffd0 }, - { 0x11002c3b, 0x1400ffd0 }, - { 0x11002c3c, 0x1400ffd0 }, - { 0x11002c3d, 0x1400ffd0 }, - { 0x11002c3e, 0x1400ffd0 }, - { 0x11002c3f, 0x1400ffd0 }, - { 0x11002c40, 0x1400ffd0 }, - { 0x11002c41, 0x1400ffd0 }, - { 0x11002c42, 0x1400ffd0 }, - { 0x11002c43, 0x1400ffd0 }, - { 0x11002c44, 0x1400ffd0 }, - { 0x11002c45, 0x1400ffd0 }, - { 0x11002c46, 0x1400ffd0 }, - { 0x11002c47, 0x1400ffd0 }, - { 0x11002c48, 0x1400ffd0 }, - { 0x11002c49, 0x1400ffd0 }, - { 0x11002c4a, 0x1400ffd0 }, - { 0x11002c4b, 0x1400ffd0 }, - { 0x11002c4c, 0x1400ffd0 }, - { 0x11002c4d, 0x1400ffd0 }, - { 0x11002c4e, 0x1400ffd0 }, - { 0x11002c4f, 0x1400ffd0 }, - { 0x11002c50, 0x1400ffd0 }, - { 0x11002c51, 0x1400ffd0 }, - { 0x11002c52, 0x1400ffd0 }, - { 0x11002c53, 0x1400ffd0 }, - { 0x11002c54, 0x1400ffd0 }, - { 0x11002c55, 0x1400ffd0 }, - { 0x11002c56, 0x1400ffd0 }, - { 0x11002c57, 0x1400ffd0 }, - { 0x11002c58, 0x1400ffd0 }, - { 0x11002c59, 0x1400ffd0 }, - { 0x11002c5a, 0x1400ffd0 }, - { 0x11002c5b, 0x1400ffd0 }, - { 0x11002c5c, 0x1400ffd0 }, - { 0x11002c5d, 0x1400ffd0 }, - { 0x11002c5e, 0x1400ffd0 }, - { 0x0a002c80, 0x24000001 }, - { 0x0a002c81, 0x1400ffff }, - { 0x0a002c82, 0x24000001 }, - { 0x0a002c83, 0x1400ffff }, - { 0x0a002c84, 0x24000001 }, - { 0x0a002c85, 0x1400ffff }, - { 0x0a002c86, 0x24000001 }, - { 0x0a002c87, 0x1400ffff }, - { 0x0a002c88, 0x24000001 }, - { 0x0a002c89, 0x1400ffff }, - { 0x0a002c8a, 0x24000001 }, - { 0x0a002c8b, 0x1400ffff }, - { 0x0a002c8c, 0x24000001 }, - { 0x0a002c8d, 0x1400ffff }, - { 0x0a002c8e, 0x24000001 }, - { 0x0a002c8f, 0x1400ffff }, - { 0x0a002c90, 0x24000001 }, - { 0x0a002c91, 0x1400ffff }, - { 0x0a002c92, 0x24000001 }, - { 0x0a002c93, 0x1400ffff }, - { 0x0a002c94, 0x24000001 }, - { 0x0a002c95, 0x1400ffff }, - { 0x0a002c96, 0x24000001 }, - { 0x0a002c97, 0x1400ffff }, - { 0x0a002c98, 0x24000001 }, - { 0x0a002c99, 0x1400ffff }, - { 0x0a002c9a, 0x24000001 }, - { 0x0a002c9b, 0x1400ffff }, - { 0x0a002c9c, 0x24000001 }, - { 0x0a002c9d, 0x1400ffff }, - { 0x0a002c9e, 0x24000001 }, - { 0x0a002c9f, 0x1400ffff }, - { 0x0a002ca0, 0x24000001 }, - { 0x0a002ca1, 0x1400ffff }, - { 0x0a002ca2, 0x24000001 }, - { 0x0a002ca3, 0x1400ffff }, - { 0x0a002ca4, 0x24000001 }, - { 0x0a002ca5, 0x1400ffff }, - { 0x0a002ca6, 0x24000001 }, - { 0x0a002ca7, 0x1400ffff }, - { 0x0a002ca8, 0x24000001 }, - { 0x0a002ca9, 0x1400ffff }, - { 0x0a002caa, 0x24000001 }, - { 0x0a002cab, 0x1400ffff }, - { 0x0a002cac, 0x24000001 }, - { 0x0a002cad, 0x1400ffff }, - { 0x0a002cae, 0x24000001 }, - { 0x0a002caf, 0x1400ffff }, - { 0x0a002cb0, 0x24000001 }, - { 0x0a002cb1, 0x1400ffff }, - { 0x0a002cb2, 0x24000001 }, - { 0x0a002cb3, 0x1400ffff }, - { 0x0a002cb4, 0x24000001 }, - { 0x0a002cb5, 0x1400ffff }, - { 0x0a002cb6, 0x24000001 }, - { 0x0a002cb7, 0x1400ffff }, - { 0x0a002cb8, 0x24000001 }, - { 0x0a002cb9, 0x1400ffff }, - { 0x0a002cba, 0x24000001 }, - { 0x0a002cbb, 0x1400ffff }, - { 0x0a002cbc, 0x24000001 }, - { 0x0a002cbd, 0x1400ffff }, - { 0x0a002cbe, 0x24000001 }, - { 0x0a002cbf, 0x1400ffff }, - { 0x0a002cc0, 0x24000001 }, - { 0x0a002cc1, 0x1400ffff }, - { 0x0a002cc2, 0x24000001 }, - { 0x0a002cc3, 0x1400ffff }, - { 0x0a002cc4, 0x24000001 }, - { 0x0a002cc5, 0x1400ffff }, - { 0x0a002cc6, 0x24000001 }, - { 0x0a002cc7, 0x1400ffff }, - { 0x0a002cc8, 0x24000001 }, - { 0x0a002cc9, 0x1400ffff }, - { 0x0a002cca, 0x24000001 }, - { 0x0a002ccb, 0x1400ffff }, - { 0x0a002ccc, 0x24000001 }, - { 0x0a002ccd, 0x1400ffff }, - { 0x0a002cce, 0x24000001 }, - { 0x0a002ccf, 0x1400ffff }, - { 0x0a002cd0, 0x24000001 }, - { 0x0a002cd1, 0x1400ffff }, - { 0x0a002cd2, 0x24000001 }, - { 0x0a002cd3, 0x1400ffff }, - { 0x0a002cd4, 0x24000001 }, - { 0x0a002cd5, 0x1400ffff }, - { 0x0a002cd6, 0x24000001 }, - { 0x0a002cd7, 0x1400ffff }, - { 0x0a002cd8, 0x24000001 }, - { 0x0a002cd9, 0x1400ffff }, - { 0x0a002cda, 0x24000001 }, - { 0x0a002cdb, 0x1400ffff }, - { 0x0a002cdc, 0x24000001 }, - { 0x0a002cdd, 0x1400ffff }, - { 0x0a002cde, 0x24000001 }, - { 0x0a002cdf, 0x1400ffff }, - { 0x0a002ce0, 0x24000001 }, - { 0x0a002ce1, 0x1400ffff }, - { 0x0a002ce2, 0x24000001 }, - { 0x0a002ce3, 0x1400ffff }, - { 0x0a002ce4, 0x14000000 }, - { 0x0a802ce5, 0x68000005 }, - { 0x0a802cf9, 0x54000003 }, - { 0x0a002cfd, 0x3c000000 }, - { 0x0a802cfe, 0x54000001 }, - { 0x10002d00, 0x1400e3a0 }, - { 0x10002d01, 0x1400e3a0 }, - { 0x10002d02, 0x1400e3a0 }, - { 0x10002d03, 0x1400e3a0 }, - { 0x10002d04, 0x1400e3a0 }, - { 0x10002d05, 0x1400e3a0 }, - { 0x10002d06, 0x1400e3a0 }, - { 0x10002d07, 0x1400e3a0 }, - { 0x10002d08, 0x1400e3a0 }, - { 0x10002d09, 0x1400e3a0 }, - { 0x10002d0a, 0x1400e3a0 }, - { 0x10002d0b, 0x1400e3a0 }, - { 0x10002d0c, 0x1400e3a0 }, - { 0x10002d0d, 0x1400e3a0 }, - { 0x10002d0e, 0x1400e3a0 }, - { 0x10002d0f, 0x1400e3a0 }, - { 0x10002d10, 0x1400e3a0 }, - { 0x10002d11, 0x1400e3a0 }, - { 0x10002d12, 0x1400e3a0 }, - { 0x10002d13, 0x1400e3a0 }, - { 0x10002d14, 0x1400e3a0 }, - { 0x10002d15, 0x1400e3a0 }, - { 0x10002d16, 0x1400e3a0 }, - { 0x10002d17, 0x1400e3a0 }, - { 0x10002d18, 0x1400e3a0 }, - { 0x10002d19, 0x1400e3a0 }, - { 0x10002d1a, 0x1400e3a0 }, - { 0x10002d1b, 0x1400e3a0 }, - { 0x10002d1c, 0x1400e3a0 }, - { 0x10002d1d, 0x1400e3a0 }, - { 0x10002d1e, 0x1400e3a0 }, - { 0x10002d1f, 0x1400e3a0 }, - { 0x10002d20, 0x1400e3a0 }, - { 0x10002d21, 0x1400e3a0 }, - { 0x10002d22, 0x1400e3a0 }, - { 0x10002d23, 0x1400e3a0 }, - { 0x10002d24, 0x1400e3a0 }, - { 0x10002d25, 0x1400e3a0 }, - { 0x3a802d30, 0x1c000035 }, - { 0x3a002d6f, 0x18000000 }, - { 0x0f802d80, 0x1c000016 }, - { 0x0f802da0, 0x1c000006 }, - { 0x0f802da8, 0x1c000006 }, - { 0x0f802db0, 0x1c000006 }, - { 0x0f802db8, 0x1c000006 }, - { 0x0f802dc0, 0x1c000006 }, - { 0x0f802dc8, 0x1c000006 }, - { 0x0f802dd0, 0x1c000006 }, - { 0x0f802dd8, 0x1c000006 }, - { 0x09802e00, 0x54000001 }, - { 0x09002e02, 0x50000000 }, - { 0x09002e03, 0x4c000000 }, - { 0x09002e04, 0x50000000 }, - { 0x09002e05, 0x4c000000 }, - { 0x09802e06, 0x54000002 }, - { 0x09002e09, 0x50000000 }, - { 0x09002e0a, 0x4c000000 }, - { 0x09002e0b, 0x54000000 }, - { 0x09002e0c, 0x50000000 }, - { 0x09002e0d, 0x4c000000 }, - { 0x09802e0e, 0x54000008 }, - { 0x09002e17, 0x44000000 }, - { 0x09002e1c, 0x50000000 }, - { 0x09002e1d, 0x4c000000 }, - { 0x16802e80, 0x68000019 }, - { 0x16802e9b, 0x68000058 }, - { 0x16802f00, 0x680000d5 }, - { 0x09802ff0, 0x6800000b }, - { 0x09003000, 0x74000000 }, - { 0x09803001, 0x54000002 }, - { 0x09003004, 0x68000000 }, - { 0x16003005, 0x18000000 }, - { 0x09003006, 0x1c000000 }, - { 0x16003007, 0x38000000 }, - { 0x09003008, 0x58000000 }, - { 0x09003009, 0x48000000 }, - { 0x0900300a, 0x58000000 }, - { 0x0900300b, 0x48000000 }, - { 0x0900300c, 0x58000000 }, - { 0x0900300d, 0x48000000 }, - { 0x0900300e, 0x58000000 }, - { 0x0900300f, 0x48000000 }, - { 0x09003010, 0x58000000 }, - { 0x09003011, 0x48000000 }, - { 0x09803012, 0x68000001 }, - { 0x09003014, 0x58000000 }, - { 0x09003015, 0x48000000 }, - { 0x09003016, 0x58000000 }, - { 0x09003017, 0x48000000 }, - { 0x09003018, 0x58000000 }, - { 0x09003019, 0x48000000 }, - { 0x0900301a, 0x58000000 }, - { 0x0900301b, 0x48000000 }, - { 0x0900301c, 0x44000000 }, - { 0x0900301d, 0x58000000 }, - { 0x0980301e, 0x48000001 }, - { 0x09003020, 0x68000000 }, - { 0x16803021, 0x38000008 }, - { 0x1b80302a, 0x30000005 }, - { 0x09003030, 0x44000000 }, - { 0x09803031, 0x18000004 }, - { 0x09803036, 0x68000001 }, - { 0x16803038, 0x38000002 }, - { 0x1600303b, 0x18000000 }, - { 0x0900303c, 0x1c000000 }, - { 0x0900303d, 0x54000000 }, - { 0x0980303e, 0x68000001 }, - { 0x1a803041, 0x1c000055 }, - { 0x1b803099, 0x30000001 }, - { 0x0980309b, 0x60000001 }, - { 0x1a80309d, 0x18000001 }, - { 0x1a00309f, 0x1c000000 }, - { 0x090030a0, 0x44000000 }, - { 0x1d8030a1, 0x1c000059 }, - { 0x090030fb, 0x54000000 }, - { 0x098030fc, 0x18000002 }, - { 0x1d0030ff, 0x1c000000 }, - { 0x03803105, 0x1c000027 }, - { 0x17803131, 0x1c00005d }, - { 0x09803190, 0x68000001 }, - { 0x09803192, 0x3c000003 }, - { 0x09803196, 0x68000009 }, - { 0x038031a0, 0x1c000017 }, - { 0x098031c0, 0x6800000f }, - { 0x1d8031f0, 0x1c00000f }, - { 0x17803200, 0x6800001e }, - { 0x09803220, 0x3c000009 }, - { 0x0980322a, 0x68000019 }, - { 0x09003250, 0x68000000 }, - { 0x09803251, 0x3c00000e }, - { 0x17803260, 0x6800001f }, - { 0x09803280, 0x3c000009 }, - { 0x0980328a, 0x68000026 }, - { 0x098032b1, 0x3c00000e }, - { 0x098032c0, 0x6800003e }, - { 0x09803300, 0x680000ff }, - { 0x16803400, 0x1c0019b5 }, - { 0x09804dc0, 0x6800003f }, - { 0x16804e00, 0x1c0051bb }, - { 0x3c80a000, 0x1c000014 }, - { 0x3c00a015, 0x18000000 }, - { 0x3c80a016, 0x1c000476 }, - { 0x3c80a490, 0x68000036 }, - { 0x0980a700, 0x60000016 }, - { 0x3080a800, 0x1c000001 }, - { 0x3000a802, 0x28000000 }, - { 0x3080a803, 0x1c000002 }, - { 0x3000a806, 0x30000000 }, - { 0x3080a807, 0x1c000003 }, - { 0x3000a80b, 0x30000000 }, - { 0x3080a80c, 0x1c000016 }, - { 0x3080a823, 0x28000001 }, - { 0x3080a825, 0x30000001 }, - { 0x3000a827, 0x28000000 }, - { 0x3080a828, 0x68000003 }, - { 0x1780ac00, 0x1c002ba3 }, - { 0x0980d800, 0x1000037f }, - { 0x0980db80, 0x1000007f }, - { 0x0980dc00, 0x100003ff }, - { 0x0980e000, 0x0c0018ff }, - { 0x1680f900, 0x1c00012d }, - { 0x1680fa30, 0x1c00003a }, - { 0x1680fa70, 0x1c000069 }, - { 0x2180fb00, 0x14000006 }, - { 0x0180fb13, 0x14000004 }, - { 0x1900fb1d, 0x1c000000 }, - { 0x1900fb1e, 0x30000000 }, - { 0x1980fb1f, 0x1c000009 }, - { 0x1900fb29, 0x64000000 }, - { 0x1980fb2a, 0x1c00000c }, - { 0x1980fb38, 0x1c000004 }, - { 0x1900fb3e, 0x1c000000 }, - { 0x1980fb40, 0x1c000001 }, - { 0x1980fb43, 0x1c000001 }, - { 0x1980fb46, 0x1c00006b }, - { 0x0080fbd3, 0x1c00016a }, - { 0x0900fd3e, 0x58000000 }, - { 0x0900fd3f, 0x48000000 }, - { 0x0080fd50, 0x1c00003f }, - { 0x0080fd92, 0x1c000035 }, - { 0x0080fdf0, 0x1c00000b }, - { 0x0000fdfc, 0x5c000000 }, - { 0x0900fdfd, 0x68000000 }, - { 0x1b80fe00, 0x3000000f }, - { 0x0980fe10, 0x54000006 }, - { 0x0900fe17, 0x58000000 }, - { 0x0900fe18, 0x48000000 }, - { 0x0900fe19, 0x54000000 }, - { 0x1b80fe20, 0x30000003 }, - { 0x0900fe30, 0x54000000 }, - { 0x0980fe31, 0x44000001 }, - { 0x0980fe33, 0x40000001 }, - { 0x0900fe35, 0x58000000 }, - { 0x0900fe36, 0x48000000 }, - { 0x0900fe37, 0x58000000 }, - { 0x0900fe38, 0x48000000 }, - { 0x0900fe39, 0x58000000 }, - { 0x0900fe3a, 0x48000000 }, - { 0x0900fe3b, 0x58000000 }, - { 0x0900fe3c, 0x48000000 }, - { 0x0900fe3d, 0x58000000 }, - { 0x0900fe3e, 0x48000000 }, - { 0x0900fe3f, 0x58000000 }, - { 0x0900fe40, 0x48000000 }, - { 0x0900fe41, 0x58000000 }, - { 0x0900fe42, 0x48000000 }, - { 0x0900fe43, 0x58000000 }, - { 0x0900fe44, 0x48000000 }, - { 0x0980fe45, 0x54000001 }, - { 0x0900fe47, 0x58000000 }, - { 0x0900fe48, 0x48000000 }, - { 0x0980fe49, 0x54000003 }, - { 0x0980fe4d, 0x40000002 }, - { 0x0980fe50, 0x54000002 }, - { 0x0980fe54, 0x54000003 }, - { 0x0900fe58, 0x44000000 }, - { 0x0900fe59, 0x58000000 }, - { 0x0900fe5a, 0x48000000 }, - { 0x0900fe5b, 0x58000000 }, - { 0x0900fe5c, 0x48000000 }, - { 0x0900fe5d, 0x58000000 }, - { 0x0900fe5e, 0x48000000 }, - { 0x0980fe5f, 0x54000002 }, - { 0x0900fe62, 0x64000000 }, - { 0x0900fe63, 0x44000000 }, - { 0x0980fe64, 0x64000002 }, - { 0x0900fe68, 0x54000000 }, - { 0x0900fe69, 0x5c000000 }, - { 0x0980fe6a, 0x54000001 }, - { 0x0080fe70, 0x1c000004 }, - { 0x0080fe76, 0x1c000086 }, - { 0x0900feff, 0x04000000 }, - { 0x0980ff01, 0x54000002 }, - { 0x0900ff04, 0x5c000000 }, - { 0x0980ff05, 0x54000002 }, - { 0x0900ff08, 0x58000000 }, - { 0x0900ff09, 0x48000000 }, - { 0x0900ff0a, 0x54000000 }, - { 0x0900ff0b, 0x64000000 }, - { 0x0900ff0c, 0x54000000 }, - { 0x0900ff0d, 0x44000000 }, - { 0x0980ff0e, 0x54000001 }, - { 0x0980ff10, 0x34000009 }, - { 0x0980ff1a, 0x54000001 }, - { 0x0980ff1c, 0x64000002 }, - { 0x0980ff1f, 0x54000001 }, - { 0x2100ff21, 0x24000020 }, - { 0x2100ff22, 0x24000020 }, - { 0x2100ff23, 0x24000020 }, - { 0x2100ff24, 0x24000020 }, - { 0x2100ff25, 0x24000020 }, - { 0x2100ff26, 0x24000020 }, - { 0x2100ff27, 0x24000020 }, - { 0x2100ff28, 0x24000020 }, - { 0x2100ff29, 0x24000020 }, - { 0x2100ff2a, 0x24000020 }, - { 0x2100ff2b, 0x24000020 }, - { 0x2100ff2c, 0x24000020 }, - { 0x2100ff2d, 0x24000020 }, - { 0x2100ff2e, 0x24000020 }, - { 0x2100ff2f, 0x24000020 }, - { 0x2100ff30, 0x24000020 }, - { 0x2100ff31, 0x24000020 }, - { 0x2100ff32, 0x24000020 }, - { 0x2100ff33, 0x24000020 }, - { 0x2100ff34, 0x24000020 }, - { 0x2100ff35, 0x24000020 }, - { 0x2100ff36, 0x24000020 }, - { 0x2100ff37, 0x24000020 }, - { 0x2100ff38, 0x24000020 }, - { 0x2100ff39, 0x24000020 }, - { 0x2100ff3a, 0x24000020 }, - { 0x0900ff3b, 0x58000000 }, - { 0x0900ff3c, 0x54000000 }, - { 0x0900ff3d, 0x48000000 }, - { 0x0900ff3e, 0x60000000 }, - { 0x0900ff3f, 0x40000000 }, - { 0x0900ff40, 0x60000000 }, - { 0x2100ff41, 0x1400ffe0 }, - { 0x2100ff42, 0x1400ffe0 }, - { 0x2100ff43, 0x1400ffe0 }, - { 0x2100ff44, 0x1400ffe0 }, - { 0x2100ff45, 0x1400ffe0 }, - { 0x2100ff46, 0x1400ffe0 }, - { 0x2100ff47, 0x1400ffe0 }, - { 0x2100ff48, 0x1400ffe0 }, - { 0x2100ff49, 0x1400ffe0 }, - { 0x2100ff4a, 0x1400ffe0 }, - { 0x2100ff4b, 0x1400ffe0 }, - { 0x2100ff4c, 0x1400ffe0 }, - { 0x2100ff4d, 0x1400ffe0 }, - { 0x2100ff4e, 0x1400ffe0 }, - { 0x2100ff4f, 0x1400ffe0 }, - { 0x2100ff50, 0x1400ffe0 }, - { 0x2100ff51, 0x1400ffe0 }, - { 0x2100ff52, 0x1400ffe0 }, - { 0x2100ff53, 0x1400ffe0 }, - { 0x2100ff54, 0x1400ffe0 }, - { 0x2100ff55, 0x1400ffe0 }, - { 0x2100ff56, 0x1400ffe0 }, - { 0x2100ff57, 0x1400ffe0 }, - { 0x2100ff58, 0x1400ffe0 }, - { 0x2100ff59, 0x1400ffe0 }, - { 0x2100ff5a, 0x1400ffe0 }, - { 0x0900ff5b, 0x58000000 }, - { 0x0900ff5c, 0x64000000 }, - { 0x0900ff5d, 0x48000000 }, - { 0x0900ff5e, 0x64000000 }, - { 0x0900ff5f, 0x58000000 }, - { 0x0900ff60, 0x48000000 }, - { 0x0900ff61, 0x54000000 }, - { 0x0900ff62, 0x58000000 }, - { 0x0900ff63, 0x48000000 }, - { 0x0980ff64, 0x54000001 }, - { 0x1d80ff66, 0x1c000009 }, - { 0x0900ff70, 0x18000000 }, - { 0x1d80ff71, 0x1c00002c }, - { 0x0980ff9e, 0x18000001 }, - { 0x1780ffa0, 0x1c00001e }, - { 0x1780ffc2, 0x1c000005 }, - { 0x1780ffca, 0x1c000005 }, - { 0x1780ffd2, 0x1c000005 }, - { 0x1780ffda, 0x1c000002 }, - { 0x0980ffe0, 0x5c000001 }, - { 0x0900ffe2, 0x64000000 }, - { 0x0900ffe3, 0x60000000 }, - { 0x0900ffe4, 0x68000000 }, - { 0x0980ffe5, 0x5c000001 }, - { 0x0900ffe8, 0x68000000 }, - { 0x0980ffe9, 0x64000003 }, - { 0x0980ffed, 0x68000001 }, - { 0x0980fff9, 0x04000002 }, - { 0x0980fffc, 0x68000001 }, - { 0x23810000, 0x1c00000b }, - { 0x2381000d, 0x1c000019 }, - { 0x23810028, 0x1c000012 }, - { 0x2381003c, 0x1c000001 }, - { 0x2381003f, 0x1c00000e }, - { 0x23810050, 0x1c00000d }, - { 0x23810080, 0x1c00007a }, - { 0x09810100, 0x54000001 }, - { 0x09010102, 0x68000000 }, - { 0x09810107, 0x3c00002c }, - { 0x09810137, 0x68000008 }, - { 0x13810140, 0x38000034 }, - { 0x13810175, 0x3c000003 }, - { 0x13810179, 0x68000010 }, - { 0x1301018a, 0x3c000000 }, - { 0x29810300, 0x1c00001e }, - { 0x29810320, 0x3c000003 }, - { 0x12810330, 0x1c000019 }, - { 0x1201034a, 0x38000000 }, - { 0x3b810380, 0x1c00001d }, - { 0x3b01039f, 0x54000000 }, - { 0x2a8103a0, 0x1c000023 }, - { 0x2a8103c8, 0x1c000007 }, - { 0x2a0103d0, 0x68000000 }, - { 0x2a8103d1, 0x38000004 }, - { 0x0d010400, 0x24000028 }, - { 0x0d010401, 0x24000028 }, - { 0x0d010402, 0x24000028 }, - { 0x0d010403, 0x24000028 }, - { 0x0d010404, 0x24000028 }, - { 0x0d010405, 0x24000028 }, - { 0x0d010406, 0x24000028 }, - { 0x0d010407, 0x24000028 }, - { 0x0d010408, 0x24000028 }, - { 0x0d010409, 0x24000028 }, - { 0x0d01040a, 0x24000028 }, - { 0x0d01040b, 0x24000028 }, - { 0x0d01040c, 0x24000028 }, - { 0x0d01040d, 0x24000028 }, - { 0x0d01040e, 0x24000028 }, - { 0x0d01040f, 0x24000028 }, - { 0x0d010410, 0x24000028 }, - { 0x0d010411, 0x24000028 }, - { 0x0d010412, 0x24000028 }, - { 0x0d010413, 0x24000028 }, - { 0x0d010414, 0x24000028 }, - { 0x0d010415, 0x24000028 }, - { 0x0d010416, 0x24000028 }, - { 0x0d010417, 0x24000028 }, - { 0x0d010418, 0x24000028 }, - { 0x0d010419, 0x24000028 }, - { 0x0d01041a, 0x24000028 }, - { 0x0d01041b, 0x24000028 }, - { 0x0d01041c, 0x24000028 }, - { 0x0d01041d, 0x24000028 }, - { 0x0d01041e, 0x24000028 }, - { 0x0d01041f, 0x24000028 }, - { 0x0d010420, 0x24000028 }, - { 0x0d010421, 0x24000028 }, - { 0x0d010422, 0x24000028 }, - { 0x0d010423, 0x24000028 }, - { 0x0d010424, 0x24000028 }, - { 0x0d010425, 0x24000028 }, - { 0x0d010426, 0x24000028 }, - { 0x0d010427, 0x24000028 }, - { 0x0d010428, 0x1400ffd8 }, - { 0x0d010429, 0x1400ffd8 }, - { 0x0d01042a, 0x1400ffd8 }, - { 0x0d01042b, 0x1400ffd8 }, - { 0x0d01042c, 0x1400ffd8 }, - { 0x0d01042d, 0x1400ffd8 }, - { 0x0d01042e, 0x1400ffd8 }, - { 0x0d01042f, 0x1400ffd8 }, - { 0x0d010430, 0x1400ffd8 }, - { 0x0d010431, 0x1400ffd8 }, - { 0x0d010432, 0x1400ffd8 }, - { 0x0d010433, 0x1400ffd8 }, - { 0x0d010434, 0x1400ffd8 }, - { 0x0d010435, 0x1400ffd8 }, - { 0x0d010436, 0x1400ffd8 }, - { 0x0d010437, 0x1400ffd8 }, - { 0x0d010438, 0x1400ffd8 }, - { 0x0d010439, 0x1400ffd8 }, - { 0x0d01043a, 0x1400ffd8 }, - { 0x0d01043b, 0x1400ffd8 }, - { 0x0d01043c, 0x1400ffd8 }, - { 0x0d01043d, 0x1400ffd8 }, - { 0x0d01043e, 0x1400ffd8 }, - { 0x0d01043f, 0x1400ffd8 }, - { 0x0d010440, 0x1400ffd8 }, - { 0x0d010441, 0x1400ffd8 }, - { 0x0d010442, 0x1400ffd8 }, - { 0x0d010443, 0x1400ffd8 }, - { 0x0d010444, 0x1400ffd8 }, - { 0x0d010445, 0x1400ffd8 }, - { 0x0d010446, 0x1400ffd8 }, - { 0x0d010447, 0x1400ffd8 }, - { 0x0d010448, 0x1400ffd8 }, - { 0x0d010449, 0x1400ffd8 }, - { 0x0d01044a, 0x1400ffd8 }, - { 0x0d01044b, 0x1400ffd8 }, - { 0x0d01044c, 0x1400ffd8 }, - { 0x0d01044d, 0x1400ffd8 }, - { 0x0d01044e, 0x1400ffd8 }, - { 0x0d01044f, 0x1400ffd8 }, - { 0x2e810450, 0x1c00004d }, - { 0x2c8104a0, 0x34000009 }, - { 0x0b810800, 0x1c000005 }, - { 0x0b010808, 0x1c000000 }, - { 0x0b81080a, 0x1c00002b }, - { 0x0b810837, 0x1c000001 }, - { 0x0b01083c, 0x1c000000 }, - { 0x0b01083f, 0x1c000000 }, - { 0x1e010a00, 0x1c000000 }, - { 0x1e810a01, 0x30000002 }, - { 0x1e810a05, 0x30000001 }, - { 0x1e810a0c, 0x30000003 }, - { 0x1e810a10, 0x1c000003 }, - { 0x1e810a15, 0x1c000002 }, - { 0x1e810a19, 0x1c00001a }, - { 0x1e810a38, 0x30000002 }, - { 0x1e010a3f, 0x30000000 }, - { 0x1e810a40, 0x3c000007 }, - { 0x1e810a50, 0x54000008 }, - { 0x0981d000, 0x680000f5 }, - { 0x0981d100, 0x68000026 }, - { 0x0981d12a, 0x6800003a }, - { 0x0981d165, 0x28000001 }, - { 0x1b81d167, 0x30000002 }, - { 0x0981d16a, 0x68000002 }, - { 0x0981d16d, 0x28000005 }, - { 0x0981d173, 0x04000007 }, - { 0x1b81d17b, 0x30000007 }, - { 0x0981d183, 0x68000001 }, - { 0x1b81d185, 0x30000006 }, - { 0x0981d18c, 0x6800001d }, - { 0x1b81d1aa, 0x30000003 }, - { 0x0981d1ae, 0x6800002f }, - { 0x1381d200, 0x68000041 }, - { 0x1381d242, 0x30000002 }, - { 0x1301d245, 0x68000000 }, - { 0x0981d300, 0x68000056 }, - { 0x0981d400, 0x24000019 }, - { 0x0981d41a, 0x14000019 }, - { 0x0981d434, 0x24000019 }, - { 0x0981d44e, 0x14000006 }, - { 0x0981d456, 0x14000011 }, - { 0x0981d468, 0x24000019 }, - { 0x0981d482, 0x14000019 }, - { 0x0901d49c, 0x24000000 }, - { 0x0981d49e, 0x24000001 }, - { 0x0901d4a2, 0x24000000 }, - { 0x0981d4a5, 0x24000001 }, - { 0x0981d4a9, 0x24000003 }, - { 0x0981d4ae, 0x24000007 }, - { 0x0981d4b6, 0x14000003 }, - { 0x0901d4bb, 0x14000000 }, - { 0x0981d4bd, 0x14000006 }, - { 0x0981d4c5, 0x1400000a }, - { 0x0981d4d0, 0x24000019 }, - { 0x0981d4ea, 0x14000019 }, - { 0x0981d504, 0x24000001 }, - { 0x0981d507, 0x24000003 }, - { 0x0981d50d, 0x24000007 }, - { 0x0981d516, 0x24000006 }, - { 0x0981d51e, 0x14000019 }, - { 0x0981d538, 0x24000001 }, - { 0x0981d53b, 0x24000003 }, - { 0x0981d540, 0x24000004 }, - { 0x0901d546, 0x24000000 }, - { 0x0981d54a, 0x24000006 }, - { 0x0981d552, 0x14000019 }, - { 0x0981d56c, 0x24000019 }, - { 0x0981d586, 0x14000019 }, - { 0x0981d5a0, 0x24000019 }, - { 0x0981d5ba, 0x14000019 }, - { 0x0981d5d4, 0x24000019 }, - { 0x0981d5ee, 0x14000019 }, - { 0x0981d608, 0x24000019 }, - { 0x0981d622, 0x14000019 }, - { 0x0981d63c, 0x24000019 }, - { 0x0981d656, 0x14000019 }, - { 0x0981d670, 0x24000019 }, - { 0x0981d68a, 0x1400001b }, - { 0x0981d6a8, 0x24000018 }, - { 0x0901d6c1, 0x64000000 }, - { 0x0981d6c2, 0x14000018 }, - { 0x0901d6db, 0x64000000 }, - { 0x0981d6dc, 0x14000005 }, - { 0x0981d6e2, 0x24000018 }, - { 0x0901d6fb, 0x64000000 }, - { 0x0981d6fc, 0x14000018 }, - { 0x0901d715, 0x64000000 }, - { 0x0981d716, 0x14000005 }, - { 0x0981d71c, 0x24000018 }, - { 0x0901d735, 0x64000000 }, - { 0x0981d736, 0x14000018 }, - { 0x0901d74f, 0x64000000 }, - { 0x0981d750, 0x14000005 }, - { 0x0981d756, 0x24000018 }, - { 0x0901d76f, 0x64000000 }, - { 0x0981d770, 0x14000018 }, - { 0x0901d789, 0x64000000 }, - { 0x0981d78a, 0x14000005 }, - { 0x0981d790, 0x24000018 }, - { 0x0901d7a9, 0x64000000 }, - { 0x0981d7aa, 0x14000018 }, - { 0x0901d7c3, 0x64000000 }, - { 0x0981d7c4, 0x14000005 }, - { 0x0981d7ce, 0x34000031 }, - { 0x16820000, 0x1c00a6d6 }, - { 0x1682f800, 0x1c00021d }, - { 0x090e0001, 0x04000000 }, - { 0x098e0020, 0x0400005f }, - { 0x1b8e0100, 0x300000ef }, - { 0x098f0000, 0x0c00fffd }, - { 0x09900000, 0x0c00fffd }, -}; diff --git a/js/src/yarr/wtfbridge.h b/js/src/yarr/wtfbridge.h new file mode 100644 index 000000000000..25a4bc5ee3d9 --- /dev/null +++ b/js/src/yarr/wtfbridge.h @@ -0,0 +1,321 @@ +/* -*- 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 ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 12, 2009. + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jswtfbridge_h__ +#define jswtfbridge_h__ + +/* + * WTF compatibility layer. This file provides various type and data + * definitions for use by Yarr. + */ + +#include "jsstr.h" +#include "jsprvtd.h" +#include "jstl.h" +#include "assembler/wtf/Platform.h" +#include "assembler/jit/ExecutableAllocator.h" + +namespace JSC { namespace Yarr { + +/* + * Basic type definitions. + */ + +typedef jschar UChar; +typedef JSLinearString UString; + +class Unicode { + public: + static UChar toUpper(UChar c) { return JS_TOUPPER(c); } + static UChar toLower(UChar c) { return JS_TOLOWER(c); } +}; + +/* + * Do-nothing smart pointer classes. These have a compatible interface + * with the smart pointers used by Yarr, but they don't actually do + * reference counting. + */ +template +class RefCounted { +}; + +template +class RefPtr { + T *ptr; + public: + RefPtr(T *p) { ptr = p; } + operator bool() const { return ptr != NULL; } + const T *operator ->() const { return ptr; } + T *get() { return ptr; } +}; + +template +class PassRefPtr { + T *ptr; + public: + PassRefPtr(T *p) { ptr = p; } + operator T*() { return ptr; } +}; + +template +class PassOwnPtr { + T *ptr; + public: + PassOwnPtr(T *p) { ptr = p; } + + T *get() { return ptr; } +}; + +template +class OwnPtr { + T *ptr; + public: + OwnPtr() : ptr(NULL) { } + OwnPtr(PassOwnPtr p) : ptr(p.get()) { } + + ~OwnPtr() { + if (ptr) + js::Foreground::delete_(ptr); + } + + OwnPtr &operator=(PassOwnPtr p) { + ptr = p.get(); + return *this; + } + + T *operator ->() { return ptr; } + + T *get() { return ptr; } + + T *release() { + T *result = ptr; + ptr = NULL; + return result; + } +}; + +template +PassRefPtr adoptRef(T *p) { return PassRefPtr(p); } + +template +PassOwnPtr adoptPtr(T *p) { return PassOwnPtr(p); } + +#define WTF_MAKE_FAST_ALLOCATED + +/* + * Vector class for Yarr. This wraps js::Vector and provides all + * the API method signatures used by Yarr. + */ +template +class Vector { + public: + js::Vector impl; + public: + Vector() {} + + Vector(const Vector &v) { + // XXX yarr-oom + (void) append(v); + } + + size_t size() const { + return impl.length(); + } + + T &operator[](size_t i) { + return impl[i]; + } + + const T &operator[](size_t i) const { + return impl[i]; + } + + T &at(size_t i) { + return impl[i]; + } + + const T *begin() const { + return impl.begin(); + } + + T &last() { + return impl.back(); + } + + bool isEmpty() const { + return impl.empty(); + } + + template + void append(const U &u) { + // XXX yarr-oom + (void) impl.append(static_cast(u)); + } + + template + void append(const Vector &v) { + // XXX yarr-oom + (void) impl.append(v.impl); + } + + void insert(size_t i, const T& t) { + // XXX yarr-oom + (void) impl.insert(&impl[i], t); + } + + void remove(size_t i) { + impl.erase(&impl[i]); + } + + void clear() { + return impl.clear(); + } + + void shrink(size_t newLength) { + // XXX yarr-oom + JS_ASSERT(newLength <= impl.length()); + (void) impl.resize(newLength); + } + + void deleteAllValues() { + for (T *p = impl.begin(); p != impl.end(); ++p) + js::Foreground::delete_(*p); + } +}; + +template +class Vector > { + public: + js::Vector impl; + public: + Vector() {} + + size_t size() const { + return impl.length(); + } + + void append(T *t) { + // XXX yarr-oom + (void) impl.append(t); + } + + PassOwnPtr operator[](size_t i) { + return PassOwnPtr(impl[i]); + } + + void clear() { + for (T **p = impl.begin(); p != impl.end(); ++p) + js::Foreground::delete_(*p); + return impl.clear(); + } +}; + +template +inline void +deleteAllValues(Vector &v) { + v.deleteAllValues(); +} + +/* + * Minimal JSGlobalData. This used by Yarr to get the allocator. + */ +class JSGlobalData { + public: + ExecutableAllocator *regexAllocator; + + JSGlobalData(ExecutableAllocator *regexAllocator) + : regexAllocator(regexAllocator) { } +}; + +/* + * Sentinel value used in Yarr. + */ +const size_t notFound = size_t(-1); + + /* + * Do-nothing version of a macro used by WTF to avoid unused + * parameter warnings. + */ +#define UNUSED_PARAM(e) + +} /* namespace Yarr */ + +/* + * Replacements for std:: functions used in Yarr. We put them in + * namespace JSC::std so that they can still be called as std::X + * in Yarr. + */ +namespace std { + +/* + * windows.h defines a 'min' macro that would mangle the function + * name. + */ +#if WTF_COMPILER_MSVC +# undef min +# undef max +#endif + +template +inline T +min(T t1, T t2) +{ + return JS_MIN(t1, t2); +} + +template +inline T +max(T t1, T t2) +{ + return JS_MAX(t1, t2); +} + +template +inline void +swap(T &t1, T &t2) +{ + T tmp = t1; + t1 = t2; + t2 = tmp; +} +} /* namespace std */ + +} /* namespace JSC */ + +#endif diff --git a/js/src/yarr/yarr/RegexJIT.cpp b/js/src/yarr/yarr/RegexJIT.cpp deleted file mode 100644 index 1571c35b7125..000000000000 --- a/js/src/yarr/yarr/RegexJIT.cpp +++ /dev/null @@ -1,1589 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#include "RegexJIT.h" - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/LinkBuffer.h" -#include "assembler/assembler/MacroAssembler.h" -#include "RegexCompiler.h" - -#include "yarr/pcre/pcre.h" // temporary, remove when fallback is removed. - -using namespace WTF; - -namespace JSC { namespace Yarr { - -class JSGlobalData; - -class RegexGenerator : private MacroAssembler { - friend void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); - -#if WTF_CPU_ARM - static const RegisterID input = ARMRegisters::r0; - static const RegisterID index = ARMRegisters::r1; - static const RegisterID length = ARMRegisters::r2; - static const RegisterID output = ARMRegisters::r4; - - static const RegisterID regT0 = ARMRegisters::r5; - static const RegisterID regT1 = ARMRegisters::r6; - - static const RegisterID returnRegister = ARMRegisters::r0; -#elif WTF_CPU_MIPS - static const RegisterID input = MIPSRegisters::a0; - static const RegisterID index = MIPSRegisters::a1; - static const RegisterID length = MIPSRegisters::a2; - static const RegisterID output = MIPSRegisters::a3; - - static const RegisterID regT0 = MIPSRegisters::t4; - static const RegisterID regT1 = MIPSRegisters::t5; - - static const RegisterID returnRegister = MIPSRegisters::v0; -#elif WTF_CPU_SPARC - static const RegisterID input = SparcRegisters::i0; - static const RegisterID index = SparcRegisters::i1; - static const RegisterID length = SparcRegisters::i2; - static const RegisterID output = SparcRegisters::i3; - - static const RegisterID regT0 = SparcRegisters::i4; - static const RegisterID regT1 = SparcRegisters::i5; - - static const RegisterID returnRegister = SparcRegisters::i0; -#elif WTF_CPU_X86 - static const RegisterID input = X86Registers::eax; - static const RegisterID index = X86Registers::edx; - static const RegisterID length = X86Registers::ecx; - static const RegisterID output = X86Registers::edi; - - static const RegisterID regT0 = X86Registers::ebx; - static const RegisterID regT1 = X86Registers::esi; - - static const RegisterID returnRegister = X86Registers::eax; -#elif WTF_CPU_X86_64 -#if WTF_PLATFORM_WIN - static const RegisterID input = X86Registers::ecx; - static const RegisterID index = X86Registers::edx; - static const RegisterID length = X86Registers::r8; - static const RegisterID output = X86Registers::r9; -#else - static const RegisterID input = X86Registers::edi; - static const RegisterID index = X86Registers::esi; - static const RegisterID length = X86Registers::edx; - static const RegisterID output = X86Registers::ecx; -#endif - - static const RegisterID regT0 = X86Registers::eax; - static const RegisterID regT1 = X86Registers::ebx; - - static const RegisterID returnRegister = X86Registers::eax; -#endif - - void optimizeAlternative(PatternAlternative* alternative) - { - if (!alternative->m_terms.length()) - return; - - for (unsigned i = 0; i < alternative->m_terms.length() - 1; ++i) { - PatternTerm& term = alternative->m_terms[i]; - PatternTerm& nextTerm = alternative->m_terms[i + 1]; - - if ((term.type == PatternTerm::TypeCharacterClass) - && (term.quantityType == QuantifierFixedCount) - && (nextTerm.type == PatternTerm::TypePatternCharacter) - && (nextTerm.quantityType == QuantifierFixedCount)) { - PatternTerm termCopy = term; - alternative->m_terms[i] = nextTerm; - alternative->m_terms[i + 1] = termCopy; - } - } - } - - void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) - { - do { - // pick which range we're going to generate - int which = count >> 1; - char lo = ranges[which].begin; - char hi = ranges[which].end; - - // check if there are any ranges or matches below lo. If not, just jl to failure - - // if there is anything else to check, check that first, if it falls through jmp to failure. - if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { - Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); - - // generate code for all ranges before this one - if (which) - matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); - - while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { - matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex]))); - ++*matchIndex; - } - failures.append(jump()); - - loOrAbove.link(this); - } else if (which) { - Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); - - matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); - failures.append(jump()); - - loOrAbove.link(this); - } else - failures.append(branch32(LessThan, character, Imm32((unsigned short)lo))); - - while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) - ++*matchIndex; - - matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi))); - // fall through to here, the value is above hi. - - // shuffle along & loop around if there are any more matches to handle. - unsigned next = which + 1; - ranges += next; - count -= next; - } while (count); - } - - void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass) - { - if (charClass->m_table) { - ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table)); - matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry)); - return; - } - Jump unicodeFail; - if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) { - Jump isAscii = branch32(LessThanOrEqual, character, Imm32(0x7f)); - - if (charClass->m_matchesUnicode.length()) { - for (unsigned i = 0; i < charClass->m_matchesUnicode.length(); ++i) { - UChar ch = charClass->m_matchesUnicode[i]; - matchDest.append(branch32(Equal, character, Imm32(ch))); - } - } - - if (charClass->m_rangesUnicode.length()) { - for (unsigned i = 0; i < charClass->m_rangesUnicode.length(); ++i) { - UChar lo = charClass->m_rangesUnicode[i].begin; - UChar hi = charClass->m_rangesUnicode[i].end; - - Jump below = branch32(LessThan, character, Imm32(lo)); - matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi))); - below.link(this); - } - } - - unicodeFail = jump(); - isAscii.link(this); - } - - if (charClass->m_ranges.length()) { - unsigned matchIndex = 0; - JumpList failures; - matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.length(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.length()); - while (matchIndex < charClass->m_matches.length()) - matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++]))); - - failures.link(this); - } else if (charClass->m_matches.length()) { - // optimization: gather 'a','A' etc back together, can mask & test once. - js::Vector matchesAZaz; - - for (unsigned i = 0; i < charClass->m_matches.length(); ++i) { - char ch = charClass->m_matches[i]; - if (m_pattern.m_ignoreCase) { - if (isASCIILower(ch)) { - matchesAZaz.append(ch); - continue; - } - if (isASCIIUpper(ch)) - continue; - } - matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch))); - } - - if (unsigned countAZaz = matchesAZaz.length()) { - or32(Imm32(32), character); - for (unsigned i = 0; i < countAZaz; ++i) - matchDest.append(branch32(Equal, character, Imm32(matchesAZaz[i]))); - } - } - - if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) - unicodeFail.link(this); - } - - // Jumps if input not available; will have (incorrectly) incremented already! - Jump jumpIfNoAvailableInput(unsigned countToCheck) - { - add32(Imm32(countToCheck), index); - return branch32(Above, index, length); - } - - Jump jumpIfAvailableInput(unsigned countToCheck) - { - add32(Imm32(countToCheck), index); - return branch32(BelowOrEqual, index, length); - } - - Jump checkInput() - { - return branch32(BelowOrEqual, index, length); - } - - Jump atEndOfInput() - { - return branch32(Equal, index, length); - } - - Jump notAtEndOfInput() - { - return branch32(NotEqual, index, length); - } - - Jump jumpIfCharEquals(UChar ch, int inputPosition) - { - return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); - } - - Jump jumpIfCharNotEquals(UChar ch, int inputPosition) - { - return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); - } - - void readCharacter(int inputPosition, RegisterID reg) - { - load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg); - } - - void storeToFrame(RegisterID reg, unsigned frameLocation) - { - poke(reg, frameLocation); - } - - void storeToFrame(Imm32 imm, unsigned frameLocation) - { - poke(imm, frameLocation); - } - - DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) - { - return storePtrWithPatch(ImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*))); - } - - void loadFromFrame(unsigned frameLocation, RegisterID reg) - { - peek(reg, frameLocation); - } - - void loadFromFrameAndJump(unsigned frameLocation) - { - jump(Address(stackPointerRegister, frameLocation * sizeof(void*))); - } - - struct AlternativeBacktrackRecord { - DataLabelPtr dataLabel; - Label backtrackLocation; - - AlternativeBacktrackRecord(DataLabelPtr dataLabel, Label backtrackLocation) - : dataLabel(dataLabel) - , backtrackLocation(backtrackLocation) - { - } - }; - - struct TermGenerationState { - TermGenerationState(PatternDisjunction* disjunction, unsigned checkedTotal) - : disjunction(disjunction) - , checkedTotal(checkedTotal) - { - } - - void resetAlternative() - { - isBackTrackGenerated = false; - alt = 0; - } - bool alternativeValid() - { - return alt < disjunction->m_alternatives.length(); - } - void nextAlternative() - { - ++alt; - } - PatternAlternative* alternative() - { - return disjunction->m_alternatives[alt]; - } - - void resetTerm() - { - ASSERT(alternativeValid()); - t = 0; - } - bool termValid() - { - ASSERT(alternativeValid()); - return t < alternative()->m_terms.length(); - } - void nextTerm() - { - ASSERT(alternativeValid()); - ++t; - } - PatternTerm& term() - { - ASSERT(alternativeValid()); - return alternative()->m_terms[t]; - } - bool isLastTerm() - { - ASSERT(alternativeValid()); - return (t + 1) == alternative()->m_terms.length(); - } - bool isMainDisjunction() - { - return !disjunction->m_parent; - } - - PatternTerm& lookaheadTerm() - { - ASSERT(alternativeValid()); - ASSERT((t + 1) < alternative()->m_terms.length()); - return alternative()->m_terms[t + 1]; - } - bool isSinglePatternCharacterLookaheadTerm() - { - ASSERT(alternativeValid()); - return ((t + 1) < alternative()->m_terms.length()) - && (lookaheadTerm().type == PatternTerm::TypePatternCharacter) - && (lookaheadTerm().quantityType == QuantifierFixedCount) - && (lookaheadTerm().quantityCount == 1); - } - - int inputOffset() - { - return term().inputPosition - checkedTotal; - } - - void jumpToBacktrack(Jump jump, MacroAssembler* masm) - { - if (isBackTrackGenerated) - jump.linkTo(backtrackLabel, masm); - else - backTrackJumps.append(jump); - } - void jumpToBacktrack(JumpList& jumps, MacroAssembler* masm) - { - if (isBackTrackGenerated) - jumps.linkTo(backtrackLabel, masm); - else - backTrackJumps.append(jumps); - } - bool plantJumpToBacktrackIfExists(MacroAssembler* masm) - { - if (isBackTrackGenerated) { - masm->jump(backtrackLabel); - return true; - } - return false; - } - void addBacktrackJump(Jump jump) - { - backTrackJumps.append(jump); - } - void setBacktrackGenerated(Label label) - { - isBackTrackGenerated = true; - backtrackLabel = label; - } - void linkAlternativeBacktracks(MacroAssembler* masm) - { - isBackTrackGenerated = false; - backTrackJumps.link(masm); - } - void linkAlternativeBacktracksTo(Label label, MacroAssembler* masm) - { - isBackTrackGenerated = false; - backTrackJumps.linkTo(label, masm); - } - void propagateBacktrackingFrom(TermGenerationState& nestedParenthesesState, MacroAssembler* masm) - { - jumpToBacktrack(nestedParenthesesState.backTrackJumps, masm); - if (nestedParenthesesState.isBackTrackGenerated) - setBacktrackGenerated(nestedParenthesesState.backtrackLabel); - } - - PatternDisjunction* disjunction; - int checkedTotal; - private: - unsigned alt; - unsigned t; - JumpList backTrackJumps; - Label backtrackLabel; - bool isBackTrackGenerated; - }; - - void generateAssertionBOL(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - if (m_pattern.m_multiline) { - const RegisterID character = regT0; - - JumpList matchDest; - if (!term.inputPosition) - matchDest.append(branch32(Equal, index, Imm32(state.checkedTotal))); - - readCharacter(state.inputOffset() - 1, character); - matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); - state.jumpToBacktrack(jump(), this); - - matchDest.link(this); - } else { - // Erk, really should poison out these alternatives early. :-/ - if (term.inputPosition) - state.jumpToBacktrack(jump(), this); - else - state.jumpToBacktrack(branch32(NotEqual, index, Imm32(state.checkedTotal)), this); - } - } - - void generateAssertionEOL(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - if (m_pattern.m_multiline) { - const RegisterID character = regT0; - - JumpList matchDest; - if (term.inputPosition == state.checkedTotal) - matchDest.append(atEndOfInput()); - - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); - state.jumpToBacktrack(jump(), this); - - matchDest.link(this); - } else { - if (term.inputPosition == state.checkedTotal) - state.jumpToBacktrack(notAtEndOfInput(), this); - // Erk, really should poison out these alternatives early. :-/ - else - state.jumpToBacktrack(jump(), this); - } - } - - // Also falls though on nextIsNotWordChar. - void matchAssertionWordchar(TermGenerationState& state, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - if (term.inputPosition == state.checkedTotal) - nextIsNotWordChar.append(atEndOfInput()); - - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass()); - } - - void generateAssertionWordBoundary(TermGenerationState& state) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - Jump atBegin; - JumpList matchDest; - if (!term.inputPosition) - atBegin = branch32(Equal, index, Imm32(state.checkedTotal)); - readCharacter(state.inputOffset() - 1, character); - matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass()); - if (!term.inputPosition) - atBegin.link(this); - - // We fall through to here if the last character was not a wordchar. - JumpList nonWordCharThenWordChar; - JumpList nonWordCharThenNonWordChar; - if (term.invertOrCapture) { - matchAssertionWordchar(state, nonWordCharThenNonWordChar, nonWordCharThenWordChar); - nonWordCharThenWordChar.append(jump()); - } else { - matchAssertionWordchar(state, nonWordCharThenWordChar, nonWordCharThenNonWordChar); - nonWordCharThenNonWordChar.append(jump()); - } - state.jumpToBacktrack(nonWordCharThenNonWordChar, this); - - // We jump here if the last character was a wordchar. - matchDest.link(this); - JumpList wordCharThenWordChar; - JumpList wordCharThenNonWordChar; - if (term.invertOrCapture) { - matchAssertionWordchar(state, wordCharThenNonWordChar, wordCharThenWordChar); - wordCharThenWordChar.append(jump()); - } else { - matchAssertionWordchar(state, wordCharThenWordChar, wordCharThenNonWordChar); - // This can fall-though! - } - - state.jumpToBacktrack(wordCharThenWordChar, this); - - nonWordCharThenWordChar.link(this); - wordCharThenNonWordChar.link(this); - } - - void generatePatternCharacterSingle(TermGenerationState& state) - { - const RegisterID character = regT0; - UChar ch = state.term().patternCharacter; - - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - state.jumpToBacktrack(jumpIfCharNotEquals(ch, state.inputOffset()), this); - } - } - - void generatePatternCharacterPair(TermGenerationState& state) - { - const RegisterID character = regT0; -#if WTF_CPU_BIG_ENDIAN - UChar ch2 = state.term().patternCharacter; - UChar ch1 = state.lookaheadTerm().patternCharacter; -#else - UChar ch1 = state.term().patternCharacter; - UChar ch2 = state.lookaheadTerm().patternCharacter; -#endif - - int mask = 0; - int chPair = ch1 | (ch2 << 16); - - if (m_pattern.m_ignoreCase) { - if (isASCIIAlpha(ch1)) - mask |= 32; - if (isASCIIAlpha(ch2)) - mask |= 32 << 16; - } - - if (mask) { - load32WithUnalignedHalfWords(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character); - or32(Imm32(mask), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(chPair | mask)), this); - } else - state.jumpToBacktrack(branch32WithUnalignedHalfWords(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this); - } - - void generatePatternCharacterFixed(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(index, countRegister); - sub32(Imm32(term.quantityCount), countRegister); - - Label loop(this); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); - or32(Imm32(32), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - state.jumpToBacktrack(branch16(NotEqual, BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), Imm32(ch)), this); - } - add32(Imm32(1), countRegister); - branch32(NotEqual, countRegister, index).linkTo(loop, this); - } - - void generatePatternCharacterGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(Imm32(0), countRegister); - - JumpList failures; - Label loop(this); - failures.append(atEndOfInput()); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - failures.append(jumpIfCharNotEquals(ch, state.inputOffset())); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - if (term.quantityCount != 0xffffffff) { - branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); - failures.append(jump()); - } else - jump(loop); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - state.jumpToBacktrack(branchTest32(Zero, countRegister), this); - sub32(Imm32(1), countRegister); - sub32(Imm32(1), index); - - failures.link(this); - - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generatePatternCharacterNonGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(Imm32(0), countRegister); - - Jump firstTimeDoNothing = jump(); - - Label hardFail(this); - sub32(countRegister, index); - state.jumpToBacktrack(jump(), this); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - - atEndOfInput().linkTo(hardFail, this); - if (term.quantityCount != 0xffffffff) - branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - branch32(NotEqual, character, Imm32(Unicode::toLower(ch))).linkTo(hardFail, this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - jumpIfCharNotEquals(ch, state.inputOffset()).linkTo(hardFail, this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - - firstTimeDoNothing.link(this); - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateCharacterClassSingle(TermGenerationState& state) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - state.jumpToBacktrack(matchDest, this); - else { - state.jumpToBacktrack(jump(), this); - matchDest.link(this); - } - } - - void generateCharacterClassFixed(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(index, countRegister); - sub32(Imm32(term.quantityCount), countRegister); - - Label loop(this); - JumpList matchDest; - load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - state.jumpToBacktrack(matchDest, this); - else { - state.jumpToBacktrack(jump(), this); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - branch32(NotEqual, countRegister, index).linkTo(loop, this); - } - - void generateCharacterClassGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(Imm32(0), countRegister); - - JumpList failures; - Label loop(this); - failures.append(atEndOfInput()); - - if (term.invertOrCapture) { - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, failures, term.characterClass); - } else { - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - failures.append(jump()); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - if (term.quantityCount != 0xffffffff) { - branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); - failures.append(jump()); - } else - jump(loop); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - state.jumpToBacktrack(branchTest32(Zero, countRegister), this); - sub32(Imm32(1), countRegister); - sub32(Imm32(1), index); - - failures.link(this); - - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateCharacterClassNonGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(Imm32(0), countRegister); - - Jump firstTimeDoNothing = jump(); - - Label hardFail(this); - sub32(countRegister, index); - state.jumpToBacktrack(jump(), this); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - - atEndOfInput().linkTo(hardFail, this); - branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); - - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - matchDest.linkTo(hardFail, this); - else { - jump(hardFail); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - - firstTimeDoNothing.link(this); - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateParenthesesDisjunction(PatternTerm& parenthesesTerm, TermGenerationState& state, unsigned alternativeFrameLocation) - { - ASSERT((parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern) || (parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion)); - ASSERT(parenthesesTerm.quantityCount == 1); - - PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; - unsigned preCheckedCount = ((parenthesesTerm.quantityType == QuantifierFixedCount) && (parenthesesTerm.type != PatternTerm::TypeParentheticalAssertion)) ? disjunction->m_minimumSize : 0; - - if (disjunction->m_alternatives.length() == 1) { - state.resetAlternative(); - ASSERT(state.alternativeValid()); - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - int countToCheck = alternative->m_minimumSize - preCheckedCount; - if (countToCheck) { - ASSERT((parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion) || (parenthesesTerm.quantityType != QuantifierFixedCount)); - - // FIXME: This is quite horrible. The call to 'plantJumpToBacktrackIfExists' - // will be forced to always trampoline into here, just to decrement the index. - // Ick. - Jump skip = jump(); - - Label backtrackBegin(this); - sub32(Imm32(countToCheck), index); - state.addBacktrackJump(jump()); - - skip.link(this); - - state.setBacktrackGenerated(backtrackBegin); - - state.jumpToBacktrack(jumpIfNoAvailableInput(countToCheck), this); - state.checkedTotal += countToCheck; - } - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - state.checkedTotal -= countToCheck; - } else { - JumpList successes; - - for (state.resetAlternative(); state.alternativeValid(); state.nextAlternative()) { - - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - ASSERT(alternative->m_minimumSize >= preCheckedCount); - int countToCheck = alternative->m_minimumSize - preCheckedCount; - if (countToCheck) { - state.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); - state.checkedTotal += countToCheck; - } - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - // Matched an alternative. - DataLabelPtr dataLabel = storeToFrameWithPatch(alternativeFrameLocation); - successes.append(jump()); - - // Alternative did not match. - Label backtrackLocation(this); - - // Can we backtrack the alternative? - if so, do so. If not, just fall through to the next one. - state.plantJumpToBacktrackIfExists(this); - - state.linkAlternativeBacktracks(this); - - if (countToCheck) { - sub32(Imm32(countToCheck), index); - state.checkedTotal -= countToCheck; - } - - m_backtrackRecords.append(AlternativeBacktrackRecord(dataLabel, backtrackLocation)); - } - // We fall through to here when the last alternative fails. - // Add a backtrack out of here for the parenthese handling code to link up. - state.addBacktrackJump(jump()); - - // Generate a trampoline for the parens code to backtrack to, to retry the - // next alternative. - state.setBacktrackGenerated(label()); - loadFromFrameAndJump(alternativeFrameLocation); - - // FIXME: both of the above hooks are a little inefficient, in that you - // may end up trampolining here, just to trampoline back out to the - // parentheses code, or vice versa. We can probably eliminate a jump - // by restructuring, but coding this way for now for simplicity during - // development. - - successes.link(this); - } - } - - void generateParenthesesSingle(TermGenerationState& state) - { - const RegisterID indexTemporary = regT0; - PatternTerm& term = state.term(); - PatternDisjunction* disjunction = term.parentheses.disjunction; - ASSERT(term.quantityCount == 1); - - unsigned preCheckedCount = (term.quantityType == QuantifierFixedCount) ? disjunction->m_minimumSize : 0; - - unsigned parenthesesFrameLocation = term.frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation; - if (term.quantityType != QuantifierFixedCount) - alternativeFrameLocation += RegexStackSpaceForBackTrackInfoParenthesesOnce; - - // optimized case - no capture & no quantifier can be handled in a light-weight manner. - if (!term.invertOrCapture && (term.quantityType == QuantifierFixedCount)) { - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // this expects that any backtracks back out of the parentheses will be in the - // parenthesesState's backTrackJumps vector, and that if they need backtracking - // they will have set an entry point on the parenthesesState's backtrackLabel. - state.propagateBacktrackingFrom(parenthesesState, this); - } else { - Jump nonGreedySkipParentheses; - Label nonGreedyTryParentheses; - if (term.quantityType == QuantifierGreedy) - storeToFrame(index, parenthesesFrameLocation); - else if (term.quantityType == QuantifierNonGreedy) { - storeToFrame(Imm32(-1), parenthesesFrameLocation); - nonGreedySkipParentheses = jump(); - nonGreedyTryParentheses = label(); - storeToFrame(index, parenthesesFrameLocation); - } - - // store the match start index - if (term.invertOrCapture) { - int inputOffset = state.inputOffset() - preCheckedCount; - if (inputOffset) { - move(index, indexTemporary); - add32(Imm32(inputOffset), indexTemporary); - store32(indexTemporary, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); - } else - store32(index, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); - } - - // generate the body of the parentheses - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - - Jump success = (term.quantityType == QuantifierFixedCount) ? - jump() : - branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesFrameLocation * sizeof(void*)))); - - // A failure AFTER the parens jumps here - Label backtrackFromAfterParens(this); - - if (term.quantityType == QuantifierGreedy) { - // If this is -1 we have now tested with both with and without the parens. - loadFromFrame(parenthesesFrameLocation, indexTemporary); - state.jumpToBacktrack(branch32(Equal, indexTemporary, Imm32(-1)), this); - } else if (term.quantityType == QuantifierNonGreedy) { - // If this is -1 we have now tested without the parens, now test with. - loadFromFrame(parenthesesFrameLocation, indexTemporary); - branch32(Equal, indexTemporary, Imm32(-1)).linkTo(nonGreedyTryParentheses, this); - } - - parenthesesState.plantJumpToBacktrackIfExists(this); - // A failure WITHIN the parens jumps here - parenthesesState.linkAlternativeBacktracks(this); - if (term.invertOrCapture) { - store32(Imm32(-1), Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); -#if 0 - store32(Imm32(-1), Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); -#endif - } - - if (term.quantityType == QuantifierGreedy) - storeToFrame(Imm32(-1), parenthesesFrameLocation); - else - state.jumpToBacktrack(jump(), this); - - state.setBacktrackGenerated(backtrackFromAfterParens); - if (term.quantityType == QuantifierNonGreedy) - nonGreedySkipParentheses.link(this); - success.link(this); - - // store the match end index - if (term.invertOrCapture) { - int inputOffset = state.inputOffset(); - if (inputOffset) { - move(index, indexTemporary); - add32(Imm32(state.inputOffset()), indexTemporary); - store32(indexTemporary, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); - } else - store32(index, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); - } - } - } - - void generateParenthesesGreedyNoBacktrack(TermGenerationState& state) - { - PatternTerm& parenthesesTerm = state.term(); - PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; - ASSERT(parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern); - ASSERT(parenthesesTerm.quantityCount != 1); // Handled by generateParenthesesSingle. - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - - Label matchAgain(this); - - storeToFrame(index, parenthesesTerm.frameLocation); // Save the current index to check for zero len matches later. - - for (parenthesesState.resetAlternative(); parenthesesState.alternativeValid(); parenthesesState.nextAlternative()) { - - PatternAlternative* alternative = parenthesesState.alternative(); - optimizeAlternative(alternative); - - int countToCheck = alternative->m_minimumSize; - if (countToCheck) { - parenthesesState.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); - parenthesesState.checkedTotal += countToCheck; - } - - for (parenthesesState.resetTerm(); parenthesesState.termValid(); parenthesesState.nextTerm()) - generateTerm(parenthesesState); - - // If we get here, we matched! If the index advanced then try to match more since limit isn't supported yet. - branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesTerm.frameLocation * sizeof(void*))), matchAgain); - - // If we get here we matched, but we matched "" - cannot accept this alternative as is, so either backtrack, - // or fall through to try the next alternative if no backtrack is available. - parenthesesState.plantJumpToBacktrackIfExists(this); - - parenthesesState.linkAlternativeBacktracks(this); - // We get here if the alternative fails to match - fall through to the next iteration, or out of the loop. - - if (countToCheck) { - sub32(Imm32(countToCheck), index); - parenthesesState.checkedTotal -= countToCheck; - } - } - - // If the last alternative falls through to here, we have a failed match... - // Which means that we match whatever we have matched up to this point (even if nothing). - } - - void generateParentheticalAssertion(TermGenerationState& state) - { - PatternTerm& term = state.term(); - PatternDisjunction* disjunction = term.parentheses.disjunction; - ASSERT(term.quantityCount == 1); - ASSERT(term.quantityType == QuantifierFixedCount); - - unsigned parenthesesFrameLocation = term.frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation + RegexStackSpaceForBackTrackInfoParentheticalAssertion; - - int countCheckedAfterAssertion = state.checkedTotal - term.inputPosition; - - if (term.invertOrCapture) { - // Inverted case - storeToFrame(index, parenthesesFrameLocation); - - state.checkedTotal -= countCheckedAfterAssertion; - if (countCheckedAfterAssertion) - sub32(Imm32(countCheckedAfterAssertion), index); - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // Success! - which means - Fail! - loadFromFrame(parenthesesFrameLocation, index); - state.jumpToBacktrack(jump(), this); - - // And fail means success. - parenthesesState.linkAlternativeBacktracks(this); - loadFromFrame(parenthesesFrameLocation, index); - - state.checkedTotal += countCheckedAfterAssertion; - } else { - // Normal case - storeToFrame(index, parenthesesFrameLocation); - - state.checkedTotal -= countCheckedAfterAssertion; - if (countCheckedAfterAssertion) - sub32(Imm32(countCheckedAfterAssertion), index); - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // Success! - which means - Success! - loadFromFrame(parenthesesFrameLocation, index); - Jump success = jump(); - - parenthesesState.linkAlternativeBacktracks(this); - loadFromFrame(parenthesesFrameLocation, index); - state.jumpToBacktrack(jump(), this); - - success.link(this); - - state.checkedTotal += countCheckedAfterAssertion; - } - } - - void generateTerm(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - switch (term.type) { - case PatternTerm::TypeAssertionBOL: - generateAssertionBOL(state); - break; - - case PatternTerm::TypeAssertionEOL: - generateAssertionEOL(state); - break; - - case PatternTerm::TypeAssertionWordBoundary: - generateAssertionWordBoundary(state); - break; - - case PatternTerm::TypePatternCharacter: - switch (term.quantityType) { - case QuantifierFixedCount: - if (term.quantityCount == 1) { - if (state.isSinglePatternCharacterLookaheadTerm() && (state.lookaheadTerm().inputPosition == (term.inputPosition + 1))) { - generatePatternCharacterPair(state); - state.nextTerm(); - } else - generatePatternCharacterSingle(state); - } else - generatePatternCharacterFixed(state); - break; - case QuantifierGreedy: - generatePatternCharacterGreedy(state); - break; - case QuantifierNonGreedy: - generatePatternCharacterNonGreedy(state); - break; - } - break; - - case PatternTerm::TypeCharacterClass: - switch (term.quantityType) { - case QuantifierFixedCount: - if (term.quantityCount == 1) - generateCharacterClassSingle(state); - else - generateCharacterClassFixed(state); - break; - case QuantifierGreedy: - generateCharacterClassGreedy(state); - break; - case QuantifierNonGreedy: - generateCharacterClassNonGreedy(state); - break; - } - break; - - case PatternTerm::TypeBackReference: - m_shouldFallBack = true; - break; - - case PatternTerm::TypeForwardReference: - break; - - case PatternTerm::TypeParenthesesSubpattern: - if (term.quantityCount == 1 && !term.parentheses.isCopy) - generateParenthesesSingle(state); - else if (term.parentheses.isTerminal) - generateParenthesesGreedyNoBacktrack(state); - else - m_shouldFallBack = true; - break; - - case PatternTerm::TypeParentheticalAssertion: - generateParentheticalAssertion(state); - break; - } - } - - void generateDisjunction(PatternDisjunction* disjunction) - { - TermGenerationState state(disjunction, 0); - state.resetAlternative(); - - // check availability for the next alternative - int countCheckedForCurrentAlternative = 0; - int countToCheckForFirstAlternative = 0; - bool hasShorterAlternatives = false; - bool setRepeatAlternativeLabels = false; - JumpList notEnoughInputForPreviousAlternative; - Label firstAlternative; - Label firstAlternativeInputChecked; - - // The label 'firstAlternative' is used to plant a check to see if there is - // sufficient input available to run the first repeating alternative. - // The label 'firstAlternativeInputChecked' will jump directly to matching - // the first repeating alternative having skipped this check. - - if (state.alternativeValid()) { - PatternAlternative* alternative = state.alternative(); - if (!alternative->onceThrough()) { - firstAlternative = Label(this); - setRepeatAlternativeLabels = true; - } - countToCheckForFirstAlternative = alternative->m_minimumSize; - state.checkedTotal += countToCheckForFirstAlternative; - if (countToCheckForFirstAlternative) - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); - countCheckedForCurrentAlternative = countToCheckForFirstAlternative; - } - - if (setRepeatAlternativeLabels) - firstAlternativeInputChecked = Label(this); - - while (state.alternativeValid()) { - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - // Track whether any alternatives are shorter than the first one. - if (!alternative->onceThrough()) - hasShorterAlternatives = hasShorterAlternatives || (countCheckedForCurrentAlternative < countToCheckForFirstAlternative); - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - // If we get here, the alternative matched. - if (m_pattern.m_body->m_callFrameSize) - addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - ASSERT(index != returnRegister); - if (m_pattern.m_body->m_hasFixedSize) { - move(index, returnRegister); - if (alternative->m_minimumSize) - sub32(Imm32(alternative->m_minimumSize), returnRegister); - - store32(returnRegister, output); - } else - load32(Address(output), returnRegister); - - store32(index, Address(output, 4)); - - generateReturn(); - - state.nextAlternative(); - - // if there are any more alternatives, plant the check for input before looping. - if (state.alternativeValid()) { - PatternAlternative* nextAlternative = state.alternative(); - if (!setRepeatAlternativeLabels && !nextAlternative->onceThrough()) { - // We have handled non-repeating alternatives, jump to next iteration - // and loop over repeating alternatives. - state.jumpToBacktrack(jump(), this); - - countToCheckForFirstAlternative = nextAlternative->m_minimumSize; - - // If we get here, there the last input checked failed. - notEnoughInputForPreviousAlternative.link(this); - - state.linkAlternativeBacktracks(this); - - // Back up to start the looping alternatives. - if (countCheckedForCurrentAlternative) - sub32(Imm32(countCheckedForCurrentAlternative), index); - - firstAlternative = Label(this); - - state.checkedTotal = countToCheckForFirstAlternative; - if (countToCheckForFirstAlternative) - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); - - countCheckedForCurrentAlternative = countToCheckForFirstAlternative; - - firstAlternativeInputChecked = Label(this); - - setRepeatAlternativeLabels = true; - } else { - int countToCheckForNextAlternative = nextAlternative->m_minimumSize; - - if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one. - // If we get here, then the last input checked failed. - notEnoughInputForPreviousAlternative.link(this); - - // Check if sufficent input available to run the next alternative - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); - // We are now in the correct state to enter the next alternative; this add is only required - // to mirror and revert operation of the sub32, just below. - add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); - - // If we get here, then the last input checked passed. - state.linkAlternativeBacktracks(this); - // No need to check if we can run the next alternative, since it is shorter - - // just update index. - sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); - } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one. - // If we get here, then the last input checked failed. - // If there is insufficient input to run the current alternative, and the next alternative is longer, - // then there is definitely not enough input to run it - don't even check. Just adjust index, as if - // we had checked. - notEnoughInputForPreviousAlternative.link(this); - add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index); - notEnoughInputForPreviousAlternative.append(jump()); - - // The next alternative is longer than the current one; check the difference. - state.linkAlternativeBacktracks(this); - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); - } else { // CASE 3: Both alternatives are the same length. - ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative); - - // If the next alterative is the same length as this one, then no need to check the input - - // if there was sufficent input to run the current alternative then there is sufficient - // input to run the next one; if not, there isn't. - state.linkAlternativeBacktracks(this); - } - state.checkedTotal -= countCheckedForCurrentAlternative; - countCheckedForCurrentAlternative = countToCheckForNextAlternative; - state.checkedTotal += countCheckedForCurrentAlternative; - } - } - } - - // If we get here, all Alternatives failed... - - state.checkedTotal -= countCheckedForCurrentAlternative; - - if (!setRepeatAlternativeLabels) { - // If there are no alternatives that need repeating (all are marked 'onceThrough') then just link - // the match failures to this point, and fall through to the return below. - state.linkAlternativeBacktracks(this); - notEnoughInputForPreviousAlternative.link(this); - } else { - // How much more input need there be to be able to retry from the first alternative? - // examples: - // /yarr_jit/ or /wrec|pcre/ - // In these examples we need check for one more input before looping. - // /yarr_jit|pcre/ - // In this case we need check for 5 more input to loop (+4 to allow for the first alterative - // being four longer than the last alternative checked, and another +1 to effectively move - // the start position along by one). - // /yarr|rules/ or /wrec|notsomuch/ - // In these examples, provided that there was sufficient input to have just been matching for - // the second alternative we can loop without checking for available input (since the second - // alternative is longer than the first). In the latter example we need to decrement index - // (by 4) so the start position is only progressed by 1 from the last iteration. - int incrementForNextIter = (countToCheckForFirstAlternative - countCheckedForCurrentAlternative) + 1; - - // First, deal with the cases where there was sufficient input to try the last alternative. - if (incrementForNextIter > 0) // We need to check for more input anyway, fall through to the checking below. - state.linkAlternativeBacktracks(this); - else if (m_pattern.m_body->m_hasFixedSize && !incrementForNextIter) // No need to update anything, link these backtracks straight to the to pof the loop! - state.linkAlternativeBacktracksTo(firstAlternativeInputChecked, this); - else { // no need to check the input, but we do have some bookkeeping to do first. - state.linkAlternativeBacktracks(this); - - // Where necessary update our preserved start position. - if (!m_pattern.m_body->m_hasFixedSize) { - move(index, regT0); - sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); - store32(regT0, Address(output)); - } - - // Update index if necessary, and loop (without checking). - if (incrementForNextIter) - add32(Imm32(incrementForNextIter), index); - jump().linkTo(firstAlternativeInputChecked, this); - } - - notEnoughInputForPreviousAlternative.link(this); - // Update our idea of the start position, if we're tracking this. - if (!m_pattern.m_body->m_hasFixedSize) { - if (countCheckedForCurrentAlternative - 1) { - move(index, regT0); - sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); - store32(regT0, Address(output)); - } else - store32(index, Address(output)); - } - - // Check if there is sufficent input to run the first alternative again. - jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this); - // No - insufficent input to run the first alteranative, are there any other alternatives we - // might need to check? If so, the last check will have left the index incremented by - // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative - // LESS input is available, to have the effect of just progressing the start position by 1 - // from the last iteration. If this check passes we can just jump up to the check associated - // with the first alternative in the loop. This is a bit sad, since we'll end up trying the - // first alternative again, and this check will fail (otherwise the check planted just above - // here would have passed). This is a bit sad, however it saves trying to do something more - // complex here in compilation, and in the common case we should end up coallescing the checks. - // - // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least - // of the minimum-alternative-lengths. E.g. if I have two alternatives of length 200 and 150, - // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there - // is sufficient input to run either alternative (constantly failing). If there had been only - // one alternative, or if the shorter alternative had come first, we would have terminated - // immediately. :-/ - if (hasShorterAlternatives) - jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this); - // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true, - // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... - // but since we're about to return a failure this doesn't really matter!) - } - - if (m_pattern.m_body->m_callFrameSize) - addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - move(Imm32(-1), returnRegister); - - generateReturn(); - } - - void generateEnter() - { -#if WTF_CPU_X86_64 - push(X86Registers::ebp); - move(stackPointerRegister, X86Registers::ebp); - push(X86Registers::ebx); -#elif WTF_CPU_X86 - push(X86Registers::ebp); - move(stackPointerRegister, X86Registers::ebp); - // TODO: do we need spill registers to fill the output pointer if there are no sub captures? - push(X86Registers::ebx); - push(X86Registers::edi); - push(X86Registers::esi); - // load output into edi (2 = saved ebp + return address). - #if WTF_COMPILER_MSVC || WTF_COMPILER_SUNPRO - loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); - loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); - loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); - loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); - #else - loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); - #endif -#elif WTF_CPU_ARM - push(ARMRegisters::r4); - push(ARMRegisters::r5); - push(ARMRegisters::r6); -#if WTF_CPU_ARM_TRADITIONAL - push(ARMRegisters::r8); // scratch register -#endif - move(ARMRegisters::r3, output); -#elif WTF_CPU_SPARC - save(Imm32(-m_pattern.m_body->m_callFrameSize * sizeof(void*))); - // set m_callFrameSize to 0 avoid and stack movement later. - m_pattern.m_body->m_callFrameSize = 0; -#elif WTF_CPU_MIPS - // Do nothing. -#endif - } - - void generateReturn() - { -#if WTF_CPU_X86_64 - pop(X86Registers::ebx); - pop(X86Registers::ebp); -#elif WTF_CPU_X86 - pop(X86Registers::esi); - pop(X86Registers::edi); - pop(X86Registers::ebx); - pop(X86Registers::ebp); -#elif WTF_CPU_ARM -#if WTF_CPU_ARM_TRADITIONAL - pop(ARMRegisters::r8); // scratch register -#endif - pop(ARMRegisters::r6); - pop(ARMRegisters::r5); - pop(ARMRegisters::r4); -#elif WTF_CPU_SPARC - ret_and_restore(); - return; -#elif WTF_CPU_MIPS - // Do nothing -#endif - ret(); - } - -public: - RegexGenerator(RegexPattern& pattern) - : m_pattern(pattern) - , m_shouldFallBack(false) - { - } - - void generate() - { - generateEnter(); - - if (!m_pattern.m_body->m_hasFixedSize) - store32(index, Address(output)); - - if (m_pattern.m_body->m_callFrameSize) - subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - generateDisjunction(m_pattern.m_body); - } - - void compile(ExecutableAllocator& allocator, RegexCodeBlock& jitObject) - { - generate(); - - if (oom()) { - m_shouldFallBack = true; - return; - } - - ExecutablePool *dummy; - bool ok; - LinkBuffer patchBuffer(this, &allocator, &dummy, &ok); - if (!ok) { - m_shouldFallBack = true; - return; - } - - for (unsigned i = 0; i < m_backtrackRecords.length(); ++i) - patchBuffer.patch(m_backtrackRecords[i].dataLabel, patchBuffer.locationOf(m_backtrackRecords[i].backtrackLocation)); - - jitObject.set(patchBuffer.finalizeCode()); - } - - bool shouldFallBack() - { - return m_shouldFallBack; - } - -private: - RegexPattern& m_pattern; - bool m_shouldFallBack; - js::Vector m_backtrackRecords; -}; - -void jitCompileRegex(ExecutableAllocator& allocator, RegexCodeBlock& jitObject, const UString&patternString, unsigned& numSubpatterns, int &error, bool &fellBack, bool ignoreCase, bool multiline -#ifdef ANDROID - , bool forceFallback -#endif -) -{ -#ifdef ANDROID - if (!forceFallback) { -#endif - fellBack = false; - RegexPattern pattern(ignoreCase, multiline); - if ((error = compileRegex(patternString, pattern))) - return; - numSubpatterns = pattern.m_numSubpatterns; - - if (!pattern.m_containsBackreferences) { - RegexGenerator generator(pattern); - generator.compile(allocator, jitObject); - if (!generator.shouldFallBack()) - return; - } -#ifdef ANDROID - } // forceFallback -#endif - - fellBack = true; - JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase; - JSRegExpMultilineOption multilineOption = multiline ? JSRegExpMultiline : JSRegExpSingleLine; - jitObject.setFallback(jsRegExpCompile(reinterpret_cast(const_cast(patternString).chars()), patternString.length(), ignoreCaseOption, multilineOption, &numSubpatterns, &error)); -} - -}} - -#endif diff --git a/js/src/yarr/yarr/RegexJIT.h b/js/src/yarr/yarr/RegexJIT.h deleted file mode 100644 index 60a51b484c02..000000000000 --- a/js/src/yarr/yarr/RegexJIT.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2009 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 RegexJIT_h -#define RegexJIT_h - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/MacroAssembler.h" -#include "assembler/assembler/MacroAssemblerCodeRef.h" -#include "assembler/jit/ExecutableAllocator.h" -#include "RegexPattern.h" -#include "yarr/jswtfbridge.h" - -#include "yarr/pcre/pcre.h" -struct JSRegExp; // temporary, remove when fallback is removed. - -#if WTF_CPU_X86 && !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO -#define YARR_CALL __attribute__ ((regparm (3))) -#else -#define YARR_CALL -#endif - -struct JSContext; - -namespace JSC { - -namespace Yarr { - -class RegexCodeBlock { - typedef int (*RegexJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; - -public: - RegexCodeBlock() - : m_fallback(0) - { - } - - ~RegexCodeBlock() - { - if (m_fallback) - jsRegExpFree(m_fallback); - if (m_ref.m_size) - m_ref.m_executablePool->release(); - } - - JSRegExp* getFallback() { return m_fallback; } - void setFallback(JSRegExp* fallback) { m_fallback = fallback; } - - bool operator!() { return (!m_ref.m_code.executableAddress() && !m_fallback); } - void set(MacroAssembler::CodeRef ref) { m_ref = ref; } - - int execute(const UChar* input, unsigned start, unsigned length, int* output) - { - void *code = m_ref.m_code.executableAddress(); - return JS_EXTENSION((reinterpret_cast(code))(input, start, length, output)); - } - -private: - MacroAssembler::CodeRef m_ref; - JSRegExp* m_fallback; -}; - -void jitCompileRegex(ExecutableAllocator &allocator, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, int& error, bool &fellBack, bool ignoreCase = false, bool multiline = false -#ifdef ANDROID - , bool forceFallback = false -#endif -); - -inline int executeRegex(JSContext *cx, RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize) -{ - if (JSRegExp* fallback = jitObject.getFallback()) { - int result = jsRegExpExecute(cx, fallback, input, length, start, output, outputArraySize); - - if (result == JSRegExpErrorHitLimit) - return HitRecursionLimit; - - // -1 represents no-match for both PCRE and YARR. - JS_ASSERT(result >= -1); - return result; - } - - return jitObject.execute(input, start, length, output); -} - -} } // namespace JSC::Yarr - -#endif /* ENABLE_ASSEMBLER */ - -#endif // RegexJIT_h diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 50711ae8a547..7341d40d7f65 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -2032,7 +2032,7 @@ POSSIBILITY OF SUCH DAMAGE.

Apple License

-

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr/wtf, js/src/yarr/yarr, and widget/src/cocoa.

+

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr, and widget/src/cocoa.

 Copyright (C) 2008, 2009 Apple Inc. All rights reserved.

From b7962389a834b3d740f79d8a7782ef84aeeacaa7 Mon Sep 17 00:00:00 2001
From: David Mandelin 
Date: Mon, 23 May 2011 14:49:33 -0700
Subject: [PATCH 102/145] Backed out changeset 195f8cf8758f due to ARM bustage

---
 js/src/Makefile.in                            |   37 +-
 .../assembler/AbstractMacroAssembler.h        |   63 +-
 js/src/assembler/assembler/MacroAssembler.h   |   12 +-
 .../assembler/assembler/MacroAssemblerARM.cpp |    2 +-
 .../assembler/assembler/MacroAssemblerARM.h   |   50 +-
 .../assembler/assembler/MacroAssemblerARMv7.h |   44 +-
 .../assembler/MacroAssemblerCodeRef.h         |   17 +-
 .../assembler/assembler/MacroAssemblerSparc.h |   48 +-
 .../assembler/assembler/MacroAssemblerX86.h   |   14 +-
 .../assembler/MacroAssemblerX86Common.h       |   44 +-
 .../assembler/MacroAssemblerX86_64.h          |   16 +-
 js/src/assembler/jit/ExecutableAllocator.h    |   20 +-
 .../assembler/jit/ExecutableAllocatorOS2.cpp  |    2 +-
 .../jit/ExecutableAllocatorPosix.cpp          |    4 +-
 .../jit/ExecutableAllocatorSymbian.cpp        |    2 +-
 .../assembler/jit/ExecutableAllocatorWin.cpp  |    2 +-
 js/src/assembler/wtf/Platform.h               |  989 ++----
 .../jit-test/tests/basic/bug632964-regexp.js  |    3 +
 js/src/jscompartment.cpp                      |   11 +-
 js/src/jscompartment.h                        |   10 +-
 js/src/jsregexp.cpp                           |   46 +-
 js/src/jsregexpinlines.h                      |  119 +-
 js/src/jsvector.h                             |   22 +-
 js/src/methodjit/Compiler.cpp                 |   10 +-
 js/src/methodjit/MethodJIT.cpp                |    7 +-
 js/src/methodjit/TrampolineCompiler.cpp       |    2 +-
 js/src/yarr/BumpPointerAllocator.h            |  254 --
 js/src/yarr/Makefile                          |    5 +
 js/src/yarr/OSAllocator.h                     |  103 -
 js/src/yarr/OSAllocatorPosix.cpp              |  129 -
 js/src/yarr/OSAllocatorWin.cpp                |   89 -
 js/src/yarr/PageAllocation.h                  |  131 -
 js/src/yarr/PageBlock.cpp                     |   88 -
 js/src/yarr/PageBlock.h                       |   91 -
 js/src/yarr/VMTags.h                          |   90 -
 js/src/yarr/Yarr.h                            |   72 -
 js/src/yarr/YarrInterpreter.cpp               | 1914 -----------
 js/src/yarr/YarrInterpreter.h                 |  380 ---
 js/src/yarr/YarrJIT.cpp                       | 2405 -------------
 js/src/yarr/YarrJIT.h                         |   93 -
 js/src/yarr/jswtfbridge.h                     |   61 +
 js/src/yarr/pcre/AUTHORS                      |   12 +
 js/src/yarr/pcre/COPYING                      |   35 +
 js/src/yarr/pcre/chartables.c                 |   96 +
 js/src/yarr/pcre/dftables                     |  273 ++
 js/src/yarr/pcre/pcre.h                       |   68 +
 js/src/yarr/pcre/pcre.pri                     |   12 +
 js/src/yarr/pcre/pcre_compile.cpp             | 2702 +++++++++++++++
 js/src/yarr/pcre/pcre_exec.cpp                | 2193 ++++++++++++
 js/src/yarr/pcre/pcre_internal.h              |  434 +++
 js/src/yarr/pcre/pcre_tables.cpp              |   71 +
 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp     |   98 +
 js/src/yarr/pcre/pcre_xclass.cpp              |  114 +
 js/src/yarr/pcre/ucpinternal.h                |  126 +
 js/src/yarr/pcre/ucptable.cpp                 | 2968 +++++++++++++++++
 js/src/yarr/{ => wtf}/ASCIICType.h            |   33 +-
 js/src/yarr/wtfbridge.h                       |  321 --
 js/src/yarr/{ => yarr}/RegExpJitTables.h      |    0
 .../RegexCommon.h}                            |   56 +-
 .../RegexCompiler.cpp}                        |  568 +---
 .../RegexCompiler.h}                          |   25 +-
 js/src/yarr/yarr/RegexJIT.cpp                 | 1589 +++++++++
 js/src/yarr/yarr/RegexJIT.h                   |  112 +
 .../yarr/{YarrParser.h => yarr/RegexParser.h} |  260 +-
 .../{YarrPattern.h => yarr/RegexPattern.h}    |  218 +-
 toolkit/content/license.html                  |    2 +-
 66 files changed, 12024 insertions(+), 7863 deletions(-)
 delete mode 100644 js/src/yarr/BumpPointerAllocator.h
 create mode 100644 js/src/yarr/Makefile
 delete mode 100644 js/src/yarr/OSAllocator.h
 delete mode 100644 js/src/yarr/OSAllocatorPosix.cpp
 delete mode 100644 js/src/yarr/OSAllocatorWin.cpp
 delete mode 100644 js/src/yarr/PageAllocation.h
 delete mode 100644 js/src/yarr/PageBlock.cpp
 delete mode 100644 js/src/yarr/PageBlock.h
 delete mode 100644 js/src/yarr/VMTags.h
 delete mode 100644 js/src/yarr/Yarr.h
 delete mode 100644 js/src/yarr/YarrInterpreter.cpp
 delete mode 100644 js/src/yarr/YarrInterpreter.h
 delete mode 100644 js/src/yarr/YarrJIT.cpp
 delete mode 100644 js/src/yarr/YarrJIT.h
 create mode 100644 js/src/yarr/jswtfbridge.h
 create mode 100644 js/src/yarr/pcre/AUTHORS
 create mode 100644 js/src/yarr/pcre/COPYING
 create mode 100644 js/src/yarr/pcre/chartables.c
 create mode 100644 js/src/yarr/pcre/dftables
 create mode 100644 js/src/yarr/pcre/pcre.h
 create mode 100644 js/src/yarr/pcre/pcre.pri
 create mode 100644 js/src/yarr/pcre/pcre_compile.cpp
 create mode 100644 js/src/yarr/pcre/pcre_exec.cpp
 create mode 100644 js/src/yarr/pcre/pcre_internal.h
 create mode 100644 js/src/yarr/pcre/pcre_tables.cpp
 create mode 100644 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp
 create mode 100644 js/src/yarr/pcre/pcre_xclass.cpp
 create mode 100644 js/src/yarr/pcre/ucpinternal.h
 create mode 100644 js/src/yarr/pcre/ucptable.cpp
 rename js/src/yarr/{ => wtf}/ASCIICType.h (81%)
 delete mode 100644 js/src/yarr/wtfbridge.h
 rename js/src/yarr/{ => yarr}/RegExpJitTables.h (100%)
 rename js/src/yarr/{YarrSyntaxChecker.cpp => yarr/RegexCommon.h} (52%)
 rename js/src/yarr/{YarrPattern.cpp => yarr/RegexCompiler.cpp} (52%)
 rename js/src/yarr/{YarrSyntaxChecker.h => yarr/RegexCompiler.h} (74%)
 create mode 100644 js/src/yarr/yarr/RegexJIT.cpp
 create mode 100644 js/src/yarr/yarr/RegexJIT.h
 rename js/src/yarr/{YarrParser.h => yarr/RegexParser.h} (81%)
 rename js/src/yarr/{YarrPattern.h => yarr/RegexPattern.h} (70%)

diff --git a/js/src/Makefile.in b/js/src/Makefile.in
index 71f35a53d881..8023b1750b05 100644
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -362,6 +362,7 @@ CPPSRCS += 	MethodJIT.cpp \
 		Retcon.cpp \
 		TrampolineCompiler.cpp \
 		$(NULL)
+#		PICStubCompiler.cpp \
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
 ifeq (x86_64, $(TARGET_CPU))
@@ -419,17 +420,14 @@ ifeq (,$(filter arm% sparc %86 x86_64,$(TARGET_CPU)))
 
 VPATH +=	$(srcdir)/assembler \
 		$(srcdir)/assembler/wtf \
-		$(srcdir)/yarr\
+		$(srcdir)/yarr/pcre \
 		$(NULL)
 
-CPPSRCS += \
-		Assertions.cpp \
-		OSAllocatorPosix.cpp \
-		OSAllocatorWin.cpp \
-		PageBlock.cpp \
-		YarrInterpreter.cpp \
-		YarrPattern.cpp \
-		YarrSyntaxChecker.cpp \
+CPPSRCS += 	pcre_compile.cpp \
+                pcre_exec.cpp \
+                pcre_tables.cpp \
+                pcre_xclass.cpp \
+                pcre_ucp_searchfuncs.cpp \
 		$(NULL)
 else
 
@@ -442,6 +440,9 @@ VPATH += 	$(srcdir)/assembler \
 		$(srcdir)/assembler/assembler \
 		$(srcdir)/methodjit \
 		$(srcdir)/yarr \
+		$(srcdir)/yarr/yarr \
+		$(srcdir)/yarr/pcre \
+		$(srcdir)/yarr/wtf \
 		$(NONE)
 
 CPPSRCS += 	Assertions.cpp \
@@ -450,16 +451,16 @@ CPPSRCS += 	Assertions.cpp \
 		ExecutableAllocatorOS2.cpp \
 		ExecutableAllocator.cpp \
 		ARMAssembler.cpp \
-        Logging.cpp \
+                Logging.cpp \
 		MacroAssemblerARM.cpp \
 		MacroAssemblerX86Common.cpp \
-		OSAllocatorPosix.cpp \
-		OSAllocatorWin.cpp \
-		PageBlock.cpp \
-		YarrInterpreter.cpp \
-		YarrJIT.cpp \
-		YarrPattern.cpp \
-		YarrSyntaxChecker.cpp \
+		RegexCompiler.cpp \
+		RegexJIT.cpp \
+		pcre_compile.cpp \
+                pcre_exec.cpp \
+                pcre_tables.cpp \
+                pcre_xclass.cpp \
+                pcre_ucp_searchfuncs.cpp \
 		$(NONE)
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
@@ -652,7 +653,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
 
 	# We desire these numbers to go down, not up. See "User guide to memory
 	# management within SpiderMonkey" in jsutil.h.
-	$(srcdir)/config/check_source_count.py OffTheBooks:: 54 \
+	$(srcdir)/config/check_source_count.py OffTheBooks:: 52 \
 		"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
 	# This should go to zero, if possible.
 	$(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \
diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h
index 3c14c80bd4b0..260380acd307 100644
--- a/js/src/assembler/assembler/AbstractMacroAssembler.h
+++ b/js/src/assembler/assembler/AbstractMacroAssembler.h
@@ -166,13 +166,13 @@ public:
         void* m_ptr;
     };
 
-    // TrustedImmPtr:
+    // ImmPtr:
     //
     // A pointer sized immediate operand to an instruction - this is wrapped
     // in a class requiring explicit construction in order to differentiate
     // from pointers used as absolute addresses to memory operations
-    struct TrustedImmPtr {
-        explicit TrustedImmPtr(const void* value)
+    struct ImmPtr {
+        explicit ImmPtr(const void* value)
             : m_value(value)
         {
         }
@@ -185,21 +185,14 @@ public:
         const void* m_value;
     };
 
-    struct ImmPtr : public TrustedImmPtr {
-        explicit ImmPtr(const void* value)
-            : TrustedImmPtr(value)
-        {
-        }
-    };
- 
-    // TrustedImm32:
+    // Imm32:
     //
     // A 32bit immediate operand to an instruction - this is wrapped in a
     // class requiring explicit construction in order to prevent RegisterIDs
     // (which are implemented as an enum) from accidentally being passed as
     // immediate values.
-    struct TrustedImm32 {
-        explicit TrustedImm32(int32_t value)
+    struct Imm32 {
+        explicit Imm32(int32_t value)
             : m_value(value)
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(false)
@@ -208,7 +201,7 @@ public:
         }
 
 #if !WTF_CPU_X86_64
-        explicit TrustedImm32(TrustedImmPtr ptr)
+        explicit Imm32(ImmPtr ptr)
             : m_value(ptr.asIntptr())
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(true)
@@ -230,20 +223,6 @@ public:
 #endif
     };
 
-
-    struct Imm32 : public TrustedImm32 {
-        explicit Imm32(int32_t value)
-            : TrustedImm32(value)
-        {
-        }
-#if !WTF_CPU_X86_64
-        explicit Imm32(TrustedImmPtr ptr)
-            : TrustedImm32(ptr)
-        {
-        }
-#endif
-    };
-
     struct ImmDouble {
         union {
             struct {
@@ -262,6 +241,7 @@ public:
         }
     };
 
+
     // Section 2: MacroAssembler code buffer handles
     //
     // The following types are used to reference items in the code buffer
@@ -293,7 +273,7 @@ public:
         
         bool isUsed() const { return m_label.isUsed(); }
         void used() { m_label.used(); }
-        bool isSet() const { return m_label.isValid(); }
+        bool isValid() const { return m_label.isValid(); }
     private:
         JmpDst m_label;
     };
@@ -316,8 +296,6 @@ public:
         {
         }
         
-        bool isSet() const { return m_label.isValid(); }
-
     private:
         JmpDst m_label;
     };
@@ -433,20 +411,6 @@ public:
     public:
         typedef js::Vector JumpVector;
 
-        JumpList() {}
-
-        JumpList(const JumpList &other)
-        {
-            m_jumps.append(other.m_jumps);
-        }
-
-        JumpList &operator=(const JumpList &other)
-        {
-            m_jumps.clear();
-            m_jumps.append(other.m_jumps);
-            return *this;
-        }
-
         void link(AbstractMacroAssembler* masm)
         {
             size_t size = m_jumps.length();
@@ -468,22 +432,17 @@ public:
             m_jumps.append(jump);
         }
         
-        void append(const JumpList& other)
+        void append(JumpList& other)
         {
             m_jumps.append(other.m_jumps.begin(), other.m_jumps.length());
         }
 
-        void clear()
-        {
-            m_jumps.clear();
-        }
-
         bool empty()
         {
             return !m_jumps.length();
         }
         
-        const JumpVector& jumps() const { return m_jumps; }
+        const JumpVector& jumps() { return m_jumps; }
 
     private:
         JumpVector m_jumps;
diff --git a/js/src/assembler/assembler/MacroAssembler.h b/js/src/assembler/assembler/MacroAssembler.h
index 38d5a31a2590..73bda22a8ee2 100644
--- a/js/src/assembler/assembler/MacroAssembler.h
+++ b/js/src/assembler/assembler/MacroAssembler.h
@@ -95,12 +95,12 @@ public:
         storePtr(src, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(TrustedImm32 value, int index = 0)
+    void poke(Imm32 value, int index = 0)
     {
         store32(value, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(TrustedImmPtr imm, int index = 0)
+    void poke(ImmPtr imm, int index = 0)
     {
         storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*))));
     }
@@ -117,7 +117,7 @@ public:
         branch32(cond, op1, op2).linkTo(target, this);
     }
 
-    void branch32(Condition cond, RegisterID op1, TrustedImm32 imm, Label target)
+    void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target)
     {
         branch32(cond, op1, imm).linkTo(target, this);
     }
@@ -288,17 +288,17 @@ public:
         store32(src, address);
     }
 
-    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
+    void storePtr(ImmPtr imm, ImplicitAddress address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(TrustedImmPtr imm, BaseIndex address)
+    void storePtr(ImmPtr imm, BaseIndex address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(TrustedImmPtr imm, void* address)
+    void storePtr(ImmPtr imm, void* address)
     {
         store32(Imm32(imm), address);
     }
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.cpp b/js/src/assembler/assembler/MacroAssemblerARM.cpp
index 065c98197395..14b4166b7ea9 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.cpp
+++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp
@@ -34,7 +34,7 @@
 
 #include "MacroAssemblerARM.h"
 
-#if WTF_OS_LINUX || WTF_OS_ANDROID
+#if WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID
 #include 
 #include 
 #include 
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h
index 2630bce7a909..7413411f4500 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -91,14 +91,14 @@ public:
         m_assembler.adds_r(dest, dest, src);
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         add32(imm, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -173,7 +173,7 @@ public:
         m_assembler.orrs_r(dest, dest, src);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -211,12 +211,12 @@ public:
         m_assembler.subs_r(dest, dest, src);
     }
 
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
 
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         sub32(imm, ARMRegisters::S1);
@@ -240,7 +240,7 @@ public:
         m_assembler.eors_r(dest, dest, src);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -380,7 +380,7 @@ public:
         m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset);
     }
 
-    void store32(TrustedImm32 imm, BaseIndex address)
+    void store32(Imm32 imm, BaseIndex address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -389,7 +389,7 @@ public:
         store32(ARMRegisters::S1, address);
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -404,7 +404,7 @@ public:
         m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address));
         if (imm.m_isPointer)
@@ -436,7 +436,7 @@ public:
         push(ARMRegisters::S0);
     }
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(dest, imm.m_value);
@@ -449,7 +449,7 @@ public:
         m_assembler.mov_r(dest, src);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -485,7 +485,7 @@ public:
         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
     {
         ASSERT(left != ARMRegisters::S0);
         if (right.m_isPointer) {
@@ -500,21 +500,21 @@ public:
     // number of instructions emitted is constant, regardless of the argument
     // values. For ARM, this is identical to branch32WithPatch, except that it
     // does not generate a DataLabel32.
-    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
     // As branch32_force32, but allow the value ('right') to be patched.
-    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left != ARMRegisters::S1);
         dataLabel = moveWithPatch(right, ARMRegisters::S1);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left.base != ARMRegisters::S1);
         load32(left, ARMRegisters::S1);
@@ -534,19 +534,19 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -828,7 +828,7 @@ public:
         setTest32(cond, address, mask, dest);
     }
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -850,7 +850,7 @@ public:
         move(ARMRegisters::S1, dest);
     }
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -859,7 +859,7 @@ public:
         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -880,7 +880,7 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         load32(left.m_ptr, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -908,14 +908,14 @@ public:
         return Call::fromTailJump(oldJump);
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         DataLabelPtr dataLabel(this);
         m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value));
         return dataLabel;
     }
 
-    DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
+    DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
     {
         DataLabel32 dataLabel(this);
         m_assembler.ldr_un_imm(dest, initialValue.m_value);
@@ -937,7 +937,7 @@ public:
         return jump;
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h
index c23e9ea6655f..5492f8246a06 100644
--- a/js/src/assembler/assembler/MacroAssemblerARMv7.h
+++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h
@@ -131,12 +131,12 @@ public:
         m_assembler.add(dest, dest, src);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         add32(imm, dest, dest);
     }
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -147,7 +147,7 @@ public:
         }
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -170,7 +170,7 @@ public:
         add32(dataTempRegister, dest);
     }
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -239,7 +239,7 @@ public:
         m_assembler.orr(dest, dest, src);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -285,7 +285,7 @@ public:
         m_assembler.sub(dest, dest, src);
     }
 
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -296,7 +296,7 @@ public:
         }
     }
 
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -319,7 +319,7 @@ public:
         sub32(dataTempRegister, dest);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -341,7 +341,7 @@ public:
         m_assembler.eor(dest, dest, src);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -486,7 +486,7 @@ public:
         store32(src, setupArmAddress(address));
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, setupArmAddress(address));
@@ -498,7 +498,7 @@ public:
         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, address);
@@ -667,7 +667,7 @@ public:
     //
     // Move values in registers.
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         uint32_t value = imm.m_value;
 
@@ -693,7 +693,7 @@ public:
         m_assembler.mov(dest, src);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -780,7 +780,7 @@ public:
         return Jump(makeBranch(cond));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right)
     {
         compare32(left, right);
         return Jump(makeBranch(cond));
@@ -798,21 +798,21 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32WithUnalignedHalfWords(left, addressTempRegister);
@@ -825,7 +825,7 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left.m_ptr, addressTempRegister);
@@ -1065,13 +1065,13 @@ public:
         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
     }
 
-    DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
+    DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst)
     {
         moveFixedWidthEncoding(imm, dst);
         return DataLabel32(this);
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
+    DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst)
     {
         moveFixedWidthEncoding(Imm32(imm), dst);
         return DataLabelPtr(this);
@@ -1090,7 +1090,7 @@ public:
         return branch32(cond, addressTempRegister, dataTempRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
         store32(dataTempRegister, address);
@@ -1179,7 +1179,7 @@ protected:
         return addressTempRegister;
     }
 
-    void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
+    void moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
     {
         uint32_t value = imm.m_value;
         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
diff --git a/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
index 6acdfd67a74d..841fa9647128 100644
--- a/js/src/assembler/assembler/MacroAssemblerCodeRef.h
+++ b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
@@ -180,8 +180,7 @@ private:
 class MacroAssemblerCodeRef {
 public:
     MacroAssemblerCodeRef()
-        : m_executablePool(NULL),
-          m_size(0)
+        : m_size(0)
     {
     }
 
@@ -192,20 +191,6 @@ public:
     {
     }
 
-    // Release the code memory in this code ref.
-    void release()
-    {
-        if (!m_executablePool)
-            return;
-
-#if defined DEBUG && (defined WTF_CPU_X86 || defined WTF_CPU_X86_64) 
-        void *addr = m_code.executableAddress();
-        memset(addr, 0xcc, m_size);
-#endif
-        m_executablePool->release();
-        m_executablePool = NULL;
-    }
-
     MacroAssemblerCodePtr m_code;
     ExecutablePool* m_executablePool;
     size_t m_size;
diff --git a/js/src/assembler/assembler/MacroAssemblerSparc.h b/js/src/assembler/assembler/MacroAssemblerSparc.h
index 91a8f0e16163..3bdd2d871b1b 100644
--- a/js/src/assembler/assembler/MacroAssemblerSparc.h
+++ b/js/src/assembler/assembler/MacroAssemblerSparc.h
@@ -97,14 +97,14 @@ namespace JSC {
             m_assembler.addcc_r(dest, src, dest);
         }
 
-        void add32(TrustedImm32 imm, Address address)
+        void add32(Imm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             add32(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
         }
 
-        void add32(TrustedImm32 imm, RegisterID dest)
+        void add32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(dest, imm.m_value, dest);
@@ -126,7 +126,7 @@ namespace JSC {
             m_assembler.andcc_r(dest, SparcRegisters::g2, dest);
         }
 
-        void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+        void add32(Imm32 imm, RegisterID src, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(src, imm.m_value, dest);
@@ -194,7 +194,7 @@ namespace JSC {
             m_assembler.orcc_r(dest, src, dest);
         }
 
-        void or32(TrustedImm32 imm, RegisterID dest)
+        void or32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.orcc_imm(dest, imm.m_value, dest);
@@ -240,7 +240,7 @@ namespace JSC {
             m_assembler.subcc_r(dest, src, dest);
         }
 
-        void sub32(TrustedImm32 imm, RegisterID dest)
+        void sub32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.subcc_imm(dest, imm.m_value, dest);
@@ -250,7 +250,7 @@ namespace JSC {
             }
         }
 
-        void sub32(TrustedImm32 imm, Address address)
+        void sub32(Imm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -268,7 +268,7 @@ namespace JSC {
             m_assembler.xorcc_r(src, dest, dest);
         }
 
-        void xor32(TrustedImm32 imm, RegisterID dest)
+        void xor32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.xorcc_imm(dest, imm.m_value, dest);
@@ -548,7 +548,7 @@ namespace JSC {
             m_assembler.stw_r(src, address.base, SparcRegisters::g2);
         }
 
-        void store32(TrustedImm32 imm, BaseIndex address)
+        void store32(Imm32 imm, BaseIndex address)
         {
             m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
             add32(Imm32(address.offset), SparcRegisters::g2);
@@ -556,7 +556,7 @@ namespace JSC {
             m_assembler.stw_r(SparcRegisters::g3, SparcRegisters::g2, address.base);
         }
 
-        void store32(TrustedImm32 imm, ImplicitAddress address)
+        void store32(Imm32 imm, ImplicitAddress address)
         {
             m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -568,7 +568,7 @@ namespace JSC {
             m_assembler.stw_r(src, SparcRegisters::g0, SparcRegisters::g3);
         }
 
-        void store32(TrustedImm32 imm, void* address)
+        void store32(Imm32 imm, void* address)
         {
             move(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -598,7 +598,7 @@ namespace JSC {
             push(SparcRegisters::g2);
         }
 
-        void move(TrustedImm32 imm, RegisterID dest)
+        void move(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.or_imm(SparcRegisters::g0, imm.m_value, dest);
@@ -611,7 +611,7 @@ namespace JSC {
             m_assembler.or_r(src, SparcRegisters::g0, dest);
         }
 
-        void move(TrustedImmPtr imm, RegisterID dest)
+        void move(ImmPtr imm, RegisterID dest)
         {
             move(Imm32(imm), dest);
         }
@@ -641,20 +641,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32_force32(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32_force32(Condition cond, RegisterID left, Imm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
             m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g2);
             return branch32(cond, left, SparcRegisters::g2);
         }
 
-        Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+        Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
         {
             // Always use move_nocheck, since the value is to be patched.
             dataLabel = DataLabel32(this);
@@ -669,7 +669,7 @@ namespace JSC {
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32(Condition cond, RegisterID left, Imm32 right)
         {
             if (m_assembler.isimm13(right.m_value))
                 m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0);
@@ -692,20 +692,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, Address left, TrustedImm32 right)
+        Jump branch32(Condition cond, Address left, Imm32 right)
         {
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+        Jump branch32(Condition cond, BaseIndex left, Imm32 right)
         {
 
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
         {
             load32WithUnalignedHalfWords(left, SparcRegisters::g4);
             return branch32(cond, SparcRegisters::g4, right);
@@ -1052,7 +1052,7 @@ namespace JSC {
             store32(SparcRegisters::g2, address.m_ptr);
         }
 
-        void sub32(TrustedImm32 imm, AbsoluteAddress address)
+        void sub32(Imm32 imm, AbsoluteAddress address)
         {
             load32(address.m_ptr, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -1071,7 +1071,7 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+        Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
         {
             load32(left.m_ptr, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
@@ -1099,7 +1099,7 @@ namespace JSC {
             return Call::fromTailJump(oldJump);
         }
 
-        DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+        DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
         {
             DataLabelPtr dataLabel(this);
             Imm32 imm = Imm32(initialValue);
@@ -1107,7 +1107,7 @@ namespace JSC {
             return dataLabel;
         }
 
-        DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
+        DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
         {
             DataLabel32 dataLabel(this);
             m_assembler.move_nocheck(initialValue.m_value, dest);
@@ -1129,7 +1129,7 @@ namespace JSC {
             return jump;
         }
 
-        DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+        DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
         {
             DataLabelPtr dataLabel = moveWithPatch(initialValue, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86.h b/js/src/assembler/assembler/MacroAssemblerX86.h
index c6ab40f587fa..ee61b895a8fe 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.leal_mr(imm.m_value, src, dest);
     }
@@ -90,12 +90,12 @@ public:
         m_assembler.andl_im(imm.m_value, address.m_ptr);
     }
     
-    void or32(TrustedImm32 imm, AbsoluteAddress address)
+    void or32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.orl_im(imm.m_value, address.m_ptr);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.subl_im(imm.m_value, address.m_ptr);
     }
@@ -148,7 +148,7 @@ public:
         addDouble(Address(srcDest), dest);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         m_assembler.movl_i32m(imm.m_value, address);
     }
@@ -164,7 +164,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.m_ptr);
         return Jump(m_assembler.jCC(x86Condition(cond)));
@@ -186,7 +186,7 @@ public:
     }
 
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movl_i32r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -206,7 +206,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base);
         return DataLabelPtr(this);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h
index fa1b7ba8cb10..1ead9665f4e2 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86Common.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h
@@ -116,12 +116,12 @@ public:
         m_assembler.addl_rr(src, dest);
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         m_assembler.addl_im(imm.m_value, address.offset, address.base);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         m_assembler.addl_ir(imm.m_value, dest);
     }
@@ -234,7 +234,7 @@ public:
         m_assembler.orl_rr(src, dest);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         m_assembler.orl_ir(imm.m_value, dest);
     }
@@ -249,7 +249,7 @@ public:
         m_assembler.orl_mr(src.offset, src.base, dest);
     }
 
-    void or32(TrustedImm32 imm, Address address)
+    void or32(Imm32 imm, Address address)
     {
         m_assembler.orl_im(imm.m_value, address.offset, address.base);
     }
@@ -313,12 +313,12 @@ public:
         m_assembler.subl_rr(src, dest);
     }
     
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         m_assembler.subl_ir(imm.m_value, dest);
     }
     
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         m_assembler.subl_im(imm.m_value, address.offset, address.base);
     }
@@ -339,12 +339,12 @@ public:
         m_assembler.xorl_rr(src, dest);
     }
 
-    void xor32(TrustedImm32 imm, Address dest)
+    void xor32(Imm32 imm, Address dest)
     {
         m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         m_assembler.xorl_ir(imm.m_value, dest);
     }
@@ -468,7 +468,7 @@ public:
         m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(TrustedImm32 imm, BaseIndex address)
+    void store32(Imm32 imm, BaseIndex address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
@@ -483,7 +483,7 @@ public:
         m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
     }
@@ -748,7 +748,7 @@ public:
     //
     // Move values in registers.
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         // Note: on 64-bit the Imm32 value is zero extended into the register, it
         // may be useful to have a separate version that sign extends the value?
@@ -767,7 +767,7 @@ public:
             m_assembler.movq_rr(src, dest);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         m_assembler.movq_i64r(imm.asIntptr(), dest);
     }
@@ -798,7 +798,7 @@ public:
             m_assembler.movl_rr(src, dest);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         m_assembler.movl_i32r(imm.asIntptr(), dest);
     }
@@ -852,7 +852,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right)
     {
         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
             m_assembler.testl_rr(left, left);
@@ -864,14 +864,14 @@ public:
     // Branch based on a 32-bit comparison, forcing the size of the
     // immediate operand to 32 bits in the native code stream to ensure that
     // the length of code emitted by this instruction is consistent.
-    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
     {
         m_assembler.cmpl_ir_force32(right.m_value, left);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
     // Branch and record a label after the comparison.
-    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
     {
         // Always use cmpl, since the value is to be patched.
         m_assembler.cmpl_ir_force32(right.m_value, left);
@@ -879,7 +879,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
     {
         m_assembler.cmpl_im_force32(right.m_value, left.offset, left.base);
         dataLabel = DataLabel32(this);
@@ -898,19 +898,19 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         return branch32(cond, left, right);
     }
@@ -1369,7 +1369,7 @@ private:
     }
 
 #if WTF_CPU_X86
-#if WTF_OS_MAC_OS_X
+#if WTF_PLATFORM_MAC
 
     // All X86 Macs are guaranteed to support at least SSE2
     static bool isSSEPresent()
@@ -1382,7 +1382,7 @@ private:
         return true;
     }
 
-#else // OS(MAC_OS_X)
+#else // PLATFORM(MAC)
 
     static bool isSSEPresent()
     {
diff --git a/js/src/assembler/assembler/MacroAssemblerX86_64.h b/js/src/assembler/assembler/MacroAssemblerX86_64.h
index a5038a930e56..7dadc6bcaf2e 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86_64.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         add32(imm, Address(scratchRegister));
@@ -72,13 +72,13 @@ public:
         and32(imm, Address(scratchRegister));
     }
     
-    void or32(TrustedImm32 imm, AbsoluteAddress address)
+    void or32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         or32(imm, Address(scratchRegister));
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         sub32(imm, Address(scratchRegister));
@@ -114,7 +114,7 @@ public:
         m_assembler.cvtsq2sd_rr(srcDest, dest);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         move(X86Registers::eax, scratchRegister);
         move(imm, X86Registers::eax);
@@ -311,7 +311,7 @@ public:
         m_assembler.movq_rm(src, address.offset, address.base);
     }
 
-    void storePtr(TrustedImmPtr imm, BaseIndex address)
+    void storePtr(ImmPtr imm, BaseIndex address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -341,7 +341,7 @@ public:
         }
     }
 
-    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
+    void storePtr(ImmPtr imm, ImplicitAddress address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -487,7 +487,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -505,7 +505,7 @@ public:
         return branchPtr(cond, left, scratchRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
         storePtr(scratchRegister, address);
diff --git a/js/src/assembler/jit/ExecutableAllocator.h b/js/src/assembler/jit/ExecutableAllocator.h
index 9cca26f48c99..a54a4dab143b 100644
--- a/js/src/assembler/jit/ExecutableAllocator.h
+++ b/js/src/assembler/jit/ExecutableAllocator.h
@@ -52,16 +52,16 @@ extern  "C" void sync_instruction_memory(caddr_t v, u_int len);
 #endif
 #endif
 
-#if WTF_OS_IOS
+#if WTF_PLATFORM_IPHONE
 #include 
 #include 
 #endif
 
-#if WTF_OS_SYMBIAN
+#if WTF_PLATFORM_SYMBIAN
 #include 
 #endif
 
-#if WTF_CPU_MIPS && WTF_OS_LINUX
+#if WTF_CPU_MIPS && WTF_PLATFORM_LINUX
 #include 
 #endif
 
@@ -90,7 +90,7 @@ private:
     struct Allocation {
         char* pages;
         size_t size;
-#if WTF_OS_SYMBIAN
+#if WTF_PLATFORM_SYMBIAN
         RChunk* chunk;
 #endif
     };
@@ -269,7 +269,6 @@ private:
         return pool;
     }
 
-public:
     ExecutablePool* poolForSize(size_t n)
     {
 #ifndef DEBUG_STRESS_JSC_ALLOCATOR
@@ -328,6 +327,7 @@ public:
         return pool;
     }
 
+public:
 #if ENABLE_ASSEMBLER_WX_EXCLUSIVE
     static void makeWritable(void* start, size_t size)
     {
@@ -374,13 +374,13 @@ public:
         _flush_cache(reinterpret_cast(code), size, BCACHE);
 #endif
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_OS_IOS
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
     static void cacheFlush(void* code, size_t size)
     {
         sys_dcache_flush(code, size);
         sys_icache_invalidate(code, size);
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_IOS
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_LINUX
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
@@ -396,14 +396,14 @@ public:
             : "r" (code), "r" (reinterpret_cast(code) + size)
             : "r0", "r1", "r2");
     }
-#elif WTF_OS_SYMBIAN
+#elif WTF_PLATFORM_SYMBIAN
     static void cacheFlush(void* code, size_t size)
     {
         User::IMB_Range(code, static_cast(code) + size);
     }
-#elif WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
     static __asm void cacheFlush(void* code, size_t size);
-#elif WTF_CPU_ARM_TRADITIONAL && (WTF_OS_LINUX || WTF_OS_ANDROID) && WTF_COMPILER_GCC
+#elif WTF_CPU_ARM_TRADITIONAL && (WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID) && WTF_COMPILER_GCC
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
diff --git a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
index 675b604ae914..ef9e27d92b47 100644
--- a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_OS2
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_OS2
 
 #define INCL_DOS
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
index e334626ccc2f..50efd932e02a 100644
--- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
@@ -25,7 +25,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
 
 #include 
 #include 
@@ -74,7 +74,7 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe
 }
 #endif
 
-#if WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
+#if WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
 __asm void ExecutableAllocator::cacheFlush(void* code, size_t size)
 {
     ARM
diff --git a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
index f51c0d507877..c66fa80fff12 100644
--- a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
@@ -22,7 +22,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_SYMBIAN
 
 #include 
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorWin.cpp b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
index da6e756cfa66..f5775608f36f 100644
--- a/js/src/assembler/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_WIN_OS
 
 #include "jswin.h"
 
diff --git a/js/src/assembler/wtf/Platform.h b/js/src/assembler/wtf/Platform.h
index 217c9b8a1eec..68713cd4c810 100644
--- a/js/src/assembler/wtf/Platform.h
+++ b/js/src/assembler/wtf/Platform.h
@@ -1,7 +1,6 @@
 /*
  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc.  All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,267 +27,206 @@
 #ifndef WTF_Platform_h
 #define WTF_Platform_h
 
+/* Either XX(YY) --> WTF_XX_YY  or  XX(YY) --> XX_YY, depending on XX
+
+   PLATFORM(YY) --> WTF_PLATFORM_YY
+   COMPILER(YY) --> WTF_COMPILER_YY
+   CPU(YY)      --> WTF_CPU_YY
+   OS(YY)       --> WTF_OS_YY
+   USE(YY)      --> WTF_USE_YY
+
+   HAVE(YY)     --> HAVE_YY
+   ENABLE(YY)   --> ENABLE_YY
+*/
+
 /* ==== PLATFORM handles OS, operating environment, graphics API, and
    CPU. This macro will be phased out in favor of platform adaptation
    macros, policy decision macros, and top-level port definitions. ==== */
-#define PLATFORM(WTF_FEATURE) (defined WTF_PLATFORM_##WTF_FEATURE  && WTF_PLATFORM_##WTF_FEATURE)
+//#define PLATFORM(WTF_FEATURE) (defined(WTF_PLATFORM_##WTF_FEATURE)  && WTF_PLATFORM_##WTF_FEATURE)
 
 
 /* ==== Platform adaptation macros: these describe properties of the target environment. ==== */
 
 /* COMPILER() - the compiler being used to build the project */
-#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE  && WTF_COMPILER_##WTF_FEATURE)
+//#define COMPILER(WTF_FEATURE) (defined(WTF_COMPILER_##WTF_FEATURE)  && WTF_COMPILER_##WTF_FEATURE)
 /* CPU() - the target CPU architecture */
-#define CPU(WTF_FEATURE) (defined WTF_CPU_##WTF_FEATURE  && WTF_CPU_##WTF_FEATURE)
+//#define CPU(WTF_FEATURE) (defined(WTF_CPU_##WTF_FEATURE)  && WTF_CPU_##WTF_FEATURE)
 /* HAVE() - specific system features (headers, functions or similar) that are present or not */
-#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE  && HAVE_##WTF_FEATURE)
+//#define HAVE(WTF_FEATURE) (defined(HAVE_##WTF_FEATURE)  && HAVE_##WTF_FEATURE)
 /* OS() - underlying operating system; only to be used for mandated low-level services like 
    virtual memory, not to choose a GUI toolkit */
-#define OS(WTF_FEATURE) (defined WTF_OS_##WTF_FEATURE  && WTF_OS_##WTF_FEATURE)
+//#define OS(WTF_FEATURE) (defined(WTF_OS_##WTF_FEATURE)  && WTF_OS_##WTF_FEATURE)
 
 
 /* ==== Policy decision macros: these define policy choices for a particular port. ==== */
 
 /* USE() - use a particular third-party library or optional OS service */
-#define USE(WTF_FEATURE) (defined WTF_USE_##WTF_FEATURE  && WTF_USE_##WTF_FEATURE)
+//#define USE(WTF_FEATURE) (defined(WTF_USE_##WTF_FEATURE)  && WTF_USE_##WTF_FEATURE)
 /* ENABLE() - turn on a specific feature of WebKit */
-#define ENABLE(WTF_FEATURE) (defined ENABLE_##WTF_FEATURE  && ENABLE_##WTF_FEATURE)
+//#define ENABLE(WTF_FEATURE) (defined(ENABLE_##WTF_FEATURE)  && ENABLE_##WTF_FEATURE)
 
 
 
 /* ==== COMPILER() - the compiler being used to build the project ==== */
 
-/* WTF_COMPILER_MSVC Microsoft Visual C++ */
-/* WTF_COMPILER_MSVC7_OR_LOWER Microsoft Visual C++ 2003 or lower*/
-/* WTF_COMPILER_MSVC9_OR_LOWER Microsoft Visual C++ 2008 or lower*/
+/* COMPILER(MSVC) Microsoft Visual C++ */
+/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/
 #if defined(_MSC_VER)
 #define WTF_COMPILER_MSVC 1
 #if _MSC_VER < 1400
-#define WTF_COMPILER_MSVC7_OR_LOWER 1
-#elif _MSC_VER < 1600
-#define WTF_COMPILER_MSVC9_OR_LOWER 1
+#define WTF_COMPILER_MSVC7 1
 #endif
 #endif
 
-/* WTF_COMPILER_RVCT  - ARM RealView Compilation Tools */
-/* WTF_COMPILER_RVCT4_OR_GREATER - ARM RealView Compilation Tools 4.0 or greater */
+/* COMPILER(RVCT)  - ARM RealView Compilation Tools */
 #if defined(__CC_ARM) || defined(__ARMCC__)
 #define WTF_COMPILER_RVCT 1
-#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) (__ARMCC_VERSION >= (major * 100000 + minor * 10000 + patch * 1000 + build))
-#else
-/* Define this for !RVCT compilers, just so we can write things like RVCT_VERSION_AT_LEAST(3, 0, 0, 0). */
-#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) 0
 #endif
 
-/* WTF_COMPILER_GCC - GNU Compiler Collection */
+/* COMPILER(GCC) - GNU Compiler Collection */
 /* --gnu option of the RVCT compiler also defines __GNUC__ */
 #if defined(__GNUC__) && !WTF_COMPILER_RVCT
 #define WTF_COMPILER_GCC 1
 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch))
-#else
-/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */
-#define GCC_VERSION_AT_LEAST(major, minor, patch) 0
 #endif
 
-/* WTF_COMPILER_MINGW - MinGW GCC */
-/* WTF_COMPILER_MINGW64 - mingw-w64 GCC - only used as additional check to exclude mingw.org specific functions */
-#if defined(__MINGW32__)
+/* COMPILER(MINGW) - MinGW GCC */
+#if defined(MINGW) || defined(__MINGW32__)
 #define WTF_COMPILER_MINGW 1
-#include <_mingw.h> /* private MinGW header */
-    #if defined(__MINGW64_VERSION_MAJOR) /* best way to check for mingw-w64 vs mingw.org */
-        #define WTF_COMPILER_MINGW64 1
-    #endif /* __MINGW64_VERSION_MAJOR */
-#endif /* __MINGW32__ */
+#endif
 
-/* WTF_COMPILER_WINSCW - CodeWarrior for Symbian emulator */
+/* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */
 #if defined(__WINSCW__)
 #define WTF_COMPILER_WINSCW 1
-/* cross-compiling, it is not really windows */
-#undef WIN32
-#undef _WIN32
 #endif
 
-/* WTF_COMPILER_INTEL - Intel C++ Compiler */
-#if defined(__INTEL_COMPILER)
-#define WTF_COMPILER_INTEL 1
+/* COMPILER(SUNPRO) - Sun Studio for Solaris */
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#define WTF_COMPILER_SUNPRO 1
 #endif
 
-/* WTF_COMPILER_SUNCC */
-#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
-#define WTF_COMPILER_SUNCC 1
-#endif
 
 /* ==== CPU() - the target CPU architecture ==== */
 
-/* This also defines WTF_CPU_BIG_ENDIAN or WTF_CPU_MIDDLE_ENDIAN or neither, as appropriate. */
+/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */
 
-/* WTF_CPU_ALPHA - DEC Alpha */
+
+/* CPU(ALPHA) - DEC Alpha */
 #if defined(__alpha__)
 #define WTF_CPU_ALPHA 1
 #endif
 
-/* WTF_CPU_IA64 - Itanium / IA-64 */
+/* CPU(IA64) - Itanium / IA-64 */
 #if defined(__ia64__)
 #define WTF_CPU_IA64 1
-/* 32-bit mode on Itanium */
-#if !defined(__LP64__)
-#define WTF_CPU_IA64_32 1
-#endif
 #endif
 
-/* WTF_CPU_MIPS - MIPS 32-bit */
-/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now.  */
-#if (defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_)) \
-    && defined(_ABIO32)
-#define WTF_CPU_MIPS 1
-#if defined(__MIPSEB__)
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-#define WTF_MIPS_PIC (defined __PIC__)
-#define WTF_MIPS_ARCH __mips
-#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v)
-#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v)
-#define WTF_MIPS_ARCH_REV __mips_isa_rev
-#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
-#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float)
-#define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64)
-/* MIPS requires allocators to use aligned memory */
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-#endif /* MIPS */
-
-/* WTF_CPU_PPC - PowerPC 32-bit */
+/* CPU(PPC) - PowerPC 32-bit */
 #if   defined(__ppc__)     \
-    || defined(__PPC__)     \
-    || defined(__powerpc__) \
-    || defined(__powerpc)   \
-    || defined(__POWERPC__) \
-    || defined(_M_PPC)      \
-    || defined(__PPC)
+   || defined(__PPC__)     \
+   || defined(__powerpc__) \
+   || defined(__powerpc)   \
+   || defined(__POWERPC__) \
+   || defined(_M_PPC)      \
+   || defined(__PPC)
 #define WTF_CPU_PPC 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_PPC64 - PowerPC 64-bit */
+/* CPU(PPC64) - PowerPC 64-bit */
 #if   defined(__ppc64__) \
-    || defined(__PPC64__)
+   || defined(__PPC64__)
 #define WTF_CPU_PPC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SH4 - SuperH SH-4 */
+/* CPU(SH4) - SuperH SH-4 */
 #if defined(__SH4__)
 #define WTF_CPU_SH4 1
 #endif
 
-/* WTF_CPU_SPARC32 - SPARC 32-bit */
+/* CPU(SPARC32) - SPARC 32-bit */
 #if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8)
 #define WTF_CPU_SPARC32 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SPARC64 - SPARC 64-bit */
+/* CPU(SPARC64) - SPARC 64-bit */
 #if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)
 #define WTF_CPU_SPARC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SPARC - any SPARC, true for WTF_CPU_SPARC32 and WTF_CPU_SPARC64 */
+/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */
 #if WTF_CPU_SPARC32 || WTF_CPU_SPARC64
 #define WTF_CPU_SPARC 1
 #endif
 
-/* WTF_CPU_S390X - S390 64-bit */
-#if defined(__s390x__)
-#define WTF_CPU_S390X 1
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-
-/* WTF_CPU_S390 - S390 32-bit */
-#if defined(__s390__)
-#define WTF_CPU_S390 1
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-
-/* WTF_CPU_X86 - i386 / x86 32-bit */
+/* CPU(X86) - i386 / x86 32-bit */
 #if   defined(__i386__) \
-    || defined(i386)     \
-    || defined(_M_IX86)  \
-    || defined(_X86_)    \
-    || defined(__THW_INTEL)
+   || defined(i386)     \
+   || defined(_M_IX86)  \
+   || defined(_X86_)    \
+   || defined(__THW_INTEL)
 #define WTF_CPU_X86 1
 #endif
 
-/* WTF_CPU_X86_64 - AMD64 / Intel64 / x86_64 64-bit */
+/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */
 #if   defined(__x86_64__) \
-    || defined(_M_X64)
+   || defined(_M_X64)
 #define WTF_CPU_X86_64 1
 #endif
 
-/* WTF_CPU_ARM - ARM, any version*/
+/* CPU(ARM) - ARM, any version*/
 #if   defined(arm) \
-    || defined(__arm__) \
-    || defined(ARM) \
-    || defined(_ARM_)
+   || defined(__arm__)
 #define WTF_CPU_ARM 1
 
-#if defined(__ARMEB__) || (WTF_COMPILER_RVCT && defined(__BIG_ENDIAN))
+#if defined(__ARMEB__)
 #define WTF_CPU_BIG_ENDIAN 1
 
 #elif !defined(__ARM_EABI__) \
-    && !defined(__EABI__) \
-    && !defined(__VFP_FP__) \
-    && !defined(_WIN32_WCE) \
-    && !defined(ANDROID)
+   && !defined(__EABI__) \
+   && !defined(__VFP_FP__) \
+   && !defined(ANDROID)
 #define WTF_CPU_MIDDLE_ENDIAN 1
 
 #endif
 
-#define WTF_ARM_ARCH_AT_LEAST(N) (CPU(ARM) && WTF_ARM_ARCH_VERSION >= N)
+#define WTF_ARM_ARCH_AT_LEAST(N) (WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= N)
 
 /* Set WTF_ARM_ARCH_VERSION */
 #if   defined(__ARM_ARCH_4__) \
-    || defined(__ARM_ARCH_4T__) \
-    || defined(__MARM_ARMV4__) \
-    || defined(_ARMV4I_)
+   || defined(__ARM_ARCH_4T__) \
+   || defined(__MARM_ARMV4__) \
+   || defined(_ARMV4I_)
 #define WTF_ARM_ARCH_VERSION 4
 
 #elif defined(__ARM_ARCH_5__) \
-    || defined(__ARM_ARCH_5T__) \
-    || defined(__MARM_ARMV5__)
+   || defined(__ARM_ARCH_5T__) \
+   || defined(__ARM_ARCH_5E__) \
+   || defined(__ARM_ARCH_5TE__) \
+   || defined(__ARM_ARCH_5TEJ__) \
+   || defined(__MARM_ARMV5__)
 #define WTF_ARM_ARCH_VERSION 5
 
-#elif defined(__ARM_ARCH_5E__) \
-    || defined(__ARM_ARCH_5TE__) \
-    || defined(__ARM_ARCH_5TEJ__)
-#define WTF_ARM_ARCH_VERSION 5
-/*ARMv5TE requires allocators to use aligned memory*/
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-
 #elif defined(__ARM_ARCH_6__) \
-    || defined(__ARM_ARCH_6J__) \
-    || defined(__ARM_ARCH_6K__) \
-    || defined(__ARM_ARCH_6Z__) \
-    || defined(__ARM_ARCH_6ZK__) \
-    || defined(__ARM_ARCH_6T2__) \
-    || defined(__ARMV6__)
+   || defined(__ARM_ARCH_6J__) \
+   || defined(__ARM_ARCH_6K__) \
+   || defined(__ARM_ARCH_6Z__) \
+   || defined(__ARM_ARCH_6ZK__) \
+   || defined(__ARM_ARCH_6T2__) \
+   || defined(__ARMV6__)
 #define WTF_ARM_ARCH_VERSION 6
 
 #elif defined(__ARM_ARCH_7A__) \
-    || defined(__ARM_ARCH_7R__)
+   || defined(__ARM_ARCH_7R__)
 #define WTF_ARM_ARCH_VERSION 7
 
 /* RVCT sets _TARGET_ARCH_ARM */
 #elif defined(__TARGET_ARCH_ARM)
 #define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM
 
-#if defined(__TARGET_ARCH_5E) \
-    || defined(__TARGET_ARCH_5TE) \
-    || defined(__TARGET_ARCH_5TEJ)
-/*ARMv5TE requires allocators to use aligned memory*/
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-#endif
-
 #else
 #define WTF_ARM_ARCH_VERSION 0
 
@@ -299,22 +237,22 @@
 #define WTF_THUMB_ARCH_VERSION 1
 
 #elif defined(__ARM_ARCH_5T__) \
-    || defined(__ARM_ARCH_5TE__) \
-    || defined(__ARM_ARCH_5TEJ__)
+   || defined(__ARM_ARCH_5TE__) \
+   || defined(__ARM_ARCH_5TEJ__)
 #define WTF_THUMB_ARCH_VERSION 2
 
 #elif defined(__ARM_ARCH_6J__) \
-    || defined(__ARM_ARCH_6K__) \
-    || defined(__ARM_ARCH_6Z__) \
-    || defined(__ARM_ARCH_6ZK__) \
-    || defined(__ARM_ARCH_6M__)
+   || defined(__ARM_ARCH_6K__) \
+   || defined(__ARM_ARCH_6Z__) \
+   || defined(__ARM_ARCH_6ZK__) \
+   || defined(__ARM_ARCH_6M__)
 #define WTF_THUMB_ARCH_VERSION 3
 
 #elif defined(__ARM_ARCH_6T2__) \
-    || defined(__ARM_ARCH_7__) \
-    || defined(__ARM_ARCH_7A__) \
-    || defined(__ARM_ARCH_7R__) \
-    || defined(__ARM_ARCH_7M__)
+   || defined(__ARM_ARCH_7__) \
+   || defined(__ARM_ARCH_7A__) \
+   || defined(__ARM_ARCH_7R__) \
+   || defined(__ARM_ARCH_7M__)
 #define WTF_THUMB_ARCH_VERSION 4
 
 /* RVCT sets __TARGET_ARCH_THUMB */
@@ -326,22 +264,22 @@
 #endif
 
 
-/* WTF_CPU_ARMV5_OR_LOWER - ARM instruction set v5 or earlier */
+/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */
 /* On ARMv5 and below the natural alignment is required. 
    And there are some other differences for v5 or earlier. */
-#if !defined(ARMV5_OR_LOWER) && !WTF_ARM_ARCH_AT_LEAST(6)
+#if !defined(ARMV5_OR_LOWER) /* && !CPU_ARM_ARCH_AT_LEAST(6) */
 #define WTF_CPU_ARMV5_OR_LOWER 1
 #endif
 
 
-/* WTF_CPU_ARM_TRADITIONAL - Thumb2 is not available, only traditional ARM (v4 or greater) */
-/* WTF_CPU_ARM_THUMB2 - Thumb2 instruction set is available */
+/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */
+/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */
 /* Only one of these will be defined. */
 #if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
 #  if defined(thumb2) || defined(__thumb2__) \
-    || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
-#    define WTF_CPU_ARM_TRADITIONAL 0
-#    define WTF_CPU_ARM_THUMB2 1
+  || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
+#    define WTF_CPU_ARM_TRADITIONAL 1
+#    define WTF_CPU_ARM_THUMB2 0
 #  elif WTF_ARM_ARCH_AT_LEAST(4)
 #    define WTF_CPU_ARM_TRADITIONAL 1
 #    define WTF_CPU_ARM_THUMB2 0
@@ -350,36 +288,19 @@
 #  endif
 #elif WTF_CPU_ARM_TRADITIONAL && WTF_CPU_ARM_THUMB2 /* Sanity Check */
 #  error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms"
-#endif /* !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) */
-
-#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON)
-#define WTF_CPU_ARM_NEON 1
-#endif
+#endif // !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
 
 #endif /* ARM */
 
-#if WTF_CPU_ARM || WTF_CPU_MIPS
-#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
-#endif
 
-/* ==== OS() - underlying operating system; only to be used for mandated low-level services like 
-   virtual memory, not to choose a GUI toolkit ==== */
 
-/* WTF_OS_ANDROID - Android */
-#ifdef ANDROID
-#define WTF_OS_ANDROID 1
-#endif
+/* Operating systems - low-level dependencies */
 
-/* WTF_OS_AIX - AIX */
-#ifdef _AIX
-#define WTF_OS_AIX 1
-#endif
-
-/* WTF_OS_DARWIN - Any Darwin-based OS, including Mac OS X and iPhone OS */
+/* PLATFORM(DARWIN) */
+/* Operating system level dependencies for Mac OS X / Darwin that should */
+/* be used regardless of operating environment */
 #ifdef __APPLE__
-#define WTF_OS_DARWIN 1
-
-/* FIXME: BUILDING_ON_.., and TARGETING... macros should be folded into the OS() system */
+#define WTF_PLATFORM_DARWIN 1
 #include 
 #if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
 #define BUILDING_ON_TIGER 1
@@ -396,97 +317,98 @@
 #define TARGETING_SNOW_LEOPARD 1
 #endif
 #include 
-
 #endif
 
-/* WTF_OS_IOS - iOS */
-/* WTF_OS_MAC_OS_X - Mac OS X (not including iOS) */
-#if WTF_OS_DARWIN && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED)  \
-    || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)                   \
-    || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR))
-#define WTF_OS_IOS 1
-#elif WTF_OS_DARWIN && defined(TARGET_OS_MAC) && TARGET_OS_MAC
-#define WTF_OS_MAC_OS_X 1
-#endif
-
-/* WTF_OS_FREEBSD - FreeBSD */
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#define WTF_OS_FREEBSD 1
-#endif
-
-/* WTF_OS_HAIKU - Haiku */
-#ifdef __HAIKU__
-#define WTF_OS_HAIKU 1
-#endif
-
-/* WTF_OS_LINUX - Linux */
-#ifdef __linux__
-#define WTF_OS_LINUX 1
-#endif
-
-/* WTF_OS_NETBSD - NetBSD */
-#if defined(__NetBSD__)
-#define WTF_OS_NETBSD 1
-#endif
-
-/* WTF_OS_OPENBSD - OpenBSD */
-#ifdef __OpenBSD__
-#define WTF_OS_OPENBSD 1
-#endif
-
-/* WTF_OS_QNX - QNX */
-#if defined(__QNXNTO__)
-#define WTF_OS_QNX 1
-#endif
-
-/* WTF_OS_SOLARIS - Solaris */
-#if defined(sun) || defined(__sun)
-#define WTF_OS_SOLARIS 1
-#endif
-
-/* WTF_OS_WINCE - Windows CE; note that for this platform WTF_OS_WINDOWS is also defined */
-#if defined(_WIN32_WCE)
-#define WTF_OS_WINCE 1
-#endif
-
-/* WTF_OS_WINDOWS - Any version of Windows */
+/* PLATFORM(WIN_OS) */
+/* Operating system level dependencies for Windows that should be used */
+/* regardless of operating environment */
 #if defined(WIN32) || defined(_WIN32)
-#define WTF_OS_WINDOWS 1
+#define WTF_PLATFORM_WIN_OS 1
+#endif
+
+/* PLATFORM(LINUX) */
+/* Operating system level dependencies for Linux-like systems that */
+/* should be used regardless of operating environment */
+#ifdef __linux__
+#define WTF_PLATFORM_LINUX 1
+#endif
+
+/* PLATFORM(FREEBSD) */
+/* Operating system level dependencies for FreeBSD-like systems that */
+/* should be used regardless of operating environment */
+#ifdef __FreeBSD__
+#define WTF_PLATFORM_FREEBSD 1
+#endif
+
+/* PLATFORM(OPENBSD) */
+/* Operating system level dependencies for OpenBSD systems that */
+/* should be used regardless of operating environment */
+#ifdef __OpenBSD__
+#define WTF_PLATFORM_OPENBSD 1
+#endif
+
+/* PLATFORM(SOLARIS) */
+/* Operating system level dependencies for Solaris that should be used */
+/* regardless of operating environment */
+#if defined(sun) || defined(__sun)
+#define WTF_PLATFORM_SOLARIS 1
+#endif
+
+/* PLATFORM(OS2) */
+/* Operating system level dependencies for OS/2 that should be used */
+/* regardless of operating environment */
+#if defined(OS2) || defined(__OS2__)
+#define WTF_PLATFORM_OS2 1
 #endif
 
-/* WTF_OS_SYMBIAN - Symbian */
 #if defined (__SYMBIAN32__)
-#define WTF_OS_SYMBIAN 1
+/* we are cross-compiling, it is not really windows */
+#undef WTF_PLATFORM_WIN_OS
+#undef WTF_PLATFORM_WIN
+#define WTF_PLATFORM_SYMBIAN 1
 #endif
 
-/* WTF_OS_UNIX - Any Unix-like system */
-#if   WTF_OS_AIX              \
-    || WTF_OS_ANDROID          \
-    || WTF_OS_DARWIN           \
-    || WTF_OS_FREEBSD          \
-    || WTF_OS_HAIKU            \
-    || WTF_OS_LINUX            \
-    || WTF_OS_NETBSD           \
-    || WTF_OS_OPENBSD          \
-    || WTF_OS_QNX              \
-    || WTF_OS_SOLARIS          \
-    || WTF_OS_SYMBIAN          \
-    || defined(unix)        \
-    || defined(__unix)      \
-    || defined(__unix__)
-#define WTF_OS_UNIX 1
+
+/* PLATFORM(NETBSD) */
+/* Operating system level dependencies for NetBSD that should be used */
+/* regardless of operating environment */
+#if defined(__NetBSD__)
+#define WTF_PLATFORM_NETBSD 1
+#endif
+
+/* PLATFORM(QNX) */
+/* Operating system level dependencies for QNX that should be used */
+/* regardless of operating environment */
+#if defined(__QNXNTO__)
+#define WTF_PLATFORM_QNX 1
+#endif
+
+/* PLATFORM(UNIX) */
+/* Operating system level dependencies for Unix-like systems that */
+/* should be used regardless of operating environment */
+#if   WTF_PLATFORM_DARWIN     \
+   || WTF_PLATFORM_FREEBSD    \
+   || WTF_PLATFORM_SYMBIAN    \
+   || WTF_PLATFORM_NETBSD     \
+   || defined(unix)        \
+   || defined(__unix)      \
+   || defined(__unix__)    \
+   || defined(_AIX)        \
+   || defined(__HAIKU__)   \
+   || defined(__QNXNTO__)  \
+   || defined(ANDROID)
+#define WTF_PLATFORM_UNIX 1
 #endif
 
 /* Operating environments */
 
-/* FIXME: these are all mixes of OS, operating environment and policy choices. */
-/* WTF_PLATFORM_CHROMIUM */
-/* WTF_PLATFORM_QT */
-/* WTF_PLATFORM_WX */
-/* WTF_PLATFORM_GTK */
-/* WTF_PLATFORM_HAIKU */
-/* WTF_PLATFORM_MAC */
-/* WTF_PLATFORM_WIN */
+/* PLATFORM(CHROMIUM) */
+/* PLATFORM(QT) */
+/* PLATFORM(WX) */
+/* PLATFORM(GTK) */
+/* PLATFORM(HAIKU) */
+/* PLATFORM(MAC) */
+/* PLATFORM(WIN) */
 #if defined(BUILDING_CHROMIUM__)
 #define WTF_PLATFORM_CHROMIUM 1
 #elif defined(BUILDING_QT__)
@@ -497,229 +419,142 @@
 #define WTF_PLATFORM_GTK 1
 #elif defined(BUILDING_HAIKU__)
 #define WTF_PLATFORM_HAIKU 1
-#elif defined(BUILDING_BREWMP__)
-#define WTF_PLATFORM_BREWMP 1
-#if defined(AEE_SIMULATOR)
-#define WTF_PLATFORM_BREWMP_SIMULATOR 1
-#else
-#define WTF_PLATFORM_BREWMP_SIMULATOR 0
-#endif
-#undef WTF_OS_WINDOWS
-#undef WTF_PLATFORM_WIN
-#elif WTF_OS_DARWIN
+#elif WTF_PLATFORM_DARWIN
 #define WTF_PLATFORM_MAC 1
-#elif WTF_OS_WINDOWS
+#elif WTF_PLATFORM_WIN_OS
 #define WTF_PLATFORM_WIN 1
 #endif
 
-/* WTF_PLATFORM_IOS */
-/* FIXME: this is sometimes used as an OS switch and sometimes for higher-level things */
+/* PLATFORM(IPHONE) */
 #if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
-#define WTF_PLATFORM_IOS 1
+#define WTF_PLATFORM_IPHONE 1
 #endif
 
-/* WTF_PLATFORM_IOS_SIMULATOR */
+/* PLATFORM(IPHONE_SIMULATOR) */
 #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
-#define WTF_PLATFORM_IOS 1
-#define WTF_PLATFORM_IOS_SIMULATOR 1
+#define WTF_PLATFORM_IPHONE 1
+#define WTF_PLATFORM_IPHONE_SIMULATOR 1
 #else
-#define WTF_PLATFORM_IOS_SIMULATOR 0
+#define WTF_PLATFORM_IPHONE_SIMULATOR 0
 #endif
 
-#if !defined(WTF_PLATFORM_IOS)
-#define WTF_PLATFORM_IOS 0
+#if !defined(WTF_PLATFORM_IPHONE)
+#define WTF_PLATFORM_IPHONE 0
 #endif
 
-/* WTF_PLATFORM_ANDROID */
-/* FIXME: this is sometimes used as an OS() switch, and other times to drive
-   policy choices */
+/* PLATFORM(ANDROID) */
 #if defined(ANDROID)
 #define WTF_PLATFORM_ANDROID 1
 #endif
 
 /* Graphics engines */
 
-/* WTF_USE_CG and WTF_PLATFORM_CI */
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS
-#define WTF_USE_CG 1
+/* PLATFORM(CG) and PLATFORM(CI) */
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CG 1
 #endif
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS || (WTF_PLATFORM_WIN && WTF_USE_CG)
-#define WTF_USE_CA 1
+#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CI 1
 #endif
 
-/* WTF_USE_SKIA for Win/Linux, CG for Mac */
+/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */
 #if WTF_PLATFORM_CHROMIUM
-#if WTF_OS_DARWIN
-#define WTF_USE_CG 1
+#if WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CG 1
+#define WTF_PLATFORM_CI 1
 #define WTF_USE_ATSUI 1
 #define WTF_USE_CORE_TEXT 1
-#define WTF_USE_ICCJPEG 1
 #else
-#define WTF_USE_SKIA 1
-#define WTF_USE_CHROMIUM_NET 1
+#define WTF_PLATFORM_SKIA 1
 #endif
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define WTF_USE_SKIA 1
-#endif
-
 #if WTF_PLATFORM_GTK
-#define WTF_USE_CAIRO 1
+#define WTF_PLATFORM_CAIRO 1
 #endif
 
 
-#if WTF_OS_WINCE
-#include 
-#define WTF_USE_MERSENNE_TWISTER_19937 1
-#endif
-
-#if WTF_PLATFORM_QT && WTF_OS_UNIX && !WTF_OS_SYMBIAN && !WTF_OS_DARWIN
-#define WTF_USE_PTHREAD_BASED_QT 1
-#endif
-
-#if (WTF_PLATFORM_GTK || WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || (WTF_PLATFORM_QT && (WTF_OS_DARWIN || WTF_USE_PTHREAD_BASED_QT) && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
+#if (WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_OS2 || (WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
 #define ENABLE_JSC_MULTIPLE_THREADS 1
 #endif
 
-#if ENABLE_JSC_MULTIPLE_THREADS
-#define ENABLE_WTF_MULTIPLE_THREADS 1
-#endif
-
 /* On Windows, use QueryPerformanceCounter by default */
-#if WTF_OS_WINDOWS
+#if WTF_PLATFORM_WIN_OS
 #define WTF_USE_QUERY_PERFORMANCE_COUNTER  1
 #endif
 
-#if WTF_OS_WINCE && !WTF_PLATFORM_QT
-#define NOMINMAX       /* Windows min and max conflict with standard macros */
-#define NOSHLWAPI      /* shlwapi.h not available on WinCe */
-
-/* MSDN documentation says these functions are provided with uspce.lib.  But we cannot find this file. */
-#define __usp10__      /* disable "usp10.h" */
-
-#define _INC_ASSERT    /* disable "assert.h" */
-#define assert(x)
-
-#endif  /* WTF_OS_WINCE && !WTF_PLATFORM_QT */
-
 #if WTF_PLATFORM_QT
 #define WTF_USE_QT4_UNICODE 1
-#elif WTF_OS_WINCE
-#define WTF_USE_WINCE_UNICODE 1
-#elif WTF_PLATFORM_BREWMP
-#define WTF_USE_BREWMP_UNICODE 1
 #elif WTF_PLATFORM_GTK
 /* The GTK+ Unicode backend is configurable */
 #else
 #define WTF_USE_ICU_UNICODE 1
 #endif
 
-#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS
+#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CF 1
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && WTF_CPU_X86_64
 #define WTF_USE_PLUGIN_HOST_PROCESS 1
 #endif
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-#define ENABLE_GESTURE_EVENTS 1
-#define ENABLE_RUBBER_BANDING 1
-#define WTF_USE_WK_SCROLLBAR_PAINTER 1
-#endif
-#if !defined(ENABLE_JAVA_BRIDGE)
-#define ENABLE_JAVA_BRIDGE 1
+#if !defined(ENABLE_MAC_JAVA_BRIDGE)
+#define ENABLE_MAC_JAVA_BRIDGE 1
 #endif
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 1
 #endif
-#define WTF_USE_CF 1
-#define WTF_USE_PTHREADS 1
-#define HAVE_PTHREAD_RWLOCK 1
 #define HAVE_READLINE 1
 #define HAVE_RUNLOOP_TIMER 1
-#define ENABLE_FULLSCREEN_API 1
-#define ENABLE_SMOOTH_SCROLLING 1
-#define ENABLE_WEB_ARCHIVE 1
-#endif /* WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS */
+#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */
 
-#if WTF_PLATFORM_CHROMIUM && WTF_OS_DARWIN
-#define WTF_USE_CF 1
+#if WTF_PLATFORM_CHROMIUM && WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define ENABLE_SINGLE_THREADED 1
+#if WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #endif
 
-#if WTF_PLATFORM_QT && WTF_OS_DARWIN
-#define WTF_USE_CF 1
-#endif
-
-#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER) && !WTF_PLATFORM_GTK && !WTF_PLATFORM_QT
-#define ENABLE_PURGEABLE_MEMORY 1
-#endif
-
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define ENABLE_CONTEXT_MENUS 0
 #define ENABLE_DRAG_SUPPORT 0
-#define ENABLE_DATA_TRANSFER_ITEMS 0
 #define ENABLE_FTPDIR 1
 #define ENABLE_GEOLOCATION 1
 #define ENABLE_ICONDATABASE 0
 #define ENABLE_INSPECTOR 0
-#define ENABLE_JAVA_BRIDGE 0
+#define ENABLE_MAC_JAVA_BRIDGE 0
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #define ENABLE_ORIENTATION_EVENTS 1
 #define ENABLE_REPAINT_THROTTLING 1
 #define HAVE_READLINE 1
-#define WTF_USE_CF 1
+#define WTF_PLATFORM_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
-#define ENABLE_WEB_ARCHIVE 1
 #endif
 
 #if WTF_PLATFORM_ANDROID
 #define WTF_USE_PTHREADS 1
+#define WTF_PLATFORM_SGL 1
 #define USE_SYSTEM_MALLOC 1
-#define ENABLE_JAVA_BRIDGE 1
+#define ENABLE_MAC_JAVA_BRIDGE 1
 #define LOG_DISABLED 1
-/* Prevents Webkit from drawing the caret in textfields and textareas
-   This prevents unnecessary invals. */
+// Prevents Webkit from drawing the caret in textfields and textareas
+// This prevents unnecessary invals.
 #define ENABLE_TEXT_CARET 1
 #define ENABLE_JAVASCRIPT_DEBUGGER 0
-#if !defined(ENABLE_JIT) && !ENABLE_ANDROID_JSC_JIT
-#define ENABLE_JIT 0
-#endif
 #endif
 
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE
-#define WTF_USE_CF 1
-#define WTF_USE_PTHREADS 0
-#endif
-
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !defined(WIN_CAIRO)
-#define WTF_USE_CFNETWORK 1
-#endif
-
-#if WTF_USE_CFNETWORK || WTF_PLATFORM_MAC
-#define WTF_USE_CFURLCACHE 1
-#define WTF_USE_CFURLSTORAGESESSIONS 1
-#endif
-
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !WTF_PLATFORM_QT
-#define ENABLE_WEB_ARCHIVE 1
+#if WTF_PLATFORM_WIN
+#define WTF_USE_WININET 1
 #endif
 
 #if WTF_PLATFORM_WX
 #define ENABLE_ASSEMBLER 1
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
-#if WTF_OS_DARWIN
-#define WTF_USE_CF 1
-#ifndef BUILDING_ON_TIGER
-#define WTF_USE_CORE_TEXT 1
-#define ENABLE_WEB_ARCHIVE 1
-#else
-#define WTF_USE_ATSUI 1
-#endif
+#if WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #endif
 #endif
 
@@ -739,39 +574,25 @@
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define USE_SYSTEM_MALLOC 1
-#endif
-
-#if WTF_PLATFORM_BREWMP_SIMULATOR
-#define ENABLE_JIT 0
-#endif
-
 #if !defined(HAVE_ACCESSIBILITY)
-#if WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
+#if WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
 #define HAVE_ACCESSIBILITY 1
 #endif
 #endif /* !defined(HAVE_ACCESSIBILITY) */
 
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
+#if WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
 #define HAVE_SIGNAL_H 1
 #endif
 
-#if !defined(HAVE_STRNSTR)
-#if WTF_OS_DARWIN || WTF_OS_FREEBSD
-#define HAVE_STRNSTR 1
-#endif
-#endif
-
-#if !WTF_OS_WINDOWS && !WTF_OS_SOLARIS && !WTF_OS_QNX \
-    && !WTF_OS_SYMBIAN && !WTF_OS_HAIKU && !WTF_OS_RVCT \
-    && !WTF_OS_ANDROID && !WTF_PLATFORM_BREWMP
+#if !WTF_PLATFORM_WIN_OS && !WTF_PLATFORM_SOLARIS && !WTF_PLATFORM_QNX \
+    && !WTF_PLATFORM_SYMBIAN && !WTF_PLATFORM_HAIKU && !WTF_COMPILER_RVCT \
+    && !WTF_PLATFORM_ANDROID && !WTF_PLATFORM_OS2
 #define HAVE_TM_GMTOFF 1
 #define HAVE_TM_ZONE 1
 #define HAVE_TIMEGM 1
-#endif
+#endif     
 
-#if WTF_OS_DARWIN
+#if WTF_PLATFORM_DARWIN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 1
@@ -782,37 +603,23 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 #define HAVE_SYS_TIMEB_H 1
-#define WTF_USE_ACCELERATE 1
 
-#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD)
-
-#define HAVE_DISPATCH_H 1
-#define HAVE_HOSTED_CORE_ANIMATION 1
-
-#if !WTF_PLATFORM_IOS
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !WTF_PLATFORM_IPHONE && !WTF_PLATFORM_QT
 #define HAVE_MADV_FREE_REUSE 1
 #define HAVE_MADV_FREE 1
 #define HAVE_PTHREAD_SETNAME_NP 1
 #endif
 
-#endif
-
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define HAVE_MADV_FREE 1
 #endif
 
-#elif WTF_OS_WINDOWS
+#elif WTF_PLATFORM_WIN_OS
 
-#if WTF_OS_WINCE
-#define HAVE_ERRNO_H 0
-#else
 #define HAVE_SYS_TIMEB_H 1
-#define HAVE_ALIGNED_MALLOC 1
-#define HAVE_ISDEBUGGERPRESENT 1
-#endif
 #define HAVE_VIRTUALALLOC 1
 
-#elif WTF_OS_SYMBIAN
+#elif WTF_PLATFORM_SYMBIAN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 0
@@ -825,11 +632,7 @@
 #define HAVE_SYS_PARAM_H 1
 #endif
 
-#elif WTF_PLATFORM_BREWMP
-
-#define HAVE_ERRNO_H 1
-
-#elif WTF_OS_QNX
+#elif WTF_PLATFORM_QNX
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 1
@@ -838,7 +641,7 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
-#elif WTF_OS_ANDROID
+#elif WTF_PLATFORM_ANDROID
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 0
@@ -848,13 +651,23 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
+#elif WTF_PLATFORM_OS2
+
+#define HAVE_MMAP 1
+#define ENABLE_ASSEMBLER 1
+#define HAVE_ERRNO_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIMEB_H 1
+
 #else
 
 /* FIXME: is this actually used or do other platforms generate their own config.h? */
 
 #define HAVE_ERRNO_H 1
 /* As long as Haiku doesn't have a complete support of locale this will be disabled. */
-#if !WTF_OS_HAIKU
+#if !WTF_PLATFORM_HAIKU
 #define HAVE_LANGINFO_H 1
 #endif
 #define HAVE_MMAP 1
@@ -867,14 +680,6 @@
 
 /* ENABLE macro defaults */
 
-#if WTF_PLATFORM_QT
-/* We must not customize the global operator new and delete for the Qt port. */
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
-#if !WTF_OS_UNIX || WTF_OS_SYMBIAN
-#define USE_SYSTEM_MALLOC 1
-#endif
-#endif
-
 /* fastMalloc match validation allows for runtime verification that
    new is matched by delete, fastMalloc is matched by fastFree, etc. */
 #if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION)
@@ -905,10 +710,6 @@
 #define ENABLE_DRAG_SUPPORT 1
 #endif
 
-#if !defined(ENABLE_DATA_TRANSFER_ITEMS)
-#define ENABLE_DATA_TRANSFER_ITEMS 0
-#endif
-
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 0
 #endif
@@ -917,22 +718,14 @@
 #define ENABLE_INSPECTOR 1
 #endif
 
-#if !defined(ENABLE_JAVA_BRIDGE)
-#define ENABLE_JAVA_BRIDGE 0
+#if !defined(ENABLE_MAC_JAVA_BRIDGE)
+#define ENABLE_MAC_JAVA_BRIDGE 0
 #endif
 
 #if !defined(ENABLE_NETSCAPE_PLUGIN_API)
 #define ENABLE_NETSCAPE_PLUGIN_API 1
 #endif
 
-#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE)
-#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0
-#endif
-
-#if !defined(ENABLE_PURGEABLE_MEMORY)
-#define ENABLE_PURGEABLE_MEMORY 0
-#endif
-
 #if !defined(WTF_USE_PLUGIN_HOST_PROCESS)
 #define WTF_USE_PLUGIN_HOST_PROCESS 0
 #endif
@@ -945,11 +738,6 @@
 #define ENABLE_OPCODE_STATS 0
 #endif
 
-#if !defined(ENABLE_GLOBAL_FASTMALLOC_NEW)
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 1
-#endif
-
-#define ENABLE_DEBUG_WITH_BREAKPOINT 0
 #define ENABLE_SAMPLING_COUNTERS 0
 #define ENABLE_SAMPLING_FLAGS 0
 #define ENABLE_OPCODE_SAMPLING 0
@@ -965,18 +753,10 @@
 #define ENABLE_GEOLOCATION 0
 #endif
 
-#if !defined(ENABLE_GESTURE_RECOGNIZER)
-#define ENABLE_GESTURE_RECOGNIZER 0
-#endif
-
 #if !defined(ENABLE_NOTIFICATIONS)
 #define ENABLE_NOTIFICATIONS 0
 #endif
 
-#if WTF_PLATFORM_IOS
-#define ENABLE_TEXT_CARET 0
-#endif
-
 #if !defined(ENABLE_TEXT_CARET)
 #define ENABLE_TEXT_CARET 1
 #endif
@@ -985,88 +765,80 @@
 #define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0
 #endif
 
-#if !defined(ENABLE_FULLSCREEN_API)
-#define ENABLE_FULLSCREEN_API 0
-#endif
-
-#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64)
-#if (WTF_CPU_X86_64 && (WTF_OS_UNIX || WTF_OS_WINDOWS)) \
-    || (WTF_CPU_IA64 && !WTF_CPU_IA64_32) \
-    || WTF_CPU_ALPHA \
-    || WTF_CPU_SPARC64 \
-    || WTF_CPU_S390X \
-    || WTF_CPU_PPC64
+#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
+#if (WTF_CPU_X86_64 && (WTF_PLATFORM_UNIX || WTF_PLATFORM_WIN_OS)) || WTF_CPU_IA64 || WTF_CPU_ALPHA
 #define WTF_USE_JSVALUE64 1
+#elif WTF_CPU_ARM || WTF_CPU_PPC64
+#define WTF_USE_JSVALUE32 1
+#elif WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW
+/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
+on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
+#define WTF_USE_JSVALUE32 1
 #else
 #define WTF_USE_JSVALUE32_64 1
 #endif
-#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */
+#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */
 
 #if !defined(ENABLE_REPAINT_THROTTLING)
 #define ENABLE_REPAINT_THROTTLING 0
 #endif
 
-/* Disable the JIT on versions of GCC prior to 4.1 */
-#if !defined(ENABLE_JIT) && WTF_COMPILER_GCC && !GCC_VERSION_AT_LEAST(4, 1, 0)
-#define ENABLE_JIT 0
+#if !defined(ENABLE_JIT)
+
+/* The JIT is tested & working on x86_64 Mac */
+#if WTF_CPU_X86_64 && WTF_PLATFORM_MAC
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 Mac */
+#elif WTF_CPU_X86 && WTF_PLATFORM_MAC
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 OS/2 */
+#elif WTF_CPU_X86 && WTF_PLATFORM_OS2
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 Windows */
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN
+    #define ENABLE_JIT 1
+#elif WTF_CPU_SPARC
+    #define ENABLE_JIT 1
 #endif
 
-/* JIT is not implemented for 64 bit on MSVC */
-#if !defined(ENABLE_JIT) && WTF_COMPILER_MSVC && WTF_CPU_X86_64
-#define ENABLE_JIT 0
+#if WTF_PLATFORM_QT
+#if WTF_CPU_X86_64 && WTF_PLATFORM_DARWIN
+    #define ENABLE_JIT 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_DARWIN
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX
+    #define ENABLE_JIT 1
 #endif
+#endif /* PLATFORM(QT) */
 
-/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */
-#if !defined(ENABLE_JIT) \
-    && (WTF_CPU_X86 || WTF_CPU_X86_64 || WTF_CPU_ARM || WTF_CPU_MIPS) \
-    && (WTF_OS_DARWIN || !WTF_COMPILER_GCC || GCC_VERSION_AT_LEAST(4, 1, 0)) \
-    && !WTF_OS_WINCE
-#define ENABLE_JIT 1
-#endif
+#endif /* !defined(ENABLE_JIT) */
 
-/* Currently only implemented for JSVALUE64, only tested on WTF_PLATFORM_MAC */
-#if ENABLE_JIT && WTF_USE_JSVALUE64 && WTF_PLATFORM_MAC
-#define ENABLE_DFG_JIT 1
-/* Enabled with restrictions to circumvent known performance regressions. */
-#define ENABLE_DFG_JIT_RESTRICTIONS 1
-#endif
-
-/* Ensure that either the JIT or the interpreter has been enabled. */
-#if !defined(ENABLE_INTERPRETER) && !ENABLE_JIT
-#define ENABLE_INTERPRETER 1
-#endif
-#if !(ENABLE_JIT || ENABLE_INTERPRETER)
-#error You have to have at least one execution model enabled to build JSC
-#endif
-
-#if WTF_CPU_SH4 && WTF_PLATFORM_QT
-#define ENABLE_JIT 1
-#define ENABLE_YARR 1
-#define ENABLE_YARR_JIT 1
-#define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
-#define ENABLE_ASSEMBLER 1
-#endif
-
-/* Configure the JIT */
 #if ENABLE_JIT
-    #if WTF_CPU_ARM
-    #if !defined(ENABLE_JIT_USE_SOFT_MODULO) && WTF_ARM_ARCH_AT_LEAST(5)
-    #define ENABLE_JIT_USE_SOFT_MODULO 1
-    #endif
-    #endif
-
-    #ifndef ENABLE_JIT_OPTIMIZE_CALL
-    #define ENABLE_JIT_OPTIMIZE_CALL 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
-    #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
-    #define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
-    #define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
-    #endif
+#ifndef ENABLE_JIT_OPTIMIZE_CALL
+#define ENABLE_JIT_OPTIMIZE_CALL 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
+#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
+#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
+#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
+#endif
 #endif
 
 #if WTF_CPU_X86 && WTF_COMPILER_MSVC
@@ -1077,89 +849,80 @@
 #define JSC_HOST_CALL
 #endif
 
-/* Configure the interpreter */
-#if WTF_COMPILER_GCC || (RVCT_VERSION_AT_LEAST(4, 0, 0, 0) && defined(__GNUC__))
+#if WTF_COMPILER_GCC && !ENABLE_JIT
 #define HAVE_COMPUTED_GOTO 1
 #endif
-#if HAVE_COMPUTED_GOTO && ENABLE_INTERPRETER
-#define ENABLE_COMPUTED_GOTO_INTERPRETER 1
+
+#if ENABLE_JIT && defined(COVERAGE)
+    #define WTF_USE_INTERPRETER 0
+#else
+    #define WTF_USE_INTERPRETER 1
 #endif
 
-/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc.  Results dumped at exit */
-#define ENABLE_REGEXP_TRACING 0
+/* Yet Another Regex Runtime. */
+#if !defined(ENABLE_YARR_JIT)
 
-/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */
-#if WTF_PLATFORM_CHROMIUM
-#define ENABLE_YARR_JIT 0
-
-#elif ENABLE_JIT && !defined(ENABLE_YARR_JIT)
+/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */
+#if (WTF_CPU_X86 \
+ || WTF_CPU_X86_64 \
+ || WTF_CPU_SPARC \
+ || WTF_CPU_ARM_TRADITIONAL \
+ || WTF_CPU_ARM_THUMB2 \
+ || WTF_CPU_X86)
 #define ENABLE_YARR_JIT 1
-
-/* Setting this flag compares JIT results with interpreter results. */
-#define ENABLE_YARR_JIT_DEBUG 0
+#else
+#define ENABLE_YARR_JIT 0
 #endif
 
-#if ENABLE_JIT || ENABLE_YARR_JIT
+#endif /* !defined(ENABLE_YARR_JIT) */
+
+#if (ENABLE_JIT || ENABLE_YARR_JIT)
 #define ENABLE_ASSEMBLER 1
 #endif
 /* Setting this flag prevents the assembler from using RWX memory; this may improve
    security but currectly comes at a significant performance cost. */
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1
-#endif
-
-/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in.
-   On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */
-#if ENABLE_ASSEMBLER
-#if WTF_CPU_X86_64
-#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1
 #else
-#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1
-#endif
+#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0
 #endif
 
-#if !defined(ENABLE_PAN_SCROLLING) && WTF_OS_WINDOWS
+#if !defined(ENABLE_PAN_SCROLLING) && WTF_PLATFORM_WIN_OS
 #define ENABLE_PAN_SCROLLING 1
 #endif
 
-#if !defined(ENABLE_SMOOTH_SCROLLING)
-#define ENABLE_SMOOTH_SCROLLING 0
-#endif
-
-#if !defined(ENABLE_WEB_ARCHIVE)
-#define ENABLE_WEB_ARCHIVE 0
-#endif
-
-/* Use the QXmlStreamReader implementation for XMLDocumentParser */
+/* Use the QXmlStreamReader implementation for XMLTokenizer */
 /* Use the QXmlQuery implementation for XSLTProcessor */
 #if WTF_PLATFORM_QT
 #define WTF_USE_QXMLSTREAM 1
 #define WTF_USE_QXMLQUERY 1
 #endif
 
-#if WTF_PLATFORM_MAC
-/* Complex text framework */
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
-#define WTF_USE_ATSUI 0
-#define WTF_USE_CORE_TEXT 1
-#else
-#define WTF_USE_ATSUI 1
-#define WTF_USE_CORE_TEXT 0
-#endif
+#if !WTF_PLATFORM_QT
+#define WTF_USE_FONT_FAST_PATH 1
 #endif
 
 /* Accelerated compositing */
-#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER)) || WTF_PLATFORM_IOS || WTF_PLATFORM_QT || (WTF_PLATFORM_WIN && !WTF_OS_WINCE &&!defined(WIN_CAIRO))
+#if WTF_PLATFORM_MAC
+#if !defined(BUILDING_ON_TIGER)
+#define WTF_USE_ACCELERATED_COMPOSITING 1
+#endif
+#endif
+
+#if WTF_PLATFORM_IPHONE
 #define WTF_USE_ACCELERATED_COMPOSITING 1
 #endif
 
-#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || WTF_PLATFORM_IOS
-#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1
-#endif
-
-#if WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-#define WTF_USE_AVFOUNDATION 1
-#endif
+/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with
+   with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and
+   off in one place. */
+//#if WTF_PLATFORM_WIN
+//#include "QuartzCorePresent.h"
+//#if QUARTZCORE_PRESENT
+//#define WTF_USE_ACCELERATED_COMPOSITING 1
+//#define ENABLE_3D_RENDERING 1
+//#endif
+//#endif
 
 #if WTF_COMPILER_GCC
 #define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result))
@@ -1167,7 +930,7 @@
 #define WARN_UNUSED_RETURN
 #endif
 
-#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_OS_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
+#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_PLATFORM_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
 #define ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH 1
 #endif
 
@@ -1176,46 +939,4 @@
 
 #define ENABLE_JSC_ZOMBIES 0
 
-/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_QT
-#define WTF_USE_PLATFORM_STRATEGIES 1
-#endif
-
-#if WTF_PLATFORM_WIN
-#define WTF_USE_CROSS_PLATFORM_CONTEXT_MENUS 1
-#endif
-
-/* Geolocation request policy. pre-emptive policy is to acquire user permission before acquiring location.
-   Client based implementations will have option to choose between pre-emptive and nonpre-emptive permission policy.
-   pre-emptive permission policy is enabled by default for all client-based implementations. */
-#if ENABLE_CLIENT_BASED_GEOLOCATION
-#define WTF_USE_PREEMPT_GEOLOCATION_PERMISSION 1
-#endif
-
-#if WTF_CPU_ARM_THUMB2
-#define ENABLE_BRANCH_COMPACTION 1
-#endif
-
-#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
-#define ENABLE_THREADING_OPENMP 1
-#endif
-
-#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE_SINGLE_THREADED && (ENABLE_THREADING_GENERIC || ENABLE_THREADING_LIBDISPATCH || ENABLE_THREADING_OPENMP)
-#define ENABLE_PARALLEL_JOBS 1
-#endif
-
-#if ENABLE_GLIB_SUPPORT
-#include "GTypedefs.h"
-#endif
-
-/* FIXME: This define won't be needed once #27551 is fully landed. However, 
-   since most ports try to support sub-project independence, adding new headers
-   to WTF causes many ports to break, and so this way we can address the build
-   breakages one port at a time. */
-#define WTF_USE_EXPORT_MACROS 0
-
-#if WTF_PLATFORM_QT || WTF_PLATFORM_GTK
-#define WTF_USE_UNIX_DOMAIN_SOCKETS 1
-#endif
-
 #endif /* WTF_Platform_h */
diff --git a/js/src/jit-test/tests/basic/bug632964-regexp.js b/js/src/jit-test/tests/basic/bug632964-regexp.js
index 75612dbc735d..7151d3713647 100644
--- a/js/src/jit-test/tests/basic/bug632964-regexp.js
+++ b/js/src/jit-test/tests/basic/bug632964-regexp.js
@@ -1,3 +1,5 @@
+// |jit-test| error: InternalError: regular expression too complex
+
 var sText = "s";
 
 for (var i = 0; i < 250000; ++i)
@@ -10,5 +12,6 @@ var match = sText.match(/s(\s|.)*?e/gi);
 //var match = sText.match(/s([\s\S]*?)e/gi);
 //var match = sText.match(/s(?:[\s\S]*?)e/gi);
 var end = new Date();
+print(end - start);
 
 assertEq(match.length, 1);
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index c88fae9fdaf0..ecc336cdc4c3 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -48,7 +48,6 @@
 #include "jstracer.h"
 #include "jswrapper.h"
 #include "assembler/wtf/Platform.h"
-#include "yarr/BumpPointerAllocator.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
@@ -74,9 +73,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     active(false),
 #ifdef JS_METHODJIT
     jaegerCompartment(NULL),
-#endif
-#if ENABLE_YARR_JIT
-    regExpAllocator(NULL),
 #endif
     propertyTree(thisForCtor()),
     emptyArgumentsShape(NULL),
@@ -88,6 +84,9 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     initialRegExpShape(NULL),
     initialStringShape(NULL),
     debugMode(rt->debugMode),
+#if ENABLE_YARR_JIT
+    regExpAllocator(NULL),
+#endif
     mathCache(NULL)
 {
     JS_INIT_CLIST(&scripts);
@@ -136,9 +135,11 @@ JSCompartment::init()
         return false;
 #endif
 
-    regExpAllocator = rt->new_();
+#if ENABLE_YARR_JIT
+    regExpAllocator = rt->new_();
     if (!regExpAllocator)
         return false;
+#endif
 
     if (!backEdgeTable.init())
         return false;
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 8827a275f796..5b3f16643050 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -54,8 +54,11 @@
 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
 #endif
 
-namespace JSC { class ExecutableAllocator; }
-namespace WTF { class BumpPointerAllocator; }
+namespace JSC {
+
+class ExecutableAllocator;
+
+}
 
 namespace js {
 
@@ -417,7 +420,6 @@ struct JS_FRIEND_API(JSCompartment) {
      */
     size_t getMjitCodeSize() const;
 #endif
-    WTF::BumpPointerAllocator    *regExpAllocator;
 
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
@@ -464,6 +466,8 @@ struct JS_FRIEND_API(JSCompartment) {
     bool                         debugMode;  // true iff debug mode on
     JSCList                      scripts;    // scripts in this compartment
 
+    JSC::ExecutableAllocator     *regExpAllocator;
+
     js::NativeIterCache          nativeIterCache;
 
     typedef js::Maybe LazyToSourceCache;
diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp
index 3d9f09f56559..0df8ae536a47 100644
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -59,6 +59,8 @@
 #include "jsobjinlines.h"
 #include "jsregexpinlines.h"
 
+#include "yarr/RegexParser.h"
+
 #ifdef JS_TRACER
 #include "jstracer.h"
 using namespace nanojit;
@@ -191,11 +193,11 @@ js_ObjectIsRegExp(JSObject *obj)
  */
 
 void
-RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error)
+RegExp::handleYarrError(JSContext *cx, int error)
 {
     switch (error) {
       case JSC::Yarr::NoError:
-        JS_NOT_REACHED("Called reportYarrError with value for no error");
+        JS_NOT_REACHED("Precondition violation: an error must have occurred.");
         return;
 #define COMPILE_EMSG(__code, __msg) \
       case JSC::Yarr::__code: \
@@ -208,16 +210,49 @@ RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error)
       COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN);
       COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */
       COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE);
       COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
+      COMPILE_EMSG(CharacterClassRangeSingleChar, JSMSG_BAD_CLASS_RANGE);
       COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
+      COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
+      COMPILE_EMSG(HitRecursionLimit, JSMSG_REGEXP_TOO_COMPLEX);
 #undef COMPILE_EMSG
       default:
-        JS_NOT_REACHED("Unknown Yarr error code");
+        JS_NOT_REACHED("Precondition violation: unknown Yarr error code.");
     }
 }
 
+void
+RegExp::handlePCREError(JSContext *cx, int error)
+{
+#define REPORT(msg_) \
+    JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \
+    return
+    switch (error) {
+      case -2: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 0: JS_NOT_REACHED("Precondition violation: an error must have occurred.");
+      case 1: REPORT(JSMSG_TRAILING_SLASH);
+      case 2: REPORT(JSMSG_TRAILING_SLASH);
+      case 3: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 4: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 5: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 6: REPORT(JSMSG_BAD_CLASS_RANGE);
+      case 7: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 8: REPORT(JSMSG_BAD_CLASS_RANGE);
+      case 9: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 10: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
+      case 11: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 12: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
+      case 13: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 14: REPORT(JSMSG_MISSING_PAREN);
+      case 15: REPORT(JSMSG_BAD_BACKREF);
+      case 16: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 17: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      default:
+        JS_NOT_REACHED("Precondition violation: unknown PCRE error code.");
+    }
+#undef REPORT
+}
+
 bool
 RegExp::parseFlags(JSContext *cx, JSString *flagStr, uintN *flagsOut)
 {
@@ -894,4 +929,3 @@ js_InitRegExpClass(JSContext *cx, JSObject *global)
 
     return proto;
 }
-
diff --git a/js/src/jsregexpinlines.h b/js/src/jsregexpinlines.h
index 305cf1590462..70db45413e1d 100644
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -48,13 +48,12 @@
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
-#include "methodjit/MethodJIT.h"
 #include "assembler/wtf/Platform.h"
-#include "yarr/BumpPointerAllocator.h"
 
-#include "yarr/Yarr.h"
 #if ENABLE_YARR_JIT
-#include "yarr/YarrJIT.h"
+#include "yarr/yarr/RegexJIT.h"
+#else
+#include "yarr/pcre/pcre.h"
 #endif
 
 namespace js {
@@ -96,10 +95,10 @@ regexp_statics_construct(JSContext *cx, GlobalObject *parent)
 class RegExp
 {
 #if ENABLE_YARR_JIT
-    /* native code is valid only if codeBlock.isFallBack() == false */
-    JSC::Yarr::YarrCodeBlock    codeBlock;
+    JSC::Yarr::RegexCodeBlock   compiled;
+#else
+    JSRegExp                    *compiled;
 #endif
-    JSC::Yarr::BytecodePattern  *byteCode;
     JSLinearString              *source;
     size_t                      refCount;
     unsigned                    parenCount; /* Must be |unsigned| to interface with YARR. */
@@ -112,11 +111,7 @@ class RegExp
 #endif
 
     RegExp(JSLinearString *source, uint32 flags, JSCompartment *compartment)
-      :
-#if ENABLE_YARR_JIT
-        codeBlock(),
-#endif
-        byteCode(NULL), source(source), refCount(1), parenCount(0), flags(flags)
+      : compiled(), source(source), refCount(1), parenCount(0), flags(flags)
 #ifdef DEBUG
         , compartment(compartment)
 #endif
@@ -125,18 +120,17 @@ class RegExp
     JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
 
     ~RegExp() {
-#if ENABLE_YARR_JIT
-        codeBlock.release();
+#if !ENABLE_YARR_JIT
+        if (compiled)
+            jsRegExpFree(compiled);
 #endif
-        // YYY
-        if (byteCode)
-            delete byteCode;
     }
 
     bool compileHelper(JSContext *cx, JSLinearString &pattern);
     bool compile(JSContext *cx);
     static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
-    void reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error);
+    void handlePCREError(JSContext *cx, int error);
+    void handleYarrError(JSContext *cx, int error);
     static inline bool initArena(JSContext *cx);
     static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
     static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
@@ -324,6 +318,9 @@ inline bool
 RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
                         size_t *lastIndex, bool test, Value *rval)
 {
+#if !ENABLE_YARR_JIT
+    JS_ASSERT(compiled);
+#endif
     const size_t pairCount = parenCount + 1;
     const size_t bufCount = pairCount * 3; /* Should be x2, but PCRE has... needs. */
     const size_t matchItemCount = pairCount * 2;
@@ -363,20 +360,27 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
         inputOffset = *lastIndex;
     }
 
-    int result;
 #if ENABLE_YARR_JIT
-    if (!codeBlock.isFallBack())
-        result = JSC::Yarr::execute(codeBlock, chars, *lastIndex - inputOffset, len, buf);
-    else
-        result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
+    int result = JSC::Yarr::executeRegex(cx, compiled, chars, *lastIndex - inputOffset, len, buf,
+                                         bufCount);
 #else
-    result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
+    int result = jsRegExpExecute(cx, compiled, chars, len, *lastIndex - inputOffset, buf, 
+                                 bufCount);
 #endif
     if (result == -1) {
         *rval = NullValue();
         return true;
     }
 
+    if (result < 0) {
+#if ENABLE_YARR_JIT
+        handleYarrError(cx, result);
+#else
+        handlePCREError(cx, result);
+#endif
+        return false;
+    }
+
     /* 
      * Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so
      * just do another pass.
@@ -456,44 +460,53 @@ RegExp::createObjectNoStatics(JSContext *cx, const jschar *chars, size_t length,
     return obj;
 }
 
-/*
- * This function should be deleted once we can. See bug 604774.
- */
-static inline bool
-EnableYarrJIT(JSContext *cx)
+#ifdef ANDROID
+static bool
+YarrJITIsBroken(JSContext *cx)
 {
-#if defined ANDROID && defined(JS_TRACER) && defined(JS_METHODJIT)
-    return cx->traceJitEnabled || cx->methodJitEnabled;
+#if defined(JS_TRACER) && defined(JS_METHODJIT)
+    /* FIXME/bug 604774: dead code walking.
+     *
+     * If both JITs are disabled, assume they were disabled because
+     * we're running on a blacklisted device.
+     */
+    return !cx->traceJitEnabled && !cx->methodJitEnabled;
 #else
-    return true;
+    return false;
 #endif
 }
+#endif  /* ANDROID */
 
 inline bool
 RegExp::compileHelper(JSContext *cx, JSLinearString &pattern)
 {
-    JSC::Yarr::ErrorCode yarrError;
-    JSC::Yarr::YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError);
-    if (yarrError) {
-        reportYarrError(cx, yarrError);
-        return false;
-    }
-    parenCount = yarrPattern.m_numSubpatterns;
-
-#if ENABLE_YARR_JIT && defined(JS_METHODJIT)
-    if (EnableYarrJIT(cx) && !yarrPattern.m_containsBackreferences) {
-        JSC::Yarr::JSGlobalData globalData(cx->compartment->jaegerCompartment->execAlloc());
-        JSC::Yarr::jitCompile(yarrPattern, &globalData, codeBlock);
-        if (!codeBlock.isFallBack())
-            return true;
-    } else {
-        codeBlock.setFallBack(true);
-    }
+#if ENABLE_YARR_JIT
+    bool fellBack = false;
+    int error = 0;
+    jitCompileRegex(*cx->compartment->regExpAllocator, compiled, pattern, parenCount, error, fellBack, ignoreCase(), multiline()
+#ifdef ANDROID
+                    /* Temporary gross hack to work around buggy kernels. */
+                    , YarrJITIsBroken(cx)
+#endif
+);
+    if (!error)
+        return true;
+    if (fellBack)
+        handlePCREError(cx, error);
+    else
+        handleYarrError(cx, error);
+    return false;
+#else
+    int error = 0;
+    compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
+                               ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
+                               multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
+                               &parenCount, &error);
+    if (!error)
+        return true;
+    handlePCREError(cx, error);
+    return false;
 #endif
-
-    byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
-
-    return true;
 }
 
 inline bool
diff --git a/js/src/jsvector.h b/js/src/jsvector.h
index 4eaf58b6a4e7..3d413c1f64b6 100644
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -208,30 +208,12 @@ class Vector : private AllocPolicy
 
     /* compute constants */
 
-    /*
-     * Consider element size to be 1 for buffer sizing if there are
-     * 0 inline elements. This allows us to compile when the definition
-     * of the element type is not visible here.
-     *
-     * Explicit specialization is only allowed at namespace scope, so
-     * in order to keep everything here, we use a dummy template
-     * parameter with partial specialization.
-     */
-    template 
-    struct ElemSize {
-        static const size_t result = sizeof(T);
-    };
-    template 
-    struct ElemSize<0, Dummy> {
-        static const size_t result = 1;
-    };
-
     static const size_t sInlineCapacity =
-        tl::Min::result>::result;
+        tl::Min::result;
 
     /* Calculate inline buffer size; avoid 0-sized array. */
     static const size_t sInlineBytes =
-        tl::Max<1, sInlineCapacity * ElemSize::result>::result;
+        tl::Max<1, sInlineCapacity * sizeof(T)>::result;
 
     /* member data */
 
diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp
index b03c6afa0990..603d76a59c88 100644
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -503,7 +503,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             analyze::Bytecode *opinfo = analysis->maybeCode(i);
             if (opinfo && opinfo->safePoint) {
                 Label L = jumpMap[i];
-                JS_ASSERT(L.isSet());
+                JS_ASSERT(L.isValid());
                 jitNmap[ix].bcOff = i;
                 jitNmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L));
                 ix++;
@@ -625,7 +625,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
     cursor += sizeof(ic::EqualityICInfo) * jit->nEqualityICs;
     for (size_t i = 0; i < jit->nEqualityICs; i++) {
         uint32 offs = uint32(equalityICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isSet());
+        JS_ASSERT(jumpMap[offs].isValid());
         jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]);
         jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry);
         jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall);
@@ -650,7 +650,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             continue;
 
         uint32 offs = uint32(traceICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isSet());
+        JS_ASSERT(jumpMap[offs].isValid());
         jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint);
         jitTraceICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]);
         jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
@@ -800,7 +800,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
 
     for (size_t i = 0; i < jumpTableOffsets.length(); i++) {
         uint32 offset = jumpTableOffsets[i];
-        JS_ASSERT(jumpMap[offset].isSet());
+        JS_ASSERT(jumpMap[offset].isValid());
         jumpVec[i] = (void *)(result + masm.distanceOf(jumpMap[offset]));
     }
 
@@ -2089,7 +2089,7 @@ JSC::MacroAssembler::Label
 mjit::Compiler::labelOf(jsbytecode *pc)
 {
     uint32 offs = uint32(pc - script->code);
-    JS_ASSERT(jumpMap[offs].isSet());
+    JS_ASSERT(jumpMap[offs].isValid());
     return jumpMap[offs];
 }
 
diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp
index b55b0dba48a5..bd738b92ba2b 100644
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -846,7 +846,12 @@ static inline void Destroy(T &t)
 
 mjit::JITScript::~JITScript()
 {
-    code.release();
+#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) 
+    void *addr = code.m_code.executableAddress();
+    memset(addr, 0xcc, code.m_size);
+#endif
+
+    code.m_executablePool->release();
 
 #if defined JS_POLYIC
     ic::GetElementIC *getElems_ = getElems();
diff --git a/js/src/methodjit/TrampolineCompiler.cpp b/js/src/methodjit/TrampolineCompiler.cpp
index 77bb148ba311..a6ac9d709f0e 100644
--- a/js/src/methodjit/TrampolineCompiler.cpp
+++ b/js/src/methodjit/TrampolineCompiler.cpp
@@ -93,7 +93,7 @@ TrampolineCompiler::compileTrampoline(Trampolines::TrampolinePtr *where,
 
     Label entry = masm.label();
     CHECK_RESULT(generator(masm));
-    JS_ASSERT(entry.isSet());
+    JS_ASSERT(entry.isValid());
 
     bool ok;
     JSC::LinkBuffer buffer(&masm, execAlloc, poolp, &ok);
diff --git a/js/src/yarr/BumpPointerAllocator.h b/js/src/yarr/BumpPointerAllocator.h
deleted file mode 100644
index 8ef5a780f9d8..000000000000
--- a/js/src/yarr/BumpPointerAllocator.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/* -*- 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) 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef BumpPointerAllocator_h
-#define BumpPointerAllocator_h
-
-#include "PageAllocation.h"
-
-namespace WTF {
-
-#define MINIMUM_BUMP_POOL_SIZE 0x1000
-
-class BumpPointerPool {
-public:
-    // ensureCapacity will check whether the current pool has capacity to
-    // allocate 'size' bytes of memory  If it does not, it will attempt to
-    // allocate a new pool (which will be added to this one in a chain).
-    //
-    // If allocation fails (out of memory) this method will return null.
-    // If the return value is non-null, then callers should update any
-    // references they have to this current (possibly full) BumpPointerPool
-    // to instead point to the newly returned BumpPointerPool.
-    BumpPointerPool* ensureCapacity(size_t size)
-    {
-        void* allocationEnd = static_cast(m_current) + size;
-        ASSERT(allocationEnd > m_current); // check for overflow
-        if (allocationEnd <= static_cast(this))
-            return this;
-        return ensureCapacityCrossPool(this, size);
-    }
-
-    // alloc should only be called after calling ensureCapacity; as such
-    // alloc will never fail.
-    void* alloc(size_t size)
-    {
-        void* current = m_current;
-        void* allocationEnd = static_cast(current) + size;
-        ASSERT(allocationEnd > current); // check for overflow
-        ASSERT(allocationEnd <= static_cast(this));
-        m_current = allocationEnd;
-        return current;
-    }
-
-    // The dealloc method releases memory allocated using alloc.  Memory
-    // must be released in a LIFO fashion, e.g. if the client calls alloc
-    // four times, returning pointer A, B, C, D, then the only valid order
-    // in which these may be deallocaed is D, C, B, A.
-    //
-    // The client may optionally skip some deallocations.  In the example
-    // above, it would be valid to only explicitly dealloc C, A (D being
-    // dealloced along with C, B along with A).
-    //
-    // If pointer was not allocated from this pool (or pools) then dealloc
-    // will CRASH().  Callers should update any references they have to
-    // this current BumpPointerPool to instead point to the returned
-    // BumpPointerPool.
-    BumpPointerPool* dealloc(void* position)
-    {
-        if ((position >= m_start) && (position <= static_cast(this))) {
-            ASSERT(position <= m_current);
-            m_current = position;
-            return this;
-        }
-        return deallocCrossPool(this, position);
-    }
-
-private:
-    // Placement operator new, returns the last 'size' bytes of allocation for use as this.
-    void* operator new(size_t size, const PageAllocation& allocation)
-    {
-        ASSERT(size < allocation.size());
-        return reinterpret_cast(reinterpret_cast(allocation.base()) + allocation.size()) - size;
-    }
-
-    BumpPointerPool(const PageAllocation& allocation)
-        : m_current(allocation.base())
-        , m_start(allocation.base())
-        , m_next(0)
-        , m_previous(0)
-        , m_allocation(allocation)
-    {
-    }
-
-    static BumpPointerPool* create(size_t minimumCapacity = 0)
-    {
-        // Add size of BumpPointerPool object, check for overflow.
-        minimumCapacity += sizeof(BumpPointerPool);
-        if (minimumCapacity < sizeof(BumpPointerPool))
-            return 0;
-
-        size_t poolSize = MINIMUM_BUMP_POOL_SIZE;
-        while (poolSize < minimumCapacity) {
-            poolSize <<= 1;
-            // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2!
-            ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1)));
-            if (!poolSize)
-                return 0;
-        }
-
-        PageAllocation allocation = PageAllocation::allocate(poolSize);
-        if (!!allocation)
-            return new(allocation) BumpPointerPool(allocation);
-        return 0;
-    }
-
-    void shrink()
-    {
-        ASSERT(!m_previous);
-        m_current = m_start;
-        while (m_next) {
-            BumpPointerPool* nextNext = m_next->m_next;
-            m_next->destroy();
-            m_next = nextNext;
-        }
-    }
-
-    void destroy()
-    {
-        m_allocation.deallocate();
-    }
-
-    static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size)
-    {
-        // The pool passed should not have capacity, so we'll start with the next one.
-        ASSERT(previousPool);
-        ASSERT((static_cast(previousPool->m_current) + size) > previousPool->m_current); // check for overflow
-        ASSERT((static_cast(previousPool->m_current) + size) > static_cast(previousPool));
-        BumpPointerPool* pool = previousPool->m_next;
-
-        while (true) {
-            if (!pool) {
-                // We've run to the end; allocate a new pool.
-                pool = BumpPointerPool::create(size);
-                previousPool->m_next = pool;
-                pool->m_previous = previousPool;
-                return pool;
-            }
-
-            // 
-            void* current = pool->m_current;
-            void* allocationEnd = static_cast(current) + size;
-            ASSERT(allocationEnd > current); // check for overflow
-            if (allocationEnd <= static_cast(pool))
-                return pool;
-        }
-    }
-
-    static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position)
-    {
-        // Should only be called if position is not in the current pool.
-        ASSERT((position < pool->m_start) || (position > static_cast(pool)));
-
-        while (true) {
-            // Unwind the current pool to the start, move back in the chain to the previous pool.
-            pool->m_current = pool->m_start;
-            pool = pool->m_previous;
-
-            // position was nowhere in the chain!
-            if (!pool)
-                CRASH();
-
-            if ((position >= pool->m_start) && (position <= static_cast(pool))) {
-                ASSERT(position <= pool->m_current);
-                pool->m_current = position;
-                return pool;
-            }
-        }
-    }
-
-    void* m_current;
-    void* m_start;
-    BumpPointerPool* m_next;
-    BumpPointerPool* m_previous;
-    PageAllocation m_allocation;
-
-    friend class BumpPointerAllocator;
-};
-
-// A BumpPointerAllocator manages a set of BumpPointerPool objects, which
-// can be used for LIFO (stack like) allocation.
-//
-// To begin allocating using this class call startAllocator().  The result
-// of this method will be null if the initial pool allocation fails, or a
-// pointer to a BumpPointerPool object that can be used to perform
-// allocations.  Whilst running no memory will be released until
-// stopAllocator() is called.  At this point all allocations made through
-// this allocator will be reaped, and underlying memory may be freed.
-//
-// (In practice we will still hold on to the initial pool to allow allocation
-// to be quickly restared, but aditional pools will be freed).
-//
-// This allocator is non-renetrant, it is encumbant on the clients to ensure
-// startAllocator() is not called again until stopAllocator() has been called.
-class BumpPointerAllocator {
-public:
-    BumpPointerAllocator()
-        : m_head(0)
-    {
-    }
-
-    ~BumpPointerAllocator()
-    {
-        if (m_head)
-            m_head->destroy();
-    }
-
-    BumpPointerPool* startAllocator()
-    {
-        if (!m_head)
-            m_head = BumpPointerPool::create();
-        return m_head;
-    }
-
-    void stopAllocator()
-    {
-        if (m_head)
-            m_head->shrink();
-    }
-
-private:
-    BumpPointerPool* m_head;
-};
-
-}
-
-using WTF::BumpPointerAllocator;
-
-#endif // BumpPointerAllocator_h
diff --git a/js/src/yarr/Makefile b/js/src/yarr/Makefile
new file mode 100644
index 000000000000..c824cdb96b6c
--- /dev/null
+++ b/js/src/yarr/Makefile
@@ -0,0 +1,5 @@
+INCLUDES := -I. -Iyarr -Iwtf -I../assembler/assembler -I../assembler
+
+all: 
+	$(CXX) -g3 -c $(INCLUDES) yarr/*.cpp
+	$(CXX) -g3 $(INCLUDES) TestMain.cpp *.o
diff --git a/js/src/yarr/OSAllocator.h b/js/src/yarr/OSAllocator.h
deleted file mode 100644
index ecfdc3b042ec..000000000000
--- a/js/src/yarr/OSAllocator.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef OSAllocator_h
-#define OSAllocator_h
-
-#include 
-#include "wtfbridge.h"
-#include "assembler/wtf/VMTags.h"
-#include "assembler/wtf/Assertions.h"
-
-namespace WTF {
-
-class OSAllocator {
-public:
-    enum Usage {
-        UnknownUsage = -1,
-        FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY,
-        JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY,
-        JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY,
-        JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY
-    };
-
-    // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state,
-    // releaseDecommitted should be called on a region of VM allocated by a single reservation,
-    // the memory must all currently be in a decommitted state.
-    static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void releaseDecommitted(void*, size_t);
-
-    // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should
-    // never be accessed, since the OS may not have attached physical memory for these regions).
-    // Clients should only call commit on uncommitted regions and decommit on committed regions.
-    static void commit(void*, size_t, bool writable, bool executable);
-    static void decommit(void*, size_t);
-
-    // These methods are symmetric; reserveAndCommit allocates VM in an committed state,
-    // decommitAndRelease should be called on a region of VM allocated by a single reservation,
-    // the memory must all currently be in a committed state.
-    static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void decommitAndRelease(void* base, size_t size);
-
-    // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than
-    // committing/decommitting the entire region additional parameters allow a subregion to be
-    // specified.
-    static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize);
-};
-
-inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable)
-{
-    void* base = reserveUncommitted(reserveSize, usage, writable, executable);
-    commit(base, commitSize, writable, executable);
-    return base;
-}
-
-inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize)
-{
-    ASSERT(decommitBase >= releaseBase && (static_cast(decommitBase) + decommitSize) <= (static_cast(releaseBase) + releaseSize));
-#if WTF_OS_WINCE || WTF_OS_SYMBIAN
-    // On most platforms we can actually skip this final decommit; releasing the VM will
-    // implicitly decommit any physical memory in the region. This is not true on WINCE.
-    // On Symbian, this makes implementation simpler and better aligned with the RChunk API
-    decommit(decommitBase, decommitSize);
-#endif
-    releaseDecommitted(releaseBase, releaseSize);
-}
-
-inline void OSAllocator::decommitAndRelease(void* base, size_t size)
-{
-    decommitAndRelease(base, size, base, size);
-}
-
-} // namespace WTF
-
-using WTF::OSAllocator;
-
-#endif // OSAllocator_h
diff --git a/js/src/yarr/OSAllocatorPosix.cpp b/js/src/yarr/OSAllocatorPosix.cpp
deleted file mode 100644
index 57c240b22fe5..000000000000
--- a/js/src/yarr/OSAllocatorPosix.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
-
-#include "OSAllocator.h"
-
-#include 
-#include 
-#include "wtf/Assertions.h"
-
-namespace WTF {
-
-void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
-{
-    void* result = reserveAndCommit(bytes, usage, writable, executable);
-#if HAVE_MADV_FREE_REUSE
-    // To support the "reserve then commit" model, we have to initially decommit.
-    while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
-#endif
-    return result;
-}
-
-void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable)
-{
-    // All POSIX reservations start out logically committed.
-    int protection = PROT_READ;
-    if (writable)
-        protection |= PROT_WRITE;
-    if (executable)
-        protection |= PROT_EXEC;
-
-    int flags = MAP_PRIVATE | MAP_ANON;
-
-#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER)
-    int fd = usage;
-#else
-    int fd = -1;
-#endif
-
-    void* result = 0;
-#if (WTF_OS_DARWIN && WTF_CPU_X86_64)
-    if (executable) {
-        // Cook up an address to allocate at, using the following recipe:
-        //   17 bits of zero, stay in userspace kids.
-        //   26 bits of randomness for ASLR.
-        //   21 bits of zero, at least stay aligned within one level of the pagetables.
-        //
-        // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
-        // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus
-        // 2^24, which should put up somewhere in the middle of userspace (in the address range
-        // 0x200000000000 .. 0x5fffffffffff).
-        intptr_t randomLocation = 0;
-        randomLocation = arc4random() & ((1 << 25) - 1);
-        randomLocation += (1 << 24);
-        randomLocation <<= 21;
-        result = reinterpret_cast(randomLocation);
-    }
-#endif
-
-    result = mmap(result, bytes, protection, flags, fd, 0);
-    if (result == MAP_FAILED)
-        CRASH();
-    return result;
-}
-
-void OSAllocator::commit(void* address, size_t bytes, bool, bool)
-{
-#if HAVE_MADV_FREE_REUSE
-    while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
-#else
-    // Non-MADV_FREE_REUSE reservations automatically commit on demand.
-    UNUSED_PARAM(address);
-    UNUSED_PARAM(bytes);
-#endif
-}
-
-void OSAllocator::decommit(void* address, size_t bytes)
-{
-#if HAVE_MADV_FREE_REUSE
-    while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
-#elif HAVE_MADV_FREE
-    while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { }
-#elif HAVE_MADV_DONTNEED
-    while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
-#else
-    UNUSED_PARAM(address);
-    UNUSED_PARAM(bytes);
-#endif
-}
-
-void OSAllocator::releaseDecommitted(void* address, size_t bytes)
-{
-    int result = munmap(address, bytes);
-    if (result == -1)
-        CRASH();
-}
-
-} // namespace WTF
-
-#endif
diff --git a/js/src/yarr/OSAllocatorWin.cpp b/js/src/yarr/OSAllocatorWin.cpp
deleted file mode 100644
index 08df9e98aefb..000000000000
--- a/js/src/yarr/OSAllocatorWin.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
-
-#include "windows.h"
-#include "wtf/Assertions.h"
-
-#include "OSAllocator.h"
-
-namespace WTF {
-
-static inline DWORD protection(bool writable, bool executable)
-{
-    return executable ?
-        (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) :
-        (writable ? PAGE_READWRITE : PAGE_READONLY);
-}
-
-void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable));
-    if (!result)
-        CRASH();
-    return result;
-}
-
-void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable));
-    if (!result)
-        CRASH();
-    return result;
-}
-
-void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable));
-    if (!result)
-        CRASH();
-}
-
-void OSAllocator::decommit(void* address, size_t bytes)
-{
-    bool result = VirtualFree(address, bytes, MEM_DECOMMIT);
-    if (!result)
-        CRASH();
-}
-
-void OSAllocator::releaseDecommitted(void* address, size_t bytes)
-{
-    // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx,
-    // dwSize must be 0 if dwFreeType is MEM_RELEASE.
-    bool result = VirtualFree(address, 0, MEM_RELEASE);
-    if (!result)
-        CRASH();
-}
-
-} // namespace WTF
-
-#endif
diff --git a/js/src/yarr/PageAllocation.h b/js/src/yarr/PageAllocation.h
deleted file mode 100644
index a86f37116e50..000000000000
--- a/js/src/yarr/PageAllocation.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- 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) 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PageAllocation_h
-#define PageAllocation_h
-
-#include "wtfbridge.h"
-#include "OSAllocator.h"
-#include "PageBlock.h"
-#include "assembler/wtf/VMTags.h"
-
-#if WTF_OS_DARWIN
-#include 
-#include 
-#endif
-
-#if WTF_OS_HAIKU
-#include 
-#endif
-
-#if WTF_OS_WINDOWS
-#include 
-#include 
-#endif
-
-#if WTF_OS_SYMBIAN
-#include 
-#include 
-#endif
-
-#if WTF_HAVE_ERRNO_H
-#include 
-#endif
-
-#if WTF_HAVE_MMAP
-#include 
-#include 
-#endif
-
-namespace WTF {
-
-/*
-    PageAllocation
-
-    The PageAllocation class provides a cross-platform memory allocation interface
-    with similar capabilities to posix mmap/munmap.  Memory is allocated by calling
-    PageAllocation::allocate, and deallocated by calling deallocate on the
-    PageAllocation object.  The PageAllocation holds the allocation's base pointer
-    and size.
-
-    The allocate method is passed the size required (which must be a multiple of
-    the system page size, which can be accessed using PageAllocation::pageSize).
-    Callers may also optinally provide a flag indicating the usage (for use by
-    system memory usage tracking tools, where implemented), and boolean values
-    specifying the required protection (defaulting to writable, non-executable).
-*/
-
-class PageAllocation : private PageBlock {
-public:
-    PageAllocation()
-    {
-    }
-
-    using PageBlock::size;
-    using PageBlock::base;
-
-#ifndef __clang__
-    using PageBlock::operator bool;
-#else
-    // FIXME: This is a workaround for , wherein Clang incorrectly emits an access
-    // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
-    operator bool() const { return PageBlock::operator bool(); }
-#endif
-
-    static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
-    {
-        ASSERT(isPageAligned(size));
-        return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size);
-    }
-
-    void deallocate()
-    {
-        // Clear base & size before calling release; if this is *inside* allocation
-        // then we won't be able to clear then after deallocating the memory.
-        PageAllocation tmp;
-        JSC::std::swap(tmp, *this);
-
-        ASSERT(tmp);
-        ASSERT(!*this);
-
-        OSAllocator::decommitAndRelease(tmp.base(), tmp.size());
-    }
-
-private:
-    PageAllocation(void* base, size_t size)
-        : PageBlock(base, size)
-    {
-    }
-};
-
-} // namespace WTF
-
-using WTF::PageAllocation;
-
-#endif // PageAllocation_h
diff --git a/js/src/yarr/PageBlock.cpp b/js/src/yarr/PageBlock.cpp
deleted file mode 100644
index 0f435b772860..000000000000
--- a/js/src/yarr/PageBlock.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "PageBlock.h"
-#include "wtf/Assertions.h"
-
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
-#include 
-#endif
-
-#if WTF_OS_WINDOWS
-#include 
-#include 
-#endif
-
-#if WTF_OS_SYMBIAN
-#include 
-#include 
-#endif
-
-namespace WTF {
-
-static size_t s_pageSize;
-
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
-
-inline size_t systemPageSize()
-{
-    return getpagesize();
-}
-
-#elif WTF_OS_WINDOWS
-
-inline size_t systemPageSize()
-{
-    static size_t size = 0;
-    SYSTEM_INFO system_info;
-    GetSystemInfo(&system_info);
-    size = system_info.dwPageSize;
-    return size;
-}
-
-#elif WTF_OS_SYMBIAN
-
-inline size_t systemPageSize()
-{
-    static TInt page_size = 0;
-    UserHal::PageSizeInBytes(page_size);
-    return page_size;
-}
-
-#endif
-
-size_t pageSize()
-{
-    if (!s_pageSize)
-        s_pageSize = systemPageSize();
-    ASSERT(isPowerOfTwo(s_pageSize));
-    return s_pageSize;
-}
-
-} // namespace WTF
diff --git a/js/src/yarr/PageBlock.h b/js/src/yarr/PageBlock.h
deleted file mode 100644
index 33751315e049..000000000000
--- a/js/src/yarr/PageBlock.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PageBlock_h
-#define PageBlock_h
-
-#include 
-#include "jsstdint.h"
-#include "assembler/wtf/Platform.h"
-
-namespace WTF {
-
-size_t pageSize();
-inline bool isPageAligned(void* address) { return !(reinterpret_cast(address) & (pageSize() - 1)); }
-inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
-inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
-
-class PageBlock {
-public:
-    PageBlock();
-    PageBlock(const PageBlock&);
-    PageBlock(void*, size_t);
-    
-    void* base() const { return m_base; }
-    size_t size() const { return m_size; }
-
-    operator bool() const { return !!m_base; }
-
-    bool contains(void* containedBase, size_t containedSize)
-    {
-        return containedBase >= m_base
-            && (static_cast(containedBase) + containedSize) <= (static_cast(m_base) + m_size);
-    }
-
-private:
-    void* m_base;
-    size_t m_size;
-};
-
-inline PageBlock::PageBlock()
-    : m_base(0)
-    , m_size(0)
-{
-}
-
-inline PageBlock::PageBlock(const PageBlock& other)
-    : m_base(other.m_base)
-    , m_size(other.m_size)
-{
-}
-
-inline PageBlock::PageBlock(void* base, size_t size)
-    : m_base(base)
-    , m_size(size)
-{
-}
-
-} // namespace WTF
-
-using WTF::pageSize;
-using WTF::isPageAligned;
-using WTF::isPageAligned;
-using WTF::isPowerOfTwo;
-
-#endif // PageBlock_h
diff --git a/js/src/yarr/VMTags.h b/js/src/yarr/VMTags.h
deleted file mode 100644
index fe6a006d3601..000000000000
--- a/js/src/yarr/VMTags.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2009 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 VMTags_h
-#define VMTags_h
-
-// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map
-// in order to aid tools that inspect system memory use. 
-#if WTF_OS_DARWIN
-
-#include 
-
-#if !defined(TARGETING_TIGER)
-
-#if defined(VM_MEMORY_TCMALLOC)
-#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
-#else
-#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53)
-#endif // defined(VM_MEMORY_TCMALLOC)
-
-#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-#else
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64)
-#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-
-#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-#else
-#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65)
-#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-
-#else // !defined(TARGETING_TIGER)
-
-// mmap on Tiger fails with tags that work on Leopard, so fall
-// back to Tiger-compatible tags (that also work on Leopard)
-// when targeting Tiger.
-#define VM_TAG_FOR_TCMALLOC_MEMORY -1
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
-#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
-
-#endif // !defined(TARGETING_TIGER)
-
-// Tags for vm_map and vm_allocate work on both Tiger and Leopard.
-
-#if defined(VM_MEMORY_JAVASCRIPT_CORE)
-#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE)
-#else
-#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63)
-#endif // defined(VM_MEMORY_JAVASCRIPT_CORE)
-
-#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-#else
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69)
-#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-
-#else // OS(DARWIN)
-
-#define VM_TAG_FOR_TCMALLOC_MEMORY -1
-#define VM_TAG_FOR_COLLECTOR_MEMORY -1
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
-#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1
-
-#endif // OS(DARWIN)
-
-#endif // VMTags_h
diff --git a/js/src/yarr/Yarr.h b/js/src/yarr/Yarr.h
deleted file mode 100644
index 40ebcca096af..000000000000
--- a/js/src/yarr/Yarr.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- 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.
- *
- * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef Yarr_h
-#define Yarr_h
-
-#include 
-
-#include "YarrInterpreter.h"
-#include "YarrPattern.h"
-
-namespace JSC { namespace Yarr {
-
-#define YarrStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoBackReference 2
-#define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
-#define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1
-#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1
-#define YarrStackSpaceForBackTrackInfoParentheses 2
-
-static const unsigned quantifyInfinite = UINT_MAX;
-
-// The below limit restricts the number of "recursive" match calls in order to
-// avoid spending exponential time on complex regular expressions.
-static const unsigned matchLimit = 1000000;
-
-enum JSRegExpResult {
-    JSRegExpMatch = 1,
-    JSRegExpNoMatch = 0,
-    JSRegExpErrorNoMatch = -1,
-    JSRegExpErrorHitLimit = -2,
-    JSRegExpErrorNoMemory = -3,
-    JSRegExpErrorInternal = -4
-};
-
-PassOwnPtr byteCompile(YarrPattern&, BumpPointerAllocator*);
-int interpret(BytecodePattern*, const UChar* input, unsigned start, unsigned length, int* output);
-
-} } // namespace JSC::Yarr
-
-#endif // Yarr_h
-
diff --git a/js/src/yarr/YarrInterpreter.cpp b/js/src/yarr/YarrInterpreter.cpp
deleted file mode 100644
index 2be8240efe60..000000000000
--- a/js/src/yarr/YarrInterpreter.cpp
+++ /dev/null
@@ -1,1914 +0,0 @@
-/* -*- 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
- *
- * 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "YarrInterpreter.h"
-
-#include "Yarr.h"
-#include "BumpPointerAllocator.h"
-
-#ifndef NDEBUG
-#include 
-#endif
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-class Interpreter {
-public:
-    struct ParenthesesDisjunctionContext;
-
-    struct BackTrackInfoPatternCharacter {
-        uintptr_t matchAmount;
-    };
-    struct BackTrackInfoCharacterClass {
-        uintptr_t matchAmount;
-    };
-    struct BackTrackInfoBackReference {
-        uintptr_t begin; // Not really needed for greedy quantifiers.
-        uintptr_t matchAmount; // Not really needed for fixed quantifiers.
-    };
-    struct BackTrackInfoAlternative {
-        uintptr_t offset;
-    };
-    struct BackTrackInfoParentheticalAssertion {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParenthesesOnce {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParenthesesTerminal {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParentheses {
-        uintptr_t matchAmount;
-        ParenthesesDisjunctionContext* lastContext;
-    };
-
-    static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context)
-    {
-        context->next = backTrack->lastContext;
-        backTrack->lastContext = context;
-        ++backTrack->matchAmount;
-    }
-
-    static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack)
-    {
-        ASSERT(backTrack->matchAmount);
-        ASSERT(backTrack->lastContext);
-        backTrack->lastContext = backTrack->lastContext->next;
-        --backTrack->matchAmount;
-    }
-
-    struct DisjunctionContext
-    {
-        DisjunctionContext()
-            : term(0)
-        {
-        }
-
-        void* operator new(size_t, void* where)
-        {
-            return where;
-        }
-
-        int term;
-        unsigned matchBegin;
-        unsigned matchEnd;
-        uintptr_t frame[1];
-    };
-
-    DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction)
-    {
-        size_t size = sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
-        allocatorPool = allocatorPool->ensureCapacity(size);
-        if (!allocatorPool)
-            CRASH();
-        return new(allocatorPool->alloc(size)) DisjunctionContext();
-    }
-
-    void freeDisjunctionContext(DisjunctionContext* context)
-    {
-        allocatorPool = allocatorPool->dealloc(context);
-    }
-
-    struct ParenthesesDisjunctionContext
-    {
-        ParenthesesDisjunctionContext(int* output, ByteTerm& term)
-            : next(0)
-        {
-            unsigned firstSubpatternId = term.atom.subpatternId;
-            unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns;
-
-            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) {
-                subpatternBackup[i] = output[(firstSubpatternId << 1) + i];
-                output[(firstSubpatternId << 1) + i] = -1;
-            }
-
-            new(getDisjunctionContext(term)) DisjunctionContext();
-        }
-
-        void* operator new(size_t, void* where)
-        {
-            return where;
-        }
-
-        void restoreOutput(int* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns)
-        {
-            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i)
-                output[(firstSubpatternId << 1) + i] = subpatternBackup[i];
-        }
-
-        DisjunctionContext* getDisjunctionContext(ByteTerm& term)
-        {
-            return reinterpret_cast(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1]));
-        }
-
-        ParenthesesDisjunctionContext* next;
-        int subpatternBackup[1];
-    };
-
-    ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, int* output, ByteTerm& term)
-    {
-        size_t size = sizeof(ParenthesesDisjunctionContext) - sizeof(int) + (term.atom.parenthesesDisjunction->m_numSubpatterns << 1) * sizeof(int) + sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
-        allocatorPool = allocatorPool->ensureCapacity(size);
-        if (!allocatorPool)
-            CRASH();
-        return new(allocatorPool->alloc(size)) ParenthesesDisjunctionContext(output, term);
-    }
-
-    void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context)
-    {
-        allocatorPool = allocatorPool->dealloc(context);
-    }
-
-    class InputStream {
-    public:
-        InputStream(const UChar* input, unsigned start, unsigned length)
-            : input(input)
-            , pos(start)
-            , length(length)
-        {
-        }
-
-        void next()
-        {
-            ++pos;
-        }
-
-        void rewind(unsigned amount)
-        {
-            ASSERT(pos >= amount);
-            pos -= amount;
-        }
-
-        int read()
-        {
-            ASSERT(pos < length);
-            if (pos < length)
-                return input[pos];
-            return -1;
-        }
-
-        int readPair()
-        {
-            ASSERT(pos + 1 < length);
-            return input[pos] | input[pos + 1] << 16;
-        }
-
-        int readChecked(int position)
-        {
-            ASSERT(position < 0);
-            ASSERT(static_cast(-position) <= pos);
-            unsigned p = pos + position;
-            ASSERT(p < length);
-            return input[p];
-        }
-
-        int reread(unsigned from)
-        {
-            ASSERT(from < length);
-            return input[from];
-        }
-
-        int prev()
-        {
-            ASSERT(!(pos > length));
-            if (pos && length)
-                return input[pos - 1];
-            return -1;
-        }
-
-        unsigned getPos()
-        {
-            return pos;
-        }
-
-        void setPos(unsigned p)
-        {
-            pos = p;
-        }
-
-        bool atStart()
-        {
-            return pos == 0;
-        }
-
-        bool atEnd()
-        {
-            return pos == length;
-        }
-
-        bool checkInput(int count)
-        {
-            if ((pos + count) <= length) {
-                pos += count;
-                return true;
-            }
-            return false;
-        }
-
-        void uncheckInput(int count)
-        {
-            pos -= count;
-        }
-
-        bool atStart(int position)
-        {
-            return (pos + position) == 0;
-        }
-
-        bool atEnd(int position)
-        {
-            return (pos + position) == length;
-        }
-
-        bool isNotAvailableInput(int position)
-        {
-            return (pos + position) > length;
-        }
-
-    private:
-        const UChar* input;
-        unsigned pos;
-        unsigned length;
-    };
-
-    bool testCharacterClass(CharacterClass* characterClass, int ch)
-    {
-        if (ch & 0xFF80) {
-            for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i)
-                if (ch == characterClass->m_matchesUnicode[i])
-                    return true;
-            for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i)
-                if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end))
-                    return true;
-        } else {
-            for (unsigned i = 0; i < characterClass->m_matches.size(); ++i)
-                if (ch == characterClass->m_matches[i])
-                    return true;
-            for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i)
-                if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end))
-                    return true;
-        }
-
-        return false;
-    }
-
-    bool checkCharacter(int testChar, int inputPosition)
-    {
-        return testChar == input.readChecked(inputPosition);
-    }
-
-    bool checkCasedCharacter(int loChar, int hiChar, int inputPosition)
-    {
-        int ch = input.readChecked(inputPosition);
-        return (loChar == ch) || (hiChar == ch);
-    }
-
-    bool checkCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition)
-    {
-        bool match = testCharacterClass(characterClass, input.readChecked(inputPosition));
-        return invert ? !match : match;
-    }
-
-    bool tryConsumeBackReference(int matchBegin, int matchEnd, int inputOffset)
-    {
-        int matchSize = matchEnd - matchBegin;
-
-        if (!input.checkInput(matchSize))
-            return false;
-
-        if (pattern->m_ignoreCase) {
-            for (int i = 0; i < matchSize; ++i) {
-                int ch = input.reread(matchBegin + i);
-
-                int lo = Unicode::toLower(ch);
-                int hi = Unicode::toUpper(ch);
-
-                if ((lo != hi) ? (!checkCasedCharacter(lo, hi, inputOffset - matchSize + i)) : (!checkCharacter(ch, inputOffset - matchSize + i))) {
-                    input.uncheckInput(matchSize);
-                    return false;
-                }
-            }
-        } else {
-            for (int i = 0; i < matchSize; ++i) {
-                if (!checkCharacter(input.reread(matchBegin + i), inputOffset - matchSize + i)) {
-                    input.uncheckInput(matchSize);
-                    return false;
-                }
-            }
-        }
-
-        return true;
-    }
-
-    bool matchAssertionBOL(ByteTerm& term)
-    {
-        return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition - 1)));
-    }
-
-    bool matchAssertionEOL(ByteTerm& term)
-    {
-        if (term.inputPosition)
-            return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition)));
-
-        return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read()));
-    }
-
-    bool matchAssertionWordBoundary(ByteTerm& term)
-    {
-        bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition - 1));
-        bool readIsWordchar;
-        if (term.inputPosition)
-            readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition));
-        else
-            readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read());
-
-        bool wordBoundary = prevIsWordchar != readIsWordchar;
-        return term.invert() ? !wordBoundary : wordBoundary;
-    }
-
-    bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context)
-    {
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCharacter(term.atom.patternCharacter, term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context)
-    {
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeCharacterClass);
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
-                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + matchAmount))
-                    return false;
-            }
-            return true;
-        }
-
-        case QuantifierGreedy: {
-            unsigned matchAmount = 0;
-            while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            return true;
-        }
-
-        case QuantifierNonGreedy:
-            backTrack->matchAmount = 0;
-            return true;
-        }
-
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeCharacterClass);
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchBackReference(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeBackReference);
-        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        int matchBegin = output[(term.atom.subpatternId << 1)];
-        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
-
-        // If the end position of the referenced match hasn't set yet then the backreference in the same parentheses where it references to that.
-        // In this case the result of match is empty string like when it references to a parentheses with zero-width match.
-        // Eg.: /(a\1)/
-        if (matchEnd == -1)
-            return true;
-
-        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
-
-        if (matchBegin == matchEnd)
-            return true;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            backTrack->begin = input.getPos();
-            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
-                if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
-                    input.setPos(backTrack->begin);
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        case QuantifierGreedy: {
-            unsigned matchAmount = 0;
-            while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
-                ++matchAmount;
-            backTrack->matchAmount = matchAmount;
-            return true;
-        }
-
-        case QuantifierNonGreedy:
-            backTrack->begin = input.getPos();
-            backTrack->matchAmount = 0;
-            return true;
-        }
-
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeBackReference);
-        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        int matchBegin = output[(term.atom.subpatternId << 1)];
-        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
-        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
-
-        if (matchBegin == matchEnd)
-            return false;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            // for quantityCount == 1, could rewind.
-            input.setPos(backTrack->begin);
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.rewind(matchEnd - matchBegin);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
-                ++backTrack->matchAmount;
-                return true;
-            }
-            input.setPos(backTrack->begin);
-            break;
-        }
-
-        return false;
-    }
-
-    void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context)
-    {
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition;
-            output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition;
-        }
-    }
-    void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context)
-    {
-        unsigned firstSubpatternId = term.atom.subpatternId;
-        unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns;
-        context->restoreOutput(output, firstSubpatternId, count);
-    }
-    JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack)
-    {
-        while (backTrack->matchAmount) {
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-
-            JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true);
-            if (result == JSRegExpMatch)
-                return JSRegExpMatch;
-
-            resetMatches(term, context);
-            popParenthesesDisjunctionContext(backTrack);
-            freeParenthesesDisjunctionContext(context);
-
-            if (result != JSRegExpNoMatch)
-                return result;
-        }
-
-        return JSRegExpNoMatch;
-    }
-
-    bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy: {
-            // set this speculatively; if we get to the parens end this will be true.
-            backTrack->begin = input.getPos();
-            break;
-        }
-        case QuantifierNonGreedy: {
-            backTrack->begin = notFound;
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        }
-        case QuantifierFixedCount:
-            break;
-        }
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = input.getPos() + term.inputPosition;
-        }
-
-        return true;
-    }
-
-    bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
-        }
-
-        if (term.atom.quantityType == QuantifierFixedCount)
-            return true;
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        return backTrack->begin != input.getPos();
-    }
-
-    bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = -1;
-            output[(subpatternId << 1) + 1] = -1;
-        }
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy:
-            // if we backtrack to this point, there is another chance - try matching nothing.
-            ASSERT(backTrack->begin != notFound);
-            backTrack->begin = notFound;
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        case QuantifierNonGreedy:
-            ASSERT(backTrack->begin != notFound);
-        case QuantifierFixedCount:
-            break;
-        }
-
-        return false;
-    }
-
-    bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy:
-            if (backTrack->begin == notFound) {
-                context->term -= term.atom.parenthesesWidth;
-                return false;
-            }
-        case QuantifierNonGreedy:
-            if (backTrack->begin == notFound) {
-                backTrack->begin = input.getPos();
-                if (term.capture()) {
-                    // Technically this access to inputPosition should be accessing the begin term's
-                    // inputPosition, but for repeats other than fixed these values should be
-                    // the same anyway! (We don't pre-check for greedy or non-greedy matches.)
-                    ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-                    ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition);
-                    unsigned subpatternId = term.atom.subpatternId;
-                    output[subpatternId << 1] = input.getPos() + term.inputPosition;
-                }
-                context->term -= term.atom.parenthesesWidth;
-                return true;
-            }
-        case QuantifierFixedCount:
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-        ASSERT(term.atom.quantityType == QuantifierGreedy);
-        ASSERT(term.atom.quantityCount == quantifyInfinite);
-        ASSERT(!term.capture());
-
-        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        backTrack->begin = input.getPos();
-        return true;
-    }
-
-    bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd);
-
-        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        // Empty match is a failed match.
-        if (backTrack->begin == input.getPos())
-            return false;
-
-        // Successful match! Okay, what's next? - loop around and try to match moar!
-        context->term -= (term.atom.parenthesesWidth + 1);
-        return true;
-    }
-
-    bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-        ASSERT(term.atom.quantityType == QuantifierGreedy);
-        ASSERT(term.atom.quantityCount == quantifyInfinite);
-        ASSERT(!term.capture());
-
-        // If we backtrack to this point, we have failed to match this iteration of the parens.
-        // Since this is greedy / zero minimum a failed is also accepted as a match!
-        context->term += term.atom.parenthesesWidth;
-        return true;
-    }
-
-    bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*)
-    {
-        // 'Terminal' parentheses are at the end of the regex, and as such a match past end
-        // should always be returned as a successful match - we should never backtrack to here.
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        backTrack->begin = input.getPos();
-        return true;
-    }
-
-    bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        input.setPos(backTrack->begin);
-
-        // We've reached the end of the parens; if they are inverted, this is failure.
-        if (term.invert()) {
-            context->term -= term.atom.parenthesesWidth;
-            return false;
-        }
-
-        return true;
-    }
-
-    bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        // We've failed to match parens; if they are inverted, this is win!
-        if (term.invert()) {
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        }
-
-        return false;
-    }
-
-    bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        input.setPos(backTrack->begin);
-
-        context->term -= term.atom.parenthesesWidth;
-        return false;
-    }
-
-    JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
-
-        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
-
-        backTrack->matchAmount = 0;
-        backTrack->lastContext = 0;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            // While we haven't yet reached our fixed limit,
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                // Try to do a match, and it it succeeds, add it to the list.
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    // The match failed; try to find an alternate point to carry on from.
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result == JSRegExpNoMatch) {
-                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
-                        if (backtrackResult != JSRegExpMatch)
-                            return backtrackResult;
-                    } else
-                        return result;
-                }
-            }
-
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-            recordParenthesesMatch(term, context);
-            return JSRegExpMatch;
-        }
-
-        case QuantifierGreedy: {
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result != JSRegExpNoMatch)
-                        return result;
-
-                    break;
-                }
-            }
-
-            if (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                recordParenthesesMatch(term, context);
-            }
-            return JSRegExpMatch;
-        }
-
-        case QuantifierNonGreedy:
-            return JSRegExpMatch;
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    // Rules for backtracking differ depending on whether this is greedy or non-greedy.
-    //
-    // Greedy matches never should try just adding more - you should already have done
-    // the 'more' cases.  Always backtrack, at least a leetle bit.  However cases where
-    // you backtrack an item off the list needs checking, since we'll never have matched
-    // the one less case.  Tracking forwards, still add as much as possible.
-    //
-    // Non-greedy, we've already done the one less case, so don't match on popping.
-    // We haven't done the one more case, so always try to add that.
-    //
-    JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
-
-        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-
-            ParenthesesDisjunctionContext* context = 0;
-            JSRegExpResult result = parenthesesDoBacktrack(term, backTrack);
-
-            if (result != JSRegExpMatch)
-                return result;
-
-            // While we haven't yet reached our fixed limit,
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                // Try to do a match, and it it succeeds, add it to the list.
-                context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    // The match failed; try to find an alternate point to carry on from.
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result == JSRegExpNoMatch) {
-                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
-                        if (backtrackResult != JSRegExpMatch)
-                            return backtrackResult;
-                    } else
-                        return result;
-                }
-            }
-
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-            context = backTrack->lastContext;
-            recordParenthesesMatch(term, context);
-            return JSRegExpMatch;
-        }
-
-        case QuantifierGreedy: {
-            if (!backTrack->matchAmount)
-                return JSRegExpNoMatch;
-
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-            JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
-            if (result == JSRegExpMatch) {
-                while (backTrack->matchAmount < term.atom.quantityCount) {
-                    ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                    JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                    if (parenthesesResult == JSRegExpMatch)
-                        appendParenthesesDisjunctionContext(backTrack, context);
-                    else {
-                        resetMatches(term, context);
-                        freeParenthesesDisjunctionContext(context);
-
-                        if (parenthesesResult != JSRegExpNoMatch)
-                            return parenthesesResult;
-
-                        break;
-                    }
-                }
-            } else {
-                resetMatches(term, context);
-                popParenthesesDisjunctionContext(backTrack);
-                freeParenthesesDisjunctionContext(context);
-
-                if (result != JSRegExpNoMatch)
-                    return result;
-            }
-
-            if (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                recordParenthesesMatch(term, context);
-            }
-            return JSRegExpMatch;
-        }
-
-        case QuantifierNonGreedy: {
-            // If we've not reached the limit, try to add one more match.
-            if (backTrack->matchAmount < term.atom.quantityCount) {
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch) {
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                    recordParenthesesMatch(term, context);
-                    return JSRegExpMatch;
-                }
-
-                resetMatches(term, context);
-                freeParenthesesDisjunctionContext(context);
-
-                if (result != JSRegExpNoMatch)
-                    return result;
-            }
-
-            // Nope - okay backtrack looking for an alternative.
-            while (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
-                if (result == JSRegExpMatch) {
-                    // successful backtrack! we're back in the game!
-                    if (backTrack->matchAmount) {
-                        context = backTrack->lastContext;
-                        recordParenthesesMatch(term, context);
-                    }
-                    return JSRegExpMatch;
-                }
-
-                // pop a match off the stack
-                resetMatches(term, context);
-                popParenthesesDisjunctionContext(backTrack);
-                freeParenthesesDisjunctionContext(context);
-
-                return result;
-            }
-
-            return JSRegExpNoMatch;
-        }
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    void lookupForBeginChars()
-    {
-        int character;
-        bool firstSingleCharFound;
-
-        while (true) {
-            if (input.isNotAvailableInput(2))
-                return;
-
-            firstSingleCharFound = false;
-
-            character = input.readPair();
-
-            for (unsigned i = 0; i < pattern->m_beginChars.size(); ++i) {
-                BeginChar bc = pattern->m_beginChars[i];
-
-                if (!firstSingleCharFound && bc.value <= 0xFFFF) {
-                    firstSingleCharFound = true;
-                    character &= 0xFFFF;
-                }
-
-                if ((character | bc.mask) == bc.value)
-                    return;
-            }
-
-            input.next();
-        }
-    }
-
-#define MATCH_NEXT() { ++context->term; goto matchAgain; }
-#define BACKTRACK() { --context->term; goto backtrack; }
-#define currentTerm() (disjunction->terms[context->term])
-    JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false, bool isBody = false)
-    {
-        if (!--remainingMatchCount)
-            return JSRegExpErrorHitLimit;
-
-        if (btrack)
-            BACKTRACK();
-
-        if (pattern->m_containsBeginChars && isBody)
-            lookupForBeginChars();
-
-        context->matchBegin = input.getPos();
-        context->term = 0;
-
-    matchAgain:
-        ASSERT(context->term < static_cast(disjunction->terms.size()));
-
-        switch (currentTerm().type) {
-        case ByteTerm::TypeSubpatternBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeSubpatternEnd:
-            context->matchEnd = input.getPos();
-            return JSRegExpMatch;
-
-        case ByteTerm::TypeBodyAlternativeBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeBodyAlternativeDisjunction:
-        case ByteTerm::TypeBodyAlternativeEnd:
-            context->matchEnd = input.getPos();
-            return JSRegExpMatch;
-
-        case ByteTerm::TypeAlternativeBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeAlternativeDisjunction:
-        case ByteTerm::TypeAlternativeEnd: {
-            int offset = currentTerm().alternative.end;
-            BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->offset = offset;
-            context->term += offset;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypeAssertionBOL:
-            if (matchAssertionBOL(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeAssertionEOL:
-            if (matchAssertionEOL(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeAssertionWordBoundary:
-            if (matchAssertionWordBoundary(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-
-        case ByteTerm::TypePatternCharacterOnce:
-        case ByteTerm::TypePatternCharacterFixed: {
-            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
-                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + matchAmount))
-                    BACKTRACK();
-            }
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCharacterGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            unsigned matchAmount = 0;
-            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCharacterNonGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->matchAmount = 0;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypePatternCasedCharacterOnce:
-        case ByteTerm::TypePatternCasedCharacterFixed: {
-            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
-                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + matchAmount))
-                    BACKTRACK();
-            }
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCasedCharacterGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            unsigned matchAmount = 0;
-            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCasedCharacterNonGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->matchAmount = 0;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypeCharacterClass:
-            if (matchCharacterClass(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeBackReference:
-            if (matchBackReference(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpattern: {
-            JSRegExpResult result = matchParentheses(currentTerm(), context);
-
-            if (result == JSRegExpMatch) {
-                MATCH_NEXT();
-            }  else if (result != JSRegExpNoMatch)
-                return result;
-
-            BACKTRACK();
-        }
-        case ByteTerm::TypeParenthesesSubpatternOnceBegin:
-            if (matchParenthesesOnceBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternOnceEnd:
-            if (matchParenthesesOnceEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
-            if (matchParenthesesTerminalBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
-            if (matchParenthesesTerminalEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParentheticalAssertionBegin:
-            if (matchParentheticalAssertionBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParentheticalAssertionEnd:
-            if (matchParentheticalAssertionEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-
-        case ByteTerm::TypeCheckInput:
-            if (input.checkInput(currentTerm().checkInputCount))
-                MATCH_NEXT();
-            BACKTRACK();
-
-            case ByteTerm::TypeUncheckInput:
-                input.uncheckInput(currentTerm().checkInputCount);
-                MATCH_NEXT();
-        }
-
-        // We should never fall-through to here.
-        ASSERT_NOT_REACHED();
-
-    backtrack:
-        ASSERT(context->term < static_cast(disjunction->terms.size()));
-
-        switch (currentTerm().type) {
-        case ByteTerm::TypeSubpatternBegin:
-            return JSRegExpNoMatch;
-        case ByteTerm::TypeSubpatternEnd:
-            ASSERT_NOT_REACHED();
-
-        case ByteTerm::TypeBodyAlternativeBegin:
-        case ByteTerm::TypeBodyAlternativeDisjunction: {
-            int offset = currentTerm().alternative.next;
-            context->term += offset;
-            if (offset > 0)
-                MATCH_NEXT();
-
-            if (input.atEnd())
-                return JSRegExpNoMatch;
-
-            input.next();
-
-            if (pattern->m_containsBeginChars && isBody)
-                lookupForBeginChars();
-
-            context->matchBegin = input.getPos();
-
-            if (currentTerm().alternative.onceThrough)
-                context->term += currentTerm().alternative.next;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypeBodyAlternativeEnd:
-            ASSERT_NOT_REACHED();
-
-            case ByteTerm::TypeAlternativeBegin:
-            case ByteTerm::TypeAlternativeDisjunction: {
-                int offset = currentTerm().alternative.next;
-                context->term += offset;
-                if (offset > 0)
-                    MATCH_NEXT();
-                BACKTRACK();
-            }
-            case ByteTerm::TypeAlternativeEnd: {
-                // We should never backtrack back into an alternative of the main body of the regex.
-                BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-                unsigned offset = backTrack->offset;
-                context->term -= offset;
-                BACKTRACK();
-            }
-
-            case ByteTerm::TypeAssertionBOL:
-            case ByteTerm::TypeAssertionEOL:
-            case ByteTerm::TypeAssertionWordBoundary:
-                BACKTRACK();
-
-            case ByteTerm::TypePatternCharacterOnce:
-            case ByteTerm::TypePatternCharacterFixed:
-            case ByteTerm::TypePatternCharacterGreedy:
-            case ByteTerm::TypePatternCharacterNonGreedy:
-                if (backtrackPatternCharacter(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypePatternCasedCharacterOnce:
-            case ByteTerm::TypePatternCasedCharacterFixed:
-            case ByteTerm::TypePatternCasedCharacterGreedy:
-            case ByteTerm::TypePatternCasedCharacterNonGreedy:
-                if (backtrackPatternCasedCharacter(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeCharacterClass:
-                if (backtrackCharacterClass(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeBackReference:
-                if (backtrackBackReference(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpattern: {
-                JSRegExpResult result = backtrackParentheses(currentTerm(), context);
-
-                if (result == JSRegExpMatch) {
-                    MATCH_NEXT();
-                } else if (result != JSRegExpNoMatch)
-                    return result;
-
-                BACKTRACK();
-            }
-            case ByteTerm::TypeParenthesesSubpatternOnceBegin:
-                if (backtrackParenthesesOnceBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternOnceEnd:
-                if (backtrackParenthesesOnceEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
-                if (backtrackParenthesesTerminalBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
-                if (backtrackParenthesesTerminalEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParentheticalAssertionBegin:
-                if (backtrackParentheticalAssertionBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParentheticalAssertionEnd:
-                if (backtrackParentheticalAssertionEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-
-            case ByteTerm::TypeCheckInput:
-                input.uncheckInput(currentTerm().checkInputCount);
-                BACKTRACK();
-
-            case ByteTerm::TypeUncheckInput:
-                input.checkInput(currentTerm().checkInputCount);
-                BACKTRACK();
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
-    {
-        JSRegExpResult result = matchDisjunction(disjunction, context, btrack);
-
-        if (result == JSRegExpMatch) {
-            while (context->matchBegin == context->matchEnd) {
-                result = matchDisjunction(disjunction, context, true);
-                if (result != JSRegExpMatch)
-                    return result;
-            }
-            return JSRegExpMatch;
-        }
-
-        return result;
-    }
-
-    int interpret()
-    {
-        allocatorPool = pattern->m_allocator->startAllocator();
-        if (!allocatorPool)
-            CRASH();
-
-        for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i)
-            output[i] = -1;
-
-        DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get());
-
-        JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false, true);
-        if (result == JSRegExpMatch) {
-            output[0] = context->matchBegin;
-            output[1] = context->matchEnd;
-        }
-
-        freeDisjunctionContext(context);
-
-        pattern->m_allocator->stopAllocator();
-
-        // RegExp.cpp currently expects all error to be converted to -1.
-        ASSERT((result == JSRegExpMatch) == (output[0] != -1));
-        return output[0];
-    }
-
-    Interpreter(BytecodePattern* pattern, int* output, const UChar* inputChar, unsigned start, unsigned length)
-        : pattern(pattern)
-        , output(output)
-        , input(inputChar, start, length)
-        , allocatorPool(0)
-        , remainingMatchCount(matchLimit)
-    {
-    }
-
-private:
-    BytecodePattern* pattern;
-    int* output;
-    InputStream input;
-    BumpPointerPool* allocatorPool;
-    unsigned remainingMatchCount;
-};
-
-
-
-class ByteCompiler {
-    struct ParenthesesStackEntry {
-        unsigned beginTerm;
-        unsigned savedAlternativeIndex;
-        // For js::Vector. Does not create a valid object.
-        ParenthesesStackEntry() {}
-        ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/)
-            : beginTerm(beginTerm)
-            , savedAlternativeIndex(savedAlternativeIndex)
-        {
-        }
-    };
-
-public:
-    ByteCompiler(YarrPattern& pattern)
-        : m_pattern(pattern)
-    {
-        m_currentAlternativeIndex = 0;
-    }
-
-    PassOwnPtr compile(BumpPointerAllocator* allocator)
-    {
-        regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough());
-        emitDisjunction(m_pattern.m_body);
-        regexEnd();
-
-        return adoptPtr(js::OffTheBooks::new_(m_bodyDisjunction.release(), m_allParenthesesInfo, m_pattern, allocator));
-    }
-
-    void checkInput(unsigned count)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count));
-    }
-
-    void uncheckInput(unsigned count)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::UncheckInput(count));
-    }
-    
-    void assertionBOL(int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition));
-    }
-
-    void assertionEOL(int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition));
-    }
-
-    void assertionWordBoundary(bool invert, int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition));
-    }
-
-    void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        if (m_pattern.m_ignoreCase) {
-            UChar lo = Unicode::toLower(ch);
-            UChar hi = Unicode::toUpper(ch);
-
-            if (lo != hi) {
-                m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType));
-                return;
-            }
-        }
-
-        m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType));
-    }
-
-    void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition));
-
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-    }
-
-    void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        ASSERT(subpatternId);
-
-        m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition));
-
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin,
-        // then fix this up at the end! - simplifying this should make it much clearer.
-        // https://bugs.webkit.org/show_bug.cgi?id=50136
-
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, false, invert, 0));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParentheticalAssertionEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin);
-
-        bool invert = m_bodyDisjunction->terms[beginTerm].invert();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, false, invert, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    unsigned popParenthesesStack()
-    {
-        ASSERT(m_parenthesesStack.size());
-        int stackEnd = m_parenthesesStack.size() - 1;
-        unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm;
-        m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex;
-        m_parenthesesStack.shrink(stackEnd);
-
-        ASSERT(beginTerm < m_bodyDisjunction->terms.size());
-        ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size());
-
-        return beginTerm;
-    }
-
-#ifndef NDEBUG
-    void dumpDisjunction(ByteDisjunction* disjunction)
-    {
-        printf("ByteDisjunction(%p):\n\t", disjunction);
-        for (unsigned i = 0; i < disjunction->terms.size(); ++i)
-            printf("{ %d } ", disjunction->terms[i].type);
-        printf("\n");
-    }
-#endif
-
-    void closeAlternative(int beginTerm)
-    {
-        int origBeginTerm = beginTerm;
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin);
-        int endIndex = m_bodyDisjunction->terms.size();
-
-        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
-
-        if (!m_bodyDisjunction->terms[beginTerm].alternative.next)
-            m_bodyDisjunction->terms.remove(beginTerm);
-        else {
-            while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
-                beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
-                ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction);
-                m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
-                m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-            }
-
-            m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
-
-            m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd());
-            m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
-        }
-    }
-
-    void closeBodyAlternative()
-    {
-        int beginTerm = 0;
-        int origBeginTerm = 0;
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin);
-        int endIndex = m_bodyDisjunction->terms.size();
-
-        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
-
-        while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
-            beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
-            ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction);
-            m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
-            m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-        }
-
-        m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
-
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd());
-        m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-
-        ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
-
-        bool capture = parenthesesBegin.capture();
-        unsigned subpatternId = parenthesesBegin.atom.subpatternId;
-
-        unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
-        ByteDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(numSubpatterns, callFrameSize);
-
-        parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
-        for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
-            parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
-        parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
-
-        m_bodyDisjunction->terms.shrink(beginTerm);
-
-        m_allParenthesesInfo.append(parenthesesDisjunction);
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, inputPosition));
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-
-        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-
-        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough)
-    {
-        m_bodyDisjunction = adoptPtr(js::OffTheBooks::new_(numSubpatterns, callFrameSize));
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough));
-        m_bodyDisjunction->terms[0].frameLocation = 0;
-        m_currentAlternativeIndex = 0;
-    }
-
-    void regexEnd()
-    {
-        closeBodyAlternative();
-    }
-
-    void alternativeBodyDisjunction(bool onceThrough)
-    {
-        int newAlternativeIndex = m_bodyDisjunction->terms.size();
-        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough));
-
-        m_currentAlternativeIndex = newAlternativeIndex;
-    }
-
-    void alternativeDisjunction()
-    {
-        int newAlternativeIndex = m_bodyDisjunction->terms.size();
-        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction());
-
-        m_currentAlternativeIndex = newAlternativeIndex;
-    }
-
-    void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0)
-    {
-        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
-            unsigned currentCountAlreadyChecked = inputCountAlreadyChecked;
-
-            PatternAlternative* alternative = disjunction->m_alternatives[alt];
-
-            if (alt) {
-                if (disjunction == m_pattern.m_body)
-                    alternativeBodyDisjunction(alternative->onceThrough());
-                else
-                    alternativeDisjunction();
-            }
-
-            unsigned minimumSize = alternative->m_minimumSize;
-            int countToCheck = minimumSize - parenthesesInputCountAlreadyChecked;
-
-            ASSERT(countToCheck >= 0);
-            if (countToCheck) {
-                checkInput(countToCheck);
-                currentCountAlreadyChecked += countToCheck;
-            }
-
-            for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
-                PatternTerm& term = alternative->m_terms[i];
-
-                switch (term.type) {
-                case PatternTerm::TypeAssertionBOL:
-                    assertionBOL(term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypeAssertionEOL:
-                    assertionEOL(term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypeAssertionWordBoundary:
-                    assertionWordBoundary(term.invert(), term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypePatternCharacter:
-                    atomPatternCharacter(term.patternCharacter, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                    break;
-
-                case PatternTerm::TypeCharacterClass:
-                    atomCharacterClass(term.characterClass, term.invert(), term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                    break;
-
-                case PatternTerm::TypeBackReference:
-                    atomBackReference(term.backReferenceSubpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                        break;
-
-                case PatternTerm::TypeForwardReference:
-                    break;
-
-                case PatternTerm::TypeParenthesesSubpattern: {
-                    unsigned disjunctionAlreadyCheckedCount = 0;
-                    if (term.quantityCount == 1 && !term.parentheses.isCopy) {
-                        unsigned alternativeFrameLocation = term.frameLocation;
-                        // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame.
-                        if (term.quantityType == QuantifierFixedCount)
-                            disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize;
-                        else
-                            alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, alternativeFrameLocation);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
-                        atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
-                    } else if (term.parentheses.isTerminal) {
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
-                        atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
-                    } else {
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
-                        atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
-                    }
-                    break;
-                }
-
-                case PatternTerm::TypeParentheticalAssertion: {
-                    unsigned alternativeFrameLocation = term.frameLocation + YarrStackSpaceForBackTrackInfoParentheticalAssertion;
-
-                    ASSERT(currentCountAlreadyChecked >= static_cast(term.inputPosition));
-                    int positiveInputOffset = currentCountAlreadyChecked - term.inputPosition;
-                    int uncheckAmount = positiveInputOffset - term.parentheses.disjunction->m_minimumSize;
-
-                    if (uncheckAmount > 0) {
-                        uncheckInput(uncheckAmount);
-                        currentCountAlreadyChecked -= uncheckAmount;
-                    } else
-                        uncheckAmount = 0;
-
-                    atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation);
-                    emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount);
-                    atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType);
-                    if (uncheckAmount) {
-                        checkInput(uncheckAmount);
-                        currentCountAlreadyChecked += uncheckAmount;
-                    }
-                    break;
-                }
-                }
-            }
-        }
-    }
-
-private:
-    YarrPattern& m_pattern;
-    OwnPtr m_bodyDisjunction;
-    unsigned m_currentAlternativeIndex;
-    Vector m_parenthesesStack;
-    Vector m_allParenthesesInfo;
-};
-
-PassOwnPtr byteCompile(YarrPattern& pattern, BumpPointerAllocator* allocator)
-{
-    return ByteCompiler(pattern).compile(allocator);
-}
-
-int interpret(BytecodePattern* bytecode, const UChar* input, unsigned start, unsigned length, int* output)
-{
-    return Interpreter(bytecode, output, input, start, length).interpret();
-}
-
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoPatternCharacter);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoCharacterClass);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoBackReference);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);
-
-
-} }
diff --git a/js/src/yarr/YarrInterpreter.h b/js/src/yarr/YarrInterpreter.h
deleted file mode 100644
index 32b72858cad1..000000000000
--- a/js/src/yarr/YarrInterpreter.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/* -*- 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, 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef YarrInterpreter_h
-#define YarrInterpreter_h
-
-#include "YarrPattern.h"
-
-namespace WTF {
-class BumpPointerAllocator;
-}
-using WTF::BumpPointerAllocator;
-
-namespace JSC { namespace Yarr {
-
-class ByteDisjunction;
-
-struct ByteTerm {
-    enum Type {
-        TypeBodyAlternativeBegin,
-        TypeBodyAlternativeDisjunction,
-        TypeBodyAlternativeEnd,
-        TypeAlternativeBegin,
-        TypeAlternativeDisjunction,
-        TypeAlternativeEnd,
-        TypeSubpatternBegin,
-        TypeSubpatternEnd,
-        TypeAssertionBOL,
-        TypeAssertionEOL,
-        TypeAssertionWordBoundary,
-        TypePatternCharacterOnce,
-        TypePatternCharacterFixed,
-        TypePatternCharacterGreedy,
-        TypePatternCharacterNonGreedy,
-        TypePatternCasedCharacterOnce,
-        TypePatternCasedCharacterFixed,
-        TypePatternCasedCharacterGreedy,
-        TypePatternCasedCharacterNonGreedy,
-        TypeCharacterClass,
-        TypeBackReference,
-        TypeParenthesesSubpattern,
-        TypeParenthesesSubpatternOnceBegin,
-        TypeParenthesesSubpatternOnceEnd,
-        TypeParenthesesSubpatternTerminalBegin,
-        TypeParenthesesSubpatternTerminalEnd,
-        TypeParentheticalAssertionBegin,
-        TypeParentheticalAssertionEnd,
-        TypeCheckInput,
-        TypeUncheckInput
-    } type;
-    union {
-        struct {
-            union {
-                UChar patternCharacter;
-                struct {
-                    UChar lo;
-                    UChar hi;
-                } casedCharacter;
-                CharacterClass* characterClass;
-                unsigned subpatternId;
-            };
-            union {
-                ByteDisjunction* parenthesesDisjunction;
-                unsigned parenthesesWidth;
-            };
-            QuantifierType quantityType;
-            unsigned quantityCount;
-        } atom;
-        struct {
-            int next;
-            int end;
-            bool onceThrough;
-        } alternative;
-        unsigned checkInputCount;
-    };
-    unsigned frameLocation;
-    bool m_capture : 1;
-    bool m_invert : 1;
-    int inputPosition;
-
-    // For js::Vector. Does not create a valid object.
-    ByteTerm()
-    {
-    }
-
-    ByteTerm(UChar ch, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-        : frameLocation(frameLocation)
-        , m_capture(false)
-        , m_invert(false)
-    {
-        switch (quantityType) {
-        case QuantifierFixedCount:
-            type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed;
-            break;
-        case QuantifierGreedy:
-            type = ByteTerm::TypePatternCharacterGreedy;
-            break;
-        case QuantifierNonGreedy:
-            type = ByteTerm::TypePatternCharacterNonGreedy;
-            break;
-        }
-
-        atom.patternCharacter = ch;
-        atom.quantityType = quantityType;
-        atom.quantityCount = quantityCount;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-        : frameLocation(frameLocation)
-        , m_capture(false)
-        , m_invert(false)
-    {
-        switch (quantityType) {
-        case QuantifierFixedCount:
-            type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed;
-            break;
-        case QuantifierGreedy:
-            type = ByteTerm::TypePatternCasedCharacterGreedy;
-            break;
-        case QuantifierNonGreedy:
-            type = ByteTerm::TypePatternCasedCharacterNonGreedy;
-            break;
-        }
-
-        atom.casedCharacter.lo = lo;
-        atom.casedCharacter.hi = hi;
-        atom.quantityType = quantityType;
-        atom.quantityCount = quantityCount;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(CharacterClass* characterClass, bool invert, int inputPos)
-        : type(ByteTerm::TypeCharacterClass)
-        , m_capture(false)
-        , m_invert(invert)
-    {
-        atom.characterClass = characterClass;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool capture, int inputPos)
-        : type(type)
-        , m_capture(capture)
-        , m_invert(false)
-    {
-        atom.subpatternId = subpatternId;
-        atom.parenthesesDisjunction = parenthesesInfo;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-    
-    ByteTerm(Type type, bool invert = false)
-        : type(type)
-        , m_capture(false)
-        , m_invert(invert)
-    {
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-    }
-
-    ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, int inputPos)
-        : type(type)
-        , m_capture(capture)
-        , m_invert(invert)
-    {
-        atom.subpatternId = subpatternId;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-
-    static ByteTerm BOL(int inputPos)
-    {
-        ByteTerm term(TypeAssertionBOL);
-        term.inputPosition = inputPos;
-        return term;
-    }
-
-    static ByteTerm CheckInput(unsigned count)
-    {
-        ByteTerm term(TypeCheckInput);
-        term.checkInputCount = count;
-        return term;
-    }
-
-    static ByteTerm UncheckInput(unsigned count)
-    {
-        ByteTerm term(TypeUncheckInput);
-        term.checkInputCount = count;
-        return term;
-    }
-    
-    static ByteTerm EOL(int inputPos)
-    {
-        ByteTerm term(TypeAssertionEOL);
-        term.inputPosition = inputPos;
-        return term;
-    }
-
-    static ByteTerm WordBoundary(bool invert, int inputPos)
-    {
-        ByteTerm term(TypeAssertionWordBoundary, invert);
-        term.inputPosition = inputPos;
-        return term;
-    }
-    
-    static ByteTerm BackReference(unsigned subpatternId, int inputPos)
-    {
-        return ByteTerm(TypeBackReference, subpatternId, false, false, inputPos);
-    }
-
-    static ByteTerm BodyAlternativeBegin(bool onceThrough)
-    {
-        ByteTerm term(TypeBodyAlternativeBegin);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = onceThrough;
-        return term;
-    }
-
-    static ByteTerm BodyAlternativeDisjunction(bool onceThrough)
-    {
-        ByteTerm term(TypeBodyAlternativeDisjunction);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = onceThrough;
-        return term;
-    }
-
-    static ByteTerm BodyAlternativeEnd()
-    {
-        ByteTerm term(TypeBodyAlternativeEnd);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeBegin()
-    {
-        ByteTerm term(TypeAlternativeBegin);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeDisjunction()
-    {
-        ByteTerm term(TypeAlternativeDisjunction);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeEnd()
-    {
-        ByteTerm term(TypeAlternativeEnd);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm SubpatternBegin()
-    {
-        return ByteTerm(TypeSubpatternBegin);
-    }
-
-    static ByteTerm SubpatternEnd()
-    {
-        return ByteTerm(TypeSubpatternEnd);
-    }
-
-    bool invert()
-    {
-        return m_invert;
-    }
-
-    bool capture()
-    {
-        return m_capture;
-    }
-};
-
-class ByteDisjunction {
-    WTF_MAKE_FAST_ALLOCATED
-public:
-    ByteDisjunction(unsigned numSubpatterns, unsigned frameSize)
-        : m_numSubpatterns(numSubpatterns)
-        , m_frameSize(frameSize)
-    {
-    }
-
-    Vector terms;
-    unsigned m_numSubpatterns;
-    unsigned m_frameSize;
-};
-
-struct BytecodePattern {
-    WTF_MAKE_FAST_ALLOCATED
-public:
-    BytecodePattern(PassOwnPtr body, Vector allParenthesesInfo, YarrPattern& pattern, BumpPointerAllocator* allocator)
-        : m_body(body)
-        , m_ignoreCase(pattern.m_ignoreCase)
-        , m_multiline(pattern.m_multiline)
-        , m_containsBeginChars(pattern.m_containsBeginChars)
-        , m_allocator(allocator)
-    {
-        newlineCharacterClass = pattern.newlineCharacterClass();
-        wordcharCharacterClass = pattern.wordcharCharacterClass();
-
-        m_allParenthesesInfo.append(allParenthesesInfo);
-        m_userCharacterClasses.append(pattern.m_userCharacterClasses);
-        // 'Steal' the YarrPattern's CharacterClasses!  We clear its
-        // array, so that it won't delete them on destruction.  We'll
-        // take responsibility for that.
-        pattern.m_userCharacterClasses.clear();
-
-        m_beginChars.append(pattern.m_beginChars);
-    }
-
-    ~BytecodePattern()
-    {
-        deleteAllValues(m_allParenthesesInfo);
-        deleteAllValues(m_userCharacterClasses);
-    }
-
-    OwnPtr m_body;
-    bool m_ignoreCase;
-    bool m_multiline;
-    bool m_containsBeginChars;
-    // Each BytecodePattern is associated with a RegExp, each RegExp is associated
-    // with a JSGlobalData.  Cache a pointer to out JSGlobalData's m_regExpAllocator.
-    BumpPointerAllocator* m_allocator;
-
-    CharacterClass* newlineCharacterClass;
-    CharacterClass* wordcharCharacterClass;
-
-    Vector m_beginChars;
-
-private:
-    Vector m_allParenthesesInfo;
-    Vector m_userCharacterClasses;
-};
-
-} } // namespace JSC::Yarr
-
-#endif // YarrInterpreter_h
diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp
deleted file mode 100644
index c0187f240b6d..000000000000
--- a/js/src/yarr/YarrJIT.cpp
+++ /dev/null
@@ -1,2405 +0,0 @@
-/* -*- 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.
- *
- * 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "YarrJIT.h"
-
-#include "assembler/assembler/LinkBuffer.h"
-#include "Yarr.h"
-
-#if ENABLE_YARR_JIT
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-class YarrGenerator : private MacroAssembler {
-    friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
-
-#if WTF_CPU_ARM
-    static const RegisterID input = ARMRegisters::r0;
-    static const RegisterID index = ARMRegisters::r1;
-    static const RegisterID length = ARMRegisters::r2;
-    static const RegisterID output = ARMRegisters::r4;
-
-    static const RegisterID regT0 = ARMRegisters::r5;
-    static const RegisterID regT1 = ARMRegisters::r6;
-
-    static const RegisterID returnRegister = ARMRegisters::r0;
-#elif WTF_CPU_MIPS
-    static const RegisterID input = MIPSRegisters::a0;
-    static const RegisterID index = MIPSRegisters::a1;
-    static const RegisterID length = MIPSRegisters::a2;
-    static const RegisterID output = MIPSRegisters::a3;
-
-    static const RegisterID regT0 = MIPSRegisters::t4;
-    static const RegisterID regT1 = MIPSRegisters::t5;
-
-    static const RegisterID returnRegister = MIPSRegisters::v0;
-#elif WTF_CPU_SH4
-    static const RegisterID input = SH4Registers::r4;
-    static const RegisterID index = SH4Registers::r5;
-    static const RegisterID length = SH4Registers::r6;
-    static const RegisterID output = SH4Registers::r7;
-
-    static const RegisterID regT0 = SH4Registers::r0;
-    static const RegisterID regT1 = SH4Registers::r1;
-
-    static const RegisterID returnRegister = SH4Registers::r0;
-#elif WTF_CPU_X86
-    static const RegisterID input = X86Registers::eax;
-    static const RegisterID index = X86Registers::edx;
-    static const RegisterID length = X86Registers::ecx;
-    static const RegisterID output = X86Registers::edi;
-
-    static const RegisterID regT0 = X86Registers::ebx;
-    static const RegisterID regT1 = X86Registers::esi;
-
-    static const RegisterID returnRegister = X86Registers::eax;
-#elif WTF_CPU_X86_64
-    static const RegisterID input = X86Registers::edi;
-    static const RegisterID index = X86Registers::esi;
-    static const RegisterID length = X86Registers::edx;
-    static const RegisterID output = X86Registers::ecx;
-
-    static const RegisterID regT0 = X86Registers::eax;
-    static const RegisterID regT1 = X86Registers::ebx;
-
-    static const RegisterID returnRegister = X86Registers::eax;
-#endif
-
-    void optimizeAlternative(PatternAlternative* alternative)
-    {
-        if (!alternative->m_terms.size())
-            return;
-
-        for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) {
-            PatternTerm& term = alternative->m_terms[i];
-            PatternTerm& nextTerm = alternative->m_terms[i + 1];
-
-            if ((term.type == PatternTerm::TypeCharacterClass)
-                && (term.quantityType == QuantifierFixedCount)
-                && (nextTerm.type == PatternTerm::TypePatternCharacter)
-                && (nextTerm.quantityType == QuantifierFixedCount)) {
-                PatternTerm termCopy = term;
-                alternative->m_terms[i] = nextTerm;
-                alternative->m_terms[i + 1] = termCopy;
-            }
-        }
-    }
-
-    void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount)
-    {
-        do {
-            // pick which range we're going to generate
-            int which = count >> 1;
-            char lo = ranges[which].begin;
-            char hi = ranges[which].end;
-
-            // check if there are any ranges or matches below lo.  If not, just jl to failure -
-            // if there is anything else to check, check that first, if it falls through jmp to failure.
-            if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
-                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
-
-                // generate code for all ranges before this one
-                if (which)
-                    matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
-
-                while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
-                    matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex])));
-                    ++*matchIndex;
-                }
-                failures.append(jump());
-
-                loOrAbove.link(this);
-            } else if (which) {
-                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
-
-                matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
-                failures.append(jump());
-
-                loOrAbove.link(this);
-            } else
-                failures.append(branch32(LessThan, character, Imm32((unsigned short)lo)));
-
-            while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi))
-                ++*matchIndex;
-
-            matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi)));
-            // fall through to here, the value is above hi.
-
-            // shuffle along & loop around if there are any more matches to handle.
-            unsigned next = which + 1;
-            ranges += next;
-            count -= next;
-        } while (count);
-    }
-
-    void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass)
-    {
-        if (charClass->m_table) {
-            ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table));
-            matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry));
-            return;
-        }
-        Jump unicodeFail;
-        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) {
-            Jump isAscii = branch32(LessThanOrEqual, character, TrustedImm32(0x7f));
-
-            if (charClass->m_matchesUnicode.size()) {
-                for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) {
-                    UChar ch = charClass->m_matchesUnicode[i];
-                    matchDest.append(branch32(Equal, character, Imm32(ch)));
-                }
-            }
-
-            if (charClass->m_rangesUnicode.size()) {
-                for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) {
-                    UChar lo = charClass->m_rangesUnicode[i].begin;
-                    UChar hi = charClass->m_rangesUnicode[i].end;
-
-                    Jump below = branch32(LessThan, character, Imm32(lo));
-                    matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi)));
-                    below.link(this);
-                }
-            }
-
-            unicodeFail = jump();
-            isAscii.link(this);
-        }
-
-        if (charClass->m_ranges.size()) {
-            unsigned matchIndex = 0;
-            JumpList failures;
-            matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size());
-            while (matchIndex < charClass->m_matches.size())
-                matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++])));
-
-            failures.link(this);
-        } else if (charClass->m_matches.size()) {
-            // optimization: gather 'a','A' etc back together, can mask & test once.
-            Vector matchesAZaz;
-
-            for (unsigned i = 0; i < charClass->m_matches.size(); ++i) {
-                char ch = charClass->m_matches[i];
-                if (m_pattern.m_ignoreCase) {
-                    if (isASCIILower(ch)) {
-                        matchesAZaz.append(ch);
-                        continue;
-                    }
-                    if (isASCIIUpper(ch))
-                        continue;
-                }
-                matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch)));
-            }
-
-            if (unsigned countAZaz = matchesAZaz.size()) {
-                or32(TrustedImm32(32), character);
-                for (unsigned i = 0; i < countAZaz; ++i)
-                    matchDest.append(branch32(Equal, character, TrustedImm32(matchesAZaz[i])));
-            }
-        }
-
-        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size())
-            unicodeFail.link(this);
-    }
-
-    // Jumps if input not available; will have (incorrectly) incremented already!
-    Jump jumpIfNoAvailableInput(unsigned countToCheck = 0)
-    {
-        if (countToCheck)
-            add32(Imm32(countToCheck), index);
-        return branch32(Above, index, length);
-    }
-
-    Jump jumpIfAvailableInput(unsigned countToCheck)
-    {
-        add32(Imm32(countToCheck), index);
-        return branch32(BelowOrEqual, index, length);
-    }
-
-    Jump checkInput()
-    {
-        return branch32(BelowOrEqual, index, length);
-    }
-
-    Jump atEndOfInput()
-    {
-        return branch32(Equal, index, length);
-    }
-
-    Jump notAtEndOfInput()
-    {
-        return branch32(NotEqual, index, length);
-    }
-
-    Jump jumpIfCharEquals(UChar ch, int inputPosition)
-    {
-        return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
-    }
-
-    Jump jumpIfCharNotEquals(UChar ch, int inputPosition)
-    {
-        return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
-    }
-
-    void readCharacter(int inputPosition, RegisterID reg)
-    {
-        load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg);
-    }
-
-    void storeToFrame(RegisterID reg, unsigned frameLocation)
-    {
-        poke(reg, frameLocation);
-    }
-
-    void storeToFrame(TrustedImm32 imm, unsigned frameLocation)
-    {
-        poke(imm, frameLocation);
-    }
-
-    DataLabelPtr storeToFrameWithPatch(unsigned frameLocation)
-    {
-        return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*)));
-    }
-
-    void loadFromFrame(unsigned frameLocation, RegisterID reg)
-    {
-        peek(reg, frameLocation);
-    }
-
-    void loadFromFrameAndJump(unsigned frameLocation)
-    {
-        jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
-    }
-
-    enum YarrOpCode {
-        // These nodes wrap body alternatives - those in the main disjunction,
-        // rather than subpatterns or assertions. These are chained together in
-        // a doubly linked list, with a 'begin' node for the first alternative,
-        // a 'next' node for each subsequent alternative, and an 'end' node at
-        // the end. In the case of repeating alternatives, the 'end' node also
-        // has a reference back to 'begin'.
-        OpBodyAlternativeBegin,
-        OpBodyAlternativeNext,
-        OpBodyAlternativeEnd,
-        // Similar to the body alternatives, but used for subpatterns with two
-        // or more alternatives.
-        OpNestedAlternativeBegin,
-        OpNestedAlternativeNext,
-        OpNestedAlternativeEnd,
-        // Used for alternatives in subpatterns where there is only a single
-        // alternative (backtrackingis easier in these cases), or for alternatives
-        // which never need to be backtracked (those in parenthetical assertions,
-        // terminal subpatterns).
-        OpSimpleNestedAlternativeBegin,
-        OpSimpleNestedAlternativeNext,
-        OpSimpleNestedAlternativeEnd,
-        // Used to wrap 'Once' subpattern matches (quantityCount == 1).
-        OpParenthesesSubpatternOnceBegin,
-        OpParenthesesSubpatternOnceEnd,
-        // Used to wrap 'Terminal' subpattern matches (at the end of the regexp).
-        OpParenthesesSubpatternTerminalBegin,
-        OpParenthesesSubpatternTerminalEnd,
-        // Used to wrap parenthetical assertions.
-        OpParentheticalAssertionBegin,
-        OpParentheticalAssertionEnd,
-        // Wraps all simple terms (pattern characters, character classes).
-        OpTerm,
-        // Where an expression contains only 'once through' body alternatives
-        // and no repeating ones, this op is used to return match failure.
-        OpMatchFailed
-    };
-
-    // This structure is used to hold the compiled opcode information,
-    // including reference back to the original PatternTerm/PatternAlternatives,
-    // and JIT compilation data structures.
-    struct YarrOp {
-        explicit YarrOp(PatternTerm* term)
-            : m_op(OpTerm)
-            , m_term(term)
-            , m_isDeadCode(false)
-        {
-        }
-
-        explicit YarrOp(YarrOpCode op)
-            : m_op(op)
-            , m_isDeadCode(false)
-        {
-        }
-
-        // The operation, as a YarrOpCode, and also a reference to the PatternTerm.
-        YarrOpCode m_op;
-        PatternTerm* m_term;
-
-        // For alternatives, this holds the PatternAlternative and doubly linked
-        // references to this alternative's siblings. In the case of the
-        // OpBodyAlternativeEnd node at the end of a section of repeating nodes,
-        // m_nextOp will reference the OpBodyAlternativeBegin node of the first
-        // repeating alternative.
-        PatternAlternative* m_alternative;
-        size_t m_previousOp;
-        size_t m_nextOp;
-
-        // Used to record a set of Jumps out of the generated code, typically
-        // used for jumps out to backtracking code, and a single reentry back
-        // into the code for a node (likely where a backtrack will trigger
-        // rematching).
-        Label m_reentry;
-        JumpList m_jumps;
-
-        // This flag is used to null out the second pattern character, when
-        // two are fused to match a pair together.
-        bool m_isDeadCode;
-
-        // Currently used in the case of some of the more complex management of
-        // 'm_checked', to cache the offset used in this alternative, to avoid
-        // recalculating it.
-        int m_checkAdjust;
-
-        // Used by OpNestedAlternativeNext/End to hold the pointer to the
-        // value that will be pushed into the pattern's frame to return to,
-        // upon backtracking back into the disjunction.
-        DataLabelPtr m_returnAddress;
-    };
-
-    // BacktrackingState
-    // This class encapsulates information about the state of code generation
-    // whilst generating the code for backtracking, when a term fails to match.
-    // Upon entry to code generation of the backtracking code for a given node,
-    // the Backtracking state will hold references to all control flow sources
-    // that are outputs in need of further backtracking from the prior node
-    // generated (which is the subsequent operation in the regular expression,
-    // and in the m_ops Vector, since we generated backtracking backwards).
-    // These references to control flow take the form of:
-    //  - A jump list of jumps, to be linked to code that will backtrack them
-    //    further.
-    //  - A set of DataLabelPtr values, to be populated with values to be
-    //    treated effectively as return addresses backtracking into complex
-    //    subpatterns.
-    //  - A flag indicating that the current sequence of generated code up to
-    //    this point requires backtracking.
-    class BacktrackingState {
-    public:
-        BacktrackingState()
-            : m_pendingFallthrough(false)
-        {
-        }
-
-        // Add a jump or jumps, a return address, or set the flag indicating
-        // that the current 'fallthrough' control flow requires backtracking.
-        void append(const Jump& jump)
-        {
-            m_laterFailures.append(jump);
-        }
-        void append(JumpList& jumpList)
-        {
-            m_laterFailures.append(jumpList);
-        }
-        void append(const DataLabelPtr& returnAddress)
-        {
-            m_pendingReturns.append(returnAddress);
-        }
-        void fallthrough()
-        {
-            ASSERT(!m_pendingFallthrough);
-            m_pendingFallthrough = true;
-        }
-
-        // These methods clear the backtracking state, either linking to the
-        // current location, a provided label, or copying the backtracking out
-        // to a JumpList. All actions may require code generation to take place,
-        // and as such are passed a pointer to the assembler.
-        void link(MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                Label here(assembler);
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
-                m_pendingReturns.clear();
-            }
-            m_laterFailures.link(assembler);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-        void linkTo(Label label, MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], label));
-                m_pendingReturns.clear();
-            }
-            if (m_pendingFallthrough)
-                assembler->jump(label);
-            m_laterFailures.linkTo(label, assembler);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-        void takeBacktracksToJumpList(JumpList& jumpList, MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                Label here(assembler);
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
-                m_pendingReturns.clear();
-                m_pendingFallthrough = true;
-            }
-            if (m_pendingFallthrough)
-                jumpList.append(assembler->jump());
-            jumpList.append(m_laterFailures);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-
-        bool isEmpty()
-        {
-            return m_laterFailures.empty() && m_pendingReturns.isEmpty() && !m_pendingFallthrough;
-        }
-
-        // Called at the end of code generation to link all return addresses.
-        void linkDataLabels(LinkBuffer& linkBuffer)
-        {
-            ASSERT(isEmpty());
-            for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
-                linkBuffer.patch(m_backtrackRecords[i].m_dataLabel, linkBuffer.locationOf(m_backtrackRecords[i].m_backtrackLocation));
-        }
-
-    private:
-        struct ReturnAddressRecord {
-            ReturnAddressRecord(DataLabelPtr dataLabel, Label backtrackLocation)
-                : m_dataLabel(dataLabel)
-                , m_backtrackLocation(backtrackLocation)
-            {
-            }
-
-            DataLabelPtr m_dataLabel;
-            Label m_backtrackLocation;
-        };
-
-        JumpList m_laterFailures;
-        bool m_pendingFallthrough;
-        Vector m_pendingReturns;
-        Vector m_backtrackRecords;
-    };
-
-    // Generation methods:
-    // ===================
-
-    // This method provides a default implementation of backtracking common
-    // to many terms; terms commonly jump out of the forwards  matching path
-    // on any failed conditions, and add these jumps to the m_jumps list. If
-    // no special handling is required we can often just backtrack to m_jumps.
-    void backtrackTermDefault(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        m_backtrackingState.append(op.m_jumps);
-    }
-
-    void generateAssertionBOL(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        if (m_pattern.m_multiline) {
-            const RegisterID character = regT0;
-
-            JumpList matchDest;
-            if (!term->inputPosition)
-                matchDest.append(branch32(Equal, index, Imm32(m_checked)));
-
-            readCharacter((term->inputPosition - m_checked) - 1, character);
-            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
-            op.m_jumps.append(jump());
-
-            matchDest.link(this);
-        } else {
-            // Erk, really should poison out these alternatives early. :-/
-            if (term->inputPosition)
-                op.m_jumps.append(jump());
-            else
-                op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked)));
-        }
-    }
-    void backtrackAssertionBOL(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateAssertionEOL(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        if (m_pattern.m_multiline) {
-            const RegisterID character = regT0;
-
-            JumpList matchDest;
-            if (term->inputPosition == m_checked)
-                matchDest.append(atEndOfInput());
-
-            readCharacter((term->inputPosition - m_checked), character);
-            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
-            op.m_jumps.append(jump());
-
-            matchDest.link(this);
-        } else {
-            if (term->inputPosition == m_checked)
-                op.m_jumps.append(notAtEndOfInput());
-            // Erk, really should poison out these alternatives early. :-/
-            else
-                op.m_jumps.append(jump());
-        }
-    }
-    void backtrackAssertionEOL(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    // Also falls though on nextIsNotWordChar.
-    void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        if (term->inputPosition == m_checked)
-            nextIsNotWordChar.append(atEndOfInput());
-
-        readCharacter((term->inputPosition - m_checked), character);
-        matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass());
-    }
-
-    void generateAssertionWordBoundary(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        Jump atBegin;
-        JumpList matchDest;
-        if (!term->inputPosition)
-            atBegin = branch32(Equal, index, Imm32(m_checked));
-        readCharacter((term->inputPosition - m_checked) - 1, character);
-        matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass());
-        if (!term->inputPosition)
-            atBegin.link(this);
-
-        // We fall through to here if the last character was not a wordchar.
-        JumpList nonWordCharThenWordChar;
-        JumpList nonWordCharThenNonWordChar;
-        if (term->invert()) {
-            matchAssertionWordchar(opIndex, nonWordCharThenNonWordChar, nonWordCharThenWordChar);
-            nonWordCharThenWordChar.append(jump());
-        } else {
-            matchAssertionWordchar(opIndex, nonWordCharThenWordChar, nonWordCharThenNonWordChar);
-            nonWordCharThenNonWordChar.append(jump());
-        }
-        op.m_jumps.append(nonWordCharThenNonWordChar);
-
-        // We jump here if the last character was a wordchar.
-        matchDest.link(this);
-        JumpList wordCharThenWordChar;
-        JumpList wordCharThenNonWordChar;
-        if (term->invert()) {
-            matchAssertionWordchar(opIndex, wordCharThenNonWordChar, wordCharThenWordChar);
-            wordCharThenWordChar.append(jump());
-        } else {
-            matchAssertionWordchar(opIndex, wordCharThenWordChar, wordCharThenNonWordChar);
-            // This can fall-though!
-        }
-
-        op.m_jumps.append(wordCharThenWordChar);
-
-        nonWordCharThenWordChar.link(this);
-        wordCharThenNonWordChar.link(this);
-    }
-    void backtrackAssertionWordBoundary(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterOnce(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-
-        // m_ops always ends with a OpBodyAlternativeEnd or OpMatchFailed
-        // node, so there must always be at least one more node.
-        ASSERT(opIndex + 1 < m_ops.size());
-        YarrOp& nextOp = m_ops[opIndex + 1];
-
-        if (op.m_isDeadCode)
-            return;
-
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-
-        if (nextOp.m_op == OpTerm) {
-            PatternTerm* nextTerm = nextOp.m_term;
-            if (nextTerm->type == PatternTerm::TypePatternCharacter
-                && nextTerm->quantityType == QuantifierFixedCount
-                && nextTerm->quantityCount == 1
-                && nextTerm->inputPosition == (term->inputPosition + 1)) {
-
-                UChar ch2 = nextTerm->patternCharacter;
-
-                int mask = 0;
-                int chPair = ch | (ch2 << 16);
-
-                if (m_pattern.m_ignoreCase) {
-                    if (isASCIIAlpha(ch))
-                        mask |= 32;
-                    if (isASCIIAlpha(ch2))
-                        mask |= 32 << 16;
-                }
-
-                BaseIndex address(input, index, TimesTwo, (term->inputPosition - m_checked) * sizeof(UChar));
-                if (mask) {
-                    load32WithUnalignedHalfWords(address, character);
-                    or32(Imm32(mask), character);
-                    op.m_jumps.append(branch32(NotEqual, character, Imm32(chPair | mask)));
-                } else
-                    op.m_jumps.append(branch32WithUnalignedHalfWords(NotEqual, address, Imm32(chPair)));
-
-                nextOp.m_isDeadCode = true;
-                return;
-            }
-        }
-
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            op.m_jumps.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-    }
-    void backtrackPatternCharacterOnce(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterFixed(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(index, countRegister);
-        sub32(Imm32(term->quantityCount), countRegister);
-
-        Label loop(this);
-        BaseIndex address(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar));
-
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            load16(address, character);
-            or32(TrustedImm32(32), character);
-            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            op.m_jumps.append(branch16(NotEqual, address, Imm32(ch)));
-        }
-        add32(TrustedImm32(1), countRegister);
-        branch32(NotEqual, countRegister, index).linkTo(loop, this);
-    }
-    void backtrackPatternCharacterFixed(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-
-        JumpList failures;
-        Label loop(this);
-        failures.append(atEndOfInput());
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-        if (term->quantityCount == quantifyInfinite)
-            jump(loop);
-        else
-            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
-
-        failures.link(this);
-        op.m_reentry = label();
-
-        storeToFrame(countRegister, term->frameLocation);
-
-    }
-    void backtrackPatternCharacterGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-        m_backtrackingState.append(branchTest32(Zero, countRegister));
-        sub32(TrustedImm32(1), countRegister);
-        sub32(TrustedImm32(1), index);
-        jump(op.m_reentry);
-    }
-
-    void generatePatternCharacterNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-        op.m_reentry = label();
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackPatternCharacterNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        JumpList nonGreedyFailures;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-
-        nonGreedyFailures.append(atEndOfInput());
-        if (term->quantityCount != quantifyInfinite)
-            nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            nonGreedyFailures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-
-        jump(op.m_reentry);
-
-        nonGreedyFailures.link(this);
-        sub32(countRegister, index);
-        m_backtrackingState.fallthrough();
-    }
-
-    void generateCharacterClassOnce(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        JumpList matchDest;
-        readCharacter((term->inputPosition - m_checked), character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            op.m_jumps.append(matchDest);
-        else {
-            op.m_jumps.append(jump());
-            matchDest.link(this);
-        }
-    }
-    void backtrackCharacterClassOnce(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateCharacterClassFixed(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(index, countRegister);
-        sub32(Imm32(term->quantityCount), countRegister);
-
-        Label loop(this);
-        JumpList matchDest;
-        load16(BaseIndex(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar)), character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            op.m_jumps.append(matchDest);
-        else {
-            op.m_jumps.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        branch32(NotEqual, countRegister, index).linkTo(loop, this);
-    }
-    void backtrackCharacterClassFixed(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateCharacterClassGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-
-        JumpList failures;
-        Label loop(this);
-        failures.append(atEndOfInput());
-
-        if (term->invert()) {
-            readCharacter(term->inputPosition - m_checked, character);
-            matchCharacterClass(character, failures, term->characterClass);
-        } else {
-            JumpList matchDest;
-            readCharacter(term->inputPosition - m_checked, character);
-            matchCharacterClass(character, matchDest, term->characterClass);
-            failures.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-        if (term->quantityCount != quantifyInfinite) {
-            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
-            failures.append(jump());
-        } else
-            jump(loop);
-
-        failures.link(this);
-        op.m_reentry = label();
-
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackCharacterClassGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-        m_backtrackingState.append(branchTest32(Zero, countRegister));
-        sub32(TrustedImm32(1), countRegister);
-        sub32(TrustedImm32(1), index);
-        jump(op.m_reentry);
-    }
-
-    void generateCharacterClassNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-        op.m_reentry = label();
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackCharacterClassNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        JumpList nonGreedyFailures;
-
-        m_backtrackingState.link(this);
-
-        Label backtrackBegin(this);
-        loadFromFrame(term->frameLocation, countRegister);
-
-        nonGreedyFailures.append(atEndOfInput());
-        nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
-
-        JumpList matchDest;
-        readCharacter(term->inputPosition - m_checked, character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            nonGreedyFailures.append(matchDest);
-        else {
-            nonGreedyFailures.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-
-        jump(op.m_reentry);
-
-        nonGreedyFailures.link(this);
-        sub32(countRegister, index);
-        m_backtrackingState.fallthrough();
-    }
-
-    // Code generation/backtracking for simple terms
-    // (pattern characters, character classes, and assertions).
-    // These methods farm out work to the set of functions above.
-    void generateTerm(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        switch (term->type) {
-        case PatternTerm::TypePatternCharacter:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    generatePatternCharacterOnce(opIndex);
-                else
-                    generatePatternCharacterFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                generatePatternCharacterGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                generatePatternCharacterNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeCharacterClass:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    generateCharacterClassOnce(opIndex);
-                else
-                    generateCharacterClassFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                generateCharacterClassGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                generateCharacterClassNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeAssertionBOL:
-            generateAssertionBOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionEOL:
-            generateAssertionEOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionWordBoundary:
-            generateAssertionWordBoundary(opIndex);
-            break;
-
-        case PatternTerm::TypeForwardReference:
-            break;
-
-        case PatternTerm::TypeParenthesesSubpattern:
-        case PatternTerm::TypeParentheticalAssertion:
-            ASSERT_NOT_REACHED();
-        case PatternTerm::TypeBackReference:
-            m_shouldFallBack = true;
-            break;
-        }
-    }
-    void backtrackTerm(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        switch (term->type) {
-        case PatternTerm::TypePatternCharacter:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    backtrackPatternCharacterOnce(opIndex);
-                else
-                    backtrackPatternCharacterFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                backtrackPatternCharacterGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                backtrackPatternCharacterNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeCharacterClass:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    backtrackCharacterClassOnce(opIndex);
-                else
-                    backtrackCharacterClassFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                backtrackCharacterClassGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                backtrackCharacterClassNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeAssertionBOL:
-            backtrackAssertionBOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionEOL:
-            backtrackAssertionEOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionWordBoundary:
-            backtrackAssertionWordBoundary(opIndex);
-            break;
-
-        case PatternTerm::TypeForwardReference:
-            break;
-
-        case PatternTerm::TypeParenthesesSubpattern:
-        case PatternTerm::TypeParentheticalAssertion:
-            ASSERT_NOT_REACHED();
-        case PatternTerm::TypeBackReference:
-            m_shouldFallBack = true;
-            break;
-        }
-    }
-
-    void generate()
-    {
-        // Forwards generate the matching code.
-        ASSERT(m_ops.size());
-        size_t opIndex = 0;
-
-        do {
-            YarrOp& op = m_ops[opIndex];
-            switch (op.m_op) {
-
-            case OpTerm:
-                generateTerm(opIndex);
-                break;
-
-            // OpBodyAlternativeBegin/Next/End
-            //
-            // These nodes wrap the set of alternatives in the body of the regular expression.
-            // There may be either one or two chains of OpBodyAlternative nodes, one representing
-            // the 'once through' sequence of alternatives (if any exist), and one representing
-            // the repeating alternatives (again, if any exist).
-            //
-            // Upon normal entry to the Begin alternative, we will check that input is available.
-            // Reentry to the Begin alternative will take place after the check has taken place,
-            // and will assume that the input position has already been progressed as appropriate.
-            //
-            // Entry to subsequent Next/End alternatives occurs when the prior alternative has
-            // successfully completed a match - return a success state from JIT code.
-            //
-            // Next alternatives allow for reentry optimized to suit backtracking from its
-            // preceding alternative. It expects the input position to still be set to a position
-            // appropriate to its predecessor, and it will only perform an input check if the
-            // predecessor had a minimum size less than its own.
-            //
-            // In the case 'once through' expressions, the End node will also have a reentry
-            // point to jump to when the last alternative fails. Again, this expects the input
-            // position to still reflect that expected by the prior alternative.
-            case OpBodyAlternativeBegin: {
-                PatternAlternative* alternative = op.m_alternative;
-
-                // Upon entry at the head of the set of alternatives, check if input is available
-                // to run the first alternative. (This progresses the input position).
-                op.m_jumps.append(jumpIfNoAvailableInput(alternative->m_minimumSize));
-                // We will reenter after the check, and assume the input position to have been
-                // set as appropriate to this alternative.
-                op.m_reentry = label();
-
-                m_checked += alternative->m_minimumSize;
-                break;
-            }
-            case OpBodyAlternativeNext:
-            case OpBodyAlternativeEnd: {
-                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                PatternAlternative* alternative = op.m_alternative;
-
-                // If we get here, the prior alternative matched - return success.
-                
-                // Adjust the stack pointer to remove the pattern's frame.
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-
-                // Load appropriate values into the return register and the first output
-                // slot, and return. In the case of pattern with a fixed size, we will
-                // not have yet set the value in the first 
-                ASSERT(index != returnRegister);
-                if (m_pattern.m_body->m_hasFixedSize) {
-                    move(index, returnRegister);
-                    if (priorAlternative->m_minimumSize)
-                        sub32(Imm32(priorAlternative->m_minimumSize), returnRegister);
-                    store32(returnRegister, output);
-                } else
-                    load32(Address(output), returnRegister);
-                store32(index, Address(output, 4));
-                generateReturn();
-
-                // This is the divide between the tail of the prior alternative, above, and
-                // the head of the subsequent alternative, below.
-
-                if (op.m_op == OpBodyAlternativeNext) {
-                    // This is the reentry point for the Next alternative. We expect any code
-                    // that jumps here to do so with the input position matching that of the
-                    // PRIOR alteranative, and we will only check input availability if we
-                    // need to progress it forwards.
-                    op.m_reentry = label();
-                    if (int delta = alternative->m_minimumSize - priorAlternative->m_minimumSize) {
-                        add32(Imm32(delta), index);
-                        if (delta > 0)
-                            op.m_jumps.append(jumpIfNoAvailableInput());
-                    }
-                } else if (op.m_nextOp == notFound) {
-                    // This is the reentry point for the End of 'once through' alternatives,
-                    // jumped to when the las alternative fails to match.
-                    op.m_reentry = label();
-                    sub32(Imm32(priorAlternative->m_minimumSize), index);
-                }
-
-                if (op.m_op == OpBodyAlternativeNext)
-                    m_checked += alternative->m_minimumSize;
-                m_checked -= priorAlternative->m_minimumSize;
-                break;
-            }
-
-            // OpSimpleNestedAlternativeBegin/Next/End
-            // OpNestedAlternativeBegin/Next/End
-            //
-            // These nodes are used to handle sets of alternatives that are nested within
-            // subpatterns and parenthetical assertions. The 'simple' forms are used where
-            // we do not need to be able to backtrack back into any alternative other than
-            // the last, the normal forms allow backtracking into any alternative.
-            //
-            // Each Begin/Next node is responsible for planting an input check to ensure
-            // sufficient input is available on entry. Next nodes additionally need to
-            // jump to the end - Next nodes use the End node's m_jumps list to hold this
-            // set of jumps.
-            //
-            // In the non-simple forms, successful alternative matches must store a
-            // 'return address' using a DataLabelPtr, used to store the address to jump
-            // to when backtracking, to get to the code for the appropriate alternative.
-            case OpSimpleNestedAlternativeBegin:
-            case OpNestedAlternativeBegin: {
-                PatternTerm* term = op.m_term;
-                PatternAlternative* alternative = op.m_alternative;
-                PatternDisjunction* disjunction = term->parentheses.disjunction;
-
-                // Calculate how much input we need to check for, and if non-zero check.
-                op.m_checkAdjust = alternative->m_minimumSize;
-                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
-                    op.m_checkAdjust -= disjunction->m_minimumSize;
-                if (op.m_checkAdjust)
-                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
- 
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeNext:
-            case OpNestedAlternativeNext: {
-                PatternTerm* term = op.m_term;
-                PatternAlternative* alternative = op.m_alternative;
-                PatternDisjunction* disjunction = term->parentheses.disjunction;
-
-                // In the non-simple case, store a 'return address' so we can backtrack correctly.
-                if (op.m_op == OpNestedAlternativeNext) {
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
-                }
-
-                // If we reach here then the last alternative has matched - jump to the
-                // End node, to skip over any further alternatives.
-                //
-                // FIXME: this is logically O(N^2) (though N can be expected to be very
-                // small). We could avoid this either by adding an extra jump to the JIT
-                // data structures, or by making backtracking code that jumps to Next
-                // alternatives are responsible for checking that input is available (if
-                // we didn't need to plant the input checks, then m_jumps would be free).
-                YarrOp* endOp = &m_ops[op.m_nextOp];
-                while (endOp->m_nextOp != notFound) {
-                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
-                    endOp = &m_ops[endOp->m_nextOp];
-                }
-                ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
-                endOp->m_jumps.append(jump());
-
-                // This is the entry point for the next alternative.
-                op.m_reentry = label();
-
-                // Calculate how much input we need to check for, and if non-zero check.
-                op.m_checkAdjust = alternative->m_minimumSize;
-                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
-                    op.m_checkAdjust -= disjunction->m_minimumSize;
-                if (op.m_checkAdjust)
-                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeEnd:
-            case OpNestedAlternativeEnd: {
-                PatternTerm* term = op.m_term;
-
-                // In the non-simple case, store a 'return address' so we can backtrack correctly.
-                if (op.m_op == OpNestedAlternativeEnd) {
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
-                }
-
-                // If this set of alternatives contains more than one alternative,
-                // then the Next nodes will have planted jumps to the End, and added
-                // them to this node's m_jumps list.
-                op.m_jumps.link(this);
-                op.m_jumps.clear();
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                break;
-            }
-
-            // OpParenthesesSubpatternOnceBegin/End
-            //
-            // These nodes support (optionally) capturing subpatterns, that have a
-            // quantity count of 1 (this covers fixed once, and ?/?? quantifiers). 
-            case OpParenthesesSubpatternOnceBegin: {
-                PatternTerm* term = op.m_term;
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                const RegisterID indexTemporary = regT0;
-                ASSERT(term->quantityCount == 1);
-
-                // Upon entry to a Greedy quantified set of parenthese store the index.
-                // We'll use this for two purposes:
-                //  - To indicate which iteration we are on of mathing the remainder of
-                //    the expression after the parentheses - the first, including the
-                //    match within the parentheses, or the second having skipped over them.
-                //  - To check for empty matches, which must be rejected.
-                //
-                // At the head of a NonGreedy set of parentheses we'll immediately set the
-                // value on the stack to -1 (indicating a match skipping the subpattern),
-                // and plant a jump to the end. We'll also plant a label to backtrack to
-                // to reenter the subpattern later, with a store to set up index on the
-                // second iteration.
-                //
-                // FIXME: for capturing parens, could use the index in the capture array?
-                if (term->quantityType == QuantifierGreedy)
-                    storeToFrame(index, parenthesesFrameLocation);
-                else if (term->quantityType == QuantifierNonGreedy) {
-                    storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
-                    op.m_jumps.append(jump());
-                    op.m_reentry = label();
-                    storeToFrame(index, parenthesesFrameLocation);
-                }
-
-                // If the parenthese are capturing, store the starting index value to the
-                // captures array, offsetting as necessary.
-                //
-                // FIXME: could avoid offsetting this value in JIT code, apply
-                // offsets only afterwards, at the point the results array is
-                // being accessed.
-                if (term->capture()) {
-                    int offsetId = term->parentheses.subpatternId << 1;
-                    int inputOffset = term->inputPosition - m_checked;
-                    if (term->quantityType == QuantifierFixedCount)
-                        inputOffset -= term->parentheses.disjunction->m_minimumSize;
-                    if (inputOffset) {
-                        move(index, indexTemporary);
-                        add32(Imm32(inputOffset), indexTemporary);
-                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
-                    } else
-                        store32(index, Address(output, offsetId * sizeof(int)));
-                }
-                break;
-            }
-            case OpParenthesesSubpatternOnceEnd: {
-                PatternTerm* term = op.m_term;
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                const RegisterID indexTemporary = regT0;
-                ASSERT(term->quantityCount == 1);
-
-                // For Greedy/NonGreedy quantified parentheses, we must reject zero length
-                // matches. If the minimum size is know to be non-zero we need not check.
-                if (term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize)
-                    op.m_jumps.append(branch32(Equal, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*))));
-
-                // If the parenthese are capturing, store the ending index value to the
-                // captures array, offsetting as necessary.
-                //
-                // FIXME: could avoid offsetting this value in JIT code, apply
-                // offsets only afterwards, at the point the results array is
-                // being accessed.
-                if (term->capture()) {
-                    int offsetId = (term->parentheses.subpatternId << 1) + 1;
-                    int inputOffset = term->inputPosition - m_checked;
-                    if (inputOffset) {
-                        move(index, indexTemporary);
-                        add32(Imm32(inputOffset), indexTemporary);
-                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
-                    } else
-                        store32(index, Address(output, offsetId * sizeof(int)));
-                }
-
-                // If the parentheses are quantified Greedy then add a label to jump back
-                // to if get a failed match from after the parentheses. For NonGreedy
-                // parentheses, link the jump from before the subpattern to here.
-                if (term->quantityType == QuantifierGreedy)
-                    op.m_reentry = label();
-                else if (term->quantityType == QuantifierNonGreedy) {
-                    YarrOp& beginOp = m_ops[op.m_previousOp];
-                    beginOp.m_jumps.link(this);
-                }
-                break;
-            }
-
-            // OpParenthesesSubpatternTerminalBegin/End
-            case OpParenthesesSubpatternTerminalBegin: {
-                PatternTerm* term = op.m_term;
-                ASSERT(term->quantityType == QuantifierGreedy);
-                ASSERT(term->quantityCount == quantifyInfinite);
-                ASSERT(!term->capture());
-
-                // Upon entry set a label to loop back to.
-                op.m_reentry = label();
-
-                // Store the start index of the current match; we need to reject zero
-                // length matches.
-                storeToFrame(index, term->frameLocation);
-                break;
-            }
-            case OpParenthesesSubpatternTerminalEnd: {
-                PatternTerm* term = op.m_term;
-
-                // Check for zero length matches - if the match is non-zero, then we
-                // can accept it & loop back up to the head of the subpattern.
-                YarrOp& beginOp = m_ops[op.m_previousOp];
-                branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*)), beginOp.m_reentry);
-
-                // Reject the match - backtrack back into the subpattern.
-                op.m_jumps.append(jump());
-
-                // This is the entry point to jump to when we stop matching - we will
-                // do so once the subpattern cannot match any more.
-                op.m_reentry = label();
-                break;
-            }
-
-            // OpParentheticalAssertionBegin/End
-            case OpParentheticalAssertionBegin: {
-                PatternTerm* term = op.m_term;
-
-                // Store the current index - assertions should not update index, so
-                // we will need to restore it upon a successful match.
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                storeToFrame(index, parenthesesFrameLocation);
-
-                // Check 
-                op.m_checkAdjust = m_checked - term->inputPosition;
-                if (op.m_checkAdjust)
-                    sub32(Imm32(op.m_checkAdjust), index);
-
-                m_checked -= op.m_checkAdjust;
-                break;
-            }
-            case OpParentheticalAssertionEnd: {
-                PatternTerm* term = op.m_term;
-
-                // Restore the input index value.
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                loadFromFrame(parenthesesFrameLocation, index);
-
-                // If inverted, a successful match of the assertion must be treated
-                // as a failure, so jump to backtracking.
-                if (term->invert()) {
-                    op.m_jumps.append(jump());
-                    op.m_reentry = label();
-                }
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked += lastOp.m_checkAdjust;
-                break;
-            }
-
-            case OpMatchFailed:
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-                move(TrustedImm32(-1), returnRegister);
-                generateReturn();
-                break;
-            }
-
-            ++opIndex;
-        } while (opIndex < m_ops.size());
-    }
-
-    void backtrack()
-    {
-        // Backwards generate the backtracking code.
-        size_t opIndex = m_ops.size();
-        ASSERT(opIndex);
-
-        do {
-            --opIndex;
-            YarrOp& op = m_ops[opIndex];
-            switch (op.m_op) {
-
-            case OpTerm:
-                backtrackTerm(opIndex);
-                break;
-
-            // OpBodyAlternativeBegin/Next/End
-            //
-            // For each Begin/Next node representing an alternative, we need to decide what to do
-            // in two circumstances:
-            //  - If we backtrack back into this node, from within the alternative.
-            //  - If the input check at the head of the alternative fails (if this exists).
-            //
-            // We treat these two cases differently since in the former case we have slightly
-            // more information - since we are backtracking out of a prior alternative we know
-            // that at least enough input was available to run it. For example, given the regular
-            // expression /a|b/, if we backtrack out of the first alternative (a failed pattern
-            // character match of 'a'), then we need not perform an additional input availability
-            // check before running the second alternative.
-            //
-            // Backtracking required differs for the last alternative, which in the case of the
-            // repeating set of alternatives must loop. The code generated for the last alternative
-            // will also be used to handle all input check failures from any prior alternatives -
-            // these require similar functionality, in seeking the next available alternative for
-            // which there is sufficient input.
-            //
-            // Since backtracking of all other alternatives simply requires us to link backtracks
-            // to the reentry point for the subsequent alternative, we will only be generating any
-            // code when backtracking the last alternative.
-            case OpBodyAlternativeBegin:
-            case OpBodyAlternativeNext: {
-                PatternAlternative* alternative = op.m_alternative;
-
-                if (op.m_op == OpBodyAlternativeNext) {
-                    PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                    m_checked += priorAlternative->m_minimumSize;
-                }
-                m_checked -= alternative->m_minimumSize;
-
-                // Is this the last alternative? If not, then if we backtrack to this point we just
-                // need to jump to try to match the next alternative.
-                if (m_ops[op.m_nextOp].m_op != OpBodyAlternativeEnd) {
-                    m_backtrackingState.linkTo(m_ops[op.m_nextOp].m_reentry, this);
-                    break;
-                }
-                YarrOp& endOp = m_ops[op.m_nextOp];
-
-                YarrOp* beginOp = &op;
-                while (beginOp->m_op != OpBodyAlternativeBegin) {
-                    ASSERT(beginOp->m_op == OpBodyAlternativeNext);
-                    beginOp = &m_ops[beginOp->m_previousOp];
-                }
-
-                bool onceThrough = endOp.m_nextOp == notFound;
-
-                // First, generate code to handle cases where we backtrack out of an attempted match
-                // of the last alternative. If this is a 'once through' set of alternatives then we
-                // have nothing to do - link this straight through to the End.
-                if (onceThrough)
-                    m_backtrackingState.linkTo(endOp.m_reentry, this);
-                else {
-                    // Okay, we're going to need to loop. Calculate the delta between where the input
-                    // position was, and where we want it to be allowing for the fact that we need to
-                    // increment by 1. E.g. for the regexp /a|x/ we need to increment the position by
-                    // 1 between loop iterations, but for /abcd|xyz/ we need to increment by two when
-                    // looping from the last alternative to the first, for /a|xyz/ we need to decrement
-                    // by 1, and for /a|xy/ we don't need to move the input position at all.
-                    int deltaLastAlternativeToFirstAlternativePlusOne = (beginOp->m_alternative->m_minimumSize - alternative->m_minimumSize) + 1;
-
-                    // If we don't need to move the input poistion, and the pattern has a fixed size
-                    // (in which case we omit the store of the start index until the pattern has matched)
-                    // then we can just link the backtrack out of the last alternative straight to the
-                    // head of the first alternative.
-                    if (!deltaLastAlternativeToFirstAlternativePlusOne && m_pattern.m_body->m_hasFixedSize)
-                        m_backtrackingState.linkTo(beginOp->m_reentry, this);
-                    else {
-                        // We need to generate a trampoline of code to execute before looping back
-                        // around to the first alternative.
-                        m_backtrackingState.link(this);
-
-                        // If the pattern size is not fixed, then store the start index, for use if we match.
-                        if (!m_pattern.m_body->m_hasFixedSize) {
-                            if (alternative->m_minimumSize == 1)
-                                store32(index, Address(output));
-                            else {
-                                move(index, regT0);
-                                if (alternative->m_minimumSize)
-                                    sub32(Imm32(alternative->m_minimumSize - 1), regT0);
-                                else
-                                    add32(Imm32(1), regT0);
-                                store32(regT0, Address(output));
-                            }
-                        }
-
-                        if (deltaLastAlternativeToFirstAlternativePlusOne)
-                            add32(Imm32(deltaLastAlternativeToFirstAlternativePlusOne), index);
-
-                        // Loop. Since this code is only reached when we backtrack out of the last
-                        // alternative (and NOT linked to from the input check upon entry to the
-                        // last alternative) we know that there must be at least enough input as
-                        // required by the last alternative. As such, we only need to check if the
-                        // first will require more to run - if the same or less is required we can
-                        // unconditionally jump.
-                        if (deltaLastAlternativeToFirstAlternativePlusOne > 0)
-                            checkInput().linkTo(beginOp->m_reentry, this);
-                        else
-                            jump(beginOp->m_reentry);
-                    }
-                }
-
-                // We can reach this point in the code in two ways:
-                //  - Fallthrough from the code above (a repeating alternative backtracked out of its
-                //    last alternative, and did not have sufficent input to run the first).
-                //  - We will loop back up to the following label when a releating alternative loops,
-                //    following a failed input check.
-                //
-                // Either way, we have just failed the input check for the first alternative.
-                Label firstInputCheckFailed(this);
-
-                // Generate code to handle input check failures from alternatives except the last.
-                // prevOp is the alternative we're handling a bail out from (initially Begin), and
-                // nextOp is the alternative we will be attempting to reenter into.
-                // 
-                // We will link input check failures from the forwards matching path back to the code
-                // that can handle them.
-                YarrOp* prevOp = beginOp;
-                YarrOp* nextOp = &m_ops[beginOp->m_nextOp];
-                while (nextOp->m_op != OpBodyAlternativeEnd) {
-                    prevOp->m_jumps.link(this);
-
-                    int delta = nextOp->m_alternative->m_minimumSize - prevOp->m_alternative->m_minimumSize;
-                    if (delta)
-                        add32(Imm32(delta), index);
-
-                    // We only get here if an input check fails, it is only worth checking again
-                    // if the next alternative has a minimum size less than the last.
-                    if (delta < 0) {
-                        // FIXME: if we added an extra label to YarrOp, we could avoid needing to
-                        // subtract delta back out, and reduce this code. Should performance test
-                        // the benefit of this.
-                        Jump fail = jumpIfNoAvailableInput();
-                        sub32(Imm32(delta), index);
-                        jump(nextOp->m_reentry);
-                        fail.link(this);
-                    }
-                    prevOp = nextOp;
-                    nextOp = &m_ops[nextOp->m_nextOp];
-                }
-
-                // We fall through to here if there is insufficient input to run the last alternative.
-
-                // If there is insufficient input to run the last alternative, then for 'once through'
-                // alternatives we are done - just jump back up into the forwards matching path at the End.
-                if (onceThrough) {
-                    op.m_jumps.linkTo(endOp.m_reentry, this);
-                    jump(endOp.m_reentry);
-                    break;
-                }
-
-                // For repeating alternatives, link any input check failure from the last alternative to
-                // this point.
-                op.m_jumps.link(this);
-
-                bool needsToUpdateMatchStart = !m_pattern.m_body->m_hasFixedSize;
-
-                // Check for cases where input position is already incremented by 1 for the last
-                // alternative (this is particularly useful where the minimum size of the body
-                // disjunction is 0, e.g. /a*|b/).
-                if (needsToUpdateMatchStart && alternative->m_minimumSize == 1) {
-                    // index is already incremented by 1, so just store it now!
-                    store32(index, Address(output));
-                    needsToUpdateMatchStart = false;
-                }
-
-                // Check whether there is sufficient input to loop. Increment the input position by
-                // one, and check. Also add in the minimum disjunction size before checking - there
-                // is no point in looping if we're just going to fail all the input checks around
-                // the next iteration.
-                int deltaLastAlternativeToBodyMinimumPlusOne = (m_pattern.m_body->m_minimumSize + 1) - alternative->m_minimumSize;
-                if (deltaLastAlternativeToBodyMinimumPlusOne)
-                    add32(Imm32(deltaLastAlternativeToBodyMinimumPlusOne), index);
-                Jump matchFailed = jumpIfNoAvailableInput();
-
-                if (needsToUpdateMatchStart) {
-                    if (!m_pattern.m_body->m_minimumSize)
-                        store32(index, Address(output));
-                    else {
-                        move(index, regT0);
-                        sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0);
-                        store32(regT0, Address(output));
-                    }
-                }
-
-                // Calculate how much more input the first alternative requires than the minimum
-                // for the body as a whole. If no more is needed then we dont need an additional
-                // input check here - jump straight back up to the start of the first alternative.
-                int deltaBodyMinimumToFirstAlternative = beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize;
-                if (!deltaBodyMinimumToFirstAlternative)
-                    jump(beginOp->m_reentry);
-                else {
-                    add32(Imm32(deltaBodyMinimumToFirstAlternative), index);
-                    checkInput().linkTo(beginOp->m_reentry, this);
-                    jump(firstInputCheckFailed);
-                }
-
-                // We jump to here if we iterate to the point that there is insufficient input to
-                // run any matches, and need to return a failure state from JIT code.
-                matchFailed.link(this);
-
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-                move(TrustedImm32(-1), returnRegister);
-                generateReturn();
-                break;
-            }
-            case OpBodyAlternativeEnd: {
-                // We should never backtrack back into a body disjunction.
-                ASSERT(m_backtrackingState.isEmpty());
-
-                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                m_checked += priorAlternative->m_minimumSize;
-                break;
-            }
-
-            // OpSimpleNestedAlternativeBegin/Next/End
-            // OpNestedAlternativeBegin/Next/End
-            //
-            // Generate code for when we backtrack back out of an alternative into
-            // a Begin or Next node, or when the entry input count check fails. If
-            // there are more alternatives we need to jump to the next alternative,
-            // if not we backtrack back out of the current set of parentheses.
-            //
-            // In the case of non-simple nested assertions we need to also link the
-            // 'return address' appropriately to backtrack back out into the correct
-            // alternative.
-            case OpSimpleNestedAlternativeBegin:
-            case OpSimpleNestedAlternativeNext:
-            case OpNestedAlternativeBegin:
-            case OpNestedAlternativeNext: {
-                YarrOp& nextOp = m_ops[op.m_nextOp];
-                bool isBegin = op.m_previousOp == notFound;
-                bool isLastAlternative = nextOp.m_nextOp == notFound;
-                ASSERT(isBegin == (op.m_op == OpSimpleNestedAlternativeBegin || op.m_op == OpNestedAlternativeBegin));
-                ASSERT(isLastAlternative == (nextOp.m_op == OpSimpleNestedAlternativeEnd || nextOp.m_op == OpNestedAlternativeEnd));
-
-                // Treat an input check failure the same as a failed match.
-                m_backtrackingState.append(op.m_jumps);
-
-                // Set the backtracks to jump to the appropriate place. We may need
-                // to link the backtracks in one of three different way depending on
-                // the type of alternative we are dealing with:
-                //  - A single alternative, with no simplings.
-                //  - The last alternative of a set of two or more.
-                //  - An alternative other than the last of a set of two or more.
-                //
-                // In the case of a single alternative on its own, we don't need to
-                // jump anywhere - if the alternative fails to match we can just
-                // continue to backtrack out of the parentheses without jumping.
-                //
-                // In the case of the last alternative in a set of more than one, we
-                // need to jump to return back out to the beginning. We'll do so by
-                // adding a jump to the End node's m_jumps list, and linking this
-                // when we come to generate the Begin node. For alternatives other
-                // than the last, we need to jump to the next alternative.
-                //
-                // If the alternative had adjusted the input position we must link
-                // backtracking to here, correct, and then jump on. If not we can
-                // link the backtracks directly to their destination.
-                if (op.m_checkAdjust) {
-                    // Handle the cases where we need to link the backtracks here.
-                    m_backtrackingState.link(this);
-                    sub32(Imm32(op.m_checkAdjust), index);
-                    if (!isLastAlternative) {
-                        // An alternative that is not the last should jump to its successor.
-                        jump(nextOp.m_reentry);
-                    } else if (!isBegin) {
-                        // The last of more than one alternatives must jump back to the begnning.
-                        nextOp.m_jumps.append(jump());
-                    } else {
-                        // A single alternative on its own can fall through.
-                        m_backtrackingState.fallthrough();
-                    }
-                } else {
-                    // Handle the cases where we can link the backtracks directly to their destinations.
-                    if (!isLastAlternative) {
-                        // An alternative that is not the last should jump to its successor.
-                        m_backtrackingState.linkTo(nextOp.m_reentry, this);
-                    } else if (!isBegin) {
-                        // The last of more than one alternatives must jump back to the begnning.
-                        m_backtrackingState.takeBacktracksToJumpList(nextOp.m_jumps, this);
-                    }
-                    // In the case of a single alternative on its own do nothing - it can fall through.
-                }
-
-                // At this point we've handled the backtracking back into this node.
-                // Now link any backtracks that need to jump to here.
-
-                // For non-simple alternatives, link the alternative's 'return address'
-                // so that we backtrack back out into the previous alternative.
-                if (op.m_op == OpNestedAlternativeNext)
-                    m_backtrackingState.append(op.m_returnAddress);
-
-                // If there is more than one alternative, then the last alternative will
-                // have planted a jump to be linked to the end. This jump was added to the
-                // End node's m_jumps list. If we are back at the beginning, link it here.
-                if (isBegin) {
-                    YarrOp* endOp = &m_ops[op.m_nextOp];
-                    while (endOp->m_nextOp != notFound) {
-                        ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
-                        endOp = &m_ops[endOp->m_nextOp];
-                    }
-                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
-                    m_backtrackingState.append(endOp->m_jumps);
-                }
-
-                if (!isBegin) {
-                    YarrOp& lastOp = m_ops[op.m_previousOp];
-                    m_checked += lastOp.m_checkAdjust;
-                }
-                m_checked -= op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeEnd:
-            case OpNestedAlternativeEnd: {
-                PatternTerm* term = op.m_term;
-
-                // If we backtrack into the end of a simple subpattern do nothing;
-                // just continue through into the last alternative. If we backtrack
-                // into the end of a non-simple set of alterntives we need to jump
-                // to the backtracking return address set up during generation.
-                if (op.m_op == OpNestedAlternativeEnd) {
-                    m_backtrackingState.link(this);
-
-                    // Plant a jump to the return address.
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    loadFromFrameAndJump(alternativeFrameLocation);
-
-                    // Link the DataLabelPtr associated with the end of the last
-                    // alternative to this point.
-                    m_backtrackingState.append(op.m_returnAddress);
-                }
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked += lastOp.m_checkAdjust;
-                break;
-            }
-
-            // OpParenthesesSubpatternOnceBegin/End
-            //
-            // When we are backtracking back out of a capturing subpattern we need
-            // to clear the start index in the matches output array, to record that
-            // this subpattern has not been captured.
-            //
-            // When backtracking back out of a Greedy quantified subpattern we need
-            // to catch this, and try running the remainder of the alternative after
-            // the subpattern again, skipping the parentheses.
-            //
-            // Upon backtracking back into a quantified set of parentheses we need to
-            // check whether we were currently skipping the subpattern. If not, we
-            // can backtrack into them, if we were we need to either backtrack back
-            // out of the start of the parentheses, or jump back to the forwards
-            // matching start, depending of whether the match is Greedy or NonGreedy.
-            case OpParenthesesSubpatternOnceBegin: {
-                PatternTerm* term = op.m_term;
-                ASSERT(term->quantityCount == 1);
-
-                // We only need to backtrack to thispoint if capturing or greedy.
-                if (term->capture() || term->quantityType == QuantifierGreedy) {
-                    m_backtrackingState.link(this);
-
-                    // If capturing, clear the capture (we only need to reset start).
-                    if (term->capture())
-                        store32(TrustedImm32(-1), Address(output, (term->parentheses.subpatternId << 1) * sizeof(int)));
-
-                    // If Greedy, jump to the end.
-                    if (term->quantityType == QuantifierGreedy) {
-                        // Clear the flag in the stackframe indicating we ran through the subpattern.
-                        unsigned parenthesesFrameLocation = term->frameLocation;
-                        storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
-                        // Jump to after the parentheses, skipping the subpattern.
-                        jump(m_ops[op.m_nextOp].m_reentry);
-                        // A backtrack from after the parentheses, when skipping the subpattern,
-                        // will jump back to here.
-                        op.m_jumps.link(this);
-                    }
-
-                    m_backtrackingState.fallthrough();
-                }
-                break;
-            }
-            case OpParenthesesSubpatternOnceEnd: {
-                PatternTerm* term = op.m_term;
-
-                if (term->quantityType != QuantifierFixedCount) {
-                    m_backtrackingState.link(this);
-
-                    // Check whether we should backtrack back into the parentheses, or if we
-                    // are currently in a state where we had skipped over the subpattern
-                    // (in which case the flag value on the stack will be -1).
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1));
-
-                    if (term->quantityType == QuantifierGreedy) {
-                        // For Greedy parentheses, we skip after having already tried going
-                        // through the subpattern, so if we get here we're done.
-                        YarrOp& beginOp = m_ops[op.m_previousOp];
-                        beginOp.m_jumps.append(hadSkipped);
-                    } else {
-                        // For NonGreedy parentheses, we try skipping the subpattern first,
-                        // so if we get here we need to try running through the subpattern
-                        // next. Jump back to the start of the parentheses in the forwards
-                        // matching path.
-                        ASSERT(term->quantityType == QuantifierNonGreedy);
-                        YarrOp& beginOp = m_ops[op.m_previousOp];
-                        hadSkipped.linkTo(beginOp.m_reentry, this);
-                    }
-
-                    m_backtrackingState.fallthrough();
-                }
-
-                m_backtrackingState.append(op.m_jumps);
-                break;
-            }
-
-            // OpParenthesesSubpatternTerminalBegin/End
-            //
-            // Terminal subpatterns will always match - there is nothing after them to
-            // force a backtrack, and they have a minimum count of 0, and as such will
-            // always produce an acceptable result.
-            case OpParenthesesSubpatternTerminalBegin: {
-                // We will backtrack to this point once the subpattern cannot match any
-                // more. Since no match is accepted as a successful match (we are Greedy
-                // quantified with a minimum of zero) jump back to the forwards matching
-                // path at the end.
-                YarrOp& endOp = m_ops[op.m_nextOp];
-                m_backtrackingState.linkTo(endOp.m_reentry, this);
-                break;
-            }
-            case OpParenthesesSubpatternTerminalEnd:
-                // We should never be backtracking to here (hence the 'terminal' in the name).
-                ASSERT(m_backtrackingState.isEmpty());
-                m_backtrackingState.append(op.m_jumps);
-                break;
-
-            // OpParentheticalAssertionBegin/End
-            case OpParentheticalAssertionBegin: {
-                PatternTerm* term = op.m_term;
-                YarrOp& endOp = m_ops[op.m_nextOp];
-
-                // We need to handle the backtracks upon backtracking back out
-                // of a parenthetical assertion if either we need to correct
-                // the input index, or the assertion was inverted.
-                if (op.m_checkAdjust || term->invert()) {
-                     m_backtrackingState.link(this);
-
-                    if (op.m_checkAdjust)
-                        add32(Imm32(op.m_checkAdjust), index);
-
-                    // In an inverted assertion failure to match the subpattern
-                    // is treated as a successful match - jump to the end of the
-                    // subpattern. We already have adjusted the input position
-                    // back to that before the assertion, which is correct.
-                    if (term->invert())
-                        jump(endOp.m_reentry);
-
-                    m_backtrackingState.fallthrough();
-                }
-
-                // The End node's jump list will contain any backtracks into
-                // the end of the assertion. Also, if inverted, we will have
-                // added the failure caused by a successful match to this.
-                m_backtrackingState.append(endOp.m_jumps);
-
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpParentheticalAssertionEnd: {
-                // FIXME: We should really be clearing any nested subpattern
-                // matches on bailing out from after the pattern. Firefox has
-                // this bug too (presumably because they use YARR!)
-
-                // Never backtrack into an assertion; later failures bail to before the begin.
-                m_backtrackingState.takeBacktracksToJumpList(op.m_jumps, this);
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                break;
-            }
-
-            case OpMatchFailed:
-                break;
-            }
-
-        } while (opIndex);
-    }
-
-    // Compilation methods:
-    // ====================
-
-    // opCompileParenthesesSubpattern
-    // Emits ops for a subpattern (set of parentheses). These consist
-    // of a set of alternatives wrapped in an outer set of nodes for
-    // the parentheses.
-    // Supported types of parentheses are 'Once' (quantityCount == 1)
-    // and 'Terminal' (non-capturing parentheses quantified as greedy
-    // and infinite).
-    // Alternatives will use the 'Simple' set of ops if either the
-    // subpattern is terminal (in which case we will never need to
-    // backtrack), or if the subpattern only contains one alternative.
-    void opCompileParenthesesSubpattern(PatternTerm* term)
-    {
-        YarrOpCode parenthesesBeginOpCode;
-        YarrOpCode parenthesesEndOpCode;
-        YarrOpCode alternativeBeginOpCode = OpSimpleNestedAlternativeBegin;
-        YarrOpCode alternativeNextOpCode = OpSimpleNestedAlternativeNext;
-        YarrOpCode alternativeEndOpCode = OpSimpleNestedAlternativeEnd;
-
-        // We can currently only compile quantity 1 subpatterns that are
-        // not copies. We generate a copy in the case of a range quantifier,
-        // e.g. /(?:x){3,9}/, or /(?:x)+/ (These are effectively expanded to
-        // /(?:x){3,3}(?:x){0,6}/ and /(?:x)(?:x)*/ repectively). The problem
-        // comes where the subpattern is capturing, in which case we would
-        // need to restore the capture from the first subpattern upon a
-        // failure in the second.
-        if (term->quantityCount == 1 && !term->parentheses.isCopy) {
-            // Select the 'Once' nodes.
-            parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin;
-            parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd;
-
-            // If there is more than one alternative we cannot use the 'simple' nodes.
-            if (term->parentheses.disjunction->m_alternatives.size() != 1) {
-                alternativeBeginOpCode = OpNestedAlternativeBegin;
-                alternativeNextOpCode = OpNestedAlternativeNext;
-                alternativeEndOpCode = OpNestedAlternativeEnd;
-            }
-        } else if (term->parentheses.isTerminal) {
-            // Select the 'Terminal' nodes.
-            parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin;
-            parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd;
-        } else {
-            // This subpattern is not supported by the JIT.
-            m_shouldFallBack = true;
-            return;
-        }
-
-        size_t parenBegin = m_ops.size();
-        m_ops.append(parenthesesBeginOpCode);
-
-        m_ops.append(alternativeBeginOpCode);
-        m_ops.last().m_previousOp = notFound;
-        m_ops.last().m_term = term;
-        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
-        for (unsigned i = 0; i < alternatives.size(); ++i) {
-            size_t lastOpIndex = m_ops.size() - 1;
-
-            PatternAlternative* nestedAlternative = alternatives[i];
-            opCompileAlternative(nestedAlternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(alternativeNextOpCode));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = nestedAlternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            thisOp.m_term = term;
-        }
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == alternativeNextOpCode);
-        lastOp.m_op = alternativeEndOpCode;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = notFound;
-
-        size_t parenEnd = m_ops.size();
-        m_ops.append(parenthesesEndOpCode);
-
-        m_ops[parenBegin].m_term = term;
-        m_ops[parenBegin].m_previousOp = notFound;
-        m_ops[parenBegin].m_nextOp = parenEnd;
-        m_ops[parenEnd].m_term = term;
-        m_ops[parenEnd].m_previousOp = parenBegin;
-        m_ops[parenEnd].m_nextOp = notFound;
-    }
-
-    // opCompileParentheticalAssertion
-    // Emits ops for a parenthetical assertion. These consist of an
-    // OpSimpleNestedAlternativeBegin/Next/End set of nodes wrapping
-    // the alternatives, with these wrapped by an outer pair of
-    // OpParentheticalAssertionBegin/End nodes.
-    // We can always use the OpSimpleNestedAlternative nodes in the
-    // case of parenthetical assertions since these only ever match
-    // once, and will never backtrack back into the assertion.
-    void opCompileParentheticalAssertion(PatternTerm* term)
-    {
-        size_t parenBegin = m_ops.size();
-        m_ops.append(OpParentheticalAssertionBegin);
-
-        m_ops.append(OpSimpleNestedAlternativeBegin);
-        m_ops.last().m_previousOp = notFound;
-        m_ops.last().m_term = term;
-        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
-        for (unsigned i = 0; i < alternatives.size(); ++i) {
-            size_t lastOpIndex = m_ops.size() - 1;
-
-            PatternAlternative* nestedAlternative = alternatives[i];
-            opCompileAlternative(nestedAlternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(OpSimpleNestedAlternativeNext));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = nestedAlternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            thisOp.m_term = term;
-        }
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == OpSimpleNestedAlternativeNext);
-        lastOp.m_op = OpSimpleNestedAlternativeEnd;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = notFound;
-
-        size_t parenEnd = m_ops.size();
-        m_ops.append(OpParentheticalAssertionEnd);
-
-        m_ops[parenBegin].m_term = term;
-        m_ops[parenBegin].m_previousOp = notFound;
-        m_ops[parenBegin].m_nextOp = parenEnd;
-        m_ops[parenEnd].m_term = term;
-        m_ops[parenEnd].m_previousOp = parenBegin;
-        m_ops[parenEnd].m_nextOp = notFound;
-    }
-
-    // opCompileAlternative
-    // Called to emit nodes for all terms in an alternative.
-    void opCompileAlternative(PatternAlternative* alternative)
-    {
-        optimizeAlternative(alternative);
-
-        for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
-            PatternTerm* term = &alternative->m_terms[i];
-
-            switch (term->type) {
-            case PatternTerm::TypeParenthesesSubpattern:
-                opCompileParenthesesSubpattern(term);
-                break;
-
-            case PatternTerm::TypeParentheticalAssertion:
-                opCompileParentheticalAssertion(term);
-                break;
-
-            default:
-                m_ops.append(term);
-            }
-        }
-    }
-
-    // opCompileBody
-    // This method compiles the body disjunction of the regular expression.
-    // The body consists of two sets of alternatives - zero or more 'once
-    // through' (BOL anchored) alternatives, followed by zero or more
-    // repeated alternatives.
-    // For each of these two sets of alteratives, if not empty they will be
-    // wrapped in a set of OpBodyAlternativeBegin/Next/End nodes (with the
-    // 'begin' node referencing the first alternative, and 'next' nodes
-    // referencing any further alternatives. The begin/next/end nodes are
-    // linked together in a doubly linked list. In the case of repeating
-    // alternatives, the end node is also linked back to the beginning.
-    // If no repeating alternatives exist, then a OpMatchFailed node exists
-    // to return the failing result.
-    void opCompileBody(PatternDisjunction* disjunction)
-    {
-        Vector& alternatives =  disjunction->m_alternatives;
-        size_t currentAlternativeIndex = 0;
-
-        // Emit the 'once through' alternatives.
-        if (alternatives.size() && alternatives[0]->onceThrough()) {
-            m_ops.append(YarrOp(OpBodyAlternativeBegin));
-            m_ops.last().m_previousOp = notFound;
-
-            do {
-                size_t lastOpIndex = m_ops.size() - 1;
-                PatternAlternative* alternative = alternatives[currentAlternativeIndex];
-                opCompileAlternative(alternative);
-
-                size_t thisOpIndex = m_ops.size();
-                m_ops.append(YarrOp(OpBodyAlternativeNext));
-
-                YarrOp& lastOp = m_ops[lastOpIndex];
-                YarrOp& thisOp = m_ops[thisOpIndex];
-
-                lastOp.m_alternative = alternative;
-                lastOp.m_nextOp = thisOpIndex;
-                thisOp.m_previousOp = lastOpIndex;
-                
-                ++currentAlternativeIndex;
-            } while (currentAlternativeIndex < alternatives.size() && alternatives[currentAlternativeIndex]->onceThrough());
-
-            YarrOp& lastOp = m_ops.last();
-
-            ASSERT(lastOp.m_op == OpBodyAlternativeNext);
-            lastOp.m_op = OpBodyAlternativeEnd;
-            lastOp.m_alternative = 0;
-            lastOp.m_nextOp = notFound;
-        }
-
-        if (currentAlternativeIndex == alternatives.size()) {
-            m_ops.append(YarrOp(OpMatchFailed));
-            return;
-        }
-
-        // Emit the repeated alternatives.
-        size_t repeatLoop = m_ops.size();
-        m_ops.append(YarrOp(OpBodyAlternativeBegin));
-        m_ops.last().m_previousOp = notFound;
-        do {
-            size_t lastOpIndex = m_ops.size() - 1;
-            PatternAlternative* alternative = alternatives[currentAlternativeIndex];
-            ASSERT(!alternative->onceThrough());
-            opCompileAlternative(alternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(OpBodyAlternativeNext));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = alternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            
-            ++currentAlternativeIndex;
-        } while (currentAlternativeIndex < alternatives.size());
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == OpBodyAlternativeNext);
-        lastOp.m_op = OpBodyAlternativeEnd;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = repeatLoop;
-    }
-
-    void generateEnter()
-    {
-#if WTF_CPU_X86_64
-        push(X86Registers::ebp);
-        move(stackPointerRegister, X86Registers::ebp);
-        push(X86Registers::ebx);
-#elif WTF_CPU_X86
-        push(X86Registers::ebp);
-        move(stackPointerRegister, X86Registers::ebp);
-        // TODO: do we need spill registers to fill the output pointer if there are no sub captures?
-        push(X86Registers::ebx);
-        push(X86Registers::edi);
-        push(X86Registers::esi);
-        // load output into edi (2 = saved ebp + return address).
-    #if WTF_COMPILER_MSVC
-        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input);
-        loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index);
-        loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length);
-        loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output);
-    #else
-        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
-    #endif
-#elif WTF_CPU_ARM
-        push(ARMRegisters::r4);
-        push(ARMRegisters::r5);
-        push(ARMRegisters::r6);
-#if WTF_CPU_ARM_TRADITIONAL
-        push(ARMRegisters::r8); // scratch register
-#endif
-        move(ARMRegisters::r3, output);
-#elif WTF_CPU_SH4
-        push(SH4Registers::r11);
-        push(SH4Registers::r13);
-#elif WTF_CPU_MIPS
-        // Do nothing.
-#endif
-    }
-
-    void generateReturn()
-    {
-#if WTF_CPU_X86_64
-        pop(X86Registers::ebx);
-        pop(X86Registers::ebp);
-#elif WTF_CPU_X86
-        pop(X86Registers::esi);
-        pop(X86Registers::edi);
-        pop(X86Registers::ebx);
-        pop(X86Registers::ebp);
-#elif WTF_CPU_ARM
-#if WTF_CPU_ARM_TRADITIONAL
-        pop(ARMRegisters::r8); // scratch register
-#endif
-        pop(ARMRegisters::r6);
-        pop(ARMRegisters::r5);
-        pop(ARMRegisters::r4);
-#elif WTF_CPU_SH4
-        pop(SH4Registers::r13);
-        pop(SH4Registers::r11);
-#elif WTF_CPU_MIPS
-        // Do nothing
-#endif
-        ret();
-    }
-
-public:
-    YarrGenerator(YarrPattern& pattern)
-        : m_pattern(pattern)
-        , m_shouldFallBack(false)
-        , m_checked(0)
-    {
-    }
-
-    void compile(JSGlobalData* globalData, YarrCodeBlock& jitObject)
-    {
-        generateEnter();
-
-        if (!m_pattern.m_body->m_hasFixedSize)
-            store32(index, Address(output));
-
-        if (m_pattern.m_body->m_callFrameSize)
-            subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-
-        // Compile the pattern to the internal 'YarrOp' representation.
-        opCompileBody(m_pattern.m_body);
-
-        // If we encountered anything we can't handle in the JIT code
-        // (e.g. backreferences) then return early.
-        if (m_shouldFallBack) {
-            jitObject.setFallBack(true);
-            return;
-        }
-
-        generate();
-        backtrack();
-
-        // Link & finalize the code.
-        // XXX yarr-oom
-        ExecutablePool *pool;
-        bool ok;
-        LinkBuffer linkBuffer(this, globalData->regexAllocator, &pool, &ok);
-        m_backtrackingState.linkDataLabels(linkBuffer);
-        jitObject.set(linkBuffer.finalizeCode());
-        jitObject.setFallBack(m_shouldFallBack);
-    }
-
-private:
-    YarrPattern& m_pattern;
-
-    // Used to detect regular expression constructs that are not currently
-    // supported in the JIT; fall back to the interpreter when this is detected.
-    bool m_shouldFallBack;
-
-    // The regular expression expressed as a linear sequence of operations.
-    Vector m_ops;
-
-    // This records the current input offset being applied due to the current
-    // set of alternatives we are nested within. E.g. when matching the
-    // character 'b' within the regular expression /abc/, we will know that
-    // the minimum size for the alternative is 3, checked upon entry to the
-    // alternative, and that 'b' is at offset 1 from the start, and as such
-    // when matching 'b' we need to apply an offset of -2 to the load.
-    //
-    // FIXME: This should go away. Rather than tracking this value throughout
-    // code generation, we should gather this information up front & store it
-    // on the YarrOp structure.
-    int m_checked;
-
-    // This class records state whilst generating the backtracking path of code.
-    BacktrackingState m_backtrackingState;
-};
-
-void jitCompile(YarrPattern& pattern, JSGlobalData* globalData, YarrCodeBlock& jitObject)
-{
-    YarrGenerator(pattern).compile(globalData, jitObject);
-}
-
-int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output)
-{
-    return jitObject.execute(input, start, length, output);
-}
-
-}}
-
-#endif
diff --git a/js/src/yarr/YarrJIT.h b/js/src/yarr/YarrJIT.h
deleted file mode 100644
index 4f0f47f8c548..000000000000
--- a/js/src/yarr/YarrJIT.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- 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.
- *
- * 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef YarrJIT_h
-#define YarrJIT_h
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_YARR_JIT
-
-#include "assembler/assembler/MacroAssembler.h"
-#include "YarrPattern.h"
-
-#if WTF_CPU_X86 && !WTF_COMPILER_MSVC
-#define YARR_CALL __attribute__ ((regparm (3)))
-#else
-#define YARR_CALL
-#endif
-
-namespace JSC {
-
-class JSGlobalData;
-class ExecutablePool;
-
-namespace Yarr {
-
-class YarrCodeBlock {
-    typedef int (*YarrJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
-
-public:
-    YarrCodeBlock()
-        : m_needFallBack(false)
-    {
-    }
-
-    ~YarrCodeBlock()
-    {
-    }
-
-    void setFallBack(bool fallback) { m_needFallBack = fallback; }
-    bool isFallBack() { return m_needFallBack; }
-    void set(MacroAssembler::CodeRef ref) { m_ref = ref; }
-
-    int execute(const UChar* input, unsigned start, unsigned length, int* output)
-    {
-        return JS_EXTENSION((reinterpret_cast(m_ref.m_code.executableAddress()))(input, start, length, output));
-    }
-
-#if ENABLE_REGEXP_TRACING
-    void *getAddr() { return m_ref.m_code.executableAddress(); }
-#endif
-
-    void release() { m_ref.release(); }
-
-private:
-    MacroAssembler::CodeRef m_ref;
-    bool m_needFallBack;
-};
-
-void jitCompile(YarrPattern&, JSGlobalData*, YarrCodeBlock& jitObject);
-int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output);
-
-} } // namespace JSC::Yarr
-
-#endif
-
-#endif // YarrJIT_h
diff --git a/js/src/yarr/jswtfbridge.h b/js/src/yarr/jswtfbridge.h
new file mode 100644
index 000000000000..b38f76ead5a8
--- /dev/null
+++ b/js/src/yarr/jswtfbridge.h
@@ -0,0 +1,61 @@
+/* -*- 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 *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
+ * June 12, 2009.
+ *
+ * The Initial Developer of the Original Code is
+ *   the Mozilla Corporation.
+ *
+ * Contributor(s):
+ *   Chris Leary 
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jswtfbridge_h__
+#define jswtfbridge_h__
+
+/*
+ * The JS/WTF Bridge to Bona-fide Quality.
+ */
+
+#include "assembler/wtf/Platform.h"
+#include "jsstr.h"
+#include "jsprvtd.h"
+#include "jstl.h"
+
+typedef jschar UChar;
+typedef JSLinearString UString;
+
+class Unicode {
+  public:
+    static UChar toUpper(UChar c) { return JS_TOUPPER(c); }
+    static UChar toLower(UChar c) { return JS_TOLOWER(c); }
+};
+
+#endif
diff --git a/js/src/yarr/pcre/AUTHORS b/js/src/yarr/pcre/AUTHORS
new file mode 100644
index 000000000000..dbac2a54834b
--- /dev/null
+++ b/js/src/yarr/pcre/AUTHORS
@@ -0,0 +1,12 @@
+Originally written by:  Philip Hazel
+Email local part:       ph10
+Email domain:           cam.ac.uk
+
+University of Cambridge Computing Service,
+Cambridge, England. Phone: +44 1223 334714.
+
+Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
+
+Adapted for JavaScriptCore and WebKit by Apple Inc.
+
+Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/js/src/yarr/pcre/COPYING b/js/src/yarr/pcre/COPYING
new file mode 100644
index 000000000000..6ffdc24342d5
--- /dev/null
+++ b/js/src/yarr/pcre/COPYING
@@ -0,0 +1,35 @@
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed.
+
+Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * 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.
+
+    * Neither the name of the University of Cambridge nor the name of Apple
+      Inc. nor the names of their contributors may be used to endorse or
+      promote products derived from this software without specific prior
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
diff --git a/js/src/yarr/pcre/chartables.c b/js/src/yarr/pcre/chartables.c
new file mode 100644
index 000000000000..5c99db0b980f
--- /dev/null
+++ b/js/src/yarr/pcre/chartables.c
@@ -0,0 +1,96 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* This file is automatically written by the dftables auxiliary 
+program. If you edit it by hand, you might like to edit the Makefile to 
+prevent its ever being regenerated.
+
+This file contains the default tables for characters with codes less than
+128 (ASCII characters). These tables are used when no external tables are
+passed to PCRE. */
+
+const unsigned char jsc_pcre_default_tables[480] = {
+
+/* This table is a lower casing table. */
+
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
+  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+/* This table is a case flipping table. */
+
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
+  0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
+  0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 
+  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
+  0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+/* This table contains bit maps for various character classes.
+Each map is 32 bytes long and the bits run from the least
+significant end of each byte. The classes are: space, digit, word. */
+
+  0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
+  0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* This table identifies various classes of character by individual bits:
+  0x01   white space character
+  0x08   hexadecimal digit
+  0x10   alphanumeric or '_'
+*/
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*   0-  7 */
+  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /*   8- 15 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  16- 23 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  24- 31 */
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*    - '  */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  ( - /  */
+  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,  /*  0 - 7  */
+  0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  8 - ?  */
+  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  @ - G  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  H - O  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  P - W  */
+  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,  /*  X - _  */
+  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  ` - g  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  h - o  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  p - w  */
+  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /*  x -127 */
+
+
+/* End of chartables.c */
diff --git a/js/src/yarr/pcre/dftables b/js/src/yarr/pcre/dftables
new file mode 100644
index 000000000000..669b948ffc91
--- /dev/null
+++ b/js/src/yarr/pcre/dftables
@@ -0,0 +1,273 @@
+#!/usr/bin/perl -w
+#
+# This is JavaScriptCore's variant of the PCRE library. While this library
+# started out as a copy of PCRE, many of the features of PCRE have been
+# removed. This library now supports only the regular expression features
+# required by the JavaScript language specification, and has only the functions
+# needed by JavaScriptCore and the rest of WebKit.
+# 
+#                  Originally written by Philip Hazel
+#            Copyright (c) 1997-2006 University of Cambridge
+#  Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
+# 
+#     * Redistributions of source code must retain the above copyright notice,
+#       this list of conditions and the following disclaimer.
+# 
+#     * 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.
+# 
+#     * Neither the name of the University of Cambridge nor the names of its
+#       contributors may be used to endorse or promote products derived from
+#       this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
+# -----------------------------------------------------------------------------
+
+# This is a freestanding support program to generate a file containing
+# character tables. The tables are built according to the default C
+# locale.
+
+use strict;
+
+use File::Basename;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+
+sub readHeaderValues();
+
+my %pcre_internal;
+
+if (scalar(@ARGV) < 1) {
+    print STDERR "Usage: ", basename($0), " [--preprocessor=program] output-file\n";
+    exit 1;
+}
+
+my $outputFile;
+my $preprocessor;
+GetOptions('preprocessor=s' => \$preprocessor);
+if (not $preprocessor) {
+    $preprocessor = "cpp";
+}
+
+$outputFile = $ARGV[0];
+die('Must specify output file.') unless defined($outputFile);
+
+readHeaderValues();
+
+open(OUT, ">", $outputFile) or die "$!";
+binmode(OUT);
+
+printf(OUT
+    "/*************************************************\n" .
+    "*      Perl-Compatible Regular Expressions       *\n" .
+    "*************************************************/\n\n" .
+    "/* This file is automatically written by the dftables auxiliary \n" .
+    "program. If you edit it by hand, you might like to edit the Makefile to \n" .
+    "prevent its ever being regenerated.\n\n");
+printf(OUT
+    "This file contains the default tables for characters with codes less than\n" .
+    "128 (ASCII characters). These tables are used when no external tables are\n" .
+    "passed to PCRE. */\n\n" .
+    "const unsigned char jsc_pcre_default_tables[%d] = {\n\n" .
+    "/* This table is a lower casing table. */\n\n", $pcre_internal{tables_length});
+
+if ($pcre_internal{lcc_offset} != 0) {
+    die "lcc_offset != 0";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        printf(OUT "\n  ");
+    }
+    printf(OUT "0x%02X", ord(lc(chr($i))));
+    if ($i != 127) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT "/* This table is a case flipping table. */\n\n");
+
+if ($pcre_internal{fcc_offset} != 128) {
+  die "fcc_offset != 128";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        printf(OUT "\n  ");
+    }
+    my $c = chr($i);
+    printf(OUT "0x%02X", $c =~ /[[:lower:]]/ ? ord(uc($c)) : ord(lc($c)));
+    if ($i != 127) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT
+    "/* This table contains bit maps for various character classes.\n" .
+    "Each map is 32 bytes long and the bits run from the least\n" .
+    "significant end of each byte. The classes are: space, digit, word. */\n\n");
+
+if ($pcre_internal{cbits_offset} != $pcre_internal{fcc_offset} + 128) {
+    die "cbits_offset != fcc_offset + 128";
+}
+
+my @cbit_table = (0) x $pcre_internal{cbit_length};
+for (my $i = ord('0'); $i <= ord('9'); $i++) {
+    $cbit_table[$pcre_internal{cbit_digit} + $i / 8] |= 1 << ($i & 7);
+}
+$cbit_table[$pcre_internal{cbit_word} + ord('_') / 8] |= 1 << (ord('_') & 7);
+for (my $i = 0; $i < 128; $i++) {
+    my $c = chr($i);
+    if ($c =~ /[[:alnum:]]/) {
+        $cbit_table[$pcre_internal{cbit_word} + $i / 8] |= 1 << ($i & 7);
+    }
+    if ($c =~ /[[:space:]]/) {
+        $cbit_table[$pcre_internal{cbit_space} + $i / 8] |= 1 << ($i & 7);
+    }
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < $pcre_internal{cbit_length}; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        if (($i & 31) == 0) {
+            printf(OUT "\n");
+        }
+        printf(OUT "\n  ");
+    }
+    printf(OUT "0x%02X", $cbit_table[$i]);
+    if ($i != $pcre_internal{cbit_length} - 1) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT
+    "/* This table identifies various classes of character by individual bits:\n" .
+    "  0x%02x   white space character\n" .
+    "  0x%02x   hexadecimal digit\n" .
+    "  0x%02x   alphanumeric or '_'\n*/\n\n",
+    $pcre_internal{ctype_space}, $pcre_internal{ctype_xdigit}, $pcre_internal{ctype_word});
+
+if ($pcre_internal{ctypes_offset} != $pcre_internal{cbits_offset} + $pcre_internal{cbit_length}) {
+    die "ctypes_offset != cbits_offset + cbit_length";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    my $x = 0;
+    my $c = chr($i);
+    if ($c =~ /[[:space:]]/) {
+        $x += $pcre_internal{ctype_space};
+    }
+    if ($c =~ /[[:xdigit:]]/) {
+        $x += $pcre_internal{ctype_xdigit};
+    }
+    if ($c =~ /[[:alnum:]_]/) {
+        $x += $pcre_internal{ctype_word};
+    }
+    printf(OUT "0x%02X", $x);
+    if ($i != 127) {
+        printf(OUT ", ");
+    } else {
+        printf(OUT "};");
+    }
+    if (($i & 7) == 7) {
+        printf(OUT " /* ");
+        my $d = chr($i - 7);
+        if ($d =~ /[[:print:]]/) {
+            printf(OUT " %c -", $i - 7);
+        } else {
+            printf(OUT "%3d-", $i - 7);
+        }
+        if ($c =~ m/[[:print:]]/) {
+            printf(OUT " %c ", $i);
+        } else {
+            printf(OUT "%3d", $i);
+        }
+        printf(OUT " */\n");
+        if ($i != 127) {
+            printf(OUT "  ");
+        }
+    }
+}
+
+if ($pcre_internal{tables_length} != $pcre_internal{ctypes_offset} + 128) {
+    die "tables_length != ctypes_offset + 128";
+}
+
+printf(OUT "\n\n/* End of chartables.c */\n");
+
+close(OUT);
+
+exit 0;
+
+sub readHeaderValues()
+{
+    my @variables = qw(
+        cbit_digit
+        cbit_length
+        cbit_space
+        cbit_word
+        cbits_offset
+        ctype_space
+        ctype_word
+        ctype_xdigit
+        ctypes_offset
+        fcc_offset
+        lcc_offset
+        tables_length
+    );
+
+    local $/ = undef;
+
+    my $headerPath = File::Spec->catfile(dirname($0), "pcre_internal.h");
+ 
+    my ($fh, $tempFile) = tempfile(
+        basename($0) . "-XXXXXXXX",
+        DIR => File::Spec->tmpdir(),
+        SUFFIX => ".in",
+        UNLINK => 0,
+    );
+
+    print $fh "#define DFTABLES\n\n";
+
+    open(HEADER, "<", $headerPath) or die "$!";
+    print $fh 
; + close(HEADER); + + print $fh "\n\n"; + + for my $v (@variables) { + print $fh "\$pcre_internal{\"$v\"} = $v;\n"; + } + + close($fh); + + open(CPP, "$preprocessor \"$tempFile\" |") or die "$!"; + my $content = ; + close(CPP); + + eval $content; + die "$@" if $@; + unlink $tempFile; +} diff --git a/js/src/yarr/pcre/pcre.h b/js/src/yarr/pcre/pcre.h new file mode 100644 index 000000000000..91d96b784905 --- /dev/null +++ b/js/src/yarr/pcre/pcre.h @@ -0,0 +1,68 @@ +/* This is the public header file for JavaScriptCore's variant of the PCRE +library. While this library started out as a copy of PCRE, many of the +features of PCRE have been removed. This library now supports only the +regular expression features required by the JavaScript language +specification, and has only the functions needed by JavaScriptCore and the +rest of WebKit. + + Copyright (c) 1997-2005 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE. + +#ifndef JSRegExp_h +#define JSRegExp_h + +#include "yarr/jswtfbridge.h" + +struct JSRegExp; +struct JSContext; + +enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase }; +enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline }; + +/* jsRegExpExecute error codes */ +const int JSRegExpErrorNoMatch = -1; +const int JSRegExpErrorHitLimit = -2; +const int JSRegExpErrorInternal = -4; + +JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, + JSRegExpIgnoreCaseOption, JSRegExpMultilineOption, + unsigned* numSubpatterns, int *error); + +int jsRegExpExecute(JSContext *, const JSRegExp*, + const UChar* subject, int subjectLength, int startOffset, + int* offsetsVector, int offsetsVectorLength); + +void jsRegExpFree(JSRegExp*); + +#endif diff --git a/js/src/yarr/pcre/pcre.pri b/js/src/yarr/pcre/pcre.pri new file mode 100644 index 000000000000..4f59e17f4d91 --- /dev/null +++ b/js/src/yarr/pcre/pcre.pri @@ -0,0 +1,12 @@ +# Perl Compatible Regular Expressions - Qt4 build info +VPATH += $$PWD +INCLUDEPATH += $$PWD $$OUTPUT_DIR/JavaScriptCore/tmp +DEPENDPATH += $$PWD + +SOURCES += \ + pcre_compile.cpp \ + pcre_exec.cpp \ + pcre_tables.cpp \ + pcre_ucp_searchfuncs.cpp \ + pcre_xclass.cpp + diff --git a/js/src/yarr/pcre/pcre_compile.cpp b/js/src/yarr/pcre/pcre_compile.cpp new file mode 100644 index 000000000000..8d273bcbe5a6 --- /dev/null +++ b/js/src/yarr/pcre/pcre_compile.cpp @@ -0,0 +1,2702 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + Copyright (C) 2007 Eric Seidel + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains the external function jsRegExpExecute(), along with +supporting internal functions that are not used by other modules. */ + +#include "pcre_internal.h" + +#include +#include "yarr/wtf/ASCIICType.h" +#include "jsvector.h" + +using namespace WTF; + +/* Negative values for the firstchar and reqchar variables */ + +#define REQ_UNSET (-2) +#define REQ_NONE (-1) + +/************************************************* +* Code parameters and static tables * +*************************************************/ + +/* Maximum number of items on the nested bracket stacks at compile time. This +applies to the nesting of all kinds of parentheses. It does not limit +un-nested, non-capturing parentheses. This number can be made bigger if +necessary - it is used to dimension one int and one unsigned char vector at +compile time. */ + +#define BRASTACK_SIZE 200 + +/* Table for handling escaped characters in the range '0'-'z'. Positive returns +are simple data values; negative values are for special things like \d and so +on. Zero means further processing is needed (for things like \x), or the escape +is invalid. */ + +static const short escapes[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ + 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ + '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ + 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */ + '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */ + 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */ + 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */ + 0, 0, 0 /* x - z */ +}; +static const unsigned OPCODE_LEN = 1; +static const unsigned BRAZERO_LEN = OPCODE_LEN; +static const unsigned BRA_NEST_SIZE = 2; +static const unsigned BRA_LEN = OPCODE_LEN + LINK_SIZE + BRA_NEST_SIZE; +static const unsigned KET_LEN = OPCODE_LEN + LINK_SIZE; + +/* Error code numbers. They are given names so that they can more easily be +tracked. */ + +enum ErrorCode { + ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, + ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17 +}; + +/* These are the error texts that correspond to the above error codes: + // 1 + "\\ at end of pattern\0" + "\\c at end of pattern\0" + "character value in \\x{...} sequence is too large\0" + "numbers out of order in {} quantifier\0" + // 5 + "number too big in {} quantifier\0" + "missing terminating ] for character class\0" + "internal error: code overflow\0" + "range out of order in character class\0" + "nothing to repeat\0" + // 10 + "unmatched parentheses\0" + "internal error: unexpected repeat\0" + "unrecognized character after (?\0" + "failed to get memory\0" + "missing )\0" + // 15 + "reference to non-existent subpattern\0" + "regular expression too large\0" + "parentheses nested too deeply" */ + +/* Structure for passing "static" information around between the functions +doing the compiling. */ + +struct CompileData { + CompileData() { + topBackref = 0; + backrefMap = 0; + reqVaryOpt = 0; + needOuterBracket = false; + numCapturingBrackets = 0; + } + int topBackref; /* Maximum back reference */ + unsigned backrefMap; /* Bitmap of low back refs */ + int reqVaryOpt; /* "After variable item" flag for reqByte */ + bool needOuterBracket; + int numCapturingBrackets; +}; + +/* Definitions to allow mutual recursion */ + +static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&); +static bool bracketIsAnchored(const unsigned char* code); +static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap); +static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert); + +/************************************************* +* Handle escapes * +*************************************************/ + +/* This function is called when a \ has been encountered. It either returns a +positive value for a simple escape such as \n, or a negative value which +encodes one of the more complicated things such as \d. When UTF-8 is enabled, +a positive value greater than 255 may be returned. On entry, ptr is pointing at +the \. On exit, it is on the final character of the escape sequence. + +Arguments: + ptrPtr points to the pattern position pointer + errorCodePtr points to the errorcode variable + bracount number of previous extracting brackets + options the options bits + isClass true if inside a character class + +Returns: zero or positive => a data character + negative => a special escape sequence + on error, error is set +*/ + +static int checkEscape(const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int bracount, bool isClass) +{ + const UChar* ptr = *ptrPtr + 1; + + /* If backslash is at the end of the pattern, it's an error. */ + if (ptr == patternEnd) { + *errorCodePtr = ERR1; + *ptrPtr = ptr; + return 0; + } + + int c = *ptr; + + /* Non-alphamerics are literals. For digits or letters, do an initial lookup in + a table. A non-zero result is something that can be returned immediately. + Otherwise further processing may be required. */ + + if (c < '0' || c > 'z') { /* Not alphameric */ + } else if (int escapeValue = escapes[c - '0']) { + c = escapeValue; + if (isClass) { + if (-c == ESC_b) + c = '\b'; /* \b is backslash in a class */ + else if (-c == ESC_B) + c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */ + } + /* Escapes that need further processing, or are illegal. */ + + } else { + switch (c) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* Escape sequences starting with a non-zero digit are backreferences, + unless there are insufficient brackets, in which case they are octal + escape sequences. Those sequences end on the first non-octal character + or when we overflow 0-255, whichever comes first. */ + + if (!isClass) { + const UChar* oldptr = ptr; + c -= '0'; + while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount) + c = c * 10 + *(++ptr) - '0'; + if (c <= bracount) { + c = -(ESC_REF + c); + break; + } + ptr = oldptr; /* Put the pointer back and fall through */ + } + + /* Handle an octal number following \. If the first digit is 8 or 9, + this is not octal. */ + + if ((c = *ptr) >= '8') { + c = '\\'; + ptr -= 1; + break; + } + + /* \0 always starts an octal number, but we may drop through to here with a + larger first octal digit. */ + + case '0': { + c -= '0'; + int i; + for (i = 1; i <= 2; ++i) { + if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7') + break; + int cc = c * 8 + ptr[i] - '0'; + if (cc > 255) + break; + c = cc; + } + ptr += i - 1; + break; + } + + case 'x': { + c = 0; + int i; + for (i = 1; i <= 2; ++i) { + if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { + c = 'x'; + i = 1; + break; + } + int cc = ptr[i]; + if (cc >= 'a') + cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); + } + ptr += i - 1; + break; + } + + case 'u': { + c = 0; + int i; + for (i = 1; i <= 4; ++i) { + if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { + c = 'u'; + i = 1; + break; + } + int cc = ptr[i]; + if (cc >= 'a') + cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); + } + ptr += i - 1; + break; + } + + case 'c': + if (++ptr == patternEnd) { + *errorCodePtr = ERR2; + return 0; + } + + c = *ptr; + + /* To match Firefox, inside a character class, we also accept + numbers and '_' as control characters */ + if ((!isClass && !isASCIIAlpha(c)) || (!isASCIIAlphanumeric(c) && c != '_')) { + c = '\\'; + ptr -= 2; + break; + } + + /* A letter is upper-cased; then the 0x40 bit is flipped. This coding + is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ + c = toASCIIUpper(c) ^ 0x40; + break; + } + } + + *ptrPtr = ptr; + return c; +} + +/************************************************* +* Check for counted repeat * +*************************************************/ + +/* This function is called when a '{' is encountered in a place where it might +start a quantifier. It looks ahead to see if it really is a quantifier or not. +It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} +where the ddds are digits. + +Arguments: + p pointer to the first char after '{' + +Returns: true or false +*/ + +static bool isCountedRepeat(const UChar* p, const UChar* patternEnd) +{ + if (p >= patternEnd || !isASCIIDigit(*p)) + return false; + p++; + while (p < patternEnd && isASCIIDigit(*p)) + p++; + if (p < patternEnd && *p == '}') + return true; + + if (p >= patternEnd || *p++ != ',') + return false; + if (p < patternEnd && *p == '}') + return true; + + if (p >= patternEnd || !isASCIIDigit(*p)) + return false; + p++; + while (p < patternEnd && isASCIIDigit(*p)) + p++; + + return (p < patternEnd && *p == '}'); +} + +/************************************************* +* Read repeat counts * +*************************************************/ + +/* Read an item of the form {n,m} and return the values. This is called only +after isCountedRepeat() has confirmed that a repeat-count quantifier exists, +so the syntax is guaranteed to be correct, but we need to check the values. + +Arguments: + p pointer to first char after '{' + minp pointer to int for min + maxp pointer to int for max + returned as -1 if no max + errorCodePtr points to error code variable + +Returns: pointer to '}' on success; + current ptr on error, with errorCodePtr set non-zero +*/ + +static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorCodePtr) +{ + int min = 0; + int max = -1; + + /* Read the minimum value and do a paranoid check: a negative value indicates + an integer overflow. */ + + while (isASCIIDigit(*p)) + min = min * 10 + *p++ - '0'; + if (min < 0 || min > 65535) { + *errorCodePtr = ERR5; + return p; + } + + /* Read the maximum value if there is one, and again do a paranoid on its size. + Also, max must not be less than min. */ + + if (*p == '}') + max = min; + else { + if (*(++p) != '}') { + max = 0; + while (isASCIIDigit(*p)) + max = max * 10 + *p++ - '0'; + if (max < 0 || max > 65535) { + *errorCodePtr = ERR5; + return p; + } + if (max < min) { + *errorCodePtr = ERR4; + return p; + } + } + } + + /* Fill in the required variables, and pass back the pointer to the terminating + '}'. */ + + *minp = min; + *maxp = max; + return p; +} + +/************************************************* +* Find first significant op code * +*************************************************/ + +/* This is called by several functions that scan a compiled expression looking +for a fixed first character, or an anchoring op code etc. It skips over things +that do not influence this. + +Arguments: + code pointer to the start of the group +Returns: pointer to the first significant opcode +*/ + +static const unsigned char* firstSignificantOpcode(const unsigned char* code) +{ + while (*code == OP_BRANUMBER) + code += 3; + return code; +} + +static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code) +{ + while (true) { + switch (*code) { + case OP_ASSERT_NOT: + advanceToEndOfBracket(code); + code += 1 + LINK_SIZE; + break; + case OP_WORD_BOUNDARY: + case OP_NOT_WORD_BOUNDARY: + ++code; + break; + case OP_BRANUMBER: + code += 3; + break; + default: + return code; + } + } +} + +/************************************************* +* Get othercase range * +*************************************************/ + +/* This function is passed the start and end of a class range, in UTF-8 mode +with UCP support. It searches up the characters, looking for internal ranges of +characters in the "other" case. Each call returns the next one, updating the +start address. + +Arguments: + cptr points to starting character value; updated + d end value + ocptr where to put start of othercase range + odptr where to put end of othercase range + +Yield: true when range returned; false when no more +*/ + +static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr) +{ + int c, othercase = 0; + + for (c = *cptr; c <= d; c++) { + if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) + break; + } + + if (c > d) + return false; + + *ocptr = othercase; + int next = othercase + 1; + + for (++c; c <= d; c++) { + if (jsc_pcre_ucp_othercase(c) != next) + break; + next++; + } + + *odptr = next - 1; + *cptr = c; + + return true; +} + +/************************************************* + * Convert character value to UTF-8 * + *************************************************/ + +/* This function takes an integer value in the range 0 - 0x7fffffff + and encodes it as a UTF-8 character in 0 to 6 bytes. + + Arguments: + cvalue the character value + buffer pointer to buffer for result - at least 6 bytes long + + Returns: number of characters placed in the buffer + */ + +static int encodeUTF8(int cvalue, unsigned char *buffer) +{ + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (cvalue <= jsc_pcre_utf8_table1[i]) + break; + buffer += i; + for (int j = i; j > 0; j--) { + *buffer-- = 0x80 | (cvalue & 0x3f); + cvalue >>= 6; + } + *buffer = jsc_pcre_utf8_table2[i] | cvalue; + return i + 1; +} + +/************************************************* +* Compile one branch * +*************************************************/ + +/* Scan the pattern, compiling it into the code vector. + +Arguments: + options the option bits + brackets points to number of extracting brackets used + codePtr points to the pointer to the current code point + ptrPtr points to the current pattern pointer + errorCodePtr points to error code variable + firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) + reqbyteptr set to the last literal character required, else < 0 + cd contains pointers to tables etc. + +Returns: true on success + false, with *errorCodePtr set non-zero on error +*/ + +static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected) +{ + return ((ptr + 1 < patternEnd) && ptr[1] == expected); +} + +static bool +compileBranch(int options, int* brackets, unsigned char** codePtr, + const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int *firstbyteptr, + int* reqbyteptr, CompileData& cd) +{ + int repeatType, opType; + int repeatMin = 0, repeat_max = 0; /* To please picky compilers */ + int bravalue = 0; + int reqvary, tempreqvary; + int c; + unsigned char* code = *codePtr; + unsigned char* tempcode; + bool didGroupSetFirstByte = false; + const UChar* ptr = *ptrPtr; + const UChar* tempptr; + unsigned char* previous = NULL; + unsigned char classbits[32]; + + bool class_utf8; + unsigned char* class_utf8data; + unsigned char utf8_char[6]; + + /* Initialize no first byte, no required byte. REQ_UNSET means "no char + matching encountered yet". It gets changed to REQ_NONE if we hit something that + matches a non-fixed char first char; reqByte just remains unset if we never + find one. + + When we hit a repeat whose minimum is zero, we may have to adjust these values + to take the zero repeat into account. This is implemented by setting them to + zeroFirstByte and zeroReqByte when such a repeat is encountered. The individual + item types that can be repeated set these backoff variables appropriately. */ + + int firstByte = REQ_UNSET; + int reqByte = REQ_UNSET; + int zeroReqByte = REQ_UNSET; + int zeroFirstByte = REQ_UNSET; + + /* The variable reqCaseOpt contains either the REQ_IGNORE_CASE value or zero, + according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit + value > 255. It is added into the firstByte or reqByte variables to record the + case status of the value. This is used only for ASCII characters. */ + + int reqCaseOpt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0; + + /* Switch on next character until the end of the branch */ + + for (;; ptr++) { + bool negateClass; + bool shouldFlipNegation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */ + int classCharCount; + int classLastChar; + int skipBytes; + int subReqByte; + int subFirstByte; + int mcLength; + unsigned char mcbuffer[8]; + + /* Next byte in the pattern */ + + c = ptr < patternEnd ? *ptr : 0; + + /* Fill in length of a previous callout, except when the next thing is + a quantifier. */ + + bool isQuantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd)); + + switch (c) { + /* The branch terminates at end of string, |, or ). */ + + case 0: + if (ptr < patternEnd) + goto NORMAL_CHAR; + // End of string; fall through + case '|': + case ')': + *firstbyteptr = firstByte; + *reqbyteptr = reqByte; + *codePtr = code; + *ptrPtr = ptr; + return true; + + /* Handle single-character metacharacters. In multiline mode, ^ disables + the setting of any following char as a first character. */ + + case '^': + if (options & MatchAcrossMultipleLinesOption) { + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + *code++ = OP_BOL; + } else + *code++ = OP_CIRC; + previous = NULL; + break; + + case '$': + previous = NULL; + if (options & MatchAcrossMultipleLinesOption) + *code++ = OP_EOL; + else + *code++ = OP_DOLL; + break; + + /* There can never be a first char if '.' is first, whatever happens about + repeats. The value of reqByte doesn't change either. */ + + case '.': + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + previous = code; + *code++ = OP_NOT_NEWLINE; + break; + + /* Character classes. If the included characters are all < 256, we build a + 32-byte bitmap of the permitted characters, except in the special case + where there is only one such character. For negated classes, we build the + map as usual, then invert it at the end. However, we use a different opcode + so that data characters > 255 can be handled correctly. + + If the class contains characters outside the 0-255 range, a different + opcode is compiled. It may optionally have a bit map for characters < 256, + but those above are are explicitly listed afterwards. A flag byte tells + whether the bitmap is present, and whether this is a negated class or not. + */ + + case '[': { + previous = code; + shouldFlipNegation = false; + + /* PCRE supports POSIX class stuff inside a class. Perl gives an error if + they are encountered at the top level, so we'll do that too. */ + + /* If the first character is '^', set the negation flag and skip it. */ + + if (ptr + 1 >= patternEnd) { + *errorCodePtr = ERR6; + return false; + } + + if (ptr[1] == '^') { + negateClass = true; + ++ptr; + } else + negateClass = false; + + /* Keep a count of chars with values < 256 so that we can optimize the case + of just a single character (as long as it's < 256). For higher valued UTF-8 + characters, we don't yet do any optimization. */ + + classCharCount = 0; + classLastChar = -1; + + class_utf8 = false; /* No chars >= 256 */ + class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ + + /* Initialize the 32-char bit map to all zeros. We have to build the + map in a temporary bit of store, in case the class contains only 1 + character (< 256), because in that case the compiled code doesn't use the + bit map. */ + + memset(classbits, 0, 32 * sizeof(unsigned char)); + + /* Process characters until ] is reached. The first pass + through the regex checked the overall syntax, so we don't need to be very + strict here. At the start of the loop, c contains the first byte of the + character. */ + + while ((++ptr < patternEnd) && (c = *ptr) != ']') { + /* Backslash may introduce a single character, or it may introduce one + of the specials, which just set a flag. Escaped items are checked for + validity in the pre-compiling pass. The sequence \b is a special case. + Inside a class (and only there) it is treated as backspace. Elsewhere + it marks a word boundary. Other escapes have preset maps ready to + or into the one we are building. We assume they have more than one + character in them, so set classCharCount bigger than one. */ + + if (c == '\\') { + c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); + if (c < 0) { + classCharCount += 2; /* Greater than 1 is what matters */ + switch (-c) { + case ESC_d: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_digit); + continue; + + case ESC_D: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_digit); + continue; + + case ESC_w: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_word); + continue; + + case ESC_W: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_word); + continue; + + case ESC_s: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_space); + continue; + + case ESC_S: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_space); + continue; + + /* Unrecognized escapes are faulted if PCRE is running in its + strict mode. By default, for compatibility with Perl, they are + treated as literals. */ + + default: + c = *ptr; /* The final character */ + classCharCount -= 2; /* Undo the default count from above */ + } + } + + /* Fall through if we have a single character (c >= 0). This may be + > 256 in UTF-8 mode. */ + + } /* End of backslash handling */ + + /* A single character may be followed by '-' to form a range. However, + Perl does not permit ']' to be the end of the range. A '-' character + here is treated as a literal. */ + + if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') { + ptr += 2; + + int d = *ptr; + + /* The second part of a range can be a single-character escape, but + not any of the other escapes. Perl 5.6 treats a hyphen as a literal + in such circumstances. */ + + if (d == '\\') { + const UChar* oldptr = ptr; + d = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); + + /* \X is literal X; any other special means the '-' was literal */ + if (d < 0) { + ptr = oldptr - 2; + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + } + } + + /* The check that the two values are in the correct order happens in + the pre-pass. Optimize one-character ranges */ + + if (d == c) + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + + /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless + matching, we have to use an XCLASS with extra data items. Caseless + matching for characters > 127 is available only if UCP support is + available. */ + + if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) { + class_utf8 = true; + + /* With UCP support, we can find the other case equivalents of + the relevant characters. There may be several ranges. Optimize how + they fit with the basic range. */ + + if (options & IgnoreCaseOption) { + int occ, ocd; + int cc = c; + int origd = d; + while (getOthercaseRange(&cc, origd, &occ, &ocd)) { + if (occ >= c && ocd <= d) + continue; /* Skip embedded ranges */ + + if (occ < c && ocd >= c - 1) /* Extend the basic range */ + { /* if there is overlap, */ + c = occ; /* noting that if occ < c */ + continue; /* we can't have ocd > d */ + } /* because a subrange is */ + if (ocd > d && occ <= d + 1) /* always shorter than */ + { /* the basic range. */ + d = ocd; + continue; + } + + if (occ == ocd) + *class_utf8data++ = XCL_SINGLE; + else { + *class_utf8data++ = XCL_RANGE; + class_utf8data += encodeUTF8(occ, class_utf8data); + } + class_utf8data += encodeUTF8(ocd, class_utf8data); + } + } + + /* Now record the original range, possibly modified for UCP caseless + overlapping ranges. */ + + *class_utf8data++ = XCL_RANGE; + class_utf8data += encodeUTF8(c, class_utf8data); + class_utf8data += encodeUTF8(d, class_utf8data); + + /* With UCP support, we are done. Without UCP support, there is no + caseless matching for UTF-8 characters > 127; we can use the bit map + for the smaller ones. */ + + continue; /* With next character in the class */ + } + + /* We use the bit map for all cases when not in UTF-8 mode; else + ranges that lie entirely within 0-127 when there is UCP support; else + for partial ranges without UCP support. */ + + for (; c <= d; c++) { + classbits[c/8] |= (1 << (c&7)); + if (options & IgnoreCaseOption) { + int uc = flipCase(c); + classbits[uc/8] |= (1 << (uc&7)); + } + classCharCount++; /* in case a one-char range */ + classLastChar = c; + } + + continue; /* Go get the next char in the class */ + } + + /* Handle a lone single character - we can get here for a normal + non-escape char, or after \ that introduces a single character or for an + apparent range that isn't. */ + + LONE_SINGLE_CHARACTER: + + /* Handle a character that cannot go in the bit map */ + + if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) { + class_utf8 = true; + *class_utf8data++ = XCL_SINGLE; + class_utf8data += encodeUTF8(c, class_utf8data); + + if (options & IgnoreCaseOption) { + int othercase; + if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) { + *class_utf8data++ = XCL_SINGLE; + class_utf8data += encodeUTF8(othercase, class_utf8data); + } + } + } else { + /* Handle a single-byte character */ + classbits[c/8] |= (1 << (c&7)); + if (options & IgnoreCaseOption) { + c = flipCase(c); + classbits[c/8] |= (1 << (c&7)); + } + classCharCount++; + classLastChar = c; + } + } + + /* If classCharCount is 1, we saw precisely one character whose value is + less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we + can optimize the negative case only if there were no characters >= 128 + because OP_NOT and the related opcodes like OP_NOTSTAR operate on + single-bytes only. This is an historical hangover. Maybe one day we can + tidy these opcodes to handle multi-byte characters. + + The optimization throws away the bit map. We turn the item into a + 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note + that OP_NOT does not support multibyte characters. In the positive case, it + can cause firstByte to be set. Otherwise, there can be no first char if + this item is first, whatever repeat count may follow. In the case of + reqByte, save the previous value for reinstating. */ + + if (classCharCount == 1 && (!class_utf8 && (!negateClass || classLastChar < 128))) { + zeroReqByte = reqByte; + + /* The OP_NOT opcode works on one-byte characters only. */ + + if (negateClass) { + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + zeroFirstByte = firstByte; + *code++ = OP_NOT; + *code++ = classLastChar; + break; + } + + /* For a single, positive character, get the value into c, and + then we can handle this with the normal one-character code. */ + + c = classLastChar; + goto NORMAL_CHAR; + } /* End of 1-char optimization */ + + /* The general case - not the one-char optimization. If this is the first + thing in the branch, there can be no first char setting, whatever the + repeat count. Any reqByte setting must remain unchanged after any kind of + repeat. */ + + if (firstByte == REQ_UNSET) firstByte = REQ_NONE; + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + + /* If there are characters with values > 255, we have to compile an + extended class, with its own opcode. If there are no characters < 256, + we can omit the bitmap. */ + + if (class_utf8 && !shouldFlipNegation) { + *class_utf8data++ = XCL_END; /* Marks the end of extra data */ + *code++ = OP_XCLASS; + code += LINK_SIZE; + *code = negateClass? XCL_NOT : 0; + + /* If the map is required, install it, and move on to the end of + the extra data */ + + if (classCharCount > 0) { + *code++ |= XCL_MAP; + memcpy(code, classbits, 32); + code = class_utf8data; + } + + /* If the map is not required, slide down the extra data. */ + + else { + int len = class_utf8data - (code + 33); + memmove(code + 1, code + 33, len); + code += len + 1; + } + + /* Now fill in the complete length of the item */ + + putLinkValue(previous + 1, code - previous); + break; /* End of class handling */ + } + + /* If there are no characters > 255, negate the 32-byte map if necessary, + and copy it into the code vector. If this is the first thing in the branch, + there can be no first char setting, whatever the repeat count. Any reqByte + setting must remain unchanged after any kind of repeat. */ + + *code++ = (negateClass == shouldFlipNegation) ? OP_CLASS : OP_NCLASS; + if (negateClass) + for (c = 0; c < 32; c++) + code[c] = ~classbits[c]; + else + memcpy(code, classbits, 32); + code += 32; + break; + } + + /* Various kinds of repeat; '{' is not necessarily a quantifier, but this + has been tested above. */ + + case '{': + if (!isQuantifier) + goto NORMAL_CHAR; + ptr = readRepeatCounts(ptr + 1, &repeatMin, &repeat_max, errorCodePtr); + if (*errorCodePtr) + goto FAILED; + goto REPEAT; + + case '*': + repeatMin = 0; + repeat_max = -1; + goto REPEAT; + + case '+': + repeatMin = 1; + repeat_max = -1; + goto REPEAT; + + case '?': + repeatMin = 0; + repeat_max = 1; + + REPEAT: + if (!previous) { + *errorCodePtr = ERR9; + goto FAILED; + } + + if (repeatMin == 0) { + firstByte = zeroFirstByte; /* Adjust for zero repeat */ + reqByte = zeroReqByte; /* Ditto */ + } + + /* Remember whether this is a variable length repeat */ + + reqvary = (repeatMin == repeat_max) ? 0 : REQ_VARY; + + opType = 0; /* Default single-char op codes */ + + /* Save start of previous item, in case we have to move it up to make space + for an inserted OP_ONCE for the additional '+' extension. */ + /* FIXME: Probably don't need this because we don't use OP_ONCE. */ + + tempcode = previous; + + /* If the next character is '+', we have a possessive quantifier. This + implies greediness, whatever the setting of the PCRE_UNGREEDY option. + If the next character is '?' this is a minimizing repeat, by default, + but if PCRE_UNGREEDY is set, it works the other way round. We change the + repeat type to the non-default. */ + + if (safelyCheckNextChar(ptr, patternEnd, '?')) { + repeatType = 1; + ptr++; + } else + repeatType = 0; + + /* If previous was a character match, abolish the item and generate a + repeat item instead. If a char item has a minumum of more than one, ensure + that it is set in reqByte - it might not be if a sequence such as x{3} is + the first thing in a branch because the x will have gone into firstByte + instead. */ + + if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) { + /* Deal with UTF-8 characters that take up more than one byte. It's + easier to write this out separately than try to macrify it. Use c to + hold the length of the character in bytes, plus 0x80 to flag that it's a + length rather than a small character. */ + + if (code[-1] & 0x80) { + unsigned char *lastchar = code - 1; + while((*lastchar & 0xc0) == 0x80) + lastchar--; + c = code - lastchar; /* Length of UTF-8 character */ + memcpy(utf8_char, lastchar, c); /* Save the char */ + c |= 0x80; /* Flag c as a length */ + } + else { + c = code[-1]; + if (repeatMin > 1) + reqByte = c | reqCaseOpt | cd.reqVaryOpt; + } + + goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ + } + + else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) { + c = previous[1]; + if (repeatMin > 1) + reqByte = c | reqCaseOpt | cd.reqVaryOpt; + goto OUTPUT_SINGLE_REPEAT; + } + + /* If previous was a single negated character ([^a] or similar), we use + one of the special opcodes, replacing it. The code is shared with single- + character repeats by setting opt_type to add a suitable offset into + repeatType. OP_NOT is currently used only for single-byte chars. */ + + else if (*previous == OP_NOT) { + opType = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ + c = previous[1]; + goto OUTPUT_SINGLE_REPEAT; + } + + /* If previous was a character type match (\d or similar), abolish it and + create a suitable repeat item. The code is shared with single-character + repeats by setting opType to add a suitable offset into repeatType. */ + + else if (*previous <= OP_NOT_NEWLINE) { + opType = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ + c = *previous; + + OUTPUT_SINGLE_REPEAT: + int prop_type = -1; + int prop_value = -1; + + unsigned char* oldcode = code; + code = previous; /* Usually overwrite previous item */ + + /* If the maximum is zero then the minimum must also be zero; Perl allows + this case, so we do too - by simply omitting the item altogether. */ + + if (repeat_max == 0) + goto END_REPEAT; + + /* Combine the opType with the repeatType */ + + repeatType += opType; + + /* A minimum of zero is handled either as the special case * or ?, or as + an UPTO, with the maximum given. */ + + if (repeatMin == 0) { + if (repeat_max == -1) + *code++ = OP_STAR + repeatType; + else if (repeat_max == 1) + *code++ = OP_QUERY + repeatType; + else { + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* A repeat minimum of 1 is optimized into some special cases. If the + maximum is unlimited, we use OP_PLUS. Otherwise, the original item it + left in place and, if the maximum is greater than 1, we use OP_UPTO with + one less than the maximum. */ + + else if (repeatMin == 1) { + if (repeat_max == -1) + *code++ = OP_PLUS + repeatType; + else { + code = oldcode; /* leave previous item in place */ + if (repeat_max == 1) + goto END_REPEAT; + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max - 1); + } + } + + /* The case {n,n} is just an EXACT, while the general case {n,m} is + handled as an EXACT followed by an UPTO. */ + + else { + *code++ = OP_EXACT + opType; /* NB EXACT doesn't have repeatType */ + put2ByteValueAndAdvance(code, repeatMin); + + /* If the maximum is unlimited, insert an OP_STAR. Before doing so, + we have to insert the character for the previous code. For a repeated + Unicode property match, there are two extra bytes that define the + required property. In UTF-8 mode, long characters have their length in + c, with the 0x80 bit as a flag. */ + + if (repeat_max < 0) { + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else { + *code++ = c; + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + } + *code++ = OP_STAR + repeatType; + } + + /* Else insert an UPTO if the max is greater than the min, again + preceded by the character, for the previously inserted code. */ + + else if (repeat_max != repeatMin) { + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else + *code++ = c; + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + repeat_max -= repeatMin; + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* The character or character type itself comes last in all cases. */ + + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else + *code++ = c; + + /* For a repeated Unicode property match, there are two extra bytes that + define the required property. */ + + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + } + + /* If previous was a character class or a back reference, we put the repeat + stuff after it, but just skip the item if the repeat was {0,0}. */ + + else if (*previous == OP_CLASS || + *previous == OP_NCLASS || + *previous == OP_XCLASS || + *previous == OP_REF) + { + if (repeat_max == 0) { + code = previous; + goto END_REPEAT; + } + + if (repeatMin == 0 && repeat_max == -1) + *code++ = OP_CRSTAR + repeatType; + else if (repeatMin == 1 && repeat_max == -1) + *code++ = OP_CRPLUS + repeatType; + else if (repeatMin == 0 && repeat_max == 1) + *code++ = OP_CRQUERY + repeatType; + else { + *code++ = OP_CRRANGE + repeatType; + put2ByteValueAndAdvance(code, repeatMin); + if (repeat_max == -1) + repeat_max = 0; /* 2-byte encoding for max */ + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* If previous was a bracket group, we may have to replicate it in certain + cases. */ + + else if (*previous >= OP_BRA) { + int ketoffset = 0; + int len = code - previous; + unsigned char* bralink = NULL; + int nested = get2ByteValue(previous + 1 + LINK_SIZE); + + /* If the maximum repeat count is unlimited, find the end of the bracket + by scanning through from the start, and compute the offset back to it + from the current code pointer. There may be an OP_OPT setting following + the final KET, so we can't find the end just by going back from the code + pointer. */ + + if (repeat_max == -1) { + const unsigned char* ket = previous; + advanceToEndOfBracket(ket); + ketoffset = code - ket; + } + + /* The case of a zero minimum is special because of the need to stick + OP_BRAZERO in front of it, and because the group appears once in the + data, whereas in other cases it appears the minimum number of times. For + this reason, it is simplest to treat this case separately, as otherwise + the code gets far too messy. There are several special subcases when the + minimum is zero. */ + + if (repeatMin == 0) { + /* If the maximum is also zero, we just omit the group from the output + altogether. */ + + if (repeat_max == 0) { + code = previous; + goto END_REPEAT; + } + + /* If the maximum is 1 or unlimited, we just have to stick in the + BRAZERO and do no more at this point. However, we do need to adjust + any OP_RECURSE calls inside the group that refer to the group itself or + any internal group, because the offset is from the start of the whole + regex. Temporarily terminate the pattern while doing this. */ + + if (repeat_max <= 1) { + *code = OP_END; + memmove(previous+1, previous, len); + code++; + *previous++ = OP_BRAZERO + repeatType; + } + + /* If the maximum is greater than 1 and limited, we have to replicate + in a nested fashion, sticking OP_BRAZERO before each set of brackets. + The first one has to be handled carefully because it's the original + copy, which has to be moved up. The remainder can be handled by code + that is common with the non-zero minimum case below. We have to + adjust the value of repeat_max, since one less copy is required. */ + + else { + *code = OP_END; + memmove(previous + 4 + LINK_SIZE, previous, len); + code += 4 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeatType; + *previous++ = OP_BRA; + + /* We chain together the bracket offset fields that have to be + filled in later when the ends of the brackets are reached. */ + + int offset = (!bralink) ? 0 : previous - bralink; + bralink = previous; + putLinkValueAllowZeroAndAdvance(previous, offset); + put2ByteValueAndAdvance(previous, nested); + } + + repeat_max--; + } + + /* If the minimum is greater than zero, replicate the group as many + times as necessary, and adjust the maximum to the number of subsequent + copies that we need. If we set a first char from the group, and didn't + set a required char, copy the latter from the former. */ + + else { + if (repeatMin > 1) { + if (didGroupSetFirstByte && reqByte < 0) + reqByte = firstByte; + for (int i = 1; i < repeatMin; i++) { + memcpy(code, previous, len); + code += len; + } + } + if (repeat_max > 0) + repeat_max -= repeatMin; + } + + /* This code is common to both the zero and non-zero minimum cases. If + the maximum is limited, it replicates the group in a nested fashion, + remembering the bracket starts on a stack. In the case of a zero minimum, + the first one was set up above. In all cases the repeat_max now specifies + the number of additional copies needed. */ + + if (repeat_max >= 0) { + for (int i = repeat_max - 1; i >= 0; i--) { + *code++ = OP_BRAZERO + repeatType; + + /* All but the final copy start a new nesting, maintaining the + chain of brackets outstanding. */ + + if (i != 0) { + *code++ = OP_BRA; + int offset = (!bralink) ? 0 : code - bralink; + bralink = code; + putLinkValueAllowZeroAndAdvance(code, offset); + put2ByteValueAndAdvance(code, nested); + } + + memcpy(code, previous, len); + code += len; + } + + /* Now chain through the pending brackets, and fill in their length + fields (which are holding the chain links pro tem). */ + + while (bralink) { + int offset = code - bralink + 1; + unsigned char* bra = code - offset; + int oldlinkoffset = getLinkValueAllowZero(bra + 1); + bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset; + *code++ = OP_KET; + putLinkValueAndAdvance(code, offset); + putLinkValue(bra + 1, offset); + } + } + + /* If the maximum is unlimited, set a repeater in the final copy. We + can't just offset backwards from the current code point, because we + don't know if there's been an options resetting after the ket. The + correct offset was computed above. */ + + else + code[-ketoffset] = OP_KETRMAX + repeatType; + } + + // A quantifier after an assertion is mostly meaningless, but it + // can nullify the assertion if it has a 0 minimum. + else if (*previous == OP_ASSERT || *previous == OP_ASSERT_NOT) { + if (repeatMin == 0) { + code = previous; + goto END_REPEAT; + } + } + + /* Else there's some kind of shambles */ + + else { + *errorCodePtr = ERR11; + goto FAILED; + } + + /* In all case we no longer have a previous item. We also set the + "follows varying string" flag for subsequently encountered reqbytes if + it isn't already set and we have just passed a varying length item. */ + + END_REPEAT: + previous = NULL; + cd.reqVaryOpt |= reqvary; + break; + + /* Start of nested bracket sub-expression, or comment or lookahead or + lookbehind or option setting or condition. First deal with special things + that can come after a bracket; all are introduced by ?, and the appearance + of any of them means that this is not a referencing group. They were + checked for validity in the first pass over the string, so we don't have to + check for syntax errors here. */ + + case '(': + { + skipBytes = 2; + unsigned minBracket = *brackets + 1; + if (*(++ptr) == '?') { + switch (*(++ptr)) { + case ':': /* Non-extracting bracket */ + bravalue = OP_BRA; + ptr++; + break; + + case '=': /* Positive lookahead */ + bravalue = OP_ASSERT; + ptr++; + break; + + case '!': /* Negative lookahead */ + bravalue = OP_ASSERT_NOT; + ptr++; + break; + + /* Character after (? not specially recognized */ + + default: + *errorCodePtr = ERR12; + goto FAILED; + } + } + + /* Else we have a referencing group; adjust the opcode. If the bracket + number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and + arrange for the true number to follow later, in an OP_BRANUMBER item. */ + + else { + if (++(*brackets) > EXTRACT_BASIC_MAX) { + bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; + code[3 + LINK_SIZE] = OP_BRANUMBER; + put2ByteValue(code + 4 + LINK_SIZE, *brackets); + skipBytes = 5; + } + else + bravalue = OP_BRA + *brackets; + } + + /* Process nested bracketed re. We copy code into a non-variable + in order to be able to pass its address because some compilers + complain otherwise. Pass in a new setting for the ims options + if they have changed. */ + + previous = code; + *code = bravalue; + tempcode = code; + tempreqvary = cd.reqVaryOpt; /* Save value before bracket */ + { + unsigned bracketsBeforeRecursion = *brackets; + if (!compileBracket( + options, + brackets, /* Extracting bracket count */ + &tempcode, /* Where to put code (updated) */ + &ptr, /* Input pointer (updated) */ + patternEnd, + errorCodePtr, /* Where to put an error message */ + skipBytes, /* Skip over OP_BRANUMBER */ + &subFirstByte, /* For possible first char */ + &subReqByte, /* For possible last char */ + cd)) /* Tables block */ + goto FAILED; + unsigned enclosedBrackets = (*brackets - bracketsBeforeRecursion); + unsigned limitBracket = minBracket + enclosedBrackets + (bravalue > OP_BRA); + if (!((minBracket & 0xff) == minBracket && (limitBracket & 0xff) == limitBracket)) { + *errorCodePtr = ERR17; + return false; + } + JS_ASSERT(minBracket <= limitBracket); + put2ByteValue(code + 1 + LINK_SIZE, minBracket << 8 | limitBracket); + } + + /* At the end of compiling, code is still pointing to the start of the + group, while tempcode has been updated to point past the end of the group + and any option resetting that may follow it. The pattern pointer (ptr) + is on the bracket. */ + + /* Handle updating of the required and first characters. Update for normal + brackets of all kinds, and conditions with two branches (see code above). + If the bracket is followed by a quantifier with zero repeat, we have to + back off. Hence the definition of zeroReqByte and zeroFirstByte outside the + main loop so that they can be accessed for the back off. */ + + zeroReqByte = reqByte; + zeroFirstByte = firstByte; + didGroupSetFirstByte = false; + + if (bravalue >= OP_BRA) { + /* If we have not yet set a firstByte in this branch, take it from the + subpattern, remembering that it was set here so that a repeat of more + than one can replicate it as reqByte if necessary. If the subpattern has + no firstByte, set "none" for the whole branch. In both cases, a zero + repeat forces firstByte to "none". */ + + if (firstByte == REQ_UNSET) { + if (subFirstByte >= 0) { + firstByte = subFirstByte; + didGroupSetFirstByte = true; + } + else + firstByte = REQ_NONE; + zeroFirstByte = REQ_NONE; + } + + /* If firstByte was previously set, convert the subpattern's firstByte + into reqByte if there wasn't one, using the vary flag that was in + existence beforehand. */ + + else if (subFirstByte >= 0 && subReqByte < 0) + subReqByte = subFirstByte | tempreqvary; + + /* If the subpattern set a required byte (or set a first byte that isn't + really the first byte - see above), set it. */ + + if (subReqByte >= 0) + reqByte = subReqByte; + } + + /* For a forward assertion, we take the reqByte, if set. This can be + helpful if the pattern that follows the assertion doesn't set a different + char. For example, it's useful for /(?=abcde).+/. We can't set firstByte + for an assertion, however because it leads to incorrect effect for patterns + such as /(?=a)a.+/ when the "real" "a" would then become a reqByte instead + of a firstByte. This is overcome by a scan at the end if there's no + firstByte, looking for an asserted first char. */ + + else if (bravalue == OP_ASSERT && subReqByte >= 0) + reqByte = subReqByte; + + /* Now update the main code pointer to the end of the group. */ + + code = tempcode; + + /* Error if hit end of pattern */ + + if (ptr >= patternEnd || *ptr != ')') { + *errorCodePtr = ERR14; + goto FAILED; + } + break; + + } + /* Check \ for being a real metacharacter; if not, fall through and handle + it as a data character at the start of a string. Escape items are checked + for validity in the pre-compiling pass. */ + + case '\\': + tempptr = ptr; + c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, false); + + /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values + are arranged to be the negation of the corresponding OP_values. For the + back references, the values are ESC_REF plus the reference number. Only + back references and those types that consume a character may be repeated. + We can test for values between ESC_b and ESC_w for the latter; this may + have to change if any new ones are ever created. */ + + if (c < 0) { + /* For metasequences that actually match a character, we disable the + setting of a first character if it hasn't already been set. */ + + if (firstByte == REQ_UNSET && -c > ESC_b && -c <= ESC_w) + firstByte = REQ_NONE; + + /* Set values to reset to if this is followed by a zero repeat. */ + + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + + /* Back references are handled specially */ + + if (-c >= ESC_REF) { + int number = -c - ESC_REF; + previous = code; + *code++ = OP_REF; + put2ByteValueAndAdvance(code, number); + } + + /* For the rest, we can obtain the OP value by negating the escape + value */ + + else { + previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL; + *code++ = -c; + } + continue; + } + + /* Fall through. */ + + /* Handle a literal character. It is guaranteed not to be whitespace or # + when the extended flag is set. If we are in UTF-8 mode, it may be a + multi-byte literal character. */ + + default: + NORMAL_CHAR: + + previous = code; + + if (c < 128) { + mcLength = 1; + mcbuffer[0] = c; + + if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') { + *code++ = OP_ASCII_LETTER_IGNORING_CASE; + *code++ = c | 0x20; + } else { + *code++ = OP_ASCII_CHAR; + *code++ = c; + } + } else { + mcLength = encodeUTF8(c, mcbuffer); + + *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR; + for (c = 0; c < mcLength; c++) + *code++ = mcbuffer[c]; + } + + /* Set the first and required bytes appropriately. If no previous first + byte, set it from this character, but revert to none on a zero repeat. + Otherwise, leave the firstByte value alone, and don't change it on a zero + repeat. */ + + if (firstByte == REQ_UNSET) { + zeroFirstByte = REQ_NONE; + zeroReqByte = reqByte; + + /* If the character is more than one byte long, we can set firstByte + only if it is not to be matched caselessly. */ + + if (mcLength == 1 || reqCaseOpt == 0) { + firstByte = mcbuffer[0] | reqCaseOpt; + if (mcLength != 1) + reqByte = code[-1] | cd.reqVaryOpt; + } + else + firstByte = reqByte = REQ_NONE; + } + + /* firstByte was previously set; we can set reqByte only the length is + 1 or the matching is caseful. */ + + else { + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + if (mcLength == 1 || reqCaseOpt == 0) + reqByte = code[-1] | reqCaseOpt | cd.reqVaryOpt; + } + + break; /* End of literal character handling */ + } + } /* end of big loop */ + + /* Control never reaches here by falling through, only by a goto for all the + error states. Pass back the position in the pattern so that it can be displayed + to the user for diagnosing the error. */ + +FAILED: + *ptrPtr = ptr; + return false; +} + +/************************************************* +* Compile sequence of alternatives * +*************************************************/ + +/* On entry, ptr is pointing past the bracket character, but on return +it points to the closing bracket, or vertical bar, or end of string. +The code variable is pointing at the byte into which the BRA operator has been +stored. If the ims options are changed at the start (for a (?ims: group) or +during any branch, we need to insert an OP_OPT item at the start of every +following branch to ensure they get set correctly at run time, and also pass +the new options into every subsequent branch compile. + +Argument: + options option bits, including any changes for this subpattern + brackets -> int containing the number of extracting brackets used + codePtr -> the address of the current code pointer + ptrPtr -> the address of the current pattern pointer + errorCodePtr -> pointer to error code variable + skipBytes skip this many bytes at start (for OP_BRANUMBER) + firstbyteptr place to put the first required character, or a negative number + reqbyteptr place to put the last required character, or a negative number + cd points to the data block with tables pointers etc. + +Returns: true on success +*/ + +static bool +compileBracket(int options, int* brackets, unsigned char** codePtr, + const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int skipBytes, + int* firstbyteptr, int* reqbyteptr, CompileData& cd) +{ + const UChar* ptr = *ptrPtr; + unsigned char* code = *codePtr; + unsigned char* lastBranch = code; + unsigned char* start_bracket = code; + int firstByte = REQ_UNSET; + int reqByte = REQ_UNSET; + + /* Offset is set zero to mark that this bracket is still open */ + + putLinkValueAllowZero(code + 1, 0); + code += 1 + LINK_SIZE + skipBytes; + + /* Loop for each alternative branch */ + + while (true) { + /* Now compile the branch */ + + int branchFirstByte; + int branchReqByte; + if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorCodePtr, + &branchFirstByte, &branchReqByte, cd)) { + *ptrPtr = ptr; + return false; + } + + /* If this is the first branch, the firstByte and reqByte values for the + branch become the values for the regex. */ + + if (*lastBranch != OP_ALT) { + firstByte = branchFirstByte; + reqByte = branchReqByte; + } + + /* If this is not the first branch, the first char and reqByte have to + match the values from all the previous branches, except that if the previous + value for reqByte didn't have REQ_VARY set, it can still match, and we set + REQ_VARY for the regex. */ + + else { + /* If we previously had a firstByte, but it doesn't match the new branch, + we have to abandon the firstByte for the regex, but if there was previously + no reqByte, it takes on the value of the old firstByte. */ + + if (firstByte >= 0 && firstByte != branchFirstByte) { + if (reqByte < 0) + reqByte = firstByte; + firstByte = REQ_NONE; + } + + /* If we (now or from before) have no firstByte, a firstByte from the + branch becomes a reqByte if there isn't a branch reqByte. */ + + if (firstByte < 0 && branchFirstByte >= 0 && branchReqByte < 0) + branchReqByte = branchFirstByte; + + /* Now ensure that the reqbytes match */ + + if ((reqByte & ~REQ_VARY) != (branchReqByte & ~REQ_VARY)) + reqByte = REQ_NONE; + else + reqByte |= branchReqByte; /* To "or" REQ_VARY */ + } + + /* Reached end of expression, either ')' or end of pattern. Go back through + the alternative branches and reverse the chain of offsets, with the field in + the BRA item now becoming an offset to the first alternative. If there are + no alternatives, it points to the end of the group. The length in the + terminating ket is always the length of the whole bracketed item. + Return leaving the pointer at the terminating char. */ + + if (ptr >= patternEnd || *ptr != '|') { + int length = code - lastBranch; + do { + int prevLength = getLinkValueAllowZero(lastBranch + 1); + putLinkValue(lastBranch + 1, length); + length = prevLength; + lastBranch -= length; + } while (length > 0); + + /* Fill in the ket */ + + *code = OP_KET; + putLinkValue(code + 1, code - start_bracket); + code += 1 + LINK_SIZE; + + /* Set values to pass back */ + + *codePtr = code; + *ptrPtr = ptr; + *firstbyteptr = firstByte; + *reqbyteptr = reqByte; + return true; + } + + /* Another branch follows; insert an "or" node. Its length field points back + to the previous branch while the bracket remains open. At the end the chain + is reversed. It's done like this so that the start of the bracket has a + zero offset until it is closed, making it possible to detect recursion. */ + + *code = OP_ALT; + putLinkValue(code + 1, code - lastBranch); + lastBranch = code; + code += 1 + LINK_SIZE; + ptr++; + } + JS_NOT_REACHED("No fallthru."); +} + +/************************************************* +* Check for anchored expression * +*************************************************/ + +/* Try to find out if this is an anchored regular expression. Consider each +alternative branch. If they all start OP_CIRC, or with a bracket +all of whose alternatives start OP_CIRC (recurse ad lib), then +it's anchored. + +Arguments: + code points to start of expression (the bracket) + captureMap a bitmap of which brackets we are inside while testing; this + handles up to substring 31; all brackets after that share + the zero bit + backrefMap the back reference bitmap +*/ + +static bool branchIsAnchored(const unsigned char* code) +{ + const unsigned char* scode = firstSignificantOpcode(code); + int op = *scode; + + /* Brackets */ + if (op >= OP_BRA || op == OP_ASSERT) + return bracketIsAnchored(scode); + + /* Check for explicit anchoring */ + return op == OP_CIRC; +} + +static bool bracketIsAnchored(const unsigned char* code) +{ + do { + if (!branchIsAnchored(code + 1 + LINK_SIZE)) + return false; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); /* Loop for each alternative */ + return true; +} + +/************************************************* +* Check for starting with ^ or .* * +*************************************************/ + +/* This is called to find out if every branch starts with ^ or .* so that +"first char" processing can be done to speed things up in multiline +matching and for non-DOTALL patterns that start with .* (which must start at +the beginning or after \n) + +Except when the .* appears inside capturing parentheses, and there is a +subsequent back reference to those parentheses. By keeping a bitmap of the +first 31 back references, we can catch some of the more common cases more +precisely; all the greater back references share a single bit. + +Arguments: + code points to start of expression (the bracket) + captureMap a bitmap of which brackets we are inside while testing; this + handles up to substring 31; all brackets after that share + the zero bit + backrefMap the back reference bitmap +*/ + +static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) +{ + const unsigned char* scode = firstSignificantOpcode(code); + int op = *scode; + + /* Capturing brackets */ + if (op > OP_BRA) { + int captureNum = op - OP_BRA; + if (captureNum > EXTRACT_BASIC_MAX) + captureNum = get2ByteValue(scode + 2 + LINK_SIZE); + int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1; + return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap); + } + + /* Other brackets */ + if (op == OP_BRA || op == OP_ASSERT) + return bracketNeedsLineStart(scode, captureMap, backrefMap); + + /* .* means "start at start or after \n" if it isn't in brackets that + may be referenced. */ + + if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) + return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap); + + /* Explicit ^ */ + return op == OP_CIRC || op == OP_BOL; +} + +static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) +{ + do { + if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap)) + return false; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); /* Loop for each alternative */ + return true; +} + +/************************************************* +* Check for asserted fixed first char * +*************************************************/ + +/* During compilation, the "first char" settings from forward assertions are +discarded, because they can cause conflicts with actual literals that follow. +However, if we end up without a first char setting for an unanchored pattern, +it is worth scanning the regex to see if there is an initial asserted first +char. If all branches start with the same asserted char, or with a bracket all +of whose alternatives start with the same asserted char (recurse ad lib), then +we return that char, otherwise -1. + +Arguments: + code points to start of expression (the bracket) + options pointer to the options (used to check casing changes) + inassert true if in an assertion + +Returns: -1 or the fixed first char +*/ + +static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert) +{ + const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code); + int op = *scode; + + if (op >= OP_BRA) + op = OP_BRA; + + switch (op) { + default: + return -1; + + case OP_BRA: + case OP_ASSERT: + return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT); + + case OP_EXACT: + scode += 2; + /* Fall through */ + + case OP_CHAR: + case OP_CHAR_IGNORING_CASE: + case OP_ASCII_CHAR: + case OP_ASCII_LETTER_IGNORING_CASE: + case OP_PLUS: + case OP_MINPLUS: + if (!inassert) + return -1; + return scode[1]; + } +} + +static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert) +{ + int c = -1; + do { + int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert); + if (d < 0) + return -1; + if (c < 0) + c = d; + else if (c != d) + return -1; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); + return c; +} + +static inline int multiplyWithOverflowCheck(int a, int b) +{ + if (!a || !b) + return 0; + if (a > MAX_PATTERN_SIZE / b) + return -1; + return a * b; +} + +static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase, + CompileData& cd, ErrorCode& errorcode) +{ + /* Make a pass over the pattern to compute the + amount of store required to hold the compiled code. This does not have to be + perfect as long as errors are overestimates. */ + + if (patternLength > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + + int length = BRA_LEN; /* For initial BRA. */ + int branch_extra = 0; + int lastitemlength = 0; + unsigned brastackptr = 0; + int brastack[BRASTACK_SIZE]; + unsigned char bralenstack[BRASTACK_SIZE]; + int bracount = 0; + + const UChar* ptr = (const UChar*)(pattern - 1); + const UChar* patternEnd = (const UChar*)(pattern + patternLength); + + while (++ptr < patternEnd) { + int minRepeats = 0, maxRepeats = 0; + int c = *ptr; + + switch (c) { + /* A backslashed item may be an escaped data character or it may be a + character type. */ + + case '\\': + c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false); + if (errorcode != 0) + return -1; + + lastitemlength = 1; /* Default length of last item for repeats */ + + if (c >= 0) { /* Data character */ + length += 2; /* For a one-byte character */ + + if (c > 127) { + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (c <= jsc_pcre_utf8_table1[i]) break; + length += i; + lastitemlength += i; + } + + continue; + } + + /* Other escapes need one byte */ + + length++; + + /* A back reference needs an additional 2 bytes, plus either one or 5 + bytes for a repeat. We also need to keep the value of the highest + back reference. */ + + if (c <= -ESC_REF) { + int refnum = -c - ESC_REF; + cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1; + if (refnum > cd.topBackref) + cd.topBackref = refnum; + length += 2; /* For single back reference */ + if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode) + return -1; + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + else + length += 5; + if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; + } + } + continue; + + case '^': /* Single-byte metacharacters */ + case '.': + case '$': + length++; + lastitemlength = 1; + continue; + + case '*': /* These repeats won't be after brackets; */ + case '+': /* those are handled separately */ + case '?': + length++; + goto POSSESSIVE; + + /* This covers the cases of braced repeats after a single char, metachar, + class, or back reference. */ + + case '{': + if (!isCountedRepeat(ptr + 1, patternEnd)) + goto NORMAL_CHAR; + ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode); + if (errorcode != 0) + return -1; + + /* These special cases just insert one extra opcode */ + + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + + /* These cases might insert additional copies of a preceding character. */ + + else { + if (minRepeats != 1) { + length -= lastitemlength; /* Uncount the original char or metachar */ + if (minRepeats > 0) + length += 5 + lastitemlength; + } + length += lastitemlength + ((maxRepeats > 0) ? 5 : 1); + } + + if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; /* Needs no extra length */ + + POSSESSIVE: /* Test for possessive quantifier */ + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */ + } + continue; + + /* An alternation contains an offset to the next branch or ket. If any ims + options changed in the previous branch(es), and/or if we are in a + lookbehind assertion, extra space will be needed at the start of the + branch. This is handled by branch_extra. */ + + case '|': + if (brastackptr == 0) + cd.needOuterBracket = true; + length += 1 + LINK_SIZE + branch_extra; + continue; + + /* A character class uses 33 characters provided that all the character + values are less than 256. Otherwise, it uses a bit map for low valued + characters, and individual items for others. Don't worry about character + types that aren't allowed in classes - they'll get picked up during the + compile. A character class that contains only one single-byte character + uses 2 or 3 bytes, depending on whether it is negated or not. Notice this + where we can. (In UTF-8 mode we can do this only for chars < 128.) */ + + case '[': { + int class_optcount; + if (*(++ptr) == '^') { + class_optcount = 10; /* Greater than one */ + ptr++; + } + else + class_optcount = 0; + + bool class_utf8 = false; + + for (; ptr < patternEnd && *ptr != ']'; ++ptr) { + /* Check for escapes */ + + if (*ptr == '\\') { + c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); + if (errorcode != 0) + return -1; + + /* Handle escapes that turn into characters */ + + if (c >= 0) + goto NON_SPECIAL_CHARACTER; + + /* Escapes that are meta-things. The normal ones just affect the + bit map, but Unicode properties require an XCLASS extended item. */ + + else + class_optcount = 10; /* \d, \s etc; make sure > 1 */ + } + + /* Anything else increments the possible optimization count. We have to + detect ranges here so that we can compute the number of extra ranges for + caseless wide characters when UCP support is available. If there are wide + characters, we are going to have to use an XCLASS, even for single + characters. */ + + else { + c = *ptr; + + /* Come here from handling \ above when it escapes to a char value */ + + NON_SPECIAL_CHARACTER: + class_optcount++; + + int d = -1; + if (safelyCheckNextChar(ptr, patternEnd, '-')) { + const UChar* hyptr = ptr++; + if (safelyCheckNextChar(ptr, patternEnd, '\\')) { + ptr++; + d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); + if (errorcode != 0) + return -1; + } + else if ((ptr + 1 < patternEnd) && ptr[1] != ']') + d = *++ptr; + if (d < 0) + ptr = hyptr; /* go back to hyphen as data */ + } + + /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or > + 127 for caseless matching, we will need to use an XCLASS. */ + + if (d >= 0) { + class_optcount = 10; /* Ensure > 1 */ + if (d < c) { + errorcode = ERR8; + return -1; + } + + if ((d > 255 || (ignoreCase && d > 127))) { + unsigned char buffer[6]; + if (!class_utf8) /* Allow for XCLASS overhead */ + { + class_utf8 = true; + length += LINK_SIZE + 2; + } + + /* If we have UCP support, find out how many extra ranges are + needed to map the other case of characters within this range. We + have to mimic the range optimization here, because extending the + range upwards might push d over a boundary that makes it use + another byte in the UTF-8 representation. */ + + if (ignoreCase) { + int occ, ocd; + int cc = c; + int origd = d; + while (getOthercaseRange(&cc, origd, &occ, &ocd)) { + if (occ >= c && ocd <= d) + continue; /* Skip embedded */ + + if (occ < c && ocd >= c - 1) /* Extend the basic range */ + { /* if there is overlap, */ + c = occ; /* noting that if occ < c */ + continue; /* we can't have ocd > d */ + } /* because a subrange is */ + if (ocd > d && occ <= d + 1) /* always shorter than */ + { /* the basic range. */ + d = ocd; + continue; + } + + /* An extra item is needed */ + + length += 1 + encodeUTF8(occ, buffer) + + ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer)); + } + } + + /* The length of the (possibly extended) range */ + + length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer); + } + + } + + /* We have a single character. There is nothing to be done unless we + are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must + allow for an XCL_SINGLE item, doubled for caselessness if there is UCP + support. */ + + else { + if ((c > 255 || (ignoreCase && c > 127))) { + unsigned char buffer[6]; + class_optcount = 10; /* Ensure > 1 */ + if (!class_utf8) /* Allow for XCLASS overhead */ + { + class_utf8 = true; + length += LINK_SIZE + 2; + } + length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer)); + } + } + } + } + + if (ptr >= patternEnd) { /* Missing terminating ']' */ + errorcode = ERR6; + return -1; + } + + /* We can optimize when there was only one optimizable character. + Note that this does not detect the case of a negated single character. + In that case we do an incorrect length computation, but it's not a serious + problem because the computed length is too large rather than too small. */ + + if (class_optcount == 1) + goto NORMAL_CHAR; + + /* Here, we handle repeats for the class opcodes. */ + { + length += 33; + + /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, + we also need extra for wrapping the whole thing in a sub-pattern. */ + + if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode != 0) + return -1; + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + else + length += 5; + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; + } else if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; + } + } + continue; + } + + /* Brackets may be genuine groups or special things */ + + case '(': { + int branch_newextra = 0; + int bracket_length = BRA_LEN; + bool capturing = false; + + /* Handle special forms of bracket, which all start (? */ + + if (safelyCheckNextChar(ptr, patternEnd, '?')) { + switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) { + /* Non-referencing groups and lookaheads just move the pointer on, and + then behave like a non-special bracket, except that they don't increment + the count of extracting brackets. Ditto for the "once only" bracket, + which is in Perl from version 5.005. */ + + case ':': + case '=': + case '!': + ptr += 2; + break; + + /* Else loop checking valid options until ) is met. Anything else is an + error. If we are without any brackets, i.e. at top level, the settings + act as if specified in the options, so massage the options immediately. + This is for backward compatibility with Perl 5.004. */ + + default: + errorcode = ERR12; + return -1; + } + } else + capturing = true; + + /* Capturing brackets must be counted so we can process escapes in a + Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need + an additional 3 bytes of memory per capturing bracket. */ + + if (capturing) { + bracount++; + if (bracount > EXTRACT_BASIC_MAX) + bracket_length += 3; + } + + /* Save length for computing whole length at end if there's a repeat that + requires duplication of the group. Also save the current value of + branch_extra, and start the new group with the new value. If non-zero, this + will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ + + if (brastackptr >= sizeof(brastack)/sizeof(int)) { + errorcode = ERR17; + return -1; + } + + bralenstack[brastackptr] = branch_extra; + branch_extra = branch_newextra; + + brastack[brastackptr++] = length; + length += bracket_length; + continue; + } + + /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we + have to replicate this bracket up to that many times. If brastackptr is + 0 this is an unmatched bracket which will generate an error, but take care + not to try to access brastack[-1] when computing the length and restoring + the branch_extra value. */ + + case ')': { + int duplength; + length += KET_LEN; + if (brastackptr > 0) { + duplength = length - brastack[--brastackptr]; + branch_extra = bralenstack[brastackptr]; + } + else + duplength = 0; + + /* Leave ptr at the final char; for readRepeatCounts this happens + automatically; for the others we need an increment. */ + + if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode) + return -1; + } else if (c == '*') { + minRepeats = 0; + maxRepeats = -1; + ptr++; + } else if (c == '+') { + minRepeats = 1; + maxRepeats = -1; + ptr++; + } else if (c == '?') { + minRepeats = 0; + maxRepeats = 1; + ptr++; + } else { + minRepeats = 1; + maxRepeats = 1; + } + + /* If the minimum is zero, we have to allow for an OP_BRAZERO before the + group, and if the maximum is greater than zero, we have to replicate + maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting + bracket set. */ + + int repeatsLength; + if (minRepeats == 0) { + length++; + if (maxRepeats > 0) { + repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + BRA_LEN + KET_LEN + OPCODE_LEN); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength; + if (length > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + } + } + + /* When the minimum is greater than zero, we have to replicate up to + minval-1 times, with no additions required in the copies. Then, if there + is a limited maximum we have to replicate up to maxval-1 times allowing + for a BRAZERO item before each optional copy and nesting brackets for all + but one of the optional copies. */ + + else { + repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength; + if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */ + repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + BRAZERO_LEN + BRA_LEN + KET_LEN); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength - (2 + 2 * LINK_SIZE); + } + if (length > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + } + + /* Allow space for once brackets for "possessive quantifier" */ + + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; + } + continue; + } + + /* Non-special character. It won't be space or # in extended mode, so it is + always a genuine character. If we are in a \Q...\E sequence, check for the + end; if not, we have a literal. */ + + default: + NORMAL_CHAR: + length += 2; /* For a one-byte character */ + lastitemlength = 1; /* Default length of last item for repeats */ + + if (c > 127) { + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (c <= jsc_pcre_utf8_table1[i]) + break; + length += i; + lastitemlength += i; + } + + continue; + } + } + + length += KET_LEN + OPCODE_LEN; /* For final KET and END */ + + cd.numCapturingBrackets = bracount; + return length; +} + +/************************************************* +* Compile a Regular Expression * +*************************************************/ + +/* This function takes a string and returns a pointer to a block of store +holding a compiled version of the expression. The original API for this +function had no error code return variable; it is retained for backwards +compatibility. The new function is given a new name. + +Arguments: + pattern the regular expression + options various option bits + errorCodePtr pointer to error code variable (pcre_compile2() only) + can be NULL if you don't want a code value + error pointer to pointer to error text + erroroffset ptr offset in pattern where error was detected + tables pointer to character tables or NULL + +Returns: pointer to compiled data block, or NULL on error, + with error and erroroffset set +*/ + +static inline JSRegExp* returnError(ErrorCode errorcode, int *error) +{ + *error = static_cast(errorcode); + return 0; +} + +JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, + JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline, + unsigned* numSubpatterns, int *error) +{ + /* We can't pass back an error message if error is NULL; I guess the best we + can do is just return NULL, but we can set a code value if there is a code pointer. */ + if (!error) + return 0; + *error = 0; + + CompileData cd; + + ErrorCode errorcode = ERR0; + /* Call this once just to count the brackets. */ + calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); + /* Call it again to compute the length. */ + int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); + if (errorcode) + return returnError(errorcode, error); + + if (length > MAX_PATTERN_SIZE) + return returnError(ERR16, error); + + size_t size = length + sizeof(JSRegExp); + JSRegExp* re = reinterpret_cast(js::OffTheBooks::array_new(size)); + if (!re) + return returnError(ERR13, error); + + re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0); + + /* The starting points of the name/number translation table and of the code are + passed around in the compile data block. */ + + const unsigned char* codeStart = (const unsigned char*)(re + 1); + + /* Set up a starting, non-extracting bracket, then compile the expression. On + error, errorcode will be set non-zero, so we don't need to look at the result + of the function here. */ + + const UChar* ptr = (const UChar*)pattern; + const UChar* patternEnd = pattern + patternLength; + unsigned char* code = const_cast(codeStart); + int firstByte, reqByte; + int bracketCount = 0; + if (!cd.needOuterBracket) + compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstByte, &reqByte, cd); + else { + *code = OP_BRA; + unsigned char * const codeBefore = code; + compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 2, &firstByte, &reqByte, cd); + JS_ASSERT((bracketCount & 0xff) == bracketCount); + put2ByteValue(codeBefore + 1 + LINK_SIZE, 0 << 8 | (bracketCount & 0xff)); + } + re->topBracket = bracketCount; + re->topBackref = cd.topBackref; + + /* If not reached end of pattern on success, there's an excess bracket. */ + + if (errorcode == 0 && ptr < patternEnd) + errorcode = ERR10; + + /* Fill in the terminating state and check for disastrous overflow, but + if debugging, leave the test till after things are printed out. */ + + *code++ = OP_END; + + JS_ASSERT(code - codeStart <= length); + if (code - codeStart > length) + errorcode = ERR7; + + /* Give an error if there's back reference to a non-existent capturing + subpattern. */ + + if (re->topBackref > re->topBracket) + errorcode = ERR15; + + /* Failed to compile, or error while post-processing */ + + if (errorcode != ERR0) { + js::Foreground::array_delete(reinterpret_cast(re)); + return returnError(errorcode, error); + } + + /* If the anchored option was not passed, set the flag if we can determine that + the pattern is anchored by virtue of ^ characters or \A or anything else (such + as starting with .* when DOTALL is set). + + Otherwise, if we know what the first character has to be, save it, because that + speeds up unanchored matches no end. If not, see if we can set the + UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches + start with ^. and also when all branches start with .* for non-DOTALL matches. + */ + + if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart)) + re->options |= IsAnchoredOption; + else { + if (firstByte < 0) { + firstByte = (cd.needOuterBracket + ? bracketFindFirstAssertedCharacter(codeStart, false) + : branchFindFirstAssertedCharacter(codeStart, false)) + | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0); + } + if (firstByte >= 0) { + int ch = firstByte & 255; + if (ch < 127) { + re->firstByte = ((firstByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstByte; + re->options |= UseFirstByteOptimizationOption; + } + } else { + if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap)) + re->options |= UseMultiLineFirstByteOptimizationOption; + } + } + + /* For an anchored pattern, we use the "required byte" only if it follows a + variable length item in the regex. Remove the caseless flag for non-caseable + bytes. */ + + if (reqByte >= 0 && (!(re->options & IsAnchoredOption) || (reqByte & REQ_VARY))) { + int ch = reqByte & 255; + if (ch < 127) { + re->reqByte = ((reqByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqByte & ~REQ_IGNORE_CASE) : reqByte; + re->options |= UseRequiredByteOptimizationOption; + } + } + + if (numSubpatterns) + *numSubpatterns = re->topBracket; + + return re; +} + +void jsRegExpFree(JSRegExp* re) +{ + js::Foreground::array_delete(reinterpret_cast(re)); +} diff --git a/js/src/yarr/pcre/pcre_exec.cpp b/js/src/yarr/pcre/pcre_exec.cpp new file mode 100644 index 000000000000..c2d154d67b8e --- /dev/null +++ b/js/src/yarr/pcre/pcre_exec.cpp @@ -0,0 +1,2193 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + Copyright (C) 2007 Eric Seidel + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains jsRegExpExecute(), the externally visible function +that does pattern matching using an NFA algorithm, following the rules from +the JavaScript specification. There are also some supporting functions. */ + +#include "pcre_internal.h" + +#include +#include "yarr/jswtfbridge.h" +#include "yarr/wtf/ASCIICType.h" +#include "jsarena.h" +#include "jscntxt.h" + +using namespace WTF; + +#if !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO +#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION +#endif + +/* Note: Webkit sources have USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP disabled. */ +/* Note: There are hardcoded constants all over the place, but in the port of + Yarr to TraceMonkey two bytes are added to the OP_BRA* opcodes, so the + instruction stream now looks like this at the start of a bracket group: + + OP_BRA* [link:LINK_SIZE] [minNestedBracket,maxNestedBracket:2] + + Both capturing and non-capturing brackets encode this information. */ + +/* Avoid warnings on Windows. */ +#undef min +#undef max + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION +typedef int ReturnLocation; +#else +typedef void* ReturnLocation; +#endif + +/* Node on a stack of brackets. This is used to detect and reject + matches of the empty string per ECMAScript repeat match rules. This + also prevents infinite loops on quantified empty matches. One node + represents the start state at the start of this bracket group. */ +struct BracketChainNode { + BracketChainNode* previousBracket; + const UChar* bracketStart; + /* True if the minimum number of matches was already satisfied + when we started matching this group. */ + bool minSatisfied; +}; + +struct MatchFrame { + ReturnLocation returnLocation; + struct MatchFrame* previousFrame; + int *savedOffsets; + /* The frame allocates saved offsets into the regular expression arena pool so + that they can be restored during backtracking. */ + size_t savedOffsetsSize; + JSArenaPool *regExpPool; + + MatchFrame() : savedOffsetsSize(0), regExpPool(0) {} + void init(JSArenaPool *regExpPool) { this->regExpPool = regExpPool; } + + /* Function arguments that may change */ + struct { + const UChar* subjectPtr; + const unsigned char* instructionPtr; + int offsetTop; + BracketChainNode* bracketChain; + } args; + + + /* PCRE uses "fake" recursion built off of gotos, thus + stack-based local variables are not safe to use. Instead we have to + store local variables on the current MatchFrame. */ + struct { + const unsigned char* data; + const unsigned char* startOfRepeatingBracket; + const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare + const unsigned char* instructionPtrAtStartOfOnce; + + int repeatOthercase; + int savedSubjectOffset; + + int ctype; + int fc; + int fi; + int length; + int max; + int number; + int offset; + int skipBytes; + int minBracket; + int limitBracket; + int bracketsBefore; + bool minSatisfied; + + BracketChainNode bracketChainNode; + } locals; + + void saveOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + JS_ASSERT(regExpPool); + JS_ASSERT(minBracket >= 0); + JS_ASSERT(limitBracket >= minBracket); + JS_ASSERT(offsetEnd >= 0); + if (minBracket == limitBracket) + return; + const size_t newSavedOffsetCount = 3 * (limitBracket - minBracket); + /* Increase saved offset space if necessary. */ + { + size_t targetSize = sizeof(*savedOffsets) * newSavedOffsetCount; + if (savedOffsetsSize < targetSize) { + JS_ARENA_ALLOCATE_CAST(savedOffsets, int *, regExpPool, targetSize); + JS_ASSERT(savedOffsets); /* FIXME: error code, bug 574459. */ + savedOffsetsSize = targetSize; + } + } + for (unsigned i = 0; i < unsigned(limitBracket - minBracket); ++i) { + int bracketIter = minBracket + i; + JS_ASSERT(2 * bracketIter + 1 <= offsetEnd); + int start = offsets[2 * bracketIter]; + int end = offsets[2 * bracketIter + 1]; + JS_ASSERT(bracketIter <= offsetEnd); + int offset = offsets[offsetEnd - bracketIter]; + DPRINTF(("saving bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); + JS_ASSERT(start <= end); + JS_ASSERT(i * 3 + 2 < newSavedOffsetCount); + savedOffsets[i * 3 + 0] = start; + savedOffsets[i * 3 + 1] = end; + savedOffsets[i * 3 + 2] = offset; + } + } + + void clobberOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + for (int i = 0; i < limitBracket - minBracket; ++i) { + int bracketIter = minBracket + i; + JS_ASSERT(2 * bracketIter + 1 < offsetEnd); + offsets[2 * bracketIter + 0] = -1; + offsets[2 * bracketIter + 1] = -1; + } + } + + void restoreOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + JS_ASSERT(regExpPool); + JS_ASSERT_IF(limitBracket > minBracket, savedOffsets); + for (int i = 0; i < limitBracket - minBracket; ++i) { + int bracketIter = minBracket + i; + int start = savedOffsets[i * 3 + 0]; + int end = savedOffsets[i * 3 + 1]; + int offset = savedOffsets[i * 3 + 2]; + DPRINTF(("restoring bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); + JS_ASSERT(start <= end); + offsets[2 * bracketIter + 0] = start; + offsets[2 * bracketIter + 1] = end; + offsets[offsetEnd - bracketIter] = offset; + } + } + + /* Extract the bracket data after the current opcode/link at |instructionPtr| into the locals. */ + void extractBrackets(const unsigned char *instructionPtr) { + uint16 bracketMess = get2ByteValue(instructionPtr + 1 + LINK_SIZE); + locals.minBracket = (bracketMess >> 8) & 0xff; + locals.limitBracket = (bracketMess & 0xff); + JS_ASSERT(locals.minBracket <= locals.limitBracket); + } + + /* At the start of a bracketed group, add the current subject pointer to the + stack of such pointers, to be re-instated at the end of the group when we hit + the closing ket. When match() is called in other circumstances, we don't add to + this stack. */ + void startNewGroup(bool minSatisfied) { + locals.bracketChainNode.previousBracket = args.bracketChain; + locals.bracketChainNode.bracketStart = args.subjectPtr; + locals.bracketChainNode.minSatisfied = minSatisfied; + args.bracketChain = &locals.bracketChainNode; + } +}; + +/* Structure for passing "static" information around between the functions +doing traditional NFA matching, so that they are thread-safe. */ + +struct MatchData { + int *offsetVector; /* Offset vector */ + int offsetEnd; /* One past the end */ + int offsetMax; /* The maximum usable for return data */ + bool offsetOverflow; /* Set if too many extractions */ + const UChar *startSubject; /* Start of the subject string */ + const UChar *endSubject; /* End of the subject string */ + const UChar *endMatchPtr; /* Subject position at end match */ + int endOffsetTop; /* Highwater mark at end of match */ + bool multiline; + bool ignoreCase; + + void setOffsetPair(size_t pairNum, int start, int end) { + JS_ASSERT(int(2 * pairNum + 1) < offsetEnd && int(pairNum) < offsetEnd); + JS_ASSERT(start <= end); + JS_ASSERT_IF(start < 0, start == end && start == -1); + DPRINTF(("setting offset pair at %u (%d, %d)\n", pairNum, start, end)); + offsetVector[2 * pairNum + 0] = start; + offsetVector[2 * pairNum + 1] = end; + } +}; + +/* The maximum remaining length of subject we are prepared to search for a +reqByte match. */ + +#define REQ_BYTE_MAX 1000 + +/* The below limit restricts the number of "recursive" match calls in order to +avoid spending exponential time on complex regular expressions. */ + +static const unsigned matchLimit = 1000000; + +/************************************************* +* Match a back-reference * +*************************************************/ + +/* If a back reference hasn't been set, the length that is passed is greater +than the number of characters left in the string, so the match fails. + +Arguments: + offset index into the offset vector + subjectPtr points into the subject + length length to be matched + md points to match data block + +Returns: true if matched +*/ + +static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md) +{ + const UChar* p = md.startSubject + md.offsetVector[offset]; + + /* Always fail if not enough characters left */ + + if (length > md.endSubject - subjectPtr) + return false; + + /* Separate the caselesss case for speed */ + + if (md.ignoreCase) { + while (length-- > 0) { + UChar c = *p++; + int othercase = jsc_pcre_ucp_othercase(c); + UChar d = *subjectPtr++; + if (c != d && othercase != d) + return false; + } + } + else { + while (length-- > 0) + if (*p++ != *subjectPtr++) + return false; + } + + return true; +} + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + +/* Use numbered labels and switch statement at the bottom of the match function. */ + +#define RMATCH_WHERE(num) num +#define RRETURN_LABEL RRETURN_SWITCH + +#else + +/* Use GCC's computed goto extension. */ + +/* For one test case this is more than 40% faster than the switch statement. +We could avoid the use of the num argument entirely by using local labels, +but using it for the GCC case as well as the non-GCC case allows us to share +a bit more code and notice if we use conflicting numbers.*/ + +#define RMATCH_WHERE(num) JS_EXTENSION(&&RRETURN_##num) +#define RRETURN_LABEL *stack.currentFrame->returnLocation + +#endif + +#define RECURSIVE_MATCH_COMMON(num) \ + goto RECURSE;\ + RRETURN_##num: \ + stack.popCurrentFrame(); + +#define RECURSIVE_MATCH(num, ra, rb) \ + do { \ + stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ + RECURSIVE_MATCH_COMMON(num) \ + } while (0) + +#define RECURSIVE_MATCH_NEW_GROUP(num, ra, rb, gm) \ + do { \ + stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ + stack.currentFrame->startNewGroup(gm); \ + RECURSIVE_MATCH_COMMON(num) \ + } while (0) + +#define RRETURN do { JS_EXTENSION_(goto RRETURN_LABEL); } while (0) + +#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0) + +/************************************************* +* Match from current position * +*************************************************/ + +/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character +in the subject string, while substringStart holds the value of subjectPtr at the start of the +last bracketed group - used for breaking infinite loops matching zero-length +strings. This function is called recursively in many circumstances. Whenever it +returns a negative (error) response, the outer match() call must also return the +same response. + +Arguments: + subjectPtr pointer in subject + instructionPtr position in code + offsetTop current top pointer + md pointer to "static" info for the match + +Returns: 1 if matched ) these values are >= 0 + 0 if failed to match ) + a negative error value if aborted by an error condition + (e.g. stopped by repeated call or recursion limit) +*/ + +static const unsigned numFramesOnStack = 16; + +struct MatchStack { + JSArenaPool *regExpPool; + void *regExpPoolMark; + + MatchStack(JSArenaPool *regExpPool) + : regExpPool(regExpPool) + , regExpPoolMark(JS_ARENA_MARK(regExpPool)) + , framesEnd(frames + numFramesOnStack) + , currentFrame(frames) + , size(1) // match() creates accesses the first frame w/o calling pushNewFrame + { + JS_ASSERT((sizeof(frames) / sizeof(frames[0])) == numFramesOnStack); + JS_ASSERT(regExpPool); + for (size_t i = 0; i < numFramesOnStack; ++i) + frames[i].init(regExpPool); + } + + ~MatchStack() { JS_ARENA_RELEASE(regExpPool, regExpPoolMark); } + + MatchFrame frames[numFramesOnStack]; + MatchFrame* framesEnd; + MatchFrame* currentFrame; + unsigned size; + + bool canUseStackBufferForNextFrame() { + return size < numFramesOnStack; + } + + MatchFrame* allocateNextFrame() { + if (canUseStackBufferForNextFrame()) + return currentFrame + 1; + // FIXME: bug 574459 -- no NULL check + MatchFrame *frame = js::OffTheBooks::new_(); + frame->init(regExpPool); + return frame; + } + + void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation) { + MatchFrame* newframe = allocateNextFrame(); + newframe->previousFrame = currentFrame; + + newframe->args.subjectPtr = currentFrame->args.subjectPtr; + newframe->args.offsetTop = currentFrame->args.offsetTop; + newframe->args.instructionPtr = instructionPtr; + newframe->args.bracketChain = bracketChain; + newframe->returnLocation = returnLocation; + size++; + + currentFrame = newframe; + } + + void popCurrentFrame() { + MatchFrame* oldFrame = currentFrame; + currentFrame = currentFrame->previousFrame; + if (size > numFramesOnStack) + js::Foreground::delete_(oldFrame); + size--; + } + + void popAllFrames() { + while (size) + popCurrentFrame(); + } +}; + +static int matchError(int errorCode, MatchStack& stack) +{ + stack.popAllFrames(); + return errorCode; +} + +/* Get the next UTF-8 character, not advancing the pointer, incrementing length + if there are extra bytes. This is called when we know we are in UTF-8 mode. */ + +static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len) +{ + c = *subjectPtr; + if ((c & 0xc0) == 0xc0) { + int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + int gcss = 6 * gcaa; + c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; + for (int gcii = 1; gcii <= gcaa; gcii++) { + gcss -= 6; + c |= (subjectPtr[gcii] & 0x3f) << gcss; + } + len += gcaa; + } +} + +static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats) +{ + // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR + static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 }; + static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 }; + + JS_ASSERT(instructionOffset >= 0); + JS_ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR)); + + minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2 + minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset]; + maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset]; +} + +/* Helper class for passing a flag value from one op to the next that runs. + This allows us to set the flag in certain ops. When the flag is read, it + will be true only if the previous op set the flag, otherwise it is false. */ +class LinearFlag { +public: + LinearFlag() : flag(false) {} + + bool readAndClear() { + bool rv = flag; + flag = false; + return rv; + } + + void set() { + flag = true; + } + +private: + bool flag; +}; + +static int +match(JSArenaPool *regExpPool, const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md) +{ + bool isMatch = false; + int min; + bool minimize = false; /* Initialization not really needed, but some compilers think so. */ + unsigned remainingMatchCount = matchLimit; + int othercase; /* Declare here to avoid errors during jumps */ + bool minSatisfied; + + MatchStack stack(regExpPool); + LinearFlag minSatNextBracket; + + /* The opcode jump table. */ +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP +#define EMIT_JUMP_TABLE_ENTRY(opcode) JS_EXTENSION(&&LABEL_OP_##opcode) + static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) }; +#undef EMIT_JUMP_TABLE_ENTRY +#endif + + /* One-time setup of the opcode jump table. */ +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + for (int i = 255; !opcodeJumpTable[i]; i--) + opcodeJumpTable[i] = &&CAPTURING_BRACKET; +#endif + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + // Shark shows this as a hot line + // Using a static const here makes this line disappear, but makes later access hotter (not sure why) + stack.currentFrame->returnLocation = JS_EXTENSION(&&RETURN); +#else + stack.currentFrame->returnLocation = 0; +#endif + stack.currentFrame->args.subjectPtr = subjectPtr; + stack.currentFrame->args.instructionPtr = instructionPtr; + stack.currentFrame->args.offsetTop = offsetTop; + stack.currentFrame->args.bracketChain = 0; + stack.currentFrame->startNewGroup(false); + + /* This is where control jumps back to to effect "recursion" */ + +RECURSE: + if (!--remainingMatchCount) + return matchError(JSRegExpErrorHitLimit, stack); + + /* Now start processing the operations. */ + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + while (true) +#endif + { + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP +#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode +#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr] +#else +#define BEGIN_OPCODE(opcode) case OP_##opcode +#define NEXT_OPCODE continue +#endif +#define LOCALS(__ident) (stack.currentFrame->locals.__ident) + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + NEXT_OPCODE; +#else + switch (*stack.currentFrame->args.instructionPtr) +#endif + { + /* Non-capturing bracket: optimized */ + + BEGIN_OPCODE(BRA): + NON_CAPTURING_BRACKET: + DPRINTF(("start non-capturing bracket\n")); + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); + /* If we see no ALT, we have to skip three bytes of bracket data (link plus nested + bracket data. */ + stack.currentFrame->locals.skipBytes = 3; + /* We must compute this value at the top, before we move the instruction pointer. */ + stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); + do { + /* We need to extract this into a variable so we can correctly pass it by value + through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ + minSatisfied = stack.currentFrame->locals.minSatisfied; + RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); + if (isMatch) { + DPRINTF(("non-capturing bracket succeeded\n")); + RRETURN; + } + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + DPRINTF(("non-capturing bracket failed\n")); + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + RRETURN; + + /* Skip over large extraction number data if encountered. */ + + BEGIN_OPCODE(BRANUMBER): + stack.currentFrame->args.instructionPtr += 3; + NEXT_OPCODE; + + /* End of the pattern. */ + + BEGIN_OPCODE(END): + md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */ + md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */ + isMatch = true; + RRETURN; + + /* Assertion brackets. Check the alternative branches in turn - the + matching won't pass the KET for an assertion. If any one branch matches, + the assertion is true. Lookbehind assertions have an OP_REVERSE item at the + start of each branch to move the current point backwards, so the code at + this level is identical to the lookahead case. */ + + BEGIN_OPCODE(ASSERT): + { + uint16 bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); + LOCALS(minBracket) = (bracketMess >> 8) & 0xff; + LOCALS(limitBracket) = bracketMess & 0xff; + JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); + } + stack.currentFrame->locals.skipBytes = 3; + do { + RECURSIVE_MATCH_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); + if (isMatch) + break; + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + if (*stack.currentFrame->args.instructionPtr == OP_KET) { + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + RRETURN_NO_MATCH; + } + + /* Continue from after the assertion, updating the offsets high water + mark, since extracts may have been taken during the assertion. */ + + advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); + stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; + stack.currentFrame->args.offsetTop = md.endOffsetTop; + NEXT_OPCODE; + + /* Negative assertion: all branches must fail to match */ + + BEGIN_OPCODE(ASSERT_NOT): + stack.currentFrame->locals.skipBytes = 3; + { + unsigned bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); + LOCALS(minBracket) = (bracketMess >> 8) & 0xff; + LOCALS(limitBracket) = bracketMess & 0xff; + } + JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); + do { + RECURSIVE_MATCH_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); + if (isMatch) + RRETURN_NO_MATCH; + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.skipBytes + LINK_SIZE; + NEXT_OPCODE; + + /* An alternation is the end of a branch; scan along to find the end of the + bracketed group and go to there. */ + + BEGIN_OPCODE(ALT): + advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); + NEXT_OPCODE; + + /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating + that it may occur zero times. It may repeat infinitely, or not at all - + i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper + repeat limits are compiled as a number of copies, with the optional ones + preceded by BRAZERO or BRAMINZERO. */ + + BEGIN_OPCODE(BRAZERO): { + stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain, true); + if (isMatch) + RRETURN; + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); + stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE; + NEXT_OPCODE; + } + + BEGIN_OPCODE(BRAMINZERO): { + stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; + advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); + RECURSIVE_MATCH_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain, false); + if (isMatch) + RRETURN; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + } + + /* End of a group, repeated or non-repeating. If we are at the end of + an assertion "group", stop matching and return 1, but record the + current high water mark for use by positive assertions. Do this also + for the "once" (not-backup up) groups. */ + + BEGIN_OPCODE(KET): + BEGIN_OPCODE(KETRMIN): + BEGIN_OPCODE(KETRMAX): + stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart; + stack.currentFrame->locals.minSatisfied = stack.currentFrame->args.bracketChain->minSatisfied; + + /* Back up the stack of bracket start pointers. */ + + stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket; + + if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) { + md.endOffsetTop = stack.currentFrame->args.offsetTop; + isMatch = true; + RRETURN; + } + + /* In all other cases except a conditional group we have to check the + group number back at the start and if necessary complete handling an + extraction by setting the offsets and bumping the high water mark. */ + + stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA; + + /* For extended extraction brackets (large number), we have to fish out + the number from a dummy opcode at the start. */ + + if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) + stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 4 + LINK_SIZE); + stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; + + DPRINTF(("end bracket %d\n", stack.currentFrame->locals.number)); + + /* Test for a numbered group. This includes groups called as a result + of recursion. Note that whole-pattern recursion is coded as a recurse + into group 0, so it won't be picked up here. Instead, we catch it when + the OP_END is reached. */ + + if (stack.currentFrame->locals.number > 0) { + if (stack.currentFrame->locals.offset >= md.offsetMax) + md.offsetOverflow = true; + else { + int start = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; + int end = stack.currentFrame->args.subjectPtr - md.startSubject; + if (start == end && stack.currentFrame->locals.minSatisfied) { + DPRINTF(("empty string while group already matched; bailing")); + RRETURN_NO_MATCH; + } + DPRINTF(("saving; start: %d; end: %d\n", start, end)); + JS_ASSERT(start <= end); + md.setOffsetPair(stack.currentFrame->locals.number, start, end); + if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset) + stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2; + } + } + + /* For a non-repeating ket, just continue at this level. This also + happens for a repeating ket if no characters were matched in the group. + This is the forcible breaking of infinite loops as implemented in Perl + 5.005. If there is an options reset, it will get obeyed in the normal + course of events. */ + + if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + DPRINTF(("non-repeating ket or empty match\n")); + if (stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction && stack.currentFrame->locals.minSatisfied) { + DPRINTF(("empty string while group already matched; bailing")); + RRETURN_NO_MATCH; + } + stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; + NEXT_OPCODE; + } + + /* The repeating kets try the rest of the pattern or restart from the + preceding bracket, in the appropriate order. */ + + stack.currentFrame->extractBrackets(LOCALS(instructionPtrAtStartOfOnce)); + JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); + if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) { + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + else + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + DPRINTF(("recursively matching lazy group\n")); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(17, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); + } else { /* OP_KETRMAX */ + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + stack.currentFrame->clobberOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + DPRINTF(("recursively matching greedy group\n")); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(18, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); + if (isMatch) + RRETURN; + else + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); + } + RRETURN; + + /* Start of subject. */ + + BEGIN_OPCODE(CIRC): + if (stack.currentFrame->args.subjectPtr != md.startSubject) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* After internal newline if multiline. */ + + BEGIN_OPCODE(BOL): + if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1])) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* End of subject. */ + + BEGIN_OPCODE(DOLL): + if (stack.currentFrame->args.subjectPtr < md.endSubject) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Before internal newline if multiline. */ + + BEGIN_OPCODE(EOL): + if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Word boundary assertions */ + + BEGIN_OPCODE(NOT_WORD_BOUNDARY): + BEGIN_OPCODE(WORD_BOUNDARY): { + bool currentCharIsWordChar = false; + bool previousCharIsWordChar = false; + + if (stack.currentFrame->args.subjectPtr > md.startSubject) + previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]); + if (stack.currentFrame->args.subjectPtr < md.endSubject) + currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr); + + /* Now see if the situation is what we want */ + bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY); + if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar) + RRETURN_NO_MATCH; + NEXT_OPCODE; + } + + /* Match a single character type; inline for speed */ + + BEGIN_OPCODE(NOT_NEWLINE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isNewline(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_DIGIT): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(DIGIT): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_WHITESPACE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isSpaceChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(WHITESPACE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_WORDCHAR): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isWordChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(WORDCHAR): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isWordChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Match a back reference, possibly repeatedly. Look past the end of the + item to see if there is repeat information following. The code is similar + to that for character classes, but repeated for efficiency. Then obey + similar code to character type repeats - written out again for speed. + However, if the referenced string is the empty string, always treat + it as matched, any number of times (otherwise there could be infinite + loops). */ + + BEGIN_OPCODE(REF): + stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */ + stack.currentFrame->args.instructionPtr += 3; /* Advance past item */ + + /* If the reference is unset, set the length to be longer than the amount + of subject left; this ensures that every attempt at a match fails. We + can't just fail here, because of the possibility of quantifiers with zero + minima. */ + + if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0) + stack.currentFrame->locals.length = 0; + else + stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset]; + + /* Set up for repetition, or handle the non-repeated case */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + NEXT_OPCODE; + } + + /* If the length of the reference is zero, just continue with the + main loop. */ + + if (stack.currentFrame->locals.length == 0) + NEXT_OPCODE; + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + + /* If min = max, continue at the same level without recursion. + They are not both allowed to be zero. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep trying and advancing the pointer */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + /* Control never reaches here */ + } + + /* If maximizing, find the longest string and work backwards */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + break; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + + /* Match a bit-mapped character class, possibly repeatedly. This op code is + used when all the characters in the class have values in the range 0-255, + and either the matching is caseful, or the characters are in the range + 0-127 when UTF-8 processing is enabled. The only difference between + OP_CLASS and OP_NCLASS occurs when a data character outside the range is + encountered. + + First, look past the end of the item to see if there is repeat information + following. Then obey similar code to character type repeats - written out + again for speed. */ + + BEGIN_OPCODE(NCLASS): + BEGIN_OPCODE(CLASS): + stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */ + stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + min = stack.currentFrame->locals.max = 1; + break; + } + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int c = *stack.currentFrame->args.subjectPtr++; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + RRETURN_NO_MATCH; + } else { + if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) + RRETURN_NO_MATCH; + } + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + int c = *stack.currentFrame->args.subjectPtr++; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + RRETURN; + } else { + if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0) + RRETURN; + } + } + /* Control never reaches here */ + } + /* If maximizing, find the longest possible run, then work backwards. */ + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + break; + } else { + if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) + break; + } + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + /* Control never reaches here */ + + /* Match an extended character class. */ + + BEGIN_OPCODE(XCLASS): + stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */ + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + min = stack.currentFrame->locals.max = 1; + } + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int c = *stack.currentFrame->args.subjectPtr++; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + RRETURN_NO_MATCH; + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + int c = *stack.currentFrame->args.subjectPtr++; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + RRETURN; + } + /* Control never reaches here */ + } + + /* If maximizing, find the longest possible run, then work backwards. */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + break; + ++stack.currentFrame->args.subjectPtr; + } + for(;;) { + RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + RRETURN; + } + + /* Control never reaches here */ + + /* Match a single character, casefully */ + + BEGIN_OPCODE(CHAR): + stack.currentFrame->locals.length = 1; + stack.currentFrame->args.instructionPtr++; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++) + RRETURN_NO_MATCH; + NEXT_OPCODE; + + /* Match a single character, caselessly */ + + BEGIN_OPCODE(CHAR_IGNORING_CASE): { + stack.currentFrame->locals.length = 1; + stack.currentFrame->args.instructionPtr++; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int dc = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fc != dc && jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc) + RRETURN_NO_MATCH; + NEXT_OPCODE; + } + + /* Match a single ASCII character. */ + + BEGIN_OPCODE(ASCII_CHAR): + if (md.endSubject == stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1]) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + stack.currentFrame->args.instructionPtr += 2; + NEXT_OPCODE; + + /* Match one of two cases of an ASCII letter. */ + + BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE): + if (md.endSubject == stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1]) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + stack.currentFrame->args.instructionPtr += 2; + NEXT_OPCODE; + + /* Match a single character repeatedly; different opcodes share code. */ + + BEGIN_OPCODE(EXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = false; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATCHAR; + + BEGIN_OPCODE(UPTO): + BEGIN_OPCODE(MINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATCHAR; + + BEGIN_OPCODE(STAR): + BEGIN_OPCODE(MINSTAR): + BEGIN_OPCODE(PLUS): + BEGIN_OPCODE(MINPLUS): + BEGIN_OPCODE(QUERY): + BEGIN_OPCODE(MINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single-character matches. We can give + up quickly if there are fewer than the minimum number of characters left in + the subject. */ + + REPEATCHAR: + + stack.currentFrame->locals.length = 1; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + + if (stack.currentFrame->locals.fc <= 0xFFFF) { + othercase = md.ignoreCase ? jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1; + + for (int i = 1; i <= min; i++) { + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + stack.currentFrame->locals.repeatOthercase = othercase; + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase) + RRETURN; + ++stack.currentFrame->args.subjectPtr; + } + /* Control never reaches here */ + } else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) + break; + ++stack.currentFrame->args.subjectPtr; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + --stack.currentFrame->args.subjectPtr; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + } else { + /* No case on surrogate pairs, so no need to bother with "othercase". */ + + for (int i = 1; i <= min; i++) { + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += 2; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + RRETURN; + stack.currentFrame->args.subjectPtr += 2; + } + /* Control never reaches here */ + } else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr > md.endSubject - 2) + break; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + break; + stack.currentFrame->args.subjectPtr += 2; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + stack.currentFrame->args.subjectPtr -= 2; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + } + /* Control never reaches here */ + + /* Match a negated single one-byte character. */ + + BEGIN_OPCODE(NOT): { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int b = stack.currentFrame->args.instructionPtr[1]; + int c = *stack.currentFrame->args.subjectPtr++; + stack.currentFrame->args.instructionPtr += 2; + if (md.ignoreCase) { + if (c < 128) + c = toLowerCase(c); + if (toLowerCase(b) == c) + RRETURN_NO_MATCH; + } else { + if (b == c) + RRETURN_NO_MATCH; + } + NEXT_OPCODE; + } + + /* Match a negated single one-byte character repeatedly. This is almost a + repeat of the code for a repeated single character, but I haven't found a + nice way of commoning these up that doesn't require a test of the + positive/negative option for each character match. Maybe that wouldn't add + very much to the time taken, but character matching *is* what this is all + about... */ + + BEGIN_OPCODE(NOTEXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = false; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATNOTCHAR; + + BEGIN_OPCODE(NOTUPTO): + BEGIN_OPCODE(NOTMINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATNOTCHAR; + + BEGIN_OPCODE(NOTSTAR): + BEGIN_OPCODE(NOTMINSTAR): + BEGIN_OPCODE(NOTPLUS): + BEGIN_OPCODE(NOTMINPLUS): + BEGIN_OPCODE(NOTQUERY): + BEGIN_OPCODE(NOTMINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single-byte matches. We can give up quickly + if there are fewer than the minimum number of bytes left in the + subject. */ + + REPEATNOTCHAR: + if (min > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++; + + /* The code is duplicated for the caseless and caseful cases, for speed, + since matching characters is likely to be quite common. First, ensure the + minimum number of matches are present. If min = max, continue at the same + level without recursing. Otherwise, if minimizing, keep trying the rest of + the expression and advancing one matching character if failing, up to the + maximum. Alternatively, if maximizing, find the maximum number of + characters and work backwards. */ + + DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max)); + + if (md.ignoreCase) { + if (stack.currentFrame->locals.fc < 128) + stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc); + + for (int i = 1; i <= min; i++) { + int d = *stack.currentFrame->args.subjectPtr++; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fc == d) + RRETURN_NO_MATCH; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + int d = *stack.currentFrame->args.subjectPtr++; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) + RRETURN; + } + /* Control never reaches here */ + } + + /* Maximize case */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int d = *stack.currentFrame->args.subjectPtr; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fc == d) + break; + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + /* Control never reaches here */ + } + + /* Caseful comparisons */ + + else { + for (int i = 1; i <= min; i++) { + int d = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fc == d) + RRETURN_NO_MATCH; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + int d = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) + RRETURN; + } + /* Control never reaches here */ + } + + /* Maximize case */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int d = *stack.currentFrame->args.subjectPtr; + if (stack.currentFrame->locals.fc == d) + break; + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + } + /* Control never reaches here */ + + /* Match a single character type repeatedly; several different opcodes + share code. This is very similar to the code for single characters, but we + repeat it in the interests of efficiency. */ + + BEGIN_OPCODE(TYPEEXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = true; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATTYPE; + + BEGIN_OPCODE(TYPEUPTO): + BEGIN_OPCODE(TYPEMINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATTYPE; + + BEGIN_OPCODE(TYPESTAR): + BEGIN_OPCODE(TYPEMINSTAR): + BEGIN_OPCODE(TYPEPLUS): + BEGIN_OPCODE(TYPEMINPLUS): + BEGIN_OPCODE(TYPEQUERY): + BEGIN_OPCODE(TYPEMINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single character type matches. Note that + in UTF-8 mode, '.' matches a character of any length, but for the other + character types, the valid characters are all one-byte long. */ + + REPEATTYPE: + stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */ + + /* First, ensure the minimum number of matches are present. Use inline + code for maximizing the speed, and do the type test once at the start + (i.e. keep it out of the loop). Also we can test that there are at least + the minimum number of characters before we start. */ + + if (min > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if (min > 0) { + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + for (int i = 1; i <= min; i++) { + if (isNewline(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_DIGIT: + for (int i = 1; i <= min; i++) { + if (isASCIIDigit(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_DIGIT: + for (int i = 1; i <= min; i++) { + if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WHITESPACE: + for (int i = 1; i <= min; i++) { + if (isSpaceChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WHITESPACE: + for (int i = 1; i <= min; i++) { + if (!isSpaceChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WORDCHAR: + for (int i = 1; i <= min; i++) { + if (isWordChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WORDCHAR: + for (int i = 1; i <= min; i++) { + if (!isWordChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } /* End switch(stack.currentFrame->locals.ctype) */ + } + + /* If min = max, continue at the same level without recursing */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, we have to test the rest of the pattern before each + subsequent match. */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + + int c = *stack.currentFrame->args.subjectPtr++; + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + if (isNewline(c)) + RRETURN; + break; + + case OP_NOT_DIGIT: + if (isASCIIDigit(c)) + RRETURN; + break; + + case OP_DIGIT: + if (!isASCIIDigit(c)) + RRETURN; + break; + + case OP_NOT_WHITESPACE: + if (isSpaceChar(c)) + RRETURN; + break; + + case OP_WHITESPACE: + if (!isSpaceChar(c)) + RRETURN; + break; + + case OP_NOT_WORDCHAR: + if (isWordChar(c)) + RRETURN; + break; + + case OP_WORDCHAR: + if (!isWordChar(c)) + RRETURN; + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } + } + /* Control never reaches here */ + } + + /* If maximizing it is worth using inline code for speed, doing the type + test once at the start (i.e. keep it out of the loop). */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */ + + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr)) + break; + stack.currentFrame->args.subjectPtr++; + } + break; + + case OP_NOT_DIGIT: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isASCIIDigit(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_DIGIT: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isASCIIDigit(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WHITESPACE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isSpaceChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WHITESPACE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isSpaceChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WORDCHAR: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isWordChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WORDCHAR: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isWordChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } + + /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */ + + for (;;) { + RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + /* Get here if we can't make it match with any permitted repetitions */ + + RRETURN; + } + /* Control never reaches here */ + + BEGIN_OPCODE(CRMINPLUS): + BEGIN_OPCODE(CRMINQUERY): + BEGIN_OPCODE(CRMINRANGE): + BEGIN_OPCODE(CRMINSTAR): + BEGIN_OPCODE(CRPLUS): + BEGIN_OPCODE(CRQUERY): + BEGIN_OPCODE(CRRANGE): + BEGIN_OPCODE(CRSTAR): + JS_NOT_REACHED("Invalid opcode."); + return matchError(JSRegExpErrorInternal, stack); + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + CAPTURING_BRACKET: +#else + default: +#endif + /* Opening capturing bracket. If there is space in the offset vector, save + the current subject position in the working slot at the top of the vector. We + mustn't change the current values of the data slot, because they may be set + from a previous iteration of this group, and be referred to by a reference + inside the group. + + If the bracket fails to match, we need to restore this value and also the + values of the final offsets, in case they were set by a previous iteration of + the same bracket. + + If there isn't enough space in the offset vector, treat this as if it were a + non-capturing bracket. Don't worry about setting the flag for the error case + here; that is handled in the code for KET. */ + + JS_ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA); + + LOCALS(number) = *stack.currentFrame->args.instructionPtr - OP_BRA; + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); + DPRINTF(("opening capturing bracket %d\n", stack.currentFrame->locals.number)); + + /* For extended extraction brackets (large number), we have to fish out the + number from a dummy opcode at the start. */ + + if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) + stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 4 + LINK_SIZE); + stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; + + JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); + + if (stack.currentFrame->locals.offset < md.offsetMax) { + stack.currentFrame->locals.savedSubjectOffset = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; + DPRINTF(("setting subject offset for bracket to %d\n", stack.currentFrame->args.subjectPtr - md.startSubject)); + md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject; + stack.currentFrame->locals.skipBytes = 3; /* For OP_BRAs. */ + + /* We must compute this value at the top, before we move the instruction pointer. */ + stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); + do { + /* We need to extract this into a variable so we can correctly pass it by value + through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ + minSatisfied = stack.currentFrame->locals.minSatisfied; + RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); + if (isMatch) + RRETURN; + stack.currentFrame->locals.skipBytes = 1; /* For OP_ALTs. */ + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + + DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number)); + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + DPRINTF(("restoring subject offset for bracket to %d\n", stack.currentFrame->locals.savedSubjectOffset)); + md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.savedSubjectOffset; + + RRETURN; + } + + /* Insufficient room for saving captured contents */ + + goto NON_CAPTURING_BRACKET; + } + + /* Do not stick any code in here without much thought; it is assumed + that "continue" in the code above comes out to here to repeat the main + loop. */ + + } /* End of main loop */ + + JS_NOT_REACHED("Loop does not fallthru."); + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + +RRETURN_SWITCH: + switch (stack.currentFrame->returnLocation) { + case 0: goto RETURN; + case 1: goto RRETURN_1; + case 2: goto RRETURN_2; + case 6: goto RRETURN_6; + case 7: goto RRETURN_7; + case 14: goto RRETURN_14; + case 15: goto RRETURN_15; + case 16: goto RRETURN_16; + case 17: goto RRETURN_17; + case 18: goto RRETURN_18; + case 19: goto RRETURN_19; + case 20: goto RRETURN_20; + case 21: goto RRETURN_21; + case 22: goto RRETURN_22; + case 24: goto RRETURN_24; + case 26: goto RRETURN_26; + case 27: goto RRETURN_27; + case 28: goto RRETURN_28; + case 29: goto RRETURN_29; + case 30: goto RRETURN_30; + case 31: goto RRETURN_31; + case 38: goto RRETURN_38; + case 40: goto RRETURN_40; + case 42: goto RRETURN_42; + case 44: goto RRETURN_44; + case 48: goto RRETURN_48; + case 52: goto RRETURN_52; + } + + JS_NOT_REACHED("Bad computed return location."); + return matchError(JSRegExpErrorInternal, stack); + +#endif + +RETURN: + return isMatch; +} + + +/************************************************* +* Execute a Regular Expression * +*************************************************/ + +/* This function applies a compiled re to a subject string and picks out +portions of the string if it matches. Two elements in the vector are set for +each substring: the offsets to the start and end of the substring. + +Arguments: + re points to the compiled expression + extra_data points to extra data or is NULL + subject points to the subject string + length length of subject string (may contain binary zeros) + start_offset where to start in the subject string + options option bits + offsets points to a vector of ints to be filled in with offsets + offsetCount the number of elements in the vector + +Returns: > 0 => success; value is the number of elements filled in + = 0 => success, but offsets is not big enough + -1 => failed to match + < -1 => some kind of unexpected problem +*/ + +static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int firstByte, bool firstByteIsCaseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart) +{ + // If firstByte is set, try scanning to the first instance of that byte + // no need to try and match against any earlier part of the subject string. + if (firstByte >= 0) { + UChar firstChar = firstByte; + if (firstByteIsCaseless) + while (subjectPtr < endSubject) { + int c = *subjectPtr; + if (c > 127) + break; + if (toLowerCase(c) == firstChar) + break; + subjectPtr++; + } + else { + while (subjectPtr < endSubject && *subjectPtr != firstChar) + subjectPtr++; + } + } else if (useMultiLineFirstCharOptimization) { + /* Or to just after \n for a multiline match if possible */ + // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07 + if (subjectPtr > originalSubjectStart) { + while (subjectPtr < endSubject && !isNewline(subjectPtr[-1])) + subjectPtr++; + } + } +} + +static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int reqByte, int reqByte2, bool reqByteIsCaseless, bool hasFirstByte, const UChar*& reqBytePtr) +{ + /* If reqByte is set, we know that that character must appear in the subject + for the match to succeed. If the first character is set, reqByte must be + later in the subject; otherwise the test starts at the match point. This + optimization can save a huge amount of backtracking in patterns with nested + unlimited repeats that aren't going to match. Writing separate code for + cased/caseless versions makes it go faster, as does using an autoincrement + and backing off on a match. + + HOWEVER: when the subject string is very, very long, searching to its end can + take a long time, and give bad performance on quite ordinary patterns. This + showed up when somebody was matching /^C/ on a 32-megabyte string... so we + don't do this when the string is sufficiently long. + */ + + if (reqByte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) { + const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0); + + /* We don't need to repeat the search if we haven't yet reached the + place we found it at last time. */ + + if (p > reqBytePtr) { + if (reqByteIsCaseless) { + while (p < endSubject) { + int pp = *p++; + if (pp == reqByte || pp == reqByte2) { + p--; + break; + } + } + } else { + while (p < endSubject) { + if (*p++ == reqByte) { + p--; + break; + } + } + } + + /* If we can't find the required character, break the matching loop */ + + if (p >= endSubject) + return true; + + /* If we have found the required character, save the point where we + found it, so that we don't search again next time round the loop if + the start hasn't passed this character yet. */ + + reqBytePtr = p; + } + } + return false; +} + +int jsRegExpExecute(JSContext *cx, const JSRegExp* re, + const UChar* subject, int length, int start_offset, int* offsets, + int offsetCount) +{ + JS_ASSERT(re); + JS_ASSERT(subject || !length); + JS_ASSERT(offsetCount >= 0); + JS_ASSERT(offsets || offsetCount == 0); + + MatchData matchBlock; + matchBlock.startSubject = subject; + matchBlock.endSubject = matchBlock.startSubject + length; + const UChar* endSubject = matchBlock.endSubject; + + matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption); + matchBlock.ignoreCase = (re->options & IgnoreCaseOption); + + /* Use the vector supplied, rounding down its size to a multiple of 3. */ + int ocount = offsetCount - (offsetCount % 3); + + matchBlock.offsetVector = offsets; + matchBlock.offsetEnd = ocount; + matchBlock.offsetMax = (2*ocount)/3; + matchBlock.offsetOverflow = false; + + /* Compute the minimum number of offsets that we need to reset each time. Doing + this makes a huge difference to execution time when there aren't many brackets + in the pattern. */ + + int resetCount = 2 + re->topBracket * 2; + if (resetCount > offsetCount) + resetCount = ocount; + + /* Reset the working variable associated with each extraction. These should + never be used unless previously set, but they get saved and restored, and so we + initialize them to avoid reading uninitialized locations. */ + + if (matchBlock.offsetVector) { + int* iptr = matchBlock.offsetVector + ocount; + int* iend = iptr - resetCount/2 + 1; + while (--iptr >= iend) + *iptr = -1; + } + + /* Set up the first character to match, if available. The firstByte value is + never set for an anchored regular expression, but the anchoring may be forced + at run time, so we have to test for anchoring. The first char may be unset for + an unanchored pattern, of course. If there's no first char and the pattern was + studied, there may be a bitmap of possible first characters. */ + + bool firstByteIsCaseless = false; + int firstByte = -1; + if (re->options & UseFirstByteOptimizationOption) { + firstByte = re->firstByte & 255; + if ((firstByteIsCaseless = (re->firstByte & REQ_IGNORE_CASE))) + firstByte = toLowerCase(firstByte); + } + + /* For anchored or unanchored matches, there may be a "last known required + character" set. */ + + bool reqByteIsCaseless = false; + int reqByte = -1; + int reqByte2 = -1; + if (re->options & UseRequiredByteOptimizationOption) { + reqByte = re->reqByte & 255; + reqByteIsCaseless = (re->reqByte & REQ_IGNORE_CASE); + reqByte2 = flipCase(reqByte); + } + + /* Loop for handling unanchored repeated matching attempts; for anchored regexs + the loop runs just once. */ + + const UChar* startMatch = subject + start_offset; + const UChar* reqBytePtr = startMatch - 1; + bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption; + + do { + /* Reset the maximum number of extractions we might see. */ + if (matchBlock.offsetVector) { + int* iptr = matchBlock.offsetVector; + int* iend = iptr + resetCount; + while (iptr < iend) + *iptr++ = -1; + } + + tryFirstByteOptimization(startMatch, endSubject, firstByte, firstByteIsCaseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset); + if (tryRequiredByteOptimization(startMatch, endSubject, reqByte, reqByte2, reqByteIsCaseless, firstByte >= 0, reqBytePtr)) + break; + + /* When a match occurs, substrings will be set for all internal extractions; + we just need to set up the whole thing as substring 0 before returning. If + there were too many extractions, set the return code to zero. In the case + where we had to get some local store to hold offsets for backreferences, copy + those back references that we can. In this case there need not be overflow + if certain parts of the pattern were not used. */ + + /* The code starts after the JSRegExp block and the capture name table. */ + const unsigned char* start_code = (const unsigned char*)(re + 1); + + int returnCode = match(&cx->regExpPool, startMatch, start_code, 2, matchBlock); + + /* When the result is no match, advance the pointer to the next character + and continue. */ + if (returnCode == 0) { + startMatch++; + continue; + } + + if (returnCode != 1) { + JS_ASSERT(returnCode == JSRegExpErrorHitLimit); + DPRINTF((">>>> error: returning %d\n", returnCode)); + return returnCode; + } + + /* We have a match! */ + + returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2; + + if (offsetCount < 2) + returnCode = 0; + else { + offsets[0] = startMatch - matchBlock.startSubject; + offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject; + } + + JS_ASSERT(returnCode >= 0); + DPRINTF((">>>> returning %d\n", returnCode)); + return returnCode; + } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject); + + DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); + return JSRegExpErrorNoMatch; +} diff --git a/js/src/yarr/pcre/pcre_internal.h b/js/src/yarr/pcre/pcre_internal.h new file mode 100644 index 000000000000..d677cfcfa255 --- /dev/null +++ b/js/src/yarr/pcre/pcre_internal.h @@ -0,0 +1,434 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This header contains definitions that are shared between the different +modules, but which are not relevant to the exported API. This includes some +functions whose names all begin with "_pcre_". */ + +#ifndef PCRE_INTERNAL_H +#define PCRE_INTERNAL_H + +/* Bit definitions for entries in the pcre_ctypes table. */ + +#define ctype_space 0x01 +#define ctype_xdigit 0x08 +#define ctype_word 0x10 /* alphameric or '_' */ + +/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set +of bits for a class map. Some classes are built by combining these tables. */ + +#define cbit_space 0 /* \s */ +#define cbit_digit 32 /* \d */ +#define cbit_word 64 /* \w */ +#define cbit_length 96 /* Length of the cbits table */ + +/* Offsets of the various tables from the base tables pointer, and +total length. */ + +#define lcc_offset 0 +#define fcc_offset 128 +#define cbits_offset 256 +#define ctypes_offset (cbits_offset + cbit_length) +#define tables_length (ctypes_offset + 128) + +#ifndef DFTABLES + +#include "pcre.h" + +/* The value of LINK_SIZE determines the number of bytes used to store links as +offsets within the compiled regex. The default is 2, which allows for compiled +patterns up to 64K long. */ + +#define LINK_SIZE 3 + +/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef +inline, and there are *still* stupid compilers about that don't like indented +pre-processor statements, or at least there were when I first wrote this. After +all, it had only been about 10 years then... */ + +#ifdef DEBUG +#define DPRINTF(p) /*printf p; fflush(stdout);*/ +#else +#define DPRINTF(p) /*nothing*/ +#endif + +/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored +in big-endian order) by default. These are used, for example, to link from the +start of a subpattern to its alternatives and its end. The use of 2 bytes per +offset limits the size of the compiled regex to around 64K, which is big enough +for almost everybody. However, I received a request for an even bigger limit. +For this reason, and also to make the code easier to maintain, the storing and +loading of offsets from the byte string is now handled by the functions that are +defined here. */ + +/* PCRE uses some other 2-byte quantities that do not change when the size of +offsets changes. There are used for repeat counts and for other things such as +capturing parenthesis numbers in back references. */ + +static inline void put2ByteValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value >= 0 && value <= 0xFFFF); + opcodePtr[0] = value >> 8; + opcodePtr[1] = value; +} + +static inline void put3ByteValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value >= 0 && value <= 0xFFFFFF); + opcodePtr[0] = value >> 16; + opcodePtr[1] = value >> 8; + opcodePtr[2] = value; +} + +static inline int get2ByteValue(const unsigned char* opcodePtr) +{ + return (opcodePtr[0] << 8) | opcodePtr[1]; +} + +static inline int get3ByteValue(const unsigned char* opcodePtr) +{ + return (opcodePtr[0] << 16) | (opcodePtr[1] << 8) | opcodePtr[2]; +} + +static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + put2ByteValue(opcodePtr, value); + opcodePtr += 2; +} + +static inline void put3ByteValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + put3ByteValue(opcodePtr, value); + opcodePtr += 3; +} + +static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value) +{ +#if LINK_SIZE == 3 + put3ByteValue(opcodePtr, value); +#elif LINK_SIZE == 2 + put2ByteValue(opcodePtr, value); +#else +# error LINK_SIZE not supported. +#endif +} + +static inline int getLinkValueAllowZero(const unsigned char* opcodePtr) +{ +#if LINK_SIZE == 3 + return get3ByteValue(opcodePtr); +#elif LINK_SIZE == 2 + return get2ByteValue(opcodePtr); +#else +# error LINK_SIZE not supported. +#endif +} + +#define MAX_PATTERN_SIZE 1024 * 1024 // Derived by empirical testing of compile time in PCRE and WREC. +JS_STATIC_ASSERT(MAX_PATTERN_SIZE < (1 << (8 * LINK_SIZE))); + +static inline void putLinkValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value); + putLinkValueAllowZero(opcodePtr, value); +} + +static inline int getLinkValue(const unsigned char* opcodePtr) +{ + int value = getLinkValueAllowZero(opcodePtr); + JS_ASSERT(value); + return value; +} + +static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + putLinkValue(opcodePtr, value); + opcodePtr += LINK_SIZE; +} + +static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value) +{ + putLinkValueAllowZero(opcodePtr, value); + opcodePtr += LINK_SIZE; +} + +// FIXME: These are really more of a "compiled regexp state" than "regexp options" +enum RegExpOptions { + UseFirstByteOptimizationOption = 0x40000000, /* firstByte is set */ + UseRequiredByteOptimizationOption = 0x20000000, /* reqByte is set */ + UseMultiLineFirstByteOptimizationOption = 0x10000000, /* start after \n for multiline */ + IsAnchoredOption = 0x02000000, /* can't use partial with this regex */ + IgnoreCaseOption = 0x00000001, + MatchAcrossMultipleLinesOption = 0x00000002 +}; + +/* Flags added to firstByte or reqByte; a "non-literal" item is either a +variable-length repeat, or a anything other than literal characters. */ + +#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */ +#define REQ_VARY 0x0200 /* reqByte followed non-literal item */ + +/* Miscellaneous definitions */ + +/* Flag bits and data types for the extended class (OP_XCLASS) for classes that +contain UTF-8 characters with values greater than 255. */ + +#define XCL_NOT 0x01 /* Flag: this is a negative class */ +#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ + +#define XCL_END 0 /* Marks end of individual items */ +#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ +#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ + +/* These are escaped items that aren't just an encoding of a particular data +value such as \n. They must have non-zero values, as check_escape() returns +their negation. Also, they must appear in the same order as in the opcode +definitions below, up to ESC_w. The final one must be +ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two +tests in the code for an escape > ESC_b and <= ESC_w to +detect the types that may be repeated. These are the types that consume +characters. If any new escapes are put in between that don't consume a +character, that code will have to change. */ + +enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF }; + +/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets +that extract substrings. Starting from 1 (i.e. after OP_END), the values up to +OP_EOD must correspond in order to the list of escapes immediately above. +Note that whenever this list is updated, the two macro definitions that follow +must also be updated to match. */ + +#define FOR_EACH_OPCODE(macro) \ + macro(END) \ + \ + , macro(NOT_WORD_BOUNDARY) \ + , macro(WORD_BOUNDARY) \ + , macro(NOT_DIGIT) \ + , macro(DIGIT) \ + , macro(NOT_WHITESPACE) \ + , macro(WHITESPACE) \ + , macro(NOT_WORDCHAR) \ + , macro(WORDCHAR) \ + \ + , macro(NOT_NEWLINE) \ + \ + , macro(CIRC) \ + , macro(DOLL) \ + , macro(BOL) \ + , macro(EOL) \ + , macro(CHAR) \ + , macro(CHAR_IGNORING_CASE) \ + , macro(ASCII_CHAR) \ + , macro(ASCII_LETTER_IGNORING_CASE) \ + , macro(NOT) \ + \ + , macro(STAR) \ + , macro(MINSTAR) \ + , macro(PLUS) \ + , macro(MINPLUS) \ + , macro(QUERY) \ + , macro(MINQUERY) \ + , macro(UPTO) \ + , macro(MINUPTO) \ + , macro(EXACT) \ + \ + , macro(NOTSTAR) \ + , macro(NOTMINSTAR) \ + , macro(NOTPLUS) \ + , macro(NOTMINPLUS) \ + , macro(NOTQUERY) \ + , macro(NOTMINQUERY) \ + , macro(NOTUPTO) \ + , macro(NOTMINUPTO) \ + , macro(NOTEXACT) \ + \ + , macro(TYPESTAR) \ + , macro(TYPEMINSTAR) \ + , macro(TYPEPLUS) \ + , macro(TYPEMINPLUS) \ + , macro(TYPEQUERY) \ + , macro(TYPEMINQUERY) \ + , macro(TYPEUPTO) \ + , macro(TYPEMINUPTO) \ + , macro(TYPEEXACT) \ + \ + , macro(CRSTAR) \ + , macro(CRMINSTAR) \ + , macro(CRPLUS) \ + , macro(CRMINPLUS) \ + , macro(CRQUERY) \ + , macro(CRMINQUERY) \ + , macro(CRRANGE) \ + , macro(CRMINRANGE) \ + \ + , macro(CLASS) \ + , macro(NCLASS) \ + , macro(XCLASS) \ + \ + , macro(REF) \ + \ + , macro(ALT) \ + , macro(KET) \ + , macro(KETRMAX) \ + , macro(KETRMIN) \ + \ + , macro(ASSERT) \ + , macro(ASSERT_NOT) \ + \ + , macro(BRAZERO) \ + , macro(BRAMINZERO) \ + , macro(BRANUMBER) \ + , macro(BRA) + +#define OPCODE_ENUM_VALUE(opcode) OP_##opcode +enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) }; + +/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and +study.c that all opcodes are less than 128 in value. This makes handling UTF-8 +character sequences easier. */ + +/* The highest extraction number before we have to start using additional +bytes. (Originally PCRE didn't have support for extraction counts higher than +this number.) The value is limited by the number of opcodes left after OP_BRA, +i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional +opcodes. */ + +/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above +are in conflict! */ + +#define EXTRACT_BASIC_MAX 100 + +/* The code vector runs on as long as necessary after the end. */ + +struct JSRegExp { + unsigned options; + + unsigned short topBracket; + unsigned short topBackref; + + unsigned short firstByte; + unsigned short reqByte; +}; + +/* Internal shared data tables. These are tables that are used by more than one + of the exported public functions. They have to be "external" in the C sense, + but are not part of the PCRE public API. The data for these tables is in the + pcre_tables.c module. */ + +#define jsc_pcre_utf8_table1_size 6 + +extern const int jsc_pcre_utf8_table1[6]; +extern const int jsc_pcre_utf8_table2[6]; +extern const int jsc_pcre_utf8_table3[6]; +extern const unsigned char jsc_pcre_utf8_table4[0x40]; + +extern const unsigned char jsc_pcre_default_tables[tables_length]; + +static inline unsigned char toLowerCase(unsigned char c) +{ + static const unsigned char* lowerCaseChars = jsc_pcre_default_tables + lcc_offset; + return lowerCaseChars[c]; +} + +static inline unsigned char flipCase(unsigned char c) +{ + static const unsigned char* flippedCaseChars = jsc_pcre_default_tables + fcc_offset; + return flippedCaseChars[c]; +} + +static inline unsigned char classBitmapForChar(unsigned char c) +{ + static const unsigned char* charClassBitmaps = jsc_pcre_default_tables + cbits_offset; + return charClassBitmaps[c]; +} + +static inline unsigned char charTypeForChar(unsigned char c) +{ + const unsigned char* charTypeMap = jsc_pcre_default_tables + ctypes_offset; + return charTypeMap[c]; +} + +static inline bool isWordChar(UChar c) +{ + return c < 128 && (charTypeForChar(c) & ctype_word); +} + +static inline bool isSpaceChar(UChar c) +{ + return (c < 128 && (charTypeForChar(c) & ctype_space)) || c == 0x00A0; +} + +static inline bool isNewline(UChar nl) +{ + return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029); +} + +static inline bool isBracketStartOpcode(unsigned char opcode) +{ + if (opcode >= OP_BRA) + return true; + switch (opcode) { + case OP_ASSERT: + case OP_ASSERT_NOT: + return true; + default: + return false; + } +} + +static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr) +{ + JS_ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT); + do + opcodePtr += getLinkValue(opcodePtr + 1); + while (*opcodePtr == OP_ALT); +} + +/* Internal shared functions. These are functions that are used in more +that one of the source files. They have to have external linkage, but +but are not part of the public API and so not exported from the library. */ + +extern int jsc_pcre_ucp_othercase(unsigned); +extern bool jsc_pcre_xclass(int, const unsigned char*); + +#endif + +#endif + +/* End of pcre_internal.h */ diff --git a/js/src/yarr/pcre/pcre_tables.cpp b/js/src/yarr/pcre/pcre_tables.cpp new file mode 100644 index 000000000000..b1ac229d5912 --- /dev/null +++ b/js/src/yarr/pcre/pcre_tables.cpp @@ -0,0 +1,71 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains some fixed tables that are used by more than one of the +PCRE code modules. */ + +#include "pcre_internal.h" + +/************************************************* +* Tables for UTF-8 support * +*************************************************/ + +/* These are the breakpoints for different numbers of bytes in a UTF-8 +character. */ + +const int jsc_pcre_utf8_table1[6] = + { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; + +/* These are the indicator bits and the mask for the data bits to set in the +first byte of a character, indexed by the number of additional bytes. */ + +const int jsc_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; +const int jsc_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +/* Table of the number of extra characters, indexed by the first character +masked with 0x3f. The highest number for a valid UTF-8 character is in fact +0x3d. */ + +const unsigned char jsc_pcre_utf8_table4[0x40] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; + +#include "chartables.c" diff --git a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp new file mode 100644 index 000000000000..b97db921c981 --- /dev/null +++ b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp @@ -0,0 +1,98 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + + +/* This module contains code for searching the table of Unicode character +properties. */ + +#include "pcre_internal.h" + +#include "ucpinternal.h" /* Internal table details */ +#include "ucptable.cpp" /* The table itself */ + +/************************************************* +* Search table and return other case * +*************************************************/ + +/* If the given character is a letter, and there is another case for the +letter, return the other case. Otherwise, return -1. + +Arguments: + c the character value + +Returns: the other case or -1 if none +*/ + +int jsc_pcre_ucp_othercase(unsigned c) +{ + int bot = 0; + int top = sizeof(ucp_table) / sizeof(cnode); + int mid; + + /* The table is searched using a binary chop. You might think that using + intermediate variables to hold some of the common expressions would speed + things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it + makes things a lot slower. */ + + for (;;) { + if (top <= bot) + return -1; + mid = (bot + top) >> 1; + if (c == (ucp_table[mid].f0 & f0_charmask)) + break; + if (c < (ucp_table[mid].f0 & f0_charmask)) + top = mid; + else { + if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask))) + break; + bot = mid + 1; + } + } + + /* Found an entry in the table. Return -1 for a range entry. Otherwise return + the other case if there is one, else -1. */ + + if (ucp_table[mid].f0 & f0_rangeflag) + return -1; + + int offset = ucp_table[mid].f1 & f1_casemask; + if (offset & f1_caseneg) + offset |= f1_caseneg; + return !offset ? -1 : c + offset; +} diff --git a/js/src/yarr/pcre/pcre_xclass.cpp b/js/src/yarr/pcre/pcre_xclass.cpp new file mode 100644 index 000000000000..8e59018ead0c --- /dev/null +++ b/js/src/yarr/pcre/pcre_xclass.cpp @@ -0,0 +1,114 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains an internal function that is used to match an extended +class (one that contains characters whose values are > 255). */ + +#include "pcre_internal.h" + +/************************************************* +* Match character against an XCLASS * +*************************************************/ + +/* This function is called to match a character against an extended class that +might contain values > 255. + +Arguments: + c the character + data points to the flag byte of the XCLASS data + +Returns: true if character matches, else false +*/ + +/* Get the next UTF-8 character, advancing the pointer. This is called when we + know we are in UTF-8 mode. */ + +static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr) +{ + c = *subjectPtr++; + if ((c & 0xc0) == 0xc0) { + int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + int gcss = 6 * gcaa; + c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; + while (gcaa-- > 0) { + gcss -= 6; + c |= (*subjectPtr++ & 0x3f) << gcss; + } + } +} + +bool jsc_pcre_xclass(int c, const unsigned char* data) +{ + bool negated = (*data & XCL_NOT); + + /* Character values < 256 are matched against a bitmap, if one is present. If + not, we still carry on, because there may be ranges that start below 256 in the + additional data. */ + + if (c < 256) { + if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) + return !negated; /* char found */ + } + + /* First skip the bit map if present. Then match against the list of Unicode + properties or large chars or ranges that end with a large char. We won't ever + encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ + + if ((*data++ & XCL_MAP) != 0) + data += 32; + + int t; + while ((t = *data++) != XCL_END) { + if (t == XCL_SINGLE) { + int x; + getUTF8CharAndAdvancePointer(x, data); + if (c == x) + return !negated; + } + else if (t == XCL_RANGE) { + int x, y; + getUTF8CharAndAdvancePointer(x, data); + getUTF8CharAndAdvancePointer(y, data); + if (c >= x && c <= y) + return !negated; + } + } + + return negated; /* char did not match */ +} diff --git a/js/src/yarr/pcre/ucpinternal.h b/js/src/yarr/pcre/ucpinternal.h new file mode 100644 index 000000000000..c8bc4aab679c --- /dev/null +++ b/js/src/yarr/pcre/ucpinternal.h @@ -0,0 +1,126 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/************************************************* +* Unicode Property Table handler * +*************************************************/ + +/* Internal header file defining the layout of the bits in each pair of 32-bit +words that form a data item in the table. */ + +typedef struct cnode { + unsigned f0; + unsigned f1; +} cnode; + +/* Things for the f0 field */ + +#define f0_scriptmask 0xff000000 /* Mask for script field */ +#define f0_scriptshift 24 /* Shift for script value */ +#define f0_rangeflag 0x00f00000 /* Flag for a range item */ +#define f0_charmask 0x001fffff /* Mask for code point value */ + +/* Things for the f1 field */ + +#define f1_typemask 0xfc000000 /* Mask for char type field */ +#define f1_typeshift 26 /* Shift for the type field */ +#define f1_rangemask 0x0000ffff /* Mask for a range offset */ +#define f1_casemask 0x0000ffff /* Mask for a case offset */ +#define f1_caseneg 0xffff8000 /* Bits for negation */ + +/* The data consists of a vector of structures of type cnode. The two unsigned +32-bit integers are used as follows: + +(f0) (1) The most significant byte holds the script number. The numbers are + defined by the enum in ucp.h. + + (2) The 0x00800000 bit is set if this entry defines a range of characters. + It is not set if this entry defines a single character + + (3) The 0x00600000 bits are spare. + + (4) The 0x001fffff bits contain the code point. No Unicode code point will + ever be greater than 0x0010ffff, so this should be OK for ever. + +(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are + defined by an enum in ucp.h. + + (2) The 0x03ff0000 bits are spare. + + (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of + range if this entry defines a range, OR the *signed* offset to the + character's "other case" partner if this entry defines a single + character. There is no partner if the value is zero. + +------------------------------------------------------------------------------- +| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) | +------------------------------------------------------------------------------- + | | | | | + | | |-> spare | |-> spare + | | | + | |-> spare |-> spare + | + |-> range flag + +The upper/lower casing information is set only for characters that come in +pairs. The non-one-to-one mappings in the Unicode data are ignored. + +When searching the data, proceed as follows: + +(1) Set up for a binary chop search. + +(2) If the top is not greater than the bottom, the character is not in the + table. Its type must therefore be "Cn" ("Undefined"). + +(3) Find the middle vector element. + +(4) Extract the code point and compare. If equal, we are done. + +(5) If the test character is smaller, set the top to the current point, and + goto (2). + +(6) If the current entry defines a range, compute the last character by adding + the offset, and see if the test character is within the range. If it is, + we are done. + +(7) Otherwise, set the bottom to one element past the current point and goto + (2). +*/ + +/* End of ucpinternal.h */ diff --git a/js/src/yarr/pcre/ucptable.cpp b/js/src/yarr/pcre/ucptable.cpp new file mode 100644 index 000000000000..011f7f572443 --- /dev/null +++ b/js/src/yarr/pcre/ucptable.cpp @@ -0,0 +1,2968 @@ +/* This source module is automatically generated from the Unicode +property table. See ucpinternal.h for a description of the layout. */ + +static const cnode ucp_table[] = { + { 0x09800000, 0x0000001f }, + { 0x09000020, 0x74000000 }, + { 0x09800021, 0x54000002 }, + { 0x09000024, 0x5c000000 }, + { 0x09800025, 0x54000002 }, + { 0x09000028, 0x58000000 }, + { 0x09000029, 0x48000000 }, + { 0x0900002a, 0x54000000 }, + { 0x0900002b, 0x64000000 }, + { 0x0900002c, 0x54000000 }, + { 0x0900002d, 0x44000000 }, + { 0x0980002e, 0x54000001 }, + { 0x09800030, 0x34000009 }, + { 0x0980003a, 0x54000001 }, + { 0x0980003c, 0x64000002 }, + { 0x0980003f, 0x54000001 }, + { 0x21000041, 0x24000020 }, + { 0x21000042, 0x24000020 }, + { 0x21000043, 0x24000020 }, + { 0x21000044, 0x24000020 }, + { 0x21000045, 0x24000020 }, + { 0x21000046, 0x24000020 }, + { 0x21000047, 0x24000020 }, + { 0x21000048, 0x24000020 }, + { 0x21000049, 0x24000020 }, + { 0x2100004a, 0x24000020 }, + { 0x2100004b, 0x24000020 }, + { 0x2100004c, 0x24000020 }, + { 0x2100004d, 0x24000020 }, + { 0x2100004e, 0x24000020 }, + { 0x2100004f, 0x24000020 }, + { 0x21000050, 0x24000020 }, + { 0x21000051, 0x24000020 }, + { 0x21000052, 0x24000020 }, + { 0x21000053, 0x24000020 }, + { 0x21000054, 0x24000020 }, + { 0x21000055, 0x24000020 }, + { 0x21000056, 0x24000020 }, + { 0x21000057, 0x24000020 }, + { 0x21000058, 0x24000020 }, + { 0x21000059, 0x24000020 }, + { 0x2100005a, 0x24000020 }, + { 0x0900005b, 0x58000000 }, + { 0x0900005c, 0x54000000 }, + { 0x0900005d, 0x48000000 }, + { 0x0900005e, 0x60000000 }, + { 0x0900005f, 0x40000000 }, + { 0x09000060, 0x60000000 }, + { 0x21000061, 0x1400ffe0 }, + { 0x21000062, 0x1400ffe0 }, + { 0x21000063, 0x1400ffe0 }, + { 0x21000064, 0x1400ffe0 }, + { 0x21000065, 0x1400ffe0 }, + { 0x21000066, 0x1400ffe0 }, + { 0x21000067, 0x1400ffe0 }, + { 0x21000068, 0x1400ffe0 }, + { 0x21000069, 0x1400ffe0 }, + { 0x2100006a, 0x1400ffe0 }, + { 0x2100006b, 0x1400ffe0 }, + { 0x2100006c, 0x1400ffe0 }, + { 0x2100006d, 0x1400ffe0 }, + { 0x2100006e, 0x1400ffe0 }, + { 0x2100006f, 0x1400ffe0 }, + { 0x21000070, 0x1400ffe0 }, + { 0x21000071, 0x1400ffe0 }, + { 0x21000072, 0x1400ffe0 }, + { 0x21000073, 0x1400ffe0 }, + { 0x21000074, 0x1400ffe0 }, + { 0x21000075, 0x1400ffe0 }, + { 0x21000076, 0x1400ffe0 }, + { 0x21000077, 0x1400ffe0 }, + { 0x21000078, 0x1400ffe0 }, + { 0x21000079, 0x1400ffe0 }, + { 0x2100007a, 0x1400ffe0 }, + { 0x0900007b, 0x58000000 }, + { 0x0900007c, 0x64000000 }, + { 0x0900007d, 0x48000000 }, + { 0x0900007e, 0x64000000 }, + { 0x0980007f, 0x00000020 }, + { 0x090000a0, 0x74000000 }, + { 0x090000a1, 0x54000000 }, + { 0x098000a2, 0x5c000003 }, + { 0x098000a6, 0x68000001 }, + { 0x090000a8, 0x60000000 }, + { 0x090000a9, 0x68000000 }, + { 0x210000aa, 0x14000000 }, + { 0x090000ab, 0x50000000 }, + { 0x090000ac, 0x64000000 }, + { 0x090000ad, 0x04000000 }, + { 0x090000ae, 0x68000000 }, + { 0x090000af, 0x60000000 }, + { 0x090000b0, 0x68000000 }, + { 0x090000b1, 0x64000000 }, + { 0x098000b2, 0x3c000001 }, + { 0x090000b4, 0x60000000 }, + { 0x090000b5, 0x140002e7 }, + { 0x090000b6, 0x68000000 }, + { 0x090000b7, 0x54000000 }, + { 0x090000b8, 0x60000000 }, + { 0x090000b9, 0x3c000000 }, + { 0x210000ba, 0x14000000 }, + { 0x090000bb, 0x4c000000 }, + { 0x098000bc, 0x3c000002 }, + { 0x090000bf, 0x54000000 }, + { 0x210000c0, 0x24000020 }, + { 0x210000c1, 0x24000020 }, + { 0x210000c2, 0x24000020 }, + { 0x210000c3, 0x24000020 }, + { 0x210000c4, 0x24000020 }, + { 0x210000c5, 0x24000020 }, + { 0x210000c6, 0x24000020 }, + { 0x210000c7, 0x24000020 }, + { 0x210000c8, 0x24000020 }, + { 0x210000c9, 0x24000020 }, + { 0x210000ca, 0x24000020 }, + { 0x210000cb, 0x24000020 }, + { 0x210000cc, 0x24000020 }, + { 0x210000cd, 0x24000020 }, + { 0x210000ce, 0x24000020 }, + { 0x210000cf, 0x24000020 }, + { 0x210000d0, 0x24000020 }, + { 0x210000d1, 0x24000020 }, + { 0x210000d2, 0x24000020 }, + { 0x210000d3, 0x24000020 }, + { 0x210000d4, 0x24000020 }, + { 0x210000d5, 0x24000020 }, + { 0x210000d6, 0x24000020 }, + { 0x090000d7, 0x64000000 }, + { 0x210000d8, 0x24000020 }, + { 0x210000d9, 0x24000020 }, + { 0x210000da, 0x24000020 }, + { 0x210000db, 0x24000020 }, + { 0x210000dc, 0x24000020 }, + { 0x210000dd, 0x24000020 }, + { 0x210000de, 0x24000020 }, + { 0x210000df, 0x14000000 }, + { 0x210000e0, 0x1400ffe0 }, + { 0x210000e1, 0x1400ffe0 }, + { 0x210000e2, 0x1400ffe0 }, + { 0x210000e3, 0x1400ffe0 }, + { 0x210000e4, 0x1400ffe0 }, + { 0x210000e5, 0x1400ffe0 }, + { 0x210000e6, 0x1400ffe0 }, + { 0x210000e7, 0x1400ffe0 }, + { 0x210000e8, 0x1400ffe0 }, + { 0x210000e9, 0x1400ffe0 }, + { 0x210000ea, 0x1400ffe0 }, + { 0x210000eb, 0x1400ffe0 }, + { 0x210000ec, 0x1400ffe0 }, + { 0x210000ed, 0x1400ffe0 }, + { 0x210000ee, 0x1400ffe0 }, + { 0x210000ef, 0x1400ffe0 }, + { 0x210000f0, 0x1400ffe0 }, + { 0x210000f1, 0x1400ffe0 }, + { 0x210000f2, 0x1400ffe0 }, + { 0x210000f3, 0x1400ffe0 }, + { 0x210000f4, 0x1400ffe0 }, + { 0x210000f5, 0x1400ffe0 }, + { 0x210000f6, 0x1400ffe0 }, + { 0x090000f7, 0x64000000 }, + { 0x210000f8, 0x1400ffe0 }, + { 0x210000f9, 0x1400ffe0 }, + { 0x210000fa, 0x1400ffe0 }, + { 0x210000fb, 0x1400ffe0 }, + { 0x210000fc, 0x1400ffe0 }, + { 0x210000fd, 0x1400ffe0 }, + { 0x210000fe, 0x1400ffe0 }, + { 0x210000ff, 0x14000079 }, + { 0x21000100, 0x24000001 }, + { 0x21000101, 0x1400ffff }, + { 0x21000102, 0x24000001 }, + { 0x21000103, 0x1400ffff }, + { 0x21000104, 0x24000001 }, + { 0x21000105, 0x1400ffff }, + { 0x21000106, 0x24000001 }, + { 0x21000107, 0x1400ffff }, + { 0x21000108, 0x24000001 }, + { 0x21000109, 0x1400ffff }, + { 0x2100010a, 0x24000001 }, + { 0x2100010b, 0x1400ffff }, + { 0x2100010c, 0x24000001 }, + { 0x2100010d, 0x1400ffff }, + { 0x2100010e, 0x24000001 }, + { 0x2100010f, 0x1400ffff }, + { 0x21000110, 0x24000001 }, + { 0x21000111, 0x1400ffff }, + { 0x21000112, 0x24000001 }, + { 0x21000113, 0x1400ffff }, + { 0x21000114, 0x24000001 }, + { 0x21000115, 0x1400ffff }, + { 0x21000116, 0x24000001 }, + { 0x21000117, 0x1400ffff }, + { 0x21000118, 0x24000001 }, + { 0x21000119, 0x1400ffff }, + { 0x2100011a, 0x24000001 }, + { 0x2100011b, 0x1400ffff }, + { 0x2100011c, 0x24000001 }, + { 0x2100011d, 0x1400ffff }, + { 0x2100011e, 0x24000001 }, + { 0x2100011f, 0x1400ffff }, + { 0x21000120, 0x24000001 }, + { 0x21000121, 0x1400ffff }, + { 0x21000122, 0x24000001 }, + { 0x21000123, 0x1400ffff }, + { 0x21000124, 0x24000001 }, + { 0x21000125, 0x1400ffff }, + { 0x21000126, 0x24000001 }, + { 0x21000127, 0x1400ffff }, + { 0x21000128, 0x24000001 }, + { 0x21000129, 0x1400ffff }, + { 0x2100012a, 0x24000001 }, + { 0x2100012b, 0x1400ffff }, + { 0x2100012c, 0x24000001 }, + { 0x2100012d, 0x1400ffff }, + { 0x2100012e, 0x24000001 }, + { 0x2100012f, 0x1400ffff }, + { 0x21000130, 0x2400ff39 }, + { 0x21000131, 0x1400ff18 }, + { 0x21000132, 0x24000001 }, + { 0x21000133, 0x1400ffff }, + { 0x21000134, 0x24000001 }, + { 0x21000135, 0x1400ffff }, + { 0x21000136, 0x24000001 }, + { 0x21000137, 0x1400ffff }, + { 0x21000138, 0x14000000 }, + { 0x21000139, 0x24000001 }, + { 0x2100013a, 0x1400ffff }, + { 0x2100013b, 0x24000001 }, + { 0x2100013c, 0x1400ffff }, + { 0x2100013d, 0x24000001 }, + { 0x2100013e, 0x1400ffff }, + { 0x2100013f, 0x24000001 }, + { 0x21000140, 0x1400ffff }, + { 0x21000141, 0x24000001 }, + { 0x21000142, 0x1400ffff }, + { 0x21000143, 0x24000001 }, + { 0x21000144, 0x1400ffff }, + { 0x21000145, 0x24000001 }, + { 0x21000146, 0x1400ffff }, + { 0x21000147, 0x24000001 }, + { 0x21000148, 0x1400ffff }, + { 0x21000149, 0x14000000 }, + { 0x2100014a, 0x24000001 }, + { 0x2100014b, 0x1400ffff }, + { 0x2100014c, 0x24000001 }, + { 0x2100014d, 0x1400ffff }, + { 0x2100014e, 0x24000001 }, + { 0x2100014f, 0x1400ffff }, + { 0x21000150, 0x24000001 }, + { 0x21000151, 0x1400ffff }, + { 0x21000152, 0x24000001 }, + { 0x21000153, 0x1400ffff }, + { 0x21000154, 0x24000001 }, + { 0x21000155, 0x1400ffff }, + { 0x21000156, 0x24000001 }, + { 0x21000157, 0x1400ffff }, + { 0x21000158, 0x24000001 }, + { 0x21000159, 0x1400ffff }, + { 0x2100015a, 0x24000001 }, + { 0x2100015b, 0x1400ffff }, + { 0x2100015c, 0x24000001 }, + { 0x2100015d, 0x1400ffff }, + { 0x2100015e, 0x24000001 }, + { 0x2100015f, 0x1400ffff }, + { 0x21000160, 0x24000001 }, + { 0x21000161, 0x1400ffff }, + { 0x21000162, 0x24000001 }, + { 0x21000163, 0x1400ffff }, + { 0x21000164, 0x24000001 }, + { 0x21000165, 0x1400ffff }, + { 0x21000166, 0x24000001 }, + { 0x21000167, 0x1400ffff }, + { 0x21000168, 0x24000001 }, + { 0x21000169, 0x1400ffff }, + { 0x2100016a, 0x24000001 }, + { 0x2100016b, 0x1400ffff }, + { 0x2100016c, 0x24000001 }, + { 0x2100016d, 0x1400ffff }, + { 0x2100016e, 0x24000001 }, + { 0x2100016f, 0x1400ffff }, + { 0x21000170, 0x24000001 }, + { 0x21000171, 0x1400ffff }, + { 0x21000172, 0x24000001 }, + { 0x21000173, 0x1400ffff }, + { 0x21000174, 0x24000001 }, + { 0x21000175, 0x1400ffff }, + { 0x21000176, 0x24000001 }, + { 0x21000177, 0x1400ffff }, + { 0x21000178, 0x2400ff87 }, + { 0x21000179, 0x24000001 }, + { 0x2100017a, 0x1400ffff }, + { 0x2100017b, 0x24000001 }, + { 0x2100017c, 0x1400ffff }, + { 0x2100017d, 0x24000001 }, + { 0x2100017e, 0x1400ffff }, + { 0x2100017f, 0x1400fed4 }, + { 0x21000180, 0x14000000 }, + { 0x21000181, 0x240000d2 }, + { 0x21000182, 0x24000001 }, + { 0x21000183, 0x1400ffff }, + { 0x21000184, 0x24000001 }, + { 0x21000185, 0x1400ffff }, + { 0x21000186, 0x240000ce }, + { 0x21000187, 0x24000001 }, + { 0x21000188, 0x1400ffff }, + { 0x21000189, 0x240000cd }, + { 0x2100018a, 0x240000cd }, + { 0x2100018b, 0x24000001 }, + { 0x2100018c, 0x1400ffff }, + { 0x2100018d, 0x14000000 }, + { 0x2100018e, 0x2400004f }, + { 0x2100018f, 0x240000ca }, + { 0x21000190, 0x240000cb }, + { 0x21000191, 0x24000001 }, + { 0x21000192, 0x1400ffff }, + { 0x21000193, 0x240000cd }, + { 0x21000194, 0x240000cf }, + { 0x21000195, 0x14000061 }, + { 0x21000196, 0x240000d3 }, + { 0x21000197, 0x240000d1 }, + { 0x21000198, 0x24000001 }, + { 0x21000199, 0x1400ffff }, + { 0x2100019a, 0x140000a3 }, + { 0x2100019b, 0x14000000 }, + { 0x2100019c, 0x240000d3 }, + { 0x2100019d, 0x240000d5 }, + { 0x2100019e, 0x14000082 }, + { 0x2100019f, 0x240000d6 }, + { 0x210001a0, 0x24000001 }, + { 0x210001a1, 0x1400ffff }, + { 0x210001a2, 0x24000001 }, + { 0x210001a3, 0x1400ffff }, + { 0x210001a4, 0x24000001 }, + { 0x210001a5, 0x1400ffff }, + { 0x210001a6, 0x240000da }, + { 0x210001a7, 0x24000001 }, + { 0x210001a8, 0x1400ffff }, + { 0x210001a9, 0x240000da }, + { 0x218001aa, 0x14000001 }, + { 0x210001ac, 0x24000001 }, + { 0x210001ad, 0x1400ffff }, + { 0x210001ae, 0x240000da }, + { 0x210001af, 0x24000001 }, + { 0x210001b0, 0x1400ffff }, + { 0x210001b1, 0x240000d9 }, + { 0x210001b2, 0x240000d9 }, + { 0x210001b3, 0x24000001 }, + { 0x210001b4, 0x1400ffff }, + { 0x210001b5, 0x24000001 }, + { 0x210001b6, 0x1400ffff }, + { 0x210001b7, 0x240000db }, + { 0x210001b8, 0x24000001 }, + { 0x210001b9, 0x1400ffff }, + { 0x210001ba, 0x14000000 }, + { 0x210001bb, 0x1c000000 }, + { 0x210001bc, 0x24000001 }, + { 0x210001bd, 0x1400ffff }, + { 0x210001be, 0x14000000 }, + { 0x210001bf, 0x14000038 }, + { 0x218001c0, 0x1c000003 }, + { 0x210001c4, 0x24000002 }, + { 0x210001c5, 0x2000ffff }, + { 0x210001c6, 0x1400fffe }, + { 0x210001c7, 0x24000002 }, + { 0x210001c8, 0x2000ffff }, + { 0x210001c9, 0x1400fffe }, + { 0x210001ca, 0x24000002 }, + { 0x210001cb, 0x2000ffff }, + { 0x210001cc, 0x1400fffe }, + { 0x210001cd, 0x24000001 }, + { 0x210001ce, 0x1400ffff }, + { 0x210001cf, 0x24000001 }, + { 0x210001d0, 0x1400ffff }, + { 0x210001d1, 0x24000001 }, + { 0x210001d2, 0x1400ffff }, + { 0x210001d3, 0x24000001 }, + { 0x210001d4, 0x1400ffff }, + { 0x210001d5, 0x24000001 }, + { 0x210001d6, 0x1400ffff }, + { 0x210001d7, 0x24000001 }, + { 0x210001d8, 0x1400ffff }, + { 0x210001d9, 0x24000001 }, + { 0x210001da, 0x1400ffff }, + { 0x210001db, 0x24000001 }, + { 0x210001dc, 0x1400ffff }, + { 0x210001dd, 0x1400ffb1 }, + { 0x210001de, 0x24000001 }, + { 0x210001df, 0x1400ffff }, + { 0x210001e0, 0x24000001 }, + { 0x210001e1, 0x1400ffff }, + { 0x210001e2, 0x24000001 }, + { 0x210001e3, 0x1400ffff }, + { 0x210001e4, 0x24000001 }, + { 0x210001e5, 0x1400ffff }, + { 0x210001e6, 0x24000001 }, + { 0x210001e7, 0x1400ffff }, + { 0x210001e8, 0x24000001 }, + { 0x210001e9, 0x1400ffff }, + { 0x210001ea, 0x24000001 }, + { 0x210001eb, 0x1400ffff }, + { 0x210001ec, 0x24000001 }, + { 0x210001ed, 0x1400ffff }, + { 0x210001ee, 0x24000001 }, + { 0x210001ef, 0x1400ffff }, + { 0x210001f0, 0x14000000 }, + { 0x210001f1, 0x24000002 }, + { 0x210001f2, 0x2000ffff }, + { 0x210001f3, 0x1400fffe }, + { 0x210001f4, 0x24000001 }, + { 0x210001f5, 0x1400ffff }, + { 0x210001f6, 0x2400ff9f }, + { 0x210001f7, 0x2400ffc8 }, + { 0x210001f8, 0x24000001 }, + { 0x210001f9, 0x1400ffff }, + { 0x210001fa, 0x24000001 }, + { 0x210001fb, 0x1400ffff }, + { 0x210001fc, 0x24000001 }, + { 0x210001fd, 0x1400ffff }, + { 0x210001fe, 0x24000001 }, + { 0x210001ff, 0x1400ffff }, + { 0x21000200, 0x24000001 }, + { 0x21000201, 0x1400ffff }, + { 0x21000202, 0x24000001 }, + { 0x21000203, 0x1400ffff }, + { 0x21000204, 0x24000001 }, + { 0x21000205, 0x1400ffff }, + { 0x21000206, 0x24000001 }, + { 0x21000207, 0x1400ffff }, + { 0x21000208, 0x24000001 }, + { 0x21000209, 0x1400ffff }, + { 0x2100020a, 0x24000001 }, + { 0x2100020b, 0x1400ffff }, + { 0x2100020c, 0x24000001 }, + { 0x2100020d, 0x1400ffff }, + { 0x2100020e, 0x24000001 }, + { 0x2100020f, 0x1400ffff }, + { 0x21000210, 0x24000001 }, + { 0x21000211, 0x1400ffff }, + { 0x21000212, 0x24000001 }, + { 0x21000213, 0x1400ffff }, + { 0x21000214, 0x24000001 }, + { 0x21000215, 0x1400ffff }, + { 0x21000216, 0x24000001 }, + { 0x21000217, 0x1400ffff }, + { 0x21000218, 0x24000001 }, + { 0x21000219, 0x1400ffff }, + { 0x2100021a, 0x24000001 }, + { 0x2100021b, 0x1400ffff }, + { 0x2100021c, 0x24000001 }, + { 0x2100021d, 0x1400ffff }, + { 0x2100021e, 0x24000001 }, + { 0x2100021f, 0x1400ffff }, + { 0x21000220, 0x2400ff7e }, + { 0x21000221, 0x14000000 }, + { 0x21000222, 0x24000001 }, + { 0x21000223, 0x1400ffff }, + { 0x21000224, 0x24000001 }, + { 0x21000225, 0x1400ffff }, + { 0x21000226, 0x24000001 }, + { 0x21000227, 0x1400ffff }, + { 0x21000228, 0x24000001 }, + { 0x21000229, 0x1400ffff }, + { 0x2100022a, 0x24000001 }, + { 0x2100022b, 0x1400ffff }, + { 0x2100022c, 0x24000001 }, + { 0x2100022d, 0x1400ffff }, + { 0x2100022e, 0x24000001 }, + { 0x2100022f, 0x1400ffff }, + { 0x21000230, 0x24000001 }, + { 0x21000231, 0x1400ffff }, + { 0x21000232, 0x24000001 }, + { 0x21000233, 0x1400ffff }, + { 0x21800234, 0x14000005 }, + { 0x2100023a, 0x24000000 }, + { 0x2100023b, 0x24000001 }, + { 0x2100023c, 0x1400ffff }, + { 0x2100023d, 0x2400ff5d }, + { 0x2100023e, 0x24000000 }, + { 0x2180023f, 0x14000001 }, + { 0x21000241, 0x24000053 }, + { 0x21800250, 0x14000002 }, + { 0x21000253, 0x1400ff2e }, + { 0x21000254, 0x1400ff32 }, + { 0x21000255, 0x14000000 }, + { 0x21000256, 0x1400ff33 }, + { 0x21000257, 0x1400ff33 }, + { 0x21000258, 0x14000000 }, + { 0x21000259, 0x1400ff36 }, + { 0x2100025a, 0x14000000 }, + { 0x2100025b, 0x1400ff35 }, + { 0x2180025c, 0x14000003 }, + { 0x21000260, 0x1400ff33 }, + { 0x21800261, 0x14000001 }, + { 0x21000263, 0x1400ff31 }, + { 0x21800264, 0x14000003 }, + { 0x21000268, 0x1400ff2f }, + { 0x21000269, 0x1400ff2d }, + { 0x2180026a, 0x14000004 }, + { 0x2100026f, 0x1400ff2d }, + { 0x21800270, 0x14000001 }, + { 0x21000272, 0x1400ff2b }, + { 0x21800273, 0x14000001 }, + { 0x21000275, 0x1400ff2a }, + { 0x21800276, 0x14000009 }, + { 0x21000280, 0x1400ff26 }, + { 0x21800281, 0x14000001 }, + { 0x21000283, 0x1400ff26 }, + { 0x21800284, 0x14000003 }, + { 0x21000288, 0x1400ff26 }, + { 0x21000289, 0x14000000 }, + { 0x2100028a, 0x1400ff27 }, + { 0x2100028b, 0x1400ff27 }, + { 0x2180028c, 0x14000005 }, + { 0x21000292, 0x1400ff25 }, + { 0x21000293, 0x14000000 }, + { 0x21000294, 0x1400ffad }, + { 0x21800295, 0x1400001a }, + { 0x218002b0, 0x18000011 }, + { 0x098002c2, 0x60000003 }, + { 0x098002c6, 0x1800000b }, + { 0x098002d2, 0x6000000d }, + { 0x218002e0, 0x18000004 }, + { 0x098002e5, 0x60000008 }, + { 0x090002ee, 0x18000000 }, + { 0x098002ef, 0x60000010 }, + { 0x1b800300, 0x30000044 }, + { 0x1b000345, 0x30000054 }, + { 0x1b800346, 0x30000029 }, + { 0x13800374, 0x60000001 }, + { 0x1300037a, 0x18000000 }, + { 0x0900037e, 0x54000000 }, + { 0x13800384, 0x60000001 }, + { 0x13000386, 0x24000026 }, + { 0x09000387, 0x54000000 }, + { 0x13000388, 0x24000025 }, + { 0x13000389, 0x24000025 }, + { 0x1300038a, 0x24000025 }, + { 0x1300038c, 0x24000040 }, + { 0x1300038e, 0x2400003f }, + { 0x1300038f, 0x2400003f }, + { 0x13000390, 0x14000000 }, + { 0x13000391, 0x24000020 }, + { 0x13000392, 0x24000020 }, + { 0x13000393, 0x24000020 }, + { 0x13000394, 0x24000020 }, + { 0x13000395, 0x24000020 }, + { 0x13000396, 0x24000020 }, + { 0x13000397, 0x24000020 }, + { 0x13000398, 0x24000020 }, + { 0x13000399, 0x24000020 }, + { 0x1300039a, 0x24000020 }, + { 0x1300039b, 0x24000020 }, + { 0x1300039c, 0x24000020 }, + { 0x1300039d, 0x24000020 }, + { 0x1300039e, 0x24000020 }, + { 0x1300039f, 0x24000020 }, + { 0x130003a0, 0x24000020 }, + { 0x130003a1, 0x24000020 }, + { 0x130003a3, 0x24000020 }, + { 0x130003a4, 0x24000020 }, + { 0x130003a5, 0x24000020 }, + { 0x130003a6, 0x24000020 }, + { 0x130003a7, 0x24000020 }, + { 0x130003a8, 0x24000020 }, + { 0x130003a9, 0x24000020 }, + { 0x130003aa, 0x24000020 }, + { 0x130003ab, 0x24000020 }, + { 0x130003ac, 0x1400ffda }, + { 0x130003ad, 0x1400ffdb }, + { 0x130003ae, 0x1400ffdb }, + { 0x130003af, 0x1400ffdb }, + { 0x130003b0, 0x14000000 }, + { 0x130003b1, 0x1400ffe0 }, + { 0x130003b2, 0x1400ffe0 }, + { 0x130003b3, 0x1400ffe0 }, + { 0x130003b4, 0x1400ffe0 }, + { 0x130003b5, 0x1400ffe0 }, + { 0x130003b6, 0x1400ffe0 }, + { 0x130003b7, 0x1400ffe0 }, + { 0x130003b8, 0x1400ffe0 }, + { 0x130003b9, 0x1400ffe0 }, + { 0x130003ba, 0x1400ffe0 }, + { 0x130003bb, 0x1400ffe0 }, + { 0x130003bc, 0x1400ffe0 }, + { 0x130003bd, 0x1400ffe0 }, + { 0x130003be, 0x1400ffe0 }, + { 0x130003bf, 0x1400ffe0 }, + { 0x130003c0, 0x1400ffe0 }, + { 0x130003c1, 0x1400ffe0 }, + { 0x130003c2, 0x1400ffe1 }, + { 0x130003c3, 0x1400ffe0 }, + { 0x130003c4, 0x1400ffe0 }, + { 0x130003c5, 0x1400ffe0 }, + { 0x130003c6, 0x1400ffe0 }, + { 0x130003c7, 0x1400ffe0 }, + { 0x130003c8, 0x1400ffe0 }, + { 0x130003c9, 0x1400ffe0 }, + { 0x130003ca, 0x1400ffe0 }, + { 0x130003cb, 0x1400ffe0 }, + { 0x130003cc, 0x1400ffc0 }, + { 0x130003cd, 0x1400ffc1 }, + { 0x130003ce, 0x1400ffc1 }, + { 0x130003d0, 0x1400ffc2 }, + { 0x130003d1, 0x1400ffc7 }, + { 0x138003d2, 0x24000002 }, + { 0x130003d5, 0x1400ffd1 }, + { 0x130003d6, 0x1400ffca }, + { 0x130003d7, 0x14000000 }, + { 0x130003d8, 0x24000001 }, + { 0x130003d9, 0x1400ffff }, + { 0x130003da, 0x24000001 }, + { 0x130003db, 0x1400ffff }, + { 0x130003dc, 0x24000001 }, + { 0x130003dd, 0x1400ffff }, + { 0x130003de, 0x24000001 }, + { 0x130003df, 0x1400ffff }, + { 0x130003e0, 0x24000001 }, + { 0x130003e1, 0x1400ffff }, + { 0x0a0003e2, 0x24000001 }, + { 0x0a0003e3, 0x1400ffff }, + { 0x0a0003e4, 0x24000001 }, + { 0x0a0003e5, 0x1400ffff }, + { 0x0a0003e6, 0x24000001 }, + { 0x0a0003e7, 0x1400ffff }, + { 0x0a0003e8, 0x24000001 }, + { 0x0a0003e9, 0x1400ffff }, + { 0x0a0003ea, 0x24000001 }, + { 0x0a0003eb, 0x1400ffff }, + { 0x0a0003ec, 0x24000001 }, + { 0x0a0003ed, 0x1400ffff }, + { 0x0a0003ee, 0x24000001 }, + { 0x0a0003ef, 0x1400ffff }, + { 0x130003f0, 0x1400ffaa }, + { 0x130003f1, 0x1400ffb0 }, + { 0x130003f2, 0x14000007 }, + { 0x130003f3, 0x14000000 }, + { 0x130003f4, 0x2400ffc4 }, + { 0x130003f5, 0x1400ffa0 }, + { 0x130003f6, 0x64000000 }, + { 0x130003f7, 0x24000001 }, + { 0x130003f8, 0x1400ffff }, + { 0x130003f9, 0x2400fff9 }, + { 0x130003fa, 0x24000001 }, + { 0x130003fb, 0x1400ffff }, + { 0x130003fc, 0x14000000 }, + { 0x138003fd, 0x24000002 }, + { 0x0c000400, 0x24000050 }, + { 0x0c000401, 0x24000050 }, + { 0x0c000402, 0x24000050 }, + { 0x0c000403, 0x24000050 }, + { 0x0c000404, 0x24000050 }, + { 0x0c000405, 0x24000050 }, + { 0x0c000406, 0x24000050 }, + { 0x0c000407, 0x24000050 }, + { 0x0c000408, 0x24000050 }, + { 0x0c000409, 0x24000050 }, + { 0x0c00040a, 0x24000050 }, + { 0x0c00040b, 0x24000050 }, + { 0x0c00040c, 0x24000050 }, + { 0x0c00040d, 0x24000050 }, + { 0x0c00040e, 0x24000050 }, + { 0x0c00040f, 0x24000050 }, + { 0x0c000410, 0x24000020 }, + { 0x0c000411, 0x24000020 }, + { 0x0c000412, 0x24000020 }, + { 0x0c000413, 0x24000020 }, + { 0x0c000414, 0x24000020 }, + { 0x0c000415, 0x24000020 }, + { 0x0c000416, 0x24000020 }, + { 0x0c000417, 0x24000020 }, + { 0x0c000418, 0x24000020 }, + { 0x0c000419, 0x24000020 }, + { 0x0c00041a, 0x24000020 }, + { 0x0c00041b, 0x24000020 }, + { 0x0c00041c, 0x24000020 }, + { 0x0c00041d, 0x24000020 }, + { 0x0c00041e, 0x24000020 }, + { 0x0c00041f, 0x24000020 }, + { 0x0c000420, 0x24000020 }, + { 0x0c000421, 0x24000020 }, + { 0x0c000422, 0x24000020 }, + { 0x0c000423, 0x24000020 }, + { 0x0c000424, 0x24000020 }, + { 0x0c000425, 0x24000020 }, + { 0x0c000426, 0x24000020 }, + { 0x0c000427, 0x24000020 }, + { 0x0c000428, 0x24000020 }, + { 0x0c000429, 0x24000020 }, + { 0x0c00042a, 0x24000020 }, + { 0x0c00042b, 0x24000020 }, + { 0x0c00042c, 0x24000020 }, + { 0x0c00042d, 0x24000020 }, + { 0x0c00042e, 0x24000020 }, + { 0x0c00042f, 0x24000020 }, + { 0x0c000430, 0x1400ffe0 }, + { 0x0c000431, 0x1400ffe0 }, + { 0x0c000432, 0x1400ffe0 }, + { 0x0c000433, 0x1400ffe0 }, + { 0x0c000434, 0x1400ffe0 }, + { 0x0c000435, 0x1400ffe0 }, + { 0x0c000436, 0x1400ffe0 }, + { 0x0c000437, 0x1400ffe0 }, + { 0x0c000438, 0x1400ffe0 }, + { 0x0c000439, 0x1400ffe0 }, + { 0x0c00043a, 0x1400ffe0 }, + { 0x0c00043b, 0x1400ffe0 }, + { 0x0c00043c, 0x1400ffe0 }, + { 0x0c00043d, 0x1400ffe0 }, + { 0x0c00043e, 0x1400ffe0 }, + { 0x0c00043f, 0x1400ffe0 }, + { 0x0c000440, 0x1400ffe0 }, + { 0x0c000441, 0x1400ffe0 }, + { 0x0c000442, 0x1400ffe0 }, + { 0x0c000443, 0x1400ffe0 }, + { 0x0c000444, 0x1400ffe0 }, + { 0x0c000445, 0x1400ffe0 }, + { 0x0c000446, 0x1400ffe0 }, + { 0x0c000447, 0x1400ffe0 }, + { 0x0c000448, 0x1400ffe0 }, + { 0x0c000449, 0x1400ffe0 }, + { 0x0c00044a, 0x1400ffe0 }, + { 0x0c00044b, 0x1400ffe0 }, + { 0x0c00044c, 0x1400ffe0 }, + { 0x0c00044d, 0x1400ffe0 }, + { 0x0c00044e, 0x1400ffe0 }, + { 0x0c00044f, 0x1400ffe0 }, + { 0x0c000450, 0x1400ffb0 }, + { 0x0c000451, 0x1400ffb0 }, + { 0x0c000452, 0x1400ffb0 }, + { 0x0c000453, 0x1400ffb0 }, + { 0x0c000454, 0x1400ffb0 }, + { 0x0c000455, 0x1400ffb0 }, + { 0x0c000456, 0x1400ffb0 }, + { 0x0c000457, 0x1400ffb0 }, + { 0x0c000458, 0x1400ffb0 }, + { 0x0c000459, 0x1400ffb0 }, + { 0x0c00045a, 0x1400ffb0 }, + { 0x0c00045b, 0x1400ffb0 }, + { 0x0c00045c, 0x1400ffb0 }, + { 0x0c00045d, 0x1400ffb0 }, + { 0x0c00045e, 0x1400ffb0 }, + { 0x0c00045f, 0x1400ffb0 }, + { 0x0c000460, 0x24000001 }, + { 0x0c000461, 0x1400ffff }, + { 0x0c000462, 0x24000001 }, + { 0x0c000463, 0x1400ffff }, + { 0x0c000464, 0x24000001 }, + { 0x0c000465, 0x1400ffff }, + { 0x0c000466, 0x24000001 }, + { 0x0c000467, 0x1400ffff }, + { 0x0c000468, 0x24000001 }, + { 0x0c000469, 0x1400ffff }, + { 0x0c00046a, 0x24000001 }, + { 0x0c00046b, 0x1400ffff }, + { 0x0c00046c, 0x24000001 }, + { 0x0c00046d, 0x1400ffff }, + { 0x0c00046e, 0x24000001 }, + { 0x0c00046f, 0x1400ffff }, + { 0x0c000470, 0x24000001 }, + { 0x0c000471, 0x1400ffff }, + { 0x0c000472, 0x24000001 }, + { 0x0c000473, 0x1400ffff }, + { 0x0c000474, 0x24000001 }, + { 0x0c000475, 0x1400ffff }, + { 0x0c000476, 0x24000001 }, + { 0x0c000477, 0x1400ffff }, + { 0x0c000478, 0x24000001 }, + { 0x0c000479, 0x1400ffff }, + { 0x0c00047a, 0x24000001 }, + { 0x0c00047b, 0x1400ffff }, + { 0x0c00047c, 0x24000001 }, + { 0x0c00047d, 0x1400ffff }, + { 0x0c00047e, 0x24000001 }, + { 0x0c00047f, 0x1400ffff }, + { 0x0c000480, 0x24000001 }, + { 0x0c000481, 0x1400ffff }, + { 0x0c000482, 0x68000000 }, + { 0x0c800483, 0x30000003 }, + { 0x0c800488, 0x2c000001 }, + { 0x0c00048a, 0x24000001 }, + { 0x0c00048b, 0x1400ffff }, + { 0x0c00048c, 0x24000001 }, + { 0x0c00048d, 0x1400ffff }, + { 0x0c00048e, 0x24000001 }, + { 0x0c00048f, 0x1400ffff }, + { 0x0c000490, 0x24000001 }, + { 0x0c000491, 0x1400ffff }, + { 0x0c000492, 0x24000001 }, + { 0x0c000493, 0x1400ffff }, + { 0x0c000494, 0x24000001 }, + { 0x0c000495, 0x1400ffff }, + { 0x0c000496, 0x24000001 }, + { 0x0c000497, 0x1400ffff }, + { 0x0c000498, 0x24000001 }, + { 0x0c000499, 0x1400ffff }, + { 0x0c00049a, 0x24000001 }, + { 0x0c00049b, 0x1400ffff }, + { 0x0c00049c, 0x24000001 }, + { 0x0c00049d, 0x1400ffff }, + { 0x0c00049e, 0x24000001 }, + { 0x0c00049f, 0x1400ffff }, + { 0x0c0004a0, 0x24000001 }, + { 0x0c0004a1, 0x1400ffff }, + { 0x0c0004a2, 0x24000001 }, + { 0x0c0004a3, 0x1400ffff }, + { 0x0c0004a4, 0x24000001 }, + { 0x0c0004a5, 0x1400ffff }, + { 0x0c0004a6, 0x24000001 }, + { 0x0c0004a7, 0x1400ffff }, + { 0x0c0004a8, 0x24000001 }, + { 0x0c0004a9, 0x1400ffff }, + { 0x0c0004aa, 0x24000001 }, + { 0x0c0004ab, 0x1400ffff }, + { 0x0c0004ac, 0x24000001 }, + { 0x0c0004ad, 0x1400ffff }, + { 0x0c0004ae, 0x24000001 }, + { 0x0c0004af, 0x1400ffff }, + { 0x0c0004b0, 0x24000001 }, + { 0x0c0004b1, 0x1400ffff }, + { 0x0c0004b2, 0x24000001 }, + { 0x0c0004b3, 0x1400ffff }, + { 0x0c0004b4, 0x24000001 }, + { 0x0c0004b5, 0x1400ffff }, + { 0x0c0004b6, 0x24000001 }, + { 0x0c0004b7, 0x1400ffff }, + { 0x0c0004b8, 0x24000001 }, + { 0x0c0004b9, 0x1400ffff }, + { 0x0c0004ba, 0x24000001 }, + { 0x0c0004bb, 0x1400ffff }, + { 0x0c0004bc, 0x24000001 }, + { 0x0c0004bd, 0x1400ffff }, + { 0x0c0004be, 0x24000001 }, + { 0x0c0004bf, 0x1400ffff }, + { 0x0c0004c0, 0x24000000 }, + { 0x0c0004c1, 0x24000001 }, + { 0x0c0004c2, 0x1400ffff }, + { 0x0c0004c3, 0x24000001 }, + { 0x0c0004c4, 0x1400ffff }, + { 0x0c0004c5, 0x24000001 }, + { 0x0c0004c6, 0x1400ffff }, + { 0x0c0004c7, 0x24000001 }, + { 0x0c0004c8, 0x1400ffff }, + { 0x0c0004c9, 0x24000001 }, + { 0x0c0004ca, 0x1400ffff }, + { 0x0c0004cb, 0x24000001 }, + { 0x0c0004cc, 0x1400ffff }, + { 0x0c0004cd, 0x24000001 }, + { 0x0c0004ce, 0x1400ffff }, + { 0x0c0004d0, 0x24000001 }, + { 0x0c0004d1, 0x1400ffff }, + { 0x0c0004d2, 0x24000001 }, + { 0x0c0004d3, 0x1400ffff }, + { 0x0c0004d4, 0x24000001 }, + { 0x0c0004d5, 0x1400ffff }, + { 0x0c0004d6, 0x24000001 }, + { 0x0c0004d7, 0x1400ffff }, + { 0x0c0004d8, 0x24000001 }, + { 0x0c0004d9, 0x1400ffff }, + { 0x0c0004da, 0x24000001 }, + { 0x0c0004db, 0x1400ffff }, + { 0x0c0004dc, 0x24000001 }, + { 0x0c0004dd, 0x1400ffff }, + { 0x0c0004de, 0x24000001 }, + { 0x0c0004df, 0x1400ffff }, + { 0x0c0004e0, 0x24000001 }, + { 0x0c0004e1, 0x1400ffff }, + { 0x0c0004e2, 0x24000001 }, + { 0x0c0004e3, 0x1400ffff }, + { 0x0c0004e4, 0x24000001 }, + { 0x0c0004e5, 0x1400ffff }, + { 0x0c0004e6, 0x24000001 }, + { 0x0c0004e7, 0x1400ffff }, + { 0x0c0004e8, 0x24000001 }, + { 0x0c0004e9, 0x1400ffff }, + { 0x0c0004ea, 0x24000001 }, + { 0x0c0004eb, 0x1400ffff }, + { 0x0c0004ec, 0x24000001 }, + { 0x0c0004ed, 0x1400ffff }, + { 0x0c0004ee, 0x24000001 }, + { 0x0c0004ef, 0x1400ffff }, + { 0x0c0004f0, 0x24000001 }, + { 0x0c0004f1, 0x1400ffff }, + { 0x0c0004f2, 0x24000001 }, + { 0x0c0004f3, 0x1400ffff }, + { 0x0c0004f4, 0x24000001 }, + { 0x0c0004f5, 0x1400ffff }, + { 0x0c0004f6, 0x24000001 }, + { 0x0c0004f7, 0x1400ffff }, + { 0x0c0004f8, 0x24000001 }, + { 0x0c0004f9, 0x1400ffff }, + { 0x0c000500, 0x24000001 }, + { 0x0c000501, 0x1400ffff }, + { 0x0c000502, 0x24000001 }, + { 0x0c000503, 0x1400ffff }, + { 0x0c000504, 0x24000001 }, + { 0x0c000505, 0x1400ffff }, + { 0x0c000506, 0x24000001 }, + { 0x0c000507, 0x1400ffff }, + { 0x0c000508, 0x24000001 }, + { 0x0c000509, 0x1400ffff }, + { 0x0c00050a, 0x24000001 }, + { 0x0c00050b, 0x1400ffff }, + { 0x0c00050c, 0x24000001 }, + { 0x0c00050d, 0x1400ffff }, + { 0x0c00050e, 0x24000001 }, + { 0x0c00050f, 0x1400ffff }, + { 0x01000531, 0x24000030 }, + { 0x01000532, 0x24000030 }, + { 0x01000533, 0x24000030 }, + { 0x01000534, 0x24000030 }, + { 0x01000535, 0x24000030 }, + { 0x01000536, 0x24000030 }, + { 0x01000537, 0x24000030 }, + { 0x01000538, 0x24000030 }, + { 0x01000539, 0x24000030 }, + { 0x0100053a, 0x24000030 }, + { 0x0100053b, 0x24000030 }, + { 0x0100053c, 0x24000030 }, + { 0x0100053d, 0x24000030 }, + { 0x0100053e, 0x24000030 }, + { 0x0100053f, 0x24000030 }, + { 0x01000540, 0x24000030 }, + { 0x01000541, 0x24000030 }, + { 0x01000542, 0x24000030 }, + { 0x01000543, 0x24000030 }, + { 0x01000544, 0x24000030 }, + { 0x01000545, 0x24000030 }, + { 0x01000546, 0x24000030 }, + { 0x01000547, 0x24000030 }, + { 0x01000548, 0x24000030 }, + { 0x01000549, 0x24000030 }, + { 0x0100054a, 0x24000030 }, + { 0x0100054b, 0x24000030 }, + { 0x0100054c, 0x24000030 }, + { 0x0100054d, 0x24000030 }, + { 0x0100054e, 0x24000030 }, + { 0x0100054f, 0x24000030 }, + { 0x01000550, 0x24000030 }, + { 0x01000551, 0x24000030 }, + { 0x01000552, 0x24000030 }, + { 0x01000553, 0x24000030 }, + { 0x01000554, 0x24000030 }, + { 0x01000555, 0x24000030 }, + { 0x01000556, 0x24000030 }, + { 0x01000559, 0x18000000 }, + { 0x0180055a, 0x54000005 }, + { 0x01000561, 0x1400ffd0 }, + { 0x01000562, 0x1400ffd0 }, + { 0x01000563, 0x1400ffd0 }, + { 0x01000564, 0x1400ffd0 }, + { 0x01000565, 0x1400ffd0 }, + { 0x01000566, 0x1400ffd0 }, + { 0x01000567, 0x1400ffd0 }, + { 0x01000568, 0x1400ffd0 }, + { 0x01000569, 0x1400ffd0 }, + { 0x0100056a, 0x1400ffd0 }, + { 0x0100056b, 0x1400ffd0 }, + { 0x0100056c, 0x1400ffd0 }, + { 0x0100056d, 0x1400ffd0 }, + { 0x0100056e, 0x1400ffd0 }, + { 0x0100056f, 0x1400ffd0 }, + { 0x01000570, 0x1400ffd0 }, + { 0x01000571, 0x1400ffd0 }, + { 0x01000572, 0x1400ffd0 }, + { 0x01000573, 0x1400ffd0 }, + { 0x01000574, 0x1400ffd0 }, + { 0x01000575, 0x1400ffd0 }, + { 0x01000576, 0x1400ffd0 }, + { 0x01000577, 0x1400ffd0 }, + { 0x01000578, 0x1400ffd0 }, + { 0x01000579, 0x1400ffd0 }, + { 0x0100057a, 0x1400ffd0 }, + { 0x0100057b, 0x1400ffd0 }, + { 0x0100057c, 0x1400ffd0 }, + { 0x0100057d, 0x1400ffd0 }, + { 0x0100057e, 0x1400ffd0 }, + { 0x0100057f, 0x1400ffd0 }, + { 0x01000580, 0x1400ffd0 }, + { 0x01000581, 0x1400ffd0 }, + { 0x01000582, 0x1400ffd0 }, + { 0x01000583, 0x1400ffd0 }, + { 0x01000584, 0x1400ffd0 }, + { 0x01000585, 0x1400ffd0 }, + { 0x01000586, 0x1400ffd0 }, + { 0x01000587, 0x14000000 }, + { 0x09000589, 0x54000000 }, + { 0x0100058a, 0x44000000 }, + { 0x19800591, 0x30000028 }, + { 0x198005bb, 0x30000002 }, + { 0x190005be, 0x54000000 }, + { 0x190005bf, 0x30000000 }, + { 0x190005c0, 0x54000000 }, + { 0x198005c1, 0x30000001 }, + { 0x190005c3, 0x54000000 }, + { 0x198005c4, 0x30000001 }, + { 0x190005c6, 0x54000000 }, + { 0x190005c7, 0x30000000 }, + { 0x198005d0, 0x1c00001a }, + { 0x198005f0, 0x1c000002 }, + { 0x198005f3, 0x54000001 }, + { 0x09800600, 0x04000003 }, + { 0x0000060b, 0x5c000000 }, + { 0x0980060c, 0x54000001 }, + { 0x0080060e, 0x68000001 }, + { 0x00800610, 0x30000005 }, + { 0x0900061b, 0x54000000 }, + { 0x0080061e, 0x54000001 }, + { 0x00800621, 0x1c000019 }, + { 0x09000640, 0x18000000 }, + { 0x00800641, 0x1c000009 }, + { 0x1b80064b, 0x30000013 }, + { 0x09800660, 0x34000009 }, + { 0x0080066a, 0x54000003 }, + { 0x0080066e, 0x1c000001 }, + { 0x1b000670, 0x30000000 }, + { 0x00800671, 0x1c000062 }, + { 0x000006d4, 0x54000000 }, + { 0x000006d5, 0x1c000000 }, + { 0x008006d6, 0x30000006 }, + { 0x090006dd, 0x04000000 }, + { 0x000006de, 0x2c000000 }, + { 0x008006df, 0x30000005 }, + { 0x008006e5, 0x18000001 }, + { 0x008006e7, 0x30000001 }, + { 0x000006e9, 0x68000000 }, + { 0x008006ea, 0x30000003 }, + { 0x008006ee, 0x1c000001 }, + { 0x008006f0, 0x34000009 }, + { 0x008006fa, 0x1c000002 }, + { 0x008006fd, 0x68000001 }, + { 0x000006ff, 0x1c000000 }, + { 0x31800700, 0x5400000d }, + { 0x3100070f, 0x04000000 }, + { 0x31000710, 0x1c000000 }, + { 0x31000711, 0x30000000 }, + { 0x31800712, 0x1c00001d }, + { 0x31800730, 0x3000001a }, + { 0x3180074d, 0x1c000020 }, + { 0x37800780, 0x1c000025 }, + { 0x378007a6, 0x3000000a }, + { 0x370007b1, 0x1c000000 }, + { 0x0e800901, 0x30000001 }, + { 0x0e000903, 0x28000000 }, + { 0x0e800904, 0x1c000035 }, + { 0x0e00093c, 0x30000000 }, + { 0x0e00093d, 0x1c000000 }, + { 0x0e80093e, 0x28000002 }, + { 0x0e800941, 0x30000007 }, + { 0x0e800949, 0x28000003 }, + { 0x0e00094d, 0x30000000 }, + { 0x0e000950, 0x1c000000 }, + { 0x0e800951, 0x30000003 }, + { 0x0e800958, 0x1c000009 }, + { 0x0e800962, 0x30000001 }, + { 0x09800964, 0x54000001 }, + { 0x0e800966, 0x34000009 }, + { 0x09000970, 0x54000000 }, + { 0x0e00097d, 0x1c000000 }, + { 0x02000981, 0x30000000 }, + { 0x02800982, 0x28000001 }, + { 0x02800985, 0x1c000007 }, + { 0x0280098f, 0x1c000001 }, + { 0x02800993, 0x1c000015 }, + { 0x028009aa, 0x1c000006 }, + { 0x020009b2, 0x1c000000 }, + { 0x028009b6, 0x1c000003 }, + { 0x020009bc, 0x30000000 }, + { 0x020009bd, 0x1c000000 }, + { 0x028009be, 0x28000002 }, + { 0x028009c1, 0x30000003 }, + { 0x028009c7, 0x28000001 }, + { 0x028009cb, 0x28000001 }, + { 0x020009cd, 0x30000000 }, + { 0x020009ce, 0x1c000000 }, + { 0x020009d7, 0x28000000 }, + { 0x028009dc, 0x1c000001 }, + { 0x028009df, 0x1c000002 }, + { 0x028009e2, 0x30000001 }, + { 0x028009e6, 0x34000009 }, + { 0x028009f0, 0x1c000001 }, + { 0x028009f2, 0x5c000001 }, + { 0x028009f4, 0x3c000005 }, + { 0x020009fa, 0x68000000 }, + { 0x15800a01, 0x30000001 }, + { 0x15000a03, 0x28000000 }, + { 0x15800a05, 0x1c000005 }, + { 0x15800a0f, 0x1c000001 }, + { 0x15800a13, 0x1c000015 }, + { 0x15800a2a, 0x1c000006 }, + { 0x15800a32, 0x1c000001 }, + { 0x15800a35, 0x1c000001 }, + { 0x15800a38, 0x1c000001 }, + { 0x15000a3c, 0x30000000 }, + { 0x15800a3e, 0x28000002 }, + { 0x15800a41, 0x30000001 }, + { 0x15800a47, 0x30000001 }, + { 0x15800a4b, 0x30000002 }, + { 0x15800a59, 0x1c000003 }, + { 0x15000a5e, 0x1c000000 }, + { 0x15800a66, 0x34000009 }, + { 0x15800a70, 0x30000001 }, + { 0x15800a72, 0x1c000002 }, + { 0x14800a81, 0x30000001 }, + { 0x14000a83, 0x28000000 }, + { 0x14800a85, 0x1c000008 }, + { 0x14800a8f, 0x1c000002 }, + { 0x14800a93, 0x1c000015 }, + { 0x14800aaa, 0x1c000006 }, + { 0x14800ab2, 0x1c000001 }, + { 0x14800ab5, 0x1c000004 }, + { 0x14000abc, 0x30000000 }, + { 0x14000abd, 0x1c000000 }, + { 0x14800abe, 0x28000002 }, + { 0x14800ac1, 0x30000004 }, + { 0x14800ac7, 0x30000001 }, + { 0x14000ac9, 0x28000000 }, + { 0x14800acb, 0x28000001 }, + { 0x14000acd, 0x30000000 }, + { 0x14000ad0, 0x1c000000 }, + { 0x14800ae0, 0x1c000001 }, + { 0x14800ae2, 0x30000001 }, + { 0x14800ae6, 0x34000009 }, + { 0x14000af1, 0x5c000000 }, + { 0x2b000b01, 0x30000000 }, + { 0x2b800b02, 0x28000001 }, + { 0x2b800b05, 0x1c000007 }, + { 0x2b800b0f, 0x1c000001 }, + { 0x2b800b13, 0x1c000015 }, + { 0x2b800b2a, 0x1c000006 }, + { 0x2b800b32, 0x1c000001 }, + { 0x2b800b35, 0x1c000004 }, + { 0x2b000b3c, 0x30000000 }, + { 0x2b000b3d, 0x1c000000 }, + { 0x2b000b3e, 0x28000000 }, + { 0x2b000b3f, 0x30000000 }, + { 0x2b000b40, 0x28000000 }, + { 0x2b800b41, 0x30000002 }, + { 0x2b800b47, 0x28000001 }, + { 0x2b800b4b, 0x28000001 }, + { 0x2b000b4d, 0x30000000 }, + { 0x2b000b56, 0x30000000 }, + { 0x2b000b57, 0x28000000 }, + { 0x2b800b5c, 0x1c000001 }, + { 0x2b800b5f, 0x1c000002 }, + { 0x2b800b66, 0x34000009 }, + { 0x2b000b70, 0x68000000 }, + { 0x2b000b71, 0x1c000000 }, + { 0x35000b82, 0x30000000 }, + { 0x35000b83, 0x1c000000 }, + { 0x35800b85, 0x1c000005 }, + { 0x35800b8e, 0x1c000002 }, + { 0x35800b92, 0x1c000003 }, + { 0x35800b99, 0x1c000001 }, + { 0x35000b9c, 0x1c000000 }, + { 0x35800b9e, 0x1c000001 }, + { 0x35800ba3, 0x1c000001 }, + { 0x35800ba8, 0x1c000002 }, + { 0x35800bae, 0x1c00000b }, + { 0x35800bbe, 0x28000001 }, + { 0x35000bc0, 0x30000000 }, + { 0x35800bc1, 0x28000001 }, + { 0x35800bc6, 0x28000002 }, + { 0x35800bca, 0x28000002 }, + { 0x35000bcd, 0x30000000 }, + { 0x35000bd7, 0x28000000 }, + { 0x35800be6, 0x34000009 }, + { 0x35800bf0, 0x3c000002 }, + { 0x35800bf3, 0x68000005 }, + { 0x35000bf9, 0x5c000000 }, + { 0x35000bfa, 0x68000000 }, + { 0x36800c01, 0x28000002 }, + { 0x36800c05, 0x1c000007 }, + { 0x36800c0e, 0x1c000002 }, + { 0x36800c12, 0x1c000016 }, + { 0x36800c2a, 0x1c000009 }, + { 0x36800c35, 0x1c000004 }, + { 0x36800c3e, 0x30000002 }, + { 0x36800c41, 0x28000003 }, + { 0x36800c46, 0x30000002 }, + { 0x36800c4a, 0x30000003 }, + { 0x36800c55, 0x30000001 }, + { 0x36800c60, 0x1c000001 }, + { 0x36800c66, 0x34000009 }, + { 0x1c800c82, 0x28000001 }, + { 0x1c800c85, 0x1c000007 }, + { 0x1c800c8e, 0x1c000002 }, + { 0x1c800c92, 0x1c000016 }, + { 0x1c800caa, 0x1c000009 }, + { 0x1c800cb5, 0x1c000004 }, + { 0x1c000cbc, 0x30000000 }, + { 0x1c000cbd, 0x1c000000 }, + { 0x1c000cbe, 0x28000000 }, + { 0x1c000cbf, 0x30000000 }, + { 0x1c800cc0, 0x28000004 }, + { 0x1c000cc6, 0x30000000 }, + { 0x1c800cc7, 0x28000001 }, + { 0x1c800cca, 0x28000001 }, + { 0x1c800ccc, 0x30000001 }, + { 0x1c800cd5, 0x28000001 }, + { 0x1c000cde, 0x1c000000 }, + { 0x1c800ce0, 0x1c000001 }, + { 0x1c800ce6, 0x34000009 }, + { 0x24800d02, 0x28000001 }, + { 0x24800d05, 0x1c000007 }, + { 0x24800d0e, 0x1c000002 }, + { 0x24800d12, 0x1c000016 }, + { 0x24800d2a, 0x1c00000f }, + { 0x24800d3e, 0x28000002 }, + { 0x24800d41, 0x30000002 }, + { 0x24800d46, 0x28000002 }, + { 0x24800d4a, 0x28000002 }, + { 0x24000d4d, 0x30000000 }, + { 0x24000d57, 0x28000000 }, + { 0x24800d60, 0x1c000001 }, + { 0x24800d66, 0x34000009 }, + { 0x2f800d82, 0x28000001 }, + { 0x2f800d85, 0x1c000011 }, + { 0x2f800d9a, 0x1c000017 }, + { 0x2f800db3, 0x1c000008 }, + { 0x2f000dbd, 0x1c000000 }, + { 0x2f800dc0, 0x1c000006 }, + { 0x2f000dca, 0x30000000 }, + { 0x2f800dcf, 0x28000002 }, + { 0x2f800dd2, 0x30000002 }, + { 0x2f000dd6, 0x30000000 }, + { 0x2f800dd8, 0x28000007 }, + { 0x2f800df2, 0x28000001 }, + { 0x2f000df4, 0x54000000 }, + { 0x38800e01, 0x1c00002f }, + { 0x38000e31, 0x30000000 }, + { 0x38800e32, 0x1c000001 }, + { 0x38800e34, 0x30000006 }, + { 0x09000e3f, 0x5c000000 }, + { 0x38800e40, 0x1c000005 }, + { 0x38000e46, 0x18000000 }, + { 0x38800e47, 0x30000007 }, + { 0x38000e4f, 0x54000000 }, + { 0x38800e50, 0x34000009 }, + { 0x38800e5a, 0x54000001 }, + { 0x20800e81, 0x1c000001 }, + { 0x20000e84, 0x1c000000 }, + { 0x20800e87, 0x1c000001 }, + { 0x20000e8a, 0x1c000000 }, + { 0x20000e8d, 0x1c000000 }, + { 0x20800e94, 0x1c000003 }, + { 0x20800e99, 0x1c000006 }, + { 0x20800ea1, 0x1c000002 }, + { 0x20000ea5, 0x1c000000 }, + { 0x20000ea7, 0x1c000000 }, + { 0x20800eaa, 0x1c000001 }, + { 0x20800ead, 0x1c000003 }, + { 0x20000eb1, 0x30000000 }, + { 0x20800eb2, 0x1c000001 }, + { 0x20800eb4, 0x30000005 }, + { 0x20800ebb, 0x30000001 }, + { 0x20000ebd, 0x1c000000 }, + { 0x20800ec0, 0x1c000004 }, + { 0x20000ec6, 0x18000000 }, + { 0x20800ec8, 0x30000005 }, + { 0x20800ed0, 0x34000009 }, + { 0x20800edc, 0x1c000001 }, + { 0x39000f00, 0x1c000000 }, + { 0x39800f01, 0x68000002 }, + { 0x39800f04, 0x5400000e }, + { 0x39800f13, 0x68000004 }, + { 0x39800f18, 0x30000001 }, + { 0x39800f1a, 0x68000005 }, + { 0x39800f20, 0x34000009 }, + { 0x39800f2a, 0x3c000009 }, + { 0x39000f34, 0x68000000 }, + { 0x39000f35, 0x30000000 }, + { 0x39000f36, 0x68000000 }, + { 0x39000f37, 0x30000000 }, + { 0x39000f38, 0x68000000 }, + { 0x39000f39, 0x30000000 }, + { 0x39000f3a, 0x58000000 }, + { 0x39000f3b, 0x48000000 }, + { 0x39000f3c, 0x58000000 }, + { 0x39000f3d, 0x48000000 }, + { 0x39800f3e, 0x28000001 }, + { 0x39800f40, 0x1c000007 }, + { 0x39800f49, 0x1c000021 }, + { 0x39800f71, 0x3000000d }, + { 0x39000f7f, 0x28000000 }, + { 0x39800f80, 0x30000004 }, + { 0x39000f85, 0x54000000 }, + { 0x39800f86, 0x30000001 }, + { 0x39800f88, 0x1c000003 }, + { 0x39800f90, 0x30000007 }, + { 0x39800f99, 0x30000023 }, + { 0x39800fbe, 0x68000007 }, + { 0x39000fc6, 0x30000000 }, + { 0x39800fc7, 0x68000005 }, + { 0x39000fcf, 0x68000000 }, + { 0x39800fd0, 0x54000001 }, + { 0x26801000, 0x1c000021 }, + { 0x26801023, 0x1c000004 }, + { 0x26801029, 0x1c000001 }, + { 0x2600102c, 0x28000000 }, + { 0x2680102d, 0x30000003 }, + { 0x26001031, 0x28000000 }, + { 0x26001032, 0x30000000 }, + { 0x26801036, 0x30000001 }, + { 0x26001038, 0x28000000 }, + { 0x26001039, 0x30000000 }, + { 0x26801040, 0x34000009 }, + { 0x2680104a, 0x54000005 }, + { 0x26801050, 0x1c000005 }, + { 0x26801056, 0x28000001 }, + { 0x26801058, 0x30000001 }, + { 0x100010a0, 0x24001c60 }, + { 0x100010a1, 0x24001c60 }, + { 0x100010a2, 0x24001c60 }, + { 0x100010a3, 0x24001c60 }, + { 0x100010a4, 0x24001c60 }, + { 0x100010a5, 0x24001c60 }, + { 0x100010a6, 0x24001c60 }, + { 0x100010a7, 0x24001c60 }, + { 0x100010a8, 0x24001c60 }, + { 0x100010a9, 0x24001c60 }, + { 0x100010aa, 0x24001c60 }, + { 0x100010ab, 0x24001c60 }, + { 0x100010ac, 0x24001c60 }, + { 0x100010ad, 0x24001c60 }, + { 0x100010ae, 0x24001c60 }, + { 0x100010af, 0x24001c60 }, + { 0x100010b0, 0x24001c60 }, + { 0x100010b1, 0x24001c60 }, + { 0x100010b2, 0x24001c60 }, + { 0x100010b3, 0x24001c60 }, + { 0x100010b4, 0x24001c60 }, + { 0x100010b5, 0x24001c60 }, + { 0x100010b6, 0x24001c60 }, + { 0x100010b7, 0x24001c60 }, + { 0x100010b8, 0x24001c60 }, + { 0x100010b9, 0x24001c60 }, + { 0x100010ba, 0x24001c60 }, + { 0x100010bb, 0x24001c60 }, + { 0x100010bc, 0x24001c60 }, + { 0x100010bd, 0x24001c60 }, + { 0x100010be, 0x24001c60 }, + { 0x100010bf, 0x24001c60 }, + { 0x100010c0, 0x24001c60 }, + { 0x100010c1, 0x24001c60 }, + { 0x100010c2, 0x24001c60 }, + { 0x100010c3, 0x24001c60 }, + { 0x100010c4, 0x24001c60 }, + { 0x100010c5, 0x24001c60 }, + { 0x108010d0, 0x1c00002a }, + { 0x090010fb, 0x54000000 }, + { 0x100010fc, 0x18000000 }, + { 0x17801100, 0x1c000059 }, + { 0x1780115f, 0x1c000043 }, + { 0x178011a8, 0x1c000051 }, + { 0x0f801200, 0x1c000048 }, + { 0x0f80124a, 0x1c000003 }, + { 0x0f801250, 0x1c000006 }, + { 0x0f001258, 0x1c000000 }, + { 0x0f80125a, 0x1c000003 }, + { 0x0f801260, 0x1c000028 }, + { 0x0f80128a, 0x1c000003 }, + { 0x0f801290, 0x1c000020 }, + { 0x0f8012b2, 0x1c000003 }, + { 0x0f8012b8, 0x1c000006 }, + { 0x0f0012c0, 0x1c000000 }, + { 0x0f8012c2, 0x1c000003 }, + { 0x0f8012c8, 0x1c00000e }, + { 0x0f8012d8, 0x1c000038 }, + { 0x0f801312, 0x1c000003 }, + { 0x0f801318, 0x1c000042 }, + { 0x0f00135f, 0x30000000 }, + { 0x0f001360, 0x68000000 }, + { 0x0f801361, 0x54000007 }, + { 0x0f801369, 0x3c000013 }, + { 0x0f801380, 0x1c00000f }, + { 0x0f801390, 0x68000009 }, + { 0x088013a0, 0x1c000054 }, + { 0x07801401, 0x1c00026b }, + { 0x0780166d, 0x54000001 }, + { 0x0780166f, 0x1c000007 }, + { 0x28001680, 0x74000000 }, + { 0x28801681, 0x1c000019 }, + { 0x2800169b, 0x58000000 }, + { 0x2800169c, 0x48000000 }, + { 0x2d8016a0, 0x1c00004a }, + { 0x098016eb, 0x54000002 }, + { 0x2d8016ee, 0x38000002 }, + { 0x32801700, 0x1c00000c }, + { 0x3280170e, 0x1c000003 }, + { 0x32801712, 0x30000002 }, + { 0x18801720, 0x1c000011 }, + { 0x18801732, 0x30000002 }, + { 0x09801735, 0x54000001 }, + { 0x06801740, 0x1c000011 }, + { 0x06801752, 0x30000001 }, + { 0x33801760, 0x1c00000c }, + { 0x3380176e, 0x1c000002 }, + { 0x33801772, 0x30000001 }, + { 0x1f801780, 0x1c000033 }, + { 0x1f8017b4, 0x04000001 }, + { 0x1f0017b6, 0x28000000 }, + { 0x1f8017b7, 0x30000006 }, + { 0x1f8017be, 0x28000007 }, + { 0x1f0017c6, 0x30000000 }, + { 0x1f8017c7, 0x28000001 }, + { 0x1f8017c9, 0x3000000a }, + { 0x1f8017d4, 0x54000002 }, + { 0x1f0017d7, 0x18000000 }, + { 0x1f8017d8, 0x54000002 }, + { 0x1f0017db, 0x5c000000 }, + { 0x1f0017dc, 0x1c000000 }, + { 0x1f0017dd, 0x30000000 }, + { 0x1f8017e0, 0x34000009 }, + { 0x1f8017f0, 0x3c000009 }, + { 0x25801800, 0x54000005 }, + { 0x25001806, 0x44000000 }, + { 0x25801807, 0x54000003 }, + { 0x2580180b, 0x30000002 }, + { 0x2500180e, 0x74000000 }, + { 0x25801810, 0x34000009 }, + { 0x25801820, 0x1c000022 }, + { 0x25001843, 0x18000000 }, + { 0x25801844, 0x1c000033 }, + { 0x25801880, 0x1c000028 }, + { 0x250018a9, 0x30000000 }, + { 0x22801900, 0x1c00001c }, + { 0x22801920, 0x30000002 }, + { 0x22801923, 0x28000003 }, + { 0x22801927, 0x30000001 }, + { 0x22801929, 0x28000002 }, + { 0x22801930, 0x28000001 }, + { 0x22001932, 0x30000000 }, + { 0x22801933, 0x28000005 }, + { 0x22801939, 0x30000002 }, + { 0x22001940, 0x68000000 }, + { 0x22801944, 0x54000001 }, + { 0x22801946, 0x34000009 }, + { 0x34801950, 0x1c00001d }, + { 0x34801970, 0x1c000004 }, + { 0x27801980, 0x1c000029 }, + { 0x278019b0, 0x28000010 }, + { 0x278019c1, 0x1c000006 }, + { 0x278019c8, 0x28000001 }, + { 0x278019d0, 0x34000009 }, + { 0x278019de, 0x54000001 }, + { 0x1f8019e0, 0x6800001f }, + { 0x05801a00, 0x1c000016 }, + { 0x05801a17, 0x30000001 }, + { 0x05801a19, 0x28000002 }, + { 0x05801a1e, 0x54000001 }, + { 0x21801d00, 0x1400002b }, + { 0x21801d2c, 0x18000035 }, + { 0x21801d62, 0x14000015 }, + { 0x0c001d78, 0x18000000 }, + { 0x21801d79, 0x14000021 }, + { 0x21801d9b, 0x18000024 }, + { 0x1b801dc0, 0x30000003 }, + { 0x21001e00, 0x24000001 }, + { 0x21001e01, 0x1400ffff }, + { 0x21001e02, 0x24000001 }, + { 0x21001e03, 0x1400ffff }, + { 0x21001e04, 0x24000001 }, + { 0x21001e05, 0x1400ffff }, + { 0x21001e06, 0x24000001 }, + { 0x21001e07, 0x1400ffff }, + { 0x21001e08, 0x24000001 }, + { 0x21001e09, 0x1400ffff }, + { 0x21001e0a, 0x24000001 }, + { 0x21001e0b, 0x1400ffff }, + { 0x21001e0c, 0x24000001 }, + { 0x21001e0d, 0x1400ffff }, + { 0x21001e0e, 0x24000001 }, + { 0x21001e0f, 0x1400ffff }, + { 0x21001e10, 0x24000001 }, + { 0x21001e11, 0x1400ffff }, + { 0x21001e12, 0x24000001 }, + { 0x21001e13, 0x1400ffff }, + { 0x21001e14, 0x24000001 }, + { 0x21001e15, 0x1400ffff }, + { 0x21001e16, 0x24000001 }, + { 0x21001e17, 0x1400ffff }, + { 0x21001e18, 0x24000001 }, + { 0x21001e19, 0x1400ffff }, + { 0x21001e1a, 0x24000001 }, + { 0x21001e1b, 0x1400ffff }, + { 0x21001e1c, 0x24000001 }, + { 0x21001e1d, 0x1400ffff }, + { 0x21001e1e, 0x24000001 }, + { 0x21001e1f, 0x1400ffff }, + { 0x21001e20, 0x24000001 }, + { 0x21001e21, 0x1400ffff }, + { 0x21001e22, 0x24000001 }, + { 0x21001e23, 0x1400ffff }, + { 0x21001e24, 0x24000001 }, + { 0x21001e25, 0x1400ffff }, + { 0x21001e26, 0x24000001 }, + { 0x21001e27, 0x1400ffff }, + { 0x21001e28, 0x24000001 }, + { 0x21001e29, 0x1400ffff }, + { 0x21001e2a, 0x24000001 }, + { 0x21001e2b, 0x1400ffff }, + { 0x21001e2c, 0x24000001 }, + { 0x21001e2d, 0x1400ffff }, + { 0x21001e2e, 0x24000001 }, + { 0x21001e2f, 0x1400ffff }, + { 0x21001e30, 0x24000001 }, + { 0x21001e31, 0x1400ffff }, + { 0x21001e32, 0x24000001 }, + { 0x21001e33, 0x1400ffff }, + { 0x21001e34, 0x24000001 }, + { 0x21001e35, 0x1400ffff }, + { 0x21001e36, 0x24000001 }, + { 0x21001e37, 0x1400ffff }, + { 0x21001e38, 0x24000001 }, + { 0x21001e39, 0x1400ffff }, + { 0x21001e3a, 0x24000001 }, + { 0x21001e3b, 0x1400ffff }, + { 0x21001e3c, 0x24000001 }, + { 0x21001e3d, 0x1400ffff }, + { 0x21001e3e, 0x24000001 }, + { 0x21001e3f, 0x1400ffff }, + { 0x21001e40, 0x24000001 }, + { 0x21001e41, 0x1400ffff }, + { 0x21001e42, 0x24000001 }, + { 0x21001e43, 0x1400ffff }, + { 0x21001e44, 0x24000001 }, + { 0x21001e45, 0x1400ffff }, + { 0x21001e46, 0x24000001 }, + { 0x21001e47, 0x1400ffff }, + { 0x21001e48, 0x24000001 }, + { 0x21001e49, 0x1400ffff }, + { 0x21001e4a, 0x24000001 }, + { 0x21001e4b, 0x1400ffff }, + { 0x21001e4c, 0x24000001 }, + { 0x21001e4d, 0x1400ffff }, + { 0x21001e4e, 0x24000001 }, + { 0x21001e4f, 0x1400ffff }, + { 0x21001e50, 0x24000001 }, + { 0x21001e51, 0x1400ffff }, + { 0x21001e52, 0x24000001 }, + { 0x21001e53, 0x1400ffff }, + { 0x21001e54, 0x24000001 }, + { 0x21001e55, 0x1400ffff }, + { 0x21001e56, 0x24000001 }, + { 0x21001e57, 0x1400ffff }, + { 0x21001e58, 0x24000001 }, + { 0x21001e59, 0x1400ffff }, + { 0x21001e5a, 0x24000001 }, + { 0x21001e5b, 0x1400ffff }, + { 0x21001e5c, 0x24000001 }, + { 0x21001e5d, 0x1400ffff }, + { 0x21001e5e, 0x24000001 }, + { 0x21001e5f, 0x1400ffff }, + { 0x21001e60, 0x24000001 }, + { 0x21001e61, 0x1400ffff }, + { 0x21001e62, 0x24000001 }, + { 0x21001e63, 0x1400ffff }, + { 0x21001e64, 0x24000001 }, + { 0x21001e65, 0x1400ffff }, + { 0x21001e66, 0x24000001 }, + { 0x21001e67, 0x1400ffff }, + { 0x21001e68, 0x24000001 }, + { 0x21001e69, 0x1400ffff }, + { 0x21001e6a, 0x24000001 }, + { 0x21001e6b, 0x1400ffff }, + { 0x21001e6c, 0x24000001 }, + { 0x21001e6d, 0x1400ffff }, + { 0x21001e6e, 0x24000001 }, + { 0x21001e6f, 0x1400ffff }, + { 0x21001e70, 0x24000001 }, + { 0x21001e71, 0x1400ffff }, + { 0x21001e72, 0x24000001 }, + { 0x21001e73, 0x1400ffff }, + { 0x21001e74, 0x24000001 }, + { 0x21001e75, 0x1400ffff }, + { 0x21001e76, 0x24000001 }, + { 0x21001e77, 0x1400ffff }, + { 0x21001e78, 0x24000001 }, + { 0x21001e79, 0x1400ffff }, + { 0x21001e7a, 0x24000001 }, + { 0x21001e7b, 0x1400ffff }, + { 0x21001e7c, 0x24000001 }, + { 0x21001e7d, 0x1400ffff }, + { 0x21001e7e, 0x24000001 }, + { 0x21001e7f, 0x1400ffff }, + { 0x21001e80, 0x24000001 }, + { 0x21001e81, 0x1400ffff }, + { 0x21001e82, 0x24000001 }, + { 0x21001e83, 0x1400ffff }, + { 0x21001e84, 0x24000001 }, + { 0x21001e85, 0x1400ffff }, + { 0x21001e86, 0x24000001 }, + { 0x21001e87, 0x1400ffff }, + { 0x21001e88, 0x24000001 }, + { 0x21001e89, 0x1400ffff }, + { 0x21001e8a, 0x24000001 }, + { 0x21001e8b, 0x1400ffff }, + { 0x21001e8c, 0x24000001 }, + { 0x21001e8d, 0x1400ffff }, + { 0x21001e8e, 0x24000001 }, + { 0x21001e8f, 0x1400ffff }, + { 0x21001e90, 0x24000001 }, + { 0x21001e91, 0x1400ffff }, + { 0x21001e92, 0x24000001 }, + { 0x21001e93, 0x1400ffff }, + { 0x21001e94, 0x24000001 }, + { 0x21001e95, 0x1400ffff }, + { 0x21801e96, 0x14000004 }, + { 0x21001e9b, 0x1400ffc5 }, + { 0x21001ea0, 0x24000001 }, + { 0x21001ea1, 0x1400ffff }, + { 0x21001ea2, 0x24000001 }, + { 0x21001ea3, 0x1400ffff }, + { 0x21001ea4, 0x24000001 }, + { 0x21001ea5, 0x1400ffff }, + { 0x21001ea6, 0x24000001 }, + { 0x21001ea7, 0x1400ffff }, + { 0x21001ea8, 0x24000001 }, + { 0x21001ea9, 0x1400ffff }, + { 0x21001eaa, 0x24000001 }, + { 0x21001eab, 0x1400ffff }, + { 0x21001eac, 0x24000001 }, + { 0x21001ead, 0x1400ffff }, + { 0x21001eae, 0x24000001 }, + { 0x21001eaf, 0x1400ffff }, + { 0x21001eb0, 0x24000001 }, + { 0x21001eb1, 0x1400ffff }, + { 0x21001eb2, 0x24000001 }, + { 0x21001eb3, 0x1400ffff }, + { 0x21001eb4, 0x24000001 }, + { 0x21001eb5, 0x1400ffff }, + { 0x21001eb6, 0x24000001 }, + { 0x21001eb7, 0x1400ffff }, + { 0x21001eb8, 0x24000001 }, + { 0x21001eb9, 0x1400ffff }, + { 0x21001eba, 0x24000001 }, + { 0x21001ebb, 0x1400ffff }, + { 0x21001ebc, 0x24000001 }, + { 0x21001ebd, 0x1400ffff }, + { 0x21001ebe, 0x24000001 }, + { 0x21001ebf, 0x1400ffff }, + { 0x21001ec0, 0x24000001 }, + { 0x21001ec1, 0x1400ffff }, + { 0x21001ec2, 0x24000001 }, + { 0x21001ec3, 0x1400ffff }, + { 0x21001ec4, 0x24000001 }, + { 0x21001ec5, 0x1400ffff }, + { 0x21001ec6, 0x24000001 }, + { 0x21001ec7, 0x1400ffff }, + { 0x21001ec8, 0x24000001 }, + { 0x21001ec9, 0x1400ffff }, + { 0x21001eca, 0x24000001 }, + { 0x21001ecb, 0x1400ffff }, + { 0x21001ecc, 0x24000001 }, + { 0x21001ecd, 0x1400ffff }, + { 0x21001ece, 0x24000001 }, + { 0x21001ecf, 0x1400ffff }, + { 0x21001ed0, 0x24000001 }, + { 0x21001ed1, 0x1400ffff }, + { 0x21001ed2, 0x24000001 }, + { 0x21001ed3, 0x1400ffff }, + { 0x21001ed4, 0x24000001 }, + { 0x21001ed5, 0x1400ffff }, + { 0x21001ed6, 0x24000001 }, + { 0x21001ed7, 0x1400ffff }, + { 0x21001ed8, 0x24000001 }, + { 0x21001ed9, 0x1400ffff }, + { 0x21001eda, 0x24000001 }, + { 0x21001edb, 0x1400ffff }, + { 0x21001edc, 0x24000001 }, + { 0x21001edd, 0x1400ffff }, + { 0x21001ede, 0x24000001 }, + { 0x21001edf, 0x1400ffff }, + { 0x21001ee0, 0x24000001 }, + { 0x21001ee1, 0x1400ffff }, + { 0x21001ee2, 0x24000001 }, + { 0x21001ee3, 0x1400ffff }, + { 0x21001ee4, 0x24000001 }, + { 0x21001ee5, 0x1400ffff }, + { 0x21001ee6, 0x24000001 }, + { 0x21001ee7, 0x1400ffff }, + { 0x21001ee8, 0x24000001 }, + { 0x21001ee9, 0x1400ffff }, + { 0x21001eea, 0x24000001 }, + { 0x21001eeb, 0x1400ffff }, + { 0x21001eec, 0x24000001 }, + { 0x21001eed, 0x1400ffff }, + { 0x21001eee, 0x24000001 }, + { 0x21001eef, 0x1400ffff }, + { 0x21001ef0, 0x24000001 }, + { 0x21001ef1, 0x1400ffff }, + { 0x21001ef2, 0x24000001 }, + { 0x21001ef3, 0x1400ffff }, + { 0x21001ef4, 0x24000001 }, + { 0x21001ef5, 0x1400ffff }, + { 0x21001ef6, 0x24000001 }, + { 0x21001ef7, 0x1400ffff }, + { 0x21001ef8, 0x24000001 }, + { 0x21001ef9, 0x1400ffff }, + { 0x13001f00, 0x14000008 }, + { 0x13001f01, 0x14000008 }, + { 0x13001f02, 0x14000008 }, + { 0x13001f03, 0x14000008 }, + { 0x13001f04, 0x14000008 }, + { 0x13001f05, 0x14000008 }, + { 0x13001f06, 0x14000008 }, + { 0x13001f07, 0x14000008 }, + { 0x13001f08, 0x2400fff8 }, + { 0x13001f09, 0x2400fff8 }, + { 0x13001f0a, 0x2400fff8 }, + { 0x13001f0b, 0x2400fff8 }, + { 0x13001f0c, 0x2400fff8 }, + { 0x13001f0d, 0x2400fff8 }, + { 0x13001f0e, 0x2400fff8 }, + { 0x13001f0f, 0x2400fff8 }, + { 0x13001f10, 0x14000008 }, + { 0x13001f11, 0x14000008 }, + { 0x13001f12, 0x14000008 }, + { 0x13001f13, 0x14000008 }, + { 0x13001f14, 0x14000008 }, + { 0x13001f15, 0x14000008 }, + { 0x13001f18, 0x2400fff8 }, + { 0x13001f19, 0x2400fff8 }, + { 0x13001f1a, 0x2400fff8 }, + { 0x13001f1b, 0x2400fff8 }, + { 0x13001f1c, 0x2400fff8 }, + { 0x13001f1d, 0x2400fff8 }, + { 0x13001f20, 0x14000008 }, + { 0x13001f21, 0x14000008 }, + { 0x13001f22, 0x14000008 }, + { 0x13001f23, 0x14000008 }, + { 0x13001f24, 0x14000008 }, + { 0x13001f25, 0x14000008 }, + { 0x13001f26, 0x14000008 }, + { 0x13001f27, 0x14000008 }, + { 0x13001f28, 0x2400fff8 }, + { 0x13001f29, 0x2400fff8 }, + { 0x13001f2a, 0x2400fff8 }, + { 0x13001f2b, 0x2400fff8 }, + { 0x13001f2c, 0x2400fff8 }, + { 0x13001f2d, 0x2400fff8 }, + { 0x13001f2e, 0x2400fff8 }, + { 0x13001f2f, 0x2400fff8 }, + { 0x13001f30, 0x14000008 }, + { 0x13001f31, 0x14000008 }, + { 0x13001f32, 0x14000008 }, + { 0x13001f33, 0x14000008 }, + { 0x13001f34, 0x14000008 }, + { 0x13001f35, 0x14000008 }, + { 0x13001f36, 0x14000008 }, + { 0x13001f37, 0x14000008 }, + { 0x13001f38, 0x2400fff8 }, + { 0x13001f39, 0x2400fff8 }, + { 0x13001f3a, 0x2400fff8 }, + { 0x13001f3b, 0x2400fff8 }, + { 0x13001f3c, 0x2400fff8 }, + { 0x13001f3d, 0x2400fff8 }, + { 0x13001f3e, 0x2400fff8 }, + { 0x13001f3f, 0x2400fff8 }, + { 0x13001f40, 0x14000008 }, + { 0x13001f41, 0x14000008 }, + { 0x13001f42, 0x14000008 }, + { 0x13001f43, 0x14000008 }, + { 0x13001f44, 0x14000008 }, + { 0x13001f45, 0x14000008 }, + { 0x13001f48, 0x2400fff8 }, + { 0x13001f49, 0x2400fff8 }, + { 0x13001f4a, 0x2400fff8 }, + { 0x13001f4b, 0x2400fff8 }, + { 0x13001f4c, 0x2400fff8 }, + { 0x13001f4d, 0x2400fff8 }, + { 0x13001f50, 0x14000000 }, + { 0x13001f51, 0x14000008 }, + { 0x13001f52, 0x14000000 }, + { 0x13001f53, 0x14000008 }, + { 0x13001f54, 0x14000000 }, + { 0x13001f55, 0x14000008 }, + { 0x13001f56, 0x14000000 }, + { 0x13001f57, 0x14000008 }, + { 0x13001f59, 0x2400fff8 }, + { 0x13001f5b, 0x2400fff8 }, + { 0x13001f5d, 0x2400fff8 }, + { 0x13001f5f, 0x2400fff8 }, + { 0x13001f60, 0x14000008 }, + { 0x13001f61, 0x14000008 }, + { 0x13001f62, 0x14000008 }, + { 0x13001f63, 0x14000008 }, + { 0x13001f64, 0x14000008 }, + { 0x13001f65, 0x14000008 }, + { 0x13001f66, 0x14000008 }, + { 0x13001f67, 0x14000008 }, + { 0x13001f68, 0x2400fff8 }, + { 0x13001f69, 0x2400fff8 }, + { 0x13001f6a, 0x2400fff8 }, + { 0x13001f6b, 0x2400fff8 }, + { 0x13001f6c, 0x2400fff8 }, + { 0x13001f6d, 0x2400fff8 }, + { 0x13001f6e, 0x2400fff8 }, + { 0x13001f6f, 0x2400fff8 }, + { 0x13001f70, 0x1400004a }, + { 0x13001f71, 0x1400004a }, + { 0x13001f72, 0x14000056 }, + { 0x13001f73, 0x14000056 }, + { 0x13001f74, 0x14000056 }, + { 0x13001f75, 0x14000056 }, + { 0x13001f76, 0x14000064 }, + { 0x13001f77, 0x14000064 }, + { 0x13001f78, 0x14000080 }, + { 0x13001f79, 0x14000080 }, + { 0x13001f7a, 0x14000070 }, + { 0x13001f7b, 0x14000070 }, + { 0x13001f7c, 0x1400007e }, + { 0x13001f7d, 0x1400007e }, + { 0x13001f80, 0x14000008 }, + { 0x13001f81, 0x14000008 }, + { 0x13001f82, 0x14000008 }, + { 0x13001f83, 0x14000008 }, + { 0x13001f84, 0x14000008 }, + { 0x13001f85, 0x14000008 }, + { 0x13001f86, 0x14000008 }, + { 0x13001f87, 0x14000008 }, + { 0x13001f88, 0x2000fff8 }, + { 0x13001f89, 0x2000fff8 }, + { 0x13001f8a, 0x2000fff8 }, + { 0x13001f8b, 0x2000fff8 }, + { 0x13001f8c, 0x2000fff8 }, + { 0x13001f8d, 0x2000fff8 }, + { 0x13001f8e, 0x2000fff8 }, + { 0x13001f8f, 0x2000fff8 }, + { 0x13001f90, 0x14000008 }, + { 0x13001f91, 0x14000008 }, + { 0x13001f92, 0x14000008 }, + { 0x13001f93, 0x14000008 }, + { 0x13001f94, 0x14000008 }, + { 0x13001f95, 0x14000008 }, + { 0x13001f96, 0x14000008 }, + { 0x13001f97, 0x14000008 }, + { 0x13001f98, 0x2000fff8 }, + { 0x13001f99, 0x2000fff8 }, + { 0x13001f9a, 0x2000fff8 }, + { 0x13001f9b, 0x2000fff8 }, + { 0x13001f9c, 0x2000fff8 }, + { 0x13001f9d, 0x2000fff8 }, + { 0x13001f9e, 0x2000fff8 }, + { 0x13001f9f, 0x2000fff8 }, + { 0x13001fa0, 0x14000008 }, + { 0x13001fa1, 0x14000008 }, + { 0x13001fa2, 0x14000008 }, + { 0x13001fa3, 0x14000008 }, + { 0x13001fa4, 0x14000008 }, + { 0x13001fa5, 0x14000008 }, + { 0x13001fa6, 0x14000008 }, + { 0x13001fa7, 0x14000008 }, + { 0x13001fa8, 0x2000fff8 }, + { 0x13001fa9, 0x2000fff8 }, + { 0x13001faa, 0x2000fff8 }, + { 0x13001fab, 0x2000fff8 }, + { 0x13001fac, 0x2000fff8 }, + { 0x13001fad, 0x2000fff8 }, + { 0x13001fae, 0x2000fff8 }, + { 0x13001faf, 0x2000fff8 }, + { 0x13001fb0, 0x14000008 }, + { 0x13001fb1, 0x14000008 }, + { 0x13001fb2, 0x14000000 }, + { 0x13001fb3, 0x14000009 }, + { 0x13001fb4, 0x14000000 }, + { 0x13801fb6, 0x14000001 }, + { 0x13001fb8, 0x2400fff8 }, + { 0x13001fb9, 0x2400fff8 }, + { 0x13001fba, 0x2400ffb6 }, + { 0x13001fbb, 0x2400ffb6 }, + { 0x13001fbc, 0x2000fff7 }, + { 0x13001fbd, 0x60000000 }, + { 0x13001fbe, 0x1400e3db }, + { 0x13801fbf, 0x60000002 }, + { 0x13001fc2, 0x14000000 }, + { 0x13001fc3, 0x14000009 }, + { 0x13001fc4, 0x14000000 }, + { 0x13801fc6, 0x14000001 }, + { 0x13001fc8, 0x2400ffaa }, + { 0x13001fc9, 0x2400ffaa }, + { 0x13001fca, 0x2400ffaa }, + { 0x13001fcb, 0x2400ffaa }, + { 0x13001fcc, 0x2000fff7 }, + { 0x13801fcd, 0x60000002 }, + { 0x13001fd0, 0x14000008 }, + { 0x13001fd1, 0x14000008 }, + { 0x13801fd2, 0x14000001 }, + { 0x13801fd6, 0x14000001 }, + { 0x13001fd8, 0x2400fff8 }, + { 0x13001fd9, 0x2400fff8 }, + { 0x13001fda, 0x2400ff9c }, + { 0x13001fdb, 0x2400ff9c }, + { 0x13801fdd, 0x60000002 }, + { 0x13001fe0, 0x14000008 }, + { 0x13001fe1, 0x14000008 }, + { 0x13801fe2, 0x14000002 }, + { 0x13001fe5, 0x14000007 }, + { 0x13801fe6, 0x14000001 }, + { 0x13001fe8, 0x2400fff8 }, + { 0x13001fe9, 0x2400fff8 }, + { 0x13001fea, 0x2400ff90 }, + { 0x13001feb, 0x2400ff90 }, + { 0x13001fec, 0x2400fff9 }, + { 0x13801fed, 0x60000002 }, + { 0x13001ff2, 0x14000000 }, + { 0x13001ff3, 0x14000009 }, + { 0x13001ff4, 0x14000000 }, + { 0x13801ff6, 0x14000001 }, + { 0x13001ff8, 0x2400ff80 }, + { 0x13001ff9, 0x2400ff80 }, + { 0x13001ffa, 0x2400ff82 }, + { 0x13001ffb, 0x2400ff82 }, + { 0x13001ffc, 0x2000fff7 }, + { 0x13801ffd, 0x60000001 }, + { 0x09802000, 0x7400000a }, + { 0x0980200b, 0x04000004 }, + { 0x09802010, 0x44000005 }, + { 0x09802016, 0x54000001 }, + { 0x09002018, 0x50000000 }, + { 0x09002019, 0x4c000000 }, + { 0x0900201a, 0x58000000 }, + { 0x0980201b, 0x50000001 }, + { 0x0900201d, 0x4c000000 }, + { 0x0900201e, 0x58000000 }, + { 0x0900201f, 0x50000000 }, + { 0x09802020, 0x54000007 }, + { 0x09002028, 0x6c000000 }, + { 0x09002029, 0x70000000 }, + { 0x0980202a, 0x04000004 }, + { 0x0900202f, 0x74000000 }, + { 0x09802030, 0x54000008 }, + { 0x09002039, 0x50000000 }, + { 0x0900203a, 0x4c000000 }, + { 0x0980203b, 0x54000003 }, + { 0x0980203f, 0x40000001 }, + { 0x09802041, 0x54000002 }, + { 0x09002044, 0x64000000 }, + { 0x09002045, 0x58000000 }, + { 0x09002046, 0x48000000 }, + { 0x09802047, 0x5400000a }, + { 0x09002052, 0x64000000 }, + { 0x09002053, 0x54000000 }, + { 0x09002054, 0x40000000 }, + { 0x09802055, 0x54000009 }, + { 0x0900205f, 0x74000000 }, + { 0x09802060, 0x04000003 }, + { 0x0980206a, 0x04000005 }, + { 0x09002070, 0x3c000000 }, + { 0x21002071, 0x14000000 }, + { 0x09802074, 0x3c000005 }, + { 0x0980207a, 0x64000002 }, + { 0x0900207d, 0x58000000 }, + { 0x0900207e, 0x48000000 }, + { 0x2100207f, 0x14000000 }, + { 0x09802080, 0x3c000009 }, + { 0x0980208a, 0x64000002 }, + { 0x0900208d, 0x58000000 }, + { 0x0900208e, 0x48000000 }, + { 0x21802090, 0x18000004 }, + { 0x098020a0, 0x5c000015 }, + { 0x1b8020d0, 0x3000000c }, + { 0x1b8020dd, 0x2c000003 }, + { 0x1b0020e1, 0x30000000 }, + { 0x1b8020e2, 0x2c000002 }, + { 0x1b8020e5, 0x30000006 }, + { 0x09802100, 0x68000001 }, + { 0x09002102, 0x24000000 }, + { 0x09802103, 0x68000003 }, + { 0x09002107, 0x24000000 }, + { 0x09802108, 0x68000001 }, + { 0x0900210a, 0x14000000 }, + { 0x0980210b, 0x24000002 }, + { 0x0980210e, 0x14000001 }, + { 0x09802110, 0x24000002 }, + { 0x09002113, 0x14000000 }, + { 0x09002114, 0x68000000 }, + { 0x09002115, 0x24000000 }, + { 0x09802116, 0x68000002 }, + { 0x09802119, 0x24000004 }, + { 0x0980211e, 0x68000005 }, + { 0x09002124, 0x24000000 }, + { 0x09002125, 0x68000000 }, + { 0x13002126, 0x2400e2a3 }, + { 0x09002127, 0x68000000 }, + { 0x09002128, 0x24000000 }, + { 0x09002129, 0x68000000 }, + { 0x2100212a, 0x2400df41 }, + { 0x2100212b, 0x2400dfba }, + { 0x0980212c, 0x24000001 }, + { 0x0900212e, 0x68000000 }, + { 0x0900212f, 0x14000000 }, + { 0x09802130, 0x24000001 }, + { 0x09002132, 0x68000000 }, + { 0x09002133, 0x24000000 }, + { 0x09002134, 0x14000000 }, + { 0x09802135, 0x1c000003 }, + { 0x09002139, 0x14000000 }, + { 0x0980213a, 0x68000001 }, + { 0x0980213c, 0x14000001 }, + { 0x0980213e, 0x24000001 }, + { 0x09802140, 0x64000004 }, + { 0x09002145, 0x24000000 }, + { 0x09802146, 0x14000003 }, + { 0x0900214a, 0x68000000 }, + { 0x0900214b, 0x64000000 }, + { 0x0900214c, 0x68000000 }, + { 0x09802153, 0x3c00000c }, + { 0x09002160, 0x38000010 }, + { 0x09002161, 0x38000010 }, + { 0x09002162, 0x38000010 }, + { 0x09002163, 0x38000010 }, + { 0x09002164, 0x38000010 }, + { 0x09002165, 0x38000010 }, + { 0x09002166, 0x38000010 }, + { 0x09002167, 0x38000010 }, + { 0x09002168, 0x38000010 }, + { 0x09002169, 0x38000010 }, + { 0x0900216a, 0x38000010 }, + { 0x0900216b, 0x38000010 }, + { 0x0900216c, 0x38000010 }, + { 0x0900216d, 0x38000010 }, + { 0x0900216e, 0x38000010 }, + { 0x0900216f, 0x38000010 }, + { 0x09002170, 0x3800fff0 }, + { 0x09002171, 0x3800fff0 }, + { 0x09002172, 0x3800fff0 }, + { 0x09002173, 0x3800fff0 }, + { 0x09002174, 0x3800fff0 }, + { 0x09002175, 0x3800fff0 }, + { 0x09002176, 0x3800fff0 }, + { 0x09002177, 0x3800fff0 }, + { 0x09002178, 0x3800fff0 }, + { 0x09002179, 0x3800fff0 }, + { 0x0900217a, 0x3800fff0 }, + { 0x0900217b, 0x3800fff0 }, + { 0x0900217c, 0x3800fff0 }, + { 0x0900217d, 0x3800fff0 }, + { 0x0900217e, 0x3800fff0 }, + { 0x0900217f, 0x3800fff0 }, + { 0x09802180, 0x38000003 }, + { 0x09802190, 0x64000004 }, + { 0x09802195, 0x68000004 }, + { 0x0980219a, 0x64000001 }, + { 0x0980219c, 0x68000003 }, + { 0x090021a0, 0x64000000 }, + { 0x098021a1, 0x68000001 }, + { 0x090021a3, 0x64000000 }, + { 0x098021a4, 0x68000001 }, + { 0x090021a6, 0x64000000 }, + { 0x098021a7, 0x68000006 }, + { 0x090021ae, 0x64000000 }, + { 0x098021af, 0x6800001e }, + { 0x098021ce, 0x64000001 }, + { 0x098021d0, 0x68000001 }, + { 0x090021d2, 0x64000000 }, + { 0x090021d3, 0x68000000 }, + { 0x090021d4, 0x64000000 }, + { 0x098021d5, 0x6800001e }, + { 0x098021f4, 0x6400010b }, + { 0x09802300, 0x68000007 }, + { 0x09802308, 0x64000003 }, + { 0x0980230c, 0x68000013 }, + { 0x09802320, 0x64000001 }, + { 0x09802322, 0x68000006 }, + { 0x09002329, 0x58000000 }, + { 0x0900232a, 0x48000000 }, + { 0x0980232b, 0x68000050 }, + { 0x0900237c, 0x64000000 }, + { 0x0980237d, 0x6800001d }, + { 0x0980239b, 0x64000018 }, + { 0x090023b4, 0x58000000 }, + { 0x090023b5, 0x48000000 }, + { 0x090023b6, 0x54000000 }, + { 0x098023b7, 0x68000024 }, + { 0x09802400, 0x68000026 }, + { 0x09802440, 0x6800000a }, + { 0x09802460, 0x3c00003b }, + { 0x0980249c, 0x68000019 }, + { 0x090024b6, 0x6800001a }, + { 0x090024b7, 0x6800001a }, + { 0x090024b8, 0x6800001a }, + { 0x090024b9, 0x6800001a }, + { 0x090024ba, 0x6800001a }, + { 0x090024bb, 0x6800001a }, + { 0x090024bc, 0x6800001a }, + { 0x090024bd, 0x6800001a }, + { 0x090024be, 0x6800001a }, + { 0x090024bf, 0x6800001a }, + { 0x090024c0, 0x6800001a }, + { 0x090024c1, 0x6800001a }, + { 0x090024c2, 0x6800001a }, + { 0x090024c3, 0x6800001a }, + { 0x090024c4, 0x6800001a }, + { 0x090024c5, 0x6800001a }, + { 0x090024c6, 0x6800001a }, + { 0x090024c7, 0x6800001a }, + { 0x090024c8, 0x6800001a }, + { 0x090024c9, 0x6800001a }, + { 0x090024ca, 0x6800001a }, + { 0x090024cb, 0x6800001a }, + { 0x090024cc, 0x6800001a }, + { 0x090024cd, 0x6800001a }, + { 0x090024ce, 0x6800001a }, + { 0x090024cf, 0x6800001a }, + { 0x090024d0, 0x6800ffe6 }, + { 0x090024d1, 0x6800ffe6 }, + { 0x090024d2, 0x6800ffe6 }, + { 0x090024d3, 0x6800ffe6 }, + { 0x090024d4, 0x6800ffe6 }, + { 0x090024d5, 0x6800ffe6 }, + { 0x090024d6, 0x6800ffe6 }, + { 0x090024d7, 0x6800ffe6 }, + { 0x090024d8, 0x6800ffe6 }, + { 0x090024d9, 0x6800ffe6 }, + { 0x090024da, 0x6800ffe6 }, + { 0x090024db, 0x6800ffe6 }, + { 0x090024dc, 0x6800ffe6 }, + { 0x090024dd, 0x6800ffe6 }, + { 0x090024de, 0x6800ffe6 }, + { 0x090024df, 0x6800ffe6 }, + { 0x090024e0, 0x6800ffe6 }, + { 0x090024e1, 0x6800ffe6 }, + { 0x090024e2, 0x6800ffe6 }, + { 0x090024e3, 0x6800ffe6 }, + { 0x090024e4, 0x6800ffe6 }, + { 0x090024e5, 0x6800ffe6 }, + { 0x090024e6, 0x6800ffe6 }, + { 0x090024e7, 0x6800ffe6 }, + { 0x090024e8, 0x6800ffe6 }, + { 0x090024e9, 0x6800ffe6 }, + { 0x098024ea, 0x3c000015 }, + { 0x09802500, 0x680000b6 }, + { 0x090025b7, 0x64000000 }, + { 0x098025b8, 0x68000008 }, + { 0x090025c1, 0x64000000 }, + { 0x098025c2, 0x68000035 }, + { 0x098025f8, 0x64000007 }, + { 0x09802600, 0x6800006e }, + { 0x0900266f, 0x64000000 }, + { 0x09802670, 0x6800002c }, + { 0x098026a0, 0x68000011 }, + { 0x09802701, 0x68000003 }, + { 0x09802706, 0x68000003 }, + { 0x0980270c, 0x6800001b }, + { 0x09802729, 0x68000022 }, + { 0x0900274d, 0x68000000 }, + { 0x0980274f, 0x68000003 }, + { 0x09002756, 0x68000000 }, + { 0x09802758, 0x68000006 }, + { 0x09802761, 0x68000006 }, + { 0x09002768, 0x58000000 }, + { 0x09002769, 0x48000000 }, + { 0x0900276a, 0x58000000 }, + { 0x0900276b, 0x48000000 }, + { 0x0900276c, 0x58000000 }, + { 0x0900276d, 0x48000000 }, + { 0x0900276e, 0x58000000 }, + { 0x0900276f, 0x48000000 }, + { 0x09002770, 0x58000000 }, + { 0x09002771, 0x48000000 }, + { 0x09002772, 0x58000000 }, + { 0x09002773, 0x48000000 }, + { 0x09002774, 0x58000000 }, + { 0x09002775, 0x48000000 }, + { 0x09802776, 0x3c00001d }, + { 0x09002794, 0x68000000 }, + { 0x09802798, 0x68000017 }, + { 0x098027b1, 0x6800000d }, + { 0x098027c0, 0x64000004 }, + { 0x090027c5, 0x58000000 }, + { 0x090027c6, 0x48000000 }, + { 0x098027d0, 0x64000015 }, + { 0x090027e6, 0x58000000 }, + { 0x090027e7, 0x48000000 }, + { 0x090027e8, 0x58000000 }, + { 0x090027e9, 0x48000000 }, + { 0x090027ea, 0x58000000 }, + { 0x090027eb, 0x48000000 }, + { 0x098027f0, 0x6400000f }, + { 0x04802800, 0x680000ff }, + { 0x09802900, 0x64000082 }, + { 0x09002983, 0x58000000 }, + { 0x09002984, 0x48000000 }, + { 0x09002985, 0x58000000 }, + { 0x09002986, 0x48000000 }, + { 0x09002987, 0x58000000 }, + { 0x09002988, 0x48000000 }, + { 0x09002989, 0x58000000 }, + { 0x0900298a, 0x48000000 }, + { 0x0900298b, 0x58000000 }, + { 0x0900298c, 0x48000000 }, + { 0x0900298d, 0x58000000 }, + { 0x0900298e, 0x48000000 }, + { 0x0900298f, 0x58000000 }, + { 0x09002990, 0x48000000 }, + { 0x09002991, 0x58000000 }, + { 0x09002992, 0x48000000 }, + { 0x09002993, 0x58000000 }, + { 0x09002994, 0x48000000 }, + { 0x09002995, 0x58000000 }, + { 0x09002996, 0x48000000 }, + { 0x09002997, 0x58000000 }, + { 0x09002998, 0x48000000 }, + { 0x09802999, 0x6400003e }, + { 0x090029d8, 0x58000000 }, + { 0x090029d9, 0x48000000 }, + { 0x090029da, 0x58000000 }, + { 0x090029db, 0x48000000 }, + { 0x098029dc, 0x6400001f }, + { 0x090029fc, 0x58000000 }, + { 0x090029fd, 0x48000000 }, + { 0x098029fe, 0x64000101 }, + { 0x09802b00, 0x68000013 }, + { 0x11002c00, 0x24000030 }, + { 0x11002c01, 0x24000030 }, + { 0x11002c02, 0x24000030 }, + { 0x11002c03, 0x24000030 }, + { 0x11002c04, 0x24000030 }, + { 0x11002c05, 0x24000030 }, + { 0x11002c06, 0x24000030 }, + { 0x11002c07, 0x24000030 }, + { 0x11002c08, 0x24000030 }, + { 0x11002c09, 0x24000030 }, + { 0x11002c0a, 0x24000030 }, + { 0x11002c0b, 0x24000030 }, + { 0x11002c0c, 0x24000030 }, + { 0x11002c0d, 0x24000030 }, + { 0x11002c0e, 0x24000030 }, + { 0x11002c0f, 0x24000030 }, + { 0x11002c10, 0x24000030 }, + { 0x11002c11, 0x24000030 }, + { 0x11002c12, 0x24000030 }, + { 0x11002c13, 0x24000030 }, + { 0x11002c14, 0x24000030 }, + { 0x11002c15, 0x24000030 }, + { 0x11002c16, 0x24000030 }, + { 0x11002c17, 0x24000030 }, + { 0x11002c18, 0x24000030 }, + { 0x11002c19, 0x24000030 }, + { 0x11002c1a, 0x24000030 }, + { 0x11002c1b, 0x24000030 }, + { 0x11002c1c, 0x24000030 }, + { 0x11002c1d, 0x24000030 }, + { 0x11002c1e, 0x24000030 }, + { 0x11002c1f, 0x24000030 }, + { 0x11002c20, 0x24000030 }, + { 0x11002c21, 0x24000030 }, + { 0x11002c22, 0x24000030 }, + { 0x11002c23, 0x24000030 }, + { 0x11002c24, 0x24000030 }, + { 0x11002c25, 0x24000030 }, + { 0x11002c26, 0x24000030 }, + { 0x11002c27, 0x24000030 }, + { 0x11002c28, 0x24000030 }, + { 0x11002c29, 0x24000030 }, + { 0x11002c2a, 0x24000030 }, + { 0x11002c2b, 0x24000030 }, + { 0x11002c2c, 0x24000030 }, + { 0x11002c2d, 0x24000030 }, + { 0x11002c2e, 0x24000030 }, + { 0x11002c30, 0x1400ffd0 }, + { 0x11002c31, 0x1400ffd0 }, + { 0x11002c32, 0x1400ffd0 }, + { 0x11002c33, 0x1400ffd0 }, + { 0x11002c34, 0x1400ffd0 }, + { 0x11002c35, 0x1400ffd0 }, + { 0x11002c36, 0x1400ffd0 }, + { 0x11002c37, 0x1400ffd0 }, + { 0x11002c38, 0x1400ffd0 }, + { 0x11002c39, 0x1400ffd0 }, + { 0x11002c3a, 0x1400ffd0 }, + { 0x11002c3b, 0x1400ffd0 }, + { 0x11002c3c, 0x1400ffd0 }, + { 0x11002c3d, 0x1400ffd0 }, + { 0x11002c3e, 0x1400ffd0 }, + { 0x11002c3f, 0x1400ffd0 }, + { 0x11002c40, 0x1400ffd0 }, + { 0x11002c41, 0x1400ffd0 }, + { 0x11002c42, 0x1400ffd0 }, + { 0x11002c43, 0x1400ffd0 }, + { 0x11002c44, 0x1400ffd0 }, + { 0x11002c45, 0x1400ffd0 }, + { 0x11002c46, 0x1400ffd0 }, + { 0x11002c47, 0x1400ffd0 }, + { 0x11002c48, 0x1400ffd0 }, + { 0x11002c49, 0x1400ffd0 }, + { 0x11002c4a, 0x1400ffd0 }, + { 0x11002c4b, 0x1400ffd0 }, + { 0x11002c4c, 0x1400ffd0 }, + { 0x11002c4d, 0x1400ffd0 }, + { 0x11002c4e, 0x1400ffd0 }, + { 0x11002c4f, 0x1400ffd0 }, + { 0x11002c50, 0x1400ffd0 }, + { 0x11002c51, 0x1400ffd0 }, + { 0x11002c52, 0x1400ffd0 }, + { 0x11002c53, 0x1400ffd0 }, + { 0x11002c54, 0x1400ffd0 }, + { 0x11002c55, 0x1400ffd0 }, + { 0x11002c56, 0x1400ffd0 }, + { 0x11002c57, 0x1400ffd0 }, + { 0x11002c58, 0x1400ffd0 }, + { 0x11002c59, 0x1400ffd0 }, + { 0x11002c5a, 0x1400ffd0 }, + { 0x11002c5b, 0x1400ffd0 }, + { 0x11002c5c, 0x1400ffd0 }, + { 0x11002c5d, 0x1400ffd0 }, + { 0x11002c5e, 0x1400ffd0 }, + { 0x0a002c80, 0x24000001 }, + { 0x0a002c81, 0x1400ffff }, + { 0x0a002c82, 0x24000001 }, + { 0x0a002c83, 0x1400ffff }, + { 0x0a002c84, 0x24000001 }, + { 0x0a002c85, 0x1400ffff }, + { 0x0a002c86, 0x24000001 }, + { 0x0a002c87, 0x1400ffff }, + { 0x0a002c88, 0x24000001 }, + { 0x0a002c89, 0x1400ffff }, + { 0x0a002c8a, 0x24000001 }, + { 0x0a002c8b, 0x1400ffff }, + { 0x0a002c8c, 0x24000001 }, + { 0x0a002c8d, 0x1400ffff }, + { 0x0a002c8e, 0x24000001 }, + { 0x0a002c8f, 0x1400ffff }, + { 0x0a002c90, 0x24000001 }, + { 0x0a002c91, 0x1400ffff }, + { 0x0a002c92, 0x24000001 }, + { 0x0a002c93, 0x1400ffff }, + { 0x0a002c94, 0x24000001 }, + { 0x0a002c95, 0x1400ffff }, + { 0x0a002c96, 0x24000001 }, + { 0x0a002c97, 0x1400ffff }, + { 0x0a002c98, 0x24000001 }, + { 0x0a002c99, 0x1400ffff }, + { 0x0a002c9a, 0x24000001 }, + { 0x0a002c9b, 0x1400ffff }, + { 0x0a002c9c, 0x24000001 }, + { 0x0a002c9d, 0x1400ffff }, + { 0x0a002c9e, 0x24000001 }, + { 0x0a002c9f, 0x1400ffff }, + { 0x0a002ca0, 0x24000001 }, + { 0x0a002ca1, 0x1400ffff }, + { 0x0a002ca2, 0x24000001 }, + { 0x0a002ca3, 0x1400ffff }, + { 0x0a002ca4, 0x24000001 }, + { 0x0a002ca5, 0x1400ffff }, + { 0x0a002ca6, 0x24000001 }, + { 0x0a002ca7, 0x1400ffff }, + { 0x0a002ca8, 0x24000001 }, + { 0x0a002ca9, 0x1400ffff }, + { 0x0a002caa, 0x24000001 }, + { 0x0a002cab, 0x1400ffff }, + { 0x0a002cac, 0x24000001 }, + { 0x0a002cad, 0x1400ffff }, + { 0x0a002cae, 0x24000001 }, + { 0x0a002caf, 0x1400ffff }, + { 0x0a002cb0, 0x24000001 }, + { 0x0a002cb1, 0x1400ffff }, + { 0x0a002cb2, 0x24000001 }, + { 0x0a002cb3, 0x1400ffff }, + { 0x0a002cb4, 0x24000001 }, + { 0x0a002cb5, 0x1400ffff }, + { 0x0a002cb6, 0x24000001 }, + { 0x0a002cb7, 0x1400ffff }, + { 0x0a002cb8, 0x24000001 }, + { 0x0a002cb9, 0x1400ffff }, + { 0x0a002cba, 0x24000001 }, + { 0x0a002cbb, 0x1400ffff }, + { 0x0a002cbc, 0x24000001 }, + { 0x0a002cbd, 0x1400ffff }, + { 0x0a002cbe, 0x24000001 }, + { 0x0a002cbf, 0x1400ffff }, + { 0x0a002cc0, 0x24000001 }, + { 0x0a002cc1, 0x1400ffff }, + { 0x0a002cc2, 0x24000001 }, + { 0x0a002cc3, 0x1400ffff }, + { 0x0a002cc4, 0x24000001 }, + { 0x0a002cc5, 0x1400ffff }, + { 0x0a002cc6, 0x24000001 }, + { 0x0a002cc7, 0x1400ffff }, + { 0x0a002cc8, 0x24000001 }, + { 0x0a002cc9, 0x1400ffff }, + { 0x0a002cca, 0x24000001 }, + { 0x0a002ccb, 0x1400ffff }, + { 0x0a002ccc, 0x24000001 }, + { 0x0a002ccd, 0x1400ffff }, + { 0x0a002cce, 0x24000001 }, + { 0x0a002ccf, 0x1400ffff }, + { 0x0a002cd0, 0x24000001 }, + { 0x0a002cd1, 0x1400ffff }, + { 0x0a002cd2, 0x24000001 }, + { 0x0a002cd3, 0x1400ffff }, + { 0x0a002cd4, 0x24000001 }, + { 0x0a002cd5, 0x1400ffff }, + { 0x0a002cd6, 0x24000001 }, + { 0x0a002cd7, 0x1400ffff }, + { 0x0a002cd8, 0x24000001 }, + { 0x0a002cd9, 0x1400ffff }, + { 0x0a002cda, 0x24000001 }, + { 0x0a002cdb, 0x1400ffff }, + { 0x0a002cdc, 0x24000001 }, + { 0x0a002cdd, 0x1400ffff }, + { 0x0a002cde, 0x24000001 }, + { 0x0a002cdf, 0x1400ffff }, + { 0x0a002ce0, 0x24000001 }, + { 0x0a002ce1, 0x1400ffff }, + { 0x0a002ce2, 0x24000001 }, + { 0x0a002ce3, 0x1400ffff }, + { 0x0a002ce4, 0x14000000 }, + { 0x0a802ce5, 0x68000005 }, + { 0x0a802cf9, 0x54000003 }, + { 0x0a002cfd, 0x3c000000 }, + { 0x0a802cfe, 0x54000001 }, + { 0x10002d00, 0x1400e3a0 }, + { 0x10002d01, 0x1400e3a0 }, + { 0x10002d02, 0x1400e3a0 }, + { 0x10002d03, 0x1400e3a0 }, + { 0x10002d04, 0x1400e3a0 }, + { 0x10002d05, 0x1400e3a0 }, + { 0x10002d06, 0x1400e3a0 }, + { 0x10002d07, 0x1400e3a0 }, + { 0x10002d08, 0x1400e3a0 }, + { 0x10002d09, 0x1400e3a0 }, + { 0x10002d0a, 0x1400e3a0 }, + { 0x10002d0b, 0x1400e3a0 }, + { 0x10002d0c, 0x1400e3a0 }, + { 0x10002d0d, 0x1400e3a0 }, + { 0x10002d0e, 0x1400e3a0 }, + { 0x10002d0f, 0x1400e3a0 }, + { 0x10002d10, 0x1400e3a0 }, + { 0x10002d11, 0x1400e3a0 }, + { 0x10002d12, 0x1400e3a0 }, + { 0x10002d13, 0x1400e3a0 }, + { 0x10002d14, 0x1400e3a0 }, + { 0x10002d15, 0x1400e3a0 }, + { 0x10002d16, 0x1400e3a0 }, + { 0x10002d17, 0x1400e3a0 }, + { 0x10002d18, 0x1400e3a0 }, + { 0x10002d19, 0x1400e3a0 }, + { 0x10002d1a, 0x1400e3a0 }, + { 0x10002d1b, 0x1400e3a0 }, + { 0x10002d1c, 0x1400e3a0 }, + { 0x10002d1d, 0x1400e3a0 }, + { 0x10002d1e, 0x1400e3a0 }, + { 0x10002d1f, 0x1400e3a0 }, + { 0x10002d20, 0x1400e3a0 }, + { 0x10002d21, 0x1400e3a0 }, + { 0x10002d22, 0x1400e3a0 }, + { 0x10002d23, 0x1400e3a0 }, + { 0x10002d24, 0x1400e3a0 }, + { 0x10002d25, 0x1400e3a0 }, + { 0x3a802d30, 0x1c000035 }, + { 0x3a002d6f, 0x18000000 }, + { 0x0f802d80, 0x1c000016 }, + { 0x0f802da0, 0x1c000006 }, + { 0x0f802da8, 0x1c000006 }, + { 0x0f802db0, 0x1c000006 }, + { 0x0f802db8, 0x1c000006 }, + { 0x0f802dc0, 0x1c000006 }, + { 0x0f802dc8, 0x1c000006 }, + { 0x0f802dd0, 0x1c000006 }, + { 0x0f802dd8, 0x1c000006 }, + { 0x09802e00, 0x54000001 }, + { 0x09002e02, 0x50000000 }, + { 0x09002e03, 0x4c000000 }, + { 0x09002e04, 0x50000000 }, + { 0x09002e05, 0x4c000000 }, + { 0x09802e06, 0x54000002 }, + { 0x09002e09, 0x50000000 }, + { 0x09002e0a, 0x4c000000 }, + { 0x09002e0b, 0x54000000 }, + { 0x09002e0c, 0x50000000 }, + { 0x09002e0d, 0x4c000000 }, + { 0x09802e0e, 0x54000008 }, + { 0x09002e17, 0x44000000 }, + { 0x09002e1c, 0x50000000 }, + { 0x09002e1d, 0x4c000000 }, + { 0x16802e80, 0x68000019 }, + { 0x16802e9b, 0x68000058 }, + { 0x16802f00, 0x680000d5 }, + { 0x09802ff0, 0x6800000b }, + { 0x09003000, 0x74000000 }, + { 0x09803001, 0x54000002 }, + { 0x09003004, 0x68000000 }, + { 0x16003005, 0x18000000 }, + { 0x09003006, 0x1c000000 }, + { 0x16003007, 0x38000000 }, + { 0x09003008, 0x58000000 }, + { 0x09003009, 0x48000000 }, + { 0x0900300a, 0x58000000 }, + { 0x0900300b, 0x48000000 }, + { 0x0900300c, 0x58000000 }, + { 0x0900300d, 0x48000000 }, + { 0x0900300e, 0x58000000 }, + { 0x0900300f, 0x48000000 }, + { 0x09003010, 0x58000000 }, + { 0x09003011, 0x48000000 }, + { 0x09803012, 0x68000001 }, + { 0x09003014, 0x58000000 }, + { 0x09003015, 0x48000000 }, + { 0x09003016, 0x58000000 }, + { 0x09003017, 0x48000000 }, + { 0x09003018, 0x58000000 }, + { 0x09003019, 0x48000000 }, + { 0x0900301a, 0x58000000 }, + { 0x0900301b, 0x48000000 }, + { 0x0900301c, 0x44000000 }, + { 0x0900301d, 0x58000000 }, + { 0x0980301e, 0x48000001 }, + { 0x09003020, 0x68000000 }, + { 0x16803021, 0x38000008 }, + { 0x1b80302a, 0x30000005 }, + { 0x09003030, 0x44000000 }, + { 0x09803031, 0x18000004 }, + { 0x09803036, 0x68000001 }, + { 0x16803038, 0x38000002 }, + { 0x1600303b, 0x18000000 }, + { 0x0900303c, 0x1c000000 }, + { 0x0900303d, 0x54000000 }, + { 0x0980303e, 0x68000001 }, + { 0x1a803041, 0x1c000055 }, + { 0x1b803099, 0x30000001 }, + { 0x0980309b, 0x60000001 }, + { 0x1a80309d, 0x18000001 }, + { 0x1a00309f, 0x1c000000 }, + { 0x090030a0, 0x44000000 }, + { 0x1d8030a1, 0x1c000059 }, + { 0x090030fb, 0x54000000 }, + { 0x098030fc, 0x18000002 }, + { 0x1d0030ff, 0x1c000000 }, + { 0x03803105, 0x1c000027 }, + { 0x17803131, 0x1c00005d }, + { 0x09803190, 0x68000001 }, + { 0x09803192, 0x3c000003 }, + { 0x09803196, 0x68000009 }, + { 0x038031a0, 0x1c000017 }, + { 0x098031c0, 0x6800000f }, + { 0x1d8031f0, 0x1c00000f }, + { 0x17803200, 0x6800001e }, + { 0x09803220, 0x3c000009 }, + { 0x0980322a, 0x68000019 }, + { 0x09003250, 0x68000000 }, + { 0x09803251, 0x3c00000e }, + { 0x17803260, 0x6800001f }, + { 0x09803280, 0x3c000009 }, + { 0x0980328a, 0x68000026 }, + { 0x098032b1, 0x3c00000e }, + { 0x098032c0, 0x6800003e }, + { 0x09803300, 0x680000ff }, + { 0x16803400, 0x1c0019b5 }, + { 0x09804dc0, 0x6800003f }, + { 0x16804e00, 0x1c0051bb }, + { 0x3c80a000, 0x1c000014 }, + { 0x3c00a015, 0x18000000 }, + { 0x3c80a016, 0x1c000476 }, + { 0x3c80a490, 0x68000036 }, + { 0x0980a700, 0x60000016 }, + { 0x3080a800, 0x1c000001 }, + { 0x3000a802, 0x28000000 }, + { 0x3080a803, 0x1c000002 }, + { 0x3000a806, 0x30000000 }, + { 0x3080a807, 0x1c000003 }, + { 0x3000a80b, 0x30000000 }, + { 0x3080a80c, 0x1c000016 }, + { 0x3080a823, 0x28000001 }, + { 0x3080a825, 0x30000001 }, + { 0x3000a827, 0x28000000 }, + { 0x3080a828, 0x68000003 }, + { 0x1780ac00, 0x1c002ba3 }, + { 0x0980d800, 0x1000037f }, + { 0x0980db80, 0x1000007f }, + { 0x0980dc00, 0x100003ff }, + { 0x0980e000, 0x0c0018ff }, + { 0x1680f900, 0x1c00012d }, + { 0x1680fa30, 0x1c00003a }, + { 0x1680fa70, 0x1c000069 }, + { 0x2180fb00, 0x14000006 }, + { 0x0180fb13, 0x14000004 }, + { 0x1900fb1d, 0x1c000000 }, + { 0x1900fb1e, 0x30000000 }, + { 0x1980fb1f, 0x1c000009 }, + { 0x1900fb29, 0x64000000 }, + { 0x1980fb2a, 0x1c00000c }, + { 0x1980fb38, 0x1c000004 }, + { 0x1900fb3e, 0x1c000000 }, + { 0x1980fb40, 0x1c000001 }, + { 0x1980fb43, 0x1c000001 }, + { 0x1980fb46, 0x1c00006b }, + { 0x0080fbd3, 0x1c00016a }, + { 0x0900fd3e, 0x58000000 }, + { 0x0900fd3f, 0x48000000 }, + { 0x0080fd50, 0x1c00003f }, + { 0x0080fd92, 0x1c000035 }, + { 0x0080fdf0, 0x1c00000b }, + { 0x0000fdfc, 0x5c000000 }, + { 0x0900fdfd, 0x68000000 }, + { 0x1b80fe00, 0x3000000f }, + { 0x0980fe10, 0x54000006 }, + { 0x0900fe17, 0x58000000 }, + { 0x0900fe18, 0x48000000 }, + { 0x0900fe19, 0x54000000 }, + { 0x1b80fe20, 0x30000003 }, + { 0x0900fe30, 0x54000000 }, + { 0x0980fe31, 0x44000001 }, + { 0x0980fe33, 0x40000001 }, + { 0x0900fe35, 0x58000000 }, + { 0x0900fe36, 0x48000000 }, + { 0x0900fe37, 0x58000000 }, + { 0x0900fe38, 0x48000000 }, + { 0x0900fe39, 0x58000000 }, + { 0x0900fe3a, 0x48000000 }, + { 0x0900fe3b, 0x58000000 }, + { 0x0900fe3c, 0x48000000 }, + { 0x0900fe3d, 0x58000000 }, + { 0x0900fe3e, 0x48000000 }, + { 0x0900fe3f, 0x58000000 }, + { 0x0900fe40, 0x48000000 }, + { 0x0900fe41, 0x58000000 }, + { 0x0900fe42, 0x48000000 }, + { 0x0900fe43, 0x58000000 }, + { 0x0900fe44, 0x48000000 }, + { 0x0980fe45, 0x54000001 }, + { 0x0900fe47, 0x58000000 }, + { 0x0900fe48, 0x48000000 }, + { 0x0980fe49, 0x54000003 }, + { 0x0980fe4d, 0x40000002 }, + { 0x0980fe50, 0x54000002 }, + { 0x0980fe54, 0x54000003 }, + { 0x0900fe58, 0x44000000 }, + { 0x0900fe59, 0x58000000 }, + { 0x0900fe5a, 0x48000000 }, + { 0x0900fe5b, 0x58000000 }, + { 0x0900fe5c, 0x48000000 }, + { 0x0900fe5d, 0x58000000 }, + { 0x0900fe5e, 0x48000000 }, + { 0x0980fe5f, 0x54000002 }, + { 0x0900fe62, 0x64000000 }, + { 0x0900fe63, 0x44000000 }, + { 0x0980fe64, 0x64000002 }, + { 0x0900fe68, 0x54000000 }, + { 0x0900fe69, 0x5c000000 }, + { 0x0980fe6a, 0x54000001 }, + { 0x0080fe70, 0x1c000004 }, + { 0x0080fe76, 0x1c000086 }, + { 0x0900feff, 0x04000000 }, + { 0x0980ff01, 0x54000002 }, + { 0x0900ff04, 0x5c000000 }, + { 0x0980ff05, 0x54000002 }, + { 0x0900ff08, 0x58000000 }, + { 0x0900ff09, 0x48000000 }, + { 0x0900ff0a, 0x54000000 }, + { 0x0900ff0b, 0x64000000 }, + { 0x0900ff0c, 0x54000000 }, + { 0x0900ff0d, 0x44000000 }, + { 0x0980ff0e, 0x54000001 }, + { 0x0980ff10, 0x34000009 }, + { 0x0980ff1a, 0x54000001 }, + { 0x0980ff1c, 0x64000002 }, + { 0x0980ff1f, 0x54000001 }, + { 0x2100ff21, 0x24000020 }, + { 0x2100ff22, 0x24000020 }, + { 0x2100ff23, 0x24000020 }, + { 0x2100ff24, 0x24000020 }, + { 0x2100ff25, 0x24000020 }, + { 0x2100ff26, 0x24000020 }, + { 0x2100ff27, 0x24000020 }, + { 0x2100ff28, 0x24000020 }, + { 0x2100ff29, 0x24000020 }, + { 0x2100ff2a, 0x24000020 }, + { 0x2100ff2b, 0x24000020 }, + { 0x2100ff2c, 0x24000020 }, + { 0x2100ff2d, 0x24000020 }, + { 0x2100ff2e, 0x24000020 }, + { 0x2100ff2f, 0x24000020 }, + { 0x2100ff30, 0x24000020 }, + { 0x2100ff31, 0x24000020 }, + { 0x2100ff32, 0x24000020 }, + { 0x2100ff33, 0x24000020 }, + { 0x2100ff34, 0x24000020 }, + { 0x2100ff35, 0x24000020 }, + { 0x2100ff36, 0x24000020 }, + { 0x2100ff37, 0x24000020 }, + { 0x2100ff38, 0x24000020 }, + { 0x2100ff39, 0x24000020 }, + { 0x2100ff3a, 0x24000020 }, + { 0x0900ff3b, 0x58000000 }, + { 0x0900ff3c, 0x54000000 }, + { 0x0900ff3d, 0x48000000 }, + { 0x0900ff3e, 0x60000000 }, + { 0x0900ff3f, 0x40000000 }, + { 0x0900ff40, 0x60000000 }, + { 0x2100ff41, 0x1400ffe0 }, + { 0x2100ff42, 0x1400ffe0 }, + { 0x2100ff43, 0x1400ffe0 }, + { 0x2100ff44, 0x1400ffe0 }, + { 0x2100ff45, 0x1400ffe0 }, + { 0x2100ff46, 0x1400ffe0 }, + { 0x2100ff47, 0x1400ffe0 }, + { 0x2100ff48, 0x1400ffe0 }, + { 0x2100ff49, 0x1400ffe0 }, + { 0x2100ff4a, 0x1400ffe0 }, + { 0x2100ff4b, 0x1400ffe0 }, + { 0x2100ff4c, 0x1400ffe0 }, + { 0x2100ff4d, 0x1400ffe0 }, + { 0x2100ff4e, 0x1400ffe0 }, + { 0x2100ff4f, 0x1400ffe0 }, + { 0x2100ff50, 0x1400ffe0 }, + { 0x2100ff51, 0x1400ffe0 }, + { 0x2100ff52, 0x1400ffe0 }, + { 0x2100ff53, 0x1400ffe0 }, + { 0x2100ff54, 0x1400ffe0 }, + { 0x2100ff55, 0x1400ffe0 }, + { 0x2100ff56, 0x1400ffe0 }, + { 0x2100ff57, 0x1400ffe0 }, + { 0x2100ff58, 0x1400ffe0 }, + { 0x2100ff59, 0x1400ffe0 }, + { 0x2100ff5a, 0x1400ffe0 }, + { 0x0900ff5b, 0x58000000 }, + { 0x0900ff5c, 0x64000000 }, + { 0x0900ff5d, 0x48000000 }, + { 0x0900ff5e, 0x64000000 }, + { 0x0900ff5f, 0x58000000 }, + { 0x0900ff60, 0x48000000 }, + { 0x0900ff61, 0x54000000 }, + { 0x0900ff62, 0x58000000 }, + { 0x0900ff63, 0x48000000 }, + { 0x0980ff64, 0x54000001 }, + { 0x1d80ff66, 0x1c000009 }, + { 0x0900ff70, 0x18000000 }, + { 0x1d80ff71, 0x1c00002c }, + { 0x0980ff9e, 0x18000001 }, + { 0x1780ffa0, 0x1c00001e }, + { 0x1780ffc2, 0x1c000005 }, + { 0x1780ffca, 0x1c000005 }, + { 0x1780ffd2, 0x1c000005 }, + { 0x1780ffda, 0x1c000002 }, + { 0x0980ffe0, 0x5c000001 }, + { 0x0900ffe2, 0x64000000 }, + { 0x0900ffe3, 0x60000000 }, + { 0x0900ffe4, 0x68000000 }, + { 0x0980ffe5, 0x5c000001 }, + { 0x0900ffe8, 0x68000000 }, + { 0x0980ffe9, 0x64000003 }, + { 0x0980ffed, 0x68000001 }, + { 0x0980fff9, 0x04000002 }, + { 0x0980fffc, 0x68000001 }, + { 0x23810000, 0x1c00000b }, + { 0x2381000d, 0x1c000019 }, + { 0x23810028, 0x1c000012 }, + { 0x2381003c, 0x1c000001 }, + { 0x2381003f, 0x1c00000e }, + { 0x23810050, 0x1c00000d }, + { 0x23810080, 0x1c00007a }, + { 0x09810100, 0x54000001 }, + { 0x09010102, 0x68000000 }, + { 0x09810107, 0x3c00002c }, + { 0x09810137, 0x68000008 }, + { 0x13810140, 0x38000034 }, + { 0x13810175, 0x3c000003 }, + { 0x13810179, 0x68000010 }, + { 0x1301018a, 0x3c000000 }, + { 0x29810300, 0x1c00001e }, + { 0x29810320, 0x3c000003 }, + { 0x12810330, 0x1c000019 }, + { 0x1201034a, 0x38000000 }, + { 0x3b810380, 0x1c00001d }, + { 0x3b01039f, 0x54000000 }, + { 0x2a8103a0, 0x1c000023 }, + { 0x2a8103c8, 0x1c000007 }, + { 0x2a0103d0, 0x68000000 }, + { 0x2a8103d1, 0x38000004 }, + { 0x0d010400, 0x24000028 }, + { 0x0d010401, 0x24000028 }, + { 0x0d010402, 0x24000028 }, + { 0x0d010403, 0x24000028 }, + { 0x0d010404, 0x24000028 }, + { 0x0d010405, 0x24000028 }, + { 0x0d010406, 0x24000028 }, + { 0x0d010407, 0x24000028 }, + { 0x0d010408, 0x24000028 }, + { 0x0d010409, 0x24000028 }, + { 0x0d01040a, 0x24000028 }, + { 0x0d01040b, 0x24000028 }, + { 0x0d01040c, 0x24000028 }, + { 0x0d01040d, 0x24000028 }, + { 0x0d01040e, 0x24000028 }, + { 0x0d01040f, 0x24000028 }, + { 0x0d010410, 0x24000028 }, + { 0x0d010411, 0x24000028 }, + { 0x0d010412, 0x24000028 }, + { 0x0d010413, 0x24000028 }, + { 0x0d010414, 0x24000028 }, + { 0x0d010415, 0x24000028 }, + { 0x0d010416, 0x24000028 }, + { 0x0d010417, 0x24000028 }, + { 0x0d010418, 0x24000028 }, + { 0x0d010419, 0x24000028 }, + { 0x0d01041a, 0x24000028 }, + { 0x0d01041b, 0x24000028 }, + { 0x0d01041c, 0x24000028 }, + { 0x0d01041d, 0x24000028 }, + { 0x0d01041e, 0x24000028 }, + { 0x0d01041f, 0x24000028 }, + { 0x0d010420, 0x24000028 }, + { 0x0d010421, 0x24000028 }, + { 0x0d010422, 0x24000028 }, + { 0x0d010423, 0x24000028 }, + { 0x0d010424, 0x24000028 }, + { 0x0d010425, 0x24000028 }, + { 0x0d010426, 0x24000028 }, + { 0x0d010427, 0x24000028 }, + { 0x0d010428, 0x1400ffd8 }, + { 0x0d010429, 0x1400ffd8 }, + { 0x0d01042a, 0x1400ffd8 }, + { 0x0d01042b, 0x1400ffd8 }, + { 0x0d01042c, 0x1400ffd8 }, + { 0x0d01042d, 0x1400ffd8 }, + { 0x0d01042e, 0x1400ffd8 }, + { 0x0d01042f, 0x1400ffd8 }, + { 0x0d010430, 0x1400ffd8 }, + { 0x0d010431, 0x1400ffd8 }, + { 0x0d010432, 0x1400ffd8 }, + { 0x0d010433, 0x1400ffd8 }, + { 0x0d010434, 0x1400ffd8 }, + { 0x0d010435, 0x1400ffd8 }, + { 0x0d010436, 0x1400ffd8 }, + { 0x0d010437, 0x1400ffd8 }, + { 0x0d010438, 0x1400ffd8 }, + { 0x0d010439, 0x1400ffd8 }, + { 0x0d01043a, 0x1400ffd8 }, + { 0x0d01043b, 0x1400ffd8 }, + { 0x0d01043c, 0x1400ffd8 }, + { 0x0d01043d, 0x1400ffd8 }, + { 0x0d01043e, 0x1400ffd8 }, + { 0x0d01043f, 0x1400ffd8 }, + { 0x0d010440, 0x1400ffd8 }, + { 0x0d010441, 0x1400ffd8 }, + { 0x0d010442, 0x1400ffd8 }, + { 0x0d010443, 0x1400ffd8 }, + { 0x0d010444, 0x1400ffd8 }, + { 0x0d010445, 0x1400ffd8 }, + { 0x0d010446, 0x1400ffd8 }, + { 0x0d010447, 0x1400ffd8 }, + { 0x0d010448, 0x1400ffd8 }, + { 0x0d010449, 0x1400ffd8 }, + { 0x0d01044a, 0x1400ffd8 }, + { 0x0d01044b, 0x1400ffd8 }, + { 0x0d01044c, 0x1400ffd8 }, + { 0x0d01044d, 0x1400ffd8 }, + { 0x0d01044e, 0x1400ffd8 }, + { 0x0d01044f, 0x1400ffd8 }, + { 0x2e810450, 0x1c00004d }, + { 0x2c8104a0, 0x34000009 }, + { 0x0b810800, 0x1c000005 }, + { 0x0b010808, 0x1c000000 }, + { 0x0b81080a, 0x1c00002b }, + { 0x0b810837, 0x1c000001 }, + { 0x0b01083c, 0x1c000000 }, + { 0x0b01083f, 0x1c000000 }, + { 0x1e010a00, 0x1c000000 }, + { 0x1e810a01, 0x30000002 }, + { 0x1e810a05, 0x30000001 }, + { 0x1e810a0c, 0x30000003 }, + { 0x1e810a10, 0x1c000003 }, + { 0x1e810a15, 0x1c000002 }, + { 0x1e810a19, 0x1c00001a }, + { 0x1e810a38, 0x30000002 }, + { 0x1e010a3f, 0x30000000 }, + { 0x1e810a40, 0x3c000007 }, + { 0x1e810a50, 0x54000008 }, + { 0x0981d000, 0x680000f5 }, + { 0x0981d100, 0x68000026 }, + { 0x0981d12a, 0x6800003a }, + { 0x0981d165, 0x28000001 }, + { 0x1b81d167, 0x30000002 }, + { 0x0981d16a, 0x68000002 }, + { 0x0981d16d, 0x28000005 }, + { 0x0981d173, 0x04000007 }, + { 0x1b81d17b, 0x30000007 }, + { 0x0981d183, 0x68000001 }, + { 0x1b81d185, 0x30000006 }, + { 0x0981d18c, 0x6800001d }, + { 0x1b81d1aa, 0x30000003 }, + { 0x0981d1ae, 0x6800002f }, + { 0x1381d200, 0x68000041 }, + { 0x1381d242, 0x30000002 }, + { 0x1301d245, 0x68000000 }, + { 0x0981d300, 0x68000056 }, + { 0x0981d400, 0x24000019 }, + { 0x0981d41a, 0x14000019 }, + { 0x0981d434, 0x24000019 }, + { 0x0981d44e, 0x14000006 }, + { 0x0981d456, 0x14000011 }, + { 0x0981d468, 0x24000019 }, + { 0x0981d482, 0x14000019 }, + { 0x0901d49c, 0x24000000 }, + { 0x0981d49e, 0x24000001 }, + { 0x0901d4a2, 0x24000000 }, + { 0x0981d4a5, 0x24000001 }, + { 0x0981d4a9, 0x24000003 }, + { 0x0981d4ae, 0x24000007 }, + { 0x0981d4b6, 0x14000003 }, + { 0x0901d4bb, 0x14000000 }, + { 0x0981d4bd, 0x14000006 }, + { 0x0981d4c5, 0x1400000a }, + { 0x0981d4d0, 0x24000019 }, + { 0x0981d4ea, 0x14000019 }, + { 0x0981d504, 0x24000001 }, + { 0x0981d507, 0x24000003 }, + { 0x0981d50d, 0x24000007 }, + { 0x0981d516, 0x24000006 }, + { 0x0981d51e, 0x14000019 }, + { 0x0981d538, 0x24000001 }, + { 0x0981d53b, 0x24000003 }, + { 0x0981d540, 0x24000004 }, + { 0x0901d546, 0x24000000 }, + { 0x0981d54a, 0x24000006 }, + { 0x0981d552, 0x14000019 }, + { 0x0981d56c, 0x24000019 }, + { 0x0981d586, 0x14000019 }, + { 0x0981d5a0, 0x24000019 }, + { 0x0981d5ba, 0x14000019 }, + { 0x0981d5d4, 0x24000019 }, + { 0x0981d5ee, 0x14000019 }, + { 0x0981d608, 0x24000019 }, + { 0x0981d622, 0x14000019 }, + { 0x0981d63c, 0x24000019 }, + { 0x0981d656, 0x14000019 }, + { 0x0981d670, 0x24000019 }, + { 0x0981d68a, 0x1400001b }, + { 0x0981d6a8, 0x24000018 }, + { 0x0901d6c1, 0x64000000 }, + { 0x0981d6c2, 0x14000018 }, + { 0x0901d6db, 0x64000000 }, + { 0x0981d6dc, 0x14000005 }, + { 0x0981d6e2, 0x24000018 }, + { 0x0901d6fb, 0x64000000 }, + { 0x0981d6fc, 0x14000018 }, + { 0x0901d715, 0x64000000 }, + { 0x0981d716, 0x14000005 }, + { 0x0981d71c, 0x24000018 }, + { 0x0901d735, 0x64000000 }, + { 0x0981d736, 0x14000018 }, + { 0x0901d74f, 0x64000000 }, + { 0x0981d750, 0x14000005 }, + { 0x0981d756, 0x24000018 }, + { 0x0901d76f, 0x64000000 }, + { 0x0981d770, 0x14000018 }, + { 0x0901d789, 0x64000000 }, + { 0x0981d78a, 0x14000005 }, + { 0x0981d790, 0x24000018 }, + { 0x0901d7a9, 0x64000000 }, + { 0x0981d7aa, 0x14000018 }, + { 0x0901d7c3, 0x64000000 }, + { 0x0981d7c4, 0x14000005 }, + { 0x0981d7ce, 0x34000031 }, + { 0x16820000, 0x1c00a6d6 }, + { 0x1682f800, 0x1c00021d }, + { 0x090e0001, 0x04000000 }, + { 0x098e0020, 0x0400005f }, + { 0x1b8e0100, 0x300000ef }, + { 0x098f0000, 0x0c00fffd }, + { 0x09900000, 0x0c00fffd }, +}; diff --git a/js/src/yarr/ASCIICType.h b/js/src/yarr/wtf/ASCIICType.h similarity index 81% rename from js/src/yarr/ASCIICType.h rename to js/src/yarr/wtf/ASCIICType.h index a3ae9f4455e2..cf53d9ac0c87 100644 --- a/js/src/yarr/ASCIICType.h +++ b/js/src/yarr/wtf/ASCIICType.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) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +24,12 @@ * 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. - * - * ***** END LICENSE BLOCK ***** */ + */ #ifndef WTF_ASCIICType_h #define WTF_ASCIICType_h -#include "assembler/wtf/Assertions.h" +#include "yarr/jswtfbridge.h" // The behavior of many of the functions in the header is dependent // on the current locale. But in the WebKit project, all uses of those functions @@ -53,7 +49,6 @@ namespace WTF { inline bool isASCII(wchar_t c) { return !(c & ~0x7F); } #endif inline bool isASCII(int c) { return !(c & ~0x7F); } - inline bool isASCII(unsigned c) { return !(c & ~0x7F); } inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } @@ -61,7 +56,6 @@ namespace WTF { inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } #endif inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } - inline bool isASCIIAlpha(unsigned c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } @@ -69,7 +63,6 @@ namespace WTF { inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } #endif inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } - inline bool isASCIIAlphanumeric(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); } inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); } @@ -77,7 +70,6 @@ namespace WTF { inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); } #endif inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); } - inline bool isASCIIDigit(unsigned c) { return (c >= '0') & (c <= '9'); } inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } @@ -85,7 +77,6 @@ namespace WTF { inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } #endif inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } - inline bool isASCIIHexDigit(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); } inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); } @@ -93,7 +84,6 @@ namespace WTF { inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); } #endif inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); } - inline bool isASCIIOctalDigit(unsigned c) { return (c >= '0') & (c <= '7'); } inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; } inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; } @@ -101,7 +91,6 @@ namespace WTF { inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; } #endif inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; } - inline bool isASCIILower(unsigned c) { return c >= 'a' && c <= 'z'; } inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; } inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; } @@ -109,7 +98,6 @@ namespace WTF { inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; } #endif inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; } - inline bool isASCIIUpper(unsigned c) { return c >= 'A' && c <= 'Z'; } /* Statistics from a run of Apple's page load test for callers of isASCIISpace: @@ -130,7 +118,6 @@ namespace WTF { inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } #endif inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } - inline bool isASCIISpace(unsigned c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); } inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); } @@ -138,24 +125,20 @@ namespace WTF { inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); } #endif inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - inline unsigned toASCIILower(unsigned c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - // FIXME: Why do these need static_cast? inline char toASCIIUpper(char c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } inline unsigned short toASCIIUpper(unsigned short c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) inline wchar_t toASCIIUpper(wchar_t c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } #endif inline int toASCIIUpper(int c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline unsigned toASCIIUpper(unsigned c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(char c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(unsigned short c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(wchar_t c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } #endif - inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(int c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; } inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; } @@ -163,7 +146,7 @@ namespace WTF { inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; } #endif inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; } - inline bool isASCIIPrintable(unsigned c) { return c >= ' ' && c <= '~'; } + } using WTF::isASCII; diff --git a/js/src/yarr/wtfbridge.h b/js/src/yarr/wtfbridge.h deleted file mode 100644 index 25a4bc5ee3d9..000000000000 --- a/js/src/yarr/wtfbridge.h +++ /dev/null @@ -1,321 +0,0 @@ -/* -*- 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 ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released - * June 12, 2009. - * - * The Initial Developer of the Original Code is - * the Mozilla Corporation. - * - * Contributor(s): - * David Mandelin - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jswtfbridge_h__ -#define jswtfbridge_h__ - -/* - * WTF compatibility layer. This file provides various type and data - * definitions for use by Yarr. - */ - -#include "jsstr.h" -#include "jsprvtd.h" -#include "jstl.h" -#include "assembler/wtf/Platform.h" -#include "assembler/jit/ExecutableAllocator.h" - -namespace JSC { namespace Yarr { - -/* - * Basic type definitions. - */ - -typedef jschar UChar; -typedef JSLinearString UString; - -class Unicode { - public: - static UChar toUpper(UChar c) { return JS_TOUPPER(c); } - static UChar toLower(UChar c) { return JS_TOLOWER(c); } -}; - -/* - * Do-nothing smart pointer classes. These have a compatible interface - * with the smart pointers used by Yarr, but they don't actually do - * reference counting. - */ -template -class RefCounted { -}; - -template -class RefPtr { - T *ptr; - public: - RefPtr(T *p) { ptr = p; } - operator bool() const { return ptr != NULL; } - const T *operator ->() const { return ptr; } - T *get() { return ptr; } -}; - -template -class PassRefPtr { - T *ptr; - public: - PassRefPtr(T *p) { ptr = p; } - operator T*() { return ptr; } -}; - -template -class PassOwnPtr { - T *ptr; - public: - PassOwnPtr(T *p) { ptr = p; } - - T *get() { return ptr; } -}; - -template -class OwnPtr { - T *ptr; - public: - OwnPtr() : ptr(NULL) { } - OwnPtr(PassOwnPtr p) : ptr(p.get()) { } - - ~OwnPtr() { - if (ptr) - js::Foreground::delete_(ptr); - } - - OwnPtr &operator=(PassOwnPtr p) { - ptr = p.get(); - return *this; - } - - T *operator ->() { return ptr; } - - T *get() { return ptr; } - - T *release() { - T *result = ptr; - ptr = NULL; - return result; - } -}; - -template -PassRefPtr adoptRef(T *p) { return PassRefPtr(p); } - -template -PassOwnPtr adoptPtr(T *p) { return PassOwnPtr(p); } - -#define WTF_MAKE_FAST_ALLOCATED - -/* - * Vector class for Yarr. This wraps js::Vector and provides all - * the API method signatures used by Yarr. - */ -template -class Vector { - public: - js::Vector impl; - public: - Vector() {} - - Vector(const Vector &v) { - // XXX yarr-oom - (void) append(v); - } - - size_t size() const { - return impl.length(); - } - - T &operator[](size_t i) { - return impl[i]; - } - - const T &operator[](size_t i) const { - return impl[i]; - } - - T &at(size_t i) { - return impl[i]; - } - - const T *begin() const { - return impl.begin(); - } - - T &last() { - return impl.back(); - } - - bool isEmpty() const { - return impl.empty(); - } - - template - void append(const U &u) { - // XXX yarr-oom - (void) impl.append(static_cast(u)); - } - - template - void append(const Vector &v) { - // XXX yarr-oom - (void) impl.append(v.impl); - } - - void insert(size_t i, const T& t) { - // XXX yarr-oom - (void) impl.insert(&impl[i], t); - } - - void remove(size_t i) { - impl.erase(&impl[i]); - } - - void clear() { - return impl.clear(); - } - - void shrink(size_t newLength) { - // XXX yarr-oom - JS_ASSERT(newLength <= impl.length()); - (void) impl.resize(newLength); - } - - void deleteAllValues() { - for (T *p = impl.begin(); p != impl.end(); ++p) - js::Foreground::delete_(*p); - } -}; - -template -class Vector > { - public: - js::Vector impl; - public: - Vector() {} - - size_t size() const { - return impl.length(); - } - - void append(T *t) { - // XXX yarr-oom - (void) impl.append(t); - } - - PassOwnPtr operator[](size_t i) { - return PassOwnPtr(impl[i]); - } - - void clear() { - for (T **p = impl.begin(); p != impl.end(); ++p) - js::Foreground::delete_(*p); - return impl.clear(); - } -}; - -template -inline void -deleteAllValues(Vector &v) { - v.deleteAllValues(); -} - -/* - * Minimal JSGlobalData. This used by Yarr to get the allocator. - */ -class JSGlobalData { - public: - ExecutableAllocator *regexAllocator; - - JSGlobalData(ExecutableAllocator *regexAllocator) - : regexAllocator(regexAllocator) { } -}; - -/* - * Sentinel value used in Yarr. - */ -const size_t notFound = size_t(-1); - - /* - * Do-nothing version of a macro used by WTF to avoid unused - * parameter warnings. - */ -#define UNUSED_PARAM(e) - -} /* namespace Yarr */ - -/* - * Replacements for std:: functions used in Yarr. We put them in - * namespace JSC::std so that they can still be called as std::X - * in Yarr. - */ -namespace std { - -/* - * windows.h defines a 'min' macro that would mangle the function - * name. - */ -#if WTF_COMPILER_MSVC -# undef min -# undef max -#endif - -template -inline T -min(T t1, T t2) -{ - return JS_MIN(t1, t2); -} - -template -inline T -max(T t1, T t2) -{ - return JS_MAX(t1, t2); -} - -template -inline void -swap(T &t1, T &t2) -{ - T tmp = t1; - t1 = t2; - t2 = tmp; -} -} /* namespace std */ - -} /* namespace JSC */ - -#endif diff --git a/js/src/yarr/RegExpJitTables.h b/js/src/yarr/yarr/RegExpJitTables.h similarity index 100% rename from js/src/yarr/RegExpJitTables.h rename to js/src/yarr/yarr/RegExpJitTables.h diff --git a/js/src/yarr/YarrSyntaxChecker.cpp b/js/src/yarr/yarr/RegexCommon.h similarity index 52% rename from js/src/yarr/YarrSyntaxChecker.cpp rename to js/src/yarr/yarr/RegexCommon.h index f36ac5a3f5bc..3ae337ea62cc 100644 --- a/js/src/yarr/YarrSyntaxChecker.cpp +++ b/js/src/yarr/yarr/RegexCommon.h @@ -1,8 +1,5 @@ -/* -*- 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) 2011 Apple Inc. All rights reserved. +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,39 +21,30 @@ * 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 ***** */ + */ -#include "YarrSyntaxChecker.h" - -#include "YarrParser.h" +#ifndef RegexCommon_h +#define RegexCommon_h namespace JSC { namespace Yarr { -class SyntaxChecker { -public: - void assertionBOL() {} - void assertionEOL() {} - void assertionWordBoundary(bool) {} - void atomPatternCharacter(UChar) {} - void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) {} - void atomCharacterClassBegin(bool = false) {} - void atomCharacterClassAtom(UChar) {} - void atomCharacterClassRange(UChar, UChar) {} - void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) {} - void atomCharacterClassEnd() {} - void atomParenthesesSubpatternBegin(bool = true) {} - void atomParentheticalAssertionBegin(bool = false) {} - void atomParenthesesEnd() {} - void atomBackReference(unsigned) {} - void quantifyAtom(unsigned, unsigned, bool) {} - void disjunction() {} +enum ErrorCode { + HitRecursionLimit = -2, + NoError = 0, + PatternTooLarge, + QuantifierOutOfOrder, + QuantifierWithoutAtom, + MissingParentheses, + ParenthesesUnmatched, + ParenthesesTypeInvalid, + CharacterClassUnmatched, + CharacterClassOutOfOrder, + CharacterClassRangeSingleChar, + EscapeUnterminated, + QuantifierTooLarge, + NumberOfErrorCodes }; -ErrorCode checkSyntax(const UString& pattern) -{ - SyntaxChecker syntaxChecker; - return parse(syntaxChecker, pattern); -} +}} -}} // JSC::YARR +#endif diff --git a/js/src/yarr/YarrPattern.cpp b/js/src/yarr/yarr/RegexCompiler.cpp similarity index 52% rename from js/src/yarr/YarrPattern.cpp rename to js/src/yarr/yarr/RegexCompiler.cpp index 10b7d8911987..9b60cbd4a78b 100644 --- a/js/src/yarr/YarrPattern.cpp +++ b/js/src/yarr/yarr/RegexCompiler.cpp @@ -1,9 +1,5 @@ -/* -*- 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 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,13 +21,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 ***** */ + */ -#include "YarrPattern.h" +#include "jsinttypes.h" +#include "RegexCompiler.h" -#include "Yarr.h" -#include "YarrParser.h" +#include "RegexPattern.h" using namespace WTF; @@ -39,6 +34,12 @@ namespace JSC { namespace Yarr { #include "RegExpJitTables.h" +#if WTF_CPU_SPARC +#define BASE_FRAME_SIZE 24 +#else +#define BASE_FRAME_SIZE 0 +#endif + class CharacterClassConstructor { public: CharacterClassConstructor(bool isCaseInsensitive = false) @@ -56,13 +57,13 @@ public: void append(const CharacterClass* other) { - for (size_t i = 0; i < other->m_matches.size(); ++i) + for (size_t i = 0; i < other->m_matches.length(); ++i) addSorted(m_matches, other->m_matches[i]); - for (size_t i = 0; i < other->m_ranges.size(); ++i) + for (size_t i = 0; i < other->m_ranges.length(); ++i) addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end); - for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i) + for (size_t i = 0; i < other->m_matchesUnicode.length(); ++i) addSorted(m_matchesUnicode, other->m_matchesUnicode[i]); - for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i) + for (size_t i = 0; i < other->m_rangesUnicode.length(); ++i) addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end); } @@ -100,18 +101,18 @@ public: { if (lo <= 0x7f) { char asciiLo = lo; - char asciiHi = std::min(hi, (UChar)0x7f); + char asciiHi = JS_MIN(hi, (UChar)0x7f); addSortedRange(m_ranges, lo, asciiHi); if (m_isCaseInsensitive) { if ((asciiLo <= 'Z') && (asciiHi >= 'A')) - addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A')); + addSortedRange(m_ranges, JS_MAX(asciiLo, 'A')+('a'-'A'), JS_MIN(asciiHi, 'Z')+('a'-'A')); if ((asciiLo <= 'z') && (asciiHi >= 'a')) - addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a')); + addSortedRange(m_ranges, JS_MAX(asciiLo, 'a')+('A'-'a'), JS_MIN(asciiHi, 'z')+('A'-'a')); } } if (hi >= 0x80) { - uint32_t unicodeCurr = std::max(lo, (UChar)0x80); + uint32 unicodeCurr = JS_MAX(lo, (UChar)0x80); addSortedRange(m_rangesUnicode, unicodeCurr, hi); if (m_isCaseInsensitive) { @@ -121,7 +122,7 @@ public: // (if so we won't re-enter the loop, since the loop condition above // will definitely fail) - but this does mean we cannot use a UChar // to represent unicodeCurr, we must use a 32-bit value instead. - ASSERT(unicodeCurr <= 0xffff); + JS_ASSERT(unicodeCurr <= 0xffff); if (isUnicodeUpper(unicodeCurr)) { UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr); @@ -144,7 +145,8 @@ public: CharacterClass* charClass() { - CharacterClass* characterClass = js::OffTheBooks::new_(PassRefPtr(0)); + // FIXME: bug 574459 -- no NULL check + CharacterClass* characterClass = js::OffTheBooks::new_((CharacterClassTable*)NULL); characterClass->m_matches.append(m_matches); characterClass->m_ranges.append(m_ranges); @@ -157,10 +159,12 @@ public: } private: - void addSorted(Vector& matches, UChar ch) + typedef js::Vector UChars; + typedef js::Vector CharacterRanges; + void addSorted(UChars& matches, UChar ch) { unsigned pos = 0; - unsigned range = matches.size(); + unsigned range = matches.length(); // binary chop, find position to insert char. while (range) { @@ -177,15 +181,15 @@ private: } } - if (pos == matches.size()) + if (pos == matches.length()) matches.append(ch); else - matches.insert(pos, ch); + matches.insert(matches.begin() + pos, ch); } - void addSortedRange(Vector& ranges, UChar lo, UChar hi) + void addSortedRange(CharacterRanges& ranges, UChar lo, UChar hi) { - unsigned end = ranges.size(); + unsigned end = ranges.length(); // Simple linear scan - I doubt there are that many ranges anyway... // feel free to fix this with something faster (eg binary chop). @@ -197,7 +201,7 @@ private: ranges[i].begin = lo; return; } - ranges.insert(i, CharacterRange(lo, hi)); + ranges.insert(ranges.begin() + i, CharacterRange(lo, hi)); return; } // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining @@ -205,17 +209,17 @@ private: // end of the last range they concatenate, which is just as good. if (lo <= (ranges[i].end + 1)) { // found an intersect! we'll replace this entry in the array. - ranges[i].begin = std::min(ranges[i].begin, lo); - ranges[i].end = std::max(ranges[i].end, hi); + ranges[i].begin = JS_MIN(ranges[i].begin, lo); + ranges[i].end = JS_MAX(ranges[i].end, hi); // now check if the new range can subsume any subsequent ranges. unsigned next = i+1; // each iteration of the loop we will either remove something from the list, or break the loop. - while (next < ranges.size()) { + while (next < ranges.length()) { if (ranges[next].begin <= (ranges[i].end + 1)) { // the next entry now overlaps / concatenates this one. - ranges[i].end = std::max(ranges[i].end, ranges[next].end); - ranges.remove(next); + ranges[i].end = JS_MAX(ranges[i].end, ranges[next].end); + ranges.erase(ranges.begin() + next); } else break; } @@ -230,131 +234,21 @@ private: bool m_isCaseInsensitive; - Vector m_matches; - Vector m_ranges; - Vector m_matchesUnicode; - Vector m_rangesUnicode; + UChars m_matches; + CharacterRanges m_ranges; + UChars m_matchesUnicode; + CharacterRanges m_rangesUnicode; }; -struct BeginCharHelper { - BeginCharHelper(Vector* beginChars, bool isCaseInsensitive = false) - : m_beginChars(beginChars) - , m_isCaseInsensitive(isCaseInsensitive) - {} - - void addBeginChar(BeginChar beginChar, Vector* hotTerms, QuantifierType quantityType, unsigned quantityCount) - { - if (quantityType == QuantifierFixedCount && quantityCount > 1) { - // We duplicate the first found character if the quantity of the term is more than one. eg.: /a{3}/ - beginChar.value |= beginChar.value << 16; - beginChar.mask |= beginChar.mask << 16; - addCharacter(beginChar); - } else if (quantityType == QuantifierFixedCount && quantityCount == 1 && hotTerms->size()) - // In case of characters with fixed quantifier we should check the next character as well. - linkHotTerms(beginChar, hotTerms); - else - // In case of greedy matching the next character checking is unnecessary therefore we just store - // the first character. - addCharacter(beginChar); - } - - // Merge two following BeginChars in the vector to reduce the number of character checks. - void merge(unsigned size) - { - for (unsigned i = 0; i < size; i++) { - BeginChar* curr = &m_beginChars->at(i); - BeginChar* next = &m_beginChars->at(i + 1); - - // If the current and the next size of value is different we should skip the merge process - // because the 16bit and 32bit values are unmergable. - if (curr->value <= 0xFFFF && next->value > 0xFFFF) - continue; - - unsigned diff = curr->value ^ next->value; - - curr->mask |= diff; - curr->value |= curr->mask; - - m_beginChars->remove(i + 1); - size--; - } - } - -private: - void addCharacter(BeginChar beginChar) - { - unsigned pos = 0; - unsigned range = m_beginChars->size(); - - // binary chop, find position to insert char. - while (range) { - unsigned index = range >> 1; - - int val = m_beginChars->at(pos+index).value - beginChar.value; - if (!val) - return; - if (val < 0) - range = index; - else { - pos += (index+1); - range -= (index+1); - } - } - - if (pos == m_beginChars->size()) - m_beginChars->append(beginChar); - else - m_beginChars->insert(pos, beginChar); - } - - // Create BeginChar objects by appending each terms from a hotTerms vector to an existing BeginChar object. - void linkHotTerms(BeginChar beginChar, Vector* hotTerms) - { - for (unsigned i = 0; i < hotTerms->size(); i++) { - PatternTerm hotTerm = hotTerms->at(i).term; - ASSERT(hotTerm.type == PatternTerm::TypePatternCharacter); - - UChar characterNext = hotTerm.patternCharacter; - - // Append a character to an existing BeginChar object. - if (characterNext <= 0x7f) { - unsigned mask = 0; - - if (m_isCaseInsensitive && isASCIIAlpha(characterNext)) { - mask = 32; - characterNext = toASCIILower(characterNext); - } - - addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask | (mask << 16))); - } else { - UChar upper, lower; - if (m_isCaseInsensitive && ((upper = Unicode::toUpper(characterNext)) != (lower = Unicode::toLower(characterNext)))) { - addCharacter(BeginChar(beginChar.value | (upper << 16), beginChar.mask)); - addCharacter(BeginChar(beginChar.value | (lower << 16), beginChar.mask)); - } else - addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask)); - } - } - } - - Vector* m_beginChars; - bool m_isCaseInsensitive; -}; - -class YarrPatternConstructor { +class RegexPatternConstructor { public: - YarrPatternConstructor(YarrPattern& pattern) + RegexPatternConstructor(RegexPattern& pattern) : m_pattern(pattern) , m_characterClassConstructor(pattern.m_ignoreCase) - , m_beginCharHelper(&pattern.m_beginChars, pattern.m_ignoreCase) - , m_invertParentheticalAssertion(false) { - m_pattern.m_body = js::OffTheBooks::new_(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); } - ~YarrPatternConstructor() + ~RegexPatternConstructor() { } @@ -362,19 +256,10 @@ public: { m_pattern.reset(); m_characterClassConstructor.reset(); - - m_pattern.m_body = js::OffTheBooks::new_(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); } void assertionBOL() { - if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) { - m_alternative->m_startsWithBOL = true; - m_alternative->m_containsBOL = true; - m_pattern.m_containsBOL = true; - } m_alternative->m_terms.append(PatternTerm::BOL()); } void assertionEOL() @@ -433,7 +318,7 @@ public: void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert) { - ASSERT(classID != NewlineClassID); + JS_ASSERT(classID != NewlineClassID); switch (classID) { case DigitClassID: @@ -449,7 +334,7 @@ public: break; default: - ASSERT_NOT_REACHED(); + JS_NOT_REACHED("Invalid character class."); } } @@ -466,56 +351,36 @@ public: if (capture) m_pattern.m_numSubpatterns++; + // FIXME: bug 574459 -- no NULL check PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative); m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, false)); + m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture)); m_alternative = parenthesesDisjunction->addNewAlternative(); } void atomParentheticalAssertionBegin(bool invert = false) { + // FIXME: bug 574459 -- no NULL check PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative); m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, false, invert)); + m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert)); m_alternative = parenthesesDisjunction->addNewAlternative(); - m_invertParentheticalAssertion = invert; } void atomParenthesesEnd() { - ASSERT(m_alternative->m_parent); - ASSERT(m_alternative->m_parent->m_parent); - - PatternDisjunction* parenthesesDisjunction = m_alternative->m_parent; + JS_ASSERT(m_alternative->m_parent); + JS_ASSERT(m_alternative->m_parent->m_parent); m_alternative = m_alternative->m_parent->m_parent; - - PatternTerm& lastTerm = m_alternative->lastTerm(); - - unsigned numParenAlternatives = parenthesesDisjunction->m_alternatives.size(); - unsigned numBOLAnchoredAlts = 0; - - for (unsigned i = 0; i < numParenAlternatives; i++) { - // Bubble up BOL flags - if (parenthesesDisjunction->m_alternatives[i]->m_startsWithBOL) - numBOLAnchoredAlts++; - } - - if (numBOLAnchoredAlts) { - m_alternative->m_containsBOL = true; - // If all the alternatives in parens start with BOL, then so does this one - if (numBOLAnchoredAlts == numParenAlternatives) - m_alternative->m_startsWithBOL = true; - } - - lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; - m_invertParentheticalAssertion = false; + + m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; } void atomBackReference(unsigned subpatternId) { - ASSERT(subpatternId); + JS_ASSERT(subpatternId); m_pattern.m_containsBackreferences = true; - m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId); + m_pattern.m_maxBackReference = JS_MAX(m_pattern.m_maxBackReference, subpatternId); if (subpatternId > m_pattern.m_numSubpatterns) { m_alternative->m_terms.append(PatternTerm::ForwardReference()); @@ -523,14 +388,14 @@ public: } PatternAlternative* currentAlternative = m_alternative; - ASSERT(currentAlternative); + JS_ASSERT(currentAlternative); // Note to self: if we waited until the AST was baked, we could also remove forwards refs while ((currentAlternative = currentAlternative->m_parent->m_parent)) { PatternTerm& term = currentAlternative->lastTerm(); - ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); + JS_ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); - if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.capture() && (subpatternId == term.parentheses.subpatternId)) { + if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) { m_alternative->m_terms.append(PatternTerm::ForwardReference()); return; } @@ -539,43 +404,37 @@ public: m_alternative->m_terms.append(PatternTerm(subpatternId)); } - // deep copy the argument disjunction. If filterStartsWithBOL is true, - // skip alternatives with m_startsWithBOL set true. - PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false) + PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction) { - PatternDisjunction* newDisjunction = 0; - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + // FIXME: bug 574459 -- no NULL check + PatternDisjunction* newDisjunction = js::OffTheBooks::new_(); + + newDisjunction->m_parent = disjunction->m_parent; + for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) { PatternAlternative* alternative = disjunction->m_alternatives[alt]; - if (!filterStartsWithBOL || !alternative->m_startsWithBOL) { - if (!newDisjunction) { - newDisjunction = new PatternDisjunction(); - newDisjunction->m_parent = disjunction->m_parent; - } - PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) - newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL)); - } + PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); + for (unsigned i = 0; i < alternative->m_terms.length(); ++i) + newAlternative->m_terms.append(copyTerm(alternative->m_terms[i])); } - - if (newDisjunction) - m_pattern.m_disjunctions.append(newDisjunction); + + m_pattern.m_disjunctions.append(newDisjunction); return newDisjunction; } - - PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false) + + PatternTerm copyTerm(PatternTerm& term) { if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion)) return PatternTerm(term); - + PatternTerm termCopy = term; - termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL); + termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction); return termCopy; } - + void quantifyAtom(unsigned min, unsigned max, bool greedy) { - ASSERT(min <= max); - ASSERT(m_alternative->m_terms.size()); + JS_ASSERT(min <= max); + JS_ASSERT(m_alternative->m_terms.length()); if (!max) { m_alternative->removeLastTerm(); @@ -583,8 +442,8 @@ public: } PatternTerm& term = m_alternative->lastTerm(); - ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); - ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); + JS_ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); + JS_ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); // For any assertion with a zero minimum, not matching is valid and has no effect, // remove it. Otherwise, we need to match as least once, but there is no point @@ -605,7 +464,7 @@ public: term.quantify(min, QuantifierFixedCount); m_alternative->m_terms.append(copyTerm(term)); // NOTE: this term is interesting from an analysis perspective, in that it can be ignored..... - m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); + m_alternative->lastTerm().quantify((max == UINT_MAX) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern) m_alternative->lastTerm().parentheses.isCopy = true; } @@ -616,12 +475,26 @@ public: m_alternative = m_alternative->m_parent->addNewAlternative(); } + void regexBegin() + { + // FIXME: bug 574459 -- no NULL check + m_pattern.m_body = js::OffTheBooks::new_(); + m_alternative = m_pattern.m_body->addNewAlternative(); + m_pattern.m_disjunctions.append(m_pattern.m_body); + } + void regexEnd() + { + } + void regexError() + { + } + unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition) { alternative->m_hasFixedSize = true; unsigned currentInputPosition = initialInputPosition; - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { + for (unsigned i = 0; i < alternative->m_terms.length(); ++i) { PatternTerm& term = alternative->m_terms[i]; switch (term.type) { @@ -634,7 +507,7 @@ public: case PatternTerm::TypeBackReference: term.inputPosition = currentInputPosition; term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoBackReference; alternative->m_hasFixedSize = false; break; @@ -645,7 +518,7 @@ public: term.inputPosition = currentInputPosition; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoPatternCharacter; alternative->m_hasFixedSize = false; } else currentInputPosition += term.quantityCount; @@ -655,7 +528,7 @@ public: term.inputPosition = currentInputPosition; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoCharacterClass; alternative->m_hasFixedSize = false; } else currentInputPosition += term.quantityCount; @@ -666,20 +539,20 @@ public: term.frameLocation = currentCallFrameSize; if (term.quantityCount == 1 && !term.parentheses.isCopy) { if (term.quantityType != QuantifierFixedCount) - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesOnce; currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition); // If quantity is fixed, then pre-check its minimum size. if (term.quantityType == QuantifierFixedCount) currentInputPosition += term.parentheses.disjunction->m_minimumSize; term.inputPosition = currentInputPosition; } else if (term.parentheses.isTerminal) { - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesTerminal; currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition); term.inputPosition = currentInputPosition; } else { term.inputPosition = currentInputPosition; setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition); - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParentheses; } // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length. alternative->m_hasFixedSize = false; @@ -688,7 +561,7 @@ public: case PatternTerm::TypeParentheticalAssertion: term.inputPosition = currentInputPosition; term.frameLocation = currentCallFrameSize; - currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition); + currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + RegexStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition); break; } } @@ -699,23 +572,23 @@ public: unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition) { - if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1)) - initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative; + if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.length() > 1)) + initialCallFrameSize += RegexStackSpaceForBackTrackInfoAlternative; unsigned minimumInputSize = UINT_MAX; unsigned maximumCallFrameSize = 0; bool hasFixedSize = true; - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) { PatternAlternative* alternative = disjunction->m_alternatives[alt]; unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition); - minimumInputSize = std::min(minimumInputSize, alternative->m_minimumSize); - maximumCallFrameSize = std::max(maximumCallFrameSize, currentAlternativeCallFrameSize); + minimumInputSize = JS_MIN(minimumInputSize, alternative->m_minimumSize); + maximumCallFrameSize = JS_MAX(maximumCallFrameSize, currentAlternativeCallFrameSize); hasFixedSize &= alternative->m_hasFixedSize; } - ASSERT(minimumInputSize != UINT_MAX); - ASSERT(maximumCallFrameSize >= initialCallFrameSize); + JS_ASSERT(minimumInputSize != UINT_MAX); + JS_ASSERT(maximumCallFrameSize >= initialCallFrameSize); disjunction->m_hasFixedSize = hasFixedSize; disjunction->m_minimumSize = minimumInputSize; @@ -725,14 +598,13 @@ public: void setupOffsets() { - setupDisjunctionOffsets(m_pattern.m_body, 0, 0); + setupDisjunctionOffsets(m_pattern.m_body, BASE_FRAME_SIZE, 0); } // This optimization identifies sets of parentheses that we will never need to backtrack. // In these cases we do not need to store state from prior iterations. // We can presently avoid backtracking for: - // * where the parens are at the end of the regular expression (last term in any of the - // alternatives of the main body disjunction). + // * a set of parens at the end of the regular expression (last term in any of the alternatives of the main body disjunction). // * where the parens are non-capturing, and quantified unbounded greedy (*). // * where the parens do not contain any capturing subpatterns. void checkForTerminalParentheses() @@ -742,239 +614,57 @@ public: if (m_pattern.m_numSubpatterns) return; - Vector& alternatives = m_pattern.m_body->m_alternatives; - for (size_t i = 0; i < alternatives.size(); ++i) { - Vector& terms = alternatives[i]->m_terms; - if (terms.size()) { - PatternTerm& term = terms.last(); + js::Vector& alternatives = m_pattern.m_body->m_alternatives; + for (unsigned i =0; i < alternatives.length(); ++i) { + js::Vector& terms = alternatives[i]->m_terms; + if (terms.length()) { + PatternTerm& term = terms.back(); if (term.type == PatternTerm::TypeParenthesesSubpattern && term.quantityType == QuantifierGreedy - && term.quantityCount == quantifyInfinite + && term.quantityCount == UINT_MAX && !term.capture()) term.parentheses.isTerminal = true; } } } - void optimizeBOL() - { - // Look for expressions containing beginning of line (^) anchoring and unroll them. - // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops - // This code relies on the parsing code tagging alternatives with m_containsBOL and - // m_startsWithBOL and rolling those up to containing alternatives. - // At this point, this is only valid for non-multiline expressions. - PatternDisjunction* disjunction = m_pattern.m_body; - - if (!m_pattern.m_containsBOL || m_pattern.m_multiline) - return; - - PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true); - - // Set alternatives in disjunction to "onceThrough" - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) - disjunction->m_alternatives[alt]->setOnceThrough(); - - if (loopDisjunction) { - // Move alternatives from loopDisjunction to disjunction - for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt) - disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]); - - loopDisjunction->m_alternatives.clear(); - } - } - - // This function collects the terms which are potentially matching the first number of depth characters in the result. - // If this function returns false then it found at least one term which makes the beginning character - // look-up optimization inefficient. - bool setupDisjunctionBeginTerms(PatternDisjunction* disjunction, Vector* beginTerms, unsigned depth) - { - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { - PatternAlternative* alternative = disjunction->m_alternatives[alt]; - - if (!setupAlternativeBeginTerms(alternative, beginTerms, 0, depth)) - return false; - } - - return true; - } - - bool setupAlternativeBeginTerms(PatternAlternative* alternative, Vector* beginTerms, unsigned termIndex, unsigned depth) - { - bool checkNext = true; - unsigned numTerms = alternative->m_terms.size(); - - while (checkNext && termIndex < numTerms) { - PatternTerm term = alternative->m_terms[termIndex]; - checkNext = false; - - switch (term.type) { - case PatternTerm::TypeAssertionBOL: - case PatternTerm::TypeAssertionEOL: - case PatternTerm::TypeAssertionWordBoundary: - return false; - - case PatternTerm::TypeBackReference: - case PatternTerm::TypeForwardReference: - return false; - - case PatternTerm::TypePatternCharacter: - if (termIndex != numTerms - 1) { - beginTerms->append(TermChain(term)); - termIndex++; - checkNext = true; - } else if (term.quantityType == QuantifierFixedCount) { - beginTerms->append(TermChain(term)); - if (depth < 2 && termIndex < numTerms - 1 && term.quantityCount == 1) - if (!setupAlternativeBeginTerms(alternative, &beginTerms->last().hotTerms, termIndex + 1, depth + 1)) - return false; - } - - break; - - case PatternTerm::TypeCharacterClass: - return false; - - case PatternTerm::TypeParentheticalAssertion: - if (term.invert()) - return false; - - case PatternTerm::TypeParenthesesSubpattern: - if (term.quantityType != QuantifierFixedCount) { - if (termIndex == numTerms - 1) - break; - - termIndex++; - checkNext = true; - } - - if (!setupDisjunctionBeginTerms(term.parentheses.disjunction, beginTerms, depth)) - return false; - - break; - } - } - - return true; - } - - void setupBeginChars() - { - Vector beginTerms; - bool containsFixedCharacter = false; - - if ((!m_pattern.m_body->m_hasFixedSize || m_pattern.m_body->m_alternatives.size() > 1) - && setupDisjunctionBeginTerms(m_pattern.m_body, &beginTerms, 0)) { - unsigned size = beginTerms.size(); - - // If we haven't collected any terms we should abort the preparation of beginning character look-up optimization. - if (!size) - return; - - m_pattern.m_containsBeginChars = true; - - for (unsigned i = 0; i < size; i++) { - PatternTerm term = beginTerms[i].term; - - // We have just collected PatternCharacter terms, other terms are not allowed. - ASSERT(term.type == PatternTerm::TypePatternCharacter); - - if (term.quantityType == QuantifierFixedCount) - containsFixedCharacter = true; - - UChar character = term.patternCharacter; - unsigned mask = 0; - - if (character <= 0x7f) { - if (m_pattern.m_ignoreCase && isASCIIAlpha(character)) { - mask = 32; - character = toASCIILower(character); - } - - m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } else { - UChar upper, lower; - if (m_pattern.m_ignoreCase && ((upper = Unicode::toUpper(character)) != (lower = Unicode::toLower(character)))) { - m_beginCharHelper.addBeginChar(BeginChar(upper, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - m_beginCharHelper.addBeginChar(BeginChar(lower, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } else - m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } - } - - // If the pattern doesn't contain terms with fixed quantifiers then the beginning character look-up optimization is inefficient. - if (!containsFixedCharacter) { - m_pattern.m_containsBeginChars = false; - return; - } - - size = m_pattern.m_beginChars.size(); - - if (size > 2) - m_beginCharHelper.merge(size - 1); - else if (size <= 1) - m_pattern.m_containsBeginChars = false; - } - } - private: - YarrPattern& m_pattern; + RegexPattern& m_pattern; PatternAlternative* m_alternative; CharacterClassConstructor m_characterClassConstructor; - BeginCharHelper m_beginCharHelper; bool m_invertCharacterClass; - bool m_invertParentheticalAssertion; }; -ErrorCode YarrPattern::compile(const UString& patternString) -{ - YarrPatternConstructor constructor(*this); - if (ErrorCode error = parse(constructor, patternString)) +int compileRegex(const UString& patternString, RegexPattern& pattern) +{ + RegexPatternConstructor constructor(pattern); + + if (int error = parse(constructor, patternString)) return error; // If the pattern contains illegal backreferences reset & reparse. // Quoting Netscape's "What's new in JavaScript 1.2", // "Note: if the number of left parentheses is less than the number specified // in \#, the \# is taken as an octal escape as described in the next row." - if (containsIllegalBackReference()) { - unsigned numSubpatterns = m_numSubpatterns; + if (pattern.containsIllegalBackReference()) { + unsigned numSubpatterns = pattern.m_numSubpatterns; constructor.reset(); -#if !ASSERT_DISABLED - ErrorCode error = +#ifdef DEBUG + int error = #endif parse(constructor, patternString, numSubpatterns); - ASSERT(!error); - ASSERT(numSubpatterns == m_numSubpatterns); + JS_ASSERT(!error); + JS_ASSERT(numSubpatterns == pattern.m_numSubpatterns); } constructor.checkForTerminalParentheses(); - constructor.optimizeBOL(); - constructor.setupOffsets(); - constructor.setupBeginChars(); - return NoError; + return 0; } -YarrPattern::YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error) - : m_ignoreCase(ignoreCase) - , m_multiline(multiline) - , m_containsBackreferences(false) - , m_containsBeginChars(false) - , m_containsBOL(false) - , m_numSubpatterns(0) - , m_maxBackReference(0) - , newlineCached(0) - , digitsCached(0) - , spacesCached(0) - , wordcharCached(0) - , nondigitsCached(0) - , nonspacesCached(0) - , nonwordcharCached(0) -{ - *error = compile(pattern); -} } } diff --git a/js/src/yarr/YarrSyntaxChecker.h b/js/src/yarr/yarr/RegexCompiler.h similarity index 74% rename from js/src/yarr/YarrSyntaxChecker.h rename to js/src/yarr/yarr/RegexCompiler.h index 87f2ed5093b0..307c15866e59 100644 --- a/js/src/yarr/YarrSyntaxChecker.h +++ b/js/src/yarr/yarr/RegexCompiler.h @@ -1,8 +1,5 @@ -/* -*- 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) 2011 Apple Inc. All rights reserved. +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,20 +21,18 @@ * 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 YarrSyntaxChecker_h -#define YarrSyntaxChecker_h +#ifndef RegexCompiler_h +#define RegexCompiler_h -#include "wtfbridge.h" -#include "YarrParser.h" +#include "RegexParser.h" +#include "RegexPattern.h" namespace JSC { namespace Yarr { -ErrorCode checkSyntax(const UString& pattern); +int compileRegex(const UString& patternString, RegexPattern& pattern); -}} // JSC::YARR - -#endif // YarrSyntaxChecker_h +} } // namespace JSC::Yarr +#endif // RegexCompiler_h diff --git a/js/src/yarr/yarr/RegexJIT.cpp b/js/src/yarr/yarr/RegexJIT.cpp new file mode 100644 index 000000000000..1571c35b7125 --- /dev/null +++ b/js/src/yarr/yarr/RegexJIT.cpp @@ -0,0 +1,1589 @@ +/* + * Copyright (C) 2009 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. + */ + +#include "RegexJIT.h" + +#if ENABLE_ASSEMBLER + +#include "assembler/assembler/LinkBuffer.h" +#include "assembler/assembler/MacroAssembler.h" +#include "RegexCompiler.h" + +#include "yarr/pcre/pcre.h" // temporary, remove when fallback is removed. + +using namespace WTF; + +namespace JSC { namespace Yarr { + +class JSGlobalData; + +class RegexGenerator : private MacroAssembler { + friend void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); + +#if WTF_CPU_ARM + static const RegisterID input = ARMRegisters::r0; + static const RegisterID index = ARMRegisters::r1; + static const RegisterID length = ARMRegisters::r2; + static const RegisterID output = ARMRegisters::r4; + + static const RegisterID regT0 = ARMRegisters::r5; + static const RegisterID regT1 = ARMRegisters::r6; + + static const RegisterID returnRegister = ARMRegisters::r0; +#elif WTF_CPU_MIPS + static const RegisterID input = MIPSRegisters::a0; + static const RegisterID index = MIPSRegisters::a1; + static const RegisterID length = MIPSRegisters::a2; + static const RegisterID output = MIPSRegisters::a3; + + static const RegisterID regT0 = MIPSRegisters::t4; + static const RegisterID regT1 = MIPSRegisters::t5; + + static const RegisterID returnRegister = MIPSRegisters::v0; +#elif WTF_CPU_SPARC + static const RegisterID input = SparcRegisters::i0; + static const RegisterID index = SparcRegisters::i1; + static const RegisterID length = SparcRegisters::i2; + static const RegisterID output = SparcRegisters::i3; + + static const RegisterID regT0 = SparcRegisters::i4; + static const RegisterID regT1 = SparcRegisters::i5; + + static const RegisterID returnRegister = SparcRegisters::i0; +#elif WTF_CPU_X86 + static const RegisterID input = X86Registers::eax; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::ecx; + static const RegisterID output = X86Registers::edi; + + static const RegisterID regT0 = X86Registers::ebx; + static const RegisterID regT1 = X86Registers::esi; + + static const RegisterID returnRegister = X86Registers::eax; +#elif WTF_CPU_X86_64 +#if WTF_PLATFORM_WIN + static const RegisterID input = X86Registers::ecx; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::r8; + static const RegisterID output = X86Registers::r9; +#else + static const RegisterID input = X86Registers::edi; + static const RegisterID index = X86Registers::esi; + static const RegisterID length = X86Registers::edx; + static const RegisterID output = X86Registers::ecx; +#endif + + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::ebx; + + static const RegisterID returnRegister = X86Registers::eax; +#endif + + void optimizeAlternative(PatternAlternative* alternative) + { + if (!alternative->m_terms.length()) + return; + + for (unsigned i = 0; i < alternative->m_terms.length() - 1; ++i) { + PatternTerm& term = alternative->m_terms[i]; + PatternTerm& nextTerm = alternative->m_terms[i + 1]; + + if ((term.type == PatternTerm::TypeCharacterClass) + && (term.quantityType == QuantifierFixedCount) + && (nextTerm.type == PatternTerm::TypePatternCharacter) + && (nextTerm.quantityType == QuantifierFixedCount)) { + PatternTerm termCopy = term; + alternative->m_terms[i] = nextTerm; + alternative->m_terms[i + 1] = termCopy; + } + } + } + + void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) + { + do { + // pick which range we're going to generate + int which = count >> 1; + char lo = ranges[which].begin; + char hi = ranges[which].end; + + // check if there are any ranges or matches below lo. If not, just jl to failure - + // if there is anything else to check, check that first, if it falls through jmp to failure. + if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { + Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); + + // generate code for all ranges before this one + if (which) + matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); + + while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { + matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex]))); + ++*matchIndex; + } + failures.append(jump()); + + loOrAbove.link(this); + } else if (which) { + Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); + + matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); + failures.append(jump()); + + loOrAbove.link(this); + } else + failures.append(branch32(LessThan, character, Imm32((unsigned short)lo))); + + while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) + ++*matchIndex; + + matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi))); + // fall through to here, the value is above hi. + + // shuffle along & loop around if there are any more matches to handle. + unsigned next = which + 1; + ranges += next; + count -= next; + } while (count); + } + + void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass) + { + if (charClass->m_table) { + ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table)); + matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry)); + return; + } + Jump unicodeFail; + if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) { + Jump isAscii = branch32(LessThanOrEqual, character, Imm32(0x7f)); + + if (charClass->m_matchesUnicode.length()) { + for (unsigned i = 0; i < charClass->m_matchesUnicode.length(); ++i) { + UChar ch = charClass->m_matchesUnicode[i]; + matchDest.append(branch32(Equal, character, Imm32(ch))); + } + } + + if (charClass->m_rangesUnicode.length()) { + for (unsigned i = 0; i < charClass->m_rangesUnicode.length(); ++i) { + UChar lo = charClass->m_rangesUnicode[i].begin; + UChar hi = charClass->m_rangesUnicode[i].end; + + Jump below = branch32(LessThan, character, Imm32(lo)); + matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi))); + below.link(this); + } + } + + unicodeFail = jump(); + isAscii.link(this); + } + + if (charClass->m_ranges.length()) { + unsigned matchIndex = 0; + JumpList failures; + matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.length(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.length()); + while (matchIndex < charClass->m_matches.length()) + matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++]))); + + failures.link(this); + } else if (charClass->m_matches.length()) { + // optimization: gather 'a','A' etc back together, can mask & test once. + js::Vector matchesAZaz; + + for (unsigned i = 0; i < charClass->m_matches.length(); ++i) { + char ch = charClass->m_matches[i]; + if (m_pattern.m_ignoreCase) { + if (isASCIILower(ch)) { + matchesAZaz.append(ch); + continue; + } + if (isASCIIUpper(ch)) + continue; + } + matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch))); + } + + if (unsigned countAZaz = matchesAZaz.length()) { + or32(Imm32(32), character); + for (unsigned i = 0; i < countAZaz; ++i) + matchDest.append(branch32(Equal, character, Imm32(matchesAZaz[i]))); + } + } + + if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) + unicodeFail.link(this); + } + + // Jumps if input not available; will have (incorrectly) incremented already! + Jump jumpIfNoAvailableInput(unsigned countToCheck) + { + add32(Imm32(countToCheck), index); + return branch32(Above, index, length); + } + + Jump jumpIfAvailableInput(unsigned countToCheck) + { + add32(Imm32(countToCheck), index); + return branch32(BelowOrEqual, index, length); + } + + Jump checkInput() + { + return branch32(BelowOrEqual, index, length); + } + + Jump atEndOfInput() + { + return branch32(Equal, index, length); + } + + Jump notAtEndOfInput() + { + return branch32(NotEqual, index, length); + } + + Jump jumpIfCharEquals(UChar ch, int inputPosition) + { + return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); + } + + Jump jumpIfCharNotEquals(UChar ch, int inputPosition) + { + return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); + } + + void readCharacter(int inputPosition, RegisterID reg) + { + load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg); + } + + void storeToFrame(RegisterID reg, unsigned frameLocation) + { + poke(reg, frameLocation); + } + + void storeToFrame(Imm32 imm, unsigned frameLocation) + { + poke(imm, frameLocation); + } + + DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) + { + return storePtrWithPatch(ImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*))); + } + + void loadFromFrame(unsigned frameLocation, RegisterID reg) + { + peek(reg, frameLocation); + } + + void loadFromFrameAndJump(unsigned frameLocation) + { + jump(Address(stackPointerRegister, frameLocation * sizeof(void*))); + } + + struct AlternativeBacktrackRecord { + DataLabelPtr dataLabel; + Label backtrackLocation; + + AlternativeBacktrackRecord(DataLabelPtr dataLabel, Label backtrackLocation) + : dataLabel(dataLabel) + , backtrackLocation(backtrackLocation) + { + } + }; + + struct TermGenerationState { + TermGenerationState(PatternDisjunction* disjunction, unsigned checkedTotal) + : disjunction(disjunction) + , checkedTotal(checkedTotal) + { + } + + void resetAlternative() + { + isBackTrackGenerated = false; + alt = 0; + } + bool alternativeValid() + { + return alt < disjunction->m_alternatives.length(); + } + void nextAlternative() + { + ++alt; + } + PatternAlternative* alternative() + { + return disjunction->m_alternatives[alt]; + } + + void resetTerm() + { + ASSERT(alternativeValid()); + t = 0; + } + bool termValid() + { + ASSERT(alternativeValid()); + return t < alternative()->m_terms.length(); + } + void nextTerm() + { + ASSERT(alternativeValid()); + ++t; + } + PatternTerm& term() + { + ASSERT(alternativeValid()); + return alternative()->m_terms[t]; + } + bool isLastTerm() + { + ASSERT(alternativeValid()); + return (t + 1) == alternative()->m_terms.length(); + } + bool isMainDisjunction() + { + return !disjunction->m_parent; + } + + PatternTerm& lookaheadTerm() + { + ASSERT(alternativeValid()); + ASSERT((t + 1) < alternative()->m_terms.length()); + return alternative()->m_terms[t + 1]; + } + bool isSinglePatternCharacterLookaheadTerm() + { + ASSERT(alternativeValid()); + return ((t + 1) < alternative()->m_terms.length()) + && (lookaheadTerm().type == PatternTerm::TypePatternCharacter) + && (lookaheadTerm().quantityType == QuantifierFixedCount) + && (lookaheadTerm().quantityCount == 1); + } + + int inputOffset() + { + return term().inputPosition - checkedTotal; + } + + void jumpToBacktrack(Jump jump, MacroAssembler* masm) + { + if (isBackTrackGenerated) + jump.linkTo(backtrackLabel, masm); + else + backTrackJumps.append(jump); + } + void jumpToBacktrack(JumpList& jumps, MacroAssembler* masm) + { + if (isBackTrackGenerated) + jumps.linkTo(backtrackLabel, masm); + else + backTrackJumps.append(jumps); + } + bool plantJumpToBacktrackIfExists(MacroAssembler* masm) + { + if (isBackTrackGenerated) { + masm->jump(backtrackLabel); + return true; + } + return false; + } + void addBacktrackJump(Jump jump) + { + backTrackJumps.append(jump); + } + void setBacktrackGenerated(Label label) + { + isBackTrackGenerated = true; + backtrackLabel = label; + } + void linkAlternativeBacktracks(MacroAssembler* masm) + { + isBackTrackGenerated = false; + backTrackJumps.link(masm); + } + void linkAlternativeBacktracksTo(Label label, MacroAssembler* masm) + { + isBackTrackGenerated = false; + backTrackJumps.linkTo(label, masm); + } + void propagateBacktrackingFrom(TermGenerationState& nestedParenthesesState, MacroAssembler* masm) + { + jumpToBacktrack(nestedParenthesesState.backTrackJumps, masm); + if (nestedParenthesesState.isBackTrackGenerated) + setBacktrackGenerated(nestedParenthesesState.backtrackLabel); + } + + PatternDisjunction* disjunction; + int checkedTotal; + private: + unsigned alt; + unsigned t; + JumpList backTrackJumps; + Label backtrackLabel; + bool isBackTrackGenerated; + }; + + void generateAssertionBOL(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + if (m_pattern.m_multiline) { + const RegisterID character = regT0; + + JumpList matchDest; + if (!term.inputPosition) + matchDest.append(branch32(Equal, index, Imm32(state.checkedTotal))); + + readCharacter(state.inputOffset() - 1, character); + matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); + state.jumpToBacktrack(jump(), this); + + matchDest.link(this); + } else { + // Erk, really should poison out these alternatives early. :-/ + if (term.inputPosition) + state.jumpToBacktrack(jump(), this); + else + state.jumpToBacktrack(branch32(NotEqual, index, Imm32(state.checkedTotal)), this); + } + } + + void generateAssertionEOL(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + if (m_pattern.m_multiline) { + const RegisterID character = regT0; + + JumpList matchDest; + if (term.inputPosition == state.checkedTotal) + matchDest.append(atEndOfInput()); + + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); + state.jumpToBacktrack(jump(), this); + + matchDest.link(this); + } else { + if (term.inputPosition == state.checkedTotal) + state.jumpToBacktrack(notAtEndOfInput(), this); + // Erk, really should poison out these alternatives early. :-/ + else + state.jumpToBacktrack(jump(), this); + } + } + + // Also falls though on nextIsNotWordChar. + void matchAssertionWordchar(TermGenerationState& state, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + if (term.inputPosition == state.checkedTotal) + nextIsNotWordChar.append(atEndOfInput()); + + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass()); + } + + void generateAssertionWordBoundary(TermGenerationState& state) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + Jump atBegin; + JumpList matchDest; + if (!term.inputPosition) + atBegin = branch32(Equal, index, Imm32(state.checkedTotal)); + readCharacter(state.inputOffset() - 1, character); + matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass()); + if (!term.inputPosition) + atBegin.link(this); + + // We fall through to here if the last character was not a wordchar. + JumpList nonWordCharThenWordChar; + JumpList nonWordCharThenNonWordChar; + if (term.invertOrCapture) { + matchAssertionWordchar(state, nonWordCharThenNonWordChar, nonWordCharThenWordChar); + nonWordCharThenWordChar.append(jump()); + } else { + matchAssertionWordchar(state, nonWordCharThenWordChar, nonWordCharThenNonWordChar); + nonWordCharThenNonWordChar.append(jump()); + } + state.jumpToBacktrack(nonWordCharThenNonWordChar, this); + + // We jump here if the last character was a wordchar. + matchDest.link(this); + JumpList wordCharThenWordChar; + JumpList wordCharThenNonWordChar; + if (term.invertOrCapture) { + matchAssertionWordchar(state, wordCharThenNonWordChar, wordCharThenWordChar); + wordCharThenWordChar.append(jump()); + } else { + matchAssertionWordchar(state, wordCharThenWordChar, wordCharThenNonWordChar); + // This can fall-though! + } + + state.jumpToBacktrack(wordCharThenWordChar, this); + + nonWordCharThenWordChar.link(this); + wordCharThenNonWordChar.link(this); + } + + void generatePatternCharacterSingle(TermGenerationState& state) + { + const RegisterID character = regT0; + UChar ch = state.term().patternCharacter; + + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + state.jumpToBacktrack(jumpIfCharNotEquals(ch, state.inputOffset()), this); + } + } + + void generatePatternCharacterPair(TermGenerationState& state) + { + const RegisterID character = regT0; +#if WTF_CPU_BIG_ENDIAN + UChar ch2 = state.term().patternCharacter; + UChar ch1 = state.lookaheadTerm().patternCharacter; +#else + UChar ch1 = state.term().patternCharacter; + UChar ch2 = state.lookaheadTerm().patternCharacter; +#endif + + int mask = 0; + int chPair = ch1 | (ch2 << 16); + + if (m_pattern.m_ignoreCase) { + if (isASCIIAlpha(ch1)) + mask |= 32; + if (isASCIIAlpha(ch2)) + mask |= 32 << 16; + } + + if (mask) { + load32WithUnalignedHalfWords(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character); + or32(Imm32(mask), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(chPair | mask)), this); + } else + state.jumpToBacktrack(branch32WithUnalignedHalfWords(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this); + } + + void generatePatternCharacterFixed(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(index, countRegister); + sub32(Imm32(term.quantityCount), countRegister); + + Label loop(this); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); + or32(Imm32(32), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + state.jumpToBacktrack(branch16(NotEqual, BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), Imm32(ch)), this); + } + add32(Imm32(1), countRegister); + branch32(NotEqual, countRegister, index).linkTo(loop, this); + } + + void generatePatternCharacterGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(Imm32(0), countRegister); + + JumpList failures; + Label loop(this); + failures.append(atEndOfInput()); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + failures.append(jumpIfCharNotEquals(ch, state.inputOffset())); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + if (term.quantityCount != 0xffffffff) { + branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); + failures.append(jump()); + } else + jump(loop); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + state.jumpToBacktrack(branchTest32(Zero, countRegister), this); + sub32(Imm32(1), countRegister); + sub32(Imm32(1), index); + + failures.link(this); + + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generatePatternCharacterNonGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(Imm32(0), countRegister); + + Jump firstTimeDoNothing = jump(); + + Label hardFail(this); + sub32(countRegister, index); + state.jumpToBacktrack(jump(), this); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + + atEndOfInput().linkTo(hardFail, this); + if (term.quantityCount != 0xffffffff) + branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + branch32(NotEqual, character, Imm32(Unicode::toLower(ch))).linkTo(hardFail, this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + jumpIfCharNotEquals(ch, state.inputOffset()).linkTo(hardFail, this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + + firstTimeDoNothing.link(this); + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateCharacterClassSingle(TermGenerationState& state) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + state.jumpToBacktrack(matchDest, this); + else { + state.jumpToBacktrack(jump(), this); + matchDest.link(this); + } + } + + void generateCharacterClassFixed(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(index, countRegister); + sub32(Imm32(term.quantityCount), countRegister); + + Label loop(this); + JumpList matchDest; + load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + state.jumpToBacktrack(matchDest, this); + else { + state.jumpToBacktrack(jump(), this); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + branch32(NotEqual, countRegister, index).linkTo(loop, this); + } + + void generateCharacterClassGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(Imm32(0), countRegister); + + JumpList failures; + Label loop(this); + failures.append(atEndOfInput()); + + if (term.invertOrCapture) { + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, failures, term.characterClass); + } else { + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + failures.append(jump()); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + if (term.quantityCount != 0xffffffff) { + branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); + failures.append(jump()); + } else + jump(loop); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + state.jumpToBacktrack(branchTest32(Zero, countRegister), this); + sub32(Imm32(1), countRegister); + sub32(Imm32(1), index); + + failures.link(this); + + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateCharacterClassNonGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(Imm32(0), countRegister); + + Jump firstTimeDoNothing = jump(); + + Label hardFail(this); + sub32(countRegister, index); + state.jumpToBacktrack(jump(), this); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + + atEndOfInput().linkTo(hardFail, this); + branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); + + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + matchDest.linkTo(hardFail, this); + else { + jump(hardFail); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + + firstTimeDoNothing.link(this); + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateParenthesesDisjunction(PatternTerm& parenthesesTerm, TermGenerationState& state, unsigned alternativeFrameLocation) + { + ASSERT((parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern) || (parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion)); + ASSERT(parenthesesTerm.quantityCount == 1); + + PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; + unsigned preCheckedCount = ((parenthesesTerm.quantityType == QuantifierFixedCount) && (parenthesesTerm.type != PatternTerm::TypeParentheticalAssertion)) ? disjunction->m_minimumSize : 0; + + if (disjunction->m_alternatives.length() == 1) { + state.resetAlternative(); + ASSERT(state.alternativeValid()); + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + int countToCheck = alternative->m_minimumSize - preCheckedCount; + if (countToCheck) { + ASSERT((parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion) || (parenthesesTerm.quantityType != QuantifierFixedCount)); + + // FIXME: This is quite horrible. The call to 'plantJumpToBacktrackIfExists' + // will be forced to always trampoline into here, just to decrement the index. + // Ick. + Jump skip = jump(); + + Label backtrackBegin(this); + sub32(Imm32(countToCheck), index); + state.addBacktrackJump(jump()); + + skip.link(this); + + state.setBacktrackGenerated(backtrackBegin); + + state.jumpToBacktrack(jumpIfNoAvailableInput(countToCheck), this); + state.checkedTotal += countToCheck; + } + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + state.checkedTotal -= countToCheck; + } else { + JumpList successes; + + for (state.resetAlternative(); state.alternativeValid(); state.nextAlternative()) { + + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + ASSERT(alternative->m_minimumSize >= preCheckedCount); + int countToCheck = alternative->m_minimumSize - preCheckedCount; + if (countToCheck) { + state.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); + state.checkedTotal += countToCheck; + } + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + // Matched an alternative. + DataLabelPtr dataLabel = storeToFrameWithPatch(alternativeFrameLocation); + successes.append(jump()); + + // Alternative did not match. + Label backtrackLocation(this); + + // Can we backtrack the alternative? - if so, do so. If not, just fall through to the next one. + state.plantJumpToBacktrackIfExists(this); + + state.linkAlternativeBacktracks(this); + + if (countToCheck) { + sub32(Imm32(countToCheck), index); + state.checkedTotal -= countToCheck; + } + + m_backtrackRecords.append(AlternativeBacktrackRecord(dataLabel, backtrackLocation)); + } + // We fall through to here when the last alternative fails. + // Add a backtrack out of here for the parenthese handling code to link up. + state.addBacktrackJump(jump()); + + // Generate a trampoline for the parens code to backtrack to, to retry the + // next alternative. + state.setBacktrackGenerated(label()); + loadFromFrameAndJump(alternativeFrameLocation); + + // FIXME: both of the above hooks are a little inefficient, in that you + // may end up trampolining here, just to trampoline back out to the + // parentheses code, or vice versa. We can probably eliminate a jump + // by restructuring, but coding this way for now for simplicity during + // development. + + successes.link(this); + } + } + + void generateParenthesesSingle(TermGenerationState& state) + { + const RegisterID indexTemporary = regT0; + PatternTerm& term = state.term(); + PatternDisjunction* disjunction = term.parentheses.disjunction; + ASSERT(term.quantityCount == 1); + + unsigned preCheckedCount = (term.quantityType == QuantifierFixedCount) ? disjunction->m_minimumSize : 0; + + unsigned parenthesesFrameLocation = term.frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation; + if (term.quantityType != QuantifierFixedCount) + alternativeFrameLocation += RegexStackSpaceForBackTrackInfoParenthesesOnce; + + // optimized case - no capture & no quantifier can be handled in a light-weight manner. + if (!term.invertOrCapture && (term.quantityType == QuantifierFixedCount)) { + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // this expects that any backtracks back out of the parentheses will be in the + // parenthesesState's backTrackJumps vector, and that if they need backtracking + // they will have set an entry point on the parenthesesState's backtrackLabel. + state.propagateBacktrackingFrom(parenthesesState, this); + } else { + Jump nonGreedySkipParentheses; + Label nonGreedyTryParentheses; + if (term.quantityType == QuantifierGreedy) + storeToFrame(index, parenthesesFrameLocation); + else if (term.quantityType == QuantifierNonGreedy) { + storeToFrame(Imm32(-1), parenthesesFrameLocation); + nonGreedySkipParentheses = jump(); + nonGreedyTryParentheses = label(); + storeToFrame(index, parenthesesFrameLocation); + } + + // store the match start index + if (term.invertOrCapture) { + int inputOffset = state.inputOffset() - preCheckedCount; + if (inputOffset) { + move(index, indexTemporary); + add32(Imm32(inputOffset), indexTemporary); + store32(indexTemporary, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); + } else + store32(index, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); + } + + // generate the body of the parentheses + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + + Jump success = (term.quantityType == QuantifierFixedCount) ? + jump() : + branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesFrameLocation * sizeof(void*)))); + + // A failure AFTER the parens jumps here + Label backtrackFromAfterParens(this); + + if (term.quantityType == QuantifierGreedy) { + // If this is -1 we have now tested with both with and without the parens. + loadFromFrame(parenthesesFrameLocation, indexTemporary); + state.jumpToBacktrack(branch32(Equal, indexTemporary, Imm32(-1)), this); + } else if (term.quantityType == QuantifierNonGreedy) { + // If this is -1 we have now tested without the parens, now test with. + loadFromFrame(parenthesesFrameLocation, indexTemporary); + branch32(Equal, indexTemporary, Imm32(-1)).linkTo(nonGreedyTryParentheses, this); + } + + parenthesesState.plantJumpToBacktrackIfExists(this); + // A failure WITHIN the parens jumps here + parenthesesState.linkAlternativeBacktracks(this); + if (term.invertOrCapture) { + store32(Imm32(-1), Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); +#if 0 + store32(Imm32(-1), Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); +#endif + } + + if (term.quantityType == QuantifierGreedy) + storeToFrame(Imm32(-1), parenthesesFrameLocation); + else + state.jumpToBacktrack(jump(), this); + + state.setBacktrackGenerated(backtrackFromAfterParens); + if (term.quantityType == QuantifierNonGreedy) + nonGreedySkipParentheses.link(this); + success.link(this); + + // store the match end index + if (term.invertOrCapture) { + int inputOffset = state.inputOffset(); + if (inputOffset) { + move(index, indexTemporary); + add32(Imm32(state.inputOffset()), indexTemporary); + store32(indexTemporary, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); + } else + store32(index, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); + } + } + } + + void generateParenthesesGreedyNoBacktrack(TermGenerationState& state) + { + PatternTerm& parenthesesTerm = state.term(); + PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; + ASSERT(parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern); + ASSERT(parenthesesTerm.quantityCount != 1); // Handled by generateParenthesesSingle. + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + + Label matchAgain(this); + + storeToFrame(index, parenthesesTerm.frameLocation); // Save the current index to check for zero len matches later. + + for (parenthesesState.resetAlternative(); parenthesesState.alternativeValid(); parenthesesState.nextAlternative()) { + + PatternAlternative* alternative = parenthesesState.alternative(); + optimizeAlternative(alternative); + + int countToCheck = alternative->m_minimumSize; + if (countToCheck) { + parenthesesState.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); + parenthesesState.checkedTotal += countToCheck; + } + + for (parenthesesState.resetTerm(); parenthesesState.termValid(); parenthesesState.nextTerm()) + generateTerm(parenthesesState); + + // If we get here, we matched! If the index advanced then try to match more since limit isn't supported yet. + branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesTerm.frameLocation * sizeof(void*))), matchAgain); + + // If we get here we matched, but we matched "" - cannot accept this alternative as is, so either backtrack, + // or fall through to try the next alternative if no backtrack is available. + parenthesesState.plantJumpToBacktrackIfExists(this); + + parenthesesState.linkAlternativeBacktracks(this); + // We get here if the alternative fails to match - fall through to the next iteration, or out of the loop. + + if (countToCheck) { + sub32(Imm32(countToCheck), index); + parenthesesState.checkedTotal -= countToCheck; + } + } + + // If the last alternative falls through to here, we have a failed match... + // Which means that we match whatever we have matched up to this point (even if nothing). + } + + void generateParentheticalAssertion(TermGenerationState& state) + { + PatternTerm& term = state.term(); + PatternDisjunction* disjunction = term.parentheses.disjunction; + ASSERT(term.quantityCount == 1); + ASSERT(term.quantityType == QuantifierFixedCount); + + unsigned parenthesesFrameLocation = term.frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation + RegexStackSpaceForBackTrackInfoParentheticalAssertion; + + int countCheckedAfterAssertion = state.checkedTotal - term.inputPosition; + + if (term.invertOrCapture) { + // Inverted case + storeToFrame(index, parenthesesFrameLocation); + + state.checkedTotal -= countCheckedAfterAssertion; + if (countCheckedAfterAssertion) + sub32(Imm32(countCheckedAfterAssertion), index); + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // Success! - which means - Fail! + loadFromFrame(parenthesesFrameLocation, index); + state.jumpToBacktrack(jump(), this); + + // And fail means success. + parenthesesState.linkAlternativeBacktracks(this); + loadFromFrame(parenthesesFrameLocation, index); + + state.checkedTotal += countCheckedAfterAssertion; + } else { + // Normal case + storeToFrame(index, parenthesesFrameLocation); + + state.checkedTotal -= countCheckedAfterAssertion; + if (countCheckedAfterAssertion) + sub32(Imm32(countCheckedAfterAssertion), index); + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // Success! - which means - Success! + loadFromFrame(parenthesesFrameLocation, index); + Jump success = jump(); + + parenthesesState.linkAlternativeBacktracks(this); + loadFromFrame(parenthesesFrameLocation, index); + state.jumpToBacktrack(jump(), this); + + success.link(this); + + state.checkedTotal += countCheckedAfterAssertion; + } + } + + void generateTerm(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + switch (term.type) { + case PatternTerm::TypeAssertionBOL: + generateAssertionBOL(state); + break; + + case PatternTerm::TypeAssertionEOL: + generateAssertionEOL(state); + break; + + case PatternTerm::TypeAssertionWordBoundary: + generateAssertionWordBoundary(state); + break; + + case PatternTerm::TypePatternCharacter: + switch (term.quantityType) { + case QuantifierFixedCount: + if (term.quantityCount == 1) { + if (state.isSinglePatternCharacterLookaheadTerm() && (state.lookaheadTerm().inputPosition == (term.inputPosition + 1))) { + generatePatternCharacterPair(state); + state.nextTerm(); + } else + generatePatternCharacterSingle(state); + } else + generatePatternCharacterFixed(state); + break; + case QuantifierGreedy: + generatePatternCharacterGreedy(state); + break; + case QuantifierNonGreedy: + generatePatternCharacterNonGreedy(state); + break; + } + break; + + case PatternTerm::TypeCharacterClass: + switch (term.quantityType) { + case QuantifierFixedCount: + if (term.quantityCount == 1) + generateCharacterClassSingle(state); + else + generateCharacterClassFixed(state); + break; + case QuantifierGreedy: + generateCharacterClassGreedy(state); + break; + case QuantifierNonGreedy: + generateCharacterClassNonGreedy(state); + break; + } + break; + + case PatternTerm::TypeBackReference: + m_shouldFallBack = true; + break; + + case PatternTerm::TypeForwardReference: + break; + + case PatternTerm::TypeParenthesesSubpattern: + if (term.quantityCount == 1 && !term.parentheses.isCopy) + generateParenthesesSingle(state); + else if (term.parentheses.isTerminal) + generateParenthesesGreedyNoBacktrack(state); + else + m_shouldFallBack = true; + break; + + case PatternTerm::TypeParentheticalAssertion: + generateParentheticalAssertion(state); + break; + } + } + + void generateDisjunction(PatternDisjunction* disjunction) + { + TermGenerationState state(disjunction, 0); + state.resetAlternative(); + + // check availability for the next alternative + int countCheckedForCurrentAlternative = 0; + int countToCheckForFirstAlternative = 0; + bool hasShorterAlternatives = false; + bool setRepeatAlternativeLabels = false; + JumpList notEnoughInputForPreviousAlternative; + Label firstAlternative; + Label firstAlternativeInputChecked; + + // The label 'firstAlternative' is used to plant a check to see if there is + // sufficient input available to run the first repeating alternative. + // The label 'firstAlternativeInputChecked' will jump directly to matching + // the first repeating alternative having skipped this check. + + if (state.alternativeValid()) { + PatternAlternative* alternative = state.alternative(); + if (!alternative->onceThrough()) { + firstAlternative = Label(this); + setRepeatAlternativeLabels = true; + } + countToCheckForFirstAlternative = alternative->m_minimumSize; + state.checkedTotal += countToCheckForFirstAlternative; + if (countToCheckForFirstAlternative) + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); + countCheckedForCurrentAlternative = countToCheckForFirstAlternative; + } + + if (setRepeatAlternativeLabels) + firstAlternativeInputChecked = Label(this); + + while (state.alternativeValid()) { + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + // Track whether any alternatives are shorter than the first one. + if (!alternative->onceThrough()) + hasShorterAlternatives = hasShorterAlternatives || (countCheckedForCurrentAlternative < countToCheckForFirstAlternative); + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + // If we get here, the alternative matched. + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + ASSERT(index != returnRegister); + if (m_pattern.m_body->m_hasFixedSize) { + move(index, returnRegister); + if (alternative->m_minimumSize) + sub32(Imm32(alternative->m_minimumSize), returnRegister); + + store32(returnRegister, output); + } else + load32(Address(output), returnRegister); + + store32(index, Address(output, 4)); + + generateReturn(); + + state.nextAlternative(); + + // if there are any more alternatives, plant the check for input before looping. + if (state.alternativeValid()) { + PatternAlternative* nextAlternative = state.alternative(); + if (!setRepeatAlternativeLabels && !nextAlternative->onceThrough()) { + // We have handled non-repeating alternatives, jump to next iteration + // and loop over repeating alternatives. + state.jumpToBacktrack(jump(), this); + + countToCheckForFirstAlternative = nextAlternative->m_minimumSize; + + // If we get here, there the last input checked failed. + notEnoughInputForPreviousAlternative.link(this); + + state.linkAlternativeBacktracks(this); + + // Back up to start the looping alternatives. + if (countCheckedForCurrentAlternative) + sub32(Imm32(countCheckedForCurrentAlternative), index); + + firstAlternative = Label(this); + + state.checkedTotal = countToCheckForFirstAlternative; + if (countToCheckForFirstAlternative) + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); + + countCheckedForCurrentAlternative = countToCheckForFirstAlternative; + + firstAlternativeInputChecked = Label(this); + + setRepeatAlternativeLabels = true; + } else { + int countToCheckForNextAlternative = nextAlternative->m_minimumSize; + + if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one. + // If we get here, then the last input checked failed. + notEnoughInputForPreviousAlternative.link(this); + + // Check if sufficent input available to run the next alternative + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); + // We are now in the correct state to enter the next alternative; this add is only required + // to mirror and revert operation of the sub32, just below. + add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); + + // If we get here, then the last input checked passed. + state.linkAlternativeBacktracks(this); + // No need to check if we can run the next alternative, since it is shorter - + // just update index. + sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); + } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one. + // If we get here, then the last input checked failed. + // If there is insufficient input to run the current alternative, and the next alternative is longer, + // then there is definitely not enough input to run it - don't even check. Just adjust index, as if + // we had checked. + notEnoughInputForPreviousAlternative.link(this); + add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index); + notEnoughInputForPreviousAlternative.append(jump()); + + // The next alternative is longer than the current one; check the difference. + state.linkAlternativeBacktracks(this); + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); + } else { // CASE 3: Both alternatives are the same length. + ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative); + + // If the next alterative is the same length as this one, then no need to check the input - + // if there was sufficent input to run the current alternative then there is sufficient + // input to run the next one; if not, there isn't. + state.linkAlternativeBacktracks(this); + } + state.checkedTotal -= countCheckedForCurrentAlternative; + countCheckedForCurrentAlternative = countToCheckForNextAlternative; + state.checkedTotal += countCheckedForCurrentAlternative; + } + } + } + + // If we get here, all Alternatives failed... + + state.checkedTotal -= countCheckedForCurrentAlternative; + + if (!setRepeatAlternativeLabels) { + // If there are no alternatives that need repeating (all are marked 'onceThrough') then just link + // the match failures to this point, and fall through to the return below. + state.linkAlternativeBacktracks(this); + notEnoughInputForPreviousAlternative.link(this); + } else { + // How much more input need there be to be able to retry from the first alternative? + // examples: + // /yarr_jit/ or /wrec|pcre/ + // In these examples we need check for one more input before looping. + // /yarr_jit|pcre/ + // In this case we need check for 5 more input to loop (+4 to allow for the first alterative + // being four longer than the last alternative checked, and another +1 to effectively move + // the start position along by one). + // /yarr|rules/ or /wrec|notsomuch/ + // In these examples, provided that there was sufficient input to have just been matching for + // the second alternative we can loop without checking for available input (since the second + // alternative is longer than the first). In the latter example we need to decrement index + // (by 4) so the start position is only progressed by 1 from the last iteration. + int incrementForNextIter = (countToCheckForFirstAlternative - countCheckedForCurrentAlternative) + 1; + + // First, deal with the cases where there was sufficient input to try the last alternative. + if (incrementForNextIter > 0) // We need to check for more input anyway, fall through to the checking below. + state.linkAlternativeBacktracks(this); + else if (m_pattern.m_body->m_hasFixedSize && !incrementForNextIter) // No need to update anything, link these backtracks straight to the to pof the loop! + state.linkAlternativeBacktracksTo(firstAlternativeInputChecked, this); + else { // no need to check the input, but we do have some bookkeeping to do first. + state.linkAlternativeBacktracks(this); + + // Where necessary update our preserved start position. + if (!m_pattern.m_body->m_hasFixedSize) { + move(index, regT0); + sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); + store32(regT0, Address(output)); + } + + // Update index if necessary, and loop (without checking). + if (incrementForNextIter) + add32(Imm32(incrementForNextIter), index); + jump().linkTo(firstAlternativeInputChecked, this); + } + + notEnoughInputForPreviousAlternative.link(this); + // Update our idea of the start position, if we're tracking this. + if (!m_pattern.m_body->m_hasFixedSize) { + if (countCheckedForCurrentAlternative - 1) { + move(index, regT0); + sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); + store32(regT0, Address(output)); + } else + store32(index, Address(output)); + } + + // Check if there is sufficent input to run the first alternative again. + jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this); + // No - insufficent input to run the first alteranative, are there any other alternatives we + // might need to check? If so, the last check will have left the index incremented by + // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative + // LESS input is available, to have the effect of just progressing the start position by 1 + // from the last iteration. If this check passes we can just jump up to the check associated + // with the first alternative in the loop. This is a bit sad, since we'll end up trying the + // first alternative again, and this check will fail (otherwise the check planted just above + // here would have passed). This is a bit sad, however it saves trying to do something more + // complex here in compilation, and in the common case we should end up coallescing the checks. + // + // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least + // of the minimum-alternative-lengths. E.g. if I have two alternatives of length 200 and 150, + // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there + // is sufficient input to run either alternative (constantly failing). If there had been only + // one alternative, or if the shorter alternative had come first, we would have terminated + // immediately. :-/ + if (hasShorterAlternatives) + jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this); + // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true, + // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... + // but since we're about to return a failure this doesn't really matter!) + } + + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + move(Imm32(-1), returnRegister); + + generateReturn(); + } + + void generateEnter() + { +#if WTF_CPU_X86_64 + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + push(X86Registers::ebx); +#elif WTF_CPU_X86 + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + // TODO: do we need spill registers to fill the output pointer if there are no sub captures? + push(X86Registers::ebx); + push(X86Registers::edi); + push(X86Registers::esi); + // load output into edi (2 = saved ebp + return address). + #if WTF_COMPILER_MSVC || WTF_COMPILER_SUNPRO + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); + loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); + loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); + loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); + #else + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); + #endif +#elif WTF_CPU_ARM + push(ARMRegisters::r4); + push(ARMRegisters::r5); + push(ARMRegisters::r6); +#if WTF_CPU_ARM_TRADITIONAL + push(ARMRegisters::r8); // scratch register +#endif + move(ARMRegisters::r3, output); +#elif WTF_CPU_SPARC + save(Imm32(-m_pattern.m_body->m_callFrameSize * sizeof(void*))); + // set m_callFrameSize to 0 avoid and stack movement later. + m_pattern.m_body->m_callFrameSize = 0; +#elif WTF_CPU_MIPS + // Do nothing. +#endif + } + + void generateReturn() + { +#if WTF_CPU_X86_64 + pop(X86Registers::ebx); + pop(X86Registers::ebp); +#elif WTF_CPU_X86 + pop(X86Registers::esi); + pop(X86Registers::edi); + pop(X86Registers::ebx); + pop(X86Registers::ebp); +#elif WTF_CPU_ARM +#if WTF_CPU_ARM_TRADITIONAL + pop(ARMRegisters::r8); // scratch register +#endif + pop(ARMRegisters::r6); + pop(ARMRegisters::r5); + pop(ARMRegisters::r4); +#elif WTF_CPU_SPARC + ret_and_restore(); + return; +#elif WTF_CPU_MIPS + // Do nothing +#endif + ret(); + } + +public: + RegexGenerator(RegexPattern& pattern) + : m_pattern(pattern) + , m_shouldFallBack(false) + { + } + + void generate() + { + generateEnter(); + + if (!m_pattern.m_body->m_hasFixedSize) + store32(index, Address(output)); + + if (m_pattern.m_body->m_callFrameSize) + subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + generateDisjunction(m_pattern.m_body); + } + + void compile(ExecutableAllocator& allocator, RegexCodeBlock& jitObject) + { + generate(); + + if (oom()) { + m_shouldFallBack = true; + return; + } + + ExecutablePool *dummy; + bool ok; + LinkBuffer patchBuffer(this, &allocator, &dummy, &ok); + if (!ok) { + m_shouldFallBack = true; + return; + } + + for (unsigned i = 0; i < m_backtrackRecords.length(); ++i) + patchBuffer.patch(m_backtrackRecords[i].dataLabel, patchBuffer.locationOf(m_backtrackRecords[i].backtrackLocation)); + + jitObject.set(patchBuffer.finalizeCode()); + } + + bool shouldFallBack() + { + return m_shouldFallBack; + } + +private: + RegexPattern& m_pattern; + bool m_shouldFallBack; + js::Vector m_backtrackRecords; +}; + +void jitCompileRegex(ExecutableAllocator& allocator, RegexCodeBlock& jitObject, const UString&patternString, unsigned& numSubpatterns, int &error, bool &fellBack, bool ignoreCase, bool multiline +#ifdef ANDROID + , bool forceFallback +#endif +) +{ +#ifdef ANDROID + if (!forceFallback) { +#endif + fellBack = false; + RegexPattern pattern(ignoreCase, multiline); + if ((error = compileRegex(patternString, pattern))) + return; + numSubpatterns = pattern.m_numSubpatterns; + + if (!pattern.m_containsBackreferences) { + RegexGenerator generator(pattern); + generator.compile(allocator, jitObject); + if (!generator.shouldFallBack()) + return; + } +#ifdef ANDROID + } // forceFallback +#endif + + fellBack = true; + JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase; + JSRegExpMultilineOption multilineOption = multiline ? JSRegExpMultiline : JSRegExpSingleLine; + jitObject.setFallback(jsRegExpCompile(reinterpret_cast(const_cast(patternString).chars()), patternString.length(), ignoreCaseOption, multilineOption, &numSubpatterns, &error)); +} + +}} + +#endif diff --git a/js/src/yarr/yarr/RegexJIT.h b/js/src/yarr/yarr/RegexJIT.h new file mode 100644 index 000000000000..60a51b484c02 --- /dev/null +++ b/js/src/yarr/yarr/RegexJIT.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2009 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 RegexJIT_h +#define RegexJIT_h + +#if ENABLE_ASSEMBLER + +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/MacroAssemblerCodeRef.h" +#include "assembler/jit/ExecutableAllocator.h" +#include "RegexPattern.h" +#include "yarr/jswtfbridge.h" + +#include "yarr/pcre/pcre.h" +struct JSRegExp; // temporary, remove when fallback is removed. + +#if WTF_CPU_X86 && !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO +#define YARR_CALL __attribute__ ((regparm (3))) +#else +#define YARR_CALL +#endif + +struct JSContext; + +namespace JSC { + +namespace Yarr { + +class RegexCodeBlock { + typedef int (*RegexJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; + +public: + RegexCodeBlock() + : m_fallback(0) + { + } + + ~RegexCodeBlock() + { + if (m_fallback) + jsRegExpFree(m_fallback); + if (m_ref.m_size) + m_ref.m_executablePool->release(); + } + + JSRegExp* getFallback() { return m_fallback; } + void setFallback(JSRegExp* fallback) { m_fallback = fallback; } + + bool operator!() { return (!m_ref.m_code.executableAddress() && !m_fallback); } + void set(MacroAssembler::CodeRef ref) { m_ref = ref; } + + int execute(const UChar* input, unsigned start, unsigned length, int* output) + { + void *code = m_ref.m_code.executableAddress(); + return JS_EXTENSION((reinterpret_cast(code))(input, start, length, output)); + } + +private: + MacroAssembler::CodeRef m_ref; + JSRegExp* m_fallback; +}; + +void jitCompileRegex(ExecutableAllocator &allocator, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, int& error, bool &fellBack, bool ignoreCase = false, bool multiline = false +#ifdef ANDROID + , bool forceFallback = false +#endif +); + +inline int executeRegex(JSContext *cx, RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize) +{ + if (JSRegExp* fallback = jitObject.getFallback()) { + int result = jsRegExpExecute(cx, fallback, input, length, start, output, outputArraySize); + + if (result == JSRegExpErrorHitLimit) + return HitRecursionLimit; + + // -1 represents no-match for both PCRE and YARR. + JS_ASSERT(result >= -1); + return result; + } + + return jitObject.execute(input, start, length, output); +} + +} } // namespace JSC::Yarr + +#endif /* ENABLE_ASSEMBLER */ + +#endif // RegexJIT_h diff --git a/js/src/yarr/YarrParser.h b/js/src/yarr/yarr/RegexParser.h similarity index 81% rename from js/src/yarr/YarrParser.h rename to js/src/yarr/yarr/RegexParser.h index f2b50dd867e3..1ae2c2fd049b 100644 --- a/js/src/yarr/YarrParser.h +++ b/js/src/yarr/yarr/RegexParser.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. * * Redistribution and use in source and binary forms, with or without @@ -24,18 +21,18 @@ * 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 YarrParser_h -#define YarrParser_h +#ifndef RegexParser_h +#define RegexParser_h -#include "Yarr.h" +#include +#include +#include "yarr/jswtfbridge.h" +#include "yarr/yarr/RegexCommon.h" namespace JSC { namespace Yarr { -#define REGEXP_ERROR_PREFIX "Invalid regular expression: " - enum BuiltInCharacterClassID { DigitClassID, SpaceClassID, @@ -48,7 +45,7 @@ template class Parser { private: template - friend ErrorCode parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit); + friend int parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit); /* * CharacterClassParserDelegate: @@ -64,8 +61,10 @@ private: CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err) : m_delegate(delegate) , m_err(err) - , m_state(Empty) - , m_character(0) + , m_state(empty) +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 5 /* quell GCC overwarning */ + , m_character(0xFFFF) +#endif { } @@ -80,62 +79,56 @@ private: } /* - * atomPatternCharacter(): + * atomPatternCharacterUnescaped(): * - * This method is called either from parseCharacterClass() (for an unescaped - * character in a character class), or from parseEscape(). In the former case - * the value true will be passed for the argument 'hyphenIsRange', and in this - * mode we will allow a hypen to be treated as indicating a range (i.e. /[a-z]/ - * is different to /[a\-z]/). + * This method is called directly from parseCharacterClass(), to report a new + * pattern character token. This method differs from atomPatternCharacter(), + * which will be called from parseEscape(), since a hypen provided via this + * method may be indicating a character range, but a hyphen parsed by + * parseEscape() cannot be interpreted as doing so. */ - void atomPatternCharacter(UChar ch, bool hyphenIsRange = false) + void atomPatternCharacterUnescaped(UChar ch) { switch (m_state) { - case AfterCharacterClass: - // Following a builtin character class we need look out for a hyphen. - // We're looking for invalid ranges, such as /[\d-x]/ or /[\d-\d]/. - // If we see a hyphen following a charater class then unlike usual - // we'll report it to the delegate immediately, and put ourself into - // a poisoned state. Any following calls to add another character or - // character class will result in an error. (A hypen following a - // character-class is itself valid, but only at the end of a regex). - if (hyphenIsRange && ch == '-') { - m_delegate.atomCharacterClassAtom('-'); - m_state = AfterCharacterClassHyphen; - return; - } - // Otherwise just fall through - cached character so treat this as Empty. - - case Empty: + case empty: m_character = ch; - m_state = CachedCharacter; - return; + m_state = cachedCharacter; + break; - case CachedCharacter: - if (hyphenIsRange && ch == '-') - m_state = CachedCharacterHyphen; + case cachedCharacter: + if (ch == '-') + m_state = cachedCharacterHyphen; else { m_delegate.atomCharacterClassAtom(m_character); m_character = ch; } - return; + break; - case CachedCharacterHyphen: - if (ch < m_character) { + case cachedCharacterHyphen: + if (ch >= m_character) + m_delegate.atomCharacterClassRange(m_character, ch); + else m_err = CharacterClassOutOfOrder; - return; - } - m_delegate.atomCharacterClassRange(m_character, ch); - m_state = Empty; - return; - - case AfterCharacterClassHyphen: - m_delegate.atomCharacterClassAtom(ch); - m_state = Empty; - return; + m_state = empty; } } + /* + * atomPatternCharacter(): + * + * Adds a pattern character, called by parseEscape(), as such will not + * interpret a hyphen as indicating a character range. + */ + void atomPatternCharacter(UChar ch) + { + // Flush if a character is already pending to prevent the + // hyphen from begin interpreted as indicating a range. + if((ch == '-') && (m_state == cachedCharacter)) + flush(); + + atomPatternCharacterUnescaped(ch); + } + /* * atomBuiltInCharacterClass(): * @@ -143,28 +136,17 @@ private: */ void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert) { - switch (m_state) { - case CachedCharacter: - // Flush the currently cached character, then fall through. - m_delegate.atomCharacterClassAtom(m_character); - - case Empty: - case AfterCharacterClass: - m_state = AfterCharacterClass; - m_delegate.atomCharacterClassBuiltIn(classID, invert); - return; - - case CachedCharacterHyphen: - // Error! We have a range that looks like [x-\d]. We require - // the end of the range to be a single character. - m_err = CharacterClassInvalidRange; - return; - - case AfterCharacterClassHyphen: - m_delegate.atomCharacterClassBuiltIn(classID, invert); - m_state = Empty; + if (m_state == cachedCharacterHyphen) { + // If the RHS of a range does not contain exacly one character then a SyntaxError + // must be thrown. SpiderMonkey only errors out in the [c-\s] case as an extension. + // (This assumes none of the built in character classes contain a single + // character.) + m_err = CharacterClassRangeSingleChar; + m_state = empty; return; } + flush(); + m_delegate.atomCharacterClassBuiltIn(classID, invert); } /* @@ -174,29 +156,31 @@ private: */ void end() { - if (m_state == CachedCharacter) - m_delegate.atomCharacterClassAtom(m_character); - else if (m_state == CachedCharacterHyphen) { - m_delegate.atomCharacterClassAtom(m_character); - m_delegate.atomCharacterClassAtom('-'); - } + flush(); m_delegate.atomCharacterClassEnd(); } // parseEscape() should never call these delegate methods when // invoked with inCharacterClass set. - void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); } - void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); } + void assertionWordBoundary(bool) { JS_NOT_REACHED("parseEscape() should never call this"); } + void atomBackReference(unsigned) { JS_NOT_REACHED("parseEscape() should never call this"); } private: + void flush() + { + if (m_state != empty) // either cachedCharacter or cachedCharacterHyphen + m_delegate.atomCharacterClassAtom(m_character); + if (m_state == cachedCharacterHyphen) + m_delegate.atomCharacterClassAtom('-'); + m_state = empty; + } + Delegate& m_delegate; ErrorCode& m_err; enum CharacterClassConstructionState { - Empty, - CachedCharacter, - CachedCharacterHyphen, - AfterCharacterClass, - AfterCharacterClassHyphen + empty, + cachedCharacter, + cachedCharacterHyphen } m_state; UChar m_character; }; @@ -205,7 +189,7 @@ private: : m_delegate(delegate) , m_backReferenceLimit(backReferenceLimit) , m_err(NoError) - , m_data(pattern.chars()) + , m_data(const_cast(pattern).chars()) , m_size(pattern.length()) , m_index(0) , m_parenthesesNestingDepth(0) @@ -235,8 +219,8 @@ private: template bool parseEscape(EscapeDelegate& delegate) { - ASSERT(!m_err); - ASSERT(peek() == '\\'); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '\\'); consume(); if (atEndOfPattern()) { @@ -308,7 +292,7 @@ private: unsigned backReference; if (!consumeNumber(backReference)) - break; + return false; if (backReference <= m_backReferenceLimit) { delegate.atomBackReference(backReference); break; @@ -418,14 +402,14 @@ private: /* * parseCharacterClass(): * - * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape) + * Helper for parseTokens(); calls directly and indirectly (via parseCharacterClassEscape) * to an instance of CharacterClassParserDelegate, to describe the character class to the * delegate. */ void parseCharacterClass() { - ASSERT(!m_err); - ASSERT(peek() == '['); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '['); consume(); CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err); @@ -444,7 +428,7 @@ private: break; default: - characterClassConstructor.atomPatternCharacter(consume(), true); + characterClassConstructor.atomPatternCharacterUnescaped(consume()); } if (m_err) @@ -461,8 +445,8 @@ private: */ void parseParenthesesBegin() { - ASSERT(!m_err); - ASSERT(peek() == '('); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '('); consume(); if (tryConsume('?')) { @@ -500,8 +484,8 @@ private: */ void parseParenthesesEnd() { - ASSERT(!m_err); - ASSERT(peek() == ')'); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == ')'); consume(); if (m_parenthesesNestingDepth > 0) @@ -519,8 +503,8 @@ private: */ void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max) { - ASSERT(!m_err); - ASSERT(min <= max); + JS_ASSERT(!m_err); + JS_ASSERT(min <= max); if (lastTokenWasAnAtom) m_delegate.quantifyAtom(min, max, !tryConsume('?')); @@ -588,13 +572,13 @@ private: case '*': consume(); - parseQuantifier(lastTokenWasAnAtom, 0, quantifyInfinite); + parseQuantifier(lastTokenWasAnAtom, 0, UINT_MAX); lastTokenWasAnAtom = false; break; case '+': consume(); - parseQuantifier(lastTokenWasAnAtom, 1, quantifyInfinite); + parseQuantifier(lastTokenWasAnAtom, 1, UINT_MAX); lastTokenWasAnAtom = false; break; @@ -619,7 +603,7 @@ private: if (!consumeNumber(max)) break; } else { - max = quantifyInfinite; + max = UINT_MAX; } } @@ -652,18 +636,26 @@ private: /* * parse(): * - * This method calls parseTokens() to parse over the input and converts any + * This method calls regexBegin(), calls parseTokens() to parse over the input + * patterns, calls regexEnd() or regexError() as appropriate, and converts any * error code to a const char* for a result. */ - ErrorCode parse() + int parse() { + m_delegate.regexBegin(); + if (m_size > MAX_PATTERN_SIZE) m_err = PatternTooLarge; else parseTokens(); - ASSERT(atEndOfPattern() || m_err); + JS_ASSERT(atEndOfPattern() || m_err); - return m_err; + if (m_err) + m_delegate.regexError(); + else + m_delegate.regexEnd(); + + return static_cast(m_err); } @@ -683,13 +675,13 @@ private: bool atEndOfPattern() { - ASSERT(m_index <= m_size); + JS_ASSERT(m_index <= m_size); return m_index == m_size; } int peek() { - ASSERT(m_index < m_size); + JS_ASSERT(m_index < m_size); return m_data[m_index]; } @@ -700,40 +692,40 @@ private: unsigned peekDigit() { - ASSERT(peekIsDigit()); + JS_ASSERT(peekIsDigit()); return peek() - '0'; } int consume() { - ASSERT(m_index < m_size); + JS_ASSERT(m_index < m_size); return m_data[m_index++]; } unsigned consumeDigit() { - ASSERT(peekIsDigit()); + JS_ASSERT(peekIsDigit()); return consume() - '0'; } - bool consumeNumber(unsigned &accum) - { - accum = consumeDigit(); - while (peekIsDigit()) { - unsigned newValue = accum * 10 + peekDigit(); - if (newValue < accum) { /* Overflow check. */ - m_err = QuantifierTooLarge; - return false; - } - accum = newValue; - consume(); - } - return true; + bool consumeNumber(unsigned &accum) + { + accum = consumeDigit(); + while (peekIsDigit()) { + unsigned newValue = accum * 10 + peekDigit(); + if (newValue < accum) { /* Overflow check. */ + m_err = QuantifierTooLarge; + return false; + } + accum = newValue; + consume(); + } + return true; } unsigned consumeOctal() { - ASSERT(WTF::isASCIIOctalDigit(peek())); + JS_ASSERT(WTF::isASCIIOctalDigit(peek())); unsigned n = consumeDigit(); while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek())) @@ -806,6 +798,14 @@ private: * * void disjunction(); * + * void regexBegin(); + * void regexEnd(); + * void regexError(); + * + * Before any call recording tokens are made, regexBegin() will be called on the + * delegate once. Once parsing is complete either regexEnd() or regexError() will + * be called, as appropriate. + * * The regular expression is described by a sequence of assertion*() and atom*() * callbacks to the delegate, describing the terms in the regular expression. * Following an atom a quantifyAtom() call may occur to indicate that the previous @@ -836,11 +836,11 @@ private: */ template -ErrorCode parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = quantifyInfinite) +int parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = UINT_MAX) { return Parser(delegate, pattern, backReferenceLimit).parse(); } } } // namespace JSC::Yarr -#endif // YarrParser_h +#endif // RegexParser_h diff --git a/js/src/yarr/YarrPattern.h b/js/src/yarr/yarr/RegexPattern.h similarity index 70% rename from js/src/yarr/YarrPattern.h rename to js/src/yarr/yarr/RegexPattern.h index 38ae10fcf289..9d9b286a653e 100644 --- a/js/src/yarr/YarrPattern.h +++ b/js/src/yarr/yarr/RegexPattern.h @@ -1,9 +1,5 @@ -/* -*- 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 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,32 +21,26 @@ * 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 YarrPattern_h -#define YarrPattern_h +#ifndef RegexPattern_h +#define RegexPattern_h + +#include "jsvector.h" +#include "yarr/jswtfbridge.h" +#include "yarr/yarr/RegexCommon.h" -#include "wtfbridge.h" -#include "ASCIICType.h" namespace JSC { namespace Yarr { -enum ErrorCode { - NoError, - PatternTooLarge, - QuantifierOutOfOrder, - QuantifierWithoutAtom, - MissingParentheses, - ParenthesesUnmatched, - ParenthesesTypeInvalid, - CharacterClassUnmatched, - CharacterClassInvalidRange, - CharacterClassOutOfOrder, - EscapeUnterminated, - QuantifierTooLarge, - NumberOfErrorCodes -}; +#define RegexStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoBackReference 2 +#define RegexStackSpaceForBackTrackInfoAlternative 1 // One per alternative. +#define RegexStackSpaceForBackTrackInfoParentheticalAssertion 1 +#define RegexStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoParenthesesTerminal 1 +#define RegexStackSpaceForBackTrackInfoParentheses 4 struct PatternDisjunction; @@ -65,42 +55,60 @@ struct CharacterRange { } }; -struct CharacterClassTable : RefCounted { - friend class js::OffTheBooks; +/* + * Wraps a table and indicates inversion. Can be efficiently borrowed + * between character classes, so it's refcounted. + */ +struct CharacterClassTable { + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + const char* m_table; bool m_inverted; - static PassRefPtr create(const char* table, bool inverted) + jsrefcount m_refcount; + + /* Ownership transferred to caller. */ + static CharacterClassTable *create(const char* table, bool inverted) { - return adoptRef(js::OffTheBooks::new_(table, inverted)); + // FIXME: bug 574459 -- no NULL checks done by any of the callers, all + // of which are in RegExpJitTables.h. + return js::OffTheBooks::new_(table, inverted); } + void incref() { JS_ATOMIC_INCREMENT(&m_refcount); } + void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js::Foreground::delete_(this); } + private: CharacterClassTable(const char* table, bool inverted) : m_table(table) , m_inverted(inverted) + , m_refcount(0) { } }; struct CharacterClass { - WTF_MAKE_FAST_ALLOCATED -public: // All CharacterClass instances have to have the full set of matches and ranges, // they may have an optional table for faster lookups (which must match the // specified matches and ranges) - CharacterClass(PassRefPtr table) + CharacterClass(CharacterClassTable *table) : m_table(table) { + if (m_table) + m_table->incref(); } ~CharacterClass() { - js::Foreground::delete_(m_table.get()); + if (m_table) + m_table->decref(); } - Vector m_matches; - Vector m_ranges; - Vector m_matchesUnicode; - Vector m_rangesUnicode; - RefPtr m_table; + typedef js::Vector UChars; + typedef js::Vector CharacterRanges; + UChars m_matches; + CharacterRanges m_ranges; + UChars m_matchesUnicode; + CharacterRanges m_rangesUnicode; + CharacterClassTable *m_table; }; enum QuantifierType { @@ -121,12 +129,11 @@ struct PatternTerm { TypeParenthesesSubpattern, TypeParentheticalAssertion } type; - bool m_capture :1; - bool m_invert :1; + bool invertOrCapture; union { UChar patternCharacter; CharacterClass* characterClass; - unsigned backReferenceSubpatternId; + unsigned subpatternId; struct { PatternDisjunction* disjunction; unsigned subpatternId; @@ -140,21 +147,8 @@ struct PatternTerm { int inputPosition; unsigned frameLocation; - // No-argument constructor for js::Vector. - PatternTerm() - : type(PatternTerm::TypePatternCharacter) - , m_capture(false) - , m_invert(false) - { - patternCharacter = 0; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - PatternTerm(UChar ch) : type(PatternTerm::TypePatternCharacter) - , m_capture(false) - , m_invert(false) { patternCharacter = ch; quantityType = QuantifierFixedCount; @@ -163,18 +157,16 @@ struct PatternTerm { PatternTerm(CharacterClass* charClass, bool invert) : type(PatternTerm::TypeCharacterClass) - , m_capture(false) - , m_invert(invert) + , invertOrCapture(invert) { characterClass = charClass; quantityType = QuantifierFixedCount; quantityCount = 1; } - PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false) + PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool invertOrCapture) : type(type) - , m_capture(capture) - , m_invert(invert) + , invertOrCapture(invertOrCapture) { parentheses.disjunction = disjunction; parentheses.subpatternId = subpatternId; @@ -186,8 +178,7 @@ struct PatternTerm { PatternTerm(Type type, bool invert = false) : type(type) - , m_capture(false) - , m_invert(invert) + , invertOrCapture(invert) { quantityType = QuantifierFixedCount; quantityCount = 1; @@ -195,10 +186,9 @@ struct PatternTerm { PatternTerm(unsigned spatternId) : type(TypeBackReference) - , m_capture(false) - , m_invert(false) + , invertOrCapture(false) { - backReferenceSubpatternId = spatternId; + subpatternId = spatternId; quantityType = QuantifierFixedCount; quantityCount = 1; } @@ -225,12 +215,12 @@ struct PatternTerm { bool invert() { - return m_invert; + return invertOrCapture; } bool capture() { - return m_capture; + return invertOrCapture; } void quantify(unsigned count, QuantifierType type) @@ -241,8 +231,9 @@ struct PatternTerm { }; struct PatternAlternative { - WTF_MAKE_FAST_ALLOCATED -public: + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + PatternAlternative(PatternDisjunction* disjunction) : m_parent(disjunction) , m_onceThrough(false) @@ -254,14 +245,14 @@ public: PatternTerm& lastTerm() { - ASSERT(m_terms.size()); - return m_terms[m_terms.size() - 1]; + JS_ASSERT(m_terms.length()); + return m_terms[m_terms.length() - 1]; } void removeLastTerm() { - ASSERT(m_terms.size()); - m_terms.shrink(m_terms.size() - 1); + JS_ASSERT(m_terms.length()); + m_terms.popBack(); } void setOnceThrough() @@ -274,7 +265,7 @@ public: return m_onceThrough; } - Vector m_terms; + js::Vector m_terms; PatternDisjunction* m_parent; unsigned m_minimumSize; bool m_onceThrough : 1; @@ -283,9 +274,18 @@ public: bool m_containsBOL : 1; }; +template +static inline void +deleteAllValues(js::Vector &vector) +{ + for (T** t = vector.begin(); t < vector.end(); ++t) + js::Foreground::delete_(*t); +} + struct PatternDisjunction { - WTF_MAKE_FAST_ALLOCATED -public: + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + PatternDisjunction(PatternAlternative* parent = 0) : m_parent(parent) , m_hasFixedSize(false) @@ -299,12 +299,13 @@ public: PatternAlternative* addNewAlternative() { + // FIXME: bug 574459 -- no NULL check PatternAlternative* alternative = js::OffTheBooks::new_(this); m_alternatives.append(alternative); return alternative; } - Vector m_alternatives; + js::Vector m_alternatives; PatternAlternative* m_parent; unsigned m_minimumSize; unsigned m_callFrameSize; @@ -313,7 +314,7 @@ public: // You probably don't want to be calling these functions directly // (please to be calling newlineCharacterClass() et al on your -// friendly neighborhood YarrPattern instance to get nicely +// friendly neighborhood RegexPattern instance to get nicely // cached copies). CharacterClass* newlineCreate(); CharacterClass* digitsCreate(); @@ -323,34 +324,25 @@ CharacterClass* nondigitsCreate(); CharacterClass* nonspacesCreate(); CharacterClass* nonwordcharCreate(); -struct TermChain { - TermChain(PatternTerm term) - : term(term) - {} +struct RegexPattern { + RegexPattern(bool ignoreCase, bool multiline) + : m_ignoreCase(ignoreCase) + , m_multiline(multiline) + , m_containsBackreferences(false) + , m_containsBOL(false) + , m_numSubpatterns(0) + , m_maxBackReference(0) + , newlineCached(0) + , digitsCached(0) + , spacesCached(0) + , wordcharCached(0) + , nondigitsCached(0) + , nonspacesCached(0) + , nonwordcharCached(0) + { + } - PatternTerm term; - Vector hotTerms; -}; - -struct BeginChar { - BeginChar() - : value(0) - , mask(0) - {} - - BeginChar(unsigned value, unsigned mask) - : value(value) - , mask(mask) - {} - - unsigned value; - unsigned mask; -}; - -struct YarrPattern { - YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error); - - ~YarrPattern() + ~RegexPattern() { deleteAllValues(m_disjunctions); deleteAllValues(m_userCharacterClasses); @@ -362,7 +354,6 @@ struct YarrPattern { m_maxBackReference = 0; m_containsBackreferences = false; - m_containsBeginChars = false; m_containsBOL = false; newlineCached = 0; @@ -377,7 +368,6 @@ struct YarrPattern { m_disjunctions.clear(); deleteAllValues(m_userCharacterClasses); m_userCharacterClasses.clear(); - m_beginChars.clear(); } bool containsIllegalBackReference() @@ -428,21 +418,19 @@ struct YarrPattern { return nonwordcharCached; } + typedef js::Vector PatternDisjunctions; + typedef js::Vector CharacterClasses; bool m_ignoreCase : 1; bool m_multiline : 1; bool m_containsBackreferences : 1; - bool m_containsBeginChars : 1; bool m_containsBOL : 1; unsigned m_numSubpatterns; unsigned m_maxBackReference; - PatternDisjunction* m_body; - Vector m_disjunctions; - Vector m_userCharacterClasses; - Vector m_beginChars; + PatternDisjunction *m_body; + PatternDisjunctions m_disjunctions; + CharacterClasses m_userCharacterClasses; private: - ErrorCode compile(const UString& patternString); - CharacterClass* newlineCached; CharacterClass* digitsCached; CharacterClass* spacesCached; @@ -454,4 +442,4 @@ private: } } // namespace JSC::Yarr -#endif // YarrPattern_h +#endif // RegexPattern_h diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 7341d40d7f65..50711ae8a547 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -2032,7 +2032,7 @@ POSSIBILITY OF SUCH DAMAGE.

Apple License

-

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr, and widget/src/cocoa.

+

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr/wtf, js/src/yarr/yarr, and widget/src/cocoa.

 Copyright (C) 2008, 2009 Apple Inc. All rights reserved.

From c45008f574ec1de0be12fd9f4ab553771a9463ba Mon Sep 17 00:00:00 2001
From: David Mandelin 
Date: Thu, 12 May 2011 18:39:47 -0700
Subject: [PATCH 103/145] Bug 625600: Update Yarr import to WebKit rev 86639,
 r=cdleary,dvander

---
 js/src/Makefile.in                            |   37 +-
 .../assembler/AbstractMacroAssembler.h        |   63 +-
 js/src/assembler/assembler/MacroAssembler.h   |   32 +-
 .../assembler/assembler/MacroAssemblerARM.cpp |    2 +-
 .../assembler/assembler/MacroAssemblerARM.h   |   50 +-
 .../assembler/assembler/MacroAssemblerARMv7.h |   48 +-
 .../assembler/MacroAssemblerCodeRef.h         |   17 +-
 .../assembler/assembler/MacroAssemblerSparc.h |   48 +-
 .../assembler/assembler/MacroAssemblerX86.h   |   14 +-
 .../assembler/MacroAssemblerX86Common.h       |   44 +-
 .../assembler/MacroAssemblerX86_64.h          |   16 +-
 js/src/assembler/jit/ExecutableAllocator.h    |   20 +-
 .../assembler/jit/ExecutableAllocatorOS2.cpp  |    2 +-
 .../jit/ExecutableAllocatorPosix.cpp          |    4 +-
 .../jit/ExecutableAllocatorSymbian.cpp        |    2 +-
 .../assembler/jit/ExecutableAllocatorWin.cpp  |    2 +-
 js/src/assembler/wtf/Platform.h               |  981 ++++--
 .../jit-test/tests/basic/bug632964-regexp.js  |    3 -
 js/src/jscompartment.cpp                      |   11 +-
 js/src/jscompartment.h                        |   10 +-
 js/src/jsregexp.cpp                           |   46 +-
 js/src/jsregexpinlines.h                      |  119 +-
 js/src/jsvector.h                             |   22 +-
 js/src/methodjit/Compiler.cpp                 |   10 +-
 js/src/methodjit/MethodJIT.cpp                |    7 +-
 js/src/methodjit/TrampolineCompiler.cpp       |    2 +-
 js/src/yarr/{wtf => }/ASCIICType.h            |   33 +-
 js/src/yarr/BumpPointerAllocator.h            |  254 ++
 js/src/yarr/Makefile                          |    5 -
 js/src/yarr/OSAllocator.h                     |  103 +
 js/src/yarr/OSAllocatorPosix.cpp              |  129 +
 js/src/yarr/OSAllocatorWin.cpp                |   89 +
 js/src/yarr/PageAllocation.h                  |  131 +
 js/src/yarr/PageBlock.cpp                     |   88 +
 js/src/yarr/PageBlock.h                       |   91 +
 js/src/yarr/{yarr => }/RegExpJitTables.h      |    0
 js/src/yarr/VMTags.h                          |   90 +
 js/src/yarr/Yarr.h                            |   72 +
 js/src/yarr/YarrInterpreter.cpp               | 1914 +++++++++++
 js/src/yarr/YarrInterpreter.h                 |  380 +++
 js/src/yarr/YarrJIT.cpp                       | 2405 +++++++++++++
 js/src/yarr/YarrJIT.h                         |   93 +
 .../yarr/{yarr/RegexParser.h => YarrParser.h} |  262 +-
 .../RegexCompiler.cpp => YarrPattern.cpp}     |  572 +++-
 .../{yarr/RegexPattern.h => YarrPattern.h}    |  218 +-
 .../RegexCommon.h => YarrSyntaxChecker.cpp}   |   56 +-
 .../RegexCompiler.h => YarrSyntaxChecker.h}   |   25 +-
 js/src/yarr/jswtfbridge.h                     |   61 -
 js/src/yarr/pcre/AUTHORS                      |   12 -
 js/src/yarr/pcre/COPYING                      |   35 -
 js/src/yarr/pcre/chartables.c                 |   96 -
 js/src/yarr/pcre/dftables                     |  273 --
 js/src/yarr/pcre/pcre.h                       |   68 -
 js/src/yarr/pcre/pcre.pri                     |   12 -
 js/src/yarr/pcre/pcre_compile.cpp             | 2702 ---------------
 js/src/yarr/pcre/pcre_exec.cpp                | 2193 ------------
 js/src/yarr/pcre/pcre_internal.h              |  434 ---
 js/src/yarr/pcre/pcre_tables.cpp              |   71 -
 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp     |   98 -
 js/src/yarr/pcre/pcre_xclass.cpp              |  114 -
 js/src/yarr/pcre/ucpinternal.h                |  126 -
 js/src/yarr/pcre/ucptable.cpp                 | 2968 -----------------
 js/src/yarr/wtfbridge.h                       |  321 ++
 js/src/yarr/yarr/RegexJIT.cpp                 | 1589 ---------
 js/src/yarr/yarr/RegexJIT.h                   |  112 -
 toolkit/content/license.html                  |    2 +-
 66 files changed, 7864 insertions(+), 12045 deletions(-)
 rename js/src/yarr/{wtf => }/ASCIICType.h (81%)
 create mode 100644 js/src/yarr/BumpPointerAllocator.h
 delete mode 100644 js/src/yarr/Makefile
 create mode 100644 js/src/yarr/OSAllocator.h
 create mode 100644 js/src/yarr/OSAllocatorPosix.cpp
 create mode 100644 js/src/yarr/OSAllocatorWin.cpp
 create mode 100644 js/src/yarr/PageAllocation.h
 create mode 100644 js/src/yarr/PageBlock.cpp
 create mode 100644 js/src/yarr/PageBlock.h
 rename js/src/yarr/{yarr => }/RegExpJitTables.h (100%)
 create mode 100644 js/src/yarr/VMTags.h
 create mode 100644 js/src/yarr/Yarr.h
 create mode 100644 js/src/yarr/YarrInterpreter.cpp
 create mode 100644 js/src/yarr/YarrInterpreter.h
 create mode 100644 js/src/yarr/YarrJIT.cpp
 create mode 100644 js/src/yarr/YarrJIT.h
 rename js/src/yarr/{yarr/RegexParser.h => YarrParser.h} (81%)
 rename js/src/yarr/{yarr/RegexCompiler.cpp => YarrPattern.cpp} (52%)
 rename js/src/yarr/{yarr/RegexPattern.h => YarrPattern.h} (70%)
 rename js/src/yarr/{yarr/RegexCommon.h => YarrSyntaxChecker.cpp} (52%)
 rename js/src/yarr/{yarr/RegexCompiler.h => YarrSyntaxChecker.h} (74%)
 delete mode 100644 js/src/yarr/jswtfbridge.h
 delete mode 100644 js/src/yarr/pcre/AUTHORS
 delete mode 100644 js/src/yarr/pcre/COPYING
 delete mode 100644 js/src/yarr/pcre/chartables.c
 delete mode 100644 js/src/yarr/pcre/dftables
 delete mode 100644 js/src/yarr/pcre/pcre.h
 delete mode 100644 js/src/yarr/pcre/pcre.pri
 delete mode 100644 js/src/yarr/pcre/pcre_compile.cpp
 delete mode 100644 js/src/yarr/pcre/pcre_exec.cpp
 delete mode 100644 js/src/yarr/pcre/pcre_internal.h
 delete mode 100644 js/src/yarr/pcre/pcre_tables.cpp
 delete mode 100644 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp
 delete mode 100644 js/src/yarr/pcre/pcre_xclass.cpp
 delete mode 100644 js/src/yarr/pcre/ucpinternal.h
 delete mode 100644 js/src/yarr/pcre/ucptable.cpp
 create mode 100644 js/src/yarr/wtfbridge.h
 delete mode 100644 js/src/yarr/yarr/RegexJIT.cpp
 delete mode 100644 js/src/yarr/yarr/RegexJIT.h

diff --git a/js/src/Makefile.in b/js/src/Makefile.in
index 8023b1750b05..07bfdda59c82 100644
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -362,7 +362,6 @@ CPPSRCS += 	MethodJIT.cpp \
 		Retcon.cpp \
 		TrampolineCompiler.cpp \
 		$(NULL)
-#		PICStubCompiler.cpp \
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
 ifeq (x86_64, $(TARGET_CPU))
@@ -420,14 +419,17 @@ ifeq (,$(filter arm% sparc %86 x86_64,$(TARGET_CPU)))
 
 VPATH +=	$(srcdir)/assembler \
 		$(srcdir)/assembler/wtf \
-		$(srcdir)/yarr/pcre \
+		$(srcdir)/yarr\
 		$(NULL)
 
-CPPSRCS += 	pcre_compile.cpp \
-                pcre_exec.cpp \
-                pcre_tables.cpp \
-                pcre_xclass.cpp \
-                pcre_ucp_searchfuncs.cpp \
+CPPSRCS += \
+		Assertions.cpp \
+		OSAllocatorPosix.cpp \
+		OSAllocatorWin.cpp \
+		PageBlock.cpp \
+		YarrInterpreter.cpp \
+		YarrPattern.cpp \
+		YarrSyntaxChecker.cpp \
 		$(NULL)
 else
 
@@ -440,9 +442,6 @@ VPATH += 	$(srcdir)/assembler \
 		$(srcdir)/assembler/assembler \
 		$(srcdir)/methodjit \
 		$(srcdir)/yarr \
-		$(srcdir)/yarr/yarr \
-		$(srcdir)/yarr/pcre \
-		$(srcdir)/yarr/wtf \
 		$(NONE)
 
 CPPSRCS += 	Assertions.cpp \
@@ -451,16 +450,16 @@ CPPSRCS += 	Assertions.cpp \
 		ExecutableAllocatorOS2.cpp \
 		ExecutableAllocator.cpp \
 		ARMAssembler.cpp \
-                Logging.cpp \
+        Logging.cpp \
 		MacroAssemblerARM.cpp \
 		MacroAssemblerX86Common.cpp \
-		RegexCompiler.cpp \
-		RegexJIT.cpp \
-		pcre_compile.cpp \
-                pcre_exec.cpp \
-                pcre_tables.cpp \
-                pcre_xclass.cpp \
-                pcre_ucp_searchfuncs.cpp \
+		OSAllocatorPosix.cpp \
+		OSAllocatorWin.cpp \
+		PageBlock.cpp \
+		YarrInterpreter.cpp \
+		YarrJIT.cpp \
+		YarrPattern.cpp \
+		YarrSyntaxChecker.cpp \
 		$(NONE)
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
@@ -653,7 +652,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
 
 	# We desire these numbers to go down, not up. See "User guide to memory
 	# management within SpiderMonkey" in jsutil.h.
-	$(srcdir)/config/check_source_count.py OffTheBooks:: 52 \
+	$(srcdir)/config/check_source_count.py OffTheBooks:: 53 \
 		"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
 	# This should go to zero, if possible.
 	$(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \
diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h
index 260380acd307..3c14c80bd4b0 100644
--- a/js/src/assembler/assembler/AbstractMacroAssembler.h
+++ b/js/src/assembler/assembler/AbstractMacroAssembler.h
@@ -166,13 +166,13 @@ public:
         void* m_ptr;
     };
 
-    // ImmPtr:
+    // TrustedImmPtr:
     //
     // A pointer sized immediate operand to an instruction - this is wrapped
     // in a class requiring explicit construction in order to differentiate
     // from pointers used as absolute addresses to memory operations
-    struct ImmPtr {
-        explicit ImmPtr(const void* value)
+    struct TrustedImmPtr {
+        explicit TrustedImmPtr(const void* value)
             : m_value(value)
         {
         }
@@ -185,14 +185,21 @@ public:
         const void* m_value;
     };
 
-    // Imm32:
+    struct ImmPtr : public TrustedImmPtr {
+        explicit ImmPtr(const void* value)
+            : TrustedImmPtr(value)
+        {
+        }
+    };
+ 
+    // TrustedImm32:
     //
     // A 32bit immediate operand to an instruction - this is wrapped in a
     // class requiring explicit construction in order to prevent RegisterIDs
     // (which are implemented as an enum) from accidentally being passed as
     // immediate values.
-    struct Imm32 {
-        explicit Imm32(int32_t value)
+    struct TrustedImm32 {
+        explicit TrustedImm32(int32_t value)
             : m_value(value)
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(false)
@@ -201,7 +208,7 @@ public:
         }
 
 #if !WTF_CPU_X86_64
-        explicit Imm32(ImmPtr ptr)
+        explicit TrustedImm32(TrustedImmPtr ptr)
             : m_value(ptr.asIntptr())
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(true)
@@ -223,6 +230,20 @@ public:
 #endif
     };
 
+
+    struct Imm32 : public TrustedImm32 {
+        explicit Imm32(int32_t value)
+            : TrustedImm32(value)
+        {
+        }
+#if !WTF_CPU_X86_64
+        explicit Imm32(TrustedImmPtr ptr)
+            : TrustedImm32(ptr)
+        {
+        }
+#endif
+    };
+
     struct ImmDouble {
         union {
             struct {
@@ -241,7 +262,6 @@ public:
         }
     };
 
-
     // Section 2: MacroAssembler code buffer handles
     //
     // The following types are used to reference items in the code buffer
@@ -273,7 +293,7 @@ public:
         
         bool isUsed() const { return m_label.isUsed(); }
         void used() { m_label.used(); }
-        bool isValid() const { return m_label.isValid(); }
+        bool isSet() const { return m_label.isValid(); }
     private:
         JmpDst m_label;
     };
@@ -296,6 +316,8 @@ public:
         {
         }
         
+        bool isSet() const { return m_label.isValid(); }
+
     private:
         JmpDst m_label;
     };
@@ -411,6 +433,20 @@ public:
     public:
         typedef js::Vector JumpVector;
 
+        JumpList() {}
+
+        JumpList(const JumpList &other)
+        {
+            m_jumps.append(other.m_jumps);
+        }
+
+        JumpList &operator=(const JumpList &other)
+        {
+            m_jumps.clear();
+            m_jumps.append(other.m_jumps);
+            return *this;
+        }
+
         void link(AbstractMacroAssembler* masm)
         {
             size_t size = m_jumps.length();
@@ -432,17 +468,22 @@ public:
             m_jumps.append(jump);
         }
         
-        void append(JumpList& other)
+        void append(const JumpList& other)
         {
             m_jumps.append(other.m_jumps.begin(), other.m_jumps.length());
         }
 
+        void clear()
+        {
+            m_jumps.clear();
+        }
+
         bool empty()
         {
             return !m_jumps.length();
         }
         
-        const JumpVector& jumps() { return m_jumps; }
+        const JumpVector& jumps() const { return m_jumps; }
 
     private:
         JumpVector m_jumps;
diff --git a/js/src/assembler/assembler/MacroAssembler.h b/js/src/assembler/assembler/MacroAssembler.h
index 73bda22a8ee2..8a73863515c8 100644
--- a/js/src/assembler/assembler/MacroAssembler.h
+++ b/js/src/assembler/assembler/MacroAssembler.h
@@ -95,12 +95,12 @@ public:
         storePtr(src, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(Imm32 value, int index = 0)
+    void poke(TrustedImm32 value, int index = 0)
     {
         store32(value, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(ImmPtr imm, int index = 0)
+    void poke(TrustedImmPtr imm, int index = 0)
     {
         storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*))));
     }
@@ -117,7 +117,7 @@ public:
         branch32(cond, op1, op2).linkTo(target, this);
     }
 
-    void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target)
+    void branch32(Condition cond, RegisterID op1, TrustedImm32 imm, Label target)
     {
         branch32(cond, op1, imm).linkTo(target, this);
     }
@@ -177,21 +177,11 @@ public:
         and32(src, dest);
     }
 
-    void andPtr(Address address, RegisterID srcDest)
-    {
-        and32(address, srcDest);
-    }
-
     void andPtr(Imm32 imm, RegisterID srcDest)
     {
         and32(imm, srcDest);
     }
 
-    void andPtr(ImmPtr ptr, RegisterID srcDest)
-    {
-        and32(Imm32(ptr), srcDest);
-    }
-
     void notPtr(RegisterID srcDest)
     {
         not32(srcDest);
@@ -212,11 +202,6 @@ public:
         or32(imm, dest);
     }
 
-    void orPtr(Address address, RegisterID srcDest)
-    {
-        or32(address, srcDest);
-    }
-
     void subPtr(RegisterID src, RegisterID dest)
     {
         sub32(src, dest);
@@ -278,27 +263,22 @@ public:
         store32(src, address);
     }
 
-    void storePtr(RegisterID src, BaseIndex address)
-    {
-        store32(src, address);
-    }
-
     void storePtr(RegisterID src, void* address)
     {
         store32(src, address);
     }
 
-    void storePtr(ImmPtr imm, ImplicitAddress address)
+    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(ImmPtr imm, BaseIndex address)
+    void storePtr(TrustedImmPtr imm, BaseIndex address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(ImmPtr imm, void* address)
+    void storePtr(TrustedImmPtr imm, void* address)
     {
         store32(Imm32(imm), address);
     }
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.cpp b/js/src/assembler/assembler/MacroAssemblerARM.cpp
index 14b4166b7ea9..065c98197395 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.cpp
+++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp
@@ -34,7 +34,7 @@
 
 #include "MacroAssemblerARM.h"
 
-#if WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID
+#if WTF_OS_LINUX || WTF_OS_ANDROID
 #include 
 #include 
 #include 
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h
index 7413411f4500..2630bce7a909 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -91,14 +91,14 @@ public:
         m_assembler.adds_r(dest, dest, src);
     }
 
-    void add32(Imm32 imm, Address address)
+    void add32(TrustedImm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         add32(imm, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
     }
 
-    void add32(Imm32 imm, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -173,7 +173,7 @@ public:
         m_assembler.orrs_r(dest, dest, src);
     }
 
-    void or32(Imm32 imm, RegisterID dest)
+    void or32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -211,12 +211,12 @@ public:
         m_assembler.subs_r(dest, dest, src);
     }
 
-    void sub32(Imm32 imm, RegisterID dest)
+    void sub32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
 
-    void sub32(Imm32 imm, Address address)
+    void sub32(TrustedImm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         sub32(imm, ARMRegisters::S1);
@@ -240,7 +240,7 @@ public:
         m_assembler.eors_r(dest, dest, src);
     }
 
-    void xor32(Imm32 imm, RegisterID dest)
+    void xor32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -380,7 +380,7 @@ public:
         m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset);
     }
 
-    void store32(Imm32 imm, BaseIndex address)
+    void store32(TrustedImm32 imm, BaseIndex address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -389,7 +389,7 @@ public:
         store32(ARMRegisters::S1, address);
     }
 
-    void store32(Imm32 imm, ImplicitAddress address)
+    void store32(TrustedImm32 imm, ImplicitAddress address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -404,7 +404,7 @@ public:
         m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
     }
 
-    void store32(Imm32 imm, void* address)
+    void store32(TrustedImm32 imm, void* address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address));
         if (imm.m_isPointer)
@@ -436,7 +436,7 @@ public:
         push(ARMRegisters::S0);
     }
 
-    void move(Imm32 imm, RegisterID dest)
+    void move(TrustedImm32 imm, RegisterID dest)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(dest, imm.m_value);
@@ -449,7 +449,7 @@ public:
         m_assembler.mov_r(dest, src);
     }
 
-    void move(ImmPtr imm, RegisterID dest)
+    void move(TrustedImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -485,7 +485,7 @@ public:
         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
     }
 
-    Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
+    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
     {
         ASSERT(left != ARMRegisters::S0);
         if (right.m_isPointer) {
@@ -500,21 +500,21 @@ public:
     // number of instructions emitted is constant, regardless of the argument
     // values. For ARM, this is identical to branch32WithPatch, except that it
     // does not generate a DataLabel32.
-    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
     // As branch32_force32, but allow the value ('right') to be patched.
-    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left != ARMRegisters::S1);
         dataLabel = moveWithPatch(right, ARMRegisters::S1);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left.base != ARMRegisters::S1);
         load32(left, ARMRegisters::S1);
@@ -534,19 +534,19 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, Address left, Imm32 right)
+    Jump branch32(Condition cond, Address left, TrustedImm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -828,7 +828,7 @@ public:
         setTest32(cond, address, mask, dest);
     }
 
-    void add32(Imm32 imm, RegisterID src, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -850,7 +850,7 @@ public:
         move(ARMRegisters::S1, dest);
     }
 
-    void add32(Imm32 imm, AbsoluteAddress address)
+    void add32(TrustedImm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -859,7 +859,7 @@ public:
         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
     }
 
-    void sub32(Imm32 imm, AbsoluteAddress address)
+    void sub32(TrustedImm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -880,7 +880,7 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
     {
         load32(left.m_ptr, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -908,14 +908,14 @@ public:
         return Call::fromTailJump(oldJump);
     }
 
-    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
     {
         DataLabelPtr dataLabel(this);
         m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value));
         return dataLabel;
     }
 
-    DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
+    DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
     {
         DataLabel32 dataLabel(this);
         m_assembler.ldr_un_imm(dest, initialValue.m_value);
@@ -937,7 +937,7 @@ public:
         return jump;
     }
 
-    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h
index 5492f8246a06..2bdb6e8fdb5e 100644
--- a/js/src/assembler/assembler/MacroAssemblerARMv7.h
+++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h
@@ -52,7 +52,7 @@ class MacroAssemblerARMv7 : public AbstractMacroAssembler {
     struct ArmAddress {
         enum AddressType {
             HasOffset,
-            HasIndex,
+            HasIndex
         } type;
         RegisterID base;
         union {
@@ -113,7 +113,7 @@ public:
         DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
         DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
         DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
-        DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
+        DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE
     };
 
     static const RegisterID stackPointerRegister = ARMRegisters::sp;
@@ -131,12 +131,12 @@ public:
         m_assembler.add(dest, dest, src);
     }
 
-    void add32(Imm32 imm, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID dest)
     {
         add32(imm, dest, dest);
     }
 
-    void add32(Imm32 imm, RegisterID src, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -147,7 +147,7 @@ public:
         }
     }
 
-    void add32(Imm32 imm, Address address)
+    void add32(TrustedImm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -170,7 +170,7 @@ public:
         add32(dataTempRegister, dest);
     }
 
-    void add32(Imm32 imm, AbsoluteAddress address)
+    void add32(TrustedImm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -239,7 +239,7 @@ public:
         m_assembler.orr(dest, dest, src);
     }
 
-    void or32(Imm32 imm, RegisterID dest)
+    void or32(TrustedImm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -285,7 +285,7 @@ public:
         m_assembler.sub(dest, dest, src);
     }
 
-    void sub32(Imm32 imm, RegisterID dest)
+    void sub32(TrustedImm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -296,7 +296,7 @@ public:
         }
     }
 
-    void sub32(Imm32 imm, Address address)
+    void sub32(TrustedImm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -319,7 +319,7 @@ public:
         sub32(dataTempRegister, dest);
     }
 
-    void sub32(Imm32 imm, AbsoluteAddress address)
+    void sub32(TrustedImm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -341,7 +341,7 @@ public:
         m_assembler.eor(dest, dest, src);
     }
 
-    void xor32(Imm32 imm, RegisterID dest)
+    void xor32(TrustedImm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -486,7 +486,7 @@ public:
         store32(src, setupArmAddress(address));
     }
 
-    void store32(Imm32 imm, ImplicitAddress address)
+    void store32(TrustedImm32 imm, ImplicitAddress address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, setupArmAddress(address));
@@ -498,7 +498,7 @@ public:
         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
     }
 
-    void store32(Imm32 imm, void* address)
+    void store32(TrustedImm32 imm, void* address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, address);
@@ -667,7 +667,7 @@ public:
     //
     // Move values in registers.
 
-    void move(Imm32 imm, RegisterID dest)
+    void move(TrustedImm32 imm, RegisterID dest)
     {
         uint32_t value = imm.m_value;
 
@@ -693,7 +693,7 @@ public:
         m_assembler.mov(dest, src);
     }
 
-    void move(ImmPtr imm, RegisterID dest)
+    void move(TrustedImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -780,7 +780,7 @@ public:
         return Jump(makeBranch(cond));
     }
 
-    Jump branch32(Condition cond, RegisterID left, Imm32 right)
+    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
     {
         compare32(left, right);
         return Jump(makeBranch(cond));
@@ -798,21 +798,21 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, Address left, Imm32 right)
+    Jump branch32(Condition cond, Address left, TrustedImm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32WithUnalignedHalfWords(left, addressTempRegister);
@@ -825,7 +825,7 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left.m_ptr, addressTempRegister);
@@ -1065,13 +1065,13 @@ public:
         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
     }
 
-    DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst)
+    DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
     {
         moveFixedWidthEncoding(imm, dst);
         return DataLabel32(this);
     }
 
-    DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst)
+    DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
     {
         moveFixedWidthEncoding(Imm32(imm), dst);
         return DataLabelPtr(this);
@@ -1090,7 +1090,7 @@ public:
         return branch32(cond, addressTempRegister, dataTempRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
         store32(dataTempRegister, address);
@@ -1179,7 +1179,7 @@ protected:
         return addressTempRegister;
     }
 
-    void moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
+    void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
     {
         uint32_t value = imm.m_value;
         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
diff --git a/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
index 841fa9647128..6acdfd67a74d 100644
--- a/js/src/assembler/assembler/MacroAssemblerCodeRef.h
+++ b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
@@ -180,7 +180,8 @@ private:
 class MacroAssemblerCodeRef {
 public:
     MacroAssemblerCodeRef()
-        : m_size(0)
+        : m_executablePool(NULL),
+          m_size(0)
     {
     }
 
@@ -191,6 +192,20 @@ public:
     {
     }
 
+    // Release the code memory in this code ref.
+    void release()
+    {
+        if (!m_executablePool)
+            return;
+
+#if defined DEBUG && (defined WTF_CPU_X86 || defined WTF_CPU_X86_64) 
+        void *addr = m_code.executableAddress();
+        memset(addr, 0xcc, m_size);
+#endif
+        m_executablePool->release();
+        m_executablePool = NULL;
+    }
+
     MacroAssemblerCodePtr m_code;
     ExecutablePool* m_executablePool;
     size_t m_size;
diff --git a/js/src/assembler/assembler/MacroAssemblerSparc.h b/js/src/assembler/assembler/MacroAssemblerSparc.h
index 3bdd2d871b1b..91a8f0e16163 100644
--- a/js/src/assembler/assembler/MacroAssemblerSparc.h
+++ b/js/src/assembler/assembler/MacroAssemblerSparc.h
@@ -97,14 +97,14 @@ namespace JSC {
             m_assembler.addcc_r(dest, src, dest);
         }
 
-        void add32(Imm32 imm, Address address)
+        void add32(TrustedImm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             add32(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
         }
 
-        void add32(Imm32 imm, RegisterID dest)
+        void add32(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(dest, imm.m_value, dest);
@@ -126,7 +126,7 @@ namespace JSC {
             m_assembler.andcc_r(dest, SparcRegisters::g2, dest);
         }
 
-        void add32(Imm32 imm, RegisterID src, RegisterID dest)
+        void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(src, imm.m_value, dest);
@@ -194,7 +194,7 @@ namespace JSC {
             m_assembler.orcc_r(dest, src, dest);
         }
 
-        void or32(Imm32 imm, RegisterID dest)
+        void or32(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.orcc_imm(dest, imm.m_value, dest);
@@ -240,7 +240,7 @@ namespace JSC {
             m_assembler.subcc_r(dest, src, dest);
         }
 
-        void sub32(Imm32 imm, RegisterID dest)
+        void sub32(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.subcc_imm(dest, imm.m_value, dest);
@@ -250,7 +250,7 @@ namespace JSC {
             }
         }
 
-        void sub32(Imm32 imm, Address address)
+        void sub32(TrustedImm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -268,7 +268,7 @@ namespace JSC {
             m_assembler.xorcc_r(src, dest, dest);
         }
 
-        void xor32(Imm32 imm, RegisterID dest)
+        void xor32(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.xorcc_imm(dest, imm.m_value, dest);
@@ -548,7 +548,7 @@ namespace JSC {
             m_assembler.stw_r(src, address.base, SparcRegisters::g2);
         }
 
-        void store32(Imm32 imm, BaseIndex address)
+        void store32(TrustedImm32 imm, BaseIndex address)
         {
             m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
             add32(Imm32(address.offset), SparcRegisters::g2);
@@ -556,7 +556,7 @@ namespace JSC {
             m_assembler.stw_r(SparcRegisters::g3, SparcRegisters::g2, address.base);
         }
 
-        void store32(Imm32 imm, ImplicitAddress address)
+        void store32(TrustedImm32 imm, ImplicitAddress address)
         {
             m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -568,7 +568,7 @@ namespace JSC {
             m_assembler.stw_r(src, SparcRegisters::g0, SparcRegisters::g3);
         }
 
-        void store32(Imm32 imm, void* address)
+        void store32(TrustedImm32 imm, void* address)
         {
             move(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -598,7 +598,7 @@ namespace JSC {
             push(SparcRegisters::g2);
         }
 
-        void move(Imm32 imm, RegisterID dest)
+        void move(TrustedImm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.or_imm(SparcRegisters::g0, imm.m_value, dest);
@@ -611,7 +611,7 @@ namespace JSC {
             m_assembler.or_r(src, SparcRegisters::g0, dest);
         }
 
-        void move(ImmPtr imm, RegisterID dest)
+        void move(TrustedImmPtr imm, RegisterID dest)
         {
             move(Imm32(imm), dest);
         }
@@ -641,20 +641,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32_force32(Condition cond, RegisterID left, Imm32 right)
+        Jump branch32_force32(Condition cond, RegisterID left, TrustedImm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
             m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
+        Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g2);
             return branch32(cond, left, SparcRegisters::g2);
         }
 
-        Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
+        Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
         {
             // Always use move_nocheck, since the value is to be patched.
             dataLabel = DataLabel32(this);
@@ -669,7 +669,7 @@ namespace JSC {
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32(Condition cond, RegisterID left, Imm32 right)
+        Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
         {
             if (m_assembler.isimm13(right.m_value))
                 m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0);
@@ -692,20 +692,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, Address left, Imm32 right)
+        Jump branch32(Condition cond, Address left, TrustedImm32 right)
         {
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+        Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
         {
 
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
         {
             load32WithUnalignedHalfWords(left, SparcRegisters::g4);
             return branch32(cond, SparcRegisters::g4, right);
@@ -1052,7 +1052,7 @@ namespace JSC {
             store32(SparcRegisters::g2, address.m_ptr);
         }
 
-        void sub32(Imm32 imm, AbsoluteAddress address)
+        void sub32(TrustedImm32 imm, AbsoluteAddress address)
         {
             load32(address.m_ptr, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -1071,7 +1071,7 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+        Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
         {
             load32(left.m_ptr, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
@@ -1099,7 +1099,7 @@ namespace JSC {
             return Call::fromTailJump(oldJump);
         }
 
-        DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+        DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
         {
             DataLabelPtr dataLabel(this);
             Imm32 imm = Imm32(initialValue);
@@ -1107,7 +1107,7 @@ namespace JSC {
             return dataLabel;
         }
 
-        DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
+        DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
         {
             DataLabel32 dataLabel(this);
             m_assembler.move_nocheck(initialValue.m_value, dest);
@@ -1129,7 +1129,7 @@ namespace JSC {
             return jump;
         }
 
-        DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+        DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
         {
             DataLabelPtr dataLabel = moveWithPatch(initialValue, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86.h b/js/src/assembler/assembler/MacroAssemblerX86.h
index ee61b895a8fe..c6ab40f587fa 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(Imm32 imm, RegisterID src, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.leal_mr(imm.m_value, src, dest);
     }
@@ -90,12 +90,12 @@ public:
         m_assembler.andl_im(imm.m_value, address.m_ptr);
     }
     
-    void or32(Imm32 imm, AbsoluteAddress address)
+    void or32(TrustedImm32 imm, AbsoluteAddress address)
     {
         m_assembler.orl_im(imm.m_value, address.m_ptr);
     }
 
-    void sub32(Imm32 imm, AbsoluteAddress address)
+    void sub32(TrustedImm32 imm, AbsoluteAddress address)
     {
         m_assembler.subl_im(imm.m_value, address.m_ptr);
     }
@@ -148,7 +148,7 @@ public:
         addDouble(Address(srcDest), dest);
     }
 
-    void store32(Imm32 imm, void* address)
+    void store32(TrustedImm32 imm, void* address)
     {
         m_assembler.movl_i32m(imm.m_value, address);
     }
@@ -164,7 +164,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.m_ptr);
         return Jump(m_assembler.jCC(x86Condition(cond)));
@@ -186,7 +186,7 @@ public:
     }
 
 
-    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movl_i32r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -206,7 +206,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
     {
         m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base);
         return DataLabelPtr(this);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h
index 1ead9665f4e2..fa1b7ba8cb10 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86Common.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h
@@ -116,12 +116,12 @@ public:
         m_assembler.addl_rr(src, dest);
     }
 
-    void add32(Imm32 imm, Address address)
+    void add32(TrustedImm32 imm, Address address)
     {
         m_assembler.addl_im(imm.m_value, address.offset, address.base);
     }
 
-    void add32(Imm32 imm, RegisterID dest)
+    void add32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.addl_ir(imm.m_value, dest);
     }
@@ -234,7 +234,7 @@ public:
         m_assembler.orl_rr(src, dest);
     }
 
-    void or32(Imm32 imm, RegisterID dest)
+    void or32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.orl_ir(imm.m_value, dest);
     }
@@ -249,7 +249,7 @@ public:
         m_assembler.orl_mr(src.offset, src.base, dest);
     }
 
-    void or32(Imm32 imm, Address address)
+    void or32(TrustedImm32 imm, Address address)
     {
         m_assembler.orl_im(imm.m_value, address.offset, address.base);
     }
@@ -313,12 +313,12 @@ public:
         m_assembler.subl_rr(src, dest);
     }
     
-    void sub32(Imm32 imm, RegisterID dest)
+    void sub32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.subl_ir(imm.m_value, dest);
     }
     
-    void sub32(Imm32 imm, Address address)
+    void sub32(TrustedImm32 imm, Address address)
     {
         m_assembler.subl_im(imm.m_value, address.offset, address.base);
     }
@@ -339,12 +339,12 @@ public:
         m_assembler.xorl_rr(src, dest);
     }
 
-    void xor32(Imm32 imm, Address dest)
+    void xor32(TrustedImm32 imm, Address dest)
     {
         m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
     }
 
-    void xor32(Imm32 imm, RegisterID dest)
+    void xor32(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.xorl_ir(imm.m_value, dest);
     }
@@ -468,7 +468,7 @@ public:
         m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(Imm32 imm, BaseIndex address)
+    void store32(TrustedImm32 imm, BaseIndex address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
@@ -483,7 +483,7 @@ public:
         m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(Imm32 imm, ImplicitAddress address)
+    void store32(TrustedImm32 imm, ImplicitAddress address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
     }
@@ -748,7 +748,7 @@ public:
     //
     // Move values in registers.
 
-    void move(Imm32 imm, RegisterID dest)
+    void move(TrustedImm32 imm, RegisterID dest)
     {
         // Note: on 64-bit the Imm32 value is zero extended into the register, it
         // may be useful to have a separate version that sign extends the value?
@@ -767,7 +767,7 @@ public:
             m_assembler.movq_rr(src, dest);
     }
 
-    void move(ImmPtr imm, RegisterID dest)
+    void move(TrustedImmPtr imm, RegisterID dest)
     {
         m_assembler.movq_i64r(imm.asIntptr(), dest);
     }
@@ -798,7 +798,7 @@ public:
             m_assembler.movl_rr(src, dest);
     }
 
-    void move(ImmPtr imm, RegisterID dest)
+    void move(TrustedImmPtr imm, RegisterID dest)
     {
         m_assembler.movl_i32r(imm.asIntptr(), dest);
     }
@@ -852,7 +852,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, RegisterID left, Imm32 right)
+    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
     {
         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
             m_assembler.testl_rr(left, left);
@@ -864,14 +864,14 @@ public:
     // Branch based on a 32-bit comparison, forcing the size of the
     // immediate operand to 32 bits in the native code stream to ensure that
     // the length of code emitted by this instruction is consistent.
-    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
     {
         m_assembler.cmpl_ir_force32(right.m_value, left);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
     // Branch and record a label after the comparison.
-    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
     {
         // Always use cmpl, since the value is to be patched.
         m_assembler.cmpl_ir_force32(right.m_value, left);
@@ -879,7 +879,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
     {
         m_assembler.cmpl_im_force32(right.m_value, left.offset, left.base);
         dataLabel = DataLabel32(this);
@@ -898,19 +898,19 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, Address left, Imm32 right)
+    Jump branch32(Condition cond, Address left, TrustedImm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
     {
         return branch32(cond, left, right);
     }
@@ -1369,7 +1369,7 @@ private:
     }
 
 #if WTF_CPU_X86
-#if WTF_PLATFORM_MAC
+#if WTF_OS_MAC_OS_X
 
     // All X86 Macs are guaranteed to support at least SSE2
     static bool isSSEPresent()
@@ -1382,7 +1382,7 @@ private:
         return true;
     }
 
-#else // PLATFORM(MAC)
+#else // OS(MAC_OS_X)
 
     static bool isSSEPresent()
     {
diff --git a/js/src/assembler/assembler/MacroAssemblerX86_64.h b/js/src/assembler/assembler/MacroAssemblerX86_64.h
index 7dadc6bcaf2e..a5038a930e56 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86_64.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(Imm32 imm, AbsoluteAddress address)
+    void add32(TrustedImm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         add32(imm, Address(scratchRegister));
@@ -72,13 +72,13 @@ public:
         and32(imm, Address(scratchRegister));
     }
     
-    void or32(Imm32 imm, AbsoluteAddress address)
+    void or32(TrustedImm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         or32(imm, Address(scratchRegister));
     }
 
-    void sub32(Imm32 imm, AbsoluteAddress address)
+    void sub32(TrustedImm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         sub32(imm, Address(scratchRegister));
@@ -114,7 +114,7 @@ public:
         m_assembler.cvtsq2sd_rr(srcDest, dest);
     }
 
-    void store32(Imm32 imm, void* address)
+    void store32(TrustedImm32 imm, void* address)
     {
         move(X86Registers::eax, scratchRegister);
         move(imm, X86Registers::eax);
@@ -311,7 +311,7 @@ public:
         m_assembler.movq_rm(src, address.offset, address.base);
     }
 
-    void storePtr(ImmPtr imm, BaseIndex address)
+    void storePtr(TrustedImmPtr imm, BaseIndex address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -341,7 +341,7 @@ public:
         }
     }
 
-    void storePtr(ImmPtr imm, ImplicitAddress address)
+    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -487,7 +487,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -505,7 +505,7 @@ public:
         return branchPtr(cond, left, scratchRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
         storePtr(scratchRegister, address);
diff --git a/js/src/assembler/jit/ExecutableAllocator.h b/js/src/assembler/jit/ExecutableAllocator.h
index a54a4dab143b..9cca26f48c99 100644
--- a/js/src/assembler/jit/ExecutableAllocator.h
+++ b/js/src/assembler/jit/ExecutableAllocator.h
@@ -52,16 +52,16 @@ extern  "C" void sync_instruction_memory(caddr_t v, u_int len);
 #endif
 #endif
 
-#if WTF_PLATFORM_IPHONE
+#if WTF_OS_IOS
 #include 
 #include 
 #endif
 
-#if WTF_PLATFORM_SYMBIAN
+#if WTF_OS_SYMBIAN
 #include 
 #endif
 
-#if WTF_CPU_MIPS && WTF_PLATFORM_LINUX
+#if WTF_CPU_MIPS && WTF_OS_LINUX
 #include 
 #endif
 
@@ -90,7 +90,7 @@ private:
     struct Allocation {
         char* pages;
         size_t size;
-#if WTF_PLATFORM_SYMBIAN
+#if WTF_OS_SYMBIAN
         RChunk* chunk;
 #endif
     };
@@ -269,6 +269,7 @@ private:
         return pool;
     }
 
+public:
     ExecutablePool* poolForSize(size_t n)
     {
 #ifndef DEBUG_STRESS_JSC_ALLOCATOR
@@ -327,7 +328,6 @@ private:
         return pool;
     }
 
-public:
 #if ENABLE_ASSEMBLER_WX_EXCLUSIVE
     static void makeWritable(void* start, size_t size)
     {
@@ -374,13 +374,13 @@ public:
         _flush_cache(reinterpret_cast(code), size, BCACHE);
 #endif
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
+#elif WTF_CPU_ARM_THUMB2 && WTF_OS_IOS
     static void cacheFlush(void* code, size_t size)
     {
         sys_dcache_flush(code, size);
         sys_icache_invalidate(code, size);
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_LINUX
+#elif WTF_CPU_ARM_THUMB2 && WTF_IOS
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
@@ -396,14 +396,14 @@ public:
             : "r" (code), "r" (reinterpret_cast(code) + size)
             : "r0", "r1", "r2");
     }
-#elif WTF_PLATFORM_SYMBIAN
+#elif WTF_OS_SYMBIAN
     static void cacheFlush(void* code, size_t size)
     {
         User::IMB_Range(code, static_cast(code) + size);
     }
-#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
     static __asm void cacheFlush(void* code, size_t size);
-#elif WTF_CPU_ARM_TRADITIONAL && (WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID) && WTF_COMPILER_GCC
+#elif WTF_CPU_ARM_TRADITIONAL && (WTF_OS_LINUX || WTF_OS_ANDROID) && WTF_COMPILER_GCC
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
diff --git a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
index ef9e27d92b47..675b604ae914 100644
--- a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_PLATFORM_OS2
+#if ENABLE_ASSEMBLER && WTF_OS_OS2
 
 #define INCL_DOS
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
index 50efd932e02a..e334626ccc2f 100644
--- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
@@ -25,7 +25,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
 
 #include 
 #include 
@@ -74,7 +74,7 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe
 }
 #endif
 
-#if WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
+#if WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
 __asm void ExecutableAllocator::cacheFlush(void* code, size_t size)
 {
     ARM
diff --git a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
index c66fa80fff12..f51c0d507877 100644
--- a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
@@ -22,7 +22,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_PLATFORM_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_OS_SYMBIAN
 
 #include 
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorWin.cpp b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
index f5775608f36f..da6e756cfa66 100644
--- a/js/src/assembler/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_PLATFORM_WIN_OS
+#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
 
 #include "jswin.h"
 
diff --git a/js/src/assembler/wtf/Platform.h b/js/src/assembler/wtf/Platform.h
index 68713cd4c810..217c9b8a1eec 100644
--- a/js/src/assembler/wtf/Platform.h
+++ b/js/src/assembler/wtf/Platform.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc.  All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,206 +28,267 @@
 #ifndef WTF_Platform_h
 #define WTF_Platform_h
 
-/* Either XX(YY) --> WTF_XX_YY  or  XX(YY) --> XX_YY, depending on XX
-
-   PLATFORM(YY) --> WTF_PLATFORM_YY
-   COMPILER(YY) --> WTF_COMPILER_YY
-   CPU(YY)      --> WTF_CPU_YY
-   OS(YY)       --> WTF_OS_YY
-   USE(YY)      --> WTF_USE_YY
-
-   HAVE(YY)     --> HAVE_YY
-   ENABLE(YY)   --> ENABLE_YY
-*/
-
 /* ==== PLATFORM handles OS, operating environment, graphics API, and
    CPU. This macro will be phased out in favor of platform adaptation
    macros, policy decision macros, and top-level port definitions. ==== */
-//#define PLATFORM(WTF_FEATURE) (defined(WTF_PLATFORM_##WTF_FEATURE)  && WTF_PLATFORM_##WTF_FEATURE)
+#define PLATFORM(WTF_FEATURE) (defined WTF_PLATFORM_##WTF_FEATURE  && WTF_PLATFORM_##WTF_FEATURE)
 
 
 /* ==== Platform adaptation macros: these describe properties of the target environment. ==== */
 
 /* COMPILER() - the compiler being used to build the project */
-//#define COMPILER(WTF_FEATURE) (defined(WTF_COMPILER_##WTF_FEATURE)  && WTF_COMPILER_##WTF_FEATURE)
+#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE  && WTF_COMPILER_##WTF_FEATURE)
 /* CPU() - the target CPU architecture */
-//#define CPU(WTF_FEATURE) (defined(WTF_CPU_##WTF_FEATURE)  && WTF_CPU_##WTF_FEATURE)
+#define CPU(WTF_FEATURE) (defined WTF_CPU_##WTF_FEATURE  && WTF_CPU_##WTF_FEATURE)
 /* HAVE() - specific system features (headers, functions or similar) that are present or not */
-//#define HAVE(WTF_FEATURE) (defined(HAVE_##WTF_FEATURE)  && HAVE_##WTF_FEATURE)
+#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE  && HAVE_##WTF_FEATURE)
 /* OS() - underlying operating system; only to be used for mandated low-level services like 
    virtual memory, not to choose a GUI toolkit */
-//#define OS(WTF_FEATURE) (defined(WTF_OS_##WTF_FEATURE)  && WTF_OS_##WTF_FEATURE)
+#define OS(WTF_FEATURE) (defined WTF_OS_##WTF_FEATURE  && WTF_OS_##WTF_FEATURE)
 
 
 /* ==== Policy decision macros: these define policy choices for a particular port. ==== */
 
 /* USE() - use a particular third-party library or optional OS service */
-//#define USE(WTF_FEATURE) (defined(WTF_USE_##WTF_FEATURE)  && WTF_USE_##WTF_FEATURE)
+#define USE(WTF_FEATURE) (defined WTF_USE_##WTF_FEATURE  && WTF_USE_##WTF_FEATURE)
 /* ENABLE() - turn on a specific feature of WebKit */
-//#define ENABLE(WTF_FEATURE) (defined(ENABLE_##WTF_FEATURE)  && ENABLE_##WTF_FEATURE)
+#define ENABLE(WTF_FEATURE) (defined ENABLE_##WTF_FEATURE  && ENABLE_##WTF_FEATURE)
 
 
 
 /* ==== COMPILER() - the compiler being used to build the project ==== */
 
-/* COMPILER(MSVC) Microsoft Visual C++ */
-/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/
+/* WTF_COMPILER_MSVC Microsoft Visual C++ */
+/* WTF_COMPILER_MSVC7_OR_LOWER Microsoft Visual C++ 2003 or lower*/
+/* WTF_COMPILER_MSVC9_OR_LOWER Microsoft Visual C++ 2008 or lower*/
 #if defined(_MSC_VER)
 #define WTF_COMPILER_MSVC 1
 #if _MSC_VER < 1400
-#define WTF_COMPILER_MSVC7 1
+#define WTF_COMPILER_MSVC7_OR_LOWER 1
+#elif _MSC_VER < 1600
+#define WTF_COMPILER_MSVC9_OR_LOWER 1
 #endif
 #endif
 
-/* COMPILER(RVCT)  - ARM RealView Compilation Tools */
+/* WTF_COMPILER_RVCT  - ARM RealView Compilation Tools */
+/* WTF_COMPILER_RVCT4_OR_GREATER - ARM RealView Compilation Tools 4.0 or greater */
 #if defined(__CC_ARM) || defined(__ARMCC__)
 #define WTF_COMPILER_RVCT 1
+#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) (__ARMCC_VERSION >= (major * 100000 + minor * 10000 + patch * 1000 + build))
+#else
+/* Define this for !RVCT compilers, just so we can write things like RVCT_VERSION_AT_LEAST(3, 0, 0, 0). */
+#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) 0
 #endif
 
-/* COMPILER(GCC) - GNU Compiler Collection */
+/* WTF_COMPILER_GCC - GNU Compiler Collection */
 /* --gnu option of the RVCT compiler also defines __GNUC__ */
 #if defined(__GNUC__) && !WTF_COMPILER_RVCT
 #define WTF_COMPILER_GCC 1
 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch))
+#else
+/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */
+#define GCC_VERSION_AT_LEAST(major, minor, patch) 0
 #endif
 
-/* COMPILER(MINGW) - MinGW GCC */
-#if defined(MINGW) || defined(__MINGW32__)
+/* WTF_COMPILER_MINGW - MinGW GCC */
+/* WTF_COMPILER_MINGW64 - mingw-w64 GCC - only used as additional check to exclude mingw.org specific functions */
+#if defined(__MINGW32__)
 #define WTF_COMPILER_MINGW 1
-#endif
+#include <_mingw.h> /* private MinGW header */
+    #if defined(__MINGW64_VERSION_MAJOR) /* best way to check for mingw-w64 vs mingw.org */
+        #define WTF_COMPILER_MINGW64 1
+    #endif /* __MINGW64_VERSION_MAJOR */
+#endif /* __MINGW32__ */
 
-/* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */
+/* WTF_COMPILER_WINSCW - CodeWarrior for Symbian emulator */
 #if defined(__WINSCW__)
 #define WTF_COMPILER_WINSCW 1
+/* cross-compiling, it is not really windows */
+#undef WIN32
+#undef _WIN32
 #endif
 
-/* COMPILER(SUNPRO) - Sun Studio for Solaris */
-#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-#define WTF_COMPILER_SUNPRO 1
+/* WTF_COMPILER_INTEL - Intel C++ Compiler */
+#if defined(__INTEL_COMPILER)
+#define WTF_COMPILER_INTEL 1
 #endif
 
+/* WTF_COMPILER_SUNCC */
+#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
+#define WTF_COMPILER_SUNCC 1
+#endif
 
 /* ==== CPU() - the target CPU architecture ==== */
 
-/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */
+/* This also defines WTF_CPU_BIG_ENDIAN or WTF_CPU_MIDDLE_ENDIAN or neither, as appropriate. */
 
-
-/* CPU(ALPHA) - DEC Alpha */
+/* WTF_CPU_ALPHA - DEC Alpha */
 #if defined(__alpha__)
 #define WTF_CPU_ALPHA 1
 #endif
 
-/* CPU(IA64) - Itanium / IA-64 */
+/* WTF_CPU_IA64 - Itanium / IA-64 */
 #if defined(__ia64__)
 #define WTF_CPU_IA64 1
+/* 32-bit mode on Itanium */
+#if !defined(__LP64__)
+#define WTF_CPU_IA64_32 1
+#endif
 #endif
 
-/* CPU(PPC) - PowerPC 32-bit */
+/* WTF_CPU_MIPS - MIPS 32-bit */
+/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now.  */
+#if (defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_)) \
+    && defined(_ABIO32)
+#define WTF_CPU_MIPS 1
+#if defined(__MIPSEB__)
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+#define WTF_MIPS_PIC (defined __PIC__)
+#define WTF_MIPS_ARCH __mips
+#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v)
+#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v)
+#define WTF_MIPS_ARCH_REV __mips_isa_rev
+#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
+#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float)
+#define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64)
+/* MIPS requires allocators to use aligned memory */
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
+#endif /* MIPS */
+
+/* WTF_CPU_PPC - PowerPC 32-bit */
 #if   defined(__ppc__)     \
-   || defined(__PPC__)     \
-   || defined(__powerpc__) \
-   || defined(__powerpc)   \
-   || defined(__POWERPC__) \
-   || defined(_M_PPC)      \
-   || defined(__PPC)
+    || defined(__PPC__)     \
+    || defined(__powerpc__) \
+    || defined(__powerpc)   \
+    || defined(__POWERPC__) \
+    || defined(_M_PPC)      \
+    || defined(__PPC)
 #define WTF_CPU_PPC 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* CPU(PPC64) - PowerPC 64-bit */
+/* WTF_CPU_PPC64 - PowerPC 64-bit */
 #if   defined(__ppc64__) \
-   || defined(__PPC64__)
+    || defined(__PPC64__)
 #define WTF_CPU_PPC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* CPU(SH4) - SuperH SH-4 */
+/* WTF_CPU_SH4 - SuperH SH-4 */
 #if defined(__SH4__)
 #define WTF_CPU_SH4 1
 #endif
 
-/* CPU(SPARC32) - SPARC 32-bit */
+/* WTF_CPU_SPARC32 - SPARC 32-bit */
 #if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8)
 #define WTF_CPU_SPARC32 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* CPU(SPARC64) - SPARC 64-bit */
+/* WTF_CPU_SPARC64 - SPARC 64-bit */
 #if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)
 #define WTF_CPU_SPARC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */
+/* WTF_CPU_SPARC - any SPARC, true for WTF_CPU_SPARC32 and WTF_CPU_SPARC64 */
 #if WTF_CPU_SPARC32 || WTF_CPU_SPARC64
 #define WTF_CPU_SPARC 1
 #endif
 
-/* CPU(X86) - i386 / x86 32-bit */
+/* WTF_CPU_S390X - S390 64-bit */
+#if defined(__s390x__)
+#define WTF_CPU_S390X 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* WTF_CPU_S390 - S390 32-bit */
+#if defined(__s390__)
+#define WTF_CPU_S390 1
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+
+/* WTF_CPU_X86 - i386 / x86 32-bit */
 #if   defined(__i386__) \
-   || defined(i386)     \
-   || defined(_M_IX86)  \
-   || defined(_X86_)    \
-   || defined(__THW_INTEL)
+    || defined(i386)     \
+    || defined(_M_IX86)  \
+    || defined(_X86_)    \
+    || defined(__THW_INTEL)
 #define WTF_CPU_X86 1
 #endif
 
-/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */
+/* WTF_CPU_X86_64 - AMD64 / Intel64 / x86_64 64-bit */
 #if   defined(__x86_64__) \
-   || defined(_M_X64)
+    || defined(_M_X64)
 #define WTF_CPU_X86_64 1
 #endif
 
-/* CPU(ARM) - ARM, any version*/
+/* WTF_CPU_ARM - ARM, any version*/
 #if   defined(arm) \
-   || defined(__arm__)
+    || defined(__arm__) \
+    || defined(ARM) \
+    || defined(_ARM_)
 #define WTF_CPU_ARM 1
 
-#if defined(__ARMEB__)
+#if defined(__ARMEB__) || (WTF_COMPILER_RVCT && defined(__BIG_ENDIAN))
 #define WTF_CPU_BIG_ENDIAN 1
 
 #elif !defined(__ARM_EABI__) \
-   && !defined(__EABI__) \
-   && !defined(__VFP_FP__) \
-   && !defined(ANDROID)
+    && !defined(__EABI__) \
+    && !defined(__VFP_FP__) \
+    && !defined(_WIN32_WCE) \
+    && !defined(ANDROID)
 #define WTF_CPU_MIDDLE_ENDIAN 1
 
 #endif
 
-#define WTF_ARM_ARCH_AT_LEAST(N) (WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= N)
+#define WTF_ARM_ARCH_AT_LEAST(N) (CPU(ARM) && WTF_ARM_ARCH_VERSION >= N)
 
 /* Set WTF_ARM_ARCH_VERSION */
 #if   defined(__ARM_ARCH_4__) \
-   || defined(__ARM_ARCH_4T__) \
-   || defined(__MARM_ARMV4__) \
-   || defined(_ARMV4I_)
+    || defined(__ARM_ARCH_4T__) \
+    || defined(__MARM_ARMV4__) \
+    || defined(_ARMV4I_)
 #define WTF_ARM_ARCH_VERSION 4
 
 #elif defined(__ARM_ARCH_5__) \
-   || defined(__ARM_ARCH_5T__) \
-   || defined(__ARM_ARCH_5E__) \
-   || defined(__ARM_ARCH_5TE__) \
-   || defined(__ARM_ARCH_5TEJ__) \
-   || defined(__MARM_ARMV5__)
+    || defined(__ARM_ARCH_5T__) \
+    || defined(__MARM_ARMV5__)
 #define WTF_ARM_ARCH_VERSION 5
 
+#elif defined(__ARM_ARCH_5E__) \
+    || defined(__ARM_ARCH_5TE__) \
+    || defined(__ARM_ARCH_5TEJ__)
+#define WTF_ARM_ARCH_VERSION 5
+/*ARMv5TE requires allocators to use aligned memory*/
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
+
 #elif defined(__ARM_ARCH_6__) \
-   || defined(__ARM_ARCH_6J__) \
-   || defined(__ARM_ARCH_6K__) \
-   || defined(__ARM_ARCH_6Z__) \
-   || defined(__ARM_ARCH_6ZK__) \
-   || defined(__ARM_ARCH_6T2__) \
-   || defined(__ARMV6__)
+    || defined(__ARM_ARCH_6J__) \
+    || defined(__ARM_ARCH_6K__) \
+    || defined(__ARM_ARCH_6Z__) \
+    || defined(__ARM_ARCH_6ZK__) \
+    || defined(__ARM_ARCH_6T2__) \
+    || defined(__ARMV6__)
 #define WTF_ARM_ARCH_VERSION 6
 
 #elif defined(__ARM_ARCH_7A__) \
-   || defined(__ARM_ARCH_7R__)
+    || defined(__ARM_ARCH_7R__)
 #define WTF_ARM_ARCH_VERSION 7
 
 /* RVCT sets _TARGET_ARCH_ARM */
 #elif defined(__TARGET_ARCH_ARM)
 #define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM
 
+#if defined(__TARGET_ARCH_5E) \
+    || defined(__TARGET_ARCH_5TE) \
+    || defined(__TARGET_ARCH_5TEJ)
+/*ARMv5TE requires allocators to use aligned memory*/
+#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
+#endif
+
 #else
 #define WTF_ARM_ARCH_VERSION 0
 
@@ -237,22 +299,22 @@
 #define WTF_THUMB_ARCH_VERSION 1
 
 #elif defined(__ARM_ARCH_5T__) \
-   || defined(__ARM_ARCH_5TE__) \
-   || defined(__ARM_ARCH_5TEJ__)
+    || defined(__ARM_ARCH_5TE__) \
+    || defined(__ARM_ARCH_5TEJ__)
 #define WTF_THUMB_ARCH_VERSION 2
 
 #elif defined(__ARM_ARCH_6J__) \
-   || defined(__ARM_ARCH_6K__) \
-   || defined(__ARM_ARCH_6Z__) \
-   || defined(__ARM_ARCH_6ZK__) \
-   || defined(__ARM_ARCH_6M__)
+    || defined(__ARM_ARCH_6K__) \
+    || defined(__ARM_ARCH_6Z__) \
+    || defined(__ARM_ARCH_6ZK__) \
+    || defined(__ARM_ARCH_6M__)
 #define WTF_THUMB_ARCH_VERSION 3
 
 #elif defined(__ARM_ARCH_6T2__) \
-   || defined(__ARM_ARCH_7__) \
-   || defined(__ARM_ARCH_7A__) \
-   || defined(__ARM_ARCH_7R__) \
-   || defined(__ARM_ARCH_7M__)
+    || defined(__ARM_ARCH_7__) \
+    || defined(__ARM_ARCH_7A__) \
+    || defined(__ARM_ARCH_7R__) \
+    || defined(__ARM_ARCH_7M__)
 #define WTF_THUMB_ARCH_VERSION 4
 
 /* RVCT sets __TARGET_ARCH_THUMB */
@@ -264,22 +326,22 @@
 #endif
 
 
-/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */
+/* WTF_CPU_ARMV5_OR_LOWER - ARM instruction set v5 or earlier */
 /* On ARMv5 and below the natural alignment is required. 
    And there are some other differences for v5 or earlier. */
-#if !defined(ARMV5_OR_LOWER) /* && !CPU_ARM_ARCH_AT_LEAST(6) */
+#if !defined(ARMV5_OR_LOWER) && !WTF_ARM_ARCH_AT_LEAST(6)
 #define WTF_CPU_ARMV5_OR_LOWER 1
 #endif
 
 
-/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */
-/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */
+/* WTF_CPU_ARM_TRADITIONAL - Thumb2 is not available, only traditional ARM (v4 or greater) */
+/* WTF_CPU_ARM_THUMB2 - Thumb2 instruction set is available */
 /* Only one of these will be defined. */
 #if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
 #  if defined(thumb2) || defined(__thumb2__) \
-  || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
-#    define WTF_CPU_ARM_TRADITIONAL 1
-#    define WTF_CPU_ARM_THUMB2 0
+    || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
+#    define WTF_CPU_ARM_TRADITIONAL 0
+#    define WTF_CPU_ARM_THUMB2 1
 #  elif WTF_ARM_ARCH_AT_LEAST(4)
 #    define WTF_CPU_ARM_TRADITIONAL 1
 #    define WTF_CPU_ARM_THUMB2 0
@@ -288,19 +350,36 @@
 #  endif
 #elif WTF_CPU_ARM_TRADITIONAL && WTF_CPU_ARM_THUMB2 /* Sanity Check */
 #  error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms"
-#endif // !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
+#endif /* !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) */
+
+#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON)
+#define WTF_CPU_ARM_NEON 1
+#endif
 
 #endif /* ARM */
 
+#if WTF_CPU_ARM || WTF_CPU_MIPS
+#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
+#endif
 
+/* ==== OS() - underlying operating system; only to be used for mandated low-level services like 
+   virtual memory, not to choose a GUI toolkit ==== */
 
-/* Operating systems - low-level dependencies */
+/* WTF_OS_ANDROID - Android */
+#ifdef ANDROID
+#define WTF_OS_ANDROID 1
+#endif
 
-/* PLATFORM(DARWIN) */
-/* Operating system level dependencies for Mac OS X / Darwin that should */
-/* be used regardless of operating environment */
+/* WTF_OS_AIX - AIX */
+#ifdef _AIX
+#define WTF_OS_AIX 1
+#endif
+
+/* WTF_OS_DARWIN - Any Darwin-based OS, including Mac OS X and iPhone OS */
 #ifdef __APPLE__
-#define WTF_PLATFORM_DARWIN 1
+#define WTF_OS_DARWIN 1
+
+/* FIXME: BUILDING_ON_.., and TARGETING... macros should be folded into the OS() system */
 #include 
 #if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
 #define BUILDING_ON_TIGER 1
@@ -317,98 +396,97 @@
 #define TARGETING_SNOW_LEOPARD 1
 #endif
 #include 
+
 #endif
 
-/* PLATFORM(WIN_OS) */
-/* Operating system level dependencies for Windows that should be used */
-/* regardless of operating environment */
-#if defined(WIN32) || defined(_WIN32)
-#define WTF_PLATFORM_WIN_OS 1
+/* WTF_OS_IOS - iOS */
+/* WTF_OS_MAC_OS_X - Mac OS X (not including iOS) */
+#if WTF_OS_DARWIN && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED)  \
+    || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)                   \
+    || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR))
+#define WTF_OS_IOS 1
+#elif WTF_OS_DARWIN && defined(TARGET_OS_MAC) && TARGET_OS_MAC
+#define WTF_OS_MAC_OS_X 1
 #endif
 
-/* PLATFORM(LINUX) */
-/* Operating system level dependencies for Linux-like systems that */
-/* should be used regardless of operating environment */
+/* WTF_OS_FREEBSD - FreeBSD */
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#define WTF_OS_FREEBSD 1
+#endif
+
+/* WTF_OS_HAIKU - Haiku */
+#ifdef __HAIKU__
+#define WTF_OS_HAIKU 1
+#endif
+
+/* WTF_OS_LINUX - Linux */
 #ifdef __linux__
-#define WTF_PLATFORM_LINUX 1
+#define WTF_OS_LINUX 1
 #endif
 
-/* PLATFORM(FREEBSD) */
-/* Operating system level dependencies for FreeBSD-like systems that */
-/* should be used regardless of operating environment */
-#ifdef __FreeBSD__
-#define WTF_PLATFORM_FREEBSD 1
-#endif
-
-/* PLATFORM(OPENBSD) */
-/* Operating system level dependencies for OpenBSD systems that */
-/* should be used regardless of operating environment */
-#ifdef __OpenBSD__
-#define WTF_PLATFORM_OPENBSD 1
-#endif
-
-/* PLATFORM(SOLARIS) */
-/* Operating system level dependencies for Solaris that should be used */
-/* regardless of operating environment */
-#if defined(sun) || defined(__sun)
-#define WTF_PLATFORM_SOLARIS 1
-#endif
-
-/* PLATFORM(OS2) */
-/* Operating system level dependencies for OS/2 that should be used */
-/* regardless of operating environment */
-#if defined(OS2) || defined(__OS2__)
-#define WTF_PLATFORM_OS2 1
-#endif
-
-#if defined (__SYMBIAN32__)
-/* we are cross-compiling, it is not really windows */
-#undef WTF_PLATFORM_WIN_OS
-#undef WTF_PLATFORM_WIN
-#define WTF_PLATFORM_SYMBIAN 1
-#endif
-
-
-/* PLATFORM(NETBSD) */
-/* Operating system level dependencies for NetBSD that should be used */
-/* regardless of operating environment */
+/* WTF_OS_NETBSD - NetBSD */
 #if defined(__NetBSD__)
-#define WTF_PLATFORM_NETBSD 1
+#define WTF_OS_NETBSD 1
 #endif
 
-/* PLATFORM(QNX) */
-/* Operating system level dependencies for QNX that should be used */
-/* regardless of operating environment */
+/* WTF_OS_OPENBSD - OpenBSD */
+#ifdef __OpenBSD__
+#define WTF_OS_OPENBSD 1
+#endif
+
+/* WTF_OS_QNX - QNX */
 #if defined(__QNXNTO__)
-#define WTF_PLATFORM_QNX 1
+#define WTF_OS_QNX 1
 #endif
 
-/* PLATFORM(UNIX) */
-/* Operating system level dependencies for Unix-like systems that */
-/* should be used regardless of operating environment */
-#if   WTF_PLATFORM_DARWIN     \
-   || WTF_PLATFORM_FREEBSD    \
-   || WTF_PLATFORM_SYMBIAN    \
-   || WTF_PLATFORM_NETBSD     \
-   || defined(unix)        \
-   || defined(__unix)      \
-   || defined(__unix__)    \
-   || defined(_AIX)        \
-   || defined(__HAIKU__)   \
-   || defined(__QNXNTO__)  \
-   || defined(ANDROID)
-#define WTF_PLATFORM_UNIX 1
+/* WTF_OS_SOLARIS - Solaris */
+#if defined(sun) || defined(__sun)
+#define WTF_OS_SOLARIS 1
+#endif
+
+/* WTF_OS_WINCE - Windows CE; note that for this platform WTF_OS_WINDOWS is also defined */
+#if defined(_WIN32_WCE)
+#define WTF_OS_WINCE 1
+#endif
+
+/* WTF_OS_WINDOWS - Any version of Windows */
+#if defined(WIN32) || defined(_WIN32)
+#define WTF_OS_WINDOWS 1
+#endif
+
+/* WTF_OS_SYMBIAN - Symbian */
+#if defined (__SYMBIAN32__)
+#define WTF_OS_SYMBIAN 1
+#endif
+
+/* WTF_OS_UNIX - Any Unix-like system */
+#if   WTF_OS_AIX              \
+    || WTF_OS_ANDROID          \
+    || WTF_OS_DARWIN           \
+    || WTF_OS_FREEBSD          \
+    || WTF_OS_HAIKU            \
+    || WTF_OS_LINUX            \
+    || WTF_OS_NETBSD           \
+    || WTF_OS_OPENBSD          \
+    || WTF_OS_QNX              \
+    || WTF_OS_SOLARIS          \
+    || WTF_OS_SYMBIAN          \
+    || defined(unix)        \
+    || defined(__unix)      \
+    || defined(__unix__)
+#define WTF_OS_UNIX 1
 #endif
 
 /* Operating environments */
 
-/* PLATFORM(CHROMIUM) */
-/* PLATFORM(QT) */
-/* PLATFORM(WX) */
-/* PLATFORM(GTK) */
-/* PLATFORM(HAIKU) */
-/* PLATFORM(MAC) */
-/* PLATFORM(WIN) */
+/* FIXME: these are all mixes of OS, operating environment and policy choices. */
+/* WTF_PLATFORM_CHROMIUM */
+/* WTF_PLATFORM_QT */
+/* WTF_PLATFORM_WX */
+/* WTF_PLATFORM_GTK */
+/* WTF_PLATFORM_HAIKU */
+/* WTF_PLATFORM_MAC */
+/* WTF_PLATFORM_WIN */
 #if defined(BUILDING_CHROMIUM__)
 #define WTF_PLATFORM_CHROMIUM 1
 #elif defined(BUILDING_QT__)
@@ -419,142 +497,229 @@
 #define WTF_PLATFORM_GTK 1
 #elif defined(BUILDING_HAIKU__)
 #define WTF_PLATFORM_HAIKU 1
-#elif WTF_PLATFORM_DARWIN
+#elif defined(BUILDING_BREWMP__)
+#define WTF_PLATFORM_BREWMP 1
+#if defined(AEE_SIMULATOR)
+#define WTF_PLATFORM_BREWMP_SIMULATOR 1
+#else
+#define WTF_PLATFORM_BREWMP_SIMULATOR 0
+#endif
+#undef WTF_OS_WINDOWS
+#undef WTF_PLATFORM_WIN
+#elif WTF_OS_DARWIN
 #define WTF_PLATFORM_MAC 1
-#elif WTF_PLATFORM_WIN_OS
+#elif WTF_OS_WINDOWS
 #define WTF_PLATFORM_WIN 1
 #endif
 
-/* PLATFORM(IPHONE) */
+/* WTF_PLATFORM_IOS */
+/* FIXME: this is sometimes used as an OS switch and sometimes for higher-level things */
 #if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
-#define WTF_PLATFORM_IPHONE 1
+#define WTF_PLATFORM_IOS 1
 #endif
 
-/* PLATFORM(IPHONE_SIMULATOR) */
+/* WTF_PLATFORM_IOS_SIMULATOR */
 #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
-#define WTF_PLATFORM_IPHONE 1
-#define WTF_PLATFORM_IPHONE_SIMULATOR 1
+#define WTF_PLATFORM_IOS 1
+#define WTF_PLATFORM_IOS_SIMULATOR 1
 #else
-#define WTF_PLATFORM_IPHONE_SIMULATOR 0
+#define WTF_PLATFORM_IOS_SIMULATOR 0
 #endif
 
-#if !defined(WTF_PLATFORM_IPHONE)
-#define WTF_PLATFORM_IPHONE 0
+#if !defined(WTF_PLATFORM_IOS)
+#define WTF_PLATFORM_IOS 0
 #endif
 
-/* PLATFORM(ANDROID) */
+/* WTF_PLATFORM_ANDROID */
+/* FIXME: this is sometimes used as an OS() switch, and other times to drive
+   policy choices */
 #if defined(ANDROID)
 #define WTF_PLATFORM_ANDROID 1
 #endif
 
 /* Graphics engines */
 
-/* PLATFORM(CG) and PLATFORM(CI) */
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_IPHONE
-#define WTF_PLATFORM_CG 1
+/* WTF_USE_CG and WTF_PLATFORM_CI */
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS
+#define WTF_USE_CG 1
 #endif
-#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
-#define WTF_PLATFORM_CI 1
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS || (WTF_PLATFORM_WIN && WTF_USE_CG)
+#define WTF_USE_CA 1
 #endif
 
-/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */
+/* WTF_USE_SKIA for Win/Linux, CG for Mac */
 #if WTF_PLATFORM_CHROMIUM
-#if WTF_PLATFORM_DARWIN
-#define WTF_PLATFORM_CG 1
-#define WTF_PLATFORM_CI 1
+#if WTF_OS_DARWIN
+#define WTF_USE_CG 1
 #define WTF_USE_ATSUI 1
 #define WTF_USE_CORE_TEXT 1
+#define WTF_USE_ICCJPEG 1
 #else
-#define WTF_PLATFORM_SKIA 1
+#define WTF_USE_SKIA 1
+#define WTF_USE_CHROMIUM_NET 1
 #endif
 #endif
 
+#if WTF_PLATFORM_BREWMP
+#define WTF_USE_SKIA 1
+#endif
+
 #if WTF_PLATFORM_GTK
-#define WTF_PLATFORM_CAIRO 1
+#define WTF_USE_CAIRO 1
 #endif
 
 
-#if (WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_OS2 || (WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
+#if WTF_OS_WINCE
+#include 
+#define WTF_USE_MERSENNE_TWISTER_19937 1
+#endif
+
+#if WTF_PLATFORM_QT && WTF_OS_UNIX && !WTF_OS_SYMBIAN && !WTF_OS_DARWIN
+#define WTF_USE_PTHREAD_BASED_QT 1
+#endif
+
+#if (WTF_PLATFORM_GTK || WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || (WTF_PLATFORM_QT && (WTF_OS_DARWIN || WTF_USE_PTHREAD_BASED_QT) && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
 #define ENABLE_JSC_MULTIPLE_THREADS 1
 #endif
 
+#if ENABLE_JSC_MULTIPLE_THREADS
+#define ENABLE_WTF_MULTIPLE_THREADS 1
+#endif
+
 /* On Windows, use QueryPerformanceCounter by default */
-#if WTF_PLATFORM_WIN_OS
+#if WTF_OS_WINDOWS
 #define WTF_USE_QUERY_PERFORMANCE_COUNTER  1
 #endif
 
+#if WTF_OS_WINCE && !WTF_PLATFORM_QT
+#define NOMINMAX       /* Windows min and max conflict with standard macros */
+#define NOSHLWAPI      /* shlwapi.h not available on WinCe */
+
+/* MSDN documentation says these functions are provided with uspce.lib.  But we cannot find this file. */
+#define __usp10__      /* disable "usp10.h" */
+
+#define _INC_ASSERT    /* disable "assert.h" */
+#define assert(x)
+
+#endif  /* WTF_OS_WINCE && !WTF_PLATFORM_QT */
+
 #if WTF_PLATFORM_QT
 #define WTF_USE_QT4_UNICODE 1
+#elif WTF_OS_WINCE
+#define WTF_USE_WINCE_UNICODE 1
+#elif WTF_PLATFORM_BREWMP
+#define WTF_USE_BREWMP_UNICODE 1
 #elif WTF_PLATFORM_GTK
 /* The GTK+ Unicode backend is configurable */
 #else
 #define WTF_USE_ICU_UNICODE 1
 #endif
 
-#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
-#define WTF_PLATFORM_CF 1
-#define WTF_USE_PTHREADS 1
-#define HAVE_PTHREAD_RWLOCK 1
+#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && WTF_CPU_X86_64
 #define WTF_USE_PLUGIN_HOST_PROCESS 1
 #endif
-#if !defined(ENABLE_MAC_JAVA_BRIDGE)
-#define ENABLE_MAC_JAVA_BRIDGE 1
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#define ENABLE_GESTURE_EVENTS 1
+#define ENABLE_RUBBER_BANDING 1
+#define WTF_USE_WK_SCROLLBAR_PAINTER 1
+#endif
+#if !defined(ENABLE_JAVA_BRIDGE)
+#define ENABLE_JAVA_BRIDGE 1
 #endif
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 1
 #endif
+#define WTF_USE_CF 1
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
 #define HAVE_READLINE 1
 #define HAVE_RUNLOOP_TIMER 1
-#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */
+#define ENABLE_FULLSCREEN_API 1
+#define ENABLE_SMOOTH_SCROLLING 1
+#define ENABLE_WEB_ARCHIVE 1
+#endif /* WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS */
 
-#if WTF_PLATFORM_CHROMIUM && WTF_PLATFORM_DARWIN
-#define WTF_PLATFORM_CF 1
+#if WTF_PLATFORM_CHROMIUM && WTF_OS_DARWIN
+#define WTF_USE_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
 #endif
 
-#if WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN
-#define WTF_PLATFORM_CF 1
+#if WTF_PLATFORM_BREWMP
+#define ENABLE_SINGLE_THREADED 1
 #endif
 
-#if WTF_PLATFORM_IPHONE
+#if WTF_PLATFORM_QT && WTF_OS_DARWIN
+#define WTF_USE_CF 1
+#endif
+
+#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER) && !WTF_PLATFORM_GTK && !WTF_PLATFORM_QT
+#define ENABLE_PURGEABLE_MEMORY 1
+#endif
+
+#if WTF_PLATFORM_IOS
 #define ENABLE_CONTEXT_MENUS 0
 #define ENABLE_DRAG_SUPPORT 0
+#define ENABLE_DATA_TRANSFER_ITEMS 0
 #define ENABLE_FTPDIR 1
 #define ENABLE_GEOLOCATION 1
 #define ENABLE_ICONDATABASE 0
 #define ENABLE_INSPECTOR 0
-#define ENABLE_MAC_JAVA_BRIDGE 0
+#define ENABLE_JAVA_BRIDGE 0
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #define ENABLE_ORIENTATION_EVENTS 1
 #define ENABLE_REPAINT_THROTTLING 1
 #define HAVE_READLINE 1
-#define WTF_PLATFORM_CF 1
+#define WTF_USE_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
+#define ENABLE_WEB_ARCHIVE 1
 #endif
 
 #if WTF_PLATFORM_ANDROID
 #define WTF_USE_PTHREADS 1
-#define WTF_PLATFORM_SGL 1
 #define USE_SYSTEM_MALLOC 1
-#define ENABLE_MAC_JAVA_BRIDGE 1
+#define ENABLE_JAVA_BRIDGE 1
 #define LOG_DISABLED 1
-// Prevents Webkit from drawing the caret in textfields and textareas
-// This prevents unnecessary invals.
+/* Prevents Webkit from drawing the caret in textfields and textareas
+   This prevents unnecessary invals. */
 #define ENABLE_TEXT_CARET 1
 #define ENABLE_JAVASCRIPT_DEBUGGER 0
+#if !defined(ENABLE_JIT) && !ENABLE_ANDROID_JSC_JIT
+#define ENABLE_JIT 0
+#endif
 #endif
 
-#if WTF_PLATFORM_WIN
-#define WTF_USE_WININET 1
+#if WTF_PLATFORM_WIN && !WTF_OS_WINCE
+#define WTF_USE_CF 1
+#define WTF_USE_PTHREADS 0
+#endif
+
+#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !defined(WIN_CAIRO)
+#define WTF_USE_CFNETWORK 1
+#endif
+
+#if WTF_USE_CFNETWORK || WTF_PLATFORM_MAC
+#define WTF_USE_CFURLCACHE 1
+#define WTF_USE_CFURLSTORAGESESSIONS 1
+#endif
+
+#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !WTF_PLATFORM_QT
+#define ENABLE_WEB_ARCHIVE 1
 #endif
 
 #if WTF_PLATFORM_WX
 #define ENABLE_ASSEMBLER 1
-#if WTF_PLATFORM_DARWIN
-#define WTF_PLATFORM_CF 1
+#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
+#if WTF_OS_DARWIN
+#define WTF_USE_CF 1
+#ifndef BUILDING_ON_TIGER
+#define WTF_USE_CORE_TEXT 1
+#define ENABLE_WEB_ARCHIVE 1
+#else
+#define WTF_USE_ATSUI 1
+#endif
 #endif
 #endif
 
@@ -574,25 +739,39 @@
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #endif
 
+#if WTF_PLATFORM_BREWMP
+#define USE_SYSTEM_MALLOC 1
+#endif
+
+#if WTF_PLATFORM_BREWMP_SIMULATOR
+#define ENABLE_JIT 0
+#endif
+
 #if !defined(HAVE_ACCESSIBILITY)
-#if WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
+#if WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
 #define HAVE_ACCESSIBILITY 1
 #endif
 #endif /* !defined(HAVE_ACCESSIBILITY) */
 
-#if WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
+#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
 #define HAVE_SIGNAL_H 1
 #endif
 
-#if !WTF_PLATFORM_WIN_OS && !WTF_PLATFORM_SOLARIS && !WTF_PLATFORM_QNX \
-    && !WTF_PLATFORM_SYMBIAN && !WTF_PLATFORM_HAIKU && !WTF_COMPILER_RVCT \
-    && !WTF_PLATFORM_ANDROID && !WTF_PLATFORM_OS2
+#if !defined(HAVE_STRNSTR)
+#if WTF_OS_DARWIN || WTF_OS_FREEBSD
+#define HAVE_STRNSTR 1
+#endif
+#endif
+
+#if !WTF_OS_WINDOWS && !WTF_OS_SOLARIS && !WTF_OS_QNX \
+    && !WTF_OS_SYMBIAN && !WTF_OS_HAIKU && !WTF_OS_RVCT \
+    && !WTF_OS_ANDROID && !WTF_PLATFORM_BREWMP
 #define HAVE_TM_GMTOFF 1
 #define HAVE_TM_ZONE 1
 #define HAVE_TIMEGM 1
-#endif     
+#endif
 
-#if WTF_PLATFORM_DARWIN
+#if WTF_OS_DARWIN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 1
@@ -603,23 +782,37 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 #define HAVE_SYS_TIMEB_H 1
+#define WTF_USE_ACCELERATE 1
 
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !WTF_PLATFORM_IPHONE && !WTF_PLATFORM_QT
+#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD)
+
+#define HAVE_DISPATCH_H 1
+#define HAVE_HOSTED_CORE_ANIMATION 1
+
+#if !WTF_PLATFORM_IOS
 #define HAVE_MADV_FREE_REUSE 1
 #define HAVE_MADV_FREE 1
 #define HAVE_PTHREAD_SETNAME_NP 1
 #endif
 
-#if WTF_PLATFORM_IPHONE
+#endif
+
+#if WTF_PLATFORM_IOS
 #define HAVE_MADV_FREE 1
 #endif
 
-#elif WTF_PLATFORM_WIN_OS
+#elif WTF_OS_WINDOWS
 
+#if WTF_OS_WINCE
+#define HAVE_ERRNO_H 0
+#else
 #define HAVE_SYS_TIMEB_H 1
+#define HAVE_ALIGNED_MALLOC 1
+#define HAVE_ISDEBUGGERPRESENT 1
+#endif
 #define HAVE_VIRTUALALLOC 1
 
-#elif WTF_PLATFORM_SYMBIAN
+#elif WTF_OS_SYMBIAN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 0
@@ -632,7 +825,11 @@
 #define HAVE_SYS_PARAM_H 1
 #endif
 
-#elif WTF_PLATFORM_QNX
+#elif WTF_PLATFORM_BREWMP
+
+#define HAVE_ERRNO_H 1
+
+#elif WTF_OS_QNX
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 1
@@ -641,7 +838,7 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
-#elif WTF_PLATFORM_ANDROID
+#elif WTF_OS_ANDROID
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 0
@@ -651,23 +848,13 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
-#elif WTF_PLATFORM_OS2
-
-#define HAVE_MMAP 1
-#define ENABLE_ASSEMBLER 1
-#define HAVE_ERRNO_H 1
-#define HAVE_STRINGS_H 1
-#define HAVE_SYS_PARAM_H 1
-#define HAVE_SYS_TIME_H 1
-#define HAVE_SYS_TIMEB_H 1
-
 #else
 
 /* FIXME: is this actually used or do other platforms generate their own config.h? */
 
 #define HAVE_ERRNO_H 1
 /* As long as Haiku doesn't have a complete support of locale this will be disabled. */
-#if !WTF_PLATFORM_HAIKU
+#if !WTF_OS_HAIKU
 #define HAVE_LANGINFO_H 1
 #endif
 #define HAVE_MMAP 1
@@ -680,6 +867,14 @@
 
 /* ENABLE macro defaults */
 
+#if WTF_PLATFORM_QT
+/* We must not customize the global operator new and delete for the Qt port. */
+#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
+#if !WTF_OS_UNIX || WTF_OS_SYMBIAN
+#define USE_SYSTEM_MALLOC 1
+#endif
+#endif
+
 /* fastMalloc match validation allows for runtime verification that
    new is matched by delete, fastMalloc is matched by fastFree, etc. */
 #if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION)
@@ -710,6 +905,10 @@
 #define ENABLE_DRAG_SUPPORT 1
 #endif
 
+#if !defined(ENABLE_DATA_TRANSFER_ITEMS)
+#define ENABLE_DATA_TRANSFER_ITEMS 0
+#endif
+
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 0
 #endif
@@ -718,14 +917,22 @@
 #define ENABLE_INSPECTOR 1
 #endif
 
-#if !defined(ENABLE_MAC_JAVA_BRIDGE)
-#define ENABLE_MAC_JAVA_BRIDGE 0
+#if !defined(ENABLE_JAVA_BRIDGE)
+#define ENABLE_JAVA_BRIDGE 0
 #endif
 
 #if !defined(ENABLE_NETSCAPE_PLUGIN_API)
 #define ENABLE_NETSCAPE_PLUGIN_API 1
 #endif
 
+#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE)
+#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0
+#endif
+
+#if !defined(ENABLE_PURGEABLE_MEMORY)
+#define ENABLE_PURGEABLE_MEMORY 0
+#endif
+
 #if !defined(WTF_USE_PLUGIN_HOST_PROCESS)
 #define WTF_USE_PLUGIN_HOST_PROCESS 0
 #endif
@@ -738,6 +945,11 @@
 #define ENABLE_OPCODE_STATS 0
 #endif
 
+#if !defined(ENABLE_GLOBAL_FASTMALLOC_NEW)
+#define ENABLE_GLOBAL_FASTMALLOC_NEW 1
+#endif
+
+#define ENABLE_DEBUG_WITH_BREAKPOINT 0
 #define ENABLE_SAMPLING_COUNTERS 0
 #define ENABLE_SAMPLING_FLAGS 0
 #define ENABLE_OPCODE_SAMPLING 0
@@ -753,10 +965,18 @@
 #define ENABLE_GEOLOCATION 0
 #endif
 
+#if !defined(ENABLE_GESTURE_RECOGNIZER)
+#define ENABLE_GESTURE_RECOGNIZER 0
+#endif
+
 #if !defined(ENABLE_NOTIFICATIONS)
 #define ENABLE_NOTIFICATIONS 0
 #endif
 
+#if WTF_PLATFORM_IOS
+#define ENABLE_TEXT_CARET 0
+#endif
+
 #if !defined(ENABLE_TEXT_CARET)
 #define ENABLE_TEXT_CARET 1
 #endif
@@ -765,80 +985,88 @@
 #define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0
 #endif
 
-#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
-#if (WTF_CPU_X86_64 && (WTF_PLATFORM_UNIX || WTF_PLATFORM_WIN_OS)) || WTF_CPU_IA64 || WTF_CPU_ALPHA
+#if !defined(ENABLE_FULLSCREEN_API)
+#define ENABLE_FULLSCREEN_API 0
+#endif
+
+#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64)
+#if (WTF_CPU_X86_64 && (WTF_OS_UNIX || WTF_OS_WINDOWS)) \
+    || (WTF_CPU_IA64 && !WTF_CPU_IA64_32) \
+    || WTF_CPU_ALPHA \
+    || WTF_CPU_SPARC64 \
+    || WTF_CPU_S390X \
+    || WTF_CPU_PPC64
 #define WTF_USE_JSVALUE64 1
-#elif WTF_CPU_ARM || WTF_CPU_PPC64
-#define WTF_USE_JSVALUE32 1
-#elif WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW
-/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
-on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
-#define WTF_USE_JSVALUE32 1
 #else
 #define WTF_USE_JSVALUE32_64 1
 #endif
-#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */
+#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */
 
 #if !defined(ENABLE_REPAINT_THROTTLING)
 #define ENABLE_REPAINT_THROTTLING 0
 #endif
 
-#if !defined(ENABLE_JIT)
-
-/* The JIT is tested & working on x86_64 Mac */
-#if WTF_CPU_X86_64 && WTF_PLATFORM_MAC
-    #define ENABLE_JIT 1
-/* The JIT is tested & working on x86 Mac */
-#elif WTF_CPU_X86 && WTF_PLATFORM_MAC
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
-    #define ENABLE_JIT 1
-/* The JIT is tested & working on x86 OS/2 */
-#elif WTF_CPU_X86 && WTF_PLATFORM_OS2
-    #define ENABLE_JIT 1
-/* The JIT is tested & working on x86 Windows */
-#elif WTF_CPU_X86 && WTF_PLATFORM_WIN
-    #define ENABLE_JIT 1
-#elif WTF_CPU_SPARC
-    #define ENABLE_JIT 1
+/* Disable the JIT on versions of GCC prior to 4.1 */
+#if !defined(ENABLE_JIT) && WTF_COMPILER_GCC && !GCC_VERSION_AT_LEAST(4, 1, 0)
+#define ENABLE_JIT 0
 #endif
 
-#if WTF_PLATFORM_QT
-#if WTF_CPU_X86_64 && WTF_PLATFORM_DARWIN
-    #define ENABLE_JIT 1
-#elif WTF_CPU_X86 && WTF_PLATFORM_DARWIN
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
-#elif WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100
-    #define ENABLE_JIT 1
-    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
-#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX
-    #define ENABLE_JIT 1
+/* JIT is not implemented for 64 bit on MSVC */
+#if !defined(ENABLE_JIT) && WTF_COMPILER_MSVC && WTF_CPU_X86_64
+#define ENABLE_JIT 0
 #endif
-#endif /* PLATFORM(QT) */
 
-#endif /* !defined(ENABLE_JIT) */
+/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */
+#if !defined(ENABLE_JIT) \
+    && (WTF_CPU_X86 || WTF_CPU_X86_64 || WTF_CPU_ARM || WTF_CPU_MIPS) \
+    && (WTF_OS_DARWIN || !WTF_COMPILER_GCC || GCC_VERSION_AT_LEAST(4, 1, 0)) \
+    && !WTF_OS_WINCE
+#define ENABLE_JIT 1
+#endif
 
+/* Currently only implemented for JSVALUE64, only tested on WTF_PLATFORM_MAC */
+#if ENABLE_JIT && WTF_USE_JSVALUE64 && WTF_PLATFORM_MAC
+#define ENABLE_DFG_JIT 1
+/* Enabled with restrictions to circumvent known performance regressions. */
+#define ENABLE_DFG_JIT_RESTRICTIONS 1
+#endif
+
+/* Ensure that either the JIT or the interpreter has been enabled. */
+#if !defined(ENABLE_INTERPRETER) && !ENABLE_JIT
+#define ENABLE_INTERPRETER 1
+#endif
+#if !(ENABLE_JIT || ENABLE_INTERPRETER)
+#error You have to have at least one execution model enabled to build JSC
+#endif
+
+#if WTF_CPU_SH4 && WTF_PLATFORM_QT
+#define ENABLE_JIT 1
+#define ENABLE_YARR 1
+#define ENABLE_YARR_JIT 1
+#define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
+#define ENABLE_ASSEMBLER 1
+#endif
+
+/* Configure the JIT */
 #if ENABLE_JIT
-#ifndef ENABLE_JIT_OPTIMIZE_CALL
-#define ENABLE_JIT_OPTIMIZE_CALL 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
-#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
-#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
-#endif
-#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
-#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
-#endif
+    #if WTF_CPU_ARM
+    #if !defined(ENABLE_JIT_USE_SOFT_MODULO) && WTF_ARM_ARCH_AT_LEAST(5)
+    #define ENABLE_JIT_USE_SOFT_MODULO 1
+    #endif
+    #endif
+
+    #ifndef ENABLE_JIT_OPTIMIZE_CALL
+    #define ENABLE_JIT_OPTIMIZE_CALL 1
+    #endif
+    #ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
+    #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
+    #endif
+    #ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
+    #define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
+    #endif
+    #ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
+    #define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
+    #endif
 #endif
 
 #if WTF_CPU_X86 && WTF_COMPILER_MSVC
@@ -849,80 +1077,89 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
 #define JSC_HOST_CALL
 #endif
 
-#if WTF_COMPILER_GCC && !ENABLE_JIT
+/* Configure the interpreter */
+#if WTF_COMPILER_GCC || (RVCT_VERSION_AT_LEAST(4, 0, 0, 0) && defined(__GNUC__))
 #define HAVE_COMPUTED_GOTO 1
 #endif
-
-#if ENABLE_JIT && defined(COVERAGE)
-    #define WTF_USE_INTERPRETER 0
-#else
-    #define WTF_USE_INTERPRETER 1
+#if HAVE_COMPUTED_GOTO && ENABLE_INTERPRETER
+#define ENABLE_COMPUTED_GOTO_INTERPRETER 1
 #endif
 
-/* Yet Another Regex Runtime. */
-#if !defined(ENABLE_YARR_JIT)
+/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc.  Results dumped at exit */
+#define ENABLE_REGEXP_TRACING 0
 
-/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */
-#if (WTF_CPU_X86 \
- || WTF_CPU_X86_64 \
- || WTF_CPU_SPARC \
- || WTF_CPU_ARM_TRADITIONAL \
- || WTF_CPU_ARM_THUMB2 \
- || WTF_CPU_X86)
-#define ENABLE_YARR_JIT 1
-#else
+/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */
+#if WTF_PLATFORM_CHROMIUM
 #define ENABLE_YARR_JIT 0
+
+#elif ENABLE_JIT && !defined(ENABLE_YARR_JIT)
+#define ENABLE_YARR_JIT 1
+
+/* Setting this flag compares JIT results with interpreter results. */
+#define ENABLE_YARR_JIT_DEBUG 0
 #endif
 
-#endif /* !defined(ENABLE_YARR_JIT) */
-
-#if (ENABLE_JIT || ENABLE_YARR_JIT)
+#if ENABLE_JIT || ENABLE_YARR_JIT
 #define ENABLE_ASSEMBLER 1
 #endif
 /* Setting this flag prevents the assembler from using RWX memory; this may improve
    security but currectly comes at a significant performance cost. */
-#if WTF_PLATFORM_IPHONE
+#if WTF_PLATFORM_IOS
 #define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1
-#else
-#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0
 #endif
 
-#if !defined(ENABLE_PAN_SCROLLING) && WTF_PLATFORM_WIN_OS
+/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in.
+   On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */
+#if ENABLE_ASSEMBLER
+#if WTF_CPU_X86_64
+#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1
+#else
+#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1
+#endif
+#endif
+
+#if !defined(ENABLE_PAN_SCROLLING) && WTF_OS_WINDOWS
 #define ENABLE_PAN_SCROLLING 1
 #endif
 
-/* Use the QXmlStreamReader implementation for XMLTokenizer */
+#if !defined(ENABLE_SMOOTH_SCROLLING)
+#define ENABLE_SMOOTH_SCROLLING 0
+#endif
+
+#if !defined(ENABLE_WEB_ARCHIVE)
+#define ENABLE_WEB_ARCHIVE 0
+#endif
+
+/* Use the QXmlStreamReader implementation for XMLDocumentParser */
 /* Use the QXmlQuery implementation for XSLTProcessor */
 #if WTF_PLATFORM_QT
 #define WTF_USE_QXMLSTREAM 1
 #define WTF_USE_QXMLQUERY 1
 #endif
 
-#if !WTF_PLATFORM_QT
-#define WTF_USE_FONT_FAST_PATH 1
+#if WTF_PLATFORM_MAC
+/* Complex text framework */
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#define WTF_USE_ATSUI 0
+#define WTF_USE_CORE_TEXT 1
+#else
+#define WTF_USE_ATSUI 1
+#define WTF_USE_CORE_TEXT 0
+#endif
 #endif
 
 /* Accelerated compositing */
-#if WTF_PLATFORM_MAC
-#if !defined(BUILDING_ON_TIGER)
-#define WTF_USE_ACCELERATED_COMPOSITING 1
-#endif
-#endif
-
-#if WTF_PLATFORM_IPHONE
+#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER)) || WTF_PLATFORM_IOS || WTF_PLATFORM_QT || (WTF_PLATFORM_WIN && !WTF_OS_WINCE &&!defined(WIN_CAIRO))
 #define WTF_USE_ACCELERATED_COMPOSITING 1
 #endif
 
-/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with
-   with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and
-   off in one place. */
-//#if WTF_PLATFORM_WIN
-//#include "QuartzCorePresent.h"
-//#if QUARTZCORE_PRESENT
-//#define WTF_USE_ACCELERATED_COMPOSITING 1
-//#define ENABLE_3D_RENDERING 1
-//#endif
-//#endif
+#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || WTF_PLATFORM_IOS
+#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1
+#endif
+
+#if WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#define WTF_USE_AVFOUNDATION 1
+#endif
 
 #if WTF_COMPILER_GCC
 #define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result))
@@ -930,7 +1167,7 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
 #define WARN_UNUSED_RETURN
 #endif
 
-#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_PLATFORM_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
+#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
 
@@ -939,4 +1176,46 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
 
 #define ENABLE_JSC_ZOMBIES 0
 
+/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_QT
+#define WTF_USE_PLATFORM_STRATEGIES 1
+#endif
+
+#if WTF_PLATFORM_WIN
+#define WTF_USE_CROSS_PLATFORM_CONTEXT_MENUS 1
+#endif
+
+/* Geolocation request policy. pre-emptive policy is to acquire user permission before acquiring location.
+   Client based implementations will have option to choose between pre-emptive and nonpre-emptive permission policy.
+   pre-emptive permission policy is enabled by default for all client-based implementations. */
+#if ENABLE_CLIENT_BASED_GEOLOCATION
+#define WTF_USE_PREEMPT_GEOLOCATION_PERMISSION 1
+#endif
+
+#if WTF_CPU_ARM_THUMB2
+#define ENABLE_BRANCH_COMPACTION 1
+#endif
+
+#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
+#define ENABLE_THREADING_OPENMP 1
+#endif
+
+#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE_SINGLE_THREADED && (ENABLE_THREADING_GENERIC || ENABLE_THREADING_LIBDISPATCH || ENABLE_THREADING_OPENMP)
+#define ENABLE_PARALLEL_JOBS 1
+#endif
+
+#if ENABLE_GLIB_SUPPORT
+#include "GTypedefs.h"
+#endif
+
+/* FIXME: This define won't be needed once #27551 is fully landed. However, 
+   since most ports try to support sub-project independence, adding new headers
+   to WTF causes many ports to break, and so this way we can address the build
+   breakages one port at a time. */
+#define WTF_USE_EXPORT_MACROS 0
+
+#if WTF_PLATFORM_QT || WTF_PLATFORM_GTK
+#define WTF_USE_UNIX_DOMAIN_SOCKETS 1
+#endif
+
 #endif /* WTF_Platform_h */
diff --git a/js/src/jit-test/tests/basic/bug632964-regexp.js b/js/src/jit-test/tests/basic/bug632964-regexp.js
index 7151d3713647..75612dbc735d 100644
--- a/js/src/jit-test/tests/basic/bug632964-regexp.js
+++ b/js/src/jit-test/tests/basic/bug632964-regexp.js
@@ -1,5 +1,3 @@
-// |jit-test| error: InternalError: regular expression too complex
-
 var sText = "s";
 
 for (var i = 0; i < 250000; ++i)
@@ -12,6 +10,5 @@ var match = sText.match(/s(\s|.)*?e/gi);
 //var match = sText.match(/s([\s\S]*?)e/gi);
 //var match = sText.match(/s(?:[\s\S]*?)e/gi);
 var end = new Date();
-print(end - start);
 
 assertEq(match.length, 1);
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index ecc336cdc4c3..c88fae9fdaf0 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -48,6 +48,7 @@
 #include "jstracer.h"
 #include "jswrapper.h"
 #include "assembler/wtf/Platform.h"
+#include "yarr/BumpPointerAllocator.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
@@ -73,6 +74,9 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     active(false),
 #ifdef JS_METHODJIT
     jaegerCompartment(NULL),
+#endif
+#if ENABLE_YARR_JIT
+    regExpAllocator(NULL),
 #endif
     propertyTree(thisForCtor()),
     emptyArgumentsShape(NULL),
@@ -84,9 +88,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     initialRegExpShape(NULL),
     initialStringShape(NULL),
     debugMode(rt->debugMode),
-#if ENABLE_YARR_JIT
-    regExpAllocator(NULL),
-#endif
     mathCache(NULL)
 {
     JS_INIT_CLIST(&scripts);
@@ -135,11 +136,9 @@ JSCompartment::init()
         return false;
 #endif
 
-#if ENABLE_YARR_JIT
-    regExpAllocator = rt->new_();
+    regExpAllocator = rt->new_();
     if (!regExpAllocator)
         return false;
-#endif
 
     if (!backEdgeTable.init())
         return false;
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 5b3f16643050..8827a275f796 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -54,11 +54,8 @@
 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
 #endif
 
-namespace JSC {
-
-class ExecutableAllocator;
-
-}
+namespace JSC { class ExecutableAllocator; }
+namespace WTF { class BumpPointerAllocator; }
 
 namespace js {
 
@@ -420,6 +417,7 @@ struct JS_FRIEND_API(JSCompartment) {
      */
     size_t getMjitCodeSize() const;
 #endif
+    WTF::BumpPointerAllocator    *regExpAllocator;
 
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
@@ -466,8 +464,6 @@ struct JS_FRIEND_API(JSCompartment) {
     bool                         debugMode;  // true iff debug mode on
     JSCList                      scripts;    // scripts in this compartment
 
-    JSC::ExecutableAllocator     *regExpAllocator;
-
     js::NativeIterCache          nativeIterCache;
 
     typedef js::Maybe LazyToSourceCache;
diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp
index 0df8ae536a47..3d9f09f56559 100644
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -59,8 +59,6 @@
 #include "jsobjinlines.h"
 #include "jsregexpinlines.h"
 
-#include "yarr/RegexParser.h"
-
 #ifdef JS_TRACER
 #include "jstracer.h"
 using namespace nanojit;
@@ -193,11 +191,11 @@ js_ObjectIsRegExp(JSObject *obj)
  */
 
 void
-RegExp::handleYarrError(JSContext *cx, int error)
+RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error)
 {
     switch (error) {
       case JSC::Yarr::NoError:
-        JS_NOT_REACHED("Precondition violation: an error must have occurred.");
+        JS_NOT_REACHED("Called reportYarrError with value for no error");
         return;
 #define COMPILE_EMSG(__code, __msg) \
       case JSC::Yarr::__code: \
@@ -210,49 +208,16 @@ RegExp::handleYarrError(JSContext *cx, int error)
       COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN);
       COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */
       COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE);
+      COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE);
       COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(CharacterClassRangeSingleChar, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
       COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
-      COMPILE_EMSG(HitRecursionLimit, JSMSG_REGEXP_TOO_COMPLEX);
+      COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
 #undef COMPILE_EMSG
       default:
-        JS_NOT_REACHED("Precondition violation: unknown Yarr error code.");
+        JS_NOT_REACHED("Unknown Yarr error code");
     }
 }
 
-void
-RegExp::handlePCREError(JSContext *cx, int error)
-{
-#define REPORT(msg_) \
-    JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \
-    return
-    switch (error) {
-      case -2: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 0: JS_NOT_REACHED("Precondition violation: an error must have occurred.");
-      case 1: REPORT(JSMSG_TRAILING_SLASH);
-      case 2: REPORT(JSMSG_TRAILING_SLASH);
-      case 3: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 4: REPORT(JSMSG_BAD_QUANTIFIER);
-      case 5: REPORT(JSMSG_BAD_QUANTIFIER);
-      case 6: REPORT(JSMSG_BAD_CLASS_RANGE);
-      case 7: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 8: REPORT(JSMSG_BAD_CLASS_RANGE);
-      case 9: REPORT(JSMSG_BAD_QUANTIFIER);
-      case 10: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
-      case 11: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 12: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
-      case 13: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 14: REPORT(JSMSG_MISSING_PAREN);
-      case 15: REPORT(JSMSG_BAD_BACKREF);
-      case 16: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      case 17: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
-      default:
-        JS_NOT_REACHED("Precondition violation: unknown PCRE error code.");
-    }
-#undef REPORT
-}
-
 bool
 RegExp::parseFlags(JSContext *cx, JSString *flagStr, uintN *flagsOut)
 {
@@ -929,3 +894,4 @@ js_InitRegExpClass(JSContext *cx, JSObject *global)
 
     return proto;
 }
+
diff --git a/js/src/jsregexpinlines.h b/js/src/jsregexpinlines.h
index 70db45413e1d..305cf1590462 100644
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -48,12 +48,13 @@
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
+#include "methodjit/MethodJIT.h"
 #include "assembler/wtf/Platform.h"
+#include "yarr/BumpPointerAllocator.h"
 
+#include "yarr/Yarr.h"
 #if ENABLE_YARR_JIT
-#include "yarr/yarr/RegexJIT.h"
-#else
-#include "yarr/pcre/pcre.h"
+#include "yarr/YarrJIT.h"
 #endif
 
 namespace js {
@@ -95,10 +96,10 @@ regexp_statics_construct(JSContext *cx, GlobalObject *parent)
 class RegExp
 {
 #if ENABLE_YARR_JIT
-    JSC::Yarr::RegexCodeBlock   compiled;
-#else
-    JSRegExp                    *compiled;
+    /* native code is valid only if codeBlock.isFallBack() == false */
+    JSC::Yarr::YarrCodeBlock    codeBlock;
 #endif
+    JSC::Yarr::BytecodePattern  *byteCode;
     JSLinearString              *source;
     size_t                      refCount;
     unsigned                    parenCount; /* Must be |unsigned| to interface with YARR. */
@@ -111,7 +112,11 @@ class RegExp
 #endif
 
     RegExp(JSLinearString *source, uint32 flags, JSCompartment *compartment)
-      : compiled(), source(source), refCount(1), parenCount(0), flags(flags)
+      :
+#if ENABLE_YARR_JIT
+        codeBlock(),
+#endif
+        byteCode(NULL), source(source), refCount(1), parenCount(0), flags(flags)
 #ifdef DEBUG
         , compartment(compartment)
 #endif
@@ -120,17 +125,18 @@ class RegExp
     JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
 
     ~RegExp() {
-#if !ENABLE_YARR_JIT
-        if (compiled)
-            jsRegExpFree(compiled);
+#if ENABLE_YARR_JIT
+        codeBlock.release();
 #endif
+        // YYY
+        if (byteCode)
+            delete byteCode;
     }
 
     bool compileHelper(JSContext *cx, JSLinearString &pattern);
     bool compile(JSContext *cx);
     static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
-    void handlePCREError(JSContext *cx, int error);
-    void handleYarrError(JSContext *cx, int error);
+    void reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error);
     static inline bool initArena(JSContext *cx);
     static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
     static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
@@ -318,9 +324,6 @@ inline bool
 RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
                         size_t *lastIndex, bool test, Value *rval)
 {
-#if !ENABLE_YARR_JIT
-    JS_ASSERT(compiled);
-#endif
     const size_t pairCount = parenCount + 1;
     const size_t bufCount = pairCount * 3; /* Should be x2, but PCRE has... needs. */
     const size_t matchItemCount = pairCount * 2;
@@ -360,27 +363,20 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
         inputOffset = *lastIndex;
     }
 
+    int result;
 #if ENABLE_YARR_JIT
-    int result = JSC::Yarr::executeRegex(cx, compiled, chars, *lastIndex - inputOffset, len, buf,
-                                         bufCount);
+    if (!codeBlock.isFallBack())
+        result = JSC::Yarr::execute(codeBlock, chars, *lastIndex - inputOffset, len, buf);
+    else
+        result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
 #else
-    int result = jsRegExpExecute(cx, compiled, chars, len, *lastIndex - inputOffset, buf, 
-                                 bufCount);
+    result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
 #endif
     if (result == -1) {
         *rval = NullValue();
         return true;
     }
 
-    if (result < 0) {
-#if ENABLE_YARR_JIT
-        handleYarrError(cx, result);
-#else
-        handlePCREError(cx, result);
-#endif
-        return false;
-    }
-
     /* 
      * Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so
      * just do another pass.
@@ -460,53 +456,44 @@ RegExp::createObjectNoStatics(JSContext *cx, const jschar *chars, size_t length,
     return obj;
 }
 
-#ifdef ANDROID
-static bool
-YarrJITIsBroken(JSContext *cx)
+/*
+ * This function should be deleted once we can. See bug 604774.
+ */
+static inline bool
+EnableYarrJIT(JSContext *cx)
 {
-#if defined(JS_TRACER) && defined(JS_METHODJIT)
-    /* FIXME/bug 604774: dead code walking.
-     *
-     * If both JITs are disabled, assume they were disabled because
-     * we're running on a blacklisted device.
-     */
-    return !cx->traceJitEnabled && !cx->methodJitEnabled;
+#if defined ANDROID && defined(JS_TRACER) && defined(JS_METHODJIT)
+    return cx->traceJitEnabled || cx->methodJitEnabled;
 #else
-    return false;
+    return true;
 #endif
 }
-#endif  /* ANDROID */
 
 inline bool
 RegExp::compileHelper(JSContext *cx, JSLinearString &pattern)
 {
-#if ENABLE_YARR_JIT
-    bool fellBack = false;
-    int error = 0;
-    jitCompileRegex(*cx->compartment->regExpAllocator, compiled, pattern, parenCount, error, fellBack, ignoreCase(), multiline()
-#ifdef ANDROID
-                    /* Temporary gross hack to work around buggy kernels. */
-                    , YarrJITIsBroken(cx)
-#endif
-);
-    if (!error)
-        return true;
-    if (fellBack)
-        handlePCREError(cx, error);
-    else
-        handleYarrError(cx, error);
-    return false;
-#else
-    int error = 0;
-    compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
-                               ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
-                               multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
-                               &parenCount, &error);
-    if (!error)
-        return true;
-    handlePCREError(cx, error);
-    return false;
+    JSC::Yarr::ErrorCode yarrError;
+    JSC::Yarr::YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError);
+    if (yarrError) {
+        reportYarrError(cx, yarrError);
+        return false;
+    }
+    parenCount = yarrPattern.m_numSubpatterns;
+
+#if ENABLE_YARR_JIT && defined(JS_METHODJIT)
+    if (EnableYarrJIT(cx) && !yarrPattern.m_containsBackreferences) {
+        JSC::Yarr::JSGlobalData globalData(cx->compartment->jaegerCompartment->execAlloc());
+        JSC::Yarr::jitCompile(yarrPattern, &globalData, codeBlock);
+        if (!codeBlock.isFallBack())
+            return true;
+    } else {
+        codeBlock.setFallBack(true);
+    }
 #endif
+
+    byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
+
+    return true;
 }
 
 inline bool
diff --git a/js/src/jsvector.h b/js/src/jsvector.h
index 3d413c1f64b6..4eaf58b6a4e7 100644
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -208,12 +208,30 @@ class Vector : private AllocPolicy
 
     /* compute constants */
 
+    /*
+     * Consider element size to be 1 for buffer sizing if there are
+     * 0 inline elements. This allows us to compile when the definition
+     * of the element type is not visible here.
+     *
+     * Explicit specialization is only allowed at namespace scope, so
+     * in order to keep everything here, we use a dummy template
+     * parameter with partial specialization.
+     */
+    template 
+    struct ElemSize {
+        static const size_t result = sizeof(T);
+    };
+    template 
+    struct ElemSize<0, Dummy> {
+        static const size_t result = 1;
+    };
+
     static const size_t sInlineCapacity =
-        tl::Min::result;
+        tl::Min::result>::result;
 
     /* Calculate inline buffer size; avoid 0-sized array. */
     static const size_t sInlineBytes =
-        tl::Max<1, sInlineCapacity * sizeof(T)>::result;
+        tl::Max<1, sInlineCapacity * ElemSize::result>::result;
 
     /* member data */
 
diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp
index 603d76a59c88..b03c6afa0990 100644
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -503,7 +503,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             analyze::Bytecode *opinfo = analysis->maybeCode(i);
             if (opinfo && opinfo->safePoint) {
                 Label L = jumpMap[i];
-                JS_ASSERT(L.isValid());
+                JS_ASSERT(L.isSet());
                 jitNmap[ix].bcOff = i;
                 jitNmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L));
                 ix++;
@@ -625,7 +625,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
     cursor += sizeof(ic::EqualityICInfo) * jit->nEqualityICs;
     for (size_t i = 0; i < jit->nEqualityICs; i++) {
         uint32 offs = uint32(equalityICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isValid());
+        JS_ASSERT(jumpMap[offs].isSet());
         jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]);
         jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry);
         jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall);
@@ -650,7 +650,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             continue;
 
         uint32 offs = uint32(traceICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isValid());
+        JS_ASSERT(jumpMap[offs].isSet());
         jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint);
         jitTraceICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]);
         jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
@@ -800,7 +800,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
 
     for (size_t i = 0; i < jumpTableOffsets.length(); i++) {
         uint32 offset = jumpTableOffsets[i];
-        JS_ASSERT(jumpMap[offset].isValid());
+        JS_ASSERT(jumpMap[offset].isSet());
         jumpVec[i] = (void *)(result + masm.distanceOf(jumpMap[offset]));
     }
 
@@ -2089,7 +2089,7 @@ JSC::MacroAssembler::Label
 mjit::Compiler::labelOf(jsbytecode *pc)
 {
     uint32 offs = uint32(pc - script->code);
-    JS_ASSERT(jumpMap[offs].isValid());
+    JS_ASSERT(jumpMap[offs].isSet());
     return jumpMap[offs];
 }
 
diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp
index bd738b92ba2b..b55b0dba48a5 100644
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -846,12 +846,7 @@ static inline void Destroy(T &t)
 
 mjit::JITScript::~JITScript()
 {
-#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) 
-    void *addr = code.m_code.executableAddress();
-    memset(addr, 0xcc, code.m_size);
-#endif
-
-    code.m_executablePool->release();
+    code.release();
 
 #if defined JS_POLYIC
     ic::GetElementIC *getElems_ = getElems();
diff --git a/js/src/methodjit/TrampolineCompiler.cpp b/js/src/methodjit/TrampolineCompiler.cpp
index a6ac9d709f0e..77bb148ba311 100644
--- a/js/src/methodjit/TrampolineCompiler.cpp
+++ b/js/src/methodjit/TrampolineCompiler.cpp
@@ -93,7 +93,7 @@ TrampolineCompiler::compileTrampoline(Trampolines::TrampolinePtr *where,
 
     Label entry = masm.label();
     CHECK_RESULT(generator(masm));
-    JS_ASSERT(entry.isValid());
+    JS_ASSERT(entry.isSet());
 
     bool ok;
     JSC::LinkBuffer buffer(&masm, execAlloc, poolp, &ok);
diff --git a/js/src/yarr/wtf/ASCIICType.h b/js/src/yarr/ASCIICType.h
similarity index 81%
rename from js/src/yarr/wtf/ASCIICType.h
rename to js/src/yarr/ASCIICType.h
index cf53d9ac0c87..a3ae9f4455e2 100644
--- a/js/src/yarr/wtf/ASCIICType.h
+++ b/js/src/yarr/ASCIICType.h
@@ -1,4 +1,7 @@
-/*
+/* -*- 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) 2007, 2008, 2009 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -24,12 +27,13 @@
  * 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.
- */
+ *
+ * ***** END LICENSE BLOCK ***** */
 
 #ifndef WTF_ASCIICType_h
 #define WTF_ASCIICType_h
 
-#include "yarr/jswtfbridge.h"
+#include "assembler/wtf/Assertions.h"
 
 // The behavior of many of the functions in the  header is dependent
 // on the current locale. But in the WebKit project, all uses of those functions
@@ -49,6 +53,7 @@ namespace WTF {
     inline bool isASCII(wchar_t c) { return !(c & ~0x7F); }
 #endif
     inline bool isASCII(int c) { return !(c & ~0x7F); }
+    inline bool isASCII(unsigned c) { return !(c & ~0x7F); }
 
     inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
     inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
@@ -56,6 +61,7 @@ namespace WTF {
     inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
 #endif
     inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
+    inline bool isASCIIAlpha(unsigned c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; }
 
     inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
     inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
@@ -63,6 +69,7 @@ namespace WTF {
     inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
 #endif
     inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
+    inline bool isASCIIAlphanumeric(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); }
 
     inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); }
     inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); }
@@ -70,6 +77,7 @@ namespace WTF {
     inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); }
 #endif
     inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); }
+    inline bool isASCIIDigit(unsigned c) { return (c >= '0') & (c <= '9'); }
 
     inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
     inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
@@ -77,6 +85,7 @@ namespace WTF {
     inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
 #endif
     inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
+    inline bool isASCIIHexDigit(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); }
 
     inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); }
     inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); }
@@ -84,6 +93,7 @@ namespace WTF {
     inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); }
 #endif
     inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); }
+    inline bool isASCIIOctalDigit(unsigned c) { return (c >= '0') & (c <= '7'); }
 
     inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; }
     inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; }
@@ -91,6 +101,7 @@ namespace WTF {
     inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; }
 #endif
     inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; }
+    inline bool isASCIILower(unsigned c) { return c >= 'a' && c <= 'z'; }
 
     inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; }
     inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; }
@@ -98,6 +109,7 @@ namespace WTF {
     inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; }
 #endif
     inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; }
+    inline bool isASCIIUpper(unsigned c) { return c >= 'A' && c <= 'Z'; }
 
     /*
         Statistics from a run of Apple's page load test for callers of isASCIISpace:
@@ -118,6 +130,7 @@ namespace WTF {
     inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
 #endif
     inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
+    inline bool isASCIISpace(unsigned c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); }
 
     inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
     inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
@@ -125,20 +138,24 @@ namespace WTF {
     inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
 #endif
     inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
+    inline unsigned toASCIILower(unsigned c) { return c | ((c >= 'A' && c <= 'Z') << 5); }
 
+    // FIXME: Why do these need static_cast?
     inline char toASCIIUpper(char c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
     inline unsigned short toASCIIUpper(unsigned short c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
 #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
     inline wchar_t toASCIIUpper(wchar_t c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
 #endif
     inline int toASCIIUpper(int c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
+    inline unsigned toASCIIUpper(unsigned c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); }
 
-    inline int toASCIIHexValue(char c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
-    inline int toASCIIHexValue(unsigned short c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
 #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)
-    inline int toASCIIHexValue(wchar_t c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
 #endif
-    inline int toASCIIHexValue(int c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
+    inline int toASCIIHexValue(unsigned c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; }
 
     inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; }
     inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; }
@@ -146,7 +163,7 @@ namespace WTF {
     inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; }
 #endif
     inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; }
-
+    inline bool isASCIIPrintable(unsigned c) { return c >= ' ' && c <= '~'; }
 }
 
 using WTF::isASCII;
diff --git a/js/src/yarr/BumpPointerAllocator.h b/js/src/yarr/BumpPointerAllocator.h
new file mode 100644
index 000000000000..8ef5a780f9d8
--- /dev/null
+++ b/js/src/yarr/BumpPointerAllocator.h
@@ -0,0 +1,254 @@
+/* -*- 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) 2010 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef BumpPointerAllocator_h
+#define BumpPointerAllocator_h
+
+#include "PageAllocation.h"
+
+namespace WTF {
+
+#define MINIMUM_BUMP_POOL_SIZE 0x1000
+
+class BumpPointerPool {
+public:
+    // ensureCapacity will check whether the current pool has capacity to
+    // allocate 'size' bytes of memory  If it does not, it will attempt to
+    // allocate a new pool (which will be added to this one in a chain).
+    //
+    // If allocation fails (out of memory) this method will return null.
+    // If the return value is non-null, then callers should update any
+    // references they have to this current (possibly full) BumpPointerPool
+    // to instead point to the newly returned BumpPointerPool.
+    BumpPointerPool* ensureCapacity(size_t size)
+    {
+        void* allocationEnd = static_cast(m_current) + size;
+        ASSERT(allocationEnd > m_current); // check for overflow
+        if (allocationEnd <= static_cast(this))
+            return this;
+        return ensureCapacityCrossPool(this, size);
+    }
+
+    // alloc should only be called after calling ensureCapacity; as such
+    // alloc will never fail.
+    void* alloc(size_t size)
+    {
+        void* current = m_current;
+        void* allocationEnd = static_cast(current) + size;
+        ASSERT(allocationEnd > current); // check for overflow
+        ASSERT(allocationEnd <= static_cast(this));
+        m_current = allocationEnd;
+        return current;
+    }
+
+    // The dealloc method releases memory allocated using alloc.  Memory
+    // must be released in a LIFO fashion, e.g. if the client calls alloc
+    // four times, returning pointer A, B, C, D, then the only valid order
+    // in which these may be deallocaed is D, C, B, A.
+    //
+    // The client may optionally skip some deallocations.  In the example
+    // above, it would be valid to only explicitly dealloc C, A (D being
+    // dealloced along with C, B along with A).
+    //
+    // If pointer was not allocated from this pool (or pools) then dealloc
+    // will CRASH().  Callers should update any references they have to
+    // this current BumpPointerPool to instead point to the returned
+    // BumpPointerPool.
+    BumpPointerPool* dealloc(void* position)
+    {
+        if ((position >= m_start) && (position <= static_cast(this))) {
+            ASSERT(position <= m_current);
+            m_current = position;
+            return this;
+        }
+        return deallocCrossPool(this, position);
+    }
+
+private:
+    // Placement operator new, returns the last 'size' bytes of allocation for use as this.
+    void* operator new(size_t size, const PageAllocation& allocation)
+    {
+        ASSERT(size < allocation.size());
+        return reinterpret_cast(reinterpret_cast(allocation.base()) + allocation.size()) - size;
+    }
+
+    BumpPointerPool(const PageAllocation& allocation)
+        : m_current(allocation.base())
+        , m_start(allocation.base())
+        , m_next(0)
+        , m_previous(0)
+        , m_allocation(allocation)
+    {
+    }
+
+    static BumpPointerPool* create(size_t minimumCapacity = 0)
+    {
+        // Add size of BumpPointerPool object, check for overflow.
+        minimumCapacity += sizeof(BumpPointerPool);
+        if (minimumCapacity < sizeof(BumpPointerPool))
+            return 0;
+
+        size_t poolSize = MINIMUM_BUMP_POOL_SIZE;
+        while (poolSize < minimumCapacity) {
+            poolSize <<= 1;
+            // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2!
+            ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1)));
+            if (!poolSize)
+                return 0;
+        }
+
+        PageAllocation allocation = PageAllocation::allocate(poolSize);
+        if (!!allocation)
+            return new(allocation) BumpPointerPool(allocation);
+        return 0;
+    }
+
+    void shrink()
+    {
+        ASSERT(!m_previous);
+        m_current = m_start;
+        while (m_next) {
+            BumpPointerPool* nextNext = m_next->m_next;
+            m_next->destroy();
+            m_next = nextNext;
+        }
+    }
+
+    void destroy()
+    {
+        m_allocation.deallocate();
+    }
+
+    static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size)
+    {
+        // The pool passed should not have capacity, so we'll start with the next one.
+        ASSERT(previousPool);
+        ASSERT((static_cast(previousPool->m_current) + size) > previousPool->m_current); // check for overflow
+        ASSERT((static_cast(previousPool->m_current) + size) > static_cast(previousPool));
+        BumpPointerPool* pool = previousPool->m_next;
+
+        while (true) {
+            if (!pool) {
+                // We've run to the end; allocate a new pool.
+                pool = BumpPointerPool::create(size);
+                previousPool->m_next = pool;
+                pool->m_previous = previousPool;
+                return pool;
+            }
+
+            // 
+            void* current = pool->m_current;
+            void* allocationEnd = static_cast(current) + size;
+            ASSERT(allocationEnd > current); // check for overflow
+            if (allocationEnd <= static_cast(pool))
+                return pool;
+        }
+    }
+
+    static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position)
+    {
+        // Should only be called if position is not in the current pool.
+        ASSERT((position < pool->m_start) || (position > static_cast(pool)));
+
+        while (true) {
+            // Unwind the current pool to the start, move back in the chain to the previous pool.
+            pool->m_current = pool->m_start;
+            pool = pool->m_previous;
+
+            // position was nowhere in the chain!
+            if (!pool)
+                CRASH();
+
+            if ((position >= pool->m_start) && (position <= static_cast(pool))) {
+                ASSERT(position <= pool->m_current);
+                pool->m_current = position;
+                return pool;
+            }
+        }
+    }
+
+    void* m_current;
+    void* m_start;
+    BumpPointerPool* m_next;
+    BumpPointerPool* m_previous;
+    PageAllocation m_allocation;
+
+    friend class BumpPointerAllocator;
+};
+
+// A BumpPointerAllocator manages a set of BumpPointerPool objects, which
+// can be used for LIFO (stack like) allocation.
+//
+// To begin allocating using this class call startAllocator().  The result
+// of this method will be null if the initial pool allocation fails, or a
+// pointer to a BumpPointerPool object that can be used to perform
+// allocations.  Whilst running no memory will be released until
+// stopAllocator() is called.  At this point all allocations made through
+// this allocator will be reaped, and underlying memory may be freed.
+//
+// (In practice we will still hold on to the initial pool to allow allocation
+// to be quickly restared, but aditional pools will be freed).
+//
+// This allocator is non-renetrant, it is encumbant on the clients to ensure
+// startAllocator() is not called again until stopAllocator() has been called.
+class BumpPointerAllocator {
+public:
+    BumpPointerAllocator()
+        : m_head(0)
+    {
+    }
+
+    ~BumpPointerAllocator()
+    {
+        if (m_head)
+            m_head->destroy();
+    }
+
+    BumpPointerPool* startAllocator()
+    {
+        if (!m_head)
+            m_head = BumpPointerPool::create();
+        return m_head;
+    }
+
+    void stopAllocator()
+    {
+        if (m_head)
+            m_head->shrink();
+    }
+
+private:
+    BumpPointerPool* m_head;
+};
+
+}
+
+using WTF::BumpPointerAllocator;
+
+#endif // BumpPointerAllocator_h
diff --git a/js/src/yarr/Makefile b/js/src/yarr/Makefile
deleted file mode 100644
index c824cdb96b6c..000000000000
--- a/js/src/yarr/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-INCLUDES := -I. -Iyarr -Iwtf -I../assembler/assembler -I../assembler
-
-all: 
-	$(CXX) -g3 -c $(INCLUDES) yarr/*.cpp
-	$(CXX) -g3 $(INCLUDES) TestMain.cpp *.o
diff --git a/js/src/yarr/OSAllocator.h b/js/src/yarr/OSAllocator.h
new file mode 100644
index 000000000000..ecfdc3b042ec
--- /dev/null
+++ b/js/src/yarr/OSAllocator.h
@@ -0,0 +1,103 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef OSAllocator_h
+#define OSAllocator_h
+
+#include 
+#include "wtfbridge.h"
+#include "assembler/wtf/VMTags.h"
+#include "assembler/wtf/Assertions.h"
+
+namespace WTF {
+
+class OSAllocator {
+public:
+    enum Usage {
+        UnknownUsage = -1,
+        FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY,
+        JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY,
+        JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY,
+        JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY
+    };
+
+    // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state,
+    // releaseDecommitted should be called on a region of VM allocated by a single reservation,
+    // the memory must all currently be in a decommitted state.
+    static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
+    static void releaseDecommitted(void*, size_t);
+
+    // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should
+    // never be accessed, since the OS may not have attached physical memory for these regions).
+    // Clients should only call commit on uncommitted regions and decommit on committed regions.
+    static void commit(void*, size_t, bool writable, bool executable);
+    static void decommit(void*, size_t);
+
+    // These methods are symmetric; reserveAndCommit allocates VM in an committed state,
+    // decommitAndRelease should be called on a region of VM allocated by a single reservation,
+    // the memory must all currently be in a committed state.
+    static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
+    static void decommitAndRelease(void* base, size_t size);
+
+    // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than
+    // committing/decommitting the entire region additional parameters allow a subregion to be
+    // specified.
+    static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false);
+    static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize);
+};
+
+inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable)
+{
+    void* base = reserveUncommitted(reserveSize, usage, writable, executable);
+    commit(base, commitSize, writable, executable);
+    return base;
+}
+
+inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize)
+{
+    ASSERT(decommitBase >= releaseBase && (static_cast(decommitBase) + decommitSize) <= (static_cast(releaseBase) + releaseSize));
+#if WTF_OS_WINCE || WTF_OS_SYMBIAN
+    // On most platforms we can actually skip this final decommit; releasing the VM will
+    // implicitly decommit any physical memory in the region. This is not true on WINCE.
+    // On Symbian, this makes implementation simpler and better aligned with the RChunk API
+    decommit(decommitBase, decommitSize);
+#endif
+    releaseDecommitted(releaseBase, releaseSize);
+}
+
+inline void OSAllocator::decommitAndRelease(void* base, size_t size)
+{
+    decommitAndRelease(base, size, base, size);
+}
+
+} // namespace WTF
+
+using WTF::OSAllocator;
+
+#endif // OSAllocator_h
diff --git a/js/src/yarr/OSAllocatorPosix.cpp b/js/src/yarr/OSAllocatorPosix.cpp
new file mode 100644
index 000000000000..57c240b22fe5
--- /dev/null
+++ b/js/src/yarr/OSAllocatorPosix.cpp
@@ -0,0 +1,129 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assembler/wtf/Platform.h"
+
+#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
+
+#include "OSAllocator.h"
+
+#include 
+#include 
+#include "wtf/Assertions.h"
+
+namespace WTF {
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
+{
+    void* result = reserveAndCommit(bytes, usage, writable, executable);
+#if HAVE_MADV_FREE_REUSE
+    // To support the "reserve then commit" model, we have to initially decommit.
+    while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+#endif
+    return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable)
+{
+    // All POSIX reservations start out logically committed.
+    int protection = PROT_READ;
+    if (writable)
+        protection |= PROT_WRITE;
+    if (executable)
+        protection |= PROT_EXEC;
+
+    int flags = MAP_PRIVATE | MAP_ANON;
+
+#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER)
+    int fd = usage;
+#else
+    int fd = -1;
+#endif
+
+    void* result = 0;
+#if (WTF_OS_DARWIN && WTF_CPU_X86_64)
+    if (executable) {
+        // Cook up an address to allocate at, using the following recipe:
+        //   17 bits of zero, stay in userspace kids.
+        //   26 bits of randomness for ASLR.
+        //   21 bits of zero, at least stay aligned within one level of the pagetables.
+        //
+        // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
+        // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus
+        // 2^24, which should put up somewhere in the middle of userspace (in the address range
+        // 0x200000000000 .. 0x5fffffffffff).
+        intptr_t randomLocation = 0;
+        randomLocation = arc4random() & ((1 << 25) - 1);
+        randomLocation += (1 << 24);
+        randomLocation <<= 21;
+        result = reinterpret_cast(randomLocation);
+    }
+#endif
+
+    result = mmap(result, bytes, protection, flags, fd, 0);
+    if (result == MAP_FAILED)
+        CRASH();
+    return result;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool, bool)
+{
+#if HAVE_MADV_FREE_REUSE
+    while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
+#else
+    // Non-MADV_FREE_REUSE reservations automatically commit on demand.
+    UNUSED_PARAM(address);
+    UNUSED_PARAM(bytes);
+#endif
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+#if HAVE_MADV_FREE_REUSE
+    while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+#elif HAVE_MADV_FREE
+    while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { }
+#elif HAVE_MADV_DONTNEED
+    while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
+#else
+    UNUSED_PARAM(address);
+    UNUSED_PARAM(bytes);
+#endif
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+    int result = munmap(address, bytes);
+    if (result == -1)
+        CRASH();
+}
+
+} // namespace WTF
+
+#endif
diff --git a/js/src/yarr/OSAllocatorWin.cpp b/js/src/yarr/OSAllocatorWin.cpp
new file mode 100644
index 000000000000..08df9e98aefb
--- /dev/null
+++ b/js/src/yarr/OSAllocatorWin.cpp
@@ -0,0 +1,89 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "assembler/wtf/Platform.h"
+
+#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
+
+#include "windows.h"
+#include "wtf/Assertions.h"
+
+#include "OSAllocator.h"
+
+namespace WTF {
+
+static inline DWORD protection(bool writable, bool executable)
+{
+    return executable ?
+        (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) :
+        (writable ? PAGE_READWRITE : PAGE_READONLY);
+}
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable)
+{
+    void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable));
+    if (!result)
+        CRASH();
+    return result;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable)
+{
+    void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable));
+    if (!result)
+        CRASH();
+    return result;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
+{
+    void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable));
+    if (!result)
+        CRASH();
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+    bool result = VirtualFree(address, bytes, MEM_DECOMMIT);
+    if (!result)
+        CRASH();
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+    // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx,
+    // dwSize must be 0 if dwFreeType is MEM_RELEASE.
+    bool result = VirtualFree(address, 0, MEM_RELEASE);
+    if (!result)
+        CRASH();
+}
+
+} // namespace WTF
+
+#endif
diff --git a/js/src/yarr/PageAllocation.h b/js/src/yarr/PageAllocation.h
new file mode 100644
index 000000000000..a86f37116e50
--- /dev/null
+++ b/js/src/yarr/PageAllocation.h
@@ -0,0 +1,131 @@
+/* -*- 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) 2010 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PageAllocation_h
+#define PageAllocation_h
+
+#include "wtfbridge.h"
+#include "OSAllocator.h"
+#include "PageBlock.h"
+#include "assembler/wtf/VMTags.h"
+
+#if WTF_OS_DARWIN
+#include 
+#include 
+#endif
+
+#if WTF_OS_HAIKU
+#include 
+#endif
+
+#if WTF_OS_WINDOWS
+#include 
+#include 
+#endif
+
+#if WTF_OS_SYMBIAN
+#include 
+#include 
+#endif
+
+#if WTF_HAVE_ERRNO_H
+#include 
+#endif
+
+#if WTF_HAVE_MMAP
+#include 
+#include 
+#endif
+
+namespace WTF {
+
+/*
+    PageAllocation
+
+    The PageAllocation class provides a cross-platform memory allocation interface
+    with similar capabilities to posix mmap/munmap.  Memory is allocated by calling
+    PageAllocation::allocate, and deallocated by calling deallocate on the
+    PageAllocation object.  The PageAllocation holds the allocation's base pointer
+    and size.
+
+    The allocate method is passed the size required (which must be a multiple of
+    the system page size, which can be accessed using PageAllocation::pageSize).
+    Callers may also optinally provide a flag indicating the usage (for use by
+    system memory usage tracking tools, where implemented), and boolean values
+    specifying the required protection (defaulting to writable, non-executable).
+*/
+
+class PageAllocation : private PageBlock {
+public:
+    PageAllocation()
+    {
+    }
+
+    using PageBlock::size;
+    using PageBlock::base;
+
+#ifndef __clang__
+    using PageBlock::operator bool;
+#else
+    // FIXME: This is a workaround for , wherein Clang incorrectly emits an access
+    // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
+    operator bool() const { return PageBlock::operator bool(); }
+#endif
+
+    static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
+    {
+        ASSERT(isPageAligned(size));
+        return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size);
+    }
+
+    void deallocate()
+    {
+        // Clear base & size before calling release; if this is *inside* allocation
+        // then we won't be able to clear then after deallocating the memory.
+        PageAllocation tmp;
+        JSC::std::swap(tmp, *this);
+
+        ASSERT(tmp);
+        ASSERT(!*this);
+
+        OSAllocator::decommitAndRelease(tmp.base(), tmp.size());
+    }
+
+private:
+    PageAllocation(void* base, size_t size)
+        : PageBlock(base, size)
+    {
+    }
+};
+
+} // namespace WTF
+
+using WTF::PageAllocation;
+
+#endif // PageAllocation_h
diff --git a/js/src/yarr/PageBlock.cpp b/js/src/yarr/PageBlock.cpp
new file mode 100644
index 000000000000..0f435b772860
--- /dev/null
+++ b/js/src/yarr/PageBlock.cpp
@@ -0,0 +1,88 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "PageBlock.h"
+#include "wtf/Assertions.h"
+
+#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
+#include 
+#endif
+
+#if WTF_OS_WINDOWS
+#include 
+#include 
+#endif
+
+#if WTF_OS_SYMBIAN
+#include 
+#include 
+#endif
+
+namespace WTF {
+
+static size_t s_pageSize;
+
+#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
+
+inline size_t systemPageSize()
+{
+    return getpagesize();
+}
+
+#elif WTF_OS_WINDOWS
+
+inline size_t systemPageSize()
+{
+    static size_t size = 0;
+    SYSTEM_INFO system_info;
+    GetSystemInfo(&system_info);
+    size = system_info.dwPageSize;
+    return size;
+}
+
+#elif WTF_OS_SYMBIAN
+
+inline size_t systemPageSize()
+{
+    static TInt page_size = 0;
+    UserHal::PageSizeInBytes(page_size);
+    return page_size;
+}
+
+#endif
+
+size_t pageSize()
+{
+    if (!s_pageSize)
+        s_pageSize = systemPageSize();
+    ASSERT(isPowerOfTwo(s_pageSize));
+    return s_pageSize;
+}
+
+} // namespace WTF
diff --git a/js/src/yarr/PageBlock.h b/js/src/yarr/PageBlock.h
new file mode 100644
index 000000000000..33751315e049
--- /dev/null
+++ b/js/src/yarr/PageBlock.h
@@ -0,0 +1,91 @@
+/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PageBlock_h
+#define PageBlock_h
+
+#include 
+#include "jsstdint.h"
+#include "assembler/wtf/Platform.h"
+
+namespace WTF {
+
+size_t pageSize();
+inline bool isPageAligned(void* address) { return !(reinterpret_cast(address) & (pageSize() - 1)); }
+inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
+inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
+
+class PageBlock {
+public:
+    PageBlock();
+    PageBlock(const PageBlock&);
+    PageBlock(void*, size_t);
+    
+    void* base() const { return m_base; }
+    size_t size() const { return m_size; }
+
+    operator bool() const { return !!m_base; }
+
+    bool contains(void* containedBase, size_t containedSize)
+    {
+        return containedBase >= m_base
+            && (static_cast(containedBase) + containedSize) <= (static_cast(m_base) + m_size);
+    }
+
+private:
+    void* m_base;
+    size_t m_size;
+};
+
+inline PageBlock::PageBlock()
+    : m_base(0)
+    , m_size(0)
+{
+}
+
+inline PageBlock::PageBlock(const PageBlock& other)
+    : m_base(other.m_base)
+    , m_size(other.m_size)
+{
+}
+
+inline PageBlock::PageBlock(void* base, size_t size)
+    : m_base(base)
+    , m_size(size)
+{
+}
+
+} // namespace WTF
+
+using WTF::pageSize;
+using WTF::isPageAligned;
+using WTF::isPageAligned;
+using WTF::isPowerOfTwo;
+
+#endif // PageBlock_h
diff --git a/js/src/yarr/yarr/RegExpJitTables.h b/js/src/yarr/RegExpJitTables.h
similarity index 100%
rename from js/src/yarr/yarr/RegExpJitTables.h
rename to js/src/yarr/RegExpJitTables.h
diff --git a/js/src/yarr/VMTags.h b/js/src/yarr/VMTags.h
new file mode 100644
index 000000000000..fe6a006d3601
--- /dev/null
+++ b/js/src/yarr/VMTags.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 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 VMTags_h
+#define VMTags_h
+
+// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map
+// in order to aid tools that inspect system memory use. 
+#if WTF_OS_DARWIN
+
+#include 
+
+#if !defined(TARGETING_TIGER)
+
+#if defined(VM_MEMORY_TCMALLOC)
+#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
+#else
+#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53)
+#endif // defined(VM_MEMORY_TCMALLOC)
+
+#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
+#else
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64)
+#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
+
+#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
+#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
+#else
+#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65)
+#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
+
+#else // !defined(TARGETING_TIGER)
+
+// mmap on Tiger fails with tags that work on Leopard, so fall
+// back to Tiger-compatible tags (that also work on Leopard)
+// when targeting Tiger.
+#define VM_TAG_FOR_TCMALLOC_MEMORY -1
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
+#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
+
+#endif // !defined(TARGETING_TIGER)
+
+// Tags for vm_map and vm_allocate work on both Tiger and Leopard.
+
+#if defined(VM_MEMORY_JAVASCRIPT_CORE)
+#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE)
+#else
+#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63)
+#endif // defined(VM_MEMORY_JAVASCRIPT_CORE)
+
+#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
+#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
+#else
+#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69)
+#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
+
+#else // OS(DARWIN)
+
+#define VM_TAG_FOR_TCMALLOC_MEMORY -1
+#define VM_TAG_FOR_COLLECTOR_MEMORY -1
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
+#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
+#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1
+
+#endif // OS(DARWIN)
+
+#endif // VMTags_h
diff --git a/js/src/yarr/Yarr.h b/js/src/yarr/Yarr.h
new file mode 100644
index 000000000000..40ebcca096af
--- /dev/null
+++ b/js/src/yarr/Yarr.h
@@ -0,0 +1,72 @@
+/* -*- 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.
+ *
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef Yarr_h
+#define Yarr_h
+
+#include 
+
+#include "YarrInterpreter.h"
+#include "YarrPattern.h"
+
+namespace JSC { namespace Yarr {
+
+#define YarrStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoBackReference 2
+#define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
+#define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1
+#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
+#define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1
+#define YarrStackSpaceForBackTrackInfoParentheses 2
+
+static const unsigned quantifyInfinite = UINT_MAX;
+
+// The below limit restricts the number of "recursive" match calls in order to
+// avoid spending exponential time on complex regular expressions.
+static const unsigned matchLimit = 1000000;
+
+enum JSRegExpResult {
+    JSRegExpMatch = 1,
+    JSRegExpNoMatch = 0,
+    JSRegExpErrorNoMatch = -1,
+    JSRegExpErrorHitLimit = -2,
+    JSRegExpErrorNoMemory = -3,
+    JSRegExpErrorInternal = -4
+};
+
+PassOwnPtr byteCompile(YarrPattern&, BumpPointerAllocator*);
+int interpret(BytecodePattern*, const UChar* input, unsigned start, unsigned length, int* output);
+
+} } // namespace JSC::Yarr
+
+#endif // Yarr_h
+
diff --git a/js/src/yarr/YarrInterpreter.cpp b/js/src/yarr/YarrInterpreter.cpp
new file mode 100644
index 000000000000..3458cad37037
--- /dev/null
+++ b/js/src/yarr/YarrInterpreter.cpp
@@ -0,0 +1,1914 @@
+/* -*- 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
+ *
+ * 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "YarrInterpreter.h"
+
+#include "Yarr.h"
+#include "BumpPointerAllocator.h"
+
+#ifndef NDEBUG
+#include 
+#endif
+
+using namespace WTF;
+
+namespace JSC { namespace Yarr {
+
+class Interpreter {
+public:
+    struct ParenthesesDisjunctionContext;
+
+    struct BackTrackInfoPatternCharacter {
+        uintptr_t matchAmount;
+    };
+    struct BackTrackInfoCharacterClass {
+        uintptr_t matchAmount;
+    };
+    struct BackTrackInfoBackReference {
+        uintptr_t begin; // Not really needed for greedy quantifiers.
+        uintptr_t matchAmount; // Not really needed for fixed quantifiers.
+    };
+    struct BackTrackInfoAlternative {
+        uintptr_t offset;
+    };
+    struct BackTrackInfoParentheticalAssertion {
+        uintptr_t begin;
+    };
+    struct BackTrackInfoParenthesesOnce {
+        uintptr_t begin;
+    };
+    struct BackTrackInfoParenthesesTerminal {
+        uintptr_t begin;
+    };
+    struct BackTrackInfoParentheses {
+        uintptr_t matchAmount;
+        ParenthesesDisjunctionContext* lastContext;
+    };
+
+    static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context)
+    {
+        context->next = backTrack->lastContext;
+        backTrack->lastContext = context;
+        ++backTrack->matchAmount;
+    }
+
+    static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack)
+    {
+        ASSERT(backTrack->matchAmount);
+        ASSERT(backTrack->lastContext);
+        backTrack->lastContext = backTrack->lastContext->next;
+        --backTrack->matchAmount;
+    }
+
+    struct DisjunctionContext
+    {
+        DisjunctionContext()
+            : term(0)
+        {
+        }
+
+        void* operator new(size_t, void* where)
+        {
+            return where;
+        }
+
+        int term;
+        unsigned matchBegin;
+        unsigned matchEnd;
+        uintptr_t frame[1];
+    };
+
+    DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction)
+    {
+        size_t size = sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
+        allocatorPool = allocatorPool->ensureCapacity(size);
+        if (!allocatorPool)
+            CRASH();
+        return new(allocatorPool->alloc(size)) DisjunctionContext();
+    }
+
+    void freeDisjunctionContext(DisjunctionContext* context)
+    {
+        allocatorPool = allocatorPool->dealloc(context);
+    }
+
+    struct ParenthesesDisjunctionContext
+    {
+        ParenthesesDisjunctionContext(int* output, ByteTerm& term)
+            : next(0)
+        {
+            unsigned firstSubpatternId = term.atom.subpatternId;
+            unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns;
+
+            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) {
+                subpatternBackup[i] = output[(firstSubpatternId << 1) + i];
+                output[(firstSubpatternId << 1) + i] = -1;
+            }
+
+            new(getDisjunctionContext(term)) DisjunctionContext();
+        }
+
+        void* operator new(size_t, void* where)
+        {
+            return where;
+        }
+
+        void restoreOutput(int* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns)
+        {
+            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i)
+                output[(firstSubpatternId << 1) + i] = subpatternBackup[i];
+        }
+
+        DisjunctionContext* getDisjunctionContext(ByteTerm& term)
+        {
+            return reinterpret_cast(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1]));
+        }
+
+        ParenthesesDisjunctionContext* next;
+        int subpatternBackup[1];
+    };
+
+    ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, int* output, ByteTerm& term)
+    {
+        size_t size = sizeof(ParenthesesDisjunctionContext) - sizeof(int) + (term.atom.parenthesesDisjunction->m_numSubpatterns << 1) * sizeof(int) + sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
+        allocatorPool = allocatorPool->ensureCapacity(size);
+        if (!allocatorPool)
+            CRASH();
+        return new(allocatorPool->alloc(size)) ParenthesesDisjunctionContext(output, term);
+    }
+
+    void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context)
+    {
+        allocatorPool = allocatorPool->dealloc(context);
+    }
+
+    class InputStream {
+    public:
+        InputStream(const UChar* input, unsigned start, unsigned length)
+            : input(input)
+            , pos(start)
+            , length(length)
+        {
+        }
+
+        void next()
+        {
+            ++pos;
+        }
+
+        void rewind(unsigned amount)
+        {
+            ASSERT(pos >= amount);
+            pos -= amount;
+        }
+
+        int read()
+        {
+            ASSERT(pos < length);
+            if (pos < length)
+                return input[pos];
+            return -1;
+        }
+
+        int readPair()
+        {
+            ASSERT(pos + 1 < length);
+            return input[pos] | input[pos + 1] << 16;
+        }
+
+        int readChecked(int position)
+        {
+            ASSERT(position < 0);
+            ASSERT(static_cast(-position) <= pos);
+            unsigned p = pos + position;
+            ASSERT(p < length);
+            return input[p];
+        }
+
+        int reread(unsigned from)
+        {
+            ASSERT(from < length);
+            return input[from];
+        }
+
+        int prev()
+        {
+            ASSERT(!(pos > length));
+            if (pos && length)
+                return input[pos - 1];
+            return -1;
+        }
+
+        unsigned getPos()
+        {
+            return pos;
+        }
+
+        void setPos(unsigned p)
+        {
+            pos = p;
+        }
+
+        bool atStart()
+        {
+            return pos == 0;
+        }
+
+        bool atEnd()
+        {
+            return pos == length;
+        }
+
+        bool checkInput(int count)
+        {
+            if ((pos + count) <= length) {
+                pos += count;
+                return true;
+            }
+            return false;
+        }
+
+        void uncheckInput(int count)
+        {
+            pos -= count;
+        }
+
+        bool atStart(int position)
+        {
+            return (pos + position) == 0;
+        }
+
+        bool atEnd(int position)
+        {
+            return (pos + position) == length;
+        }
+
+        bool isNotAvailableInput(int position)
+        {
+            return (pos + position) > length;
+        }
+
+    private:
+        const UChar* input;
+        unsigned pos;
+        unsigned length;
+    };
+
+    bool testCharacterClass(CharacterClass* characterClass, int ch)
+    {
+        if (ch & 0xFF80) {
+            for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i)
+                if (ch == characterClass->m_matchesUnicode[i])
+                    return true;
+            for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i)
+                if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end))
+                    return true;
+        } else {
+            for (unsigned i = 0; i < characterClass->m_matches.size(); ++i)
+                if (ch == characterClass->m_matches[i])
+                    return true;
+            for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i)
+                if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end))
+                    return true;
+        }
+
+        return false;
+    }
+
+    bool checkCharacter(int testChar, int inputPosition)
+    {
+        return testChar == input.readChecked(inputPosition);
+    }
+
+    bool checkCasedCharacter(int loChar, int hiChar, int inputPosition)
+    {
+        int ch = input.readChecked(inputPosition);
+        return (loChar == ch) || (hiChar == ch);
+    }
+
+    bool checkCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition)
+    {
+        bool match = testCharacterClass(characterClass, input.readChecked(inputPosition));
+        return invert ? !match : match;
+    }
+
+    bool tryConsumeBackReference(int matchBegin, int matchEnd, int inputOffset)
+    {
+        int matchSize = matchEnd - matchBegin;
+
+        if (!input.checkInput(matchSize))
+            return false;
+
+        if (pattern->m_ignoreCase) {
+            for (int i = 0; i < matchSize; ++i) {
+                int ch = input.reread(matchBegin + i);
+
+                int lo = Unicode::toLower(ch);
+                int hi = Unicode::toUpper(ch);
+
+                if ((lo != hi) ? (!checkCasedCharacter(lo, hi, inputOffset - matchSize + i)) : (!checkCharacter(ch, inputOffset - matchSize + i))) {
+                    input.uncheckInput(matchSize);
+                    return false;
+                }
+            }
+        } else {
+            for (int i = 0; i < matchSize; ++i) {
+                if (!checkCharacter(input.reread(matchBegin + i), inputOffset - matchSize + i)) {
+                    input.uncheckInput(matchSize);
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    bool matchAssertionBOL(ByteTerm& term)
+    {
+        return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition - 1)));
+    }
+
+    bool matchAssertionEOL(ByteTerm& term)
+    {
+        if (term.inputPosition)
+            return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition)));
+
+        return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read()));
+    }
+
+    bool matchAssertionWordBoundary(ByteTerm& term)
+    {
+        bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition - 1));
+        bool readIsWordchar;
+        if (term.inputPosition)
+            readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition));
+        else
+            readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read());
+
+        bool wordBoundary = prevIsWordchar != readIsWordchar;
+        return term.invert() ? !wordBoundary : wordBoundary;
+    }
+
+    bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context)
+    {
+        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount:
+            break;
+
+        case QuantifierGreedy:
+            if (backTrack->matchAmount) {
+                --backTrack->matchAmount;
+                input.uncheckInput(1);
+                return true;
+            }
+            break;
+
+        case QuantifierNonGreedy:
+            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+                ++backTrack->matchAmount;
+                if (checkCharacter(term.atom.patternCharacter, term.inputPosition - 1))
+                    return true;
+            }
+            input.uncheckInput(backTrack->matchAmount);
+            break;
+        }
+
+        return false;
+    }
+
+    bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context)
+    {
+        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount:
+            break;
+
+        case QuantifierGreedy:
+            if (backTrack->matchAmount) {
+                --backTrack->matchAmount;
+                input.uncheckInput(1);
+                return true;
+            }
+            break;
+
+        case QuantifierNonGreedy:
+            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+                ++backTrack->matchAmount;
+                if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition - 1))
+                    return true;
+            }
+            input.uncheckInput(backTrack->matchAmount);
+            break;
+        }
+
+        return false;
+    }
+
+    bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeCharacterClass);
+        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + matchAmount))
+                    return false;
+            }
+            return true;
+        }
+
+        case QuantifierGreedy: {
+            unsigned matchAmount = 0;
+            while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) {
+                    input.uncheckInput(1);
+                    break;
+                }
+                ++matchAmount;
+            }
+            backTrack->matchAmount = matchAmount;
+
+            return true;
+        }
+
+        case QuantifierNonGreedy:
+            backTrack->matchAmount = 0;
+            return true;
+        }
+
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+
+    bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeCharacterClass);
+        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount:
+            break;
+
+        case QuantifierGreedy:
+            if (backTrack->matchAmount) {
+                --backTrack->matchAmount;
+                input.uncheckInput(1);
+                return true;
+            }
+            break;
+
+        case QuantifierNonGreedy:
+            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+                ++backTrack->matchAmount;
+                if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1))
+                    return true;
+            }
+            input.uncheckInput(backTrack->matchAmount);
+            break;
+        }
+
+        return false;
+    }
+
+    bool matchBackReference(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeBackReference);
+        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        int matchBegin = output[(term.atom.subpatternId << 1)];
+        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
+
+        // If the end position of the referenced match hasn't set yet then the backreference in the same parentheses where it references to that.
+        // In this case the result of match is empty string like when it references to a parentheses with zero-width match.
+        // Eg.: /(a\1)/
+        if (matchEnd == -1)
+            return true;
+
+        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
+
+        if (matchBegin == matchEnd)
+            return true;
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            backTrack->begin = input.getPos();
+            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+                if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
+                    input.setPos(backTrack->begin);
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        case QuantifierGreedy: {
+            unsigned matchAmount = 0;
+            while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
+                ++matchAmount;
+            backTrack->matchAmount = matchAmount;
+            return true;
+        }
+
+        case QuantifierNonGreedy:
+            backTrack->begin = input.getPos();
+            backTrack->matchAmount = 0;
+            return true;
+        }
+
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+
+    bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeBackReference);
+        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        int matchBegin = output[(term.atom.subpatternId << 1)];
+        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
+        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
+
+        if (matchBegin == matchEnd)
+            return false;
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount:
+            // for quantityCount == 1, could rewind.
+            input.setPos(backTrack->begin);
+            break;
+
+        case QuantifierGreedy:
+            if (backTrack->matchAmount) {
+                --backTrack->matchAmount;
+                input.rewind(matchEnd - matchBegin);
+                return true;
+            }
+            break;
+
+        case QuantifierNonGreedy:
+            if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
+                ++backTrack->matchAmount;
+                return true;
+            }
+            input.setPos(backTrack->begin);
+            break;
+        }
+
+        return false;
+    }
+
+    void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context)
+    {
+        if (term.capture()) {
+            unsigned subpatternId = term.atom.subpatternId;
+            output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition;
+            output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition;
+        }
+    }
+    void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context)
+    {
+        unsigned firstSubpatternId = term.atom.subpatternId;
+        unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns;
+        context->restoreOutput(output, firstSubpatternId, count);
+    }
+    JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack)
+    {
+        while (backTrack->matchAmount) {
+            ParenthesesDisjunctionContext* context = backTrack->lastContext;
+
+            JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true);
+            if (result == JSRegExpMatch)
+                return JSRegExpMatch;
+
+            resetMatches(term, context);
+            popParenthesesDisjunctionContext(backTrack);
+            freeParenthesesDisjunctionContext(context);
+
+            if (result != JSRegExpNoMatch)
+                return result;
+        }
+
+        return JSRegExpNoMatch;
+    }
+
+    bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierGreedy: {
+            // set this speculatively; if we get to the parens end this will be true.
+            backTrack->begin = input.getPos();
+            break;
+        }
+        case QuantifierNonGreedy: {
+            backTrack->begin = notFound;
+            context->term += term.atom.parenthesesWidth;
+            return true;
+        }
+        case QuantifierFixedCount:
+            break;
+        }
+
+        if (term.capture()) {
+            unsigned subpatternId = term.atom.subpatternId;
+            output[(subpatternId << 1)] = input.getPos() + term.inputPosition;
+        }
+
+        return true;
+    }
+
+    bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
+        ASSERT(term.atom.quantityCount == 1);
+
+        if (term.capture()) {
+            unsigned subpatternId = term.atom.subpatternId;
+            output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
+        }
+
+        if (term.atom.quantityType == QuantifierFixedCount)
+            return true;
+
+        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        return backTrack->begin != input.getPos();
+    }
+
+    bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        if (term.capture()) {
+            unsigned subpatternId = term.atom.subpatternId;
+            output[(subpatternId << 1)] = -1;
+            output[(subpatternId << 1) + 1] = -1;
+        }
+
+        switch (term.atom.quantityType) {
+        case QuantifierGreedy:
+            // if we backtrack to this point, there is another chance - try matching nothing.
+            ASSERT(backTrack->begin != notFound);
+            backTrack->begin = notFound;
+            context->term += term.atom.parenthesesWidth;
+            return true;
+        case QuantifierNonGreedy:
+            ASSERT(backTrack->begin != notFound);
+        case QuantifierFixedCount:
+            break;
+        }
+
+        return false;
+    }
+
+    bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        switch (term.atom.quantityType) {
+        case QuantifierGreedy:
+            if (backTrack->begin == notFound) {
+                context->term -= term.atom.parenthesesWidth;
+                return false;
+            }
+        case QuantifierNonGreedy:
+            if (backTrack->begin == notFound) {
+                backTrack->begin = input.getPos();
+                if (term.capture()) {
+                    // Technically this access to inputPosition should be accessing the begin term's
+                    // inputPosition, but for repeats other than fixed these values should be
+                    // the same anyway! (We don't pre-check for greedy or non-greedy matches.)
+                    ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+                    ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition);
+                    unsigned subpatternId = term.atom.subpatternId;
+                    output[subpatternId << 1] = input.getPos() + term.inputPosition;
+                }
+                context->term -= term.atom.parenthesesWidth;
+                return true;
+            }
+        case QuantifierFixedCount:
+            break;
+        }
+
+        return false;
+    }
+
+    bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+        ASSERT(term.atom.quantityType == QuantifierGreedy);
+        ASSERT(term.atom.quantityCount == quantifyInfinite);
+        ASSERT(!term.capture());
+
+        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        backTrack->begin = input.getPos();
+        return true;
+    }
+
+    bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd);
+
+        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        // Empty match is a failed match.
+        if (backTrack->begin == input.getPos())
+            return false;
+
+        // Successful match! Okay, what's next? - loop around and try to match moar!
+        context->term -= (term.atom.parenthesesWidth + 1);
+        return true;
+    }
+
+    bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+        ASSERT(term.atom.quantityType == QuantifierGreedy);
+        ASSERT(term.atom.quantityCount == quantifyInfinite);
+        ASSERT(!term.capture());
+
+        // If we backtrack to this point, we have failed to match this iteration of the parens.
+        // Since this is greedy / zero minimum a failed is also accepted as a match!
+        context->term += term.atom.parenthesesWidth;
+        return true;
+    }
+
+    bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*)
+    {
+        // 'Terminal' parentheses are at the end of the regex, and as such a match past end
+        // should always be returned as a successful match - we should never backtrack to here.
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+
+    bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        backTrack->begin = input.getPos();
+        return true;
+    }
+
+    bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        input.setPos(backTrack->begin);
+
+        // We've reached the end of the parens; if they are inverted, this is failure.
+        if (term.invert()) {
+            context->term -= term.atom.parenthesesWidth;
+            return false;
+        }
+
+        return true;
+    }
+
+    bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
+        ASSERT(term.atom.quantityCount == 1);
+
+        // We've failed to match parens; if they are inverted, this is win!
+        if (term.invert()) {
+            context->term += term.atom.parenthesesWidth;
+            return true;
+        }
+
+        return false;
+    }
+
+    bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
+        ASSERT(term.atom.quantityCount == 1);
+
+        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+
+        input.setPos(backTrack->begin);
+
+        context->term -= term.atom.parenthesesWidth;
+        return false;
+    }
+
+    JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
+
+        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
+
+        backTrack->matchAmount = 0;
+        backTrack->lastContext = 0;
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            // While we haven't yet reached our fixed limit,
+            while (backTrack->matchAmount < term.atom.quantityCount) {
+                // Try to do a match, and it it succeeds, add it to the list.
+                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                if (result == JSRegExpMatch)
+                    appendParenthesesDisjunctionContext(backTrack, context);
+                else {
+                    // The match failed; try to find an alternate point to carry on from.
+                    resetMatches(term, context);
+                    freeParenthesesDisjunctionContext(context);
+
+                    if (result == JSRegExpNoMatch) {
+                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
+                        if (backtrackResult != JSRegExpMatch)
+                            return backtrackResult;
+                    } else
+                        return result;
+                }
+            }
+
+            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+            ParenthesesDisjunctionContext* context = backTrack->lastContext;
+            recordParenthesesMatch(term, context);
+            return JSRegExpMatch;
+        }
+
+        case QuantifierGreedy: {
+            while (backTrack->matchAmount < term.atom.quantityCount) {
+                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                if (result == JSRegExpMatch)
+                    appendParenthesesDisjunctionContext(backTrack, context);
+                else {
+                    resetMatches(term, context);
+                    freeParenthesesDisjunctionContext(context);
+
+                    if (result != JSRegExpNoMatch)
+                        return result;
+
+                    break;
+                }
+            }
+
+            if (backTrack->matchAmount) {
+                ParenthesesDisjunctionContext* context = backTrack->lastContext;
+                recordParenthesesMatch(term, context);
+            }
+            return JSRegExpMatch;
+        }
+
+        case QuantifierNonGreedy:
+            return JSRegExpMatch;
+        }
+
+        ASSERT_NOT_REACHED();
+        return JSRegExpErrorNoMatch;
+    }
+
+    // Rules for backtracking differ depending on whether this is greedy or non-greedy.
+    //
+    // Greedy matches never should try just adding more - you should already have done
+    // the 'more' cases.  Always backtrack, at least a leetle bit.  However cases where
+    // you backtrack an item off the list needs checking, since we'll never have matched
+    // the one less case.  Tracking forwards, still add as much as possible.
+    //
+    // Non-greedy, we've already done the one less case, so don't match on popping.
+    // We haven't done the one more case, so always try to add that.
+    //
+    JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context)
+    {
+        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
+
+        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
+        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+
+            ParenthesesDisjunctionContext* context = 0;
+            JSRegExpResult result = parenthesesDoBacktrack(term, backTrack);
+
+            if (result != JSRegExpMatch)
+                return result;
+
+            // While we haven't yet reached our fixed limit,
+            while (backTrack->matchAmount < term.atom.quantityCount) {
+                // Try to do a match, and it it succeeds, add it to the list.
+                context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+
+                if (result == JSRegExpMatch)
+                    appendParenthesesDisjunctionContext(backTrack, context);
+                else {
+                    // The match failed; try to find an alternate point to carry on from.
+                    resetMatches(term, context);
+                    freeParenthesesDisjunctionContext(context);
+
+                    if (result == JSRegExpNoMatch) {
+                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
+                        if (backtrackResult != JSRegExpMatch)
+                            return backtrackResult;
+                    } else
+                        return result;
+                }
+            }
+
+            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+            context = backTrack->lastContext;
+            recordParenthesesMatch(term, context);
+            return JSRegExpMatch;
+        }
+
+        case QuantifierGreedy: {
+            if (!backTrack->matchAmount)
+                return JSRegExpNoMatch;
+
+            ParenthesesDisjunctionContext* context = backTrack->lastContext;
+            JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
+            if (result == JSRegExpMatch) {
+                while (backTrack->matchAmount < term.atom.quantityCount) {
+                    ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                    JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                    if (parenthesesResult == JSRegExpMatch)
+                        appendParenthesesDisjunctionContext(backTrack, context);
+                    else {
+                        resetMatches(term, context);
+                        freeParenthesesDisjunctionContext(context);
+
+                        if (parenthesesResult != JSRegExpNoMatch)
+                            return parenthesesResult;
+
+                        break;
+                    }
+                }
+            } else {
+                resetMatches(term, context);
+                popParenthesesDisjunctionContext(backTrack);
+                freeParenthesesDisjunctionContext(context);
+
+                if (result != JSRegExpNoMatch)
+                    return result;
+            }
+
+            if (backTrack->matchAmount) {
+                ParenthesesDisjunctionContext* context = backTrack->lastContext;
+                recordParenthesesMatch(term, context);
+            }
+            return JSRegExpMatch;
+        }
+
+        case QuantifierNonGreedy: {
+            // If we've not reached the limit, try to add one more match.
+            if (backTrack->matchAmount < term.atom.quantityCount) {
+                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
+                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                if (result == JSRegExpMatch) {
+                    appendParenthesesDisjunctionContext(backTrack, context);
+                    recordParenthesesMatch(term, context);
+                    return JSRegExpMatch;
+                }
+
+                resetMatches(term, context);
+                freeParenthesesDisjunctionContext(context);
+
+                if (result != JSRegExpNoMatch)
+                    return result;
+            }
+
+            // Nope - okay backtrack looking for an alternative.
+            while (backTrack->matchAmount) {
+                ParenthesesDisjunctionContext* context = backTrack->lastContext;
+                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
+                if (result == JSRegExpMatch) {
+                    // successful backtrack! we're back in the game!
+                    if (backTrack->matchAmount) {
+                        context = backTrack->lastContext;
+                        recordParenthesesMatch(term, context);
+                    }
+                    return JSRegExpMatch;
+                }
+
+                // pop a match off the stack
+                resetMatches(term, context);
+                popParenthesesDisjunctionContext(backTrack);
+                freeParenthesesDisjunctionContext(context);
+
+                return result;
+            }
+
+            return JSRegExpNoMatch;
+        }
+        }
+
+        ASSERT_NOT_REACHED();
+        return JSRegExpErrorNoMatch;
+    }
+
+    void lookupForBeginChars()
+    {
+        int character;
+        bool firstSingleCharFound;
+
+        while (true) {
+            if (input.isNotAvailableInput(2))
+                return;
+
+            firstSingleCharFound = false;
+
+            character = input.readPair();
+
+            for (unsigned i = 0; i < pattern->m_beginChars.size(); ++i) {
+                BeginChar bc = pattern->m_beginChars[i];
+
+                if (!firstSingleCharFound && bc.value <= 0xFFFF) {
+                    firstSingleCharFound = true;
+                    character &= 0xFFFF;
+                }
+
+                if ((character | bc.mask) == bc.value)
+                    return;
+            }
+
+            input.next();
+        }
+    }
+
+#define MATCH_NEXT() { ++context->term; goto matchAgain; }
+#define BACKTRACK() { --context->term; goto backtrack; }
+#define currentTerm() (disjunction->terms[context->term])
+    JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false, bool isBody = false)
+    {
+        if (!--remainingMatchCount)
+            return JSRegExpErrorHitLimit;
+
+        if (btrack)
+            BACKTRACK();
+
+        if (pattern->m_containsBeginChars && isBody)
+            lookupForBeginChars();
+
+        context->matchBegin = input.getPos();
+        context->term = 0;
+
+    matchAgain:
+        ASSERT(context->term < static_cast(disjunction->terms.size()));
+
+        switch (currentTerm().type) {
+        case ByteTerm::TypeSubpatternBegin:
+            MATCH_NEXT();
+        case ByteTerm::TypeSubpatternEnd:
+            context->matchEnd = input.getPos();
+            return JSRegExpMatch;
+
+        case ByteTerm::TypeBodyAlternativeBegin:
+            MATCH_NEXT();
+        case ByteTerm::TypeBodyAlternativeDisjunction:
+        case ByteTerm::TypeBodyAlternativeEnd:
+            context->matchEnd = input.getPos();
+            return JSRegExpMatch;
+
+        case ByteTerm::TypeAlternativeBegin:
+            MATCH_NEXT();
+        case ByteTerm::TypeAlternativeDisjunction:
+        case ByteTerm::TypeAlternativeEnd: {
+            int offset = currentTerm().alternative.end;
+            BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            backTrack->offset = offset;
+            context->term += offset;
+            MATCH_NEXT();
+        }
+
+        case ByteTerm::TypeAssertionBOL:
+            if (matchAssertionBOL(currentTerm()))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeAssertionEOL:
+            if (matchAssertionEOL(currentTerm()))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeAssertionWordBoundary:
+            if (matchAssertionWordBoundary(currentTerm()))
+                MATCH_NEXT();
+            BACKTRACK();
+
+        case ByteTerm::TypePatternCharacterOnce:
+        case ByteTerm::TypePatternCharacterFixed: {
+            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + matchAmount))
+                    BACKTRACK();
+            }
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypePatternCharacterGreedy: {
+            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            unsigned matchAmount = 0;
+            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
+                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 1)) {
+                    input.uncheckInput(1);
+                    break;
+                }
+                ++matchAmount;
+            }
+            backTrack->matchAmount = matchAmount;
+
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypePatternCharacterNonGreedy: {
+            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            backTrack->matchAmount = 0;
+            MATCH_NEXT();
+        }
+
+        case ByteTerm::TypePatternCasedCharacterOnce:
+        case ByteTerm::TypePatternCasedCharacterFixed: {
+            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + matchAmount))
+                    BACKTRACK();
+            }
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypePatternCasedCharacterGreedy: {
+            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            unsigned matchAmount = 0;
+            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
+                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - 1)) {
+                    input.uncheckInput(1);
+                    break;
+                }
+                ++matchAmount;
+            }
+            backTrack->matchAmount = matchAmount;
+
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypePatternCasedCharacterNonGreedy: {
+            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+            backTrack->matchAmount = 0;
+            MATCH_NEXT();
+        }
+
+        case ByteTerm::TypeCharacterClass:
+            if (matchCharacterClass(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeBackReference:
+            if (matchBackReference(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParenthesesSubpattern: {
+            JSRegExpResult result = matchParentheses(currentTerm(), context);
+
+            if (result == JSRegExpMatch) {
+                MATCH_NEXT();
+            }  else if (result != JSRegExpNoMatch)
+                return result;
+
+            BACKTRACK();
+        }
+        case ByteTerm::TypeParenthesesSubpatternOnceBegin:
+            if (matchParenthesesOnceBegin(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParenthesesSubpatternOnceEnd:
+            if (matchParenthesesOnceEnd(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
+            if (matchParenthesesTerminalBegin(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
+            if (matchParenthesesTerminalEnd(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParentheticalAssertionBegin:
+            if (matchParentheticalAssertionBegin(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+        case ByteTerm::TypeParentheticalAssertionEnd:
+            if (matchParentheticalAssertionEnd(currentTerm(), context))
+                MATCH_NEXT();
+            BACKTRACK();
+
+        case ByteTerm::TypeCheckInput:
+            if (input.checkInput(currentTerm().checkInputCount))
+                MATCH_NEXT();
+            BACKTRACK();
+
+            case ByteTerm::TypeUncheckInput:
+                input.uncheckInput(currentTerm().checkInputCount);
+                MATCH_NEXT();
+        }
+
+        // We should never fall-through to here.
+        ASSERT_NOT_REACHED();
+
+    backtrack:
+        ASSERT(context->term < static_cast(disjunction->terms.size()));
+
+        switch (currentTerm().type) {
+        case ByteTerm::TypeSubpatternBegin:
+            return JSRegExpNoMatch;
+        case ByteTerm::TypeSubpatternEnd:
+            ASSERT_NOT_REACHED();
+
+        case ByteTerm::TypeBodyAlternativeBegin:
+        case ByteTerm::TypeBodyAlternativeDisjunction: {
+            int offset = currentTerm().alternative.next;
+            context->term += offset;
+            if (offset > 0)
+                MATCH_NEXT();
+
+            if (input.atEnd())
+                return JSRegExpNoMatch;
+
+            input.next();
+
+            if (pattern->m_containsBeginChars && isBody)
+                lookupForBeginChars();
+
+            context->matchBegin = input.getPos();
+
+            if (currentTerm().alternative.onceThrough)
+                context->term += currentTerm().alternative.next;
+
+            MATCH_NEXT();
+        }
+        case ByteTerm::TypeBodyAlternativeEnd:
+            ASSERT_NOT_REACHED();
+
+            case ByteTerm::TypeAlternativeBegin:
+            case ByteTerm::TypeAlternativeDisjunction: {
+                int offset = currentTerm().alternative.next;
+                context->term += offset;
+                if (offset > 0)
+                    MATCH_NEXT();
+                BACKTRACK();
+            }
+            case ByteTerm::TypeAlternativeEnd: {
+                // We should never backtrack back into an alternative of the main body of the regex.
+                BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
+                unsigned offset = backTrack->offset;
+                context->term -= offset;
+                BACKTRACK();
+            }
+
+            case ByteTerm::TypeAssertionBOL:
+            case ByteTerm::TypeAssertionEOL:
+            case ByteTerm::TypeAssertionWordBoundary:
+                BACKTRACK();
+
+            case ByteTerm::TypePatternCharacterOnce:
+            case ByteTerm::TypePatternCharacterFixed:
+            case ByteTerm::TypePatternCharacterGreedy:
+            case ByteTerm::TypePatternCharacterNonGreedy:
+                if (backtrackPatternCharacter(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypePatternCasedCharacterOnce:
+            case ByteTerm::TypePatternCasedCharacterFixed:
+            case ByteTerm::TypePatternCasedCharacterGreedy:
+            case ByteTerm::TypePatternCasedCharacterNonGreedy:
+                if (backtrackPatternCasedCharacter(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeCharacterClass:
+                if (backtrackCharacterClass(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeBackReference:
+                if (backtrackBackReference(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParenthesesSubpattern: {
+                JSRegExpResult result = backtrackParentheses(currentTerm(), context);
+
+                if (result == JSRegExpMatch) {
+                    MATCH_NEXT();
+                } else if (result != JSRegExpNoMatch)
+                    return result;
+
+                BACKTRACK();
+            }
+            case ByteTerm::TypeParenthesesSubpatternOnceBegin:
+                if (backtrackParenthesesOnceBegin(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParenthesesSubpatternOnceEnd:
+                if (backtrackParenthesesOnceEnd(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
+                if (backtrackParenthesesTerminalBegin(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
+                if (backtrackParenthesesTerminalEnd(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParentheticalAssertionBegin:
+                if (backtrackParentheticalAssertionBegin(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+            case ByteTerm::TypeParentheticalAssertionEnd:
+                if (backtrackParentheticalAssertionEnd(currentTerm(), context))
+                    MATCH_NEXT();
+                BACKTRACK();
+
+            case ByteTerm::TypeCheckInput:
+                input.uncheckInput(currentTerm().checkInputCount);
+                BACKTRACK();
+
+            case ByteTerm::TypeUncheckInput:
+                input.checkInput(currentTerm().checkInputCount);
+                BACKTRACK();
+        }
+
+        ASSERT_NOT_REACHED();
+        return JSRegExpErrorNoMatch;
+    }
+
+    JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
+    {
+        JSRegExpResult result = matchDisjunction(disjunction, context, btrack);
+
+        if (result == JSRegExpMatch) {
+            while (context->matchBegin == context->matchEnd) {
+                result = matchDisjunction(disjunction, context, true);
+                if (result != JSRegExpMatch)
+                    return result;
+            }
+            return JSRegExpMatch;
+        }
+
+        return result;
+    }
+
+    int interpret()
+    {
+        allocatorPool = pattern->m_allocator->startAllocator();
+        if (!allocatorPool)
+            CRASH();
+
+        for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i)
+            output[i] = -1;
+
+        DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get());
+
+        JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false, true);
+        if (result == JSRegExpMatch) {
+            output[0] = context->matchBegin;
+            output[1] = context->matchEnd;
+        }
+
+        freeDisjunctionContext(context);
+
+        pattern->m_allocator->stopAllocator();
+
+        // RegExp.cpp currently expects all error to be converted to -1.
+        ASSERT((result == JSRegExpMatch) == (output[0] != -1));
+        return output[0];
+    }
+
+    Interpreter(BytecodePattern* pattern, int* output, const UChar* inputChar, unsigned start, unsigned length)
+        : pattern(pattern)
+        , output(output)
+        , input(inputChar, start, length)
+        , allocatorPool(0)
+        , remainingMatchCount(matchLimit)
+    {
+    }
+
+private:
+    BytecodePattern* pattern;
+    int* output;
+    InputStream input;
+    BumpPointerPool* allocatorPool;
+    unsigned remainingMatchCount;
+};
+
+
+
+class ByteCompiler {
+    struct ParenthesesStackEntry {
+        unsigned beginTerm;
+        unsigned savedAlternativeIndex;
+        // For js::Vector. Does not create a valid object.
+        ParenthesesStackEntry() {}
+        ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/)
+            : beginTerm(beginTerm)
+            , savedAlternativeIndex(savedAlternativeIndex)
+        {
+        }
+    };
+
+public:
+    ByteCompiler(YarrPattern& pattern)
+        : m_pattern(pattern)
+    {
+        m_currentAlternativeIndex = 0;
+    }
+
+    PassOwnPtr compile(BumpPointerAllocator* allocator)
+    {
+        regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough());
+        emitDisjunction(m_pattern.m_body);
+        regexEnd();
+
+        return adoptPtr(js::OffTheBooks::new_(m_bodyDisjunction.release(), m_allParenthesesInfo, m_pattern, allocator));
+    }
+
+    void checkInput(unsigned count)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count));
+    }
+
+    void uncheckInput(unsigned count)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::UncheckInput(count));
+    }
+    
+    void assertionBOL(int inputPosition)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition));
+    }
+
+    void assertionEOL(int inputPosition)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition));
+    }
+
+    void assertionWordBoundary(bool invert, int inputPosition)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition));
+    }
+
+    void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        if (m_pattern.m_ignoreCase) {
+            UChar lo = Unicode::toLower(ch);
+            UChar hi = Unicode::toUpper(ch);
+
+            if (lo != hi) {
+                m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType));
+                return;
+            }
+        }
+
+        m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType));
+    }
+
+    void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition));
+
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+    }
+
+    void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        ASSERT(subpatternId);
+
+        m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition));
+
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+    }
+
+    void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+    {
+        int beginTerm = m_bodyDisjunction->terms.size();
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+        m_currentAlternativeIndex = beginTerm + 1;
+    }
+
+    void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+    {
+        int beginTerm = m_bodyDisjunction->terms.size();
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+        m_currentAlternativeIndex = beginTerm + 1;
+    }
+
+    void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
+    {
+        // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin,
+        // then fix this up at the end! - simplifying this should make it much clearer.
+        // https://bugs.webkit.org/show_bug.cgi?id=50136
+
+        int beginTerm = m_bodyDisjunction->terms.size();
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+        m_currentAlternativeIndex = beginTerm + 1;
+    }
+
+    void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation)
+    {
+        int beginTerm = m_bodyDisjunction->terms.size();
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, false, invert, 0));
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
+
+        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
+        m_currentAlternativeIndex = beginTerm + 1;
+    }
+
+    void atomParentheticalAssertionEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        unsigned beginTerm = popParenthesesStack();
+        closeAlternative(beginTerm + 1);
+        unsigned endTerm = m_bodyDisjunction->terms.size();
+
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin);
+
+        bool invert = m_bodyDisjunction->terms[beginTerm].invert();
+        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, false, invert, inputPosition));
+        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+    }
+
+    unsigned popParenthesesStack()
+    {
+        ASSERT(m_parenthesesStack.size());
+        int stackEnd = m_parenthesesStack.size() - 1;
+        unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm;
+        m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex;
+        m_parenthesesStack.shrink(stackEnd);
+
+        ASSERT(beginTerm < m_bodyDisjunction->terms.size());
+        ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size());
+
+        return beginTerm;
+    }
+
+#ifndef NDEBUG
+    void dumpDisjunction(ByteDisjunction* disjunction)
+    {
+        printf("ByteDisjunction(%p):\n\t", (void *) disjunction);
+        for (unsigned i = 0; i < disjunction->terms.size(); ++i)
+            printf("{ %d } ", disjunction->terms[i].type);
+        printf("\n");
+    }
+#endif
+
+    void closeAlternative(int beginTerm)
+    {
+        int origBeginTerm = beginTerm;
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin);
+        int endIndex = m_bodyDisjunction->terms.size();
+
+        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
+
+        if (!m_bodyDisjunction->terms[beginTerm].alternative.next)
+            m_bodyDisjunction->terms.remove(beginTerm);
+        else {
+            while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
+                beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
+                ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction);
+                m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
+                m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+            }
+
+            m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
+
+            m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd());
+            m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
+        }
+    }
+
+    void closeBodyAlternative()
+    {
+        int beginTerm = 0;
+        int origBeginTerm = 0;
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin);
+        int endIndex = m_bodyDisjunction->terms.size();
+
+        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
+
+        while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
+            beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
+            ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction);
+            m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
+            m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+        }
+
+        m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
+
+        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd());
+        m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
+    }
+
+    void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
+    {
+        unsigned beginTerm = popParenthesesStack();
+        closeAlternative(beginTerm + 1);
+        unsigned endTerm = m_bodyDisjunction->terms.size();
+
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+
+        ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
+
+        bool capture = parenthesesBegin.capture();
+        unsigned subpatternId = parenthesesBegin.atom.subpatternId;
+
+        unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
+        ByteDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(numSubpatterns, callFrameSize);
+
+        parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
+        for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
+            parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
+        parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
+
+        m_bodyDisjunction->terms.shrink(beginTerm);
+
+        m_allParenthesesInfo.append(parenthesesDisjunction);
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, inputPosition));
+
+        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
+    }
+
+    void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        unsigned beginTerm = popParenthesesStack();
+        closeAlternative(beginTerm + 1);
+        unsigned endTerm = m_bodyDisjunction->terms.size();
+
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
+
+        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
+        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+    }
+
+    void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+    {
+        unsigned beginTerm = popParenthesesStack();
+        closeAlternative(beginTerm + 1);
+        unsigned endTerm = m_bodyDisjunction->terms.size();
+
+        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
+
+        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
+        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
+
+        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, capture, false, inputPosition));
+        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
+        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
+
+        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
+        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
+        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
+    }
+
+    void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough)
+    {
+        m_bodyDisjunction = adoptPtr(js::OffTheBooks::new_(numSubpatterns, callFrameSize));
+        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough));
+        m_bodyDisjunction->terms[0].frameLocation = 0;
+        m_currentAlternativeIndex = 0;
+    }
+
+    void regexEnd()
+    {
+        closeBodyAlternative();
+    }
+
+    void alternativeBodyDisjunction(bool onceThrough)
+    {
+        int newAlternativeIndex = m_bodyDisjunction->terms.size();
+        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
+        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough));
+
+        m_currentAlternativeIndex = newAlternativeIndex;
+    }
+
+    void alternativeDisjunction()
+    {
+        int newAlternativeIndex = m_bodyDisjunction->terms.size();
+        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
+        m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction());
+
+        m_currentAlternativeIndex = newAlternativeIndex;
+    }
+
+    void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0)
+    {
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
+            unsigned currentCountAlreadyChecked = inputCountAlreadyChecked;
+
+            PatternAlternative* alternative = disjunction->m_alternatives[alt];
+
+            if (alt) {
+                if (disjunction == m_pattern.m_body)
+                    alternativeBodyDisjunction(alternative->onceThrough());
+                else
+                    alternativeDisjunction();
+            }
+
+            unsigned minimumSize = alternative->m_minimumSize;
+            int countToCheck = minimumSize - parenthesesInputCountAlreadyChecked;
+
+            ASSERT(countToCheck >= 0);
+            if (countToCheck) {
+                checkInput(countToCheck);
+                currentCountAlreadyChecked += countToCheck;
+            }
+
+            for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
+                PatternTerm& term = alternative->m_terms[i];
+
+                switch (term.type) {
+                case PatternTerm::TypeAssertionBOL:
+                    assertionBOL(term.inputPosition - currentCountAlreadyChecked);
+                    break;
+
+                case PatternTerm::TypeAssertionEOL:
+                    assertionEOL(term.inputPosition - currentCountAlreadyChecked);
+                    break;
+
+                case PatternTerm::TypeAssertionWordBoundary:
+                    assertionWordBoundary(term.invert(), term.inputPosition - currentCountAlreadyChecked);
+                    break;
+
+                case PatternTerm::TypePatternCharacter:
+                    atomPatternCharacter(term.patternCharacter, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+                    break;
+
+                case PatternTerm::TypeCharacterClass:
+                    atomCharacterClass(term.characterClass, term.invert(), term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+                    break;
+
+                case PatternTerm::TypeBackReference:
+                    atomBackReference(term.backReferenceSubpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
+                        break;
+
+                case PatternTerm::TypeForwardReference:
+                    break;
+
+                case PatternTerm::TypeParenthesesSubpattern: {
+                    unsigned disjunctionAlreadyCheckedCount = 0;
+                    if (term.quantityCount == 1 && !term.parentheses.isCopy) {
+                        unsigned alternativeFrameLocation = term.frameLocation;
+                        // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame.
+                        if (term.quantityType == QuantifierFixedCount)
+                            disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize;
+                        else
+                            alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+                        atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, alternativeFrameLocation);
+                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
+                        atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
+                    } else if (term.parentheses.isTerminal) {
+                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+                        atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce);
+                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
+                        atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
+                    } else {
+                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
+                        atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0);
+                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
+                        atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
+                    }
+                    break;
+                }
+
+                case PatternTerm::TypeParentheticalAssertion: {
+                    unsigned alternativeFrameLocation = term.frameLocation + YarrStackSpaceForBackTrackInfoParentheticalAssertion;
+
+                    ASSERT(currentCountAlreadyChecked >= static_cast(term.inputPosition));
+                    int positiveInputOffset = currentCountAlreadyChecked - term.inputPosition;
+                    int uncheckAmount = positiveInputOffset - term.parentheses.disjunction->m_minimumSize;
+
+                    if (uncheckAmount > 0) {
+                        uncheckInput(uncheckAmount);
+                        currentCountAlreadyChecked -= uncheckAmount;
+                    } else
+                        uncheckAmount = 0;
+
+                    atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation);
+                    emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount);
+                    atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType);
+                    if (uncheckAmount) {
+                        checkInput(uncheckAmount);
+                        currentCountAlreadyChecked += uncheckAmount;
+                    }
+                    break;
+                }
+                }
+            }
+        }
+    }
+
+private:
+    YarrPattern& m_pattern;
+    OwnPtr m_bodyDisjunction;
+    unsigned m_currentAlternativeIndex;
+    Vector m_parenthesesStack;
+    Vector m_allParenthesesInfo;
+};
+
+PassOwnPtr byteCompile(YarrPattern& pattern, BumpPointerAllocator* allocator)
+{
+    return ByteCompiler(pattern).compile(allocator);
+}
+
+int interpret(BytecodePattern* bytecode, const UChar* input, unsigned start, unsigned length, int* output)
+{
+    return Interpreter(bytecode, output, input, start, length).interpret();
+}
+
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoPatternCharacter);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoCharacterClass);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoBackReference);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce);
+COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);
+
+
+} }
diff --git a/js/src/yarr/YarrInterpreter.h b/js/src/yarr/YarrInterpreter.h
new file mode 100644
index 000000000000..32b72858cad1
--- /dev/null
+++ b/js/src/yarr/YarrInterpreter.h
@@ -0,0 +1,380 @@
+/* -*- 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, 2010 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef YarrInterpreter_h
+#define YarrInterpreter_h
+
+#include "YarrPattern.h"
+
+namespace WTF {
+class BumpPointerAllocator;
+}
+using WTF::BumpPointerAllocator;
+
+namespace JSC { namespace Yarr {
+
+class ByteDisjunction;
+
+struct ByteTerm {
+    enum Type {
+        TypeBodyAlternativeBegin,
+        TypeBodyAlternativeDisjunction,
+        TypeBodyAlternativeEnd,
+        TypeAlternativeBegin,
+        TypeAlternativeDisjunction,
+        TypeAlternativeEnd,
+        TypeSubpatternBegin,
+        TypeSubpatternEnd,
+        TypeAssertionBOL,
+        TypeAssertionEOL,
+        TypeAssertionWordBoundary,
+        TypePatternCharacterOnce,
+        TypePatternCharacterFixed,
+        TypePatternCharacterGreedy,
+        TypePatternCharacterNonGreedy,
+        TypePatternCasedCharacterOnce,
+        TypePatternCasedCharacterFixed,
+        TypePatternCasedCharacterGreedy,
+        TypePatternCasedCharacterNonGreedy,
+        TypeCharacterClass,
+        TypeBackReference,
+        TypeParenthesesSubpattern,
+        TypeParenthesesSubpatternOnceBegin,
+        TypeParenthesesSubpatternOnceEnd,
+        TypeParenthesesSubpatternTerminalBegin,
+        TypeParenthesesSubpatternTerminalEnd,
+        TypeParentheticalAssertionBegin,
+        TypeParentheticalAssertionEnd,
+        TypeCheckInput,
+        TypeUncheckInput
+    } type;
+    union {
+        struct {
+            union {
+                UChar patternCharacter;
+                struct {
+                    UChar lo;
+                    UChar hi;
+                } casedCharacter;
+                CharacterClass* characterClass;
+                unsigned subpatternId;
+            };
+            union {
+                ByteDisjunction* parenthesesDisjunction;
+                unsigned parenthesesWidth;
+            };
+            QuantifierType quantityType;
+            unsigned quantityCount;
+        } atom;
+        struct {
+            int next;
+            int end;
+            bool onceThrough;
+        } alternative;
+        unsigned checkInputCount;
+    };
+    unsigned frameLocation;
+    bool m_capture : 1;
+    bool m_invert : 1;
+    int inputPosition;
+
+    // For js::Vector. Does not create a valid object.
+    ByteTerm()
+    {
+    }
+
+    ByteTerm(UChar ch, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+        : frameLocation(frameLocation)
+        , m_capture(false)
+        , m_invert(false)
+    {
+        switch (quantityType) {
+        case QuantifierFixedCount:
+            type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed;
+            break;
+        case QuantifierGreedy:
+            type = ByteTerm::TypePatternCharacterGreedy;
+            break;
+        case QuantifierNonGreedy:
+            type = ByteTerm::TypePatternCharacterNonGreedy;
+            break;
+        }
+
+        atom.patternCharacter = ch;
+        atom.quantityType = quantityType;
+        atom.quantityCount = quantityCount;
+        inputPosition = inputPos;
+    }
+
+    ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
+        : frameLocation(frameLocation)
+        , m_capture(false)
+        , m_invert(false)
+    {
+        switch (quantityType) {
+        case QuantifierFixedCount:
+            type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed;
+            break;
+        case QuantifierGreedy:
+            type = ByteTerm::TypePatternCasedCharacterGreedy;
+            break;
+        case QuantifierNonGreedy:
+            type = ByteTerm::TypePatternCasedCharacterNonGreedy;
+            break;
+        }
+
+        atom.casedCharacter.lo = lo;
+        atom.casedCharacter.hi = hi;
+        atom.quantityType = quantityType;
+        atom.quantityCount = quantityCount;
+        inputPosition = inputPos;
+    }
+
+    ByteTerm(CharacterClass* characterClass, bool invert, int inputPos)
+        : type(ByteTerm::TypeCharacterClass)
+        , m_capture(false)
+        , m_invert(invert)
+    {
+        atom.characterClass = characterClass;
+        atom.quantityType = QuantifierFixedCount;
+        atom.quantityCount = 1;
+        inputPosition = inputPos;
+    }
+
+    ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool capture, int inputPos)
+        : type(type)
+        , m_capture(capture)
+        , m_invert(false)
+    {
+        atom.subpatternId = subpatternId;
+        atom.parenthesesDisjunction = parenthesesInfo;
+        atom.quantityType = QuantifierFixedCount;
+        atom.quantityCount = 1;
+        inputPosition = inputPos;
+    }
+    
+    ByteTerm(Type type, bool invert = false)
+        : type(type)
+        , m_capture(false)
+        , m_invert(invert)
+    {
+        atom.quantityType = QuantifierFixedCount;
+        atom.quantityCount = 1;
+    }
+
+    ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, int inputPos)
+        : type(type)
+        , m_capture(capture)
+        , m_invert(invert)
+    {
+        atom.subpatternId = subpatternId;
+        atom.quantityType = QuantifierFixedCount;
+        atom.quantityCount = 1;
+        inputPosition = inputPos;
+    }
+
+    static ByteTerm BOL(int inputPos)
+    {
+        ByteTerm term(TypeAssertionBOL);
+        term.inputPosition = inputPos;
+        return term;
+    }
+
+    static ByteTerm CheckInput(unsigned count)
+    {
+        ByteTerm term(TypeCheckInput);
+        term.checkInputCount = count;
+        return term;
+    }
+
+    static ByteTerm UncheckInput(unsigned count)
+    {
+        ByteTerm term(TypeUncheckInput);
+        term.checkInputCount = count;
+        return term;
+    }
+    
+    static ByteTerm EOL(int inputPos)
+    {
+        ByteTerm term(TypeAssertionEOL);
+        term.inputPosition = inputPos;
+        return term;
+    }
+
+    static ByteTerm WordBoundary(bool invert, int inputPos)
+    {
+        ByteTerm term(TypeAssertionWordBoundary, invert);
+        term.inputPosition = inputPos;
+        return term;
+    }
+    
+    static ByteTerm BackReference(unsigned subpatternId, int inputPos)
+    {
+        return ByteTerm(TypeBackReference, subpatternId, false, false, inputPos);
+    }
+
+    static ByteTerm BodyAlternativeBegin(bool onceThrough)
+    {
+        ByteTerm term(TypeBodyAlternativeBegin);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = onceThrough;
+        return term;
+    }
+
+    static ByteTerm BodyAlternativeDisjunction(bool onceThrough)
+    {
+        ByteTerm term(TypeBodyAlternativeDisjunction);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = onceThrough;
+        return term;
+    }
+
+    static ByteTerm BodyAlternativeEnd()
+    {
+        ByteTerm term(TypeBodyAlternativeEnd);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = false;
+        return term;
+    }
+
+    static ByteTerm AlternativeBegin()
+    {
+        ByteTerm term(TypeAlternativeBegin);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = false;
+        return term;
+    }
+
+    static ByteTerm AlternativeDisjunction()
+    {
+        ByteTerm term(TypeAlternativeDisjunction);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = false;
+        return term;
+    }
+
+    static ByteTerm AlternativeEnd()
+    {
+        ByteTerm term(TypeAlternativeEnd);
+        term.alternative.next = 0;
+        term.alternative.end = 0;
+        term.alternative.onceThrough = false;
+        return term;
+    }
+
+    static ByteTerm SubpatternBegin()
+    {
+        return ByteTerm(TypeSubpatternBegin);
+    }
+
+    static ByteTerm SubpatternEnd()
+    {
+        return ByteTerm(TypeSubpatternEnd);
+    }
+
+    bool invert()
+    {
+        return m_invert;
+    }
+
+    bool capture()
+    {
+        return m_capture;
+    }
+};
+
+class ByteDisjunction {
+    WTF_MAKE_FAST_ALLOCATED
+public:
+    ByteDisjunction(unsigned numSubpatterns, unsigned frameSize)
+        : m_numSubpatterns(numSubpatterns)
+        , m_frameSize(frameSize)
+    {
+    }
+
+    Vector terms;
+    unsigned m_numSubpatterns;
+    unsigned m_frameSize;
+};
+
+struct BytecodePattern {
+    WTF_MAKE_FAST_ALLOCATED
+public:
+    BytecodePattern(PassOwnPtr body, Vector allParenthesesInfo, YarrPattern& pattern, BumpPointerAllocator* allocator)
+        : m_body(body)
+        , m_ignoreCase(pattern.m_ignoreCase)
+        , m_multiline(pattern.m_multiline)
+        , m_containsBeginChars(pattern.m_containsBeginChars)
+        , m_allocator(allocator)
+    {
+        newlineCharacterClass = pattern.newlineCharacterClass();
+        wordcharCharacterClass = pattern.wordcharCharacterClass();
+
+        m_allParenthesesInfo.append(allParenthesesInfo);
+        m_userCharacterClasses.append(pattern.m_userCharacterClasses);
+        // 'Steal' the YarrPattern's CharacterClasses!  We clear its
+        // array, so that it won't delete them on destruction.  We'll
+        // take responsibility for that.
+        pattern.m_userCharacterClasses.clear();
+
+        m_beginChars.append(pattern.m_beginChars);
+    }
+
+    ~BytecodePattern()
+    {
+        deleteAllValues(m_allParenthesesInfo);
+        deleteAllValues(m_userCharacterClasses);
+    }
+
+    OwnPtr m_body;
+    bool m_ignoreCase;
+    bool m_multiline;
+    bool m_containsBeginChars;
+    // Each BytecodePattern is associated with a RegExp, each RegExp is associated
+    // with a JSGlobalData.  Cache a pointer to out JSGlobalData's m_regExpAllocator.
+    BumpPointerAllocator* m_allocator;
+
+    CharacterClass* newlineCharacterClass;
+    CharacterClass* wordcharCharacterClass;
+
+    Vector m_beginChars;
+
+private:
+    Vector m_allParenthesesInfo;
+    Vector m_userCharacterClasses;
+};
+
+} } // namespace JSC::Yarr
+
+#endif // YarrInterpreter_h
diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp
new file mode 100644
index 000000000000..c0187f240b6d
--- /dev/null
+++ b/js/src/yarr/YarrJIT.cpp
@@ -0,0 +1,2405 @@
+/* -*- 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.
+ *
+ * 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "YarrJIT.h"
+
+#include "assembler/assembler/LinkBuffer.h"
+#include "Yarr.h"
+
+#if ENABLE_YARR_JIT
+
+using namespace WTF;
+
+namespace JSC { namespace Yarr {
+
+class YarrGenerator : private MacroAssembler {
+    friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
+
+#if WTF_CPU_ARM
+    static const RegisterID input = ARMRegisters::r0;
+    static const RegisterID index = ARMRegisters::r1;
+    static const RegisterID length = ARMRegisters::r2;
+    static const RegisterID output = ARMRegisters::r4;
+
+    static const RegisterID regT0 = ARMRegisters::r5;
+    static const RegisterID regT1 = ARMRegisters::r6;
+
+    static const RegisterID returnRegister = ARMRegisters::r0;
+#elif WTF_CPU_MIPS
+    static const RegisterID input = MIPSRegisters::a0;
+    static const RegisterID index = MIPSRegisters::a1;
+    static const RegisterID length = MIPSRegisters::a2;
+    static const RegisterID output = MIPSRegisters::a3;
+
+    static const RegisterID regT0 = MIPSRegisters::t4;
+    static const RegisterID regT1 = MIPSRegisters::t5;
+
+    static const RegisterID returnRegister = MIPSRegisters::v0;
+#elif WTF_CPU_SH4
+    static const RegisterID input = SH4Registers::r4;
+    static const RegisterID index = SH4Registers::r5;
+    static const RegisterID length = SH4Registers::r6;
+    static const RegisterID output = SH4Registers::r7;
+
+    static const RegisterID regT0 = SH4Registers::r0;
+    static const RegisterID regT1 = SH4Registers::r1;
+
+    static const RegisterID returnRegister = SH4Registers::r0;
+#elif WTF_CPU_X86
+    static const RegisterID input = X86Registers::eax;
+    static const RegisterID index = X86Registers::edx;
+    static const RegisterID length = X86Registers::ecx;
+    static const RegisterID output = X86Registers::edi;
+
+    static const RegisterID regT0 = X86Registers::ebx;
+    static const RegisterID regT1 = X86Registers::esi;
+
+    static const RegisterID returnRegister = X86Registers::eax;
+#elif WTF_CPU_X86_64
+    static const RegisterID input = X86Registers::edi;
+    static const RegisterID index = X86Registers::esi;
+    static const RegisterID length = X86Registers::edx;
+    static const RegisterID output = X86Registers::ecx;
+
+    static const RegisterID regT0 = X86Registers::eax;
+    static const RegisterID regT1 = X86Registers::ebx;
+
+    static const RegisterID returnRegister = X86Registers::eax;
+#endif
+
+    void optimizeAlternative(PatternAlternative* alternative)
+    {
+        if (!alternative->m_terms.size())
+            return;
+
+        for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) {
+            PatternTerm& term = alternative->m_terms[i];
+            PatternTerm& nextTerm = alternative->m_terms[i + 1];
+
+            if ((term.type == PatternTerm::TypeCharacterClass)
+                && (term.quantityType == QuantifierFixedCount)
+                && (nextTerm.type == PatternTerm::TypePatternCharacter)
+                && (nextTerm.quantityType == QuantifierFixedCount)) {
+                PatternTerm termCopy = term;
+                alternative->m_terms[i] = nextTerm;
+                alternative->m_terms[i + 1] = termCopy;
+            }
+        }
+    }
+
+    void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount)
+    {
+        do {
+            // pick which range we're going to generate
+            int which = count >> 1;
+            char lo = ranges[which].begin;
+            char hi = ranges[which].end;
+
+            // check if there are any ranges or matches below lo.  If not, just jl to failure -
+            // if there is anything else to check, check that first, if it falls through jmp to failure.
+            if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
+                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
+
+                // generate code for all ranges before this one
+                if (which)
+                    matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
+
+                while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
+                    matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex])));
+                    ++*matchIndex;
+                }
+                failures.append(jump());
+
+                loOrAbove.link(this);
+            } else if (which) {
+                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
+
+                matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
+                failures.append(jump());
+
+                loOrAbove.link(this);
+            } else
+                failures.append(branch32(LessThan, character, Imm32((unsigned short)lo)));
+
+            while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi))
+                ++*matchIndex;
+
+            matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi)));
+            // fall through to here, the value is above hi.
+
+            // shuffle along & loop around if there are any more matches to handle.
+            unsigned next = which + 1;
+            ranges += next;
+            count -= next;
+        } while (count);
+    }
+
+    void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass)
+    {
+        if (charClass->m_table) {
+            ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table));
+            matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry));
+            return;
+        }
+        Jump unicodeFail;
+        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) {
+            Jump isAscii = branch32(LessThanOrEqual, character, TrustedImm32(0x7f));
+
+            if (charClass->m_matchesUnicode.size()) {
+                for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) {
+                    UChar ch = charClass->m_matchesUnicode[i];
+                    matchDest.append(branch32(Equal, character, Imm32(ch)));
+                }
+            }
+
+            if (charClass->m_rangesUnicode.size()) {
+                for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) {
+                    UChar lo = charClass->m_rangesUnicode[i].begin;
+                    UChar hi = charClass->m_rangesUnicode[i].end;
+
+                    Jump below = branch32(LessThan, character, Imm32(lo));
+                    matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi)));
+                    below.link(this);
+                }
+            }
+
+            unicodeFail = jump();
+            isAscii.link(this);
+        }
+
+        if (charClass->m_ranges.size()) {
+            unsigned matchIndex = 0;
+            JumpList failures;
+            matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size());
+            while (matchIndex < charClass->m_matches.size())
+                matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++])));
+
+            failures.link(this);
+        } else if (charClass->m_matches.size()) {
+            // optimization: gather 'a','A' etc back together, can mask & test once.
+            Vector matchesAZaz;
+
+            for (unsigned i = 0; i < charClass->m_matches.size(); ++i) {
+                char ch = charClass->m_matches[i];
+                if (m_pattern.m_ignoreCase) {
+                    if (isASCIILower(ch)) {
+                        matchesAZaz.append(ch);
+                        continue;
+                    }
+                    if (isASCIIUpper(ch))
+                        continue;
+                }
+                matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch)));
+            }
+
+            if (unsigned countAZaz = matchesAZaz.size()) {
+                or32(TrustedImm32(32), character);
+                for (unsigned i = 0; i < countAZaz; ++i)
+                    matchDest.append(branch32(Equal, character, TrustedImm32(matchesAZaz[i])));
+            }
+        }
+
+        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size())
+            unicodeFail.link(this);
+    }
+
+    // Jumps if input not available; will have (incorrectly) incremented already!
+    Jump jumpIfNoAvailableInput(unsigned countToCheck = 0)
+    {
+        if (countToCheck)
+            add32(Imm32(countToCheck), index);
+        return branch32(Above, index, length);
+    }
+
+    Jump jumpIfAvailableInput(unsigned countToCheck)
+    {
+        add32(Imm32(countToCheck), index);
+        return branch32(BelowOrEqual, index, length);
+    }
+
+    Jump checkInput()
+    {
+        return branch32(BelowOrEqual, index, length);
+    }
+
+    Jump atEndOfInput()
+    {
+        return branch32(Equal, index, length);
+    }
+
+    Jump notAtEndOfInput()
+    {
+        return branch32(NotEqual, index, length);
+    }
+
+    Jump jumpIfCharEquals(UChar ch, int inputPosition)
+    {
+        return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
+    }
+
+    Jump jumpIfCharNotEquals(UChar ch, int inputPosition)
+    {
+        return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
+    }
+
+    void readCharacter(int inputPosition, RegisterID reg)
+    {
+        load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg);
+    }
+
+    void storeToFrame(RegisterID reg, unsigned frameLocation)
+    {
+        poke(reg, frameLocation);
+    }
+
+    void storeToFrame(TrustedImm32 imm, unsigned frameLocation)
+    {
+        poke(imm, frameLocation);
+    }
+
+    DataLabelPtr storeToFrameWithPatch(unsigned frameLocation)
+    {
+        return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*)));
+    }
+
+    void loadFromFrame(unsigned frameLocation, RegisterID reg)
+    {
+        peek(reg, frameLocation);
+    }
+
+    void loadFromFrameAndJump(unsigned frameLocation)
+    {
+        jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
+    }
+
+    enum YarrOpCode {
+        // These nodes wrap body alternatives - those in the main disjunction,
+        // rather than subpatterns or assertions. These are chained together in
+        // a doubly linked list, with a 'begin' node for the first alternative,
+        // a 'next' node for each subsequent alternative, and an 'end' node at
+        // the end. In the case of repeating alternatives, the 'end' node also
+        // has a reference back to 'begin'.
+        OpBodyAlternativeBegin,
+        OpBodyAlternativeNext,
+        OpBodyAlternativeEnd,
+        // Similar to the body alternatives, but used for subpatterns with two
+        // or more alternatives.
+        OpNestedAlternativeBegin,
+        OpNestedAlternativeNext,
+        OpNestedAlternativeEnd,
+        // Used for alternatives in subpatterns where there is only a single
+        // alternative (backtrackingis easier in these cases), or for alternatives
+        // which never need to be backtracked (those in parenthetical assertions,
+        // terminal subpatterns).
+        OpSimpleNestedAlternativeBegin,
+        OpSimpleNestedAlternativeNext,
+        OpSimpleNestedAlternativeEnd,
+        // Used to wrap 'Once' subpattern matches (quantityCount == 1).
+        OpParenthesesSubpatternOnceBegin,
+        OpParenthesesSubpatternOnceEnd,
+        // Used to wrap 'Terminal' subpattern matches (at the end of the regexp).
+        OpParenthesesSubpatternTerminalBegin,
+        OpParenthesesSubpatternTerminalEnd,
+        // Used to wrap parenthetical assertions.
+        OpParentheticalAssertionBegin,
+        OpParentheticalAssertionEnd,
+        // Wraps all simple terms (pattern characters, character classes).
+        OpTerm,
+        // Where an expression contains only 'once through' body alternatives
+        // and no repeating ones, this op is used to return match failure.
+        OpMatchFailed
+    };
+
+    // This structure is used to hold the compiled opcode information,
+    // including reference back to the original PatternTerm/PatternAlternatives,
+    // and JIT compilation data structures.
+    struct YarrOp {
+        explicit YarrOp(PatternTerm* term)
+            : m_op(OpTerm)
+            , m_term(term)
+            , m_isDeadCode(false)
+        {
+        }
+
+        explicit YarrOp(YarrOpCode op)
+            : m_op(op)
+            , m_isDeadCode(false)
+        {
+        }
+
+        // The operation, as a YarrOpCode, and also a reference to the PatternTerm.
+        YarrOpCode m_op;
+        PatternTerm* m_term;
+
+        // For alternatives, this holds the PatternAlternative and doubly linked
+        // references to this alternative's siblings. In the case of the
+        // OpBodyAlternativeEnd node at the end of a section of repeating nodes,
+        // m_nextOp will reference the OpBodyAlternativeBegin node of the first
+        // repeating alternative.
+        PatternAlternative* m_alternative;
+        size_t m_previousOp;
+        size_t m_nextOp;
+
+        // Used to record a set of Jumps out of the generated code, typically
+        // used for jumps out to backtracking code, and a single reentry back
+        // into the code for a node (likely where a backtrack will trigger
+        // rematching).
+        Label m_reentry;
+        JumpList m_jumps;
+
+        // This flag is used to null out the second pattern character, when
+        // two are fused to match a pair together.
+        bool m_isDeadCode;
+
+        // Currently used in the case of some of the more complex management of
+        // 'm_checked', to cache the offset used in this alternative, to avoid
+        // recalculating it.
+        int m_checkAdjust;
+
+        // Used by OpNestedAlternativeNext/End to hold the pointer to the
+        // value that will be pushed into the pattern's frame to return to,
+        // upon backtracking back into the disjunction.
+        DataLabelPtr m_returnAddress;
+    };
+
+    // BacktrackingState
+    // This class encapsulates information about the state of code generation
+    // whilst generating the code for backtracking, when a term fails to match.
+    // Upon entry to code generation of the backtracking code for a given node,
+    // the Backtracking state will hold references to all control flow sources
+    // that are outputs in need of further backtracking from the prior node
+    // generated (which is the subsequent operation in the regular expression,
+    // and in the m_ops Vector, since we generated backtracking backwards).
+    // These references to control flow take the form of:
+    //  - A jump list of jumps, to be linked to code that will backtrack them
+    //    further.
+    //  - A set of DataLabelPtr values, to be populated with values to be
+    //    treated effectively as return addresses backtracking into complex
+    //    subpatterns.
+    //  - A flag indicating that the current sequence of generated code up to
+    //    this point requires backtracking.
+    class BacktrackingState {
+    public:
+        BacktrackingState()
+            : m_pendingFallthrough(false)
+        {
+        }
+
+        // Add a jump or jumps, a return address, or set the flag indicating
+        // that the current 'fallthrough' control flow requires backtracking.
+        void append(const Jump& jump)
+        {
+            m_laterFailures.append(jump);
+        }
+        void append(JumpList& jumpList)
+        {
+            m_laterFailures.append(jumpList);
+        }
+        void append(const DataLabelPtr& returnAddress)
+        {
+            m_pendingReturns.append(returnAddress);
+        }
+        void fallthrough()
+        {
+            ASSERT(!m_pendingFallthrough);
+            m_pendingFallthrough = true;
+        }
+
+        // These methods clear the backtracking state, either linking to the
+        // current location, a provided label, or copying the backtracking out
+        // to a JumpList. All actions may require code generation to take place,
+        // and as such are passed a pointer to the assembler.
+        void link(MacroAssembler* assembler)
+        {
+            if (m_pendingReturns.size()) {
+                Label here(assembler);
+                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
+                m_pendingReturns.clear();
+            }
+            m_laterFailures.link(assembler);
+            m_laterFailures.clear();
+            m_pendingFallthrough = false;
+        }
+        void linkTo(Label label, MacroAssembler* assembler)
+        {
+            if (m_pendingReturns.size()) {
+                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], label));
+                m_pendingReturns.clear();
+            }
+            if (m_pendingFallthrough)
+                assembler->jump(label);
+            m_laterFailures.linkTo(label, assembler);
+            m_laterFailures.clear();
+            m_pendingFallthrough = false;
+        }
+        void takeBacktracksToJumpList(JumpList& jumpList, MacroAssembler* assembler)
+        {
+            if (m_pendingReturns.size()) {
+                Label here(assembler);
+                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
+                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
+                m_pendingReturns.clear();
+                m_pendingFallthrough = true;
+            }
+            if (m_pendingFallthrough)
+                jumpList.append(assembler->jump());
+            jumpList.append(m_laterFailures);
+            m_laterFailures.clear();
+            m_pendingFallthrough = false;
+        }
+
+        bool isEmpty()
+        {
+            return m_laterFailures.empty() && m_pendingReturns.isEmpty() && !m_pendingFallthrough;
+        }
+
+        // Called at the end of code generation to link all return addresses.
+        void linkDataLabels(LinkBuffer& linkBuffer)
+        {
+            ASSERT(isEmpty());
+            for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
+                linkBuffer.patch(m_backtrackRecords[i].m_dataLabel, linkBuffer.locationOf(m_backtrackRecords[i].m_backtrackLocation));
+        }
+
+    private:
+        struct ReturnAddressRecord {
+            ReturnAddressRecord(DataLabelPtr dataLabel, Label backtrackLocation)
+                : m_dataLabel(dataLabel)
+                , m_backtrackLocation(backtrackLocation)
+            {
+            }
+
+            DataLabelPtr m_dataLabel;
+            Label m_backtrackLocation;
+        };
+
+        JumpList m_laterFailures;
+        bool m_pendingFallthrough;
+        Vector m_pendingReturns;
+        Vector m_backtrackRecords;
+    };
+
+    // Generation methods:
+    // ===================
+
+    // This method provides a default implementation of backtracking common
+    // to many terms; terms commonly jump out of the forwards  matching path
+    // on any failed conditions, and add these jumps to the m_jumps list. If
+    // no special handling is required we can often just backtrack to m_jumps.
+    void backtrackTermDefault(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        m_backtrackingState.append(op.m_jumps);
+    }
+
+    void generateAssertionBOL(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        if (m_pattern.m_multiline) {
+            const RegisterID character = regT0;
+
+            JumpList matchDest;
+            if (!term->inputPosition)
+                matchDest.append(branch32(Equal, index, Imm32(m_checked)));
+
+            readCharacter((term->inputPosition - m_checked) - 1, character);
+            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
+            op.m_jumps.append(jump());
+
+            matchDest.link(this);
+        } else {
+            // Erk, really should poison out these alternatives early. :-/
+            if (term->inputPosition)
+                op.m_jumps.append(jump());
+            else
+                op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked)));
+        }
+    }
+    void backtrackAssertionBOL(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generateAssertionEOL(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        if (m_pattern.m_multiline) {
+            const RegisterID character = regT0;
+
+            JumpList matchDest;
+            if (term->inputPosition == m_checked)
+                matchDest.append(atEndOfInput());
+
+            readCharacter((term->inputPosition - m_checked), character);
+            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
+            op.m_jumps.append(jump());
+
+            matchDest.link(this);
+        } else {
+            if (term->inputPosition == m_checked)
+                op.m_jumps.append(notAtEndOfInput());
+            // Erk, really should poison out these alternatives early. :-/
+            else
+                op.m_jumps.append(jump());
+        }
+    }
+    void backtrackAssertionEOL(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    // Also falls though on nextIsNotWordChar.
+    void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+
+        if (term->inputPosition == m_checked)
+            nextIsNotWordChar.append(atEndOfInput());
+
+        readCharacter((term->inputPosition - m_checked), character);
+        matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass());
+    }
+
+    void generateAssertionWordBoundary(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+
+        Jump atBegin;
+        JumpList matchDest;
+        if (!term->inputPosition)
+            atBegin = branch32(Equal, index, Imm32(m_checked));
+        readCharacter((term->inputPosition - m_checked) - 1, character);
+        matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass());
+        if (!term->inputPosition)
+            atBegin.link(this);
+
+        // We fall through to here if the last character was not a wordchar.
+        JumpList nonWordCharThenWordChar;
+        JumpList nonWordCharThenNonWordChar;
+        if (term->invert()) {
+            matchAssertionWordchar(opIndex, nonWordCharThenNonWordChar, nonWordCharThenWordChar);
+            nonWordCharThenWordChar.append(jump());
+        } else {
+            matchAssertionWordchar(opIndex, nonWordCharThenWordChar, nonWordCharThenNonWordChar);
+            nonWordCharThenNonWordChar.append(jump());
+        }
+        op.m_jumps.append(nonWordCharThenNonWordChar);
+
+        // We jump here if the last character was a wordchar.
+        matchDest.link(this);
+        JumpList wordCharThenWordChar;
+        JumpList wordCharThenNonWordChar;
+        if (term->invert()) {
+            matchAssertionWordchar(opIndex, wordCharThenNonWordChar, wordCharThenWordChar);
+            wordCharThenWordChar.append(jump());
+        } else {
+            matchAssertionWordchar(opIndex, wordCharThenWordChar, wordCharThenNonWordChar);
+            // This can fall-though!
+        }
+
+        op.m_jumps.append(wordCharThenWordChar);
+
+        nonWordCharThenWordChar.link(this);
+        wordCharThenNonWordChar.link(this);
+    }
+    void backtrackAssertionWordBoundary(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generatePatternCharacterOnce(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+
+        // m_ops always ends with a OpBodyAlternativeEnd or OpMatchFailed
+        // node, so there must always be at least one more node.
+        ASSERT(opIndex + 1 < m_ops.size());
+        YarrOp& nextOp = m_ops[opIndex + 1];
+
+        if (op.m_isDeadCode)
+            return;
+
+        PatternTerm* term = op.m_term;
+        UChar ch = term->patternCharacter;
+
+        const RegisterID character = regT0;
+
+        if (nextOp.m_op == OpTerm) {
+            PatternTerm* nextTerm = nextOp.m_term;
+            if (nextTerm->type == PatternTerm::TypePatternCharacter
+                && nextTerm->quantityType == QuantifierFixedCount
+                && nextTerm->quantityCount == 1
+                && nextTerm->inputPosition == (term->inputPosition + 1)) {
+
+                UChar ch2 = nextTerm->patternCharacter;
+
+                int mask = 0;
+                int chPair = ch | (ch2 << 16);
+
+                if (m_pattern.m_ignoreCase) {
+                    if (isASCIIAlpha(ch))
+                        mask |= 32;
+                    if (isASCIIAlpha(ch2))
+                        mask |= 32 << 16;
+                }
+
+                BaseIndex address(input, index, TimesTwo, (term->inputPosition - m_checked) * sizeof(UChar));
+                if (mask) {
+                    load32WithUnalignedHalfWords(address, character);
+                    or32(Imm32(mask), character);
+                    op.m_jumps.append(branch32(NotEqual, character, Imm32(chPair | mask)));
+                } else
+                    op.m_jumps.append(branch32WithUnalignedHalfWords(NotEqual, address, Imm32(chPair)));
+
+                nextOp.m_isDeadCode = true;
+                return;
+            }
+        }
+
+        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+            readCharacter(term->inputPosition - m_checked, character);
+            or32(TrustedImm32(32), character);
+            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+        } else {
+            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+            op.m_jumps.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+        }
+    }
+    void backtrackPatternCharacterOnce(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generatePatternCharacterFixed(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+        UChar ch = term->patternCharacter;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        move(index, countRegister);
+        sub32(Imm32(term->quantityCount), countRegister);
+
+        Label loop(this);
+        BaseIndex address(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar));
+
+        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+            load16(address, character);
+            or32(TrustedImm32(32), character);
+            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+        } else {
+            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+            op.m_jumps.append(branch16(NotEqual, address, Imm32(ch)));
+        }
+        add32(TrustedImm32(1), countRegister);
+        branch32(NotEqual, countRegister, index).linkTo(loop, this);
+    }
+    void backtrackPatternCharacterFixed(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generatePatternCharacterGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+        UChar ch = term->patternCharacter;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        move(TrustedImm32(0), countRegister);
+
+        JumpList failures;
+        Label loop(this);
+        failures.append(atEndOfInput());
+        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+            readCharacter(term->inputPosition - m_checked, character);
+            or32(TrustedImm32(32), character);
+            failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+        } else {
+            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+            failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        add32(TrustedImm32(1), index);
+        if (term->quantityCount == quantifyInfinite)
+            jump(loop);
+        else
+            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
+
+        failures.link(this);
+        op.m_reentry = label();
+
+        storeToFrame(countRegister, term->frameLocation);
+
+    }
+    void backtrackPatternCharacterGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID countRegister = regT1;
+
+        m_backtrackingState.link(this);
+
+        loadFromFrame(term->frameLocation, countRegister);
+        m_backtrackingState.append(branchTest32(Zero, countRegister));
+        sub32(TrustedImm32(1), countRegister);
+        sub32(TrustedImm32(1), index);
+        jump(op.m_reentry);
+    }
+
+    void generatePatternCharacterNonGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID countRegister = regT1;
+
+        move(TrustedImm32(0), countRegister);
+        op.m_reentry = label();
+        storeToFrame(countRegister, term->frameLocation);
+    }
+    void backtrackPatternCharacterNonGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+        UChar ch = term->patternCharacter;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        JumpList nonGreedyFailures;
+
+        m_backtrackingState.link(this);
+
+        loadFromFrame(term->frameLocation, countRegister);
+
+        nonGreedyFailures.append(atEndOfInput());
+        if (term->quantityCount != quantifyInfinite)
+            nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
+        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
+            readCharacter(term->inputPosition - m_checked, character);
+            or32(TrustedImm32(32), character);
+            nonGreedyFailures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
+        } else {
+            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
+            nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        add32(TrustedImm32(1), index);
+
+        jump(op.m_reentry);
+
+        nonGreedyFailures.link(this);
+        sub32(countRegister, index);
+        m_backtrackingState.fallthrough();
+    }
+
+    void generateCharacterClassOnce(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+
+        JumpList matchDest;
+        readCharacter((term->inputPosition - m_checked), character);
+        matchCharacterClass(character, matchDest, term->characterClass);
+
+        if (term->invert())
+            op.m_jumps.append(matchDest);
+        else {
+            op.m_jumps.append(jump());
+            matchDest.link(this);
+        }
+    }
+    void backtrackCharacterClassOnce(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generateCharacterClassFixed(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        move(index, countRegister);
+        sub32(Imm32(term->quantityCount), countRegister);
+
+        Label loop(this);
+        JumpList matchDest;
+        load16(BaseIndex(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar)), character);
+        matchCharacterClass(character, matchDest, term->characterClass);
+
+        if (term->invert())
+            op.m_jumps.append(matchDest);
+        else {
+            op.m_jumps.append(jump());
+            matchDest.link(this);
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        branch32(NotEqual, countRegister, index).linkTo(loop, this);
+    }
+    void backtrackCharacterClassFixed(size_t opIndex)
+    {
+        backtrackTermDefault(opIndex);
+    }
+
+    void generateCharacterClassGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        move(TrustedImm32(0), countRegister);
+
+        JumpList failures;
+        Label loop(this);
+        failures.append(atEndOfInput());
+
+        if (term->invert()) {
+            readCharacter(term->inputPosition - m_checked, character);
+            matchCharacterClass(character, failures, term->characterClass);
+        } else {
+            JumpList matchDest;
+            readCharacter(term->inputPosition - m_checked, character);
+            matchCharacterClass(character, matchDest, term->characterClass);
+            failures.append(jump());
+            matchDest.link(this);
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        add32(TrustedImm32(1), index);
+        if (term->quantityCount != quantifyInfinite) {
+            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
+            failures.append(jump());
+        } else
+            jump(loop);
+
+        failures.link(this);
+        op.m_reentry = label();
+
+        storeToFrame(countRegister, term->frameLocation);
+    }
+    void backtrackCharacterClassGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID countRegister = regT1;
+
+        m_backtrackingState.link(this);
+
+        loadFromFrame(term->frameLocation, countRegister);
+        m_backtrackingState.append(branchTest32(Zero, countRegister));
+        sub32(TrustedImm32(1), countRegister);
+        sub32(TrustedImm32(1), index);
+        jump(op.m_reentry);
+    }
+
+    void generateCharacterClassNonGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID countRegister = regT1;
+
+        move(TrustedImm32(0), countRegister);
+        op.m_reentry = label();
+        storeToFrame(countRegister, term->frameLocation);
+    }
+    void backtrackCharacterClassNonGreedy(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        const RegisterID character = regT0;
+        const RegisterID countRegister = regT1;
+
+        JumpList nonGreedyFailures;
+
+        m_backtrackingState.link(this);
+
+        Label backtrackBegin(this);
+        loadFromFrame(term->frameLocation, countRegister);
+
+        nonGreedyFailures.append(atEndOfInput());
+        nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
+
+        JumpList matchDest;
+        readCharacter(term->inputPosition - m_checked, character);
+        matchCharacterClass(character, matchDest, term->characterClass);
+
+        if (term->invert())
+            nonGreedyFailures.append(matchDest);
+        else {
+            nonGreedyFailures.append(jump());
+            matchDest.link(this);
+        }
+
+        add32(TrustedImm32(1), countRegister);
+        add32(TrustedImm32(1), index);
+
+        jump(op.m_reentry);
+
+        nonGreedyFailures.link(this);
+        sub32(countRegister, index);
+        m_backtrackingState.fallthrough();
+    }
+
+    // Code generation/backtracking for simple terms
+    // (pattern characters, character classes, and assertions).
+    // These methods farm out work to the set of functions above.
+    void generateTerm(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        switch (term->type) {
+        case PatternTerm::TypePatternCharacter:
+            switch (term->quantityType) {
+            case QuantifierFixedCount:
+                if (term->quantityCount == 1)
+                    generatePatternCharacterOnce(opIndex);
+                else
+                    generatePatternCharacterFixed(opIndex);
+                break;
+            case QuantifierGreedy:
+                generatePatternCharacterGreedy(opIndex);
+                break;
+            case QuantifierNonGreedy:
+                generatePatternCharacterNonGreedy(opIndex);
+                break;
+            }
+            break;
+
+        case PatternTerm::TypeCharacterClass:
+            switch (term->quantityType) {
+            case QuantifierFixedCount:
+                if (term->quantityCount == 1)
+                    generateCharacterClassOnce(opIndex);
+                else
+                    generateCharacterClassFixed(opIndex);
+                break;
+            case QuantifierGreedy:
+                generateCharacterClassGreedy(opIndex);
+                break;
+            case QuantifierNonGreedy:
+                generateCharacterClassNonGreedy(opIndex);
+                break;
+            }
+            break;
+
+        case PatternTerm::TypeAssertionBOL:
+            generateAssertionBOL(opIndex);
+            break;
+
+        case PatternTerm::TypeAssertionEOL:
+            generateAssertionEOL(opIndex);
+            break;
+
+        case PatternTerm::TypeAssertionWordBoundary:
+            generateAssertionWordBoundary(opIndex);
+            break;
+
+        case PatternTerm::TypeForwardReference:
+            break;
+
+        case PatternTerm::TypeParenthesesSubpattern:
+        case PatternTerm::TypeParentheticalAssertion:
+            ASSERT_NOT_REACHED();
+        case PatternTerm::TypeBackReference:
+            m_shouldFallBack = true;
+            break;
+        }
+    }
+    void backtrackTerm(size_t opIndex)
+    {
+        YarrOp& op = m_ops[opIndex];
+        PatternTerm* term = op.m_term;
+
+        switch (term->type) {
+        case PatternTerm::TypePatternCharacter:
+            switch (term->quantityType) {
+            case QuantifierFixedCount:
+                if (term->quantityCount == 1)
+                    backtrackPatternCharacterOnce(opIndex);
+                else
+                    backtrackPatternCharacterFixed(opIndex);
+                break;
+            case QuantifierGreedy:
+                backtrackPatternCharacterGreedy(opIndex);
+                break;
+            case QuantifierNonGreedy:
+                backtrackPatternCharacterNonGreedy(opIndex);
+                break;
+            }
+            break;
+
+        case PatternTerm::TypeCharacterClass:
+            switch (term->quantityType) {
+            case QuantifierFixedCount:
+                if (term->quantityCount == 1)
+                    backtrackCharacterClassOnce(opIndex);
+                else
+                    backtrackCharacterClassFixed(opIndex);
+                break;
+            case QuantifierGreedy:
+                backtrackCharacterClassGreedy(opIndex);
+                break;
+            case QuantifierNonGreedy:
+                backtrackCharacterClassNonGreedy(opIndex);
+                break;
+            }
+            break;
+
+        case PatternTerm::TypeAssertionBOL:
+            backtrackAssertionBOL(opIndex);
+            break;
+
+        case PatternTerm::TypeAssertionEOL:
+            backtrackAssertionEOL(opIndex);
+            break;
+
+        case PatternTerm::TypeAssertionWordBoundary:
+            backtrackAssertionWordBoundary(opIndex);
+            break;
+
+        case PatternTerm::TypeForwardReference:
+            break;
+
+        case PatternTerm::TypeParenthesesSubpattern:
+        case PatternTerm::TypeParentheticalAssertion:
+            ASSERT_NOT_REACHED();
+        case PatternTerm::TypeBackReference:
+            m_shouldFallBack = true;
+            break;
+        }
+    }
+
+    void generate()
+    {
+        // Forwards generate the matching code.
+        ASSERT(m_ops.size());
+        size_t opIndex = 0;
+
+        do {
+            YarrOp& op = m_ops[opIndex];
+            switch (op.m_op) {
+
+            case OpTerm:
+                generateTerm(opIndex);
+                break;
+
+            // OpBodyAlternativeBegin/Next/End
+            //
+            // These nodes wrap the set of alternatives in the body of the regular expression.
+            // There may be either one or two chains of OpBodyAlternative nodes, one representing
+            // the 'once through' sequence of alternatives (if any exist), and one representing
+            // the repeating alternatives (again, if any exist).
+            //
+            // Upon normal entry to the Begin alternative, we will check that input is available.
+            // Reentry to the Begin alternative will take place after the check has taken place,
+            // and will assume that the input position has already been progressed as appropriate.
+            //
+            // Entry to subsequent Next/End alternatives occurs when the prior alternative has
+            // successfully completed a match - return a success state from JIT code.
+            //
+            // Next alternatives allow for reentry optimized to suit backtracking from its
+            // preceding alternative. It expects the input position to still be set to a position
+            // appropriate to its predecessor, and it will only perform an input check if the
+            // predecessor had a minimum size less than its own.
+            //
+            // In the case 'once through' expressions, the End node will also have a reentry
+            // point to jump to when the last alternative fails. Again, this expects the input
+            // position to still reflect that expected by the prior alternative.
+            case OpBodyAlternativeBegin: {
+                PatternAlternative* alternative = op.m_alternative;
+
+                // Upon entry at the head of the set of alternatives, check if input is available
+                // to run the first alternative. (This progresses the input position).
+                op.m_jumps.append(jumpIfNoAvailableInput(alternative->m_minimumSize));
+                // We will reenter after the check, and assume the input position to have been
+                // set as appropriate to this alternative.
+                op.m_reentry = label();
+
+                m_checked += alternative->m_minimumSize;
+                break;
+            }
+            case OpBodyAlternativeNext:
+            case OpBodyAlternativeEnd: {
+                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+                PatternAlternative* alternative = op.m_alternative;
+
+                // If we get here, the prior alternative matched - return success.
+                
+                // Adjust the stack pointer to remove the pattern's frame.
+                if (m_pattern.m_body->m_callFrameSize)
+                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+
+                // Load appropriate values into the return register and the first output
+                // slot, and return. In the case of pattern with a fixed size, we will
+                // not have yet set the value in the first 
+                ASSERT(index != returnRegister);
+                if (m_pattern.m_body->m_hasFixedSize) {
+                    move(index, returnRegister);
+                    if (priorAlternative->m_minimumSize)
+                        sub32(Imm32(priorAlternative->m_minimumSize), returnRegister);
+                    store32(returnRegister, output);
+                } else
+                    load32(Address(output), returnRegister);
+                store32(index, Address(output, 4));
+                generateReturn();
+
+                // This is the divide between the tail of the prior alternative, above, and
+                // the head of the subsequent alternative, below.
+
+                if (op.m_op == OpBodyAlternativeNext) {
+                    // This is the reentry point for the Next alternative. We expect any code
+                    // that jumps here to do so with the input position matching that of the
+                    // PRIOR alteranative, and we will only check input availability if we
+                    // need to progress it forwards.
+                    op.m_reentry = label();
+                    if (int delta = alternative->m_minimumSize - priorAlternative->m_minimumSize) {
+                        add32(Imm32(delta), index);
+                        if (delta > 0)
+                            op.m_jumps.append(jumpIfNoAvailableInput());
+                    }
+                } else if (op.m_nextOp == notFound) {
+                    // This is the reentry point for the End of 'once through' alternatives,
+                    // jumped to when the las alternative fails to match.
+                    op.m_reentry = label();
+                    sub32(Imm32(priorAlternative->m_minimumSize), index);
+                }
+
+                if (op.m_op == OpBodyAlternativeNext)
+                    m_checked += alternative->m_minimumSize;
+                m_checked -= priorAlternative->m_minimumSize;
+                break;
+            }
+
+            // OpSimpleNestedAlternativeBegin/Next/End
+            // OpNestedAlternativeBegin/Next/End
+            //
+            // These nodes are used to handle sets of alternatives that are nested within
+            // subpatterns and parenthetical assertions. The 'simple' forms are used where
+            // we do not need to be able to backtrack back into any alternative other than
+            // the last, the normal forms allow backtracking into any alternative.
+            //
+            // Each Begin/Next node is responsible for planting an input check to ensure
+            // sufficient input is available on entry. Next nodes additionally need to
+            // jump to the end - Next nodes use the End node's m_jumps list to hold this
+            // set of jumps.
+            //
+            // In the non-simple forms, successful alternative matches must store a
+            // 'return address' using a DataLabelPtr, used to store the address to jump
+            // to when backtracking, to get to the code for the appropriate alternative.
+            case OpSimpleNestedAlternativeBegin:
+            case OpNestedAlternativeBegin: {
+                PatternTerm* term = op.m_term;
+                PatternAlternative* alternative = op.m_alternative;
+                PatternDisjunction* disjunction = term->parentheses.disjunction;
+
+                // Calculate how much input we need to check for, and if non-zero check.
+                op.m_checkAdjust = alternative->m_minimumSize;
+                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
+                    op.m_checkAdjust -= disjunction->m_minimumSize;
+                if (op.m_checkAdjust)
+                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
+ 
+                m_checked += op.m_checkAdjust;
+                break;
+            }
+            case OpSimpleNestedAlternativeNext:
+            case OpNestedAlternativeNext: {
+                PatternTerm* term = op.m_term;
+                PatternAlternative* alternative = op.m_alternative;
+                PatternDisjunction* disjunction = term->parentheses.disjunction;
+
+                // In the non-simple case, store a 'return address' so we can backtrack correctly.
+                if (op.m_op == OpNestedAlternativeNext) {
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
+                    if (term->quantityType != QuantifierFixedCount)
+                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
+                }
+
+                // If we reach here then the last alternative has matched - jump to the
+                // End node, to skip over any further alternatives.
+                //
+                // FIXME: this is logically O(N^2) (though N can be expected to be very
+                // small). We could avoid this either by adding an extra jump to the JIT
+                // data structures, or by making backtracking code that jumps to Next
+                // alternatives are responsible for checking that input is available (if
+                // we didn't need to plant the input checks, then m_jumps would be free).
+                YarrOp* endOp = &m_ops[op.m_nextOp];
+                while (endOp->m_nextOp != notFound) {
+                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
+                    endOp = &m_ops[endOp->m_nextOp];
+                }
+                ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
+                endOp->m_jumps.append(jump());
+
+                // This is the entry point for the next alternative.
+                op.m_reentry = label();
+
+                // Calculate how much input we need to check for, and if non-zero check.
+                op.m_checkAdjust = alternative->m_minimumSize;
+                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
+                    op.m_checkAdjust -= disjunction->m_minimumSize;
+                if (op.m_checkAdjust)
+                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked -= lastOp.m_checkAdjust;
+                m_checked += op.m_checkAdjust;
+                break;
+            }
+            case OpSimpleNestedAlternativeEnd:
+            case OpNestedAlternativeEnd: {
+                PatternTerm* term = op.m_term;
+
+                // In the non-simple case, store a 'return address' so we can backtrack correctly.
+                if (op.m_op == OpNestedAlternativeEnd) {
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
+                    if (term->quantityType != QuantifierFixedCount)
+                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
+                }
+
+                // If this set of alternatives contains more than one alternative,
+                // then the Next nodes will have planted jumps to the End, and added
+                // them to this node's m_jumps list.
+                op.m_jumps.link(this);
+                op.m_jumps.clear();
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked -= lastOp.m_checkAdjust;
+                break;
+            }
+
+            // OpParenthesesSubpatternOnceBegin/End
+            //
+            // These nodes support (optionally) capturing subpatterns, that have a
+            // quantity count of 1 (this covers fixed once, and ?/?? quantifiers). 
+            case OpParenthesesSubpatternOnceBegin: {
+                PatternTerm* term = op.m_term;
+                unsigned parenthesesFrameLocation = term->frameLocation;
+                const RegisterID indexTemporary = regT0;
+                ASSERT(term->quantityCount == 1);
+
+                // Upon entry to a Greedy quantified set of parenthese store the index.
+                // We'll use this for two purposes:
+                //  - To indicate which iteration we are on of mathing the remainder of
+                //    the expression after the parentheses - the first, including the
+                //    match within the parentheses, or the second having skipped over them.
+                //  - To check for empty matches, which must be rejected.
+                //
+                // At the head of a NonGreedy set of parentheses we'll immediately set the
+                // value on the stack to -1 (indicating a match skipping the subpattern),
+                // and plant a jump to the end. We'll also plant a label to backtrack to
+                // to reenter the subpattern later, with a store to set up index on the
+                // second iteration.
+                //
+                // FIXME: for capturing parens, could use the index in the capture array?
+                if (term->quantityType == QuantifierGreedy)
+                    storeToFrame(index, parenthesesFrameLocation);
+                else if (term->quantityType == QuantifierNonGreedy) {
+                    storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
+                    op.m_jumps.append(jump());
+                    op.m_reentry = label();
+                    storeToFrame(index, parenthesesFrameLocation);
+                }
+
+                // If the parenthese are capturing, store the starting index value to the
+                // captures array, offsetting as necessary.
+                //
+                // FIXME: could avoid offsetting this value in JIT code, apply
+                // offsets only afterwards, at the point the results array is
+                // being accessed.
+                if (term->capture()) {
+                    int offsetId = term->parentheses.subpatternId << 1;
+                    int inputOffset = term->inputPosition - m_checked;
+                    if (term->quantityType == QuantifierFixedCount)
+                        inputOffset -= term->parentheses.disjunction->m_minimumSize;
+                    if (inputOffset) {
+                        move(index, indexTemporary);
+                        add32(Imm32(inputOffset), indexTemporary);
+                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
+                    } else
+                        store32(index, Address(output, offsetId * sizeof(int)));
+                }
+                break;
+            }
+            case OpParenthesesSubpatternOnceEnd: {
+                PatternTerm* term = op.m_term;
+                unsigned parenthesesFrameLocation = term->frameLocation;
+                const RegisterID indexTemporary = regT0;
+                ASSERT(term->quantityCount == 1);
+
+                // For Greedy/NonGreedy quantified parentheses, we must reject zero length
+                // matches. If the minimum size is know to be non-zero we need not check.
+                if (term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize)
+                    op.m_jumps.append(branch32(Equal, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*))));
+
+                // If the parenthese are capturing, store the ending index value to the
+                // captures array, offsetting as necessary.
+                //
+                // FIXME: could avoid offsetting this value in JIT code, apply
+                // offsets only afterwards, at the point the results array is
+                // being accessed.
+                if (term->capture()) {
+                    int offsetId = (term->parentheses.subpatternId << 1) + 1;
+                    int inputOffset = term->inputPosition - m_checked;
+                    if (inputOffset) {
+                        move(index, indexTemporary);
+                        add32(Imm32(inputOffset), indexTemporary);
+                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
+                    } else
+                        store32(index, Address(output, offsetId * sizeof(int)));
+                }
+
+                // If the parentheses are quantified Greedy then add a label to jump back
+                // to if get a failed match from after the parentheses. For NonGreedy
+                // parentheses, link the jump from before the subpattern to here.
+                if (term->quantityType == QuantifierGreedy)
+                    op.m_reentry = label();
+                else if (term->quantityType == QuantifierNonGreedy) {
+                    YarrOp& beginOp = m_ops[op.m_previousOp];
+                    beginOp.m_jumps.link(this);
+                }
+                break;
+            }
+
+            // OpParenthesesSubpatternTerminalBegin/End
+            case OpParenthesesSubpatternTerminalBegin: {
+                PatternTerm* term = op.m_term;
+                ASSERT(term->quantityType == QuantifierGreedy);
+                ASSERT(term->quantityCount == quantifyInfinite);
+                ASSERT(!term->capture());
+
+                // Upon entry set a label to loop back to.
+                op.m_reentry = label();
+
+                // Store the start index of the current match; we need to reject zero
+                // length matches.
+                storeToFrame(index, term->frameLocation);
+                break;
+            }
+            case OpParenthesesSubpatternTerminalEnd: {
+                PatternTerm* term = op.m_term;
+
+                // Check for zero length matches - if the match is non-zero, then we
+                // can accept it & loop back up to the head of the subpattern.
+                YarrOp& beginOp = m_ops[op.m_previousOp];
+                branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*)), beginOp.m_reentry);
+
+                // Reject the match - backtrack back into the subpattern.
+                op.m_jumps.append(jump());
+
+                // This is the entry point to jump to when we stop matching - we will
+                // do so once the subpattern cannot match any more.
+                op.m_reentry = label();
+                break;
+            }
+
+            // OpParentheticalAssertionBegin/End
+            case OpParentheticalAssertionBegin: {
+                PatternTerm* term = op.m_term;
+
+                // Store the current index - assertions should not update index, so
+                // we will need to restore it upon a successful match.
+                unsigned parenthesesFrameLocation = term->frameLocation;
+                storeToFrame(index, parenthesesFrameLocation);
+
+                // Check 
+                op.m_checkAdjust = m_checked - term->inputPosition;
+                if (op.m_checkAdjust)
+                    sub32(Imm32(op.m_checkAdjust), index);
+
+                m_checked -= op.m_checkAdjust;
+                break;
+            }
+            case OpParentheticalAssertionEnd: {
+                PatternTerm* term = op.m_term;
+
+                // Restore the input index value.
+                unsigned parenthesesFrameLocation = term->frameLocation;
+                loadFromFrame(parenthesesFrameLocation, index);
+
+                // If inverted, a successful match of the assertion must be treated
+                // as a failure, so jump to backtracking.
+                if (term->invert()) {
+                    op.m_jumps.append(jump());
+                    op.m_reentry = label();
+                }
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked += lastOp.m_checkAdjust;
+                break;
+            }
+
+            case OpMatchFailed:
+                if (m_pattern.m_body->m_callFrameSize)
+                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+                move(TrustedImm32(-1), returnRegister);
+                generateReturn();
+                break;
+            }
+
+            ++opIndex;
+        } while (opIndex < m_ops.size());
+    }
+
+    void backtrack()
+    {
+        // Backwards generate the backtracking code.
+        size_t opIndex = m_ops.size();
+        ASSERT(opIndex);
+
+        do {
+            --opIndex;
+            YarrOp& op = m_ops[opIndex];
+            switch (op.m_op) {
+
+            case OpTerm:
+                backtrackTerm(opIndex);
+                break;
+
+            // OpBodyAlternativeBegin/Next/End
+            //
+            // For each Begin/Next node representing an alternative, we need to decide what to do
+            // in two circumstances:
+            //  - If we backtrack back into this node, from within the alternative.
+            //  - If the input check at the head of the alternative fails (if this exists).
+            //
+            // We treat these two cases differently since in the former case we have slightly
+            // more information - since we are backtracking out of a prior alternative we know
+            // that at least enough input was available to run it. For example, given the regular
+            // expression /a|b/, if we backtrack out of the first alternative (a failed pattern
+            // character match of 'a'), then we need not perform an additional input availability
+            // check before running the second alternative.
+            //
+            // Backtracking required differs for the last alternative, which in the case of the
+            // repeating set of alternatives must loop. The code generated for the last alternative
+            // will also be used to handle all input check failures from any prior alternatives -
+            // these require similar functionality, in seeking the next available alternative for
+            // which there is sufficient input.
+            //
+            // Since backtracking of all other alternatives simply requires us to link backtracks
+            // to the reentry point for the subsequent alternative, we will only be generating any
+            // code when backtracking the last alternative.
+            case OpBodyAlternativeBegin:
+            case OpBodyAlternativeNext: {
+                PatternAlternative* alternative = op.m_alternative;
+
+                if (op.m_op == OpBodyAlternativeNext) {
+                    PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+                    m_checked += priorAlternative->m_minimumSize;
+                }
+                m_checked -= alternative->m_minimumSize;
+
+                // Is this the last alternative? If not, then if we backtrack to this point we just
+                // need to jump to try to match the next alternative.
+                if (m_ops[op.m_nextOp].m_op != OpBodyAlternativeEnd) {
+                    m_backtrackingState.linkTo(m_ops[op.m_nextOp].m_reentry, this);
+                    break;
+                }
+                YarrOp& endOp = m_ops[op.m_nextOp];
+
+                YarrOp* beginOp = &op;
+                while (beginOp->m_op != OpBodyAlternativeBegin) {
+                    ASSERT(beginOp->m_op == OpBodyAlternativeNext);
+                    beginOp = &m_ops[beginOp->m_previousOp];
+                }
+
+                bool onceThrough = endOp.m_nextOp == notFound;
+
+                // First, generate code to handle cases where we backtrack out of an attempted match
+                // of the last alternative. If this is a 'once through' set of alternatives then we
+                // have nothing to do - link this straight through to the End.
+                if (onceThrough)
+                    m_backtrackingState.linkTo(endOp.m_reentry, this);
+                else {
+                    // Okay, we're going to need to loop. Calculate the delta between where the input
+                    // position was, and where we want it to be allowing for the fact that we need to
+                    // increment by 1. E.g. for the regexp /a|x/ we need to increment the position by
+                    // 1 between loop iterations, but for /abcd|xyz/ we need to increment by two when
+                    // looping from the last alternative to the first, for /a|xyz/ we need to decrement
+                    // by 1, and for /a|xy/ we don't need to move the input position at all.
+                    int deltaLastAlternativeToFirstAlternativePlusOne = (beginOp->m_alternative->m_minimumSize - alternative->m_minimumSize) + 1;
+
+                    // If we don't need to move the input poistion, and the pattern has a fixed size
+                    // (in which case we omit the store of the start index until the pattern has matched)
+                    // then we can just link the backtrack out of the last alternative straight to the
+                    // head of the first alternative.
+                    if (!deltaLastAlternativeToFirstAlternativePlusOne && m_pattern.m_body->m_hasFixedSize)
+                        m_backtrackingState.linkTo(beginOp->m_reentry, this);
+                    else {
+                        // We need to generate a trampoline of code to execute before looping back
+                        // around to the first alternative.
+                        m_backtrackingState.link(this);
+
+                        // If the pattern size is not fixed, then store the start index, for use if we match.
+                        if (!m_pattern.m_body->m_hasFixedSize) {
+                            if (alternative->m_minimumSize == 1)
+                                store32(index, Address(output));
+                            else {
+                                move(index, regT0);
+                                if (alternative->m_minimumSize)
+                                    sub32(Imm32(alternative->m_minimumSize - 1), regT0);
+                                else
+                                    add32(Imm32(1), regT0);
+                                store32(regT0, Address(output));
+                            }
+                        }
+
+                        if (deltaLastAlternativeToFirstAlternativePlusOne)
+                            add32(Imm32(deltaLastAlternativeToFirstAlternativePlusOne), index);
+
+                        // Loop. Since this code is only reached when we backtrack out of the last
+                        // alternative (and NOT linked to from the input check upon entry to the
+                        // last alternative) we know that there must be at least enough input as
+                        // required by the last alternative. As such, we only need to check if the
+                        // first will require more to run - if the same or less is required we can
+                        // unconditionally jump.
+                        if (deltaLastAlternativeToFirstAlternativePlusOne > 0)
+                            checkInput().linkTo(beginOp->m_reentry, this);
+                        else
+                            jump(beginOp->m_reentry);
+                    }
+                }
+
+                // We can reach this point in the code in two ways:
+                //  - Fallthrough from the code above (a repeating alternative backtracked out of its
+                //    last alternative, and did not have sufficent input to run the first).
+                //  - We will loop back up to the following label when a releating alternative loops,
+                //    following a failed input check.
+                //
+                // Either way, we have just failed the input check for the first alternative.
+                Label firstInputCheckFailed(this);
+
+                // Generate code to handle input check failures from alternatives except the last.
+                // prevOp is the alternative we're handling a bail out from (initially Begin), and
+                // nextOp is the alternative we will be attempting to reenter into.
+                // 
+                // We will link input check failures from the forwards matching path back to the code
+                // that can handle them.
+                YarrOp* prevOp = beginOp;
+                YarrOp* nextOp = &m_ops[beginOp->m_nextOp];
+                while (nextOp->m_op != OpBodyAlternativeEnd) {
+                    prevOp->m_jumps.link(this);
+
+                    int delta = nextOp->m_alternative->m_minimumSize - prevOp->m_alternative->m_minimumSize;
+                    if (delta)
+                        add32(Imm32(delta), index);
+
+                    // We only get here if an input check fails, it is only worth checking again
+                    // if the next alternative has a minimum size less than the last.
+                    if (delta < 0) {
+                        // FIXME: if we added an extra label to YarrOp, we could avoid needing to
+                        // subtract delta back out, and reduce this code. Should performance test
+                        // the benefit of this.
+                        Jump fail = jumpIfNoAvailableInput();
+                        sub32(Imm32(delta), index);
+                        jump(nextOp->m_reentry);
+                        fail.link(this);
+                    }
+                    prevOp = nextOp;
+                    nextOp = &m_ops[nextOp->m_nextOp];
+                }
+
+                // We fall through to here if there is insufficient input to run the last alternative.
+
+                // If there is insufficient input to run the last alternative, then for 'once through'
+                // alternatives we are done - just jump back up into the forwards matching path at the End.
+                if (onceThrough) {
+                    op.m_jumps.linkTo(endOp.m_reentry, this);
+                    jump(endOp.m_reentry);
+                    break;
+                }
+
+                // For repeating alternatives, link any input check failure from the last alternative to
+                // this point.
+                op.m_jumps.link(this);
+
+                bool needsToUpdateMatchStart = !m_pattern.m_body->m_hasFixedSize;
+
+                // Check for cases where input position is already incremented by 1 for the last
+                // alternative (this is particularly useful where the minimum size of the body
+                // disjunction is 0, e.g. /a*|b/).
+                if (needsToUpdateMatchStart && alternative->m_minimumSize == 1) {
+                    // index is already incremented by 1, so just store it now!
+                    store32(index, Address(output));
+                    needsToUpdateMatchStart = false;
+                }
+
+                // Check whether there is sufficient input to loop. Increment the input position by
+                // one, and check. Also add in the minimum disjunction size before checking - there
+                // is no point in looping if we're just going to fail all the input checks around
+                // the next iteration.
+                int deltaLastAlternativeToBodyMinimumPlusOne = (m_pattern.m_body->m_minimumSize + 1) - alternative->m_minimumSize;
+                if (deltaLastAlternativeToBodyMinimumPlusOne)
+                    add32(Imm32(deltaLastAlternativeToBodyMinimumPlusOne), index);
+                Jump matchFailed = jumpIfNoAvailableInput();
+
+                if (needsToUpdateMatchStart) {
+                    if (!m_pattern.m_body->m_minimumSize)
+                        store32(index, Address(output));
+                    else {
+                        move(index, regT0);
+                        sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0);
+                        store32(regT0, Address(output));
+                    }
+                }
+
+                // Calculate how much more input the first alternative requires than the minimum
+                // for the body as a whole. If no more is needed then we dont need an additional
+                // input check here - jump straight back up to the start of the first alternative.
+                int deltaBodyMinimumToFirstAlternative = beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize;
+                if (!deltaBodyMinimumToFirstAlternative)
+                    jump(beginOp->m_reentry);
+                else {
+                    add32(Imm32(deltaBodyMinimumToFirstAlternative), index);
+                    checkInput().linkTo(beginOp->m_reentry, this);
+                    jump(firstInputCheckFailed);
+                }
+
+                // We jump to here if we iterate to the point that there is insufficient input to
+                // run any matches, and need to return a failure state from JIT code.
+                matchFailed.link(this);
+
+                if (m_pattern.m_body->m_callFrameSize)
+                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+                move(TrustedImm32(-1), returnRegister);
+                generateReturn();
+                break;
+            }
+            case OpBodyAlternativeEnd: {
+                // We should never backtrack back into a body disjunction.
+                ASSERT(m_backtrackingState.isEmpty());
+
+                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
+                m_checked += priorAlternative->m_minimumSize;
+                break;
+            }
+
+            // OpSimpleNestedAlternativeBegin/Next/End
+            // OpNestedAlternativeBegin/Next/End
+            //
+            // Generate code for when we backtrack back out of an alternative into
+            // a Begin or Next node, or when the entry input count check fails. If
+            // there are more alternatives we need to jump to the next alternative,
+            // if not we backtrack back out of the current set of parentheses.
+            //
+            // In the case of non-simple nested assertions we need to also link the
+            // 'return address' appropriately to backtrack back out into the correct
+            // alternative.
+            case OpSimpleNestedAlternativeBegin:
+            case OpSimpleNestedAlternativeNext:
+            case OpNestedAlternativeBegin:
+            case OpNestedAlternativeNext: {
+                YarrOp& nextOp = m_ops[op.m_nextOp];
+                bool isBegin = op.m_previousOp == notFound;
+                bool isLastAlternative = nextOp.m_nextOp == notFound;
+                ASSERT(isBegin == (op.m_op == OpSimpleNestedAlternativeBegin || op.m_op == OpNestedAlternativeBegin));
+                ASSERT(isLastAlternative == (nextOp.m_op == OpSimpleNestedAlternativeEnd || nextOp.m_op == OpNestedAlternativeEnd));
+
+                // Treat an input check failure the same as a failed match.
+                m_backtrackingState.append(op.m_jumps);
+
+                // Set the backtracks to jump to the appropriate place. We may need
+                // to link the backtracks in one of three different way depending on
+                // the type of alternative we are dealing with:
+                //  - A single alternative, with no simplings.
+                //  - The last alternative of a set of two or more.
+                //  - An alternative other than the last of a set of two or more.
+                //
+                // In the case of a single alternative on its own, we don't need to
+                // jump anywhere - if the alternative fails to match we can just
+                // continue to backtrack out of the parentheses without jumping.
+                //
+                // In the case of the last alternative in a set of more than one, we
+                // need to jump to return back out to the beginning. We'll do so by
+                // adding a jump to the End node's m_jumps list, and linking this
+                // when we come to generate the Begin node. For alternatives other
+                // than the last, we need to jump to the next alternative.
+                //
+                // If the alternative had adjusted the input position we must link
+                // backtracking to here, correct, and then jump on. If not we can
+                // link the backtracks directly to their destination.
+                if (op.m_checkAdjust) {
+                    // Handle the cases where we need to link the backtracks here.
+                    m_backtrackingState.link(this);
+                    sub32(Imm32(op.m_checkAdjust), index);
+                    if (!isLastAlternative) {
+                        // An alternative that is not the last should jump to its successor.
+                        jump(nextOp.m_reentry);
+                    } else if (!isBegin) {
+                        // The last of more than one alternatives must jump back to the begnning.
+                        nextOp.m_jumps.append(jump());
+                    } else {
+                        // A single alternative on its own can fall through.
+                        m_backtrackingState.fallthrough();
+                    }
+                } else {
+                    // Handle the cases where we can link the backtracks directly to their destinations.
+                    if (!isLastAlternative) {
+                        // An alternative that is not the last should jump to its successor.
+                        m_backtrackingState.linkTo(nextOp.m_reentry, this);
+                    } else if (!isBegin) {
+                        // The last of more than one alternatives must jump back to the begnning.
+                        m_backtrackingState.takeBacktracksToJumpList(nextOp.m_jumps, this);
+                    }
+                    // In the case of a single alternative on its own do nothing - it can fall through.
+                }
+
+                // At this point we've handled the backtracking back into this node.
+                // Now link any backtracks that need to jump to here.
+
+                // For non-simple alternatives, link the alternative's 'return address'
+                // so that we backtrack back out into the previous alternative.
+                if (op.m_op == OpNestedAlternativeNext)
+                    m_backtrackingState.append(op.m_returnAddress);
+
+                // If there is more than one alternative, then the last alternative will
+                // have planted a jump to be linked to the end. This jump was added to the
+                // End node's m_jumps list. If we are back at the beginning, link it here.
+                if (isBegin) {
+                    YarrOp* endOp = &m_ops[op.m_nextOp];
+                    while (endOp->m_nextOp != notFound) {
+                        ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
+                        endOp = &m_ops[endOp->m_nextOp];
+                    }
+                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
+                    m_backtrackingState.append(endOp->m_jumps);
+                }
+
+                if (!isBegin) {
+                    YarrOp& lastOp = m_ops[op.m_previousOp];
+                    m_checked += lastOp.m_checkAdjust;
+                }
+                m_checked -= op.m_checkAdjust;
+                break;
+            }
+            case OpSimpleNestedAlternativeEnd:
+            case OpNestedAlternativeEnd: {
+                PatternTerm* term = op.m_term;
+
+                // If we backtrack into the end of a simple subpattern do nothing;
+                // just continue through into the last alternative. If we backtrack
+                // into the end of a non-simple set of alterntives we need to jump
+                // to the backtracking return address set up during generation.
+                if (op.m_op == OpNestedAlternativeEnd) {
+                    m_backtrackingState.link(this);
+
+                    // Plant a jump to the return address.
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
+                    if (term->quantityType != QuantifierFixedCount)
+                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
+                    loadFromFrameAndJump(alternativeFrameLocation);
+
+                    // Link the DataLabelPtr associated with the end of the last
+                    // alternative to this point.
+                    m_backtrackingState.append(op.m_returnAddress);
+                }
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked += lastOp.m_checkAdjust;
+                break;
+            }
+
+            // OpParenthesesSubpatternOnceBegin/End
+            //
+            // When we are backtracking back out of a capturing subpattern we need
+            // to clear the start index in the matches output array, to record that
+            // this subpattern has not been captured.
+            //
+            // When backtracking back out of a Greedy quantified subpattern we need
+            // to catch this, and try running the remainder of the alternative after
+            // the subpattern again, skipping the parentheses.
+            //
+            // Upon backtracking back into a quantified set of parentheses we need to
+            // check whether we were currently skipping the subpattern. If not, we
+            // can backtrack into them, if we were we need to either backtrack back
+            // out of the start of the parentheses, or jump back to the forwards
+            // matching start, depending of whether the match is Greedy or NonGreedy.
+            case OpParenthesesSubpatternOnceBegin: {
+                PatternTerm* term = op.m_term;
+                ASSERT(term->quantityCount == 1);
+
+                // We only need to backtrack to thispoint if capturing or greedy.
+                if (term->capture() || term->quantityType == QuantifierGreedy) {
+                    m_backtrackingState.link(this);
+
+                    // If capturing, clear the capture (we only need to reset start).
+                    if (term->capture())
+                        store32(TrustedImm32(-1), Address(output, (term->parentheses.subpatternId << 1) * sizeof(int)));
+
+                    // If Greedy, jump to the end.
+                    if (term->quantityType == QuantifierGreedy) {
+                        // Clear the flag in the stackframe indicating we ran through the subpattern.
+                        unsigned parenthesesFrameLocation = term->frameLocation;
+                        storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
+                        // Jump to after the parentheses, skipping the subpattern.
+                        jump(m_ops[op.m_nextOp].m_reentry);
+                        // A backtrack from after the parentheses, when skipping the subpattern,
+                        // will jump back to here.
+                        op.m_jumps.link(this);
+                    }
+
+                    m_backtrackingState.fallthrough();
+                }
+                break;
+            }
+            case OpParenthesesSubpatternOnceEnd: {
+                PatternTerm* term = op.m_term;
+
+                if (term->quantityType != QuantifierFixedCount) {
+                    m_backtrackingState.link(this);
+
+                    // Check whether we should backtrack back into the parentheses, or if we
+                    // are currently in a state where we had skipped over the subpattern
+                    // (in which case the flag value on the stack will be -1).
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1));
+
+                    if (term->quantityType == QuantifierGreedy) {
+                        // For Greedy parentheses, we skip after having already tried going
+                        // through the subpattern, so if we get here we're done.
+                        YarrOp& beginOp = m_ops[op.m_previousOp];
+                        beginOp.m_jumps.append(hadSkipped);
+                    } else {
+                        // For NonGreedy parentheses, we try skipping the subpattern first,
+                        // so if we get here we need to try running through the subpattern
+                        // next. Jump back to the start of the parentheses in the forwards
+                        // matching path.
+                        ASSERT(term->quantityType == QuantifierNonGreedy);
+                        YarrOp& beginOp = m_ops[op.m_previousOp];
+                        hadSkipped.linkTo(beginOp.m_reentry, this);
+                    }
+
+                    m_backtrackingState.fallthrough();
+                }
+
+                m_backtrackingState.append(op.m_jumps);
+                break;
+            }
+
+            // OpParenthesesSubpatternTerminalBegin/End
+            //
+            // Terminal subpatterns will always match - there is nothing after them to
+            // force a backtrack, and they have a minimum count of 0, and as such will
+            // always produce an acceptable result.
+            case OpParenthesesSubpatternTerminalBegin: {
+                // We will backtrack to this point once the subpattern cannot match any
+                // more. Since no match is accepted as a successful match (we are Greedy
+                // quantified with a minimum of zero) jump back to the forwards matching
+                // path at the end.
+                YarrOp& endOp = m_ops[op.m_nextOp];
+                m_backtrackingState.linkTo(endOp.m_reentry, this);
+                break;
+            }
+            case OpParenthesesSubpatternTerminalEnd:
+                // We should never be backtracking to here (hence the 'terminal' in the name).
+                ASSERT(m_backtrackingState.isEmpty());
+                m_backtrackingState.append(op.m_jumps);
+                break;
+
+            // OpParentheticalAssertionBegin/End
+            case OpParentheticalAssertionBegin: {
+                PatternTerm* term = op.m_term;
+                YarrOp& endOp = m_ops[op.m_nextOp];
+
+                // We need to handle the backtracks upon backtracking back out
+                // of a parenthetical assertion if either we need to correct
+                // the input index, or the assertion was inverted.
+                if (op.m_checkAdjust || term->invert()) {
+                     m_backtrackingState.link(this);
+
+                    if (op.m_checkAdjust)
+                        add32(Imm32(op.m_checkAdjust), index);
+
+                    // In an inverted assertion failure to match the subpattern
+                    // is treated as a successful match - jump to the end of the
+                    // subpattern. We already have adjusted the input position
+                    // back to that before the assertion, which is correct.
+                    if (term->invert())
+                        jump(endOp.m_reentry);
+
+                    m_backtrackingState.fallthrough();
+                }
+
+                // The End node's jump list will contain any backtracks into
+                // the end of the assertion. Also, if inverted, we will have
+                // added the failure caused by a successful match to this.
+                m_backtrackingState.append(endOp.m_jumps);
+
+                m_checked += op.m_checkAdjust;
+                break;
+            }
+            case OpParentheticalAssertionEnd: {
+                // FIXME: We should really be clearing any nested subpattern
+                // matches on bailing out from after the pattern. Firefox has
+                // this bug too (presumably because they use YARR!)
+
+                // Never backtrack into an assertion; later failures bail to before the begin.
+                m_backtrackingState.takeBacktracksToJumpList(op.m_jumps, this);
+
+                YarrOp& lastOp = m_ops[op.m_previousOp];
+                m_checked -= lastOp.m_checkAdjust;
+                break;
+            }
+
+            case OpMatchFailed:
+                break;
+            }
+
+        } while (opIndex);
+    }
+
+    // Compilation methods:
+    // ====================
+
+    // opCompileParenthesesSubpattern
+    // Emits ops for a subpattern (set of parentheses). These consist
+    // of a set of alternatives wrapped in an outer set of nodes for
+    // the parentheses.
+    // Supported types of parentheses are 'Once' (quantityCount == 1)
+    // and 'Terminal' (non-capturing parentheses quantified as greedy
+    // and infinite).
+    // Alternatives will use the 'Simple' set of ops if either the
+    // subpattern is terminal (in which case we will never need to
+    // backtrack), or if the subpattern only contains one alternative.
+    void opCompileParenthesesSubpattern(PatternTerm* term)
+    {
+        YarrOpCode parenthesesBeginOpCode;
+        YarrOpCode parenthesesEndOpCode;
+        YarrOpCode alternativeBeginOpCode = OpSimpleNestedAlternativeBegin;
+        YarrOpCode alternativeNextOpCode = OpSimpleNestedAlternativeNext;
+        YarrOpCode alternativeEndOpCode = OpSimpleNestedAlternativeEnd;
+
+        // We can currently only compile quantity 1 subpatterns that are
+        // not copies. We generate a copy in the case of a range quantifier,
+        // e.g. /(?:x){3,9}/, or /(?:x)+/ (These are effectively expanded to
+        // /(?:x){3,3}(?:x){0,6}/ and /(?:x)(?:x)*/ repectively). The problem
+        // comes where the subpattern is capturing, in which case we would
+        // need to restore the capture from the first subpattern upon a
+        // failure in the second.
+        if (term->quantityCount == 1 && !term->parentheses.isCopy) {
+            // Select the 'Once' nodes.
+            parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin;
+            parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd;
+
+            // If there is more than one alternative we cannot use the 'simple' nodes.
+            if (term->parentheses.disjunction->m_alternatives.size() != 1) {
+                alternativeBeginOpCode = OpNestedAlternativeBegin;
+                alternativeNextOpCode = OpNestedAlternativeNext;
+                alternativeEndOpCode = OpNestedAlternativeEnd;
+            }
+        } else if (term->parentheses.isTerminal) {
+            // Select the 'Terminal' nodes.
+            parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin;
+            parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd;
+        } else {
+            // This subpattern is not supported by the JIT.
+            m_shouldFallBack = true;
+            return;
+        }
+
+        size_t parenBegin = m_ops.size();
+        m_ops.append(parenthesesBeginOpCode);
+
+        m_ops.append(alternativeBeginOpCode);
+        m_ops.last().m_previousOp = notFound;
+        m_ops.last().m_term = term;
+        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
+        for (unsigned i = 0; i < alternatives.size(); ++i) {
+            size_t lastOpIndex = m_ops.size() - 1;
+
+            PatternAlternative* nestedAlternative = alternatives[i];
+            opCompileAlternative(nestedAlternative);
+
+            size_t thisOpIndex = m_ops.size();
+            m_ops.append(YarrOp(alternativeNextOpCode));
+
+            YarrOp& lastOp = m_ops[lastOpIndex];
+            YarrOp& thisOp = m_ops[thisOpIndex];
+
+            lastOp.m_alternative = nestedAlternative;
+            lastOp.m_nextOp = thisOpIndex;
+            thisOp.m_previousOp = lastOpIndex;
+            thisOp.m_term = term;
+        }
+        YarrOp& lastOp = m_ops.last();
+        ASSERT(lastOp.m_op == alternativeNextOpCode);
+        lastOp.m_op = alternativeEndOpCode;
+        lastOp.m_alternative = 0;
+        lastOp.m_nextOp = notFound;
+
+        size_t parenEnd = m_ops.size();
+        m_ops.append(parenthesesEndOpCode);
+
+        m_ops[parenBegin].m_term = term;
+        m_ops[parenBegin].m_previousOp = notFound;
+        m_ops[parenBegin].m_nextOp = parenEnd;
+        m_ops[parenEnd].m_term = term;
+        m_ops[parenEnd].m_previousOp = parenBegin;
+        m_ops[parenEnd].m_nextOp = notFound;
+    }
+
+    // opCompileParentheticalAssertion
+    // Emits ops for a parenthetical assertion. These consist of an
+    // OpSimpleNestedAlternativeBegin/Next/End set of nodes wrapping
+    // the alternatives, with these wrapped by an outer pair of
+    // OpParentheticalAssertionBegin/End nodes.
+    // We can always use the OpSimpleNestedAlternative nodes in the
+    // case of parenthetical assertions since these only ever match
+    // once, and will never backtrack back into the assertion.
+    void opCompileParentheticalAssertion(PatternTerm* term)
+    {
+        size_t parenBegin = m_ops.size();
+        m_ops.append(OpParentheticalAssertionBegin);
+
+        m_ops.append(OpSimpleNestedAlternativeBegin);
+        m_ops.last().m_previousOp = notFound;
+        m_ops.last().m_term = term;
+        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
+        for (unsigned i = 0; i < alternatives.size(); ++i) {
+            size_t lastOpIndex = m_ops.size() - 1;
+
+            PatternAlternative* nestedAlternative = alternatives[i];
+            opCompileAlternative(nestedAlternative);
+
+            size_t thisOpIndex = m_ops.size();
+            m_ops.append(YarrOp(OpSimpleNestedAlternativeNext));
+
+            YarrOp& lastOp = m_ops[lastOpIndex];
+            YarrOp& thisOp = m_ops[thisOpIndex];
+
+            lastOp.m_alternative = nestedAlternative;
+            lastOp.m_nextOp = thisOpIndex;
+            thisOp.m_previousOp = lastOpIndex;
+            thisOp.m_term = term;
+        }
+        YarrOp& lastOp = m_ops.last();
+        ASSERT(lastOp.m_op == OpSimpleNestedAlternativeNext);
+        lastOp.m_op = OpSimpleNestedAlternativeEnd;
+        lastOp.m_alternative = 0;
+        lastOp.m_nextOp = notFound;
+
+        size_t parenEnd = m_ops.size();
+        m_ops.append(OpParentheticalAssertionEnd);
+
+        m_ops[parenBegin].m_term = term;
+        m_ops[parenBegin].m_previousOp = notFound;
+        m_ops[parenBegin].m_nextOp = parenEnd;
+        m_ops[parenEnd].m_term = term;
+        m_ops[parenEnd].m_previousOp = parenBegin;
+        m_ops[parenEnd].m_nextOp = notFound;
+    }
+
+    // opCompileAlternative
+    // Called to emit nodes for all terms in an alternative.
+    void opCompileAlternative(PatternAlternative* alternative)
+    {
+        optimizeAlternative(alternative);
+
+        for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
+            PatternTerm* term = &alternative->m_terms[i];
+
+            switch (term->type) {
+            case PatternTerm::TypeParenthesesSubpattern:
+                opCompileParenthesesSubpattern(term);
+                break;
+
+            case PatternTerm::TypeParentheticalAssertion:
+                opCompileParentheticalAssertion(term);
+                break;
+
+            default:
+                m_ops.append(term);
+            }
+        }
+    }
+
+    // opCompileBody
+    // This method compiles the body disjunction of the regular expression.
+    // The body consists of two sets of alternatives - zero or more 'once
+    // through' (BOL anchored) alternatives, followed by zero or more
+    // repeated alternatives.
+    // For each of these two sets of alteratives, if not empty they will be
+    // wrapped in a set of OpBodyAlternativeBegin/Next/End nodes (with the
+    // 'begin' node referencing the first alternative, and 'next' nodes
+    // referencing any further alternatives. The begin/next/end nodes are
+    // linked together in a doubly linked list. In the case of repeating
+    // alternatives, the end node is also linked back to the beginning.
+    // If no repeating alternatives exist, then a OpMatchFailed node exists
+    // to return the failing result.
+    void opCompileBody(PatternDisjunction* disjunction)
+    {
+        Vector& alternatives =  disjunction->m_alternatives;
+        size_t currentAlternativeIndex = 0;
+
+        // Emit the 'once through' alternatives.
+        if (alternatives.size() && alternatives[0]->onceThrough()) {
+            m_ops.append(YarrOp(OpBodyAlternativeBegin));
+            m_ops.last().m_previousOp = notFound;
+
+            do {
+                size_t lastOpIndex = m_ops.size() - 1;
+                PatternAlternative* alternative = alternatives[currentAlternativeIndex];
+                opCompileAlternative(alternative);
+
+                size_t thisOpIndex = m_ops.size();
+                m_ops.append(YarrOp(OpBodyAlternativeNext));
+
+                YarrOp& lastOp = m_ops[lastOpIndex];
+                YarrOp& thisOp = m_ops[thisOpIndex];
+
+                lastOp.m_alternative = alternative;
+                lastOp.m_nextOp = thisOpIndex;
+                thisOp.m_previousOp = lastOpIndex;
+                
+                ++currentAlternativeIndex;
+            } while (currentAlternativeIndex < alternatives.size() && alternatives[currentAlternativeIndex]->onceThrough());
+
+            YarrOp& lastOp = m_ops.last();
+
+            ASSERT(lastOp.m_op == OpBodyAlternativeNext);
+            lastOp.m_op = OpBodyAlternativeEnd;
+            lastOp.m_alternative = 0;
+            lastOp.m_nextOp = notFound;
+        }
+
+        if (currentAlternativeIndex == alternatives.size()) {
+            m_ops.append(YarrOp(OpMatchFailed));
+            return;
+        }
+
+        // Emit the repeated alternatives.
+        size_t repeatLoop = m_ops.size();
+        m_ops.append(YarrOp(OpBodyAlternativeBegin));
+        m_ops.last().m_previousOp = notFound;
+        do {
+            size_t lastOpIndex = m_ops.size() - 1;
+            PatternAlternative* alternative = alternatives[currentAlternativeIndex];
+            ASSERT(!alternative->onceThrough());
+            opCompileAlternative(alternative);
+
+            size_t thisOpIndex = m_ops.size();
+            m_ops.append(YarrOp(OpBodyAlternativeNext));
+
+            YarrOp& lastOp = m_ops[lastOpIndex];
+            YarrOp& thisOp = m_ops[thisOpIndex];
+
+            lastOp.m_alternative = alternative;
+            lastOp.m_nextOp = thisOpIndex;
+            thisOp.m_previousOp = lastOpIndex;
+            
+            ++currentAlternativeIndex;
+        } while (currentAlternativeIndex < alternatives.size());
+        YarrOp& lastOp = m_ops.last();
+        ASSERT(lastOp.m_op == OpBodyAlternativeNext);
+        lastOp.m_op = OpBodyAlternativeEnd;
+        lastOp.m_alternative = 0;
+        lastOp.m_nextOp = repeatLoop;
+    }
+
+    void generateEnter()
+    {
+#if WTF_CPU_X86_64
+        push(X86Registers::ebp);
+        move(stackPointerRegister, X86Registers::ebp);
+        push(X86Registers::ebx);
+#elif WTF_CPU_X86
+        push(X86Registers::ebp);
+        move(stackPointerRegister, X86Registers::ebp);
+        // TODO: do we need spill registers to fill the output pointer if there are no sub captures?
+        push(X86Registers::ebx);
+        push(X86Registers::edi);
+        push(X86Registers::esi);
+        // load output into edi (2 = saved ebp + return address).
+    #if WTF_COMPILER_MSVC
+        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input);
+        loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index);
+        loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length);
+        loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output);
+    #else
+        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
+    #endif
+#elif WTF_CPU_ARM
+        push(ARMRegisters::r4);
+        push(ARMRegisters::r5);
+        push(ARMRegisters::r6);
+#if WTF_CPU_ARM_TRADITIONAL
+        push(ARMRegisters::r8); // scratch register
+#endif
+        move(ARMRegisters::r3, output);
+#elif WTF_CPU_SH4
+        push(SH4Registers::r11);
+        push(SH4Registers::r13);
+#elif WTF_CPU_MIPS
+        // Do nothing.
+#endif
+    }
+
+    void generateReturn()
+    {
+#if WTF_CPU_X86_64
+        pop(X86Registers::ebx);
+        pop(X86Registers::ebp);
+#elif WTF_CPU_X86
+        pop(X86Registers::esi);
+        pop(X86Registers::edi);
+        pop(X86Registers::ebx);
+        pop(X86Registers::ebp);
+#elif WTF_CPU_ARM
+#if WTF_CPU_ARM_TRADITIONAL
+        pop(ARMRegisters::r8); // scratch register
+#endif
+        pop(ARMRegisters::r6);
+        pop(ARMRegisters::r5);
+        pop(ARMRegisters::r4);
+#elif WTF_CPU_SH4
+        pop(SH4Registers::r13);
+        pop(SH4Registers::r11);
+#elif WTF_CPU_MIPS
+        // Do nothing
+#endif
+        ret();
+    }
+
+public:
+    YarrGenerator(YarrPattern& pattern)
+        : m_pattern(pattern)
+        , m_shouldFallBack(false)
+        , m_checked(0)
+    {
+    }
+
+    void compile(JSGlobalData* globalData, YarrCodeBlock& jitObject)
+    {
+        generateEnter();
+
+        if (!m_pattern.m_body->m_hasFixedSize)
+            store32(index, Address(output));
+
+        if (m_pattern.m_body->m_callFrameSize)
+            subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
+
+        // Compile the pattern to the internal 'YarrOp' representation.
+        opCompileBody(m_pattern.m_body);
+
+        // If we encountered anything we can't handle in the JIT code
+        // (e.g. backreferences) then return early.
+        if (m_shouldFallBack) {
+            jitObject.setFallBack(true);
+            return;
+        }
+
+        generate();
+        backtrack();
+
+        // Link & finalize the code.
+        // XXX yarr-oom
+        ExecutablePool *pool;
+        bool ok;
+        LinkBuffer linkBuffer(this, globalData->regexAllocator, &pool, &ok);
+        m_backtrackingState.linkDataLabels(linkBuffer);
+        jitObject.set(linkBuffer.finalizeCode());
+        jitObject.setFallBack(m_shouldFallBack);
+    }
+
+private:
+    YarrPattern& m_pattern;
+
+    // Used to detect regular expression constructs that are not currently
+    // supported in the JIT; fall back to the interpreter when this is detected.
+    bool m_shouldFallBack;
+
+    // The regular expression expressed as a linear sequence of operations.
+    Vector m_ops;
+
+    // This records the current input offset being applied due to the current
+    // set of alternatives we are nested within. E.g. when matching the
+    // character 'b' within the regular expression /abc/, we will know that
+    // the minimum size for the alternative is 3, checked upon entry to the
+    // alternative, and that 'b' is at offset 1 from the start, and as such
+    // when matching 'b' we need to apply an offset of -2 to the load.
+    //
+    // FIXME: This should go away. Rather than tracking this value throughout
+    // code generation, we should gather this information up front & store it
+    // on the YarrOp structure.
+    int m_checked;
+
+    // This class records state whilst generating the backtracking path of code.
+    BacktrackingState m_backtrackingState;
+};
+
+void jitCompile(YarrPattern& pattern, JSGlobalData* globalData, YarrCodeBlock& jitObject)
+{
+    YarrGenerator(pattern).compile(globalData, jitObject);
+}
+
+int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output)
+{
+    return jitObject.execute(input, start, length, output);
+}
+
+}}
+
+#endif
diff --git a/js/src/yarr/YarrJIT.h b/js/src/yarr/YarrJIT.h
new file mode 100644
index 000000000000..4f0f47f8c548
--- /dev/null
+++ b/js/src/yarr/YarrJIT.h
@@ -0,0 +1,93 @@
+/* -*- 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.
+ *
+ * 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. 
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef YarrJIT_h
+#define YarrJIT_h
+
+#include "assembler/wtf/Platform.h"
+
+#if ENABLE_YARR_JIT
+
+#include "assembler/assembler/MacroAssembler.h"
+#include "YarrPattern.h"
+
+#if WTF_CPU_X86 && !WTF_COMPILER_MSVC
+#define YARR_CALL __attribute__ ((regparm (3)))
+#else
+#define YARR_CALL
+#endif
+
+namespace JSC {
+
+class JSGlobalData;
+class ExecutablePool;
+
+namespace Yarr {
+
+class YarrCodeBlock {
+    typedef int (*YarrJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
+
+public:
+    YarrCodeBlock()
+        : m_needFallBack(false)
+    {
+    }
+
+    ~YarrCodeBlock()
+    {
+    }
+
+    void setFallBack(bool fallback) { m_needFallBack = fallback; }
+    bool isFallBack() { return m_needFallBack; }
+    void set(MacroAssembler::CodeRef ref) { m_ref = ref; }
+
+    int execute(const UChar* input, unsigned start, unsigned length, int* output)
+    {
+        return JS_EXTENSION((reinterpret_cast(m_ref.m_code.executableAddress()))(input, start, length, output));
+    }
+
+#if ENABLE_REGEXP_TRACING
+    void *getAddr() { return m_ref.m_code.executableAddress(); }
+#endif
+
+    void release() { m_ref.release(); }
+
+private:
+    MacroAssembler::CodeRef m_ref;
+    bool m_needFallBack;
+};
+
+void jitCompile(YarrPattern&, JSGlobalData*, YarrCodeBlock& jitObject);
+int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output);
+
+} } // namespace JSC::Yarr
+
+#endif
+
+#endif // YarrJIT_h
diff --git a/js/src/yarr/yarr/RegexParser.h b/js/src/yarr/YarrParser.h
similarity index 81%
rename from js/src/yarr/yarr/RegexParser.h
rename to js/src/yarr/YarrParser.h
index 1ae2c2fd049b..f2b50dd867e3 100644
--- a/js/src/yarr/yarr/RegexParser.h
+++ b/js/src/yarr/YarrParser.h
@@ -1,4 +1,7 @@
-/*
+/* -*- 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.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -21,18 +24,18 @@
  * 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 RegexParser_h
-#define RegexParser_h
+#ifndef YarrParser_h
+#define YarrParser_h
 
-#include 
-#include 
-#include "yarr/jswtfbridge.h"
-#include "yarr/yarr/RegexCommon.h"
+#include "Yarr.h"
 
 namespace JSC { namespace Yarr {
 
+#define REGEXP_ERROR_PREFIX "Invalid regular expression: "
+
 enum BuiltInCharacterClassID {
     DigitClassID,
     SpaceClassID,
@@ -45,7 +48,7 @@ template
 class Parser {
 private:
     template
-    friend int parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit);
+    friend ErrorCode parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit);
 
     /*
      * CharacterClassParserDelegate:
@@ -61,10 +64,8 @@ private:
         CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err)
             : m_delegate(delegate)
             , m_err(err)
-            , m_state(empty)
-#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 5 /* quell GCC overwarning */
-            , m_character(0xFFFF)
-#endif
+            , m_state(Empty)
+            , m_character(0)
         {
         }
 
@@ -79,56 +80,62 @@ private:
         }
 
         /*
-         * atomPatternCharacterUnescaped():
+         * atomPatternCharacter():
          *
-         * This method is called directly from parseCharacterClass(), to report a new
-         * pattern character token.  This method differs from atomPatternCharacter(),
-         * which will be called from parseEscape(), since a hypen provided via this
-         * method may be indicating a character range, but a hyphen parsed by
-         * parseEscape() cannot be interpreted as doing so.
+         * This method is called either from parseCharacterClass() (for an unescaped
+         * character in a character class), or from parseEscape(). In the former case
+         * the value true will be passed for the argument 'hyphenIsRange', and in this
+         * mode we will allow a hypen to be treated as indicating a range (i.e. /[a-z]/
+         * is different to /[a\-z]/).
          */
-        void atomPatternCharacterUnescaped(UChar ch)
+        void atomPatternCharacter(UChar ch, bool hyphenIsRange = false)
         {
             switch (m_state) {
-            case empty:
-                m_character = ch;
-                m_state = cachedCharacter;
-                break;
+            case AfterCharacterClass:
+                // Following a builtin character class we need look out for a hyphen.
+                // We're looking for invalid ranges, such as /[\d-x]/ or /[\d-\d]/.
+                // If we see a hyphen following a charater class then unlike usual
+                // we'll report it to the delegate immediately, and put ourself into
+                // a poisoned state. Any following calls to add another character or
+                // character class will result in an error. (A hypen following a
+                // character-class is itself valid, but only  at the end of a regex).
+                if (hyphenIsRange && ch == '-') {
+                    m_delegate.atomCharacterClassAtom('-');
+                    m_state = AfterCharacterClassHyphen;
+                    return;
+                }
+                // Otherwise just fall through - cached character so treat this as Empty.
 
-            case cachedCharacter:
-                if (ch == '-')
-                    m_state = cachedCharacterHyphen;
+            case Empty:
+                m_character = ch;
+                m_state = CachedCharacter;
+                return;
+
+            case CachedCharacter:
+                if (hyphenIsRange && ch == '-')
+                    m_state = CachedCharacterHyphen;
                 else {
                     m_delegate.atomCharacterClassAtom(m_character);
                     m_character = ch;
                 }
-                break;
+                return;
 
-            case cachedCharacterHyphen:
-                if (ch >= m_character)
-                    m_delegate.atomCharacterClassRange(m_character, ch);
-                else
+            case CachedCharacterHyphen:
+                if (ch < m_character) {
                     m_err = CharacterClassOutOfOrder;
-                m_state = empty;
+                    return;
+                }
+                m_delegate.atomCharacterClassRange(m_character, ch);
+                m_state = Empty;
+                return;
+
+            case AfterCharacterClassHyphen:
+                m_delegate.atomCharacterClassAtom(ch);
+                m_state = Empty;
+                return;
             }
         }
 
-        /*
-         * atomPatternCharacter():
-         *
-         * Adds a pattern character, called by parseEscape(), as such will not
-         * interpret a hyphen as indicating a character range.
-         */
-        void atomPatternCharacter(UChar ch)
-        {
-            // Flush if a character is already pending to prevent the
-            // hyphen from begin interpreted as indicating a range.
-            if((ch == '-') && (m_state == cachedCharacter))
-                flush();
-
-            atomPatternCharacterUnescaped(ch);
-        }
-
         /*
          * atomBuiltInCharacterClass():
          *
@@ -136,17 +143,28 @@ private:
          */
         void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert)
         {
-            if (m_state == cachedCharacterHyphen) {
-                // If the RHS of a range does not contain exacly one character then a SyntaxError
-                // must be thrown. SpiderMonkey only errors out in the [c-\s] case as an extension.
-                // (This assumes none of the built in character classes contain a single
-                // character.)
-                m_err = CharacterClassRangeSingleChar;
-                m_state = empty;
+            switch (m_state) {
+            case CachedCharacter:
+                // Flush the currently cached character, then fall through.
+                m_delegate.atomCharacterClassAtom(m_character);
+
+            case Empty:
+            case AfterCharacterClass:
+                m_state = AfterCharacterClass;
+                m_delegate.atomCharacterClassBuiltIn(classID, invert);
+                return;
+
+            case CachedCharacterHyphen:
+                // Error! We have a range that looks like [x-\d]. We require
+                // the end of the range to be a single character.
+                m_err = CharacterClassInvalidRange;
+                return;
+
+            case AfterCharacterClassHyphen:
+                m_delegate.atomCharacterClassBuiltIn(classID, invert);
+                m_state = Empty;
                 return;
             }
-            flush();
-            m_delegate.atomCharacterClassBuiltIn(classID, invert);
         }
 
         /*
@@ -156,31 +174,29 @@ private:
          */
         void end()
         {
-            flush();
+            if (m_state == CachedCharacter)
+                m_delegate.atomCharacterClassAtom(m_character);
+            else if (m_state == CachedCharacterHyphen) {
+                m_delegate.atomCharacterClassAtom(m_character);
+                m_delegate.atomCharacterClassAtom('-');
+            }
             m_delegate.atomCharacterClassEnd();
         }
 
         // parseEscape() should never call these delegate methods when
         // invoked with inCharacterClass set.
-        void assertionWordBoundary(bool) { JS_NOT_REACHED("parseEscape() should never call this"); }
-        void atomBackReference(unsigned) { JS_NOT_REACHED("parseEscape() should never call this"); }
+        void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); }
+        void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); }
 
     private:
-        void flush()
-        {
-            if (m_state != empty) // either cachedCharacter or cachedCharacterHyphen
-                m_delegate.atomCharacterClassAtom(m_character);
-            if (m_state == cachedCharacterHyphen)
-                m_delegate.atomCharacterClassAtom('-');
-            m_state = empty;
-        }
-    
         Delegate& m_delegate;
         ErrorCode& m_err;
         enum CharacterClassConstructionState {
-            empty,
-            cachedCharacter,
-            cachedCharacterHyphen
+            Empty,
+            CachedCharacter,
+            CachedCharacterHyphen,
+            AfterCharacterClass,
+            AfterCharacterClassHyphen
         } m_state;
         UChar m_character;
     };
@@ -189,7 +205,7 @@ private:
         : m_delegate(delegate)
         , m_backReferenceLimit(backReferenceLimit)
         , m_err(NoError)
-        , m_data(const_cast(pattern).chars())
+        , m_data(pattern.chars())
         , m_size(pattern.length())
         , m_index(0)
         , m_parenthesesNestingDepth(0)
@@ -219,8 +235,8 @@ private:
     template
     bool parseEscape(EscapeDelegate& delegate)
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(peek() == '\\');
+        ASSERT(!m_err);
+        ASSERT(peek() == '\\');
         consume();
 
         if (atEndOfPattern()) {
@@ -292,7 +308,7 @@ private:
 
                 unsigned backReference;
                 if (!consumeNumber(backReference))
-                    return false;
+                    break;
                 if (backReference <= m_backReferenceLimit) {
                     delegate.atomBackReference(backReference);
                     break;
@@ -402,14 +418,14 @@ private:
     /*
      * parseCharacterClass():
      *
-     * Helper for parseTokens(); calls directly and indirectly (via parseCharacterClassEscape)
+     * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape)
      * to an instance of CharacterClassParserDelegate, to describe the character class to the
      * delegate.
      */
     void parseCharacterClass()
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(peek() == '[');
+        ASSERT(!m_err);
+        ASSERT(peek() == '[');
         consume();
 
         CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err);
@@ -428,7 +444,7 @@ private:
                 break;
 
             default:
-                characterClassConstructor.atomPatternCharacterUnescaped(consume());
+                characterClassConstructor.atomPatternCharacter(consume(), true);
             }
 
             if (m_err)
@@ -445,8 +461,8 @@ private:
      */
     void parseParenthesesBegin()
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(peek() == '(');
+        ASSERT(!m_err);
+        ASSERT(peek() == '(');
         consume();
 
         if (tryConsume('?')) {
@@ -484,8 +500,8 @@ private:
      */
     void parseParenthesesEnd()
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(peek() == ')');
+        ASSERT(!m_err);
+        ASSERT(peek() == ')');
         consume();
 
         if (m_parenthesesNestingDepth > 0)
@@ -503,8 +519,8 @@ private:
      */
     void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max)
     {
-        JS_ASSERT(!m_err);
-        JS_ASSERT(min <= max);
+        ASSERT(!m_err);
+        ASSERT(min <= max);
 
         if (lastTokenWasAnAtom)
             m_delegate.quantifyAtom(min, max, !tryConsume('?'));
@@ -572,13 +588,13 @@ private:
 
             case '*':
                 consume();
-                parseQuantifier(lastTokenWasAnAtom, 0, UINT_MAX);
+                parseQuantifier(lastTokenWasAnAtom, 0, quantifyInfinite);
                 lastTokenWasAnAtom = false;
                 break;
 
             case '+':
                 consume();
-                parseQuantifier(lastTokenWasAnAtom, 1, UINT_MAX);
+                parseQuantifier(lastTokenWasAnAtom, 1, quantifyInfinite);
                 lastTokenWasAnAtom = false;
                 break;
 
@@ -603,7 +619,7 @@ private:
                             if (!consumeNumber(max))
                                 break;
                         } else {
-                            max = UINT_MAX;
+                            max = quantifyInfinite;
                         }
                     }
 
@@ -636,26 +652,18 @@ private:
     /*
      * parse():
      *
-     * This method calls regexBegin(), calls parseTokens() to parse over the input
-     * patterns, calls regexEnd() or regexError() as appropriate, and converts any
+     * This method calls parseTokens() to parse over the input and converts any
      * error code to a const char* for a result.
      */
-    int parse()
+    ErrorCode parse()
     {
-        m_delegate.regexBegin();
-
         if (m_size > MAX_PATTERN_SIZE)
             m_err = PatternTooLarge;
         else
             parseTokens();
-        JS_ASSERT(atEndOfPattern() || m_err);
+        ASSERT(atEndOfPattern() || m_err);
 
-        if (m_err)
-            m_delegate.regexError();
-        else
-            m_delegate.regexEnd();
-
-        return static_cast(m_err);
+        return m_err;
     }
 
 
@@ -675,13 +683,13 @@ private:
 
     bool atEndOfPattern()
     {
-        JS_ASSERT(m_index <= m_size);
+        ASSERT(m_index <= m_size);
         return m_index == m_size;
     }
 
     int peek()
     {
-        JS_ASSERT(m_index < m_size);
+        ASSERT(m_index < m_size);
         return m_data[m_index];
     }
 
@@ -692,40 +700,40 @@ private:
 
     unsigned peekDigit()
     {
-        JS_ASSERT(peekIsDigit());
+        ASSERT(peekIsDigit());
         return peek() - '0';
     }
 
     int consume()
     {
-        JS_ASSERT(m_index < m_size);
+        ASSERT(m_index < m_size);
         return m_data[m_index++];
     }
 
     unsigned consumeDigit()
     {
-        JS_ASSERT(peekIsDigit());
+        ASSERT(peekIsDigit());
         return consume() - '0';
     }
 
-    bool consumeNumber(unsigned &accum)
-    {
-        accum = consumeDigit();
-        while (peekIsDigit()) {
-            unsigned newValue = accum * 10 + peekDigit();
-            if (newValue < accum) { /* Overflow check. */
-                m_err = QuantifierTooLarge;
-                return false;
-            }
-            accum = newValue;
-            consume();
-        }
-        return true;
+    bool consumeNumber(unsigned &accum)
+    {
+        accum = consumeDigit();
+        while (peekIsDigit()) {
+            unsigned newValue = accum * 10 + peekDigit();
+            if (newValue < accum) { /* Overflow check. */
+                m_err = QuantifierTooLarge;
+                return false;
+            }
+            accum = newValue;
+            consume();
+        }
+        return true;
     }
 
     unsigned consumeOctal()
     {
-        JS_ASSERT(WTF::isASCIIOctalDigit(peek()));
+        ASSERT(WTF::isASCIIOctalDigit(peek()));
 
         unsigned n = consumeDigit();
         while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek()))
@@ -798,14 +806,6 @@ private:
  *
  *    void disjunction();
  *
- *    void regexBegin();
- *    void regexEnd();
- *    void regexError();
- *
- * Before any call recording tokens are made, regexBegin() will be called on the
- * delegate once.  Once parsing is complete either regexEnd() or regexError() will
- * be called, as appropriate.
- *
  * The regular expression is described by a sequence of assertion*() and atom*()
  * callbacks to the delegate, describing the terms in the regular expression.
  * Following an atom a quantifyAtom() call may occur to indicate that the previous
@@ -836,11 +836,11 @@ private:
  */
 
 template
-int parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = UINT_MAX)
+ErrorCode parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = quantifyInfinite)
 {
     return Parser(delegate, pattern, backReferenceLimit).parse();
 }
 
 } } // namespace JSC::Yarr
 
-#endif // RegexParser_h
+#endif // YarrParser_h
diff --git a/js/src/yarr/yarr/RegexCompiler.cpp b/js/src/yarr/YarrPattern.cpp
similarity index 52%
rename from js/src/yarr/yarr/RegexCompiler.cpp
rename to js/src/yarr/YarrPattern.cpp
index 9b60cbd4a78b..10b7d8911987 100644
--- a/js/src/yarr/yarr/RegexCompiler.cpp
+++ b/js/src/yarr/YarrPattern.cpp
@@ -1,5 +1,9 @@
-/*
+/* -*- 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
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -21,12 +25,13 @@
  * 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 ***** */
 
-#include "jsinttypes.h"
-#include "RegexCompiler.h"
+#include "YarrPattern.h"
 
-#include "RegexPattern.h"
+#include "Yarr.h"
+#include "YarrParser.h"
 
 using namespace WTF;
 
@@ -34,12 +39,6 @@ namespace JSC { namespace Yarr {
 
 #include "RegExpJitTables.h"
 
-#if WTF_CPU_SPARC
-#define BASE_FRAME_SIZE 24
-#else
-#define BASE_FRAME_SIZE 0
-#endif
-
 class CharacterClassConstructor {
 public:
     CharacterClassConstructor(bool isCaseInsensitive = false)
@@ -57,13 +56,13 @@ public:
 
     void append(const CharacterClass* other)
     {
-        for (size_t i = 0; i < other->m_matches.length(); ++i)
+        for (size_t i = 0; i < other->m_matches.size(); ++i)
             addSorted(m_matches, other->m_matches[i]);
-        for (size_t i = 0; i < other->m_ranges.length(); ++i)
+        for (size_t i = 0; i < other->m_ranges.size(); ++i)
             addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end);
-        for (size_t i = 0; i < other->m_matchesUnicode.length(); ++i)
+        for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i)
             addSorted(m_matchesUnicode, other->m_matchesUnicode[i]);
-        for (size_t i = 0; i < other->m_rangesUnicode.length(); ++i)
+        for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i)
             addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end);
     }
 
@@ -101,18 +100,18 @@ public:
     {
         if (lo <= 0x7f) {
             char asciiLo = lo;
-            char asciiHi = JS_MIN(hi, (UChar)0x7f);
+            char asciiHi = std::min(hi, (UChar)0x7f);
             addSortedRange(m_ranges, lo, asciiHi);
             
             if (m_isCaseInsensitive) {
                 if ((asciiLo <= 'Z') && (asciiHi >= 'A'))
-                    addSortedRange(m_ranges, JS_MAX(asciiLo, 'A')+('a'-'A'), JS_MIN(asciiHi, 'Z')+('a'-'A'));
+                    addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A'));
                 if ((asciiLo <= 'z') && (asciiHi >= 'a'))
-                    addSortedRange(m_ranges, JS_MAX(asciiLo, 'a')+('A'-'a'), JS_MIN(asciiHi, 'z')+('A'-'a'));
+                    addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a'));
             }
         }
         if (hi >= 0x80) {
-            uint32 unicodeCurr = JS_MAX(lo, (UChar)0x80);
+            uint32_t unicodeCurr = std::max(lo, (UChar)0x80);
             addSortedRange(m_rangesUnicode, unicodeCurr, hi);
             
             if (m_isCaseInsensitive) {
@@ -122,7 +121,7 @@ public:
                     // (if so we won't re-enter the loop, since the loop condition above
                     // will definitely fail) - but this does mean we cannot use a UChar
                     // to represent unicodeCurr, we must use a 32-bit value instead.
-                    JS_ASSERT(unicodeCurr <= 0xffff);
+                    ASSERT(unicodeCurr <= 0xffff);
 
                     if (isUnicodeUpper(unicodeCurr)) {
                         UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr);
@@ -145,8 +144,7 @@ public:
 
     CharacterClass* charClass()
     {
-        // FIXME: bug 574459 -- no NULL check
-        CharacterClass* characterClass = js::OffTheBooks::new_((CharacterClassTable*)NULL);
+        CharacterClass* characterClass = js::OffTheBooks::new_(PassRefPtr(0));
 
         characterClass->m_matches.append(m_matches);
         characterClass->m_ranges.append(m_ranges);
@@ -159,12 +157,10 @@ public:
     }
 
 private:
-    typedef js::Vector UChars;
-    typedef js::Vector CharacterRanges;
-    void addSorted(UChars& matches, UChar ch)
+    void addSorted(Vector& matches, UChar ch)
     {
         unsigned pos = 0;
-        unsigned range = matches.length();
+        unsigned range = matches.size();
 
         // binary chop, find position to insert char.
         while (range) {
@@ -181,15 +177,15 @@ private:
             }
         }
         
-        if (pos == matches.length())
+        if (pos == matches.size())
             matches.append(ch);
         else
-            matches.insert(matches.begin() + pos, ch);
+            matches.insert(pos, ch);
     }
 
-    void addSortedRange(CharacterRanges& ranges, UChar lo, UChar hi)
+    void addSortedRange(Vector& ranges, UChar lo, UChar hi)
     {
-        unsigned end = ranges.length();
+        unsigned end = ranges.size();
         
         // Simple linear scan - I doubt there are that many ranges anyway...
         // feel free to fix this with something faster (eg binary chop).
@@ -201,7 +197,7 @@ private:
                     ranges[i].begin = lo;
                     return;
                 }
-                ranges.insert(ranges.begin() + i, CharacterRange(lo, hi));
+                ranges.insert(i, CharacterRange(lo, hi));
                 return;
             }
             // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining
@@ -209,17 +205,17 @@ private:
             // end of the last range they concatenate, which is just as good.
             if (lo <= (ranges[i].end + 1)) {
                 // found an intersect! we'll replace this entry in the array.
-                ranges[i].begin = JS_MIN(ranges[i].begin, lo);
-                ranges[i].end = JS_MAX(ranges[i].end, hi);
+                ranges[i].begin = std::min(ranges[i].begin, lo);
+                ranges[i].end = std::max(ranges[i].end, hi);
 
                 // now check if the new range can subsume any subsequent ranges.
                 unsigned next = i+1;
                 // each iteration of the loop we will either remove something from the list, or break the loop.
-                while (next < ranges.length()) {
+                while (next < ranges.size()) {
                     if (ranges[next].begin <= (ranges[i].end + 1)) {
                         // the next entry now overlaps / concatenates this one.
-                        ranges[i].end = JS_MAX(ranges[i].end, ranges[next].end);
-                        ranges.erase(ranges.begin() + next);
+                        ranges[i].end = std::max(ranges[i].end, ranges[next].end);
+                        ranges.remove(next);
                     } else
                         break;
                 }
@@ -234,21 +230,131 @@ private:
 
     bool m_isCaseInsensitive;
 
-    UChars m_matches;
-    CharacterRanges m_ranges;
-    UChars m_matchesUnicode;
-    CharacterRanges m_rangesUnicode;
+    Vector m_matches;
+    Vector m_ranges;
+    Vector m_matchesUnicode;
+    Vector m_rangesUnicode;
 };
 
-class RegexPatternConstructor {
-public:
-    RegexPatternConstructor(RegexPattern& pattern)
-        : m_pattern(pattern)
-        , m_characterClassConstructor(pattern.m_ignoreCase)
+struct BeginCharHelper {
+    BeginCharHelper(Vector* beginChars, bool isCaseInsensitive = false)
+        : m_beginChars(beginChars)
+        , m_isCaseInsensitive(isCaseInsensitive)
+    {}
+
+    void addBeginChar(BeginChar beginChar, Vector* hotTerms, QuantifierType quantityType, unsigned quantityCount)
     {
+        if (quantityType == QuantifierFixedCount && quantityCount > 1) {
+            // We duplicate the first found character if the quantity of the term is more than one. eg.: /a{3}/
+            beginChar.value |= beginChar.value << 16;
+            beginChar.mask |= beginChar.mask << 16;
+            addCharacter(beginChar);
+        } else if (quantityType == QuantifierFixedCount && quantityCount == 1 && hotTerms->size())
+            // In case of characters with fixed quantifier we should check the next character as well.
+            linkHotTerms(beginChar, hotTerms);
+        else
+            // In case of greedy matching the next character checking is unnecessary therefore we just store
+            // the first character.
+            addCharacter(beginChar);
     }
 
-    ~RegexPatternConstructor()
+    // Merge two following BeginChars in the vector to reduce the number of character checks.
+    void merge(unsigned size)
+    {
+        for (unsigned i = 0; i < size; i++) {
+            BeginChar* curr = &m_beginChars->at(i);
+            BeginChar* next = &m_beginChars->at(i + 1);
+
+            // If the current and the next size of value is different we should skip the merge process
+            // because the 16bit and 32bit values are unmergable.
+            if (curr->value <= 0xFFFF && next->value > 0xFFFF)
+                continue;
+
+            unsigned diff = curr->value ^ next->value;
+
+            curr->mask |= diff;
+            curr->value |= curr->mask;
+
+            m_beginChars->remove(i + 1);
+            size--;
+        }
+    }
+
+private:
+    void addCharacter(BeginChar beginChar)
+    {
+        unsigned pos = 0;
+        unsigned range = m_beginChars->size();
+
+        // binary chop, find position to insert char.
+        while (range) {
+            unsigned index = range >> 1;
+
+            int val = m_beginChars->at(pos+index).value - beginChar.value;
+            if (!val)
+                return;
+            if (val < 0)
+                range = index;
+            else {
+                pos += (index+1);
+                range -= (index+1);
+            }
+        }
+
+        if (pos == m_beginChars->size())
+            m_beginChars->append(beginChar);
+        else
+            m_beginChars->insert(pos, beginChar);
+    }
+
+    // Create BeginChar objects by appending each terms from a hotTerms vector to an existing BeginChar object.
+    void linkHotTerms(BeginChar beginChar, Vector* hotTerms)
+    {
+        for (unsigned i = 0; i < hotTerms->size(); i++) {
+            PatternTerm hotTerm = hotTerms->at(i).term;
+            ASSERT(hotTerm.type == PatternTerm::TypePatternCharacter);
+
+            UChar characterNext = hotTerm.patternCharacter;
+
+            // Append a character to an existing BeginChar object.
+            if (characterNext <= 0x7f) {
+                unsigned mask = 0;
+
+                if (m_isCaseInsensitive && isASCIIAlpha(characterNext)) {
+                    mask = 32;
+                    characterNext = toASCIILower(characterNext);
+                }
+
+                addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask | (mask << 16)));
+            } else {
+                UChar upper, lower;
+                if (m_isCaseInsensitive && ((upper = Unicode::toUpper(characterNext)) != (lower = Unicode::toLower(characterNext)))) {
+                    addCharacter(BeginChar(beginChar.value | (upper << 16), beginChar.mask));
+                    addCharacter(BeginChar(beginChar.value | (lower << 16), beginChar.mask));
+                } else
+                    addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask));
+            }
+        }
+    }
+
+    Vector* m_beginChars;
+    bool m_isCaseInsensitive;
+};
+
+class YarrPatternConstructor {
+public:
+    YarrPatternConstructor(YarrPattern& pattern)
+        : m_pattern(pattern)
+        , m_characterClassConstructor(pattern.m_ignoreCase)
+        , m_beginCharHelper(&pattern.m_beginChars, pattern.m_ignoreCase)
+        , m_invertParentheticalAssertion(false)
+    {
+        m_pattern.m_body = js::OffTheBooks::new_();
+        m_alternative = m_pattern.m_body->addNewAlternative();
+        m_pattern.m_disjunctions.append(m_pattern.m_body);
+    }
+
+    ~YarrPatternConstructor()
     {
     }
 
@@ -256,10 +362,19 @@ public:
     {
         m_pattern.reset();
         m_characterClassConstructor.reset();
+
+        m_pattern.m_body = js::OffTheBooks::new_();
+        m_alternative = m_pattern.m_body->addNewAlternative();
+        m_pattern.m_disjunctions.append(m_pattern.m_body);
     }
     
     void assertionBOL()
     {
+        if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) {
+            m_alternative->m_startsWithBOL = true;
+            m_alternative->m_containsBOL = true;
+            m_pattern.m_containsBOL = true;
+        }
         m_alternative->m_terms.append(PatternTerm::BOL());
     }
     void assertionEOL()
@@ -318,7 +433,7 @@ public:
 
     void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert)
     {
-        JS_ASSERT(classID != NewlineClassID);
+        ASSERT(classID != NewlineClassID);
 
         switch (classID) {
         case DigitClassID:
@@ -334,7 +449,7 @@ public:
             break;
         
         default:
-            JS_NOT_REACHED("Invalid character class.");
+            ASSERT_NOT_REACHED();
         }
     }
 
@@ -351,36 +466,56 @@ public:
         if (capture)
             m_pattern.m_numSubpatterns++;
 
-        // FIXME: bug 574459 -- no NULL check
         PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative);
         m_pattern.m_disjunctions.append(parenthesesDisjunction);
-        m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture));
+        m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, false));
         m_alternative = parenthesesDisjunction->addNewAlternative();
     }
 
     void atomParentheticalAssertionBegin(bool invert = false)
     {
-        // FIXME: bug 574459 -- no NULL check
         PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative);
         m_pattern.m_disjunctions.append(parenthesesDisjunction);
-        m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert));
+        m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, false, invert));
         m_alternative = parenthesesDisjunction->addNewAlternative();
+        m_invertParentheticalAssertion = invert;
     }
 
     void atomParenthesesEnd()
     {
-        JS_ASSERT(m_alternative->m_parent);
-        JS_ASSERT(m_alternative->m_parent->m_parent);
+        ASSERT(m_alternative->m_parent);
+        ASSERT(m_alternative->m_parent->m_parent);
+
+        PatternDisjunction* parenthesesDisjunction = m_alternative->m_parent;
         m_alternative = m_alternative->m_parent->m_parent;
-        
-        m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
+
+        PatternTerm& lastTerm = m_alternative->lastTerm();
+
+        unsigned numParenAlternatives = parenthesesDisjunction->m_alternatives.size();
+        unsigned numBOLAnchoredAlts = 0;
+
+        for (unsigned i = 0; i < numParenAlternatives; i++) {
+            // Bubble up BOL flags
+            if (parenthesesDisjunction->m_alternatives[i]->m_startsWithBOL)
+                numBOLAnchoredAlts++;
+        }
+
+        if (numBOLAnchoredAlts) {
+            m_alternative->m_containsBOL = true;
+            // If all the alternatives in parens start with BOL, then so does this one
+            if (numBOLAnchoredAlts == numParenAlternatives)
+                m_alternative->m_startsWithBOL = true;
+        }
+
+        lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
+        m_invertParentheticalAssertion = false;
     }
 
     void atomBackReference(unsigned subpatternId)
     {
-        JS_ASSERT(subpatternId);
+        ASSERT(subpatternId);
         m_pattern.m_containsBackreferences = true;
-        m_pattern.m_maxBackReference = JS_MAX(m_pattern.m_maxBackReference, subpatternId);
+        m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId);
 
         if (subpatternId > m_pattern.m_numSubpatterns) {
             m_alternative->m_terms.append(PatternTerm::ForwardReference());
@@ -388,14 +523,14 @@ public:
         }
 
         PatternAlternative* currentAlternative = m_alternative;
-        JS_ASSERT(currentAlternative);
+        ASSERT(currentAlternative);
 
         // Note to self: if we waited until the AST was baked, we could also remove forwards refs 
         while ((currentAlternative = currentAlternative->m_parent->m_parent)) {
             PatternTerm& term = currentAlternative->lastTerm();
-            JS_ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion));
+            ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion));
 
-            if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) {
+            if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.capture() && (subpatternId == term.parentheses.subpatternId)) {
                 m_alternative->m_terms.append(PatternTerm::ForwardReference());
                 return;
             }
@@ -404,37 +539,43 @@ public:
         m_alternative->m_terms.append(PatternTerm(subpatternId));
     }
 
-    PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction)
+    // deep copy the argument disjunction.  If filterStartsWithBOL is true, 
+    // skip alternatives with m_startsWithBOL set true.
+    PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false)
     {
-        // FIXME: bug 574459 -- no NULL check
-        PatternDisjunction* newDisjunction = js::OffTheBooks::new_();
-
-        newDisjunction->m_parent = disjunction->m_parent;
-        for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) {
+        PatternDisjunction* newDisjunction = 0;
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
             PatternAlternative* alternative = disjunction->m_alternatives[alt];
-            PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
-            for (unsigned i = 0; i < alternative->m_terms.length(); ++i)
-                newAlternative->m_terms.append(copyTerm(alternative->m_terms[i]));
+            if (!filterStartsWithBOL || !alternative->m_startsWithBOL) {
+                if (!newDisjunction) {
+                    newDisjunction = new PatternDisjunction();
+                    newDisjunction->m_parent = disjunction->m_parent;
+                }
+                PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
+                for (unsigned i = 0; i < alternative->m_terms.size(); ++i)
+                    newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL));
+            }
         }
-
-        m_pattern.m_disjunctions.append(newDisjunction);
+        
+        if (newDisjunction)
+            m_pattern.m_disjunctions.append(newDisjunction);
         return newDisjunction;
     }
-
-    PatternTerm copyTerm(PatternTerm& term)
+    
+    PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false)
     {
         if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion))
             return PatternTerm(term);
-
+        
         PatternTerm termCopy = term;
-        termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction);
+        termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL);
         return termCopy;
     }
-
+    
     void quantifyAtom(unsigned min, unsigned max, bool greedy)
     {
-        JS_ASSERT(min <= max);
-        JS_ASSERT(m_alternative->m_terms.length());
+        ASSERT(min <= max);
+        ASSERT(m_alternative->m_terms.size());
 
         if (!max) {
             m_alternative->removeLastTerm();
@@ -442,8 +583,8 @@ public:
         }
 
         PatternTerm& term = m_alternative->lastTerm();
-        JS_ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary);
-        JS_ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount));
+        ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary);
+        ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount));
 
         // For any assertion with a zero minimum, not matching is valid and has no effect,
         // remove it.  Otherwise, we need to match as least once, but there is no point
@@ -464,7 +605,7 @@ public:
             term.quantify(min, QuantifierFixedCount);
             m_alternative->m_terms.append(copyTerm(term));
             // NOTE: this term is interesting from an analysis perspective, in that it can be ignored.....
-            m_alternative->lastTerm().quantify((max == UINT_MAX) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy);
+            m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy);
             if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern)
                 m_alternative->lastTerm().parentheses.isCopy = true;
         }
@@ -475,26 +616,12 @@ public:
         m_alternative = m_alternative->m_parent->addNewAlternative();
     }
 
-    void regexBegin()
-    {
-        // FIXME: bug 574459 -- no NULL check
-        m_pattern.m_body = js::OffTheBooks::new_();
-        m_alternative = m_pattern.m_body->addNewAlternative();
-        m_pattern.m_disjunctions.append(m_pattern.m_body);
-    }
-    void regexEnd()
-    {
-    }
-    void regexError()
-    {
-    }
-
     unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition)
     {
         alternative->m_hasFixedSize = true;
         unsigned currentInputPosition = initialInputPosition;
 
-        for (unsigned i = 0; i < alternative->m_terms.length(); ++i) {
+        for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
             PatternTerm& term = alternative->m_terms[i];
 
             switch (term.type) {
@@ -507,7 +634,7 @@ public:
             case PatternTerm::TypeBackReference:
                 term.inputPosition = currentInputPosition;
                 term.frameLocation = currentCallFrameSize;
-                currentCallFrameSize += RegexStackSpaceForBackTrackInfoBackReference;
+                currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference;
                 alternative->m_hasFixedSize = false;
                 break;
 
@@ -518,7 +645,7 @@ public:
                 term.inputPosition = currentInputPosition;
                 if (term.quantityType != QuantifierFixedCount) {
                     term.frameLocation = currentCallFrameSize;
-                    currentCallFrameSize += RegexStackSpaceForBackTrackInfoPatternCharacter;
+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter;
                     alternative->m_hasFixedSize = false;
                 } else
                     currentInputPosition += term.quantityCount;
@@ -528,7 +655,7 @@ public:
                 term.inputPosition = currentInputPosition;
                 if (term.quantityType != QuantifierFixedCount) {
                     term.frameLocation = currentCallFrameSize;
-                    currentCallFrameSize += RegexStackSpaceForBackTrackInfoCharacterClass;
+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass;
                     alternative->m_hasFixedSize = false;
                 } else
                     currentInputPosition += term.quantityCount;
@@ -539,20 +666,20 @@ public:
                 term.frameLocation = currentCallFrameSize;
                 if (term.quantityCount == 1 && !term.parentheses.isCopy) {
                     if (term.quantityType != QuantifierFixedCount)
-                        currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesOnce;
+                        currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce;
                     currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
                     // If quantity is fixed, then pre-check its minimum size.
                     if (term.quantityType == QuantifierFixedCount)
                         currentInputPosition += term.parentheses.disjunction->m_minimumSize;
                     term.inputPosition = currentInputPosition;
                 } else if (term.parentheses.isTerminal) {
-                    currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesTerminal;
+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal;
                     currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition);
                     term.inputPosition = currentInputPosition;
                 } else {
                     term.inputPosition = currentInputPosition;
                     setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition);
-                    currentCallFrameSize += RegexStackSpaceForBackTrackInfoParentheses;
+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses;
                 }
                 // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length.
                 alternative->m_hasFixedSize = false;
@@ -561,7 +688,7 @@ public:
             case PatternTerm::TypeParentheticalAssertion:
                 term.inputPosition = currentInputPosition;
                 term.frameLocation = currentCallFrameSize;
-                currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + RegexStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition);
+                currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition);
                 break;
             }
         }
@@ -572,23 +699,23 @@ public:
 
     unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition)
     {
-        if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.length() > 1))
-            initialCallFrameSize += RegexStackSpaceForBackTrackInfoAlternative;
+        if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1))
+            initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative;
 
         unsigned minimumInputSize = UINT_MAX;
         unsigned maximumCallFrameSize = 0;
         bool hasFixedSize = true;
 
-        for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) {
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
             PatternAlternative* alternative = disjunction->m_alternatives[alt];
             unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition);
-            minimumInputSize = JS_MIN(minimumInputSize, alternative->m_minimumSize);
-            maximumCallFrameSize = JS_MAX(maximumCallFrameSize, currentAlternativeCallFrameSize);
+            minimumInputSize = std::min(minimumInputSize, alternative->m_minimumSize);
+            maximumCallFrameSize = std::max(maximumCallFrameSize, currentAlternativeCallFrameSize);
             hasFixedSize &= alternative->m_hasFixedSize;
         }
         
-        JS_ASSERT(minimumInputSize != UINT_MAX);
-        JS_ASSERT(maximumCallFrameSize >= initialCallFrameSize);
+        ASSERT(minimumInputSize != UINT_MAX);
+        ASSERT(maximumCallFrameSize >= initialCallFrameSize);
 
         disjunction->m_hasFixedSize = hasFixedSize;
         disjunction->m_minimumSize = minimumInputSize;
@@ -598,13 +725,14 @@ public:
 
     void setupOffsets()
     {
-        setupDisjunctionOffsets(m_pattern.m_body, BASE_FRAME_SIZE, 0);
+        setupDisjunctionOffsets(m_pattern.m_body, 0, 0);
     }
 
     // This optimization identifies sets of parentheses that we will never need to backtrack.
     // In these cases we do not need to store state from prior iterations.
     // We can presently avoid backtracking for:
-    //   * a set of parens at the end of the regular expression (last term in any of the alternatives of the main body disjunction).
+    //   * where the parens are at the end of the regular expression (last term in any of the
+    //     alternatives of the main body disjunction).
     //   * where the parens are non-capturing, and quantified unbounded greedy (*).
     //   * where the parens do not contain any capturing subpatterns.
     void checkForTerminalParentheses()
@@ -614,57 +742,239 @@ public:
         if (m_pattern.m_numSubpatterns)
             return;
 
-        js::Vector& alternatives = m_pattern.m_body->m_alternatives;
-        for (unsigned i =0; i < alternatives.length(); ++i) {
-            js::Vector& terms = alternatives[i]->m_terms;
-            if (terms.length()) {
-                PatternTerm& term = terms.back();
+        Vector& alternatives = m_pattern.m_body->m_alternatives;
+        for (size_t i = 0; i < alternatives.size(); ++i) {
+            Vector& terms = alternatives[i]->m_terms;
+            if (terms.size()) {
+                PatternTerm& term = terms.last();
                 if (term.type == PatternTerm::TypeParenthesesSubpattern
                     && term.quantityType == QuantifierGreedy
-                    && term.quantityCount == UINT_MAX
+                    && term.quantityCount == quantifyInfinite
                     && !term.capture())
                     term.parentheses.isTerminal = true;
             }
         }
     }
 
+    void optimizeBOL()
+    {
+        // Look for expressions containing beginning of line (^) anchoring and unroll them.
+        // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops
+        // This code relies on the parsing code tagging alternatives with m_containsBOL and
+        // m_startsWithBOL and rolling those up to containing alternatives.
+        // At this point, this is only valid for non-multiline expressions.
+        PatternDisjunction* disjunction = m_pattern.m_body;
+        
+        if (!m_pattern.m_containsBOL || m_pattern.m_multiline)
+            return;
+        
+        PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true);
+
+        // Set alternatives in disjunction to "onceThrough"
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt)
+            disjunction->m_alternatives[alt]->setOnceThrough();
+
+        if (loopDisjunction) {
+            // Move alternatives from loopDisjunction to disjunction
+            for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt)
+                disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]);
+                
+            loopDisjunction->m_alternatives.clear();
+        }
+    }
+
+    // This function collects the terms which are potentially matching the first number of depth characters in the result.
+    // If this function returns false then it found at least one term which makes the beginning character
+    // look-up optimization inefficient.
+    bool setupDisjunctionBeginTerms(PatternDisjunction* disjunction, Vector* beginTerms, unsigned depth)
+    {
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
+            PatternAlternative* alternative = disjunction->m_alternatives[alt];
+
+            if (!setupAlternativeBeginTerms(alternative, beginTerms, 0, depth))
+                return false;
+        }
+
+        return true;
+    }
+
+    bool setupAlternativeBeginTerms(PatternAlternative* alternative, Vector* beginTerms, unsigned termIndex, unsigned depth)
+    {
+        bool checkNext = true;
+        unsigned numTerms = alternative->m_terms.size();
+
+        while (checkNext && termIndex < numTerms) {
+            PatternTerm term = alternative->m_terms[termIndex];
+            checkNext = false;
+
+            switch (term.type) {
+            case PatternTerm::TypeAssertionBOL:
+            case PatternTerm::TypeAssertionEOL:
+            case PatternTerm::TypeAssertionWordBoundary:
+                return false;
+
+            case PatternTerm::TypeBackReference:
+            case PatternTerm::TypeForwardReference:
+                return false;
+
+            case PatternTerm::TypePatternCharacter:
+                if (termIndex != numTerms - 1) {
+                    beginTerms->append(TermChain(term));
+                    termIndex++;
+                    checkNext = true;
+                } else if (term.quantityType == QuantifierFixedCount) {
+                    beginTerms->append(TermChain(term));
+                    if (depth < 2 && termIndex < numTerms - 1 && term.quantityCount == 1)
+                        if (!setupAlternativeBeginTerms(alternative, &beginTerms->last().hotTerms, termIndex + 1, depth + 1))
+                            return false;
+                }
+
+                break;
+
+            case PatternTerm::TypeCharacterClass:
+                return false;
+
+            case PatternTerm::TypeParentheticalAssertion:
+                if (term.invert())
+                    return false;
+
+            case PatternTerm::TypeParenthesesSubpattern:
+                if (term.quantityType != QuantifierFixedCount) {
+                    if (termIndex == numTerms - 1)
+                        break;
+
+                    termIndex++;
+                    checkNext = true;
+                }
+
+                if (!setupDisjunctionBeginTerms(term.parentheses.disjunction, beginTerms, depth))
+                    return false;
+
+                break;
+            }
+        }
+
+        return true;
+    }
+
+    void setupBeginChars()
+    {
+        Vector beginTerms;
+        bool containsFixedCharacter = false;
+
+        if ((!m_pattern.m_body->m_hasFixedSize || m_pattern.m_body->m_alternatives.size() > 1)
+                && setupDisjunctionBeginTerms(m_pattern.m_body, &beginTerms, 0)) {
+            unsigned size = beginTerms.size();
+
+            // If we haven't collected any terms we should abort the preparation of beginning character look-up optimization.
+            if (!size)
+                return;
+
+            m_pattern.m_containsBeginChars = true;
+
+            for (unsigned i = 0; i < size; i++) {
+                PatternTerm term = beginTerms[i].term;
+
+                // We have just collected PatternCharacter terms, other terms are not allowed.
+                ASSERT(term.type == PatternTerm::TypePatternCharacter);
+
+                if (term.quantityType == QuantifierFixedCount)
+                    containsFixedCharacter = true;
+
+                UChar character = term.patternCharacter;
+                unsigned mask = 0;
+
+                if (character <= 0x7f) {
+                    if (m_pattern.m_ignoreCase && isASCIIAlpha(character)) {
+                        mask = 32;
+                        character = toASCIILower(character);
+                    }
+
+                    m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount);
+                } else {
+                    UChar upper, lower;
+                    if (m_pattern.m_ignoreCase && ((upper = Unicode::toUpper(character)) != (lower = Unicode::toLower(character)))) {
+                        m_beginCharHelper.addBeginChar(BeginChar(upper, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount);
+                        m_beginCharHelper.addBeginChar(BeginChar(lower, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount);
+                    } else
+                        m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount);
+                }
+            }
+
+            // If the pattern doesn't contain terms with fixed quantifiers then the beginning character look-up optimization is inefficient.
+            if (!containsFixedCharacter) {
+                m_pattern.m_containsBeginChars = false;
+                return;
+            }
+
+            size = m_pattern.m_beginChars.size();
+
+            if (size > 2)
+                m_beginCharHelper.merge(size - 1);
+            else if (size <= 1)
+                m_pattern.m_containsBeginChars = false;
+        }
+    }
+
 private:
-    RegexPattern& m_pattern;
+    YarrPattern& m_pattern;
     PatternAlternative* m_alternative;
     CharacterClassConstructor m_characterClassConstructor;
+    BeginCharHelper m_beginCharHelper;
     bool m_invertCharacterClass;
+    bool m_invertParentheticalAssertion;
 };
 
-
-int compileRegex(const UString& patternString, RegexPattern& pattern)
+ErrorCode YarrPattern::compile(const UString& patternString)
 {
-    RegexPatternConstructor constructor(pattern);
+    YarrPatternConstructor constructor(*this);
 
-    if (int error = parse(constructor, patternString))
+    if (ErrorCode error = parse(constructor, patternString))
         return error;
     
     // If the pattern contains illegal backreferences reset & reparse.
     // Quoting Netscape's "What's new in JavaScript 1.2",
     //      "Note: if the number of left parentheses is less than the number specified
     //       in \#, the \# is taken as an octal escape as described in the next row."
-    if (pattern.containsIllegalBackReference()) {
-        unsigned numSubpatterns = pattern.m_numSubpatterns;
+    if (containsIllegalBackReference()) {
+        unsigned numSubpatterns = m_numSubpatterns;
 
         constructor.reset();
-#ifdef DEBUG
-        int error =
+#if !ASSERT_DISABLED
+        ErrorCode error =
 #endif
             parse(constructor, patternString, numSubpatterns);
 
-        JS_ASSERT(!error);
-        JS_ASSERT(numSubpatterns == pattern.m_numSubpatterns);
+        ASSERT(!error);
+        ASSERT(numSubpatterns == m_numSubpatterns);
     }
 
     constructor.checkForTerminalParentheses();
+    constructor.optimizeBOL();
+        
     constructor.setupOffsets();
+    constructor.setupBeginChars();
 
-    return 0;
+    return NoError;
 }
 
+YarrPattern::YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error)
+    : m_ignoreCase(ignoreCase)
+    , m_multiline(multiline)
+    , m_containsBackreferences(false)
+    , m_containsBeginChars(false)
+    , m_containsBOL(false)
+    , m_numSubpatterns(0)
+    , m_maxBackReference(0)
+    , newlineCached(0)
+    , digitsCached(0)
+    , spacesCached(0)
+    , wordcharCached(0)
+    , nondigitsCached(0)
+    , nonspacesCached(0)
+    , nonwordcharCached(0)
+{
+    *error = compile(pattern);
+}
 
 } }
diff --git a/js/src/yarr/yarr/RegexPattern.h b/js/src/yarr/YarrPattern.h
similarity index 70%
rename from js/src/yarr/yarr/RegexPattern.h
rename to js/src/yarr/YarrPattern.h
index 9d9b286a653e..38ae10fcf289 100644
--- a/js/src/yarr/yarr/RegexPattern.h
+++ b/js/src/yarr/YarrPattern.h
@@ -1,5 +1,9 @@
-/*
+/* -*- 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
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -21,26 +25,32 @@
  * 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 RegexPattern_h
-#define RegexPattern_h
-
-#include "jsvector.h"
-#include "yarr/jswtfbridge.h"
-#include "yarr/yarr/RegexCommon.h"
+#ifndef YarrPattern_h
+#define YarrPattern_h
 
+#include "wtfbridge.h"
+#include "ASCIICType.h"
 
 namespace JSC { namespace Yarr {
 
-#define RegexStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoBackReference 2
-#define RegexStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
-#define RegexStackSpaceForBackTrackInfoParentheticalAssertion 1
-#define RegexStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
-#define RegexStackSpaceForBackTrackInfoParenthesesTerminal 1
-#define RegexStackSpaceForBackTrackInfoParentheses 4
+enum ErrorCode {
+    NoError,
+    PatternTooLarge,
+    QuantifierOutOfOrder,
+    QuantifierWithoutAtom,
+    MissingParentheses,
+    ParenthesesUnmatched,
+    ParenthesesTypeInvalid,
+    CharacterClassUnmatched,
+    CharacterClassInvalidRange,
+    CharacterClassOutOfOrder,
+    EscapeUnterminated,
+    QuantifierTooLarge,
+    NumberOfErrorCodes
+};
 
 struct PatternDisjunction;
 
@@ -55,60 +65,42 @@ struct CharacterRange {
     }
 };
 
-/*
- * Wraps a table and indicates inversion. Can be efficiently borrowed
- * between character classes, so it's refcounted.
- */
-struct CharacterClassTable {
-
-    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
-
+struct CharacterClassTable : RefCounted {
+    friend class js::OffTheBooks;
     const char* m_table;
     bool m_inverted;
-    jsrefcount m_refcount;
-
-    /* Ownership transferred to caller. */
-    static CharacterClassTable *create(const char* table, bool inverted)
+    static PassRefPtr create(const char* table, bool inverted)
     {
-        // FIXME: bug 574459 -- no NULL checks done by any of the callers, all
-        // of which are in RegExpJitTables.h.
-        return js::OffTheBooks::new_(table, inverted);
+        return adoptRef(js::OffTheBooks::new_(table, inverted));
     }
 
-    void incref() { JS_ATOMIC_INCREMENT(&m_refcount); }
-    void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js::Foreground::delete_(this); }
-
 private:
     CharacterClassTable(const char* table, bool inverted)
         : m_table(table)
         , m_inverted(inverted)
-        , m_refcount(0)
     {
     }
 };
 
 struct CharacterClass {
+    WTF_MAKE_FAST_ALLOCATED
+public:
     // All CharacterClass instances have to have the full set of matches and ranges,
     // they may have an optional table for faster lookups (which must match the
     // specified matches and ranges)
-    CharacterClass(CharacterClassTable *table)
+    CharacterClass(PassRefPtr table)
         : m_table(table)
     {
-        if (m_table)
-            m_table->incref();
     }
     ~CharacterClass()
     {
-        if (m_table)
-            m_table->decref();
+        js::Foreground::delete_(m_table.get());
     }
-    typedef js::Vector UChars;
-    typedef js::Vector CharacterRanges;
-    UChars m_matches;
-    CharacterRanges m_ranges;
-    UChars m_matchesUnicode;
-    CharacterRanges m_rangesUnicode;
-    CharacterClassTable *m_table;
+    Vector m_matches;
+    Vector m_ranges;
+    Vector m_matchesUnicode;
+    Vector m_rangesUnicode;
+    RefPtr m_table;
 };
 
 enum QuantifierType {
@@ -129,11 +121,12 @@ struct PatternTerm {
         TypeParenthesesSubpattern,
         TypeParentheticalAssertion
     } type;
-    bool invertOrCapture;
+    bool m_capture :1;
+    bool m_invert :1;
     union {
         UChar patternCharacter;
         CharacterClass* characterClass;
-        unsigned subpatternId;
+        unsigned backReferenceSubpatternId;
         struct {
             PatternDisjunction* disjunction;
             unsigned subpatternId;
@@ -147,8 +140,21 @@ struct PatternTerm {
     int inputPosition;
     unsigned frameLocation;
 
+    // No-argument constructor for js::Vector.
+    PatternTerm()
+        : type(PatternTerm::TypePatternCharacter)
+        , m_capture(false)
+        , m_invert(false)
+    {
+        patternCharacter = 0;
+        quantityType = QuantifierFixedCount;
+        quantityCount = 1;
+    }
+
     PatternTerm(UChar ch)
         : type(PatternTerm::TypePatternCharacter)
+        , m_capture(false)
+        , m_invert(false)
     {
         patternCharacter = ch;
         quantityType = QuantifierFixedCount;
@@ -157,16 +163,18 @@ struct PatternTerm {
 
     PatternTerm(CharacterClass* charClass, bool invert)
         : type(PatternTerm::TypeCharacterClass)
-        , invertOrCapture(invert)
+        , m_capture(false)
+        , m_invert(invert)
     {
         characterClass = charClass;
         quantityType = QuantifierFixedCount;
         quantityCount = 1;
     }
 
-    PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool invertOrCapture)
+    PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false)
         : type(type)
-        , invertOrCapture(invertOrCapture)
+        , m_capture(capture)
+        , m_invert(invert)
     {
         parentheses.disjunction = disjunction;
         parentheses.subpatternId = subpatternId;
@@ -178,7 +186,8 @@ struct PatternTerm {
     
     PatternTerm(Type type, bool invert = false)
         : type(type)
-        , invertOrCapture(invert)
+        , m_capture(false)
+        , m_invert(invert)
     {
         quantityType = QuantifierFixedCount;
         quantityCount = 1;
@@ -186,9 +195,10 @@ struct PatternTerm {
 
     PatternTerm(unsigned spatternId)
         : type(TypeBackReference)
-        , invertOrCapture(false)
+        , m_capture(false)
+        , m_invert(false)
     {
-        subpatternId = spatternId;
+        backReferenceSubpatternId = spatternId;
         quantityType = QuantifierFixedCount;
         quantityCount = 1;
     }
@@ -215,12 +225,12 @@ struct PatternTerm {
     
     bool invert()
     {
-        return invertOrCapture;
+        return m_invert;
     }
 
     bool capture()
     {
-        return invertOrCapture;
+        return m_capture;
     }
     
     void quantify(unsigned count, QuantifierType type)
@@ -231,9 +241,8 @@ struct PatternTerm {
 };
 
 struct PatternAlternative {
-
-    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
-
+    WTF_MAKE_FAST_ALLOCATED
+public:
     PatternAlternative(PatternDisjunction* disjunction)
         : m_parent(disjunction)
         , m_onceThrough(false)
@@ -245,14 +254,14 @@ struct PatternAlternative {
 
     PatternTerm& lastTerm()
     {
-        JS_ASSERT(m_terms.length());
-        return m_terms[m_terms.length() - 1];
+        ASSERT(m_terms.size());
+        return m_terms[m_terms.size() - 1];
     }
     
     void removeLastTerm()
     {
-        JS_ASSERT(m_terms.length());
-        m_terms.popBack();
+        ASSERT(m_terms.size());
+        m_terms.shrink(m_terms.size() - 1);
     }
     
     void setOnceThrough()
@@ -265,7 +274,7 @@ struct PatternAlternative {
         return m_onceThrough;
     }
 
-    js::Vector m_terms;
+    Vector m_terms;
     PatternDisjunction* m_parent;
     unsigned m_minimumSize;
     bool m_onceThrough : 1;
@@ -274,18 +283,9 @@ struct PatternAlternative {
     bool m_containsBOL : 1;
 };
 
-template
-static inline void
-deleteAllValues(js::Vector &vector)
-{
-    for (T** t = vector.begin(); t < vector.end(); ++t)
-        js::Foreground::delete_(*t);
-}
-
 struct PatternDisjunction {
-
-    JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
-
+    WTF_MAKE_FAST_ALLOCATED
+public:
     PatternDisjunction(PatternAlternative* parent = 0)
         : m_parent(parent)
         , m_hasFixedSize(false)
@@ -299,13 +299,12 @@ struct PatternDisjunction {
 
     PatternAlternative* addNewAlternative()
     {
-        // FIXME: bug 574459 -- no NULL check
         PatternAlternative* alternative = js::OffTheBooks::new_(this);
         m_alternatives.append(alternative);
         return alternative;
     }
 
-    js::Vector m_alternatives;
+    Vector m_alternatives;
     PatternAlternative* m_parent;
     unsigned m_minimumSize;
     unsigned m_callFrameSize;
@@ -314,7 +313,7 @@ struct PatternDisjunction {
 
 // You probably don't want to be calling these functions directly
 // (please to be calling newlineCharacterClass() et al on your
-// friendly neighborhood RegexPattern instance to get nicely
+// friendly neighborhood YarrPattern instance to get nicely
 // cached copies).
 CharacterClass* newlineCreate();
 CharacterClass* digitsCreate();
@@ -324,25 +323,34 @@ CharacterClass* nondigitsCreate();
 CharacterClass* nonspacesCreate();
 CharacterClass* nonwordcharCreate();
 
-struct RegexPattern {
-    RegexPattern(bool ignoreCase, bool multiline)
-        : m_ignoreCase(ignoreCase)
-        , m_multiline(multiline)
-        , m_containsBackreferences(false)
-        , m_containsBOL(false)
-        , m_numSubpatterns(0)
-        , m_maxBackReference(0)
-        , newlineCached(0)
-        , digitsCached(0)
-        , spacesCached(0)
-        , wordcharCached(0)
-        , nondigitsCached(0)
-        , nonspacesCached(0)
-        , nonwordcharCached(0)
-    {
-    }
+struct TermChain {
+    TermChain(PatternTerm term)
+        : term(term)
+    {}
 
-    ~RegexPattern()
+    PatternTerm term;
+    Vector hotTerms;
+};
+
+struct BeginChar {
+    BeginChar()
+        : value(0)
+        , mask(0)
+    {}
+
+    BeginChar(unsigned value, unsigned mask)
+        : value(value)
+        , mask(mask)
+    {}
+
+    unsigned value;
+    unsigned mask;
+};
+
+struct YarrPattern {
+    YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error);
+
+    ~YarrPattern()
     {
         deleteAllValues(m_disjunctions);
         deleteAllValues(m_userCharacterClasses);
@@ -354,6 +362,7 @@ struct RegexPattern {
         m_maxBackReference = 0;
 
         m_containsBackreferences = false;
+        m_containsBeginChars = false;
         m_containsBOL = false;
 
         newlineCached = 0;
@@ -368,6 +377,7 @@ struct RegexPattern {
         m_disjunctions.clear();
         deleteAllValues(m_userCharacterClasses);
         m_userCharacterClasses.clear();
+        m_beginChars.clear();
     }
 
     bool containsIllegalBackReference()
@@ -418,19 +428,21 @@ struct RegexPattern {
         return nonwordcharCached;
     }
 
-    typedef js::Vector PatternDisjunctions;
-    typedef js::Vector CharacterClasses;
     bool m_ignoreCase : 1;
     bool m_multiline : 1;
     bool m_containsBackreferences : 1;
+    bool m_containsBeginChars : 1;
     bool m_containsBOL : 1;
     unsigned m_numSubpatterns;
     unsigned m_maxBackReference;
-    PatternDisjunction *m_body;
-    PatternDisjunctions m_disjunctions;
-    CharacterClasses m_userCharacterClasses;
+    PatternDisjunction* m_body;
+    Vector m_disjunctions;
+    Vector m_userCharacterClasses;
+    Vector m_beginChars;
 
 private:
+    ErrorCode compile(const UString& patternString);
+
     CharacterClass* newlineCached;
     CharacterClass* digitsCached;
     CharacterClass* spacesCached;
@@ -442,4 +454,4 @@ private:
 
 } } // namespace JSC::Yarr
 
-#endif // RegexPattern_h
+#endif // YarrPattern_h
diff --git a/js/src/yarr/yarr/RegexCommon.h b/js/src/yarr/YarrSyntaxChecker.cpp
similarity index 52%
rename from js/src/yarr/yarr/RegexCommon.h
rename to js/src/yarr/YarrSyntaxChecker.cpp
index 3ae337ea62cc..f36ac5a3f5bc 100644
--- a/js/src/yarr/yarr/RegexCommon.h
+++ b/js/src/yarr/YarrSyntaxChecker.cpp
@@ -1,5 +1,8 @@
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+/* -*- 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) 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
@@ -21,30 +24,39 @@
  * 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 RegexCommon_h
-#define RegexCommon_h
+#include "YarrSyntaxChecker.h"
+
+#include "YarrParser.h"
 
 namespace JSC { namespace Yarr {
 
-enum ErrorCode {
-    HitRecursionLimit = -2,
-    NoError = 0,
-    PatternTooLarge,
-    QuantifierOutOfOrder,
-    QuantifierWithoutAtom,
-    MissingParentheses,
-    ParenthesesUnmatched,
-    ParenthesesTypeInvalid,
-    CharacterClassUnmatched,
-    CharacterClassOutOfOrder,
-    CharacterClassRangeSingleChar,
-    EscapeUnterminated,
-    QuantifierTooLarge,
-    NumberOfErrorCodes
+class SyntaxChecker {
+public:
+    void assertionBOL() {}
+    void assertionEOL() {}
+    void assertionWordBoundary(bool) {}
+    void atomPatternCharacter(UChar) {}
+    void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) {}
+    void atomCharacterClassBegin(bool = false) {}
+    void atomCharacterClassAtom(UChar) {}
+    void atomCharacterClassRange(UChar, UChar) {}
+    void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) {}
+    void atomCharacterClassEnd() {}
+    void atomParenthesesSubpatternBegin(bool = true) {}
+    void atomParentheticalAssertionBegin(bool = false) {}
+    void atomParenthesesEnd() {}
+    void atomBackReference(unsigned) {}
+    void quantifyAtom(unsigned, unsigned, bool) {}
+    void disjunction() {}
 };
 
-}}
+ErrorCode checkSyntax(const UString& pattern)
+{
+    SyntaxChecker syntaxChecker;
+    return parse(syntaxChecker, pattern);
+}
 
-#endif
+}} // JSC::YARR
diff --git a/js/src/yarr/yarr/RegexCompiler.h b/js/src/yarr/YarrSyntaxChecker.h
similarity index 74%
rename from js/src/yarr/yarr/RegexCompiler.h
rename to js/src/yarr/YarrSyntaxChecker.h
index 307c15866e59..87f2ed5093b0 100644
--- a/js/src/yarr/yarr/RegexCompiler.h
+++ b/js/src/yarr/YarrSyntaxChecker.h
@@ -1,5 +1,8 @@
-/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+/* -*- 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) 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
@@ -21,18 +24,20 @@
  * 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 RegexCompiler_h
-#define RegexCompiler_h
+#ifndef YarrSyntaxChecker_h
+#define YarrSyntaxChecker_h
 
-#include "RegexParser.h"
-#include "RegexPattern.h"
+#include "wtfbridge.h"
+#include "YarrParser.h"
 
 namespace JSC { namespace Yarr {
 
-int compileRegex(const UString& patternString, RegexPattern& pattern);
+ErrorCode checkSyntax(const UString& pattern);
 
-} } // namespace JSC::Yarr
+}} // JSC::YARR
+
+#endif // YarrSyntaxChecker_h
 
-#endif // RegexCompiler_h
diff --git a/js/src/yarr/jswtfbridge.h b/js/src/yarr/jswtfbridge.h
deleted file mode 100644
index b38f76ead5a8..000000000000
--- a/js/src/yarr/jswtfbridge.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- 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 *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
- * June 12, 2009.
- *
- * The Initial Developer of the Original Code is
- *   the Mozilla Corporation.
- *
- * Contributor(s):
- *   Chris Leary 
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef jswtfbridge_h__
-#define jswtfbridge_h__
-
-/*
- * The JS/WTF Bridge to Bona-fide Quality.
- */
-
-#include "assembler/wtf/Platform.h"
-#include "jsstr.h"
-#include "jsprvtd.h"
-#include "jstl.h"
-
-typedef jschar UChar;
-typedef JSLinearString UString;
-
-class Unicode {
-  public:
-    static UChar toUpper(UChar c) { return JS_TOUPPER(c); }
-    static UChar toLower(UChar c) { return JS_TOLOWER(c); }
-};
-
-#endif
diff --git a/js/src/yarr/pcre/AUTHORS b/js/src/yarr/pcre/AUTHORS
deleted file mode 100644
index dbac2a54834b..000000000000
--- a/js/src/yarr/pcre/AUTHORS
+++ /dev/null
@@ -1,12 +0,0 @@
-Originally written by:  Philip Hazel
-Email local part:       ph10
-Email domain:           cam.ac.uk
-
-University of Cambridge Computing Service,
-Cambridge, England. Phone: +44 1223 334714.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Adapted for JavaScriptCore and WebKit by Apple Inc.
-
-Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/js/src/yarr/pcre/COPYING b/js/src/yarr/pcre/COPYING
deleted file mode 100644
index 6ffdc24342d5..000000000000
--- a/js/src/yarr/pcre/COPYING
+++ /dev/null
@@ -1,35 +0,0 @@
-PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
-This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-    * Redistributions of source code must retain the above copyright notice,
-      this list of conditions and the following disclaimer.
-
-    * 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.
-
-    * Neither the name of the University of Cambridge nor the name of Apple
-      Inc. nor the names of their contributors may be used to endorse or
-      promote products derived from this software without specific prior
-      written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
diff --git a/js/src/yarr/pcre/chartables.c b/js/src/yarr/pcre/chartables.c
deleted file mode 100644
index 5c99db0b980f..000000000000
--- a/js/src/yarr/pcre/chartables.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*************************************************
-*      Perl-Compatible Regular Expressions       *
-*************************************************/
-
-/* This file is automatically written by the dftables auxiliary 
-program. If you edit it by hand, you might like to edit the Makefile to 
-prevent its ever being regenerated.
-
-This file contains the default tables for characters with codes less than
-128 (ASCII characters). These tables are used when no external tables are
-passed to PCRE. */
-
-const unsigned char jsc_pcre_default_tables[480] = {
-
-/* This table is a lower casing table. */
-
-  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
-  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
-  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
-  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
-  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
-  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
-  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
-  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
-  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
-  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
-  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
-  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
-  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
-  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
-  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
-  0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
-
-/* This table is a case flipping table. */
-
-  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
-  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
-  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
-  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
-  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
-  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
-  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
-  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
-  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
-  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
-  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
-  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
-  0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
-  0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 
-  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
-  0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
-
-/* This table contains bit maps for various character classes.
-Each map is 32 bytes long and the bits run from the least
-significant end of each byte. The classes are: space, digit, word. */
-
-  0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
-  0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-/* This table identifies various classes of character by individual bits:
-  0x01   white space character
-  0x08   hexadecimal digit
-  0x10   alphanumeric or '_'
-*/
-
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*   0-  7 */
-  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /*   8- 15 */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  16- 23 */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  24- 31 */
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*    - '  */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  ( - /  */
-  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,  /*  0 - 7  */
-  0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  8 - ?  */
-  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  @ - G  */
-  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  H - O  */
-  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  P - W  */
-  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,  /*  X - _  */
-  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  ` - g  */
-  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  h - o  */
-  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  p - w  */
-  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /*  x -127 */
-
-
-/* End of chartables.c */
diff --git a/js/src/yarr/pcre/dftables b/js/src/yarr/pcre/dftables
deleted file mode 100644
index 669b948ffc91..000000000000
--- a/js/src/yarr/pcre/dftables
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/usr/bin/perl -w
-#
-# This is JavaScriptCore's variant of the PCRE library. While this library
-# started out as a copy of PCRE, many of the features of PCRE have been
-# removed. This library now supports only the regular expression features
-# required by the JavaScript language specification, and has only the functions
-# needed by JavaScriptCore and the rest of WebKit.
-# 
-#                  Originally written by Philip Hazel
-#            Copyright (c) 1997-2006 University of Cambridge
-#  Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
-# 
-#     * Redistributions of source code must retain the above copyright notice,
-#       this list of conditions and the following disclaimer.
-# 
-#     * 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.
-# 
-#     * Neither the name of the University of Cambridge nor the names of its
-#       contributors may be used to endorse or promote products derived from
-#       this software without specific prior written permission.
-# 
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
-# -----------------------------------------------------------------------------
-
-# This is a freestanding support program to generate a file containing
-# character tables. The tables are built according to the default C
-# locale.
-
-use strict;
-
-use File::Basename;
-use File::Spec;
-use File::Temp qw(tempfile);
-use Getopt::Long;
-
-sub readHeaderValues();
-
-my %pcre_internal;
-
-if (scalar(@ARGV) < 1) {
-    print STDERR "Usage: ", basename($0), " [--preprocessor=program] output-file\n";
-    exit 1;
-}
-
-my $outputFile;
-my $preprocessor;
-GetOptions('preprocessor=s' => \$preprocessor);
-if (not $preprocessor) {
-    $preprocessor = "cpp";
-}
-
-$outputFile = $ARGV[0];
-die('Must specify output file.') unless defined($outputFile);
-
-readHeaderValues();
-
-open(OUT, ">", $outputFile) or die "$!";
-binmode(OUT);
-
-printf(OUT
-    "/*************************************************\n" .
-    "*      Perl-Compatible Regular Expressions       *\n" .
-    "*************************************************/\n\n" .
-    "/* This file is automatically written by the dftables auxiliary \n" .
-    "program. If you edit it by hand, you might like to edit the Makefile to \n" .
-    "prevent its ever being regenerated.\n\n");
-printf(OUT
-    "This file contains the default tables for characters with codes less than\n" .
-    "128 (ASCII characters). These tables are used when no external tables are\n" .
-    "passed to PCRE. */\n\n" .
-    "const unsigned char jsc_pcre_default_tables[%d] = {\n\n" .
-    "/* This table is a lower casing table. */\n\n", $pcre_internal{tables_length});
-
-if ($pcre_internal{lcc_offset} != 0) {
-    die "lcc_offset != 0";
-}
-
-printf(OUT "  ");
-for (my $i = 0; $i < 128; $i++) {
-    if (($i & 7) == 0 && $i != 0) {
-        printf(OUT "\n  ");
-    }
-    printf(OUT "0x%02X", ord(lc(chr($i))));
-    if ($i != 127) {
-        printf(OUT ", ");
-    }
-}
-printf(OUT ",\n\n");
-
-printf(OUT "/* This table is a case flipping table. */\n\n");
-
-if ($pcre_internal{fcc_offset} != 128) {
-  die "fcc_offset != 128";
-}
-
-printf(OUT "  ");
-for (my $i = 0; $i < 128; $i++) {
-    if (($i & 7) == 0 && $i != 0) {
-        printf(OUT "\n  ");
-    }
-    my $c = chr($i);
-    printf(OUT "0x%02X", $c =~ /[[:lower:]]/ ? ord(uc($c)) : ord(lc($c)));
-    if ($i != 127) {
-        printf(OUT ", ");
-    }
-}
-printf(OUT ",\n\n");
-
-printf(OUT
-    "/* This table contains bit maps for various character classes.\n" .
-    "Each map is 32 bytes long and the bits run from the least\n" .
-    "significant end of each byte. The classes are: space, digit, word. */\n\n");
-
-if ($pcre_internal{cbits_offset} != $pcre_internal{fcc_offset} + 128) {
-    die "cbits_offset != fcc_offset + 128";
-}
-
-my @cbit_table = (0) x $pcre_internal{cbit_length};
-for (my $i = ord('0'); $i <= ord('9'); $i++) {
-    $cbit_table[$pcre_internal{cbit_digit} + $i / 8] |= 1 << ($i & 7);
-}
-$cbit_table[$pcre_internal{cbit_word} + ord('_') / 8] |= 1 << (ord('_') & 7);
-for (my $i = 0; $i < 128; $i++) {
-    my $c = chr($i);
-    if ($c =~ /[[:alnum:]]/) {
-        $cbit_table[$pcre_internal{cbit_word} + $i / 8] |= 1 << ($i & 7);
-    }
-    if ($c =~ /[[:space:]]/) {
-        $cbit_table[$pcre_internal{cbit_space} + $i / 8] |= 1 << ($i & 7);
-    }
-}
-
-printf(OUT "  ");
-for (my $i = 0; $i < $pcre_internal{cbit_length}; $i++) {
-    if (($i & 7) == 0 && $i != 0) {
-        if (($i & 31) == 0) {
-            printf(OUT "\n");
-        }
-        printf(OUT "\n  ");
-    }
-    printf(OUT "0x%02X", $cbit_table[$i]);
-    if ($i != $pcre_internal{cbit_length} - 1) {
-        printf(OUT ", ");
-    }
-}
-printf(OUT ",\n\n");
-
-printf(OUT
-    "/* This table identifies various classes of character by individual bits:\n" .
-    "  0x%02x   white space character\n" .
-    "  0x%02x   hexadecimal digit\n" .
-    "  0x%02x   alphanumeric or '_'\n*/\n\n",
-    $pcre_internal{ctype_space}, $pcre_internal{ctype_xdigit}, $pcre_internal{ctype_word});
-
-if ($pcre_internal{ctypes_offset} != $pcre_internal{cbits_offset} + $pcre_internal{cbit_length}) {
-    die "ctypes_offset != cbits_offset + cbit_length";
-}
-
-printf(OUT "  ");
-for (my $i = 0; $i < 128; $i++) {
-    my $x = 0;
-    my $c = chr($i);
-    if ($c =~ /[[:space:]]/) {
-        $x += $pcre_internal{ctype_space};
-    }
-    if ($c =~ /[[:xdigit:]]/) {
-        $x += $pcre_internal{ctype_xdigit};
-    }
-    if ($c =~ /[[:alnum:]_]/) {
-        $x += $pcre_internal{ctype_word};
-    }
-    printf(OUT "0x%02X", $x);
-    if ($i != 127) {
-        printf(OUT ", ");
-    } else {
-        printf(OUT "};");
-    }
-    if (($i & 7) == 7) {
-        printf(OUT " /* ");
-        my $d = chr($i - 7);
-        if ($d =~ /[[:print:]]/) {
-            printf(OUT " %c -", $i - 7);
-        } else {
-            printf(OUT "%3d-", $i - 7);
-        }
-        if ($c =~ m/[[:print:]]/) {
-            printf(OUT " %c ", $i);
-        } else {
-            printf(OUT "%3d", $i);
-        }
-        printf(OUT " */\n");
-        if ($i != 127) {
-            printf(OUT "  ");
-        }
-    }
-}
-
-if ($pcre_internal{tables_length} != $pcre_internal{ctypes_offset} + 128) {
-    die "tables_length != ctypes_offset + 128";
-}
-
-printf(OUT "\n\n/* End of chartables.c */\n");
-
-close(OUT);
-
-exit 0;
-
-sub readHeaderValues()
-{
-    my @variables = qw(
-        cbit_digit
-        cbit_length
-        cbit_space
-        cbit_word
-        cbits_offset
-        ctype_space
-        ctype_word
-        ctype_xdigit
-        ctypes_offset
-        fcc_offset
-        lcc_offset
-        tables_length
-    );
-
-    local $/ = undef;
-
-    my $headerPath = File::Spec->catfile(dirname($0), "pcre_internal.h");
- 
-    my ($fh, $tempFile) = tempfile(
-        basename($0) . "-XXXXXXXX",
-        DIR => File::Spec->tmpdir(),
-        SUFFIX => ".in",
-        UNLINK => 0,
-    );
-
-    print $fh "#define DFTABLES\n\n";
-
-    open(HEADER, "<", $headerPath) or die "$!";
-    print $fh 
; - close(HEADER); - - print $fh "\n\n"; - - for my $v (@variables) { - print $fh "\$pcre_internal{\"$v\"} = $v;\n"; - } - - close($fh); - - open(CPP, "$preprocessor \"$tempFile\" |") or die "$!"; - my $content = ; - close(CPP); - - eval $content; - die "$@" if $@; - unlink $tempFile; -} diff --git a/js/src/yarr/pcre/pcre.h b/js/src/yarr/pcre/pcre.h deleted file mode 100644 index 91d96b784905..000000000000 --- a/js/src/yarr/pcre/pcre.h +++ /dev/null @@ -1,68 +0,0 @@ -/* This is the public header file for JavaScriptCore's variant of the PCRE -library. While this library started out as a copy of PCRE, many of the -features of PCRE have been removed. This library now supports only the -regular expression features required by the JavaScript language -specification, and has only the functions needed by JavaScriptCore and the -rest of WebKit. - - Copyright (c) 1997-2005 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE. - -#ifndef JSRegExp_h -#define JSRegExp_h - -#include "yarr/jswtfbridge.h" - -struct JSRegExp; -struct JSContext; - -enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase }; -enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline }; - -/* jsRegExpExecute error codes */ -const int JSRegExpErrorNoMatch = -1; -const int JSRegExpErrorHitLimit = -2; -const int JSRegExpErrorInternal = -4; - -JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, - JSRegExpIgnoreCaseOption, JSRegExpMultilineOption, - unsigned* numSubpatterns, int *error); - -int jsRegExpExecute(JSContext *, const JSRegExp*, - const UChar* subject, int subjectLength, int startOffset, - int* offsetsVector, int offsetsVectorLength); - -void jsRegExpFree(JSRegExp*); - -#endif diff --git a/js/src/yarr/pcre/pcre.pri b/js/src/yarr/pcre/pcre.pri deleted file mode 100644 index 4f59e17f4d91..000000000000 --- a/js/src/yarr/pcre/pcre.pri +++ /dev/null @@ -1,12 +0,0 @@ -# Perl Compatible Regular Expressions - Qt4 build info -VPATH += $$PWD -INCLUDEPATH += $$PWD $$OUTPUT_DIR/JavaScriptCore/tmp -DEPENDPATH += $$PWD - -SOURCES += \ - pcre_compile.cpp \ - pcre_exec.cpp \ - pcre_tables.cpp \ - pcre_ucp_searchfuncs.cpp \ - pcre_xclass.cpp - diff --git a/js/src/yarr/pcre/pcre_compile.cpp b/js/src/yarr/pcre/pcre_compile.cpp deleted file mode 100644 index 8d273bcbe5a6..000000000000 --- a/js/src/yarr/pcre/pcre_compile.cpp +++ /dev/null @@ -1,2702 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - Copyright (C) 2007 Eric Seidel - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains the external function jsRegExpExecute(), along with -supporting internal functions that are not used by other modules. */ - -#include "pcre_internal.h" - -#include -#include "yarr/wtf/ASCIICType.h" -#include "jsvector.h" - -using namespace WTF; - -/* Negative values for the firstchar and reqchar variables */ - -#define REQ_UNSET (-2) -#define REQ_NONE (-1) - -/************************************************* -* Code parameters and static tables * -*************************************************/ - -/* Maximum number of items on the nested bracket stacks at compile time. This -applies to the nesting of all kinds of parentheses. It does not limit -un-nested, non-capturing parentheses. This number can be made bigger if -necessary - it is used to dimension one int and one unsigned char vector at -compile time. */ - -#define BRASTACK_SIZE 200 - -/* Table for handling escaped characters in the range '0'-'z'. Positive returns -are simple data values; negative values are for special things like \d and so -on. Zero means further processing is needed (for things like \x), or the escape -is invalid. */ - -static const short escapes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ - 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ - '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ - 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ - 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ - 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */ - '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */ - 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */ - 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */ - 0, 0, 0 /* x - z */ -}; -static const unsigned OPCODE_LEN = 1; -static const unsigned BRAZERO_LEN = OPCODE_LEN; -static const unsigned BRA_NEST_SIZE = 2; -static const unsigned BRA_LEN = OPCODE_LEN + LINK_SIZE + BRA_NEST_SIZE; -static const unsigned KET_LEN = OPCODE_LEN + LINK_SIZE; - -/* Error code numbers. They are given names so that they can more easily be -tracked. */ - -enum ErrorCode { - ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, - ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17 -}; - -/* These are the error texts that correspond to the above error codes: - // 1 - "\\ at end of pattern\0" - "\\c at end of pattern\0" - "character value in \\x{...} sequence is too large\0" - "numbers out of order in {} quantifier\0" - // 5 - "number too big in {} quantifier\0" - "missing terminating ] for character class\0" - "internal error: code overflow\0" - "range out of order in character class\0" - "nothing to repeat\0" - // 10 - "unmatched parentheses\0" - "internal error: unexpected repeat\0" - "unrecognized character after (?\0" - "failed to get memory\0" - "missing )\0" - // 15 - "reference to non-existent subpattern\0" - "regular expression too large\0" - "parentheses nested too deeply" */ - -/* Structure for passing "static" information around between the functions -doing the compiling. */ - -struct CompileData { - CompileData() { - topBackref = 0; - backrefMap = 0; - reqVaryOpt = 0; - needOuterBracket = false; - numCapturingBrackets = 0; - } - int topBackref; /* Maximum back reference */ - unsigned backrefMap; /* Bitmap of low back refs */ - int reqVaryOpt; /* "After variable item" flag for reqByte */ - bool needOuterBracket; - int numCapturingBrackets; -}; - -/* Definitions to allow mutual recursion */ - -static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&); -static bool bracketIsAnchored(const unsigned char* code); -static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap); -static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert); - -/************************************************* -* Handle escapes * -*************************************************/ - -/* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \n, or a negative value which -encodes one of the more complicated things such as \d. When UTF-8 is enabled, -a positive value greater than 255 may be returned. On entry, ptr is pointing at -the \. On exit, it is on the final character of the escape sequence. - -Arguments: - ptrPtr points to the pattern position pointer - errorCodePtr points to the errorcode variable - bracount number of previous extracting brackets - options the options bits - isClass true if inside a character class - -Returns: zero or positive => a data character - negative => a special escape sequence - on error, error is set -*/ - -static int checkEscape(const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int bracount, bool isClass) -{ - const UChar* ptr = *ptrPtr + 1; - - /* If backslash is at the end of the pattern, it's an error. */ - if (ptr == patternEnd) { - *errorCodePtr = ERR1; - *ptrPtr = ptr; - return 0; - } - - int c = *ptr; - - /* Non-alphamerics are literals. For digits or letters, do an initial lookup in - a table. A non-zero result is something that can be returned immediately. - Otherwise further processing may be required. */ - - if (c < '0' || c > 'z') { /* Not alphameric */ - } else if (int escapeValue = escapes[c - '0']) { - c = escapeValue; - if (isClass) { - if (-c == ESC_b) - c = '\b'; /* \b is backslash in a class */ - else if (-c == ESC_B) - c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */ - } - /* Escapes that need further processing, or are illegal. */ - - } else { - switch (c) { - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - /* Escape sequences starting with a non-zero digit are backreferences, - unless there are insufficient brackets, in which case they are octal - escape sequences. Those sequences end on the first non-octal character - or when we overflow 0-255, whichever comes first. */ - - if (!isClass) { - const UChar* oldptr = ptr; - c -= '0'; - while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount) - c = c * 10 + *(++ptr) - '0'; - if (c <= bracount) { - c = -(ESC_REF + c); - break; - } - ptr = oldptr; /* Put the pointer back and fall through */ - } - - /* Handle an octal number following \. If the first digit is 8 or 9, - this is not octal. */ - - if ((c = *ptr) >= '8') { - c = '\\'; - ptr -= 1; - break; - } - - /* \0 always starts an octal number, but we may drop through to here with a - larger first octal digit. */ - - case '0': { - c -= '0'; - int i; - for (i = 1; i <= 2; ++i) { - if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7') - break; - int cc = c * 8 + ptr[i] - '0'; - if (cc > 255) - break; - c = cc; - } - ptr += i - 1; - break; - } - - case 'x': { - c = 0; - int i; - for (i = 1; i <= 2; ++i) { - if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { - c = 'x'; - i = 1; - break; - } - int cc = ptr[i]; - if (cc >= 'a') - cc -= 32; /* Convert to upper case */ - c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); - } - ptr += i - 1; - break; - } - - case 'u': { - c = 0; - int i; - for (i = 1; i <= 4; ++i) { - if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { - c = 'u'; - i = 1; - break; - } - int cc = ptr[i]; - if (cc >= 'a') - cc -= 32; /* Convert to upper case */ - c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); - } - ptr += i - 1; - break; - } - - case 'c': - if (++ptr == patternEnd) { - *errorCodePtr = ERR2; - return 0; - } - - c = *ptr; - - /* To match Firefox, inside a character class, we also accept - numbers and '_' as control characters */ - if ((!isClass && !isASCIIAlpha(c)) || (!isASCIIAlphanumeric(c) && c != '_')) { - c = '\\'; - ptr -= 2; - break; - } - - /* A letter is upper-cased; then the 0x40 bit is flipped. This coding - is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ - c = toASCIIUpper(c) ^ 0x40; - break; - } - } - - *ptrPtr = ptr; - return c; -} - -/************************************************* -* Check for counted repeat * -*************************************************/ - -/* This function is called when a '{' is encountered in a place where it might -start a quantifier. It looks ahead to see if it really is a quantifier or not. -It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} -where the ddds are digits. - -Arguments: - p pointer to the first char after '{' - -Returns: true or false -*/ - -static bool isCountedRepeat(const UChar* p, const UChar* patternEnd) -{ - if (p >= patternEnd || !isASCIIDigit(*p)) - return false; - p++; - while (p < patternEnd && isASCIIDigit(*p)) - p++; - if (p < patternEnd && *p == '}') - return true; - - if (p >= patternEnd || *p++ != ',') - return false; - if (p < patternEnd && *p == '}') - return true; - - if (p >= patternEnd || !isASCIIDigit(*p)) - return false; - p++; - while (p < patternEnd && isASCIIDigit(*p)) - p++; - - return (p < patternEnd && *p == '}'); -} - -/************************************************* -* Read repeat counts * -*************************************************/ - -/* Read an item of the form {n,m} and return the values. This is called only -after isCountedRepeat() has confirmed that a repeat-count quantifier exists, -so the syntax is guaranteed to be correct, but we need to check the values. - -Arguments: - p pointer to first char after '{' - minp pointer to int for min - maxp pointer to int for max - returned as -1 if no max - errorCodePtr points to error code variable - -Returns: pointer to '}' on success; - current ptr on error, with errorCodePtr set non-zero -*/ - -static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorCodePtr) -{ - int min = 0; - int max = -1; - - /* Read the minimum value and do a paranoid check: a negative value indicates - an integer overflow. */ - - while (isASCIIDigit(*p)) - min = min * 10 + *p++ - '0'; - if (min < 0 || min > 65535) { - *errorCodePtr = ERR5; - return p; - } - - /* Read the maximum value if there is one, and again do a paranoid on its size. - Also, max must not be less than min. */ - - if (*p == '}') - max = min; - else { - if (*(++p) != '}') { - max = 0; - while (isASCIIDigit(*p)) - max = max * 10 + *p++ - '0'; - if (max < 0 || max > 65535) { - *errorCodePtr = ERR5; - return p; - } - if (max < min) { - *errorCodePtr = ERR4; - return p; - } - } - } - - /* Fill in the required variables, and pass back the pointer to the terminating - '}'. */ - - *minp = min; - *maxp = max; - return p; -} - -/************************************************* -* Find first significant op code * -*************************************************/ - -/* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring op code etc. It skips over things -that do not influence this. - -Arguments: - code pointer to the start of the group -Returns: pointer to the first significant opcode -*/ - -static const unsigned char* firstSignificantOpcode(const unsigned char* code) -{ - while (*code == OP_BRANUMBER) - code += 3; - return code; -} - -static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code) -{ - while (true) { - switch (*code) { - case OP_ASSERT_NOT: - advanceToEndOfBracket(code); - code += 1 + LINK_SIZE; - break; - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - ++code; - break; - case OP_BRANUMBER: - code += 3; - break; - default: - return code; - } - } -} - -/************************************************* -* Get othercase range * -*************************************************/ - -/* This function is passed the start and end of a class range, in UTF-8 mode -with UCP support. It searches up the characters, looking for internal ranges of -characters in the "other" case. Each call returns the next one, updating the -start address. - -Arguments: - cptr points to starting character value; updated - d end value - ocptr where to put start of othercase range - odptr where to put end of othercase range - -Yield: true when range returned; false when no more -*/ - -static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr) -{ - int c, othercase = 0; - - for (c = *cptr; c <= d; c++) { - if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) - break; - } - - if (c > d) - return false; - - *ocptr = othercase; - int next = othercase + 1; - - for (++c; c <= d; c++) { - if (jsc_pcre_ucp_othercase(c) != next) - break; - next++; - } - - *odptr = next - 1; - *cptr = c; - - return true; -} - -/************************************************* - * Convert character value to UTF-8 * - *************************************************/ - -/* This function takes an integer value in the range 0 - 0x7fffffff - and encodes it as a UTF-8 character in 0 to 6 bytes. - - Arguments: - cvalue the character value - buffer pointer to buffer for result - at least 6 bytes long - - Returns: number of characters placed in the buffer - */ - -static int encodeUTF8(int cvalue, unsigned char *buffer) -{ - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (cvalue <= jsc_pcre_utf8_table1[i]) - break; - buffer += i; - for (int j = i; j > 0; j--) { - *buffer-- = 0x80 | (cvalue & 0x3f); - cvalue >>= 6; - } - *buffer = jsc_pcre_utf8_table2[i] | cvalue; - return i + 1; -} - -/************************************************* -* Compile one branch * -*************************************************/ - -/* Scan the pattern, compiling it into the code vector. - -Arguments: - options the option bits - brackets points to number of extracting brackets used - codePtr points to the pointer to the current code point - ptrPtr points to the current pattern pointer - errorCodePtr points to error code variable - firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) - reqbyteptr set to the last literal character required, else < 0 - cd contains pointers to tables etc. - -Returns: true on success - false, with *errorCodePtr set non-zero on error -*/ - -static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected) -{ - return ((ptr + 1 < patternEnd) && ptr[1] == expected); -} - -static bool -compileBranch(int options, int* brackets, unsigned char** codePtr, - const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int *firstbyteptr, - int* reqbyteptr, CompileData& cd) -{ - int repeatType, opType; - int repeatMin = 0, repeat_max = 0; /* To please picky compilers */ - int bravalue = 0; - int reqvary, tempreqvary; - int c; - unsigned char* code = *codePtr; - unsigned char* tempcode; - bool didGroupSetFirstByte = false; - const UChar* ptr = *ptrPtr; - const UChar* tempptr; - unsigned char* previous = NULL; - unsigned char classbits[32]; - - bool class_utf8; - unsigned char* class_utf8data; - unsigned char utf8_char[6]; - - /* Initialize no first byte, no required byte. REQ_UNSET means "no char - matching encountered yet". It gets changed to REQ_NONE if we hit something that - matches a non-fixed char first char; reqByte just remains unset if we never - find one. - - When we hit a repeat whose minimum is zero, we may have to adjust these values - to take the zero repeat into account. This is implemented by setting them to - zeroFirstByte and zeroReqByte when such a repeat is encountered. The individual - item types that can be repeated set these backoff variables appropriately. */ - - int firstByte = REQ_UNSET; - int reqByte = REQ_UNSET; - int zeroReqByte = REQ_UNSET; - int zeroFirstByte = REQ_UNSET; - - /* The variable reqCaseOpt contains either the REQ_IGNORE_CASE value or zero, - according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit - value > 255. It is added into the firstByte or reqByte variables to record the - case status of the value. This is used only for ASCII characters. */ - - int reqCaseOpt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0; - - /* Switch on next character until the end of the branch */ - - for (;; ptr++) { - bool negateClass; - bool shouldFlipNegation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */ - int classCharCount; - int classLastChar; - int skipBytes; - int subReqByte; - int subFirstByte; - int mcLength; - unsigned char mcbuffer[8]; - - /* Next byte in the pattern */ - - c = ptr < patternEnd ? *ptr : 0; - - /* Fill in length of a previous callout, except when the next thing is - a quantifier. */ - - bool isQuantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd)); - - switch (c) { - /* The branch terminates at end of string, |, or ). */ - - case 0: - if (ptr < patternEnd) - goto NORMAL_CHAR; - // End of string; fall through - case '|': - case ')': - *firstbyteptr = firstByte; - *reqbyteptr = reqByte; - *codePtr = code; - *ptrPtr = ptr; - return true; - - /* Handle single-character metacharacters. In multiline mode, ^ disables - the setting of any following char as a first character. */ - - case '^': - if (options & MatchAcrossMultipleLinesOption) { - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - *code++ = OP_BOL; - } else - *code++ = OP_CIRC; - previous = NULL; - break; - - case '$': - previous = NULL; - if (options & MatchAcrossMultipleLinesOption) - *code++ = OP_EOL; - else - *code++ = OP_DOLL; - break; - - /* There can never be a first char if '.' is first, whatever happens about - repeats. The value of reqByte doesn't change either. */ - - case '.': - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - previous = code; - *code++ = OP_NOT_NEWLINE; - break; - - /* Character classes. If the included characters are all < 256, we build a - 32-byte bitmap of the permitted characters, except in the special case - where there is only one such character. For negated classes, we build the - map as usual, then invert it at the end. However, we use a different opcode - so that data characters > 255 can be handled correctly. - - If the class contains characters outside the 0-255 range, a different - opcode is compiled. It may optionally have a bit map for characters < 256, - but those above are are explicitly listed afterwards. A flag byte tells - whether the bitmap is present, and whether this is a negated class or not. - */ - - case '[': { - previous = code; - shouldFlipNegation = false; - - /* PCRE supports POSIX class stuff inside a class. Perl gives an error if - they are encountered at the top level, so we'll do that too. */ - - /* If the first character is '^', set the negation flag and skip it. */ - - if (ptr + 1 >= patternEnd) { - *errorCodePtr = ERR6; - return false; - } - - if (ptr[1] == '^') { - negateClass = true; - ++ptr; - } else - negateClass = false; - - /* Keep a count of chars with values < 256 so that we can optimize the case - of just a single character (as long as it's < 256). For higher valued UTF-8 - characters, we don't yet do any optimization. */ - - classCharCount = 0; - classLastChar = -1; - - class_utf8 = false; /* No chars >= 256 */ - class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ - - /* Initialize the 32-char bit map to all zeros. We have to build the - map in a temporary bit of store, in case the class contains only 1 - character (< 256), because in that case the compiled code doesn't use the - bit map. */ - - memset(classbits, 0, 32 * sizeof(unsigned char)); - - /* Process characters until ] is reached. The first pass - through the regex checked the overall syntax, so we don't need to be very - strict here. At the start of the loop, c contains the first byte of the - character. */ - - while ((++ptr < patternEnd) && (c = *ptr) != ']') { - /* Backslash may introduce a single character, or it may introduce one - of the specials, which just set a flag. Escaped items are checked for - validity in the pre-compiling pass. The sequence \b is a special case. - Inside a class (and only there) it is treated as backspace. Elsewhere - it marks a word boundary. Other escapes have preset maps ready to - or into the one we are building. We assume they have more than one - character in them, so set classCharCount bigger than one. */ - - if (c == '\\') { - c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); - if (c < 0) { - classCharCount += 2; /* Greater than 1 is what matters */ - switch (-c) { - case ESC_d: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_digit); - continue; - - case ESC_D: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_digit); - continue; - - case ESC_w: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_word); - continue; - - case ESC_W: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_word); - continue; - - case ESC_s: - for (c = 0; c < 32; c++) - classbits[c] |= classBitmapForChar(c + cbit_space); - continue; - - case ESC_S: - shouldFlipNegation = true; - for (c = 0; c < 32; c++) - classbits[c] |= ~classBitmapForChar(c + cbit_space); - continue; - - /* Unrecognized escapes are faulted if PCRE is running in its - strict mode. By default, for compatibility with Perl, they are - treated as literals. */ - - default: - c = *ptr; /* The final character */ - classCharCount -= 2; /* Undo the default count from above */ - } - } - - /* Fall through if we have a single character (c >= 0). This may be - > 256 in UTF-8 mode. */ - - } /* End of backslash handling */ - - /* A single character may be followed by '-' to form a range. However, - Perl does not permit ']' to be the end of the range. A '-' character - here is treated as a literal. */ - - if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') { - ptr += 2; - - int d = *ptr; - - /* The second part of a range can be a single-character escape, but - not any of the other escapes. Perl 5.6 treats a hyphen as a literal - in such circumstances. */ - - if (d == '\\') { - const UChar* oldptr = ptr; - d = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); - - /* \X is literal X; any other special means the '-' was literal */ - if (d < 0) { - ptr = oldptr - 2; - goto LONE_SINGLE_CHARACTER; /* A few lines below */ - } - } - - /* The check that the two values are in the correct order happens in - the pre-pass. Optimize one-character ranges */ - - if (d == c) - goto LONE_SINGLE_CHARACTER; /* A few lines below */ - - /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless - matching, we have to use an XCLASS with extra data items. Caseless - matching for characters > 127 is available only if UCP support is - available. */ - - if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) { - class_utf8 = true; - - /* With UCP support, we can find the other case equivalents of - the relevant characters. There may be several ranges. Optimize how - they fit with the basic range. */ - - if (options & IgnoreCaseOption) { - int occ, ocd; - int cc = c; - int origd = d; - while (getOthercaseRange(&cc, origd, &occ, &ocd)) { - if (occ >= c && ocd <= d) - continue; /* Skip embedded ranges */ - - if (occ < c && ocd >= c - 1) /* Extend the basic range */ - { /* if there is overlap, */ - c = occ; /* noting that if occ < c */ - continue; /* we can't have ocd > d */ - } /* because a subrange is */ - if (ocd > d && occ <= d + 1) /* always shorter than */ - { /* the basic range. */ - d = ocd; - continue; - } - - if (occ == ocd) - *class_utf8data++ = XCL_SINGLE; - else { - *class_utf8data++ = XCL_RANGE; - class_utf8data += encodeUTF8(occ, class_utf8data); - } - class_utf8data += encodeUTF8(ocd, class_utf8data); - } - } - - /* Now record the original range, possibly modified for UCP caseless - overlapping ranges. */ - - *class_utf8data++ = XCL_RANGE; - class_utf8data += encodeUTF8(c, class_utf8data); - class_utf8data += encodeUTF8(d, class_utf8data); - - /* With UCP support, we are done. Without UCP support, there is no - caseless matching for UTF-8 characters > 127; we can use the bit map - for the smaller ones. */ - - continue; /* With next character in the class */ - } - - /* We use the bit map for all cases when not in UTF-8 mode; else - ranges that lie entirely within 0-127 when there is UCP support; else - for partial ranges without UCP support. */ - - for (; c <= d; c++) { - classbits[c/8] |= (1 << (c&7)); - if (options & IgnoreCaseOption) { - int uc = flipCase(c); - classbits[uc/8] |= (1 << (uc&7)); - } - classCharCount++; /* in case a one-char range */ - classLastChar = c; - } - - continue; /* Go get the next char in the class */ - } - - /* Handle a lone single character - we can get here for a normal - non-escape char, or after \ that introduces a single character or for an - apparent range that isn't. */ - - LONE_SINGLE_CHARACTER: - - /* Handle a character that cannot go in the bit map */ - - if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) { - class_utf8 = true; - *class_utf8data++ = XCL_SINGLE; - class_utf8data += encodeUTF8(c, class_utf8data); - - if (options & IgnoreCaseOption) { - int othercase; - if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) { - *class_utf8data++ = XCL_SINGLE; - class_utf8data += encodeUTF8(othercase, class_utf8data); - } - } - } else { - /* Handle a single-byte character */ - classbits[c/8] |= (1 << (c&7)); - if (options & IgnoreCaseOption) { - c = flipCase(c); - classbits[c/8] |= (1 << (c&7)); - } - classCharCount++; - classLastChar = c; - } - } - - /* If classCharCount is 1, we saw precisely one character whose value is - less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we - can optimize the negative case only if there were no characters >= 128 - because OP_NOT and the related opcodes like OP_NOTSTAR operate on - single-bytes only. This is an historical hangover. Maybe one day we can - tidy these opcodes to handle multi-byte characters. - - The optimization throws away the bit map. We turn the item into a - 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note - that OP_NOT does not support multibyte characters. In the positive case, it - can cause firstByte to be set. Otherwise, there can be no first char if - this item is first, whatever repeat count may follow. In the case of - reqByte, save the previous value for reinstating. */ - - if (classCharCount == 1 && (!class_utf8 && (!negateClass || classLastChar < 128))) { - zeroReqByte = reqByte; - - /* The OP_NOT opcode works on one-byte characters only. */ - - if (negateClass) { - if (firstByte == REQ_UNSET) - firstByte = REQ_NONE; - zeroFirstByte = firstByte; - *code++ = OP_NOT; - *code++ = classLastChar; - break; - } - - /* For a single, positive character, get the value into c, and - then we can handle this with the normal one-character code. */ - - c = classLastChar; - goto NORMAL_CHAR; - } /* End of 1-char optimization */ - - /* The general case - not the one-char optimization. If this is the first - thing in the branch, there can be no first char setting, whatever the - repeat count. Any reqByte setting must remain unchanged after any kind of - repeat. */ - - if (firstByte == REQ_UNSET) firstByte = REQ_NONE; - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - - /* If there are characters with values > 255, we have to compile an - extended class, with its own opcode. If there are no characters < 256, - we can omit the bitmap. */ - - if (class_utf8 && !shouldFlipNegation) { - *class_utf8data++ = XCL_END; /* Marks the end of extra data */ - *code++ = OP_XCLASS; - code += LINK_SIZE; - *code = negateClass? XCL_NOT : 0; - - /* If the map is required, install it, and move on to the end of - the extra data */ - - if (classCharCount > 0) { - *code++ |= XCL_MAP; - memcpy(code, classbits, 32); - code = class_utf8data; - } - - /* If the map is not required, slide down the extra data. */ - - else { - int len = class_utf8data - (code + 33); - memmove(code + 1, code + 33, len); - code += len + 1; - } - - /* Now fill in the complete length of the item */ - - putLinkValue(previous + 1, code - previous); - break; /* End of class handling */ - } - - /* If there are no characters > 255, negate the 32-byte map if necessary, - and copy it into the code vector. If this is the first thing in the branch, - there can be no first char setting, whatever the repeat count. Any reqByte - setting must remain unchanged after any kind of repeat. */ - - *code++ = (negateClass == shouldFlipNegation) ? OP_CLASS : OP_NCLASS; - if (negateClass) - for (c = 0; c < 32; c++) - code[c] = ~classbits[c]; - else - memcpy(code, classbits, 32); - code += 32; - break; - } - - /* Various kinds of repeat; '{' is not necessarily a quantifier, but this - has been tested above. */ - - case '{': - if (!isQuantifier) - goto NORMAL_CHAR; - ptr = readRepeatCounts(ptr + 1, &repeatMin, &repeat_max, errorCodePtr); - if (*errorCodePtr) - goto FAILED; - goto REPEAT; - - case '*': - repeatMin = 0; - repeat_max = -1; - goto REPEAT; - - case '+': - repeatMin = 1; - repeat_max = -1; - goto REPEAT; - - case '?': - repeatMin = 0; - repeat_max = 1; - - REPEAT: - if (!previous) { - *errorCodePtr = ERR9; - goto FAILED; - } - - if (repeatMin == 0) { - firstByte = zeroFirstByte; /* Adjust for zero repeat */ - reqByte = zeroReqByte; /* Ditto */ - } - - /* Remember whether this is a variable length repeat */ - - reqvary = (repeatMin == repeat_max) ? 0 : REQ_VARY; - - opType = 0; /* Default single-char op codes */ - - /* Save start of previous item, in case we have to move it up to make space - for an inserted OP_ONCE for the additional '+' extension. */ - /* FIXME: Probably don't need this because we don't use OP_ONCE. */ - - tempcode = previous; - - /* If the next character is '+', we have a possessive quantifier. This - implies greediness, whatever the setting of the PCRE_UNGREEDY option. - If the next character is '?' this is a minimizing repeat, by default, - but if PCRE_UNGREEDY is set, it works the other way round. We change the - repeat type to the non-default. */ - - if (safelyCheckNextChar(ptr, patternEnd, '?')) { - repeatType = 1; - ptr++; - } else - repeatType = 0; - - /* If previous was a character match, abolish the item and generate a - repeat item instead. If a char item has a minumum of more than one, ensure - that it is set in reqByte - it might not be if a sequence such as x{3} is - the first thing in a branch because the x will have gone into firstByte - instead. */ - - if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) { - /* Deal with UTF-8 characters that take up more than one byte. It's - easier to write this out separately than try to macrify it. Use c to - hold the length of the character in bytes, plus 0x80 to flag that it's a - length rather than a small character. */ - - if (code[-1] & 0x80) { - unsigned char *lastchar = code - 1; - while((*lastchar & 0xc0) == 0x80) - lastchar--; - c = code - lastchar; /* Length of UTF-8 character */ - memcpy(utf8_char, lastchar, c); /* Save the char */ - c |= 0x80; /* Flag c as a length */ - } - else { - c = code[-1]; - if (repeatMin > 1) - reqByte = c | reqCaseOpt | cd.reqVaryOpt; - } - - goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ - } - - else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) { - c = previous[1]; - if (repeatMin > 1) - reqByte = c | reqCaseOpt | cd.reqVaryOpt; - goto OUTPUT_SINGLE_REPEAT; - } - - /* If previous was a single negated character ([^a] or similar), we use - one of the special opcodes, replacing it. The code is shared with single- - character repeats by setting opt_type to add a suitable offset into - repeatType. OP_NOT is currently used only for single-byte chars. */ - - else if (*previous == OP_NOT) { - opType = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ - c = previous[1]; - goto OUTPUT_SINGLE_REPEAT; - } - - /* If previous was a character type match (\d or similar), abolish it and - create a suitable repeat item. The code is shared with single-character - repeats by setting opType to add a suitable offset into repeatType. */ - - else if (*previous <= OP_NOT_NEWLINE) { - opType = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ - c = *previous; - - OUTPUT_SINGLE_REPEAT: - int prop_type = -1; - int prop_value = -1; - - unsigned char* oldcode = code; - code = previous; /* Usually overwrite previous item */ - - /* If the maximum is zero then the minimum must also be zero; Perl allows - this case, so we do too - by simply omitting the item altogether. */ - - if (repeat_max == 0) - goto END_REPEAT; - - /* Combine the opType with the repeatType */ - - repeatType += opType; - - /* A minimum of zero is handled either as the special case * or ?, or as - an UPTO, with the maximum given. */ - - if (repeatMin == 0) { - if (repeat_max == -1) - *code++ = OP_STAR + repeatType; - else if (repeat_max == 1) - *code++ = OP_QUERY + repeatType; - else { - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* A repeat minimum of 1 is optimized into some special cases. If the - maximum is unlimited, we use OP_PLUS. Otherwise, the original item it - left in place and, if the maximum is greater than 1, we use OP_UPTO with - one less than the maximum. */ - - else if (repeatMin == 1) { - if (repeat_max == -1) - *code++ = OP_PLUS + repeatType; - else { - code = oldcode; /* leave previous item in place */ - if (repeat_max == 1) - goto END_REPEAT; - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max - 1); - } - } - - /* The case {n,n} is just an EXACT, while the general case {n,m} is - handled as an EXACT followed by an UPTO. */ - - else { - *code++ = OP_EXACT + opType; /* NB EXACT doesn't have repeatType */ - put2ByteValueAndAdvance(code, repeatMin); - - /* If the maximum is unlimited, insert an OP_STAR. Before doing so, - we have to insert the character for the previous code. For a repeated - Unicode property match, there are two extra bytes that define the - required property. In UTF-8 mode, long characters have their length in - c, with the 0x80 bit as a flag. */ - - if (repeat_max < 0) { - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else { - *code++ = c; - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - } - *code++ = OP_STAR + repeatType; - } - - /* Else insert an UPTO if the max is greater than the min, again - preceded by the character, for the previously inserted code. */ - - else if (repeat_max != repeatMin) { - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else - *code++ = c; - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - repeat_max -= repeatMin; - *code++ = OP_UPTO + repeatType; - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* The character or character type itself comes last in all cases. */ - - if (c >= 128) { - memcpy(code, utf8_char, c & 7); - code += c & 7; - } else - *code++ = c; - - /* For a repeated Unicode property match, there are two extra bytes that - define the required property. */ - - if (prop_type >= 0) { - *code++ = prop_type; - *code++ = prop_value; - } - } - - /* If previous was a character class or a back reference, we put the repeat - stuff after it, but just skip the item if the repeat was {0,0}. */ - - else if (*previous == OP_CLASS || - *previous == OP_NCLASS || - *previous == OP_XCLASS || - *previous == OP_REF) - { - if (repeat_max == 0) { - code = previous; - goto END_REPEAT; - } - - if (repeatMin == 0 && repeat_max == -1) - *code++ = OP_CRSTAR + repeatType; - else if (repeatMin == 1 && repeat_max == -1) - *code++ = OP_CRPLUS + repeatType; - else if (repeatMin == 0 && repeat_max == 1) - *code++ = OP_CRQUERY + repeatType; - else { - *code++ = OP_CRRANGE + repeatType; - put2ByteValueAndAdvance(code, repeatMin); - if (repeat_max == -1) - repeat_max = 0; /* 2-byte encoding for max */ - put2ByteValueAndAdvance(code, repeat_max); - } - } - - /* If previous was a bracket group, we may have to replicate it in certain - cases. */ - - else if (*previous >= OP_BRA) { - int ketoffset = 0; - int len = code - previous; - unsigned char* bralink = NULL; - int nested = get2ByteValue(previous + 1 + LINK_SIZE); - - /* If the maximum repeat count is unlimited, find the end of the bracket - by scanning through from the start, and compute the offset back to it - from the current code pointer. There may be an OP_OPT setting following - the final KET, so we can't find the end just by going back from the code - pointer. */ - - if (repeat_max == -1) { - const unsigned char* ket = previous; - advanceToEndOfBracket(ket); - ketoffset = code - ket; - } - - /* The case of a zero minimum is special because of the need to stick - OP_BRAZERO in front of it, and because the group appears once in the - data, whereas in other cases it appears the minimum number of times. For - this reason, it is simplest to treat this case separately, as otherwise - the code gets far too messy. There are several special subcases when the - minimum is zero. */ - - if (repeatMin == 0) { - /* If the maximum is also zero, we just omit the group from the output - altogether. */ - - if (repeat_max == 0) { - code = previous; - goto END_REPEAT; - } - - /* If the maximum is 1 or unlimited, we just have to stick in the - BRAZERO and do no more at this point. However, we do need to adjust - any OP_RECURSE calls inside the group that refer to the group itself or - any internal group, because the offset is from the start of the whole - regex. Temporarily terminate the pattern while doing this. */ - - if (repeat_max <= 1) { - *code = OP_END; - memmove(previous+1, previous, len); - code++; - *previous++ = OP_BRAZERO + repeatType; - } - - /* If the maximum is greater than 1 and limited, we have to replicate - in a nested fashion, sticking OP_BRAZERO before each set of brackets. - The first one has to be handled carefully because it's the original - copy, which has to be moved up. The remainder can be handled by code - that is common with the non-zero minimum case below. We have to - adjust the value of repeat_max, since one less copy is required. */ - - else { - *code = OP_END; - memmove(previous + 4 + LINK_SIZE, previous, len); - code += 4 + LINK_SIZE; - *previous++ = OP_BRAZERO + repeatType; - *previous++ = OP_BRA; - - /* We chain together the bracket offset fields that have to be - filled in later when the ends of the brackets are reached. */ - - int offset = (!bralink) ? 0 : previous - bralink; - bralink = previous; - putLinkValueAllowZeroAndAdvance(previous, offset); - put2ByteValueAndAdvance(previous, nested); - } - - repeat_max--; - } - - /* If the minimum is greater than zero, replicate the group as many - times as necessary, and adjust the maximum to the number of subsequent - copies that we need. If we set a first char from the group, and didn't - set a required char, copy the latter from the former. */ - - else { - if (repeatMin > 1) { - if (didGroupSetFirstByte && reqByte < 0) - reqByte = firstByte; - for (int i = 1; i < repeatMin; i++) { - memcpy(code, previous, len); - code += len; - } - } - if (repeat_max > 0) - repeat_max -= repeatMin; - } - - /* This code is common to both the zero and non-zero minimum cases. If - the maximum is limited, it replicates the group in a nested fashion, - remembering the bracket starts on a stack. In the case of a zero minimum, - the first one was set up above. In all cases the repeat_max now specifies - the number of additional copies needed. */ - - if (repeat_max >= 0) { - for (int i = repeat_max - 1; i >= 0; i--) { - *code++ = OP_BRAZERO + repeatType; - - /* All but the final copy start a new nesting, maintaining the - chain of brackets outstanding. */ - - if (i != 0) { - *code++ = OP_BRA; - int offset = (!bralink) ? 0 : code - bralink; - bralink = code; - putLinkValueAllowZeroAndAdvance(code, offset); - put2ByteValueAndAdvance(code, nested); - } - - memcpy(code, previous, len); - code += len; - } - - /* Now chain through the pending brackets, and fill in their length - fields (which are holding the chain links pro tem). */ - - while (bralink) { - int offset = code - bralink + 1; - unsigned char* bra = code - offset; - int oldlinkoffset = getLinkValueAllowZero(bra + 1); - bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset; - *code++ = OP_KET; - putLinkValueAndAdvance(code, offset); - putLinkValue(bra + 1, offset); - } - } - - /* If the maximum is unlimited, set a repeater in the final copy. We - can't just offset backwards from the current code point, because we - don't know if there's been an options resetting after the ket. The - correct offset was computed above. */ - - else - code[-ketoffset] = OP_KETRMAX + repeatType; - } - - // A quantifier after an assertion is mostly meaningless, but it - // can nullify the assertion if it has a 0 minimum. - else if (*previous == OP_ASSERT || *previous == OP_ASSERT_NOT) { - if (repeatMin == 0) { - code = previous; - goto END_REPEAT; - } - } - - /* Else there's some kind of shambles */ - - else { - *errorCodePtr = ERR11; - goto FAILED; - } - - /* In all case we no longer have a previous item. We also set the - "follows varying string" flag for subsequently encountered reqbytes if - it isn't already set and we have just passed a varying length item. */ - - END_REPEAT: - previous = NULL; - cd.reqVaryOpt |= reqvary; - break; - - /* Start of nested bracket sub-expression, or comment or lookahead or - lookbehind or option setting or condition. First deal with special things - that can come after a bracket; all are introduced by ?, and the appearance - of any of them means that this is not a referencing group. They were - checked for validity in the first pass over the string, so we don't have to - check for syntax errors here. */ - - case '(': - { - skipBytes = 2; - unsigned minBracket = *brackets + 1; - if (*(++ptr) == '?') { - switch (*(++ptr)) { - case ':': /* Non-extracting bracket */ - bravalue = OP_BRA; - ptr++; - break; - - case '=': /* Positive lookahead */ - bravalue = OP_ASSERT; - ptr++; - break; - - case '!': /* Negative lookahead */ - bravalue = OP_ASSERT_NOT; - ptr++; - break; - - /* Character after (? not specially recognized */ - - default: - *errorCodePtr = ERR12; - goto FAILED; - } - } - - /* Else we have a referencing group; adjust the opcode. If the bracket - number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and - arrange for the true number to follow later, in an OP_BRANUMBER item. */ - - else { - if (++(*brackets) > EXTRACT_BASIC_MAX) { - bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; - code[3 + LINK_SIZE] = OP_BRANUMBER; - put2ByteValue(code + 4 + LINK_SIZE, *brackets); - skipBytes = 5; - } - else - bravalue = OP_BRA + *brackets; - } - - /* Process nested bracketed re. We copy code into a non-variable - in order to be able to pass its address because some compilers - complain otherwise. Pass in a new setting for the ims options - if they have changed. */ - - previous = code; - *code = bravalue; - tempcode = code; - tempreqvary = cd.reqVaryOpt; /* Save value before bracket */ - { - unsigned bracketsBeforeRecursion = *brackets; - if (!compileBracket( - options, - brackets, /* Extracting bracket count */ - &tempcode, /* Where to put code (updated) */ - &ptr, /* Input pointer (updated) */ - patternEnd, - errorCodePtr, /* Where to put an error message */ - skipBytes, /* Skip over OP_BRANUMBER */ - &subFirstByte, /* For possible first char */ - &subReqByte, /* For possible last char */ - cd)) /* Tables block */ - goto FAILED; - unsigned enclosedBrackets = (*brackets - bracketsBeforeRecursion); - unsigned limitBracket = minBracket + enclosedBrackets + (bravalue > OP_BRA); - if (!((minBracket & 0xff) == minBracket && (limitBracket & 0xff) == limitBracket)) { - *errorCodePtr = ERR17; - return false; - } - JS_ASSERT(minBracket <= limitBracket); - put2ByteValue(code + 1 + LINK_SIZE, minBracket << 8 | limitBracket); - } - - /* At the end of compiling, code is still pointing to the start of the - group, while tempcode has been updated to point past the end of the group - and any option resetting that may follow it. The pattern pointer (ptr) - is on the bracket. */ - - /* Handle updating of the required and first characters. Update for normal - brackets of all kinds, and conditions with two branches (see code above). - If the bracket is followed by a quantifier with zero repeat, we have to - back off. Hence the definition of zeroReqByte and zeroFirstByte outside the - main loop so that they can be accessed for the back off. */ - - zeroReqByte = reqByte; - zeroFirstByte = firstByte; - didGroupSetFirstByte = false; - - if (bravalue >= OP_BRA) { - /* If we have not yet set a firstByte in this branch, take it from the - subpattern, remembering that it was set here so that a repeat of more - than one can replicate it as reqByte if necessary. If the subpattern has - no firstByte, set "none" for the whole branch. In both cases, a zero - repeat forces firstByte to "none". */ - - if (firstByte == REQ_UNSET) { - if (subFirstByte >= 0) { - firstByte = subFirstByte; - didGroupSetFirstByte = true; - } - else - firstByte = REQ_NONE; - zeroFirstByte = REQ_NONE; - } - - /* If firstByte was previously set, convert the subpattern's firstByte - into reqByte if there wasn't one, using the vary flag that was in - existence beforehand. */ - - else if (subFirstByte >= 0 && subReqByte < 0) - subReqByte = subFirstByte | tempreqvary; - - /* If the subpattern set a required byte (or set a first byte that isn't - really the first byte - see above), set it. */ - - if (subReqByte >= 0) - reqByte = subReqByte; - } - - /* For a forward assertion, we take the reqByte, if set. This can be - helpful if the pattern that follows the assertion doesn't set a different - char. For example, it's useful for /(?=abcde).+/. We can't set firstByte - for an assertion, however because it leads to incorrect effect for patterns - such as /(?=a)a.+/ when the "real" "a" would then become a reqByte instead - of a firstByte. This is overcome by a scan at the end if there's no - firstByte, looking for an asserted first char. */ - - else if (bravalue == OP_ASSERT && subReqByte >= 0) - reqByte = subReqByte; - - /* Now update the main code pointer to the end of the group. */ - - code = tempcode; - - /* Error if hit end of pattern */ - - if (ptr >= patternEnd || *ptr != ')') { - *errorCodePtr = ERR14; - goto FAILED; - } - break; - - } - /* Check \ for being a real metacharacter; if not, fall through and handle - it as a data character at the start of a string. Escape items are checked - for validity in the pre-compiling pass. */ - - case '\\': - tempptr = ptr; - c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, false); - - /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values - are arranged to be the negation of the corresponding OP_values. For the - back references, the values are ESC_REF plus the reference number. Only - back references and those types that consume a character may be repeated. - We can test for values between ESC_b and ESC_w for the latter; this may - have to change if any new ones are ever created. */ - - if (c < 0) { - /* For metasequences that actually match a character, we disable the - setting of a first character if it hasn't already been set. */ - - if (firstByte == REQ_UNSET && -c > ESC_b && -c <= ESC_w) - firstByte = REQ_NONE; - - /* Set values to reset to if this is followed by a zero repeat. */ - - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - - /* Back references are handled specially */ - - if (-c >= ESC_REF) { - int number = -c - ESC_REF; - previous = code; - *code++ = OP_REF; - put2ByteValueAndAdvance(code, number); - } - - /* For the rest, we can obtain the OP value by negating the escape - value */ - - else { - previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL; - *code++ = -c; - } - continue; - } - - /* Fall through. */ - - /* Handle a literal character. It is guaranteed not to be whitespace or # - when the extended flag is set. If we are in UTF-8 mode, it may be a - multi-byte literal character. */ - - default: - NORMAL_CHAR: - - previous = code; - - if (c < 128) { - mcLength = 1; - mcbuffer[0] = c; - - if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') { - *code++ = OP_ASCII_LETTER_IGNORING_CASE; - *code++ = c | 0x20; - } else { - *code++ = OP_ASCII_CHAR; - *code++ = c; - } - } else { - mcLength = encodeUTF8(c, mcbuffer); - - *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR; - for (c = 0; c < mcLength; c++) - *code++ = mcbuffer[c]; - } - - /* Set the first and required bytes appropriately. If no previous first - byte, set it from this character, but revert to none on a zero repeat. - Otherwise, leave the firstByte value alone, and don't change it on a zero - repeat. */ - - if (firstByte == REQ_UNSET) { - zeroFirstByte = REQ_NONE; - zeroReqByte = reqByte; - - /* If the character is more than one byte long, we can set firstByte - only if it is not to be matched caselessly. */ - - if (mcLength == 1 || reqCaseOpt == 0) { - firstByte = mcbuffer[0] | reqCaseOpt; - if (mcLength != 1) - reqByte = code[-1] | cd.reqVaryOpt; - } - else - firstByte = reqByte = REQ_NONE; - } - - /* firstByte was previously set; we can set reqByte only the length is - 1 or the matching is caseful. */ - - else { - zeroFirstByte = firstByte; - zeroReqByte = reqByte; - if (mcLength == 1 || reqCaseOpt == 0) - reqByte = code[-1] | reqCaseOpt | cd.reqVaryOpt; - } - - break; /* End of literal character handling */ - } - } /* end of big loop */ - - /* Control never reaches here by falling through, only by a goto for all the - error states. Pass back the position in the pattern so that it can be displayed - to the user for diagnosing the error. */ - -FAILED: - *ptrPtr = ptr; - return false; -} - -/************************************************* -* Compile sequence of alternatives * -*************************************************/ - -/* On entry, ptr is pointing past the bracket character, but on return -it points to the closing bracket, or vertical bar, or end of string. -The code variable is pointing at the byte into which the BRA operator has been -stored. If the ims options are changed at the start (for a (?ims: group) or -during any branch, we need to insert an OP_OPT item at the start of every -following branch to ensure they get set correctly at run time, and also pass -the new options into every subsequent branch compile. - -Argument: - options option bits, including any changes for this subpattern - brackets -> int containing the number of extracting brackets used - codePtr -> the address of the current code pointer - ptrPtr -> the address of the current pattern pointer - errorCodePtr -> pointer to error code variable - skipBytes skip this many bytes at start (for OP_BRANUMBER) - firstbyteptr place to put the first required character, or a negative number - reqbyteptr place to put the last required character, or a negative number - cd points to the data block with tables pointers etc. - -Returns: true on success -*/ - -static bool -compileBracket(int options, int* brackets, unsigned char** codePtr, - const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int skipBytes, - int* firstbyteptr, int* reqbyteptr, CompileData& cd) -{ - const UChar* ptr = *ptrPtr; - unsigned char* code = *codePtr; - unsigned char* lastBranch = code; - unsigned char* start_bracket = code; - int firstByte = REQ_UNSET; - int reqByte = REQ_UNSET; - - /* Offset is set zero to mark that this bracket is still open */ - - putLinkValueAllowZero(code + 1, 0); - code += 1 + LINK_SIZE + skipBytes; - - /* Loop for each alternative branch */ - - while (true) { - /* Now compile the branch */ - - int branchFirstByte; - int branchReqByte; - if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorCodePtr, - &branchFirstByte, &branchReqByte, cd)) { - *ptrPtr = ptr; - return false; - } - - /* If this is the first branch, the firstByte and reqByte values for the - branch become the values for the regex. */ - - if (*lastBranch != OP_ALT) { - firstByte = branchFirstByte; - reqByte = branchReqByte; - } - - /* If this is not the first branch, the first char and reqByte have to - match the values from all the previous branches, except that if the previous - value for reqByte didn't have REQ_VARY set, it can still match, and we set - REQ_VARY for the regex. */ - - else { - /* If we previously had a firstByte, but it doesn't match the new branch, - we have to abandon the firstByte for the regex, but if there was previously - no reqByte, it takes on the value of the old firstByte. */ - - if (firstByte >= 0 && firstByte != branchFirstByte) { - if (reqByte < 0) - reqByte = firstByte; - firstByte = REQ_NONE; - } - - /* If we (now or from before) have no firstByte, a firstByte from the - branch becomes a reqByte if there isn't a branch reqByte. */ - - if (firstByte < 0 && branchFirstByte >= 0 && branchReqByte < 0) - branchReqByte = branchFirstByte; - - /* Now ensure that the reqbytes match */ - - if ((reqByte & ~REQ_VARY) != (branchReqByte & ~REQ_VARY)) - reqByte = REQ_NONE; - else - reqByte |= branchReqByte; /* To "or" REQ_VARY */ - } - - /* Reached end of expression, either ')' or end of pattern. Go back through - the alternative branches and reverse the chain of offsets, with the field in - the BRA item now becoming an offset to the first alternative. If there are - no alternatives, it points to the end of the group. The length in the - terminating ket is always the length of the whole bracketed item. - Return leaving the pointer at the terminating char. */ - - if (ptr >= patternEnd || *ptr != '|') { - int length = code - lastBranch; - do { - int prevLength = getLinkValueAllowZero(lastBranch + 1); - putLinkValue(lastBranch + 1, length); - length = prevLength; - lastBranch -= length; - } while (length > 0); - - /* Fill in the ket */ - - *code = OP_KET; - putLinkValue(code + 1, code - start_bracket); - code += 1 + LINK_SIZE; - - /* Set values to pass back */ - - *codePtr = code; - *ptrPtr = ptr; - *firstbyteptr = firstByte; - *reqbyteptr = reqByte; - return true; - } - - /* Another branch follows; insert an "or" node. Its length field points back - to the previous branch while the bracket remains open. At the end the chain - is reversed. It's done like this so that the start of the bracket has a - zero offset until it is closed, making it possible to detect recursion. */ - - *code = OP_ALT; - putLinkValue(code + 1, code - lastBranch); - lastBranch = code; - code += 1 + LINK_SIZE; - ptr++; - } - JS_NOT_REACHED("No fallthru."); -} - -/************************************************* -* Check for anchored expression * -*************************************************/ - -/* Try to find out if this is an anchored regular expression. Consider each -alternative branch. If they all start OP_CIRC, or with a bracket -all of whose alternatives start OP_CIRC (recurse ad lib), then -it's anchored. - -Arguments: - code points to start of expression (the bracket) - captureMap a bitmap of which brackets we are inside while testing; this - handles up to substring 31; all brackets after that share - the zero bit - backrefMap the back reference bitmap -*/ - -static bool branchIsAnchored(const unsigned char* code) -{ - const unsigned char* scode = firstSignificantOpcode(code); - int op = *scode; - - /* Brackets */ - if (op >= OP_BRA || op == OP_ASSERT) - return bracketIsAnchored(scode); - - /* Check for explicit anchoring */ - return op == OP_CIRC; -} - -static bool bracketIsAnchored(const unsigned char* code) -{ - do { - if (!branchIsAnchored(code + 1 + LINK_SIZE)) - return false; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); /* Loop for each alternative */ - return true; -} - -/************************************************* -* Check for starting with ^ or .* * -*************************************************/ - -/* This is called to find out if every branch starts with ^ or .* so that -"first char" processing can be done to speed things up in multiline -matching and for non-DOTALL patterns that start with .* (which must start at -the beginning or after \n) - -Except when the .* appears inside capturing parentheses, and there is a -subsequent back reference to those parentheses. By keeping a bitmap of the -first 31 back references, we can catch some of the more common cases more -precisely; all the greater back references share a single bit. - -Arguments: - code points to start of expression (the bracket) - captureMap a bitmap of which brackets we are inside while testing; this - handles up to substring 31; all brackets after that share - the zero bit - backrefMap the back reference bitmap -*/ - -static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) -{ - const unsigned char* scode = firstSignificantOpcode(code); - int op = *scode; - - /* Capturing brackets */ - if (op > OP_BRA) { - int captureNum = op - OP_BRA; - if (captureNum > EXTRACT_BASIC_MAX) - captureNum = get2ByteValue(scode + 2 + LINK_SIZE); - int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1; - return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap); - } - - /* Other brackets */ - if (op == OP_BRA || op == OP_ASSERT) - return bracketNeedsLineStart(scode, captureMap, backrefMap); - - /* .* means "start at start or after \n" if it isn't in brackets that - may be referenced. */ - - if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) - return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap); - - /* Explicit ^ */ - return op == OP_CIRC || op == OP_BOL; -} - -static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) -{ - do { - if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap)) - return false; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); /* Loop for each alternative */ - return true; -} - -/************************************************* -* Check for asserted fixed first char * -*************************************************/ - -/* During compilation, the "first char" settings from forward assertions are -discarded, because they can cause conflicts with actual literals that follow. -However, if we end up without a first char setting for an unanchored pattern, -it is worth scanning the regex to see if there is an initial asserted first -char. If all branches start with the same asserted char, or with a bracket all -of whose alternatives start with the same asserted char (recurse ad lib), then -we return that char, otherwise -1. - -Arguments: - code points to start of expression (the bracket) - options pointer to the options (used to check casing changes) - inassert true if in an assertion - -Returns: -1 or the fixed first char -*/ - -static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert) -{ - const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code); - int op = *scode; - - if (op >= OP_BRA) - op = OP_BRA; - - switch (op) { - default: - return -1; - - case OP_BRA: - case OP_ASSERT: - return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT); - - case OP_EXACT: - scode += 2; - /* Fall through */ - - case OP_CHAR: - case OP_CHAR_IGNORING_CASE: - case OP_ASCII_CHAR: - case OP_ASCII_LETTER_IGNORING_CASE: - case OP_PLUS: - case OP_MINPLUS: - if (!inassert) - return -1; - return scode[1]; - } -} - -static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert) -{ - int c = -1; - do { - int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert); - if (d < 0) - return -1; - if (c < 0) - c = d; - else if (c != d) - return -1; - code += getLinkValue(code + 1); - } while (*code == OP_ALT); - return c; -} - -static inline int multiplyWithOverflowCheck(int a, int b) -{ - if (!a || !b) - return 0; - if (a > MAX_PATTERN_SIZE / b) - return -1; - return a * b; -} - -static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase, - CompileData& cd, ErrorCode& errorcode) -{ - /* Make a pass over the pattern to compute the - amount of store required to hold the compiled code. This does not have to be - perfect as long as errors are overestimates. */ - - if (patternLength > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - - int length = BRA_LEN; /* For initial BRA. */ - int branch_extra = 0; - int lastitemlength = 0; - unsigned brastackptr = 0; - int brastack[BRASTACK_SIZE]; - unsigned char bralenstack[BRASTACK_SIZE]; - int bracount = 0; - - const UChar* ptr = (const UChar*)(pattern - 1); - const UChar* patternEnd = (const UChar*)(pattern + patternLength); - - while (++ptr < patternEnd) { - int minRepeats = 0, maxRepeats = 0; - int c = *ptr; - - switch (c) { - /* A backslashed item may be an escaped data character or it may be a - character type. */ - - case '\\': - c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false); - if (errorcode != 0) - return -1; - - lastitemlength = 1; /* Default length of last item for repeats */ - - if (c >= 0) { /* Data character */ - length += 2; /* For a one-byte character */ - - if (c > 127) { - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (c <= jsc_pcre_utf8_table1[i]) break; - length += i; - lastitemlength += i; - } - - continue; - } - - /* Other escapes need one byte */ - - length++; - - /* A back reference needs an additional 2 bytes, plus either one or 5 - bytes for a repeat. We also need to keep the value of the highest - back reference. */ - - if (c <= -ESC_REF) { - int refnum = -c - ESC_REF; - cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1; - if (refnum > cd.topBackref) - cd.topBackref = refnum; - length += 2; /* For single back reference */ - if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode) - return -1; - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - else - length += 5; - if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; - } - } - continue; - - case '^': /* Single-byte metacharacters */ - case '.': - case '$': - length++; - lastitemlength = 1; - continue; - - case '*': /* These repeats won't be after brackets; */ - case '+': /* those are handled separately */ - case '?': - length++; - goto POSSESSIVE; - - /* This covers the cases of braced repeats after a single char, metachar, - class, or back reference. */ - - case '{': - if (!isCountedRepeat(ptr + 1, patternEnd)) - goto NORMAL_CHAR; - ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode); - if (errorcode != 0) - return -1; - - /* These special cases just insert one extra opcode */ - - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - - /* These cases might insert additional copies of a preceding character. */ - - else { - if (minRepeats != 1) { - length -= lastitemlength; /* Uncount the original char or metachar */ - if (minRepeats > 0) - length += 5 + lastitemlength; - } - length += lastitemlength + ((maxRepeats > 0) ? 5 : 1); - } - - if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; /* Needs no extra length */ - - POSSESSIVE: /* Test for possessive quantifier */ - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */ - } - continue; - - /* An alternation contains an offset to the next branch or ket. If any ims - options changed in the previous branch(es), and/or if we are in a - lookbehind assertion, extra space will be needed at the start of the - branch. This is handled by branch_extra. */ - - case '|': - if (brastackptr == 0) - cd.needOuterBracket = true; - length += 1 + LINK_SIZE + branch_extra; - continue; - - /* A character class uses 33 characters provided that all the character - values are less than 256. Otherwise, it uses a bit map for low valued - characters, and individual items for others. Don't worry about character - types that aren't allowed in classes - they'll get picked up during the - compile. A character class that contains only one single-byte character - uses 2 or 3 bytes, depending on whether it is negated or not. Notice this - where we can. (In UTF-8 mode we can do this only for chars < 128.) */ - - case '[': { - int class_optcount; - if (*(++ptr) == '^') { - class_optcount = 10; /* Greater than one */ - ptr++; - } - else - class_optcount = 0; - - bool class_utf8 = false; - - for (; ptr < patternEnd && *ptr != ']'; ++ptr) { - /* Check for escapes */ - - if (*ptr == '\\') { - c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); - if (errorcode != 0) - return -1; - - /* Handle escapes that turn into characters */ - - if (c >= 0) - goto NON_SPECIAL_CHARACTER; - - /* Escapes that are meta-things. The normal ones just affect the - bit map, but Unicode properties require an XCLASS extended item. */ - - else - class_optcount = 10; /* \d, \s etc; make sure > 1 */ - } - - /* Anything else increments the possible optimization count. We have to - detect ranges here so that we can compute the number of extra ranges for - caseless wide characters when UCP support is available. If there are wide - characters, we are going to have to use an XCLASS, even for single - characters. */ - - else { - c = *ptr; - - /* Come here from handling \ above when it escapes to a char value */ - - NON_SPECIAL_CHARACTER: - class_optcount++; - - int d = -1; - if (safelyCheckNextChar(ptr, patternEnd, '-')) { - const UChar* hyptr = ptr++; - if (safelyCheckNextChar(ptr, patternEnd, '\\')) { - ptr++; - d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); - if (errorcode != 0) - return -1; - } - else if ((ptr + 1 < patternEnd) && ptr[1] != ']') - d = *++ptr; - if (d < 0) - ptr = hyptr; /* go back to hyphen as data */ - } - - /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or > - 127 for caseless matching, we will need to use an XCLASS. */ - - if (d >= 0) { - class_optcount = 10; /* Ensure > 1 */ - if (d < c) { - errorcode = ERR8; - return -1; - } - - if ((d > 255 || (ignoreCase && d > 127))) { - unsigned char buffer[6]; - if (!class_utf8) /* Allow for XCLASS overhead */ - { - class_utf8 = true; - length += LINK_SIZE + 2; - } - - /* If we have UCP support, find out how many extra ranges are - needed to map the other case of characters within this range. We - have to mimic the range optimization here, because extending the - range upwards might push d over a boundary that makes it use - another byte in the UTF-8 representation. */ - - if (ignoreCase) { - int occ, ocd; - int cc = c; - int origd = d; - while (getOthercaseRange(&cc, origd, &occ, &ocd)) { - if (occ >= c && ocd <= d) - continue; /* Skip embedded */ - - if (occ < c && ocd >= c - 1) /* Extend the basic range */ - { /* if there is overlap, */ - c = occ; /* noting that if occ < c */ - continue; /* we can't have ocd > d */ - } /* because a subrange is */ - if (ocd > d && occ <= d + 1) /* always shorter than */ - { /* the basic range. */ - d = ocd; - continue; - } - - /* An extra item is needed */ - - length += 1 + encodeUTF8(occ, buffer) + - ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer)); - } - } - - /* The length of the (possibly extended) range */ - - length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer); - } - - } - - /* We have a single character. There is nothing to be done unless we - are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must - allow for an XCL_SINGLE item, doubled for caselessness if there is UCP - support. */ - - else { - if ((c > 255 || (ignoreCase && c > 127))) { - unsigned char buffer[6]; - class_optcount = 10; /* Ensure > 1 */ - if (!class_utf8) /* Allow for XCLASS overhead */ - { - class_utf8 = true; - length += LINK_SIZE + 2; - } - length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer)); - } - } - } - } - - if (ptr >= patternEnd) { /* Missing terminating ']' */ - errorcode = ERR6; - return -1; - } - - /* We can optimize when there was only one optimizable character. - Note that this does not detect the case of a negated single character. - In that case we do an incorrect length computation, but it's not a serious - problem because the computed length is too large rather than too small. */ - - if (class_optcount == 1) - goto NORMAL_CHAR; - - /* Here, we handle repeats for the class opcodes. */ - { - length += 33; - - /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, - we also need extra for wrapping the whole thing in a sub-pattern. */ - - if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode != 0) - return -1; - if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || - (minRepeats == 1 && maxRepeats == -1)) - length++; - else - length += 5; - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; - } else if (safelyCheckNextChar(ptr, patternEnd, '?')) - ptr++; - } - } - continue; - } - - /* Brackets may be genuine groups or special things */ - - case '(': { - int branch_newextra = 0; - int bracket_length = BRA_LEN; - bool capturing = false; - - /* Handle special forms of bracket, which all start (? */ - - if (safelyCheckNextChar(ptr, patternEnd, '?')) { - switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) { - /* Non-referencing groups and lookaheads just move the pointer on, and - then behave like a non-special bracket, except that they don't increment - the count of extracting brackets. Ditto for the "once only" bracket, - which is in Perl from version 5.005. */ - - case ':': - case '=': - case '!': - ptr += 2; - break; - - /* Else loop checking valid options until ) is met. Anything else is an - error. If we are without any brackets, i.e. at top level, the settings - act as if specified in the options, so massage the options immediately. - This is for backward compatibility with Perl 5.004. */ - - default: - errorcode = ERR12; - return -1; - } - } else - capturing = true; - - /* Capturing brackets must be counted so we can process escapes in a - Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need - an additional 3 bytes of memory per capturing bracket. */ - - if (capturing) { - bracount++; - if (bracount > EXTRACT_BASIC_MAX) - bracket_length += 3; - } - - /* Save length for computing whole length at end if there's a repeat that - requires duplication of the group. Also save the current value of - branch_extra, and start the new group with the new value. If non-zero, this - will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ - - if (brastackptr >= sizeof(brastack)/sizeof(int)) { - errorcode = ERR17; - return -1; - } - - bralenstack[brastackptr] = branch_extra; - branch_extra = branch_newextra; - - brastack[brastackptr++] = length; - length += bracket_length; - continue; - } - - /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we - have to replicate this bracket up to that many times. If brastackptr is - 0 this is an unmatched bracket which will generate an error, but take care - not to try to access brastack[-1] when computing the length and restoring - the branch_extra value. */ - - case ')': { - int duplength; - length += KET_LEN; - if (brastackptr > 0) { - duplength = length - brastack[--brastackptr]; - branch_extra = bralenstack[brastackptr]; - } - else - duplength = 0; - - /* Leave ptr at the final char; for readRepeatCounts this happens - automatically; for the others we need an increment. */ - - if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) { - ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); - if (errorcode) - return -1; - } else if (c == '*') { - minRepeats = 0; - maxRepeats = -1; - ptr++; - } else if (c == '+') { - minRepeats = 1; - maxRepeats = -1; - ptr++; - } else if (c == '?') { - minRepeats = 0; - maxRepeats = 1; - ptr++; - } else { - minRepeats = 1; - maxRepeats = 1; - } - - /* If the minimum is zero, we have to allow for an OP_BRAZERO before the - group, and if the maximum is greater than zero, we have to replicate - maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting - bracket set. */ - - int repeatsLength; - if (minRepeats == 0) { - length++; - if (maxRepeats > 0) { - repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + BRA_LEN + KET_LEN + OPCODE_LEN); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength; - if (length > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - } - } - - /* When the minimum is greater than zero, we have to replicate up to - minval-1 times, with no additions required in the copies. Then, if there - is a limited maximum we have to replicate up to maxval-1 times allowing - for a BRAZERO item before each optional copy and nesting brackets for all - but one of the optional copies. */ - - else { - repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength; - if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */ - repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + BRAZERO_LEN + BRA_LEN + KET_LEN); - if (repeatsLength < 0) { - errorcode = ERR16; - return -1; - } - length += repeatsLength - (2 + 2 * LINK_SIZE); - } - if (length > MAX_PATTERN_SIZE) { - errorcode = ERR16; - return -1; - } - } - - /* Allow space for once brackets for "possessive quantifier" */ - - if (safelyCheckNextChar(ptr, patternEnd, '+')) { - ptr++; - length += 2 + 2 * LINK_SIZE; - } - continue; - } - - /* Non-special character. It won't be space or # in extended mode, so it is - always a genuine character. If we are in a \Q...\E sequence, check for the - end; if not, we have a literal. */ - - default: - NORMAL_CHAR: - length += 2; /* For a one-byte character */ - lastitemlength = 1; /* Default length of last item for repeats */ - - if (c > 127) { - int i; - for (i = 0; i < jsc_pcre_utf8_table1_size; i++) - if (c <= jsc_pcre_utf8_table1[i]) - break; - length += i; - lastitemlength += i; - } - - continue; - } - } - - length += KET_LEN + OPCODE_LEN; /* For final KET and END */ - - cd.numCapturingBrackets = bracount; - return length; -} - -/************************************************* -* Compile a Regular Expression * -*************************************************/ - -/* This function takes a string and returns a pointer to a block of store -holding a compiled version of the expression. The original API for this -function had no error code return variable; it is retained for backwards -compatibility. The new function is given a new name. - -Arguments: - pattern the regular expression - options various option bits - errorCodePtr pointer to error code variable (pcre_compile2() only) - can be NULL if you don't want a code value - error pointer to pointer to error text - erroroffset ptr offset in pattern where error was detected - tables pointer to character tables or NULL - -Returns: pointer to compiled data block, or NULL on error, - with error and erroroffset set -*/ - -static inline JSRegExp* returnError(ErrorCode errorcode, int *error) -{ - *error = static_cast(errorcode); - return 0; -} - -JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, - JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline, - unsigned* numSubpatterns, int *error) -{ - /* We can't pass back an error message if error is NULL; I guess the best we - can do is just return NULL, but we can set a code value if there is a code pointer. */ - if (!error) - return 0; - *error = 0; - - CompileData cd; - - ErrorCode errorcode = ERR0; - /* Call this once just to count the brackets. */ - calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); - /* Call it again to compute the length. */ - int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); - if (errorcode) - return returnError(errorcode, error); - - if (length > MAX_PATTERN_SIZE) - return returnError(ERR16, error); - - size_t size = length + sizeof(JSRegExp); - JSRegExp* re = reinterpret_cast(js::OffTheBooks::array_new(size)); - if (!re) - return returnError(ERR13, error); - - re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0); - - /* The starting points of the name/number translation table and of the code are - passed around in the compile data block. */ - - const unsigned char* codeStart = (const unsigned char*)(re + 1); - - /* Set up a starting, non-extracting bracket, then compile the expression. On - error, errorcode will be set non-zero, so we don't need to look at the result - of the function here. */ - - const UChar* ptr = (const UChar*)pattern; - const UChar* patternEnd = pattern + patternLength; - unsigned char* code = const_cast(codeStart); - int firstByte, reqByte; - int bracketCount = 0; - if (!cd.needOuterBracket) - compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstByte, &reqByte, cd); - else { - *code = OP_BRA; - unsigned char * const codeBefore = code; - compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 2, &firstByte, &reqByte, cd); - JS_ASSERT((bracketCount & 0xff) == bracketCount); - put2ByteValue(codeBefore + 1 + LINK_SIZE, 0 << 8 | (bracketCount & 0xff)); - } - re->topBracket = bracketCount; - re->topBackref = cd.topBackref; - - /* If not reached end of pattern on success, there's an excess bracket. */ - - if (errorcode == 0 && ptr < patternEnd) - errorcode = ERR10; - - /* Fill in the terminating state and check for disastrous overflow, but - if debugging, leave the test till after things are printed out. */ - - *code++ = OP_END; - - JS_ASSERT(code - codeStart <= length); - if (code - codeStart > length) - errorcode = ERR7; - - /* Give an error if there's back reference to a non-existent capturing - subpattern. */ - - if (re->topBackref > re->topBracket) - errorcode = ERR15; - - /* Failed to compile, or error while post-processing */ - - if (errorcode != ERR0) { - js::Foreground::array_delete(reinterpret_cast(re)); - return returnError(errorcode, error); - } - - /* If the anchored option was not passed, set the flag if we can determine that - the pattern is anchored by virtue of ^ characters or \A or anything else (such - as starting with .* when DOTALL is set). - - Otherwise, if we know what the first character has to be, save it, because that - speeds up unanchored matches no end. If not, see if we can set the - UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches - start with ^. and also when all branches start with .* for non-DOTALL matches. - */ - - if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart)) - re->options |= IsAnchoredOption; - else { - if (firstByte < 0) { - firstByte = (cd.needOuterBracket - ? bracketFindFirstAssertedCharacter(codeStart, false) - : branchFindFirstAssertedCharacter(codeStart, false)) - | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0); - } - if (firstByte >= 0) { - int ch = firstByte & 255; - if (ch < 127) { - re->firstByte = ((firstByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstByte; - re->options |= UseFirstByteOptimizationOption; - } - } else { - if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap)) - re->options |= UseMultiLineFirstByteOptimizationOption; - } - } - - /* For an anchored pattern, we use the "required byte" only if it follows a - variable length item in the regex. Remove the caseless flag for non-caseable - bytes. */ - - if (reqByte >= 0 && (!(re->options & IsAnchoredOption) || (reqByte & REQ_VARY))) { - int ch = reqByte & 255; - if (ch < 127) { - re->reqByte = ((reqByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqByte & ~REQ_IGNORE_CASE) : reqByte; - re->options |= UseRequiredByteOptimizationOption; - } - } - - if (numSubpatterns) - *numSubpatterns = re->topBracket; - - return re; -} - -void jsRegExpFree(JSRegExp* re) -{ - js::Foreground::array_delete(reinterpret_cast(re)); -} diff --git a/js/src/yarr/pcre/pcre_exec.cpp b/js/src/yarr/pcre/pcre_exec.cpp deleted file mode 100644 index c2d154d67b8e..000000000000 --- a/js/src/yarr/pcre/pcre_exec.cpp +++ /dev/null @@ -1,2193 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - Copyright (C) 2007 Eric Seidel - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains jsRegExpExecute(), the externally visible function -that does pattern matching using an NFA algorithm, following the rules from -the JavaScript specification. There are also some supporting functions. */ - -#include "pcre_internal.h" - -#include -#include "yarr/jswtfbridge.h" -#include "yarr/wtf/ASCIICType.h" -#include "jsarena.h" -#include "jscntxt.h" - -using namespace WTF; - -#if !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO -#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION -#endif - -/* Note: Webkit sources have USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP disabled. */ -/* Note: There are hardcoded constants all over the place, but in the port of - Yarr to TraceMonkey two bytes are added to the OP_BRA* opcodes, so the - instruction stream now looks like this at the start of a bracket group: - - OP_BRA* [link:LINK_SIZE] [minNestedBracket,maxNestedBracket:2] - - Both capturing and non-capturing brackets encode this information. */ - -/* Avoid warnings on Windows. */ -#undef min -#undef max - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION -typedef int ReturnLocation; -#else -typedef void* ReturnLocation; -#endif - -/* Node on a stack of brackets. This is used to detect and reject - matches of the empty string per ECMAScript repeat match rules. This - also prevents infinite loops on quantified empty matches. One node - represents the start state at the start of this bracket group. */ -struct BracketChainNode { - BracketChainNode* previousBracket; - const UChar* bracketStart; - /* True if the minimum number of matches was already satisfied - when we started matching this group. */ - bool minSatisfied; -}; - -struct MatchFrame { - ReturnLocation returnLocation; - struct MatchFrame* previousFrame; - int *savedOffsets; - /* The frame allocates saved offsets into the regular expression arena pool so - that they can be restored during backtracking. */ - size_t savedOffsetsSize; - JSArenaPool *regExpPool; - - MatchFrame() : savedOffsetsSize(0), regExpPool(0) {} - void init(JSArenaPool *regExpPool) { this->regExpPool = regExpPool; } - - /* Function arguments that may change */ - struct { - const UChar* subjectPtr; - const unsigned char* instructionPtr; - int offsetTop; - BracketChainNode* bracketChain; - } args; - - - /* PCRE uses "fake" recursion built off of gotos, thus - stack-based local variables are not safe to use. Instead we have to - store local variables on the current MatchFrame. */ - struct { - const unsigned char* data; - const unsigned char* startOfRepeatingBracket; - const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare - const unsigned char* instructionPtrAtStartOfOnce; - - int repeatOthercase; - int savedSubjectOffset; - - int ctype; - int fc; - int fi; - int length; - int max; - int number; - int offset; - int skipBytes; - int minBracket; - int limitBracket; - int bracketsBefore; - bool minSatisfied; - - BracketChainNode bracketChainNode; - } locals; - - void saveOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - JS_ASSERT(regExpPool); - JS_ASSERT(minBracket >= 0); - JS_ASSERT(limitBracket >= minBracket); - JS_ASSERT(offsetEnd >= 0); - if (minBracket == limitBracket) - return; - const size_t newSavedOffsetCount = 3 * (limitBracket - minBracket); - /* Increase saved offset space if necessary. */ - { - size_t targetSize = sizeof(*savedOffsets) * newSavedOffsetCount; - if (savedOffsetsSize < targetSize) { - JS_ARENA_ALLOCATE_CAST(savedOffsets, int *, regExpPool, targetSize); - JS_ASSERT(savedOffsets); /* FIXME: error code, bug 574459. */ - savedOffsetsSize = targetSize; - } - } - for (unsigned i = 0; i < unsigned(limitBracket - minBracket); ++i) { - int bracketIter = minBracket + i; - JS_ASSERT(2 * bracketIter + 1 <= offsetEnd); - int start = offsets[2 * bracketIter]; - int end = offsets[2 * bracketIter + 1]; - JS_ASSERT(bracketIter <= offsetEnd); - int offset = offsets[offsetEnd - bracketIter]; - DPRINTF(("saving bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); - JS_ASSERT(start <= end); - JS_ASSERT(i * 3 + 2 < newSavedOffsetCount); - savedOffsets[i * 3 + 0] = start; - savedOffsets[i * 3 + 1] = end; - savedOffsets[i * 3 + 2] = offset; - } - } - - void clobberOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - for (int i = 0; i < limitBracket - minBracket; ++i) { - int bracketIter = minBracket + i; - JS_ASSERT(2 * bracketIter + 1 < offsetEnd); - offsets[2 * bracketIter + 0] = -1; - offsets[2 * bracketIter + 1] = -1; - } - } - - void restoreOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { - JS_ASSERT(regExpPool); - JS_ASSERT_IF(limitBracket > minBracket, savedOffsets); - for (int i = 0; i < limitBracket - minBracket; ++i) { - int bracketIter = minBracket + i; - int start = savedOffsets[i * 3 + 0]; - int end = savedOffsets[i * 3 + 1]; - int offset = savedOffsets[i * 3 + 2]; - DPRINTF(("restoring bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); - JS_ASSERT(start <= end); - offsets[2 * bracketIter + 0] = start; - offsets[2 * bracketIter + 1] = end; - offsets[offsetEnd - bracketIter] = offset; - } - } - - /* Extract the bracket data after the current opcode/link at |instructionPtr| into the locals. */ - void extractBrackets(const unsigned char *instructionPtr) { - uint16 bracketMess = get2ByteValue(instructionPtr + 1 + LINK_SIZE); - locals.minBracket = (bracketMess >> 8) & 0xff; - locals.limitBracket = (bracketMess & 0xff); - JS_ASSERT(locals.minBracket <= locals.limitBracket); - } - - /* At the start of a bracketed group, add the current subject pointer to the - stack of such pointers, to be re-instated at the end of the group when we hit - the closing ket. When match() is called in other circumstances, we don't add to - this stack. */ - void startNewGroup(bool minSatisfied) { - locals.bracketChainNode.previousBracket = args.bracketChain; - locals.bracketChainNode.bracketStart = args.subjectPtr; - locals.bracketChainNode.minSatisfied = minSatisfied; - args.bracketChain = &locals.bracketChainNode; - } -}; - -/* Structure for passing "static" information around between the functions -doing traditional NFA matching, so that they are thread-safe. */ - -struct MatchData { - int *offsetVector; /* Offset vector */ - int offsetEnd; /* One past the end */ - int offsetMax; /* The maximum usable for return data */ - bool offsetOverflow; /* Set if too many extractions */ - const UChar *startSubject; /* Start of the subject string */ - const UChar *endSubject; /* End of the subject string */ - const UChar *endMatchPtr; /* Subject position at end match */ - int endOffsetTop; /* Highwater mark at end of match */ - bool multiline; - bool ignoreCase; - - void setOffsetPair(size_t pairNum, int start, int end) { - JS_ASSERT(int(2 * pairNum + 1) < offsetEnd && int(pairNum) < offsetEnd); - JS_ASSERT(start <= end); - JS_ASSERT_IF(start < 0, start == end && start == -1); - DPRINTF(("setting offset pair at %u (%d, %d)\n", pairNum, start, end)); - offsetVector[2 * pairNum + 0] = start; - offsetVector[2 * pairNum + 1] = end; - } -}; - -/* The maximum remaining length of subject we are prepared to search for a -reqByte match. */ - -#define REQ_BYTE_MAX 1000 - -/* The below limit restricts the number of "recursive" match calls in order to -avoid spending exponential time on complex regular expressions. */ - -static const unsigned matchLimit = 1000000; - -/************************************************* -* Match a back-reference * -*************************************************/ - -/* If a back reference hasn't been set, the length that is passed is greater -than the number of characters left in the string, so the match fails. - -Arguments: - offset index into the offset vector - subjectPtr points into the subject - length length to be matched - md points to match data block - -Returns: true if matched -*/ - -static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md) -{ - const UChar* p = md.startSubject + md.offsetVector[offset]; - - /* Always fail if not enough characters left */ - - if (length > md.endSubject - subjectPtr) - return false; - - /* Separate the caselesss case for speed */ - - if (md.ignoreCase) { - while (length-- > 0) { - UChar c = *p++; - int othercase = jsc_pcre_ucp_othercase(c); - UChar d = *subjectPtr++; - if (c != d && othercase != d) - return false; - } - } - else { - while (length-- > 0) - if (*p++ != *subjectPtr++) - return false; - } - - return true; -} - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - -/* Use numbered labels and switch statement at the bottom of the match function. */ - -#define RMATCH_WHERE(num) num -#define RRETURN_LABEL RRETURN_SWITCH - -#else - -/* Use GCC's computed goto extension. */ - -/* For one test case this is more than 40% faster than the switch statement. -We could avoid the use of the num argument entirely by using local labels, -but using it for the GCC case as well as the non-GCC case allows us to share -a bit more code and notice if we use conflicting numbers.*/ - -#define RMATCH_WHERE(num) JS_EXTENSION(&&RRETURN_##num) -#define RRETURN_LABEL *stack.currentFrame->returnLocation - -#endif - -#define RECURSIVE_MATCH_COMMON(num) \ - goto RECURSE;\ - RRETURN_##num: \ - stack.popCurrentFrame(); - -#define RECURSIVE_MATCH(num, ra, rb) \ - do { \ - stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ - RECURSIVE_MATCH_COMMON(num) \ - } while (0) - -#define RECURSIVE_MATCH_NEW_GROUP(num, ra, rb, gm) \ - do { \ - stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ - stack.currentFrame->startNewGroup(gm); \ - RECURSIVE_MATCH_COMMON(num) \ - } while (0) - -#define RRETURN do { JS_EXTENSION_(goto RRETURN_LABEL); } while (0) - -#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0) - -/************************************************* -* Match from current position * -*************************************************/ - -/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character -in the subject string, while substringStart holds the value of subjectPtr at the start of the -last bracketed group - used for breaking infinite loops matching zero-length -strings. This function is called recursively in many circumstances. Whenever it -returns a negative (error) response, the outer match() call must also return the -same response. - -Arguments: - subjectPtr pointer in subject - instructionPtr position in code - offsetTop current top pointer - md pointer to "static" info for the match - -Returns: 1 if matched ) these values are >= 0 - 0 if failed to match ) - a negative error value if aborted by an error condition - (e.g. stopped by repeated call or recursion limit) -*/ - -static const unsigned numFramesOnStack = 16; - -struct MatchStack { - JSArenaPool *regExpPool; - void *regExpPoolMark; - - MatchStack(JSArenaPool *regExpPool) - : regExpPool(regExpPool) - , regExpPoolMark(JS_ARENA_MARK(regExpPool)) - , framesEnd(frames + numFramesOnStack) - , currentFrame(frames) - , size(1) // match() creates accesses the first frame w/o calling pushNewFrame - { - JS_ASSERT((sizeof(frames) / sizeof(frames[0])) == numFramesOnStack); - JS_ASSERT(regExpPool); - for (size_t i = 0; i < numFramesOnStack; ++i) - frames[i].init(regExpPool); - } - - ~MatchStack() { JS_ARENA_RELEASE(regExpPool, regExpPoolMark); } - - MatchFrame frames[numFramesOnStack]; - MatchFrame* framesEnd; - MatchFrame* currentFrame; - unsigned size; - - bool canUseStackBufferForNextFrame() { - return size < numFramesOnStack; - } - - MatchFrame* allocateNextFrame() { - if (canUseStackBufferForNextFrame()) - return currentFrame + 1; - // FIXME: bug 574459 -- no NULL check - MatchFrame *frame = js::OffTheBooks::new_(); - frame->init(regExpPool); - return frame; - } - - void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation) { - MatchFrame* newframe = allocateNextFrame(); - newframe->previousFrame = currentFrame; - - newframe->args.subjectPtr = currentFrame->args.subjectPtr; - newframe->args.offsetTop = currentFrame->args.offsetTop; - newframe->args.instructionPtr = instructionPtr; - newframe->args.bracketChain = bracketChain; - newframe->returnLocation = returnLocation; - size++; - - currentFrame = newframe; - } - - void popCurrentFrame() { - MatchFrame* oldFrame = currentFrame; - currentFrame = currentFrame->previousFrame; - if (size > numFramesOnStack) - js::Foreground::delete_(oldFrame); - size--; - } - - void popAllFrames() { - while (size) - popCurrentFrame(); - } -}; - -static int matchError(int errorCode, MatchStack& stack) -{ - stack.popAllFrames(); - return errorCode; -} - -/* Get the next UTF-8 character, not advancing the pointer, incrementing length - if there are extra bytes. This is called when we know we are in UTF-8 mode. */ - -static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len) -{ - c = *subjectPtr; - if ((c & 0xc0) == 0xc0) { - int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ - int gcss = 6 * gcaa; - c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; - for (int gcii = 1; gcii <= gcaa; gcii++) { - gcss -= 6; - c |= (subjectPtr[gcii] & 0x3f) << gcss; - } - len += gcaa; - } -} - -static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats) -{ - // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR - static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 }; - static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 }; - - JS_ASSERT(instructionOffset >= 0); - JS_ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR)); - - minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2 - minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset]; - maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset]; -} - -/* Helper class for passing a flag value from one op to the next that runs. - This allows us to set the flag in certain ops. When the flag is read, it - will be true only if the previous op set the flag, otherwise it is false. */ -class LinearFlag { -public: - LinearFlag() : flag(false) {} - - bool readAndClear() { - bool rv = flag; - flag = false; - return rv; - } - - void set() { - flag = true; - } - -private: - bool flag; -}; - -static int -match(JSArenaPool *regExpPool, const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md) -{ - bool isMatch = false; - int min; - bool minimize = false; /* Initialization not really needed, but some compilers think so. */ - unsigned remainingMatchCount = matchLimit; - int othercase; /* Declare here to avoid errors during jumps */ - bool minSatisfied; - - MatchStack stack(regExpPool); - LinearFlag minSatNextBracket; - - /* The opcode jump table. */ -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP -#define EMIT_JUMP_TABLE_ENTRY(opcode) JS_EXTENSION(&&LABEL_OP_##opcode) - static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) }; -#undef EMIT_JUMP_TABLE_ENTRY -#endif - - /* One-time setup of the opcode jump table. */ -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - for (int i = 255; !opcodeJumpTable[i]; i--) - opcodeJumpTable[i] = &&CAPTURING_BRACKET; -#endif - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - // Shark shows this as a hot line - // Using a static const here makes this line disappear, but makes later access hotter (not sure why) - stack.currentFrame->returnLocation = JS_EXTENSION(&&RETURN); -#else - stack.currentFrame->returnLocation = 0; -#endif - stack.currentFrame->args.subjectPtr = subjectPtr; - stack.currentFrame->args.instructionPtr = instructionPtr; - stack.currentFrame->args.offsetTop = offsetTop; - stack.currentFrame->args.bracketChain = 0; - stack.currentFrame->startNewGroup(false); - - /* This is where control jumps back to to effect "recursion" */ - -RECURSE: - if (!--remainingMatchCount) - return matchError(JSRegExpErrorHitLimit, stack); - - /* Now start processing the operations. */ - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - while (true) -#endif - { - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP -#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode -#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr] -#else -#define BEGIN_OPCODE(opcode) case OP_##opcode -#define NEXT_OPCODE continue -#endif -#define LOCALS(__ident) (stack.currentFrame->locals.__ident) - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - NEXT_OPCODE; -#else - switch (*stack.currentFrame->args.instructionPtr) -#endif - { - /* Non-capturing bracket: optimized */ - - BEGIN_OPCODE(BRA): - NON_CAPTURING_BRACKET: - DPRINTF(("start non-capturing bracket\n")); - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); - /* If we see no ALT, we have to skip three bytes of bracket data (link plus nested - bracket data. */ - stack.currentFrame->locals.skipBytes = 3; - /* We must compute this value at the top, before we move the instruction pointer. */ - stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); - do { - /* We need to extract this into a variable so we can correctly pass it by value - through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ - minSatisfied = stack.currentFrame->locals.minSatisfied; - RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); - if (isMatch) { - DPRINTF(("non-capturing bracket succeeded\n")); - RRETURN; - } - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - DPRINTF(("non-capturing bracket failed\n")); - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - RRETURN; - - /* Skip over large extraction number data if encountered. */ - - BEGIN_OPCODE(BRANUMBER): - stack.currentFrame->args.instructionPtr += 3; - NEXT_OPCODE; - - /* End of the pattern. */ - - BEGIN_OPCODE(END): - md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */ - md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */ - isMatch = true; - RRETURN; - - /* Assertion brackets. Check the alternative branches in turn - the - matching won't pass the KET for an assertion. If any one branch matches, - the assertion is true. Lookbehind assertions have an OP_REVERSE item at the - start of each branch to move the current point backwards, so the code at - this level is identical to the lookahead case. */ - - BEGIN_OPCODE(ASSERT): - { - uint16 bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); - LOCALS(minBracket) = (bracketMess >> 8) & 0xff; - LOCALS(limitBracket) = bracketMess & 0xff; - JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); - } - stack.currentFrame->locals.skipBytes = 3; - do { - RECURSIVE_MATCH_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); - if (isMatch) - break; - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - if (*stack.currentFrame->args.instructionPtr == OP_KET) { - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - RRETURN_NO_MATCH; - } - - /* Continue from after the assertion, updating the offsets high water - mark, since extracts may have been taken during the assertion. */ - - advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); - stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; - stack.currentFrame->args.offsetTop = md.endOffsetTop; - NEXT_OPCODE; - - /* Negative assertion: all branches must fail to match */ - - BEGIN_OPCODE(ASSERT_NOT): - stack.currentFrame->locals.skipBytes = 3; - { - unsigned bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); - LOCALS(minBracket) = (bracketMess >> 8) & 0xff; - LOCALS(limitBracket) = bracketMess & 0xff; - } - JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); - do { - RECURSIVE_MATCH_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); - if (isMatch) - RRETURN_NO_MATCH; - stack.currentFrame->locals.skipBytes = 1; - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.skipBytes + LINK_SIZE; - NEXT_OPCODE; - - /* An alternation is the end of a branch; scan along to find the end of the - bracketed group and go to there. */ - - BEGIN_OPCODE(ALT): - advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); - NEXT_OPCODE; - - /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating - that it may occur zero times. It may repeat infinitely, or not at all - - i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper - repeat limits are compiled as a number of copies, with the optional ones - preceded by BRAZERO or BRAMINZERO. */ - - BEGIN_OPCODE(BRAZERO): { - stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain, true); - if (isMatch) - RRETURN; - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); - stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE; - NEXT_OPCODE; - } - - BEGIN_OPCODE(BRAMINZERO): { - stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; - advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); - RECURSIVE_MATCH_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain, false); - if (isMatch) - RRETURN; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - } - - /* End of a group, repeated or non-repeating. If we are at the end of - an assertion "group", stop matching and return 1, but record the - current high water mark for use by positive assertions. Do this also - for the "once" (not-backup up) groups. */ - - BEGIN_OPCODE(KET): - BEGIN_OPCODE(KETRMIN): - BEGIN_OPCODE(KETRMAX): - stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart; - stack.currentFrame->locals.minSatisfied = stack.currentFrame->args.bracketChain->minSatisfied; - - /* Back up the stack of bracket start pointers. */ - - stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket; - - if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) { - md.endOffsetTop = stack.currentFrame->args.offsetTop; - isMatch = true; - RRETURN; - } - - /* In all other cases except a conditional group we have to check the - group number back at the start and if necessary complete handling an - extraction by setting the offsets and bumping the high water mark. */ - - stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA; - - /* For extended extraction brackets (large number), we have to fish out - the number from a dummy opcode at the start. */ - - if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) - stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 4 + LINK_SIZE); - stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; - - DPRINTF(("end bracket %d\n", stack.currentFrame->locals.number)); - - /* Test for a numbered group. This includes groups called as a result - of recursion. Note that whole-pattern recursion is coded as a recurse - into group 0, so it won't be picked up here. Instead, we catch it when - the OP_END is reached. */ - - if (stack.currentFrame->locals.number > 0) { - if (stack.currentFrame->locals.offset >= md.offsetMax) - md.offsetOverflow = true; - else { - int start = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; - int end = stack.currentFrame->args.subjectPtr - md.startSubject; - if (start == end && stack.currentFrame->locals.minSatisfied) { - DPRINTF(("empty string while group already matched; bailing")); - RRETURN_NO_MATCH; - } - DPRINTF(("saving; start: %d; end: %d\n", start, end)); - JS_ASSERT(start <= end); - md.setOffsetPair(stack.currentFrame->locals.number, start, end); - if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset) - stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2; - } - } - - /* For a non-repeating ket, just continue at this level. This also - happens for a repeating ket if no characters were matched in the group. - This is the forcible breaking of infinite loops as implemented in Perl - 5.005. If there is an options reset, it will get obeyed in the normal - course of events. */ - - if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - DPRINTF(("non-repeating ket or empty match\n")); - if (stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction && stack.currentFrame->locals.minSatisfied) { - DPRINTF(("empty string while group already matched; bailing")); - RRETURN_NO_MATCH; - } - stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; - NEXT_OPCODE; - } - - /* The repeating kets try the rest of the pattern or restart from the - preceding bracket, in the appropriate order. */ - - stack.currentFrame->extractBrackets(LOCALS(instructionPtrAtStartOfOnce)); - JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); - if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) { - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - else - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - DPRINTF(("recursively matching lazy group\n")); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(17, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); - } else { /* OP_KETRMAX */ - stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - stack.currentFrame->clobberOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - DPRINTF(("recursively matching greedy group\n")); - minSatNextBracket.set(); - RECURSIVE_MATCH_NEW_GROUP(18, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); - if (isMatch) - RRETURN; - else - stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); - RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); - } - RRETURN; - - /* Start of subject. */ - - BEGIN_OPCODE(CIRC): - if (stack.currentFrame->args.subjectPtr != md.startSubject) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* After internal newline if multiline. */ - - BEGIN_OPCODE(BOL): - if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1])) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* End of subject. */ - - BEGIN_OPCODE(DOLL): - if (stack.currentFrame->args.subjectPtr < md.endSubject) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Before internal newline if multiline. */ - - BEGIN_OPCODE(EOL): - if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Word boundary assertions */ - - BEGIN_OPCODE(NOT_WORD_BOUNDARY): - BEGIN_OPCODE(WORD_BOUNDARY): { - bool currentCharIsWordChar = false; - bool previousCharIsWordChar = false; - - if (stack.currentFrame->args.subjectPtr > md.startSubject) - previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]); - if (stack.currentFrame->args.subjectPtr < md.endSubject) - currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr); - - /* Now see if the situation is what we want */ - bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY); - if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar) - RRETURN_NO_MATCH; - NEXT_OPCODE; - } - - /* Match a single character type; inline for speed */ - - BEGIN_OPCODE(NOT_NEWLINE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isNewline(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_DIGIT): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(DIGIT): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_WHITESPACE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isSpaceChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(WHITESPACE): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(NOT_WORDCHAR): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (isWordChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - BEGIN_OPCODE(WORDCHAR): - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (!isWordChar(*stack.currentFrame->args.subjectPtr++)) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr++; - NEXT_OPCODE; - - /* Match a back reference, possibly repeatedly. Look past the end of the - item to see if there is repeat information following. The code is similar - to that for character classes, but repeated for efficiency. Then obey - similar code to character type repeats - written out again for speed. - However, if the referenced string is the empty string, always treat - it as matched, any number of times (otherwise there could be infinite - loops). */ - - BEGIN_OPCODE(REF): - stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */ - stack.currentFrame->args.instructionPtr += 3; /* Advance past item */ - - /* If the reference is unset, set the length to be longer than the amount - of subject left; this ensures that every attempt at a match fails. We - can't just fail here, because of the possibility of quantifiers with zero - minima. */ - - if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0) - stack.currentFrame->locals.length = 0; - else - stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset]; - - /* Set up for repetition, or handle the non-repeated case */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - NEXT_OPCODE; - } - - /* If the length of the reference is zero, just continue with the - main loop. */ - - if (stack.currentFrame->locals.length == 0) - NEXT_OPCODE; - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - - /* If min = max, continue at the same level without recursion. - They are not both allowed to be zero. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep trying and advancing the pointer */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - RRETURN; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - /* Control never reaches here */ - } - - /* If maximizing, find the longest string and work backwards */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) - break; - stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - - /* Match a bit-mapped character class, possibly repeatedly. This op code is - used when all the characters in the class have values in the range 0-255, - and either the matching is caseful, or the characters are in the range - 0-127 when UTF-8 processing is enabled. The only difference between - OP_CLASS and OP_NCLASS occurs when a data character outside the range is - encountered. - - First, look past the end of the item to see if there is repeat information - following. Then obey similar code to character type repeats - written out - again for speed. */ - - BEGIN_OPCODE(NCLASS): - BEGIN_OPCODE(CLASS): - stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */ - stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - min = stack.currentFrame->locals.max = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int c = *stack.currentFrame->args.subjectPtr++; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - RRETURN_NO_MATCH; - } else { - if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) - RRETURN_NO_MATCH; - } - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - int c = *stack.currentFrame->args.subjectPtr++; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - RRETURN; - } else { - if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0) - RRETURN; - } - } - /* Control never reaches here */ - } - /* If maximizing, find the longest possible run, then work backwards. */ - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (c > 255) { - if (stack.currentFrame->locals.data[-1] == OP_CLASS) - break; - } else { - if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) - break; - } - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - /* Control never reaches here */ - - /* Match an extended character class. */ - - BEGIN_OPCODE(XCLASS): - stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */ - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */ - - switch (*stack.currentFrame->args.instructionPtr) { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); - min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); - if (stack.currentFrame->locals.max == 0) - stack.currentFrame->locals.max = INT_MAX; - stack.currentFrame->args.instructionPtr += 5; - break; - - default: /* No repeat follows */ - min = stack.currentFrame->locals.max = 1; - } - - /* First, ensure the minimum number of matches are present. */ - - for (int i = 1; i <= min; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int c = *stack.currentFrame->args.subjectPtr++; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - RRETURN_NO_MATCH; - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - int c = *stack.currentFrame->args.subjectPtr++; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - RRETURN; - } - /* Control never reaches here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) - break; - ++stack.currentFrame->args.subjectPtr; - } - for(;;) { - RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - RRETURN; - } - - /* Control never reaches here */ - - /* Match a single character, casefully */ - - BEGIN_OPCODE(CHAR): - stack.currentFrame->locals.length = 1; - stack.currentFrame->args.instructionPtr++; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++) - RRETURN_NO_MATCH; - NEXT_OPCODE; - - /* Match a single character, caselessly */ - - BEGIN_OPCODE(CHAR_IGNORING_CASE): { - stack.currentFrame->locals.length = 1; - stack.currentFrame->args.instructionPtr++; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int dc = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fc != dc && jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc) - RRETURN_NO_MATCH; - NEXT_OPCODE; - } - - /* Match a single ASCII character. */ - - BEGIN_OPCODE(ASCII_CHAR): - if (md.endSubject == stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1]) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - stack.currentFrame->args.instructionPtr += 2; - NEXT_OPCODE; - - /* Match one of two cases of an ASCII letter. */ - - BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE): - if (md.endSubject == stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1]) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - stack.currentFrame->args.instructionPtr += 2; - NEXT_OPCODE; - - /* Match a single character repeatedly; different opcodes share code. */ - - BEGIN_OPCODE(EXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = false; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATCHAR; - - BEGIN_OPCODE(UPTO): - BEGIN_OPCODE(MINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATCHAR; - - BEGIN_OPCODE(STAR): - BEGIN_OPCODE(MINSTAR): - BEGIN_OPCODE(PLUS): - BEGIN_OPCODE(MINPLUS): - BEGIN_OPCODE(QUERY): - BEGIN_OPCODE(MINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single-character matches. We can give - up quickly if there are fewer than the minimum number of characters left in - the subject. */ - - REPEATCHAR: - - stack.currentFrame->locals.length = 1; - getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); - if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; - - if (stack.currentFrame->locals.fc <= 0xFFFF) { - othercase = md.ignoreCase ? jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1; - - for (int i = 1; i <= min; i++) { - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - stack.currentFrame->locals.repeatOthercase = othercase; - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase) - RRETURN; - ++stack.currentFrame->args.subjectPtr; - } - /* Control never reaches here */ - } else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) - break; - ++stack.currentFrame->args.subjectPtr; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - --stack.currentFrame->args.subjectPtr; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - } else { - /* No case on surrogate pairs, so no need to bother with "othercase". */ - - for (int i = 1; i <= min; i++) { - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - RRETURN_NO_MATCH; - stack.currentFrame->args.subjectPtr += 2; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - RRETURN; - stack.currentFrame->args.subjectPtr += 2; - } - /* Control never reaches here */ - } else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr > md.endSubject - 2) - break; - if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) - break; - stack.currentFrame->args.subjectPtr += 2; - } - while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { - RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - stack.currentFrame->args.subjectPtr -= 2; - } - RRETURN_NO_MATCH; - } - /* Control never reaches here */ - } - /* Control never reaches here */ - - /* Match a negated single one-byte character. */ - - BEGIN_OPCODE(NOT): { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN_NO_MATCH; - int b = stack.currentFrame->args.instructionPtr[1]; - int c = *stack.currentFrame->args.subjectPtr++; - stack.currentFrame->args.instructionPtr += 2; - if (md.ignoreCase) { - if (c < 128) - c = toLowerCase(c); - if (toLowerCase(b) == c) - RRETURN_NO_MATCH; - } else { - if (b == c) - RRETURN_NO_MATCH; - } - NEXT_OPCODE; - } - - /* Match a negated single one-byte character repeatedly. This is almost a - repeat of the code for a repeated single character, but I haven't found a - nice way of commoning these up that doesn't require a test of the - positive/negative option for each character match. Maybe that wouldn't add - very much to the time taken, but character matching *is* what this is all - about... */ - - BEGIN_OPCODE(NOTEXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = false; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATNOTCHAR; - - BEGIN_OPCODE(NOTUPTO): - BEGIN_OPCODE(NOTMINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATNOTCHAR; - - BEGIN_OPCODE(NOTSTAR): - BEGIN_OPCODE(NOTMINSTAR): - BEGIN_OPCODE(NOTPLUS): - BEGIN_OPCODE(NOTMINPLUS): - BEGIN_OPCODE(NOTQUERY): - BEGIN_OPCODE(NOTMINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single-byte matches. We can give up quickly - if there are fewer than the minimum number of bytes left in the - subject. */ - - REPEATNOTCHAR: - if (min > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++; - - /* The code is duplicated for the caseless and caseful cases, for speed, - since matching characters is likely to be quite common. First, ensure the - minimum number of matches are present. If min = max, continue at the same - level without recursing. Otherwise, if minimizing, keep trying the rest of - the expression and advancing one matching character if failing, up to the - maximum. Alternatively, if maximizing, find the maximum number of - characters and work backwards. */ - - DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max)); - - if (md.ignoreCase) { - if (stack.currentFrame->locals.fc < 128) - stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc); - - for (int i = 1; i <= min; i++) { - int d = *stack.currentFrame->args.subjectPtr++; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fc == d) - RRETURN_NO_MATCH; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - int d = *stack.currentFrame->args.subjectPtr++; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) - RRETURN; - } - /* Control never reaches here */ - } - - /* Maximize case */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int d = *stack.currentFrame->args.subjectPtr; - if (d < 128) - d = toLowerCase(d); - if (stack.currentFrame->locals.fc == d) - break; - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - /* Control never reaches here */ - } - - /* Caseful comparisons */ - - else { - for (int i = 1; i <= min; i++) { - int d = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fc == d) - RRETURN_NO_MATCH; - } - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - int d = *stack.currentFrame->args.subjectPtr++; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) - RRETURN; - } - /* Control never reaches here */ - } - - /* Maximize case */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; - - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int d = *stack.currentFrame->args.subjectPtr; - if (stack.currentFrame->locals.fc == d) - break; - ++stack.currentFrame->args.subjectPtr; - } - for (;;) { - RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - RRETURN; - } - } - /* Control never reaches here */ - - /* Match a single character type repeatedly; several different opcodes - share code. This is very similar to the code for single characters, but we - repeat it in the interests of efficiency. */ - - BEGIN_OPCODE(TYPEEXACT): - min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = true; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATTYPE; - - BEGIN_OPCODE(TYPEUPTO): - BEGIN_OPCODE(TYPEMINUPTO): - min = 0; - stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); - minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO; - stack.currentFrame->args.instructionPtr += 3; - goto REPEATTYPE; - - BEGIN_OPCODE(TYPESTAR): - BEGIN_OPCODE(TYPEMINSTAR): - BEGIN_OPCODE(TYPEPLUS): - BEGIN_OPCODE(TYPEMINPLUS): - BEGIN_OPCODE(TYPEQUERY): - BEGIN_OPCODE(TYPEMINQUERY): - repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max); - - /* Common code for all repeated single character type matches. Note that - in UTF-8 mode, '.' matches a character of any length, but for the other - character types, the valid characters are all one-byte long. */ - - REPEATTYPE: - stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */ - - /* First, ensure the minimum number of matches are present. Use inline - code for maximizing the speed, and do the type test once at the start - (i.e. keep it out of the loop). Also we can test that there are at least - the minimum number of characters before we start. */ - - if (min > md.endSubject - stack.currentFrame->args.subjectPtr) - RRETURN_NO_MATCH; - if (min > 0) { - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - for (int i = 1; i <= min; i++) { - if (isNewline(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_DIGIT: - for (int i = 1; i <= min; i++) { - if (isASCIIDigit(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_DIGIT: - for (int i = 1; i <= min; i++) { - if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WHITESPACE: - for (int i = 1; i <= min; i++) { - if (isSpaceChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WHITESPACE: - for (int i = 1; i <= min; i++) { - if (!isSpaceChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WORDCHAR: - for (int i = 1; i <= min; i++) { - if (isWordChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WORDCHAR: - for (int i = 1; i <= min; i++) { - if (!isWordChar(*stack.currentFrame->args.subjectPtr)) - RRETURN_NO_MATCH; - ++stack.currentFrame->args.subjectPtr; - } - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } /* End switch(stack.currentFrame->locals.ctype) */ - } - - /* If min = max, continue at the same level without recursing */ - - if (min == stack.currentFrame->locals.max) - NEXT_OPCODE; - - /* If minimizing, we have to test the rest of the pattern before each - subsequent match. */ - - if (minimize) { - for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { - RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) - RRETURN; - - int c = *stack.currentFrame->args.subjectPtr++; - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - if (isNewline(c)) - RRETURN; - break; - - case OP_NOT_DIGIT: - if (isASCIIDigit(c)) - RRETURN; - break; - - case OP_DIGIT: - if (!isASCIIDigit(c)) - RRETURN; - break; - - case OP_NOT_WHITESPACE: - if (isSpaceChar(c)) - RRETURN; - break; - - case OP_WHITESPACE: - if (!isSpaceChar(c)) - RRETURN; - break; - - case OP_NOT_WORDCHAR: - if (isWordChar(c)) - RRETURN; - break; - - case OP_WORDCHAR: - if (!isWordChar(c)) - RRETURN; - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } - } - /* Control never reaches here */ - } - - /* If maximizing it is worth using inline code for speed, doing the type - test once at the start (i.e. keep it out of the loop). */ - - else { - stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */ - - switch (stack.currentFrame->locals.ctype) { - case OP_NOT_NEWLINE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr)) - break; - stack.currentFrame->args.subjectPtr++; - } - break; - - case OP_NOT_DIGIT: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isASCIIDigit(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_DIGIT: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isASCIIDigit(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WHITESPACE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isSpaceChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WHITESPACE: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isSpaceChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_NOT_WORDCHAR: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (isWordChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - case OP_WORDCHAR: - for (int i = min; i < stack.currentFrame->locals.max; i++) { - if (stack.currentFrame->args.subjectPtr >= md.endSubject) - break; - int c = *stack.currentFrame->args.subjectPtr; - if (!isWordChar(c)) - break; - ++stack.currentFrame->args.subjectPtr; - } - break; - - default: - JS_NOT_REACHED("Invalid character type."); - return matchError(JSRegExpErrorInternal, stack); - } - - /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */ - - for (;;) { - RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); - if (isMatch) - RRETURN; - if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) - break; /* Stop if tried at original pos */ - } - - /* Get here if we can't make it match with any permitted repetitions */ - - RRETURN; - } - /* Control never reaches here */ - - BEGIN_OPCODE(CRMINPLUS): - BEGIN_OPCODE(CRMINQUERY): - BEGIN_OPCODE(CRMINRANGE): - BEGIN_OPCODE(CRMINSTAR): - BEGIN_OPCODE(CRPLUS): - BEGIN_OPCODE(CRQUERY): - BEGIN_OPCODE(CRRANGE): - BEGIN_OPCODE(CRSTAR): - JS_NOT_REACHED("Invalid opcode."); - return matchError(JSRegExpErrorInternal, stack); - -#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP - CAPTURING_BRACKET: -#else - default: -#endif - /* Opening capturing bracket. If there is space in the offset vector, save - the current subject position in the working slot at the top of the vector. We - mustn't change the current values of the data slot, because they may be set - from a previous iteration of this group, and be referred to by a reference - inside the group. - - If the bracket fails to match, we need to restore this value and also the - values of the final offsets, in case they were set by a previous iteration of - the same bracket. - - If there isn't enough space in the offset vector, treat this as if it were a - non-capturing bracket. Don't worry about setting the flag for the error case - here; that is handled in the code for KET. */ - - JS_ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA); - - LOCALS(number) = *stack.currentFrame->args.instructionPtr - OP_BRA; - stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); - DPRINTF(("opening capturing bracket %d\n", stack.currentFrame->locals.number)); - - /* For extended extraction brackets (large number), we have to fish out the - number from a dummy opcode at the start. */ - - if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) - stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 4 + LINK_SIZE); - stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; - - JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); - - if (stack.currentFrame->locals.offset < md.offsetMax) { - stack.currentFrame->locals.savedSubjectOffset = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; - DPRINTF(("setting subject offset for bracket to %d\n", stack.currentFrame->args.subjectPtr - md.startSubject)); - md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject; - stack.currentFrame->locals.skipBytes = 3; /* For OP_BRAs. */ - - /* We must compute this value at the top, before we move the instruction pointer. */ - stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); - do { - /* We need to extract this into a variable so we can correctly pass it by value - through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ - minSatisfied = stack.currentFrame->locals.minSatisfied; - RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); - if (isMatch) - RRETURN; - stack.currentFrame->locals.skipBytes = 1; /* For OP_ALTs. */ - stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); - } while (*stack.currentFrame->args.instructionPtr == OP_ALT); - - DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number)); - for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) - md.setOffsetPair(i, -1, -1); - DPRINTF(("restoring subject offset for bracket to %d\n", stack.currentFrame->locals.savedSubjectOffset)); - md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.savedSubjectOffset; - - RRETURN; - } - - /* Insufficient room for saving captured contents */ - - goto NON_CAPTURING_BRACKET; - } - - /* Do not stick any code in here without much thought; it is assumed - that "continue" in the code above comes out to here to repeat the main - loop. */ - - } /* End of main loop */ - - JS_NOT_REACHED("Loop does not fallthru."); - -#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION - -RRETURN_SWITCH: - switch (stack.currentFrame->returnLocation) { - case 0: goto RETURN; - case 1: goto RRETURN_1; - case 2: goto RRETURN_2; - case 6: goto RRETURN_6; - case 7: goto RRETURN_7; - case 14: goto RRETURN_14; - case 15: goto RRETURN_15; - case 16: goto RRETURN_16; - case 17: goto RRETURN_17; - case 18: goto RRETURN_18; - case 19: goto RRETURN_19; - case 20: goto RRETURN_20; - case 21: goto RRETURN_21; - case 22: goto RRETURN_22; - case 24: goto RRETURN_24; - case 26: goto RRETURN_26; - case 27: goto RRETURN_27; - case 28: goto RRETURN_28; - case 29: goto RRETURN_29; - case 30: goto RRETURN_30; - case 31: goto RRETURN_31; - case 38: goto RRETURN_38; - case 40: goto RRETURN_40; - case 42: goto RRETURN_42; - case 44: goto RRETURN_44; - case 48: goto RRETURN_48; - case 52: goto RRETURN_52; - } - - JS_NOT_REACHED("Bad computed return location."); - return matchError(JSRegExpErrorInternal, stack); - -#endif - -RETURN: - return isMatch; -} - - -/************************************************* -* Execute a Regular Expression * -*************************************************/ - -/* This function applies a compiled re to a subject string and picks out -portions of the string if it matches. Two elements in the vector are set for -each substring: the offsets to the start and end of the substring. - -Arguments: - re points to the compiled expression - extra_data points to extra data or is NULL - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - offsets points to a vector of ints to be filled in with offsets - offsetCount the number of elements in the vector - -Returns: > 0 => success; value is the number of elements filled in - = 0 => success, but offsets is not big enough - -1 => failed to match - < -1 => some kind of unexpected problem -*/ - -static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int firstByte, bool firstByteIsCaseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart) -{ - // If firstByte is set, try scanning to the first instance of that byte - // no need to try and match against any earlier part of the subject string. - if (firstByte >= 0) { - UChar firstChar = firstByte; - if (firstByteIsCaseless) - while (subjectPtr < endSubject) { - int c = *subjectPtr; - if (c > 127) - break; - if (toLowerCase(c) == firstChar) - break; - subjectPtr++; - } - else { - while (subjectPtr < endSubject && *subjectPtr != firstChar) - subjectPtr++; - } - } else if (useMultiLineFirstCharOptimization) { - /* Or to just after \n for a multiline match if possible */ - // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07 - if (subjectPtr > originalSubjectStart) { - while (subjectPtr < endSubject && !isNewline(subjectPtr[-1])) - subjectPtr++; - } - } -} - -static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int reqByte, int reqByte2, bool reqByteIsCaseless, bool hasFirstByte, const UChar*& reqBytePtr) -{ - /* If reqByte is set, we know that that character must appear in the subject - for the match to succeed. If the first character is set, reqByte must be - later in the subject; otherwise the test starts at the match point. This - optimization can save a huge amount of backtracking in patterns with nested - unlimited repeats that aren't going to match. Writing separate code for - cased/caseless versions makes it go faster, as does using an autoincrement - and backing off on a match. - - HOWEVER: when the subject string is very, very long, searching to its end can - take a long time, and give bad performance on quite ordinary patterns. This - showed up when somebody was matching /^C/ on a 32-megabyte string... so we - don't do this when the string is sufficiently long. - */ - - if (reqByte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) { - const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0); - - /* We don't need to repeat the search if we haven't yet reached the - place we found it at last time. */ - - if (p > reqBytePtr) { - if (reqByteIsCaseless) { - while (p < endSubject) { - int pp = *p++; - if (pp == reqByte || pp == reqByte2) { - p--; - break; - } - } - } else { - while (p < endSubject) { - if (*p++ == reqByte) { - p--; - break; - } - } - } - - /* If we can't find the required character, break the matching loop */ - - if (p >= endSubject) - return true; - - /* If we have found the required character, save the point where we - found it, so that we don't search again next time round the loop if - the start hasn't passed this character yet. */ - - reqBytePtr = p; - } - } - return false; -} - -int jsRegExpExecute(JSContext *cx, const JSRegExp* re, - const UChar* subject, int length, int start_offset, int* offsets, - int offsetCount) -{ - JS_ASSERT(re); - JS_ASSERT(subject || !length); - JS_ASSERT(offsetCount >= 0); - JS_ASSERT(offsets || offsetCount == 0); - - MatchData matchBlock; - matchBlock.startSubject = subject; - matchBlock.endSubject = matchBlock.startSubject + length; - const UChar* endSubject = matchBlock.endSubject; - - matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption); - matchBlock.ignoreCase = (re->options & IgnoreCaseOption); - - /* Use the vector supplied, rounding down its size to a multiple of 3. */ - int ocount = offsetCount - (offsetCount % 3); - - matchBlock.offsetVector = offsets; - matchBlock.offsetEnd = ocount; - matchBlock.offsetMax = (2*ocount)/3; - matchBlock.offsetOverflow = false; - - /* Compute the minimum number of offsets that we need to reset each time. Doing - this makes a huge difference to execution time when there aren't many brackets - in the pattern. */ - - int resetCount = 2 + re->topBracket * 2; - if (resetCount > offsetCount) - resetCount = ocount; - - /* Reset the working variable associated with each extraction. These should - never be used unless previously set, but they get saved and restored, and so we - initialize them to avoid reading uninitialized locations. */ - - if (matchBlock.offsetVector) { - int* iptr = matchBlock.offsetVector + ocount; - int* iend = iptr - resetCount/2 + 1; - while (--iptr >= iend) - *iptr = -1; - } - - /* Set up the first character to match, if available. The firstByte value is - never set for an anchored regular expression, but the anchoring may be forced - at run time, so we have to test for anchoring. The first char may be unset for - an unanchored pattern, of course. If there's no first char and the pattern was - studied, there may be a bitmap of possible first characters. */ - - bool firstByteIsCaseless = false; - int firstByte = -1; - if (re->options & UseFirstByteOptimizationOption) { - firstByte = re->firstByte & 255; - if ((firstByteIsCaseless = (re->firstByte & REQ_IGNORE_CASE))) - firstByte = toLowerCase(firstByte); - } - - /* For anchored or unanchored matches, there may be a "last known required - character" set. */ - - bool reqByteIsCaseless = false; - int reqByte = -1; - int reqByte2 = -1; - if (re->options & UseRequiredByteOptimizationOption) { - reqByte = re->reqByte & 255; - reqByteIsCaseless = (re->reqByte & REQ_IGNORE_CASE); - reqByte2 = flipCase(reqByte); - } - - /* Loop for handling unanchored repeated matching attempts; for anchored regexs - the loop runs just once. */ - - const UChar* startMatch = subject + start_offset; - const UChar* reqBytePtr = startMatch - 1; - bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption; - - do { - /* Reset the maximum number of extractions we might see. */ - if (matchBlock.offsetVector) { - int* iptr = matchBlock.offsetVector; - int* iend = iptr + resetCount; - while (iptr < iend) - *iptr++ = -1; - } - - tryFirstByteOptimization(startMatch, endSubject, firstByte, firstByteIsCaseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset); - if (tryRequiredByteOptimization(startMatch, endSubject, reqByte, reqByte2, reqByteIsCaseless, firstByte >= 0, reqBytePtr)) - break; - - /* When a match occurs, substrings will be set for all internal extractions; - we just need to set up the whole thing as substring 0 before returning. If - there were too many extractions, set the return code to zero. In the case - where we had to get some local store to hold offsets for backreferences, copy - those back references that we can. In this case there need not be overflow - if certain parts of the pattern were not used. */ - - /* The code starts after the JSRegExp block and the capture name table. */ - const unsigned char* start_code = (const unsigned char*)(re + 1); - - int returnCode = match(&cx->regExpPool, startMatch, start_code, 2, matchBlock); - - /* When the result is no match, advance the pointer to the next character - and continue. */ - if (returnCode == 0) { - startMatch++; - continue; - } - - if (returnCode != 1) { - JS_ASSERT(returnCode == JSRegExpErrorHitLimit); - DPRINTF((">>>> error: returning %d\n", returnCode)); - return returnCode; - } - - /* We have a match! */ - - returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2; - - if (offsetCount < 2) - returnCode = 0; - else { - offsets[0] = startMatch - matchBlock.startSubject; - offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject; - } - - JS_ASSERT(returnCode >= 0); - DPRINTF((">>>> returning %d\n", returnCode)); - return returnCode; - } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject); - - DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); - return JSRegExpErrorNoMatch; -} diff --git a/js/src/yarr/pcre/pcre_internal.h b/js/src/yarr/pcre/pcre_internal.h deleted file mode 100644 index d677cfcfa255..000000000000 --- a/js/src/yarr/pcre/pcre_internal.h +++ /dev/null @@ -1,434 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This header contains definitions that are shared between the different -modules, but which are not relevant to the exported API. This includes some -functions whose names all begin with "_pcre_". */ - -#ifndef PCRE_INTERNAL_H -#define PCRE_INTERNAL_H - -/* Bit definitions for entries in the pcre_ctypes table. */ - -#define ctype_space 0x01 -#define ctype_xdigit 0x08 -#define ctype_word 0x10 /* alphameric or '_' */ - -/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set -of bits for a class map. Some classes are built by combining these tables. */ - -#define cbit_space 0 /* \s */ -#define cbit_digit 32 /* \d */ -#define cbit_word 64 /* \w */ -#define cbit_length 96 /* Length of the cbits table */ - -/* Offsets of the various tables from the base tables pointer, and -total length. */ - -#define lcc_offset 0 -#define fcc_offset 128 -#define cbits_offset 256 -#define ctypes_offset (cbits_offset + cbit_length) -#define tables_length (ctypes_offset + 128) - -#ifndef DFTABLES - -#include "pcre.h" - -/* The value of LINK_SIZE determines the number of bytes used to store links as -offsets within the compiled regex. The default is 2, which allows for compiled -patterns up to 64K long. */ - -#define LINK_SIZE 3 - -/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef -inline, and there are *still* stupid compilers about that don't like indented -pre-processor statements, or at least there were when I first wrote this. After -all, it had only been about 10 years then... */ - -#ifdef DEBUG -#define DPRINTF(p) /*printf p; fflush(stdout);*/ -#else -#define DPRINTF(p) /*nothing*/ -#endif - -/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored -in big-endian order) by default. These are used, for example, to link from the -start of a subpattern to its alternatives and its end. The use of 2 bytes per -offset limits the size of the compiled regex to around 64K, which is big enough -for almost everybody. However, I received a request for an even bigger limit. -For this reason, and also to make the code easier to maintain, the storing and -loading of offsets from the byte string is now handled by the functions that are -defined here. */ - -/* PCRE uses some other 2-byte quantities that do not change when the size of -offsets changes. There are used for repeat counts and for other things such as -capturing parenthesis numbers in back references. */ - -static inline void put2ByteValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value >= 0 && value <= 0xFFFF); - opcodePtr[0] = value >> 8; - opcodePtr[1] = value; -} - -static inline void put3ByteValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value >= 0 && value <= 0xFFFFFF); - opcodePtr[0] = value >> 16; - opcodePtr[1] = value >> 8; - opcodePtr[2] = value; -} - -static inline int get2ByteValue(const unsigned char* opcodePtr) -{ - return (opcodePtr[0] << 8) | opcodePtr[1]; -} - -static inline int get3ByteValue(const unsigned char* opcodePtr) -{ - return (opcodePtr[0] << 16) | (opcodePtr[1] << 8) | opcodePtr[2]; -} - -static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - put2ByteValue(opcodePtr, value); - opcodePtr += 2; -} - -static inline void put3ByteValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - put3ByteValue(opcodePtr, value); - opcodePtr += 3; -} - -static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value) -{ -#if LINK_SIZE == 3 - put3ByteValue(opcodePtr, value); -#elif LINK_SIZE == 2 - put2ByteValue(opcodePtr, value); -#else -# error LINK_SIZE not supported. -#endif -} - -static inline int getLinkValueAllowZero(const unsigned char* opcodePtr) -{ -#if LINK_SIZE == 3 - return get3ByteValue(opcodePtr); -#elif LINK_SIZE == 2 - return get2ByteValue(opcodePtr); -#else -# error LINK_SIZE not supported. -#endif -} - -#define MAX_PATTERN_SIZE 1024 * 1024 // Derived by empirical testing of compile time in PCRE and WREC. -JS_STATIC_ASSERT(MAX_PATTERN_SIZE < (1 << (8 * LINK_SIZE))); - -static inline void putLinkValue(unsigned char* opcodePtr, int value) -{ - JS_ASSERT(value); - putLinkValueAllowZero(opcodePtr, value); -} - -static inline int getLinkValue(const unsigned char* opcodePtr) -{ - int value = getLinkValueAllowZero(opcodePtr); - JS_ASSERT(value); - return value; -} - -static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value) -{ - putLinkValue(opcodePtr, value); - opcodePtr += LINK_SIZE; -} - -static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value) -{ - putLinkValueAllowZero(opcodePtr, value); - opcodePtr += LINK_SIZE; -} - -// FIXME: These are really more of a "compiled regexp state" than "regexp options" -enum RegExpOptions { - UseFirstByteOptimizationOption = 0x40000000, /* firstByte is set */ - UseRequiredByteOptimizationOption = 0x20000000, /* reqByte is set */ - UseMultiLineFirstByteOptimizationOption = 0x10000000, /* start after \n for multiline */ - IsAnchoredOption = 0x02000000, /* can't use partial with this regex */ - IgnoreCaseOption = 0x00000001, - MatchAcrossMultipleLinesOption = 0x00000002 -}; - -/* Flags added to firstByte or reqByte; a "non-literal" item is either a -variable-length repeat, or a anything other than literal characters. */ - -#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */ -#define REQ_VARY 0x0200 /* reqByte followed non-literal item */ - -/* Miscellaneous definitions */ - -/* Flag bits and data types for the extended class (OP_XCLASS) for classes that -contain UTF-8 characters with values greater than 255. */ - -#define XCL_NOT 0x01 /* Flag: this is a negative class */ -#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ - -#define XCL_END 0 /* Marks end of individual items */ -#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ -#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ - -/* These are escaped items that aren't just an encoding of a particular data -value such as \n. They must have non-zero values, as check_escape() returns -their negation. Also, they must appear in the same order as in the opcode -definitions below, up to ESC_w. The final one must be -ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two -tests in the code for an escape > ESC_b and <= ESC_w to -detect the types that may be repeated. These are the types that consume -characters. If any new escapes are put in between that don't consume a -character, that code will have to change. */ - -enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF }; - -/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets -that extract substrings. Starting from 1 (i.e. after OP_END), the values up to -OP_EOD must correspond in order to the list of escapes immediately above. -Note that whenever this list is updated, the two macro definitions that follow -must also be updated to match. */ - -#define FOR_EACH_OPCODE(macro) \ - macro(END) \ - \ - , macro(NOT_WORD_BOUNDARY) \ - , macro(WORD_BOUNDARY) \ - , macro(NOT_DIGIT) \ - , macro(DIGIT) \ - , macro(NOT_WHITESPACE) \ - , macro(WHITESPACE) \ - , macro(NOT_WORDCHAR) \ - , macro(WORDCHAR) \ - \ - , macro(NOT_NEWLINE) \ - \ - , macro(CIRC) \ - , macro(DOLL) \ - , macro(BOL) \ - , macro(EOL) \ - , macro(CHAR) \ - , macro(CHAR_IGNORING_CASE) \ - , macro(ASCII_CHAR) \ - , macro(ASCII_LETTER_IGNORING_CASE) \ - , macro(NOT) \ - \ - , macro(STAR) \ - , macro(MINSTAR) \ - , macro(PLUS) \ - , macro(MINPLUS) \ - , macro(QUERY) \ - , macro(MINQUERY) \ - , macro(UPTO) \ - , macro(MINUPTO) \ - , macro(EXACT) \ - \ - , macro(NOTSTAR) \ - , macro(NOTMINSTAR) \ - , macro(NOTPLUS) \ - , macro(NOTMINPLUS) \ - , macro(NOTQUERY) \ - , macro(NOTMINQUERY) \ - , macro(NOTUPTO) \ - , macro(NOTMINUPTO) \ - , macro(NOTEXACT) \ - \ - , macro(TYPESTAR) \ - , macro(TYPEMINSTAR) \ - , macro(TYPEPLUS) \ - , macro(TYPEMINPLUS) \ - , macro(TYPEQUERY) \ - , macro(TYPEMINQUERY) \ - , macro(TYPEUPTO) \ - , macro(TYPEMINUPTO) \ - , macro(TYPEEXACT) \ - \ - , macro(CRSTAR) \ - , macro(CRMINSTAR) \ - , macro(CRPLUS) \ - , macro(CRMINPLUS) \ - , macro(CRQUERY) \ - , macro(CRMINQUERY) \ - , macro(CRRANGE) \ - , macro(CRMINRANGE) \ - \ - , macro(CLASS) \ - , macro(NCLASS) \ - , macro(XCLASS) \ - \ - , macro(REF) \ - \ - , macro(ALT) \ - , macro(KET) \ - , macro(KETRMAX) \ - , macro(KETRMIN) \ - \ - , macro(ASSERT) \ - , macro(ASSERT_NOT) \ - \ - , macro(BRAZERO) \ - , macro(BRAMINZERO) \ - , macro(BRANUMBER) \ - , macro(BRA) - -#define OPCODE_ENUM_VALUE(opcode) OP_##opcode -enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) }; - -/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and -study.c that all opcodes are less than 128 in value. This makes handling UTF-8 -character sequences easier. */ - -/* The highest extraction number before we have to start using additional -bytes. (Originally PCRE didn't have support for extraction counts higher than -this number.) The value is limited by the number of opcodes left after OP_BRA, -i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional -opcodes. */ - -/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above -are in conflict! */ - -#define EXTRACT_BASIC_MAX 100 - -/* The code vector runs on as long as necessary after the end. */ - -struct JSRegExp { - unsigned options; - - unsigned short topBracket; - unsigned short topBackref; - - unsigned short firstByte; - unsigned short reqByte; -}; - -/* Internal shared data tables. These are tables that are used by more than one - of the exported public functions. They have to be "external" in the C sense, - but are not part of the PCRE public API. The data for these tables is in the - pcre_tables.c module. */ - -#define jsc_pcre_utf8_table1_size 6 - -extern const int jsc_pcre_utf8_table1[6]; -extern const int jsc_pcre_utf8_table2[6]; -extern const int jsc_pcre_utf8_table3[6]; -extern const unsigned char jsc_pcre_utf8_table4[0x40]; - -extern const unsigned char jsc_pcre_default_tables[tables_length]; - -static inline unsigned char toLowerCase(unsigned char c) -{ - static const unsigned char* lowerCaseChars = jsc_pcre_default_tables + lcc_offset; - return lowerCaseChars[c]; -} - -static inline unsigned char flipCase(unsigned char c) -{ - static const unsigned char* flippedCaseChars = jsc_pcre_default_tables + fcc_offset; - return flippedCaseChars[c]; -} - -static inline unsigned char classBitmapForChar(unsigned char c) -{ - static const unsigned char* charClassBitmaps = jsc_pcre_default_tables + cbits_offset; - return charClassBitmaps[c]; -} - -static inline unsigned char charTypeForChar(unsigned char c) -{ - const unsigned char* charTypeMap = jsc_pcre_default_tables + ctypes_offset; - return charTypeMap[c]; -} - -static inline bool isWordChar(UChar c) -{ - return c < 128 && (charTypeForChar(c) & ctype_word); -} - -static inline bool isSpaceChar(UChar c) -{ - return (c < 128 && (charTypeForChar(c) & ctype_space)) || c == 0x00A0; -} - -static inline bool isNewline(UChar nl) -{ - return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029); -} - -static inline bool isBracketStartOpcode(unsigned char opcode) -{ - if (opcode >= OP_BRA) - return true; - switch (opcode) { - case OP_ASSERT: - case OP_ASSERT_NOT: - return true; - default: - return false; - } -} - -static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr) -{ - JS_ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT); - do - opcodePtr += getLinkValue(opcodePtr + 1); - while (*opcodePtr == OP_ALT); -} - -/* Internal shared functions. These are functions that are used in more -that one of the source files. They have to have external linkage, but -but are not part of the public API and so not exported from the library. */ - -extern int jsc_pcre_ucp_othercase(unsigned); -extern bool jsc_pcre_xclass(int, const unsigned char*); - -#endif - -#endif - -/* End of pcre_internal.h */ diff --git a/js/src/yarr/pcre/pcre_tables.cpp b/js/src/yarr/pcre/pcre_tables.cpp deleted file mode 100644 index b1ac229d5912..000000000000 --- a/js/src/yarr/pcre/pcre_tables.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains some fixed tables that are used by more than one of the -PCRE code modules. */ - -#include "pcre_internal.h" - -/************************************************* -* Tables for UTF-8 support * -*************************************************/ - -/* These are the breakpoints for different numbers of bytes in a UTF-8 -character. */ - -const int jsc_pcre_utf8_table1[6] = - { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; - -/* These are the indicator bits and the mask for the data bits to set in the -first byte of a character, indexed by the number of additional bytes. */ - -const int jsc_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; -const int jsc_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; - -/* Table of the number of extra characters, indexed by the first character -masked with 0x3f. The highest number for a valid UTF-8 character is in fact -0x3d. */ - -const unsigned char jsc_pcre_utf8_table4[0x40] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; - -#include "chartables.c" diff --git a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp deleted file mode 100644 index b97db921c981..000000000000 --- a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains code for searching the table of Unicode character -properties. */ - -#include "pcre_internal.h" - -#include "ucpinternal.h" /* Internal table details */ -#include "ucptable.cpp" /* The table itself */ - -/************************************************* -* Search table and return other case * -*************************************************/ - -/* If the given character is a letter, and there is another case for the -letter, return the other case. Otherwise, return -1. - -Arguments: - c the character value - -Returns: the other case or -1 if none -*/ - -int jsc_pcre_ucp_othercase(unsigned c) -{ - int bot = 0; - int top = sizeof(ucp_table) / sizeof(cnode); - int mid; - - /* The table is searched using a binary chop. You might think that using - intermediate variables to hold some of the common expressions would speed - things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it - makes things a lot slower. */ - - for (;;) { - if (top <= bot) - return -1; - mid = (bot + top) >> 1; - if (c == (ucp_table[mid].f0 & f0_charmask)) - break; - if (c < (ucp_table[mid].f0 & f0_charmask)) - top = mid; - else { - if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask))) - break; - bot = mid + 1; - } - } - - /* Found an entry in the table. Return -1 for a range entry. Otherwise return - the other case if there is one, else -1. */ - - if (ucp_table[mid].f0 & f0_rangeflag) - return -1; - - int offset = ucp_table[mid].f1 & f1_casemask; - if (offset & f1_caseneg) - offset |= f1_caseneg; - return !offset ? -1 : c + offset; -} diff --git a/js/src/yarr/pcre/pcre_xclass.cpp b/js/src/yarr/pcre/pcre_xclass.cpp deleted file mode 100644 index 8e59018ead0c..000000000000 --- a/js/src/yarr/pcre/pcre_xclass.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains an internal function that is used to match an extended -class (one that contains characters whose values are > 255). */ - -#include "pcre_internal.h" - -/************************************************* -* Match character against an XCLASS * -*************************************************/ - -/* This function is called to match a character against an extended class that -might contain values > 255. - -Arguments: - c the character - data points to the flag byte of the XCLASS data - -Returns: true if character matches, else false -*/ - -/* Get the next UTF-8 character, advancing the pointer. This is called when we - know we are in UTF-8 mode. */ - -static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr) -{ - c = *subjectPtr++; - if ((c & 0xc0) == 0xc0) { - int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ - int gcss = 6 * gcaa; - c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; - while (gcaa-- > 0) { - gcss -= 6; - c |= (*subjectPtr++ & 0x3f) << gcss; - } - } -} - -bool jsc_pcre_xclass(int c, const unsigned char* data) -{ - bool negated = (*data & XCL_NOT); - - /* Character values < 256 are matched against a bitmap, if one is present. If - not, we still carry on, because there may be ranges that start below 256 in the - additional data. */ - - if (c < 256) { - if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) - return !negated; /* char found */ - } - - /* First skip the bit map if present. Then match against the list of Unicode - properties or large chars or ranges that end with a large char. We won't ever - encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ - - if ((*data++ & XCL_MAP) != 0) - data += 32; - - int t; - while ((t = *data++) != XCL_END) { - if (t == XCL_SINGLE) { - int x; - getUTF8CharAndAdvancePointer(x, data); - if (c == x) - return !negated; - } - else if (t == XCL_RANGE) { - int x, y; - getUTF8CharAndAdvancePointer(x, data); - getUTF8CharAndAdvancePointer(y, data); - if (c >= x && c <= y) - return !negated; - } - } - - return negated; /* char did not match */ -} diff --git a/js/src/yarr/pcre/ucpinternal.h b/js/src/yarr/pcre/ucpinternal.h deleted file mode 100644 index c8bc4aab679c..000000000000 --- a/js/src/yarr/pcre/ucpinternal.h +++ /dev/null @@ -1,126 +0,0 @@ -/* This is JavaScriptCore's variant of the PCRE library. While this library -started out as a copy of PCRE, many of the features of PCRE have been -removed. This library now supports only the regular expression features -required by the JavaScript language specification, and has only the functions -needed by JavaScriptCore and the rest of WebKit. - - Originally written by Philip Hazel - Copyright (c) 1997-2006 University of Cambridge - Copyright (C) 2002, 2004, 2006, 2007 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: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. ------------------------------------------------------------------------------ -*/ - -/************************************************* -* Unicode Property Table handler * -*************************************************/ - -/* Internal header file defining the layout of the bits in each pair of 32-bit -words that form a data item in the table. */ - -typedef struct cnode { - unsigned f0; - unsigned f1; -} cnode; - -/* Things for the f0 field */ - -#define f0_scriptmask 0xff000000 /* Mask for script field */ -#define f0_scriptshift 24 /* Shift for script value */ -#define f0_rangeflag 0x00f00000 /* Flag for a range item */ -#define f0_charmask 0x001fffff /* Mask for code point value */ - -/* Things for the f1 field */ - -#define f1_typemask 0xfc000000 /* Mask for char type field */ -#define f1_typeshift 26 /* Shift for the type field */ -#define f1_rangemask 0x0000ffff /* Mask for a range offset */ -#define f1_casemask 0x0000ffff /* Mask for a case offset */ -#define f1_caseneg 0xffff8000 /* Bits for negation */ - -/* The data consists of a vector of structures of type cnode. The two unsigned -32-bit integers are used as follows: - -(f0) (1) The most significant byte holds the script number. The numbers are - defined by the enum in ucp.h. - - (2) The 0x00800000 bit is set if this entry defines a range of characters. - It is not set if this entry defines a single character - - (3) The 0x00600000 bits are spare. - - (4) The 0x001fffff bits contain the code point. No Unicode code point will - ever be greater than 0x0010ffff, so this should be OK for ever. - -(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are - defined by an enum in ucp.h. - - (2) The 0x03ff0000 bits are spare. - - (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of - range if this entry defines a range, OR the *signed* offset to the - character's "other case" partner if this entry defines a single - character. There is no partner if the value is zero. - -------------------------------------------------------------------------------- -| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) | -------------------------------------------------------------------------------- - | | | | | - | | |-> spare | |-> spare - | | | - | |-> spare |-> spare - | - |-> range flag - -The upper/lower casing information is set only for characters that come in -pairs. The non-one-to-one mappings in the Unicode data are ignored. - -When searching the data, proceed as follows: - -(1) Set up for a binary chop search. - -(2) If the top is not greater than the bottom, the character is not in the - table. Its type must therefore be "Cn" ("Undefined"). - -(3) Find the middle vector element. - -(4) Extract the code point and compare. If equal, we are done. - -(5) If the test character is smaller, set the top to the current point, and - goto (2). - -(6) If the current entry defines a range, compute the last character by adding - the offset, and see if the test character is within the range. If it is, - we are done. - -(7) Otherwise, set the bottom to one element past the current point and goto - (2). -*/ - -/* End of ucpinternal.h */ diff --git a/js/src/yarr/pcre/ucptable.cpp b/js/src/yarr/pcre/ucptable.cpp deleted file mode 100644 index 011f7f572443..000000000000 --- a/js/src/yarr/pcre/ucptable.cpp +++ /dev/null @@ -1,2968 +0,0 @@ -/* This source module is automatically generated from the Unicode -property table. See ucpinternal.h for a description of the layout. */ - -static const cnode ucp_table[] = { - { 0x09800000, 0x0000001f }, - { 0x09000020, 0x74000000 }, - { 0x09800021, 0x54000002 }, - { 0x09000024, 0x5c000000 }, - { 0x09800025, 0x54000002 }, - { 0x09000028, 0x58000000 }, - { 0x09000029, 0x48000000 }, - { 0x0900002a, 0x54000000 }, - { 0x0900002b, 0x64000000 }, - { 0x0900002c, 0x54000000 }, - { 0x0900002d, 0x44000000 }, - { 0x0980002e, 0x54000001 }, - { 0x09800030, 0x34000009 }, - { 0x0980003a, 0x54000001 }, - { 0x0980003c, 0x64000002 }, - { 0x0980003f, 0x54000001 }, - { 0x21000041, 0x24000020 }, - { 0x21000042, 0x24000020 }, - { 0x21000043, 0x24000020 }, - { 0x21000044, 0x24000020 }, - { 0x21000045, 0x24000020 }, - { 0x21000046, 0x24000020 }, - { 0x21000047, 0x24000020 }, - { 0x21000048, 0x24000020 }, - { 0x21000049, 0x24000020 }, - { 0x2100004a, 0x24000020 }, - { 0x2100004b, 0x24000020 }, - { 0x2100004c, 0x24000020 }, - { 0x2100004d, 0x24000020 }, - { 0x2100004e, 0x24000020 }, - { 0x2100004f, 0x24000020 }, - { 0x21000050, 0x24000020 }, - { 0x21000051, 0x24000020 }, - { 0x21000052, 0x24000020 }, - { 0x21000053, 0x24000020 }, - { 0x21000054, 0x24000020 }, - { 0x21000055, 0x24000020 }, - { 0x21000056, 0x24000020 }, - { 0x21000057, 0x24000020 }, - { 0x21000058, 0x24000020 }, - { 0x21000059, 0x24000020 }, - { 0x2100005a, 0x24000020 }, - { 0x0900005b, 0x58000000 }, - { 0x0900005c, 0x54000000 }, - { 0x0900005d, 0x48000000 }, - { 0x0900005e, 0x60000000 }, - { 0x0900005f, 0x40000000 }, - { 0x09000060, 0x60000000 }, - { 0x21000061, 0x1400ffe0 }, - { 0x21000062, 0x1400ffe0 }, - { 0x21000063, 0x1400ffe0 }, - { 0x21000064, 0x1400ffe0 }, - { 0x21000065, 0x1400ffe0 }, - { 0x21000066, 0x1400ffe0 }, - { 0x21000067, 0x1400ffe0 }, - { 0x21000068, 0x1400ffe0 }, - { 0x21000069, 0x1400ffe0 }, - { 0x2100006a, 0x1400ffe0 }, - { 0x2100006b, 0x1400ffe0 }, - { 0x2100006c, 0x1400ffe0 }, - { 0x2100006d, 0x1400ffe0 }, - { 0x2100006e, 0x1400ffe0 }, - { 0x2100006f, 0x1400ffe0 }, - { 0x21000070, 0x1400ffe0 }, - { 0x21000071, 0x1400ffe0 }, - { 0x21000072, 0x1400ffe0 }, - { 0x21000073, 0x1400ffe0 }, - { 0x21000074, 0x1400ffe0 }, - { 0x21000075, 0x1400ffe0 }, - { 0x21000076, 0x1400ffe0 }, - { 0x21000077, 0x1400ffe0 }, - { 0x21000078, 0x1400ffe0 }, - { 0x21000079, 0x1400ffe0 }, - { 0x2100007a, 0x1400ffe0 }, - { 0x0900007b, 0x58000000 }, - { 0x0900007c, 0x64000000 }, - { 0x0900007d, 0x48000000 }, - { 0x0900007e, 0x64000000 }, - { 0x0980007f, 0x00000020 }, - { 0x090000a0, 0x74000000 }, - { 0x090000a1, 0x54000000 }, - { 0x098000a2, 0x5c000003 }, - { 0x098000a6, 0x68000001 }, - { 0x090000a8, 0x60000000 }, - { 0x090000a9, 0x68000000 }, - { 0x210000aa, 0x14000000 }, - { 0x090000ab, 0x50000000 }, - { 0x090000ac, 0x64000000 }, - { 0x090000ad, 0x04000000 }, - { 0x090000ae, 0x68000000 }, - { 0x090000af, 0x60000000 }, - { 0x090000b0, 0x68000000 }, - { 0x090000b1, 0x64000000 }, - { 0x098000b2, 0x3c000001 }, - { 0x090000b4, 0x60000000 }, - { 0x090000b5, 0x140002e7 }, - { 0x090000b6, 0x68000000 }, - { 0x090000b7, 0x54000000 }, - { 0x090000b8, 0x60000000 }, - { 0x090000b9, 0x3c000000 }, - { 0x210000ba, 0x14000000 }, - { 0x090000bb, 0x4c000000 }, - { 0x098000bc, 0x3c000002 }, - { 0x090000bf, 0x54000000 }, - { 0x210000c0, 0x24000020 }, - { 0x210000c1, 0x24000020 }, - { 0x210000c2, 0x24000020 }, - { 0x210000c3, 0x24000020 }, - { 0x210000c4, 0x24000020 }, - { 0x210000c5, 0x24000020 }, - { 0x210000c6, 0x24000020 }, - { 0x210000c7, 0x24000020 }, - { 0x210000c8, 0x24000020 }, - { 0x210000c9, 0x24000020 }, - { 0x210000ca, 0x24000020 }, - { 0x210000cb, 0x24000020 }, - { 0x210000cc, 0x24000020 }, - { 0x210000cd, 0x24000020 }, - { 0x210000ce, 0x24000020 }, - { 0x210000cf, 0x24000020 }, - { 0x210000d0, 0x24000020 }, - { 0x210000d1, 0x24000020 }, - { 0x210000d2, 0x24000020 }, - { 0x210000d3, 0x24000020 }, - { 0x210000d4, 0x24000020 }, - { 0x210000d5, 0x24000020 }, - { 0x210000d6, 0x24000020 }, - { 0x090000d7, 0x64000000 }, - { 0x210000d8, 0x24000020 }, - { 0x210000d9, 0x24000020 }, - { 0x210000da, 0x24000020 }, - { 0x210000db, 0x24000020 }, - { 0x210000dc, 0x24000020 }, - { 0x210000dd, 0x24000020 }, - { 0x210000de, 0x24000020 }, - { 0x210000df, 0x14000000 }, - { 0x210000e0, 0x1400ffe0 }, - { 0x210000e1, 0x1400ffe0 }, - { 0x210000e2, 0x1400ffe0 }, - { 0x210000e3, 0x1400ffe0 }, - { 0x210000e4, 0x1400ffe0 }, - { 0x210000e5, 0x1400ffe0 }, - { 0x210000e6, 0x1400ffe0 }, - { 0x210000e7, 0x1400ffe0 }, - { 0x210000e8, 0x1400ffe0 }, - { 0x210000e9, 0x1400ffe0 }, - { 0x210000ea, 0x1400ffe0 }, - { 0x210000eb, 0x1400ffe0 }, - { 0x210000ec, 0x1400ffe0 }, - { 0x210000ed, 0x1400ffe0 }, - { 0x210000ee, 0x1400ffe0 }, - { 0x210000ef, 0x1400ffe0 }, - { 0x210000f0, 0x1400ffe0 }, - { 0x210000f1, 0x1400ffe0 }, - { 0x210000f2, 0x1400ffe0 }, - { 0x210000f3, 0x1400ffe0 }, - { 0x210000f4, 0x1400ffe0 }, - { 0x210000f5, 0x1400ffe0 }, - { 0x210000f6, 0x1400ffe0 }, - { 0x090000f7, 0x64000000 }, - { 0x210000f8, 0x1400ffe0 }, - { 0x210000f9, 0x1400ffe0 }, - { 0x210000fa, 0x1400ffe0 }, - { 0x210000fb, 0x1400ffe0 }, - { 0x210000fc, 0x1400ffe0 }, - { 0x210000fd, 0x1400ffe0 }, - { 0x210000fe, 0x1400ffe0 }, - { 0x210000ff, 0x14000079 }, - { 0x21000100, 0x24000001 }, - { 0x21000101, 0x1400ffff }, - { 0x21000102, 0x24000001 }, - { 0x21000103, 0x1400ffff }, - { 0x21000104, 0x24000001 }, - { 0x21000105, 0x1400ffff }, - { 0x21000106, 0x24000001 }, - { 0x21000107, 0x1400ffff }, - { 0x21000108, 0x24000001 }, - { 0x21000109, 0x1400ffff }, - { 0x2100010a, 0x24000001 }, - { 0x2100010b, 0x1400ffff }, - { 0x2100010c, 0x24000001 }, - { 0x2100010d, 0x1400ffff }, - { 0x2100010e, 0x24000001 }, - { 0x2100010f, 0x1400ffff }, - { 0x21000110, 0x24000001 }, - { 0x21000111, 0x1400ffff }, - { 0x21000112, 0x24000001 }, - { 0x21000113, 0x1400ffff }, - { 0x21000114, 0x24000001 }, - { 0x21000115, 0x1400ffff }, - { 0x21000116, 0x24000001 }, - { 0x21000117, 0x1400ffff }, - { 0x21000118, 0x24000001 }, - { 0x21000119, 0x1400ffff }, - { 0x2100011a, 0x24000001 }, - { 0x2100011b, 0x1400ffff }, - { 0x2100011c, 0x24000001 }, - { 0x2100011d, 0x1400ffff }, - { 0x2100011e, 0x24000001 }, - { 0x2100011f, 0x1400ffff }, - { 0x21000120, 0x24000001 }, - { 0x21000121, 0x1400ffff }, - { 0x21000122, 0x24000001 }, - { 0x21000123, 0x1400ffff }, - { 0x21000124, 0x24000001 }, - { 0x21000125, 0x1400ffff }, - { 0x21000126, 0x24000001 }, - { 0x21000127, 0x1400ffff }, - { 0x21000128, 0x24000001 }, - { 0x21000129, 0x1400ffff }, - { 0x2100012a, 0x24000001 }, - { 0x2100012b, 0x1400ffff }, - { 0x2100012c, 0x24000001 }, - { 0x2100012d, 0x1400ffff }, - { 0x2100012e, 0x24000001 }, - { 0x2100012f, 0x1400ffff }, - { 0x21000130, 0x2400ff39 }, - { 0x21000131, 0x1400ff18 }, - { 0x21000132, 0x24000001 }, - { 0x21000133, 0x1400ffff }, - { 0x21000134, 0x24000001 }, - { 0x21000135, 0x1400ffff }, - { 0x21000136, 0x24000001 }, - { 0x21000137, 0x1400ffff }, - { 0x21000138, 0x14000000 }, - { 0x21000139, 0x24000001 }, - { 0x2100013a, 0x1400ffff }, - { 0x2100013b, 0x24000001 }, - { 0x2100013c, 0x1400ffff }, - { 0x2100013d, 0x24000001 }, - { 0x2100013e, 0x1400ffff }, - { 0x2100013f, 0x24000001 }, - { 0x21000140, 0x1400ffff }, - { 0x21000141, 0x24000001 }, - { 0x21000142, 0x1400ffff }, - { 0x21000143, 0x24000001 }, - { 0x21000144, 0x1400ffff }, - { 0x21000145, 0x24000001 }, - { 0x21000146, 0x1400ffff }, - { 0x21000147, 0x24000001 }, - { 0x21000148, 0x1400ffff }, - { 0x21000149, 0x14000000 }, - { 0x2100014a, 0x24000001 }, - { 0x2100014b, 0x1400ffff }, - { 0x2100014c, 0x24000001 }, - { 0x2100014d, 0x1400ffff }, - { 0x2100014e, 0x24000001 }, - { 0x2100014f, 0x1400ffff }, - { 0x21000150, 0x24000001 }, - { 0x21000151, 0x1400ffff }, - { 0x21000152, 0x24000001 }, - { 0x21000153, 0x1400ffff }, - { 0x21000154, 0x24000001 }, - { 0x21000155, 0x1400ffff }, - { 0x21000156, 0x24000001 }, - { 0x21000157, 0x1400ffff }, - { 0x21000158, 0x24000001 }, - { 0x21000159, 0x1400ffff }, - { 0x2100015a, 0x24000001 }, - { 0x2100015b, 0x1400ffff }, - { 0x2100015c, 0x24000001 }, - { 0x2100015d, 0x1400ffff }, - { 0x2100015e, 0x24000001 }, - { 0x2100015f, 0x1400ffff }, - { 0x21000160, 0x24000001 }, - { 0x21000161, 0x1400ffff }, - { 0x21000162, 0x24000001 }, - { 0x21000163, 0x1400ffff }, - { 0x21000164, 0x24000001 }, - { 0x21000165, 0x1400ffff }, - { 0x21000166, 0x24000001 }, - { 0x21000167, 0x1400ffff }, - { 0x21000168, 0x24000001 }, - { 0x21000169, 0x1400ffff }, - { 0x2100016a, 0x24000001 }, - { 0x2100016b, 0x1400ffff }, - { 0x2100016c, 0x24000001 }, - { 0x2100016d, 0x1400ffff }, - { 0x2100016e, 0x24000001 }, - { 0x2100016f, 0x1400ffff }, - { 0x21000170, 0x24000001 }, - { 0x21000171, 0x1400ffff }, - { 0x21000172, 0x24000001 }, - { 0x21000173, 0x1400ffff }, - { 0x21000174, 0x24000001 }, - { 0x21000175, 0x1400ffff }, - { 0x21000176, 0x24000001 }, - { 0x21000177, 0x1400ffff }, - { 0x21000178, 0x2400ff87 }, - { 0x21000179, 0x24000001 }, - { 0x2100017a, 0x1400ffff }, - { 0x2100017b, 0x24000001 }, - { 0x2100017c, 0x1400ffff }, - { 0x2100017d, 0x24000001 }, - { 0x2100017e, 0x1400ffff }, - { 0x2100017f, 0x1400fed4 }, - { 0x21000180, 0x14000000 }, - { 0x21000181, 0x240000d2 }, - { 0x21000182, 0x24000001 }, - { 0x21000183, 0x1400ffff }, - { 0x21000184, 0x24000001 }, - { 0x21000185, 0x1400ffff }, - { 0x21000186, 0x240000ce }, - { 0x21000187, 0x24000001 }, - { 0x21000188, 0x1400ffff }, - { 0x21000189, 0x240000cd }, - { 0x2100018a, 0x240000cd }, - { 0x2100018b, 0x24000001 }, - { 0x2100018c, 0x1400ffff }, - { 0x2100018d, 0x14000000 }, - { 0x2100018e, 0x2400004f }, - { 0x2100018f, 0x240000ca }, - { 0x21000190, 0x240000cb }, - { 0x21000191, 0x24000001 }, - { 0x21000192, 0x1400ffff }, - { 0x21000193, 0x240000cd }, - { 0x21000194, 0x240000cf }, - { 0x21000195, 0x14000061 }, - { 0x21000196, 0x240000d3 }, - { 0x21000197, 0x240000d1 }, - { 0x21000198, 0x24000001 }, - { 0x21000199, 0x1400ffff }, - { 0x2100019a, 0x140000a3 }, - { 0x2100019b, 0x14000000 }, - { 0x2100019c, 0x240000d3 }, - { 0x2100019d, 0x240000d5 }, - { 0x2100019e, 0x14000082 }, - { 0x2100019f, 0x240000d6 }, - { 0x210001a0, 0x24000001 }, - { 0x210001a1, 0x1400ffff }, - { 0x210001a2, 0x24000001 }, - { 0x210001a3, 0x1400ffff }, - { 0x210001a4, 0x24000001 }, - { 0x210001a5, 0x1400ffff }, - { 0x210001a6, 0x240000da }, - { 0x210001a7, 0x24000001 }, - { 0x210001a8, 0x1400ffff }, - { 0x210001a9, 0x240000da }, - { 0x218001aa, 0x14000001 }, - { 0x210001ac, 0x24000001 }, - { 0x210001ad, 0x1400ffff }, - { 0x210001ae, 0x240000da }, - { 0x210001af, 0x24000001 }, - { 0x210001b0, 0x1400ffff }, - { 0x210001b1, 0x240000d9 }, - { 0x210001b2, 0x240000d9 }, - { 0x210001b3, 0x24000001 }, - { 0x210001b4, 0x1400ffff }, - { 0x210001b5, 0x24000001 }, - { 0x210001b6, 0x1400ffff }, - { 0x210001b7, 0x240000db }, - { 0x210001b8, 0x24000001 }, - { 0x210001b9, 0x1400ffff }, - { 0x210001ba, 0x14000000 }, - { 0x210001bb, 0x1c000000 }, - { 0x210001bc, 0x24000001 }, - { 0x210001bd, 0x1400ffff }, - { 0x210001be, 0x14000000 }, - { 0x210001bf, 0x14000038 }, - { 0x218001c0, 0x1c000003 }, - { 0x210001c4, 0x24000002 }, - { 0x210001c5, 0x2000ffff }, - { 0x210001c6, 0x1400fffe }, - { 0x210001c7, 0x24000002 }, - { 0x210001c8, 0x2000ffff }, - { 0x210001c9, 0x1400fffe }, - { 0x210001ca, 0x24000002 }, - { 0x210001cb, 0x2000ffff }, - { 0x210001cc, 0x1400fffe }, - { 0x210001cd, 0x24000001 }, - { 0x210001ce, 0x1400ffff }, - { 0x210001cf, 0x24000001 }, - { 0x210001d0, 0x1400ffff }, - { 0x210001d1, 0x24000001 }, - { 0x210001d2, 0x1400ffff }, - { 0x210001d3, 0x24000001 }, - { 0x210001d4, 0x1400ffff }, - { 0x210001d5, 0x24000001 }, - { 0x210001d6, 0x1400ffff }, - { 0x210001d7, 0x24000001 }, - { 0x210001d8, 0x1400ffff }, - { 0x210001d9, 0x24000001 }, - { 0x210001da, 0x1400ffff }, - { 0x210001db, 0x24000001 }, - { 0x210001dc, 0x1400ffff }, - { 0x210001dd, 0x1400ffb1 }, - { 0x210001de, 0x24000001 }, - { 0x210001df, 0x1400ffff }, - { 0x210001e0, 0x24000001 }, - { 0x210001e1, 0x1400ffff }, - { 0x210001e2, 0x24000001 }, - { 0x210001e3, 0x1400ffff }, - { 0x210001e4, 0x24000001 }, - { 0x210001e5, 0x1400ffff }, - { 0x210001e6, 0x24000001 }, - { 0x210001e7, 0x1400ffff }, - { 0x210001e8, 0x24000001 }, - { 0x210001e9, 0x1400ffff }, - { 0x210001ea, 0x24000001 }, - { 0x210001eb, 0x1400ffff }, - { 0x210001ec, 0x24000001 }, - { 0x210001ed, 0x1400ffff }, - { 0x210001ee, 0x24000001 }, - { 0x210001ef, 0x1400ffff }, - { 0x210001f0, 0x14000000 }, - { 0x210001f1, 0x24000002 }, - { 0x210001f2, 0x2000ffff }, - { 0x210001f3, 0x1400fffe }, - { 0x210001f4, 0x24000001 }, - { 0x210001f5, 0x1400ffff }, - { 0x210001f6, 0x2400ff9f }, - { 0x210001f7, 0x2400ffc8 }, - { 0x210001f8, 0x24000001 }, - { 0x210001f9, 0x1400ffff }, - { 0x210001fa, 0x24000001 }, - { 0x210001fb, 0x1400ffff }, - { 0x210001fc, 0x24000001 }, - { 0x210001fd, 0x1400ffff }, - { 0x210001fe, 0x24000001 }, - { 0x210001ff, 0x1400ffff }, - { 0x21000200, 0x24000001 }, - { 0x21000201, 0x1400ffff }, - { 0x21000202, 0x24000001 }, - { 0x21000203, 0x1400ffff }, - { 0x21000204, 0x24000001 }, - { 0x21000205, 0x1400ffff }, - { 0x21000206, 0x24000001 }, - { 0x21000207, 0x1400ffff }, - { 0x21000208, 0x24000001 }, - { 0x21000209, 0x1400ffff }, - { 0x2100020a, 0x24000001 }, - { 0x2100020b, 0x1400ffff }, - { 0x2100020c, 0x24000001 }, - { 0x2100020d, 0x1400ffff }, - { 0x2100020e, 0x24000001 }, - { 0x2100020f, 0x1400ffff }, - { 0x21000210, 0x24000001 }, - { 0x21000211, 0x1400ffff }, - { 0x21000212, 0x24000001 }, - { 0x21000213, 0x1400ffff }, - { 0x21000214, 0x24000001 }, - { 0x21000215, 0x1400ffff }, - { 0x21000216, 0x24000001 }, - { 0x21000217, 0x1400ffff }, - { 0x21000218, 0x24000001 }, - { 0x21000219, 0x1400ffff }, - { 0x2100021a, 0x24000001 }, - { 0x2100021b, 0x1400ffff }, - { 0x2100021c, 0x24000001 }, - { 0x2100021d, 0x1400ffff }, - { 0x2100021e, 0x24000001 }, - { 0x2100021f, 0x1400ffff }, - { 0x21000220, 0x2400ff7e }, - { 0x21000221, 0x14000000 }, - { 0x21000222, 0x24000001 }, - { 0x21000223, 0x1400ffff }, - { 0x21000224, 0x24000001 }, - { 0x21000225, 0x1400ffff }, - { 0x21000226, 0x24000001 }, - { 0x21000227, 0x1400ffff }, - { 0x21000228, 0x24000001 }, - { 0x21000229, 0x1400ffff }, - { 0x2100022a, 0x24000001 }, - { 0x2100022b, 0x1400ffff }, - { 0x2100022c, 0x24000001 }, - { 0x2100022d, 0x1400ffff }, - { 0x2100022e, 0x24000001 }, - { 0x2100022f, 0x1400ffff }, - { 0x21000230, 0x24000001 }, - { 0x21000231, 0x1400ffff }, - { 0x21000232, 0x24000001 }, - { 0x21000233, 0x1400ffff }, - { 0x21800234, 0x14000005 }, - { 0x2100023a, 0x24000000 }, - { 0x2100023b, 0x24000001 }, - { 0x2100023c, 0x1400ffff }, - { 0x2100023d, 0x2400ff5d }, - { 0x2100023e, 0x24000000 }, - { 0x2180023f, 0x14000001 }, - { 0x21000241, 0x24000053 }, - { 0x21800250, 0x14000002 }, - { 0x21000253, 0x1400ff2e }, - { 0x21000254, 0x1400ff32 }, - { 0x21000255, 0x14000000 }, - { 0x21000256, 0x1400ff33 }, - { 0x21000257, 0x1400ff33 }, - { 0x21000258, 0x14000000 }, - { 0x21000259, 0x1400ff36 }, - { 0x2100025a, 0x14000000 }, - { 0x2100025b, 0x1400ff35 }, - { 0x2180025c, 0x14000003 }, - { 0x21000260, 0x1400ff33 }, - { 0x21800261, 0x14000001 }, - { 0x21000263, 0x1400ff31 }, - { 0x21800264, 0x14000003 }, - { 0x21000268, 0x1400ff2f }, - { 0x21000269, 0x1400ff2d }, - { 0x2180026a, 0x14000004 }, - { 0x2100026f, 0x1400ff2d }, - { 0x21800270, 0x14000001 }, - { 0x21000272, 0x1400ff2b }, - { 0x21800273, 0x14000001 }, - { 0x21000275, 0x1400ff2a }, - { 0x21800276, 0x14000009 }, - { 0x21000280, 0x1400ff26 }, - { 0x21800281, 0x14000001 }, - { 0x21000283, 0x1400ff26 }, - { 0x21800284, 0x14000003 }, - { 0x21000288, 0x1400ff26 }, - { 0x21000289, 0x14000000 }, - { 0x2100028a, 0x1400ff27 }, - { 0x2100028b, 0x1400ff27 }, - { 0x2180028c, 0x14000005 }, - { 0x21000292, 0x1400ff25 }, - { 0x21000293, 0x14000000 }, - { 0x21000294, 0x1400ffad }, - { 0x21800295, 0x1400001a }, - { 0x218002b0, 0x18000011 }, - { 0x098002c2, 0x60000003 }, - { 0x098002c6, 0x1800000b }, - { 0x098002d2, 0x6000000d }, - { 0x218002e0, 0x18000004 }, - { 0x098002e5, 0x60000008 }, - { 0x090002ee, 0x18000000 }, - { 0x098002ef, 0x60000010 }, - { 0x1b800300, 0x30000044 }, - { 0x1b000345, 0x30000054 }, - { 0x1b800346, 0x30000029 }, - { 0x13800374, 0x60000001 }, - { 0x1300037a, 0x18000000 }, - { 0x0900037e, 0x54000000 }, - { 0x13800384, 0x60000001 }, - { 0x13000386, 0x24000026 }, - { 0x09000387, 0x54000000 }, - { 0x13000388, 0x24000025 }, - { 0x13000389, 0x24000025 }, - { 0x1300038a, 0x24000025 }, - { 0x1300038c, 0x24000040 }, - { 0x1300038e, 0x2400003f }, - { 0x1300038f, 0x2400003f }, - { 0x13000390, 0x14000000 }, - { 0x13000391, 0x24000020 }, - { 0x13000392, 0x24000020 }, - { 0x13000393, 0x24000020 }, - { 0x13000394, 0x24000020 }, - { 0x13000395, 0x24000020 }, - { 0x13000396, 0x24000020 }, - { 0x13000397, 0x24000020 }, - { 0x13000398, 0x24000020 }, - { 0x13000399, 0x24000020 }, - { 0x1300039a, 0x24000020 }, - { 0x1300039b, 0x24000020 }, - { 0x1300039c, 0x24000020 }, - { 0x1300039d, 0x24000020 }, - { 0x1300039e, 0x24000020 }, - { 0x1300039f, 0x24000020 }, - { 0x130003a0, 0x24000020 }, - { 0x130003a1, 0x24000020 }, - { 0x130003a3, 0x24000020 }, - { 0x130003a4, 0x24000020 }, - { 0x130003a5, 0x24000020 }, - { 0x130003a6, 0x24000020 }, - { 0x130003a7, 0x24000020 }, - { 0x130003a8, 0x24000020 }, - { 0x130003a9, 0x24000020 }, - { 0x130003aa, 0x24000020 }, - { 0x130003ab, 0x24000020 }, - { 0x130003ac, 0x1400ffda }, - { 0x130003ad, 0x1400ffdb }, - { 0x130003ae, 0x1400ffdb }, - { 0x130003af, 0x1400ffdb }, - { 0x130003b0, 0x14000000 }, - { 0x130003b1, 0x1400ffe0 }, - { 0x130003b2, 0x1400ffe0 }, - { 0x130003b3, 0x1400ffe0 }, - { 0x130003b4, 0x1400ffe0 }, - { 0x130003b5, 0x1400ffe0 }, - { 0x130003b6, 0x1400ffe0 }, - { 0x130003b7, 0x1400ffe0 }, - { 0x130003b8, 0x1400ffe0 }, - { 0x130003b9, 0x1400ffe0 }, - { 0x130003ba, 0x1400ffe0 }, - { 0x130003bb, 0x1400ffe0 }, - { 0x130003bc, 0x1400ffe0 }, - { 0x130003bd, 0x1400ffe0 }, - { 0x130003be, 0x1400ffe0 }, - { 0x130003bf, 0x1400ffe0 }, - { 0x130003c0, 0x1400ffe0 }, - { 0x130003c1, 0x1400ffe0 }, - { 0x130003c2, 0x1400ffe1 }, - { 0x130003c3, 0x1400ffe0 }, - { 0x130003c4, 0x1400ffe0 }, - { 0x130003c5, 0x1400ffe0 }, - { 0x130003c6, 0x1400ffe0 }, - { 0x130003c7, 0x1400ffe0 }, - { 0x130003c8, 0x1400ffe0 }, - { 0x130003c9, 0x1400ffe0 }, - { 0x130003ca, 0x1400ffe0 }, - { 0x130003cb, 0x1400ffe0 }, - { 0x130003cc, 0x1400ffc0 }, - { 0x130003cd, 0x1400ffc1 }, - { 0x130003ce, 0x1400ffc1 }, - { 0x130003d0, 0x1400ffc2 }, - { 0x130003d1, 0x1400ffc7 }, - { 0x138003d2, 0x24000002 }, - { 0x130003d5, 0x1400ffd1 }, - { 0x130003d6, 0x1400ffca }, - { 0x130003d7, 0x14000000 }, - { 0x130003d8, 0x24000001 }, - { 0x130003d9, 0x1400ffff }, - { 0x130003da, 0x24000001 }, - { 0x130003db, 0x1400ffff }, - { 0x130003dc, 0x24000001 }, - { 0x130003dd, 0x1400ffff }, - { 0x130003de, 0x24000001 }, - { 0x130003df, 0x1400ffff }, - { 0x130003e0, 0x24000001 }, - { 0x130003e1, 0x1400ffff }, - { 0x0a0003e2, 0x24000001 }, - { 0x0a0003e3, 0x1400ffff }, - { 0x0a0003e4, 0x24000001 }, - { 0x0a0003e5, 0x1400ffff }, - { 0x0a0003e6, 0x24000001 }, - { 0x0a0003e7, 0x1400ffff }, - { 0x0a0003e8, 0x24000001 }, - { 0x0a0003e9, 0x1400ffff }, - { 0x0a0003ea, 0x24000001 }, - { 0x0a0003eb, 0x1400ffff }, - { 0x0a0003ec, 0x24000001 }, - { 0x0a0003ed, 0x1400ffff }, - { 0x0a0003ee, 0x24000001 }, - { 0x0a0003ef, 0x1400ffff }, - { 0x130003f0, 0x1400ffaa }, - { 0x130003f1, 0x1400ffb0 }, - { 0x130003f2, 0x14000007 }, - { 0x130003f3, 0x14000000 }, - { 0x130003f4, 0x2400ffc4 }, - { 0x130003f5, 0x1400ffa0 }, - { 0x130003f6, 0x64000000 }, - { 0x130003f7, 0x24000001 }, - { 0x130003f8, 0x1400ffff }, - { 0x130003f9, 0x2400fff9 }, - { 0x130003fa, 0x24000001 }, - { 0x130003fb, 0x1400ffff }, - { 0x130003fc, 0x14000000 }, - { 0x138003fd, 0x24000002 }, - { 0x0c000400, 0x24000050 }, - { 0x0c000401, 0x24000050 }, - { 0x0c000402, 0x24000050 }, - { 0x0c000403, 0x24000050 }, - { 0x0c000404, 0x24000050 }, - { 0x0c000405, 0x24000050 }, - { 0x0c000406, 0x24000050 }, - { 0x0c000407, 0x24000050 }, - { 0x0c000408, 0x24000050 }, - { 0x0c000409, 0x24000050 }, - { 0x0c00040a, 0x24000050 }, - { 0x0c00040b, 0x24000050 }, - { 0x0c00040c, 0x24000050 }, - { 0x0c00040d, 0x24000050 }, - { 0x0c00040e, 0x24000050 }, - { 0x0c00040f, 0x24000050 }, - { 0x0c000410, 0x24000020 }, - { 0x0c000411, 0x24000020 }, - { 0x0c000412, 0x24000020 }, - { 0x0c000413, 0x24000020 }, - { 0x0c000414, 0x24000020 }, - { 0x0c000415, 0x24000020 }, - { 0x0c000416, 0x24000020 }, - { 0x0c000417, 0x24000020 }, - { 0x0c000418, 0x24000020 }, - { 0x0c000419, 0x24000020 }, - { 0x0c00041a, 0x24000020 }, - { 0x0c00041b, 0x24000020 }, - { 0x0c00041c, 0x24000020 }, - { 0x0c00041d, 0x24000020 }, - { 0x0c00041e, 0x24000020 }, - { 0x0c00041f, 0x24000020 }, - { 0x0c000420, 0x24000020 }, - { 0x0c000421, 0x24000020 }, - { 0x0c000422, 0x24000020 }, - { 0x0c000423, 0x24000020 }, - { 0x0c000424, 0x24000020 }, - { 0x0c000425, 0x24000020 }, - { 0x0c000426, 0x24000020 }, - { 0x0c000427, 0x24000020 }, - { 0x0c000428, 0x24000020 }, - { 0x0c000429, 0x24000020 }, - { 0x0c00042a, 0x24000020 }, - { 0x0c00042b, 0x24000020 }, - { 0x0c00042c, 0x24000020 }, - { 0x0c00042d, 0x24000020 }, - { 0x0c00042e, 0x24000020 }, - { 0x0c00042f, 0x24000020 }, - { 0x0c000430, 0x1400ffe0 }, - { 0x0c000431, 0x1400ffe0 }, - { 0x0c000432, 0x1400ffe0 }, - { 0x0c000433, 0x1400ffe0 }, - { 0x0c000434, 0x1400ffe0 }, - { 0x0c000435, 0x1400ffe0 }, - { 0x0c000436, 0x1400ffe0 }, - { 0x0c000437, 0x1400ffe0 }, - { 0x0c000438, 0x1400ffe0 }, - { 0x0c000439, 0x1400ffe0 }, - { 0x0c00043a, 0x1400ffe0 }, - { 0x0c00043b, 0x1400ffe0 }, - { 0x0c00043c, 0x1400ffe0 }, - { 0x0c00043d, 0x1400ffe0 }, - { 0x0c00043e, 0x1400ffe0 }, - { 0x0c00043f, 0x1400ffe0 }, - { 0x0c000440, 0x1400ffe0 }, - { 0x0c000441, 0x1400ffe0 }, - { 0x0c000442, 0x1400ffe0 }, - { 0x0c000443, 0x1400ffe0 }, - { 0x0c000444, 0x1400ffe0 }, - { 0x0c000445, 0x1400ffe0 }, - { 0x0c000446, 0x1400ffe0 }, - { 0x0c000447, 0x1400ffe0 }, - { 0x0c000448, 0x1400ffe0 }, - { 0x0c000449, 0x1400ffe0 }, - { 0x0c00044a, 0x1400ffe0 }, - { 0x0c00044b, 0x1400ffe0 }, - { 0x0c00044c, 0x1400ffe0 }, - { 0x0c00044d, 0x1400ffe0 }, - { 0x0c00044e, 0x1400ffe0 }, - { 0x0c00044f, 0x1400ffe0 }, - { 0x0c000450, 0x1400ffb0 }, - { 0x0c000451, 0x1400ffb0 }, - { 0x0c000452, 0x1400ffb0 }, - { 0x0c000453, 0x1400ffb0 }, - { 0x0c000454, 0x1400ffb0 }, - { 0x0c000455, 0x1400ffb0 }, - { 0x0c000456, 0x1400ffb0 }, - { 0x0c000457, 0x1400ffb0 }, - { 0x0c000458, 0x1400ffb0 }, - { 0x0c000459, 0x1400ffb0 }, - { 0x0c00045a, 0x1400ffb0 }, - { 0x0c00045b, 0x1400ffb0 }, - { 0x0c00045c, 0x1400ffb0 }, - { 0x0c00045d, 0x1400ffb0 }, - { 0x0c00045e, 0x1400ffb0 }, - { 0x0c00045f, 0x1400ffb0 }, - { 0x0c000460, 0x24000001 }, - { 0x0c000461, 0x1400ffff }, - { 0x0c000462, 0x24000001 }, - { 0x0c000463, 0x1400ffff }, - { 0x0c000464, 0x24000001 }, - { 0x0c000465, 0x1400ffff }, - { 0x0c000466, 0x24000001 }, - { 0x0c000467, 0x1400ffff }, - { 0x0c000468, 0x24000001 }, - { 0x0c000469, 0x1400ffff }, - { 0x0c00046a, 0x24000001 }, - { 0x0c00046b, 0x1400ffff }, - { 0x0c00046c, 0x24000001 }, - { 0x0c00046d, 0x1400ffff }, - { 0x0c00046e, 0x24000001 }, - { 0x0c00046f, 0x1400ffff }, - { 0x0c000470, 0x24000001 }, - { 0x0c000471, 0x1400ffff }, - { 0x0c000472, 0x24000001 }, - { 0x0c000473, 0x1400ffff }, - { 0x0c000474, 0x24000001 }, - { 0x0c000475, 0x1400ffff }, - { 0x0c000476, 0x24000001 }, - { 0x0c000477, 0x1400ffff }, - { 0x0c000478, 0x24000001 }, - { 0x0c000479, 0x1400ffff }, - { 0x0c00047a, 0x24000001 }, - { 0x0c00047b, 0x1400ffff }, - { 0x0c00047c, 0x24000001 }, - { 0x0c00047d, 0x1400ffff }, - { 0x0c00047e, 0x24000001 }, - { 0x0c00047f, 0x1400ffff }, - { 0x0c000480, 0x24000001 }, - { 0x0c000481, 0x1400ffff }, - { 0x0c000482, 0x68000000 }, - { 0x0c800483, 0x30000003 }, - { 0x0c800488, 0x2c000001 }, - { 0x0c00048a, 0x24000001 }, - { 0x0c00048b, 0x1400ffff }, - { 0x0c00048c, 0x24000001 }, - { 0x0c00048d, 0x1400ffff }, - { 0x0c00048e, 0x24000001 }, - { 0x0c00048f, 0x1400ffff }, - { 0x0c000490, 0x24000001 }, - { 0x0c000491, 0x1400ffff }, - { 0x0c000492, 0x24000001 }, - { 0x0c000493, 0x1400ffff }, - { 0x0c000494, 0x24000001 }, - { 0x0c000495, 0x1400ffff }, - { 0x0c000496, 0x24000001 }, - { 0x0c000497, 0x1400ffff }, - { 0x0c000498, 0x24000001 }, - { 0x0c000499, 0x1400ffff }, - { 0x0c00049a, 0x24000001 }, - { 0x0c00049b, 0x1400ffff }, - { 0x0c00049c, 0x24000001 }, - { 0x0c00049d, 0x1400ffff }, - { 0x0c00049e, 0x24000001 }, - { 0x0c00049f, 0x1400ffff }, - { 0x0c0004a0, 0x24000001 }, - { 0x0c0004a1, 0x1400ffff }, - { 0x0c0004a2, 0x24000001 }, - { 0x0c0004a3, 0x1400ffff }, - { 0x0c0004a4, 0x24000001 }, - { 0x0c0004a5, 0x1400ffff }, - { 0x0c0004a6, 0x24000001 }, - { 0x0c0004a7, 0x1400ffff }, - { 0x0c0004a8, 0x24000001 }, - { 0x0c0004a9, 0x1400ffff }, - { 0x0c0004aa, 0x24000001 }, - { 0x0c0004ab, 0x1400ffff }, - { 0x0c0004ac, 0x24000001 }, - { 0x0c0004ad, 0x1400ffff }, - { 0x0c0004ae, 0x24000001 }, - { 0x0c0004af, 0x1400ffff }, - { 0x0c0004b0, 0x24000001 }, - { 0x0c0004b1, 0x1400ffff }, - { 0x0c0004b2, 0x24000001 }, - { 0x0c0004b3, 0x1400ffff }, - { 0x0c0004b4, 0x24000001 }, - { 0x0c0004b5, 0x1400ffff }, - { 0x0c0004b6, 0x24000001 }, - { 0x0c0004b7, 0x1400ffff }, - { 0x0c0004b8, 0x24000001 }, - { 0x0c0004b9, 0x1400ffff }, - { 0x0c0004ba, 0x24000001 }, - { 0x0c0004bb, 0x1400ffff }, - { 0x0c0004bc, 0x24000001 }, - { 0x0c0004bd, 0x1400ffff }, - { 0x0c0004be, 0x24000001 }, - { 0x0c0004bf, 0x1400ffff }, - { 0x0c0004c0, 0x24000000 }, - { 0x0c0004c1, 0x24000001 }, - { 0x0c0004c2, 0x1400ffff }, - { 0x0c0004c3, 0x24000001 }, - { 0x0c0004c4, 0x1400ffff }, - { 0x0c0004c5, 0x24000001 }, - { 0x0c0004c6, 0x1400ffff }, - { 0x0c0004c7, 0x24000001 }, - { 0x0c0004c8, 0x1400ffff }, - { 0x0c0004c9, 0x24000001 }, - { 0x0c0004ca, 0x1400ffff }, - { 0x0c0004cb, 0x24000001 }, - { 0x0c0004cc, 0x1400ffff }, - { 0x0c0004cd, 0x24000001 }, - { 0x0c0004ce, 0x1400ffff }, - { 0x0c0004d0, 0x24000001 }, - { 0x0c0004d1, 0x1400ffff }, - { 0x0c0004d2, 0x24000001 }, - { 0x0c0004d3, 0x1400ffff }, - { 0x0c0004d4, 0x24000001 }, - { 0x0c0004d5, 0x1400ffff }, - { 0x0c0004d6, 0x24000001 }, - { 0x0c0004d7, 0x1400ffff }, - { 0x0c0004d8, 0x24000001 }, - { 0x0c0004d9, 0x1400ffff }, - { 0x0c0004da, 0x24000001 }, - { 0x0c0004db, 0x1400ffff }, - { 0x0c0004dc, 0x24000001 }, - { 0x0c0004dd, 0x1400ffff }, - { 0x0c0004de, 0x24000001 }, - { 0x0c0004df, 0x1400ffff }, - { 0x0c0004e0, 0x24000001 }, - { 0x0c0004e1, 0x1400ffff }, - { 0x0c0004e2, 0x24000001 }, - { 0x0c0004e3, 0x1400ffff }, - { 0x0c0004e4, 0x24000001 }, - { 0x0c0004e5, 0x1400ffff }, - { 0x0c0004e6, 0x24000001 }, - { 0x0c0004e7, 0x1400ffff }, - { 0x0c0004e8, 0x24000001 }, - { 0x0c0004e9, 0x1400ffff }, - { 0x0c0004ea, 0x24000001 }, - { 0x0c0004eb, 0x1400ffff }, - { 0x0c0004ec, 0x24000001 }, - { 0x0c0004ed, 0x1400ffff }, - { 0x0c0004ee, 0x24000001 }, - { 0x0c0004ef, 0x1400ffff }, - { 0x0c0004f0, 0x24000001 }, - { 0x0c0004f1, 0x1400ffff }, - { 0x0c0004f2, 0x24000001 }, - { 0x0c0004f3, 0x1400ffff }, - { 0x0c0004f4, 0x24000001 }, - { 0x0c0004f5, 0x1400ffff }, - { 0x0c0004f6, 0x24000001 }, - { 0x0c0004f7, 0x1400ffff }, - { 0x0c0004f8, 0x24000001 }, - { 0x0c0004f9, 0x1400ffff }, - { 0x0c000500, 0x24000001 }, - { 0x0c000501, 0x1400ffff }, - { 0x0c000502, 0x24000001 }, - { 0x0c000503, 0x1400ffff }, - { 0x0c000504, 0x24000001 }, - { 0x0c000505, 0x1400ffff }, - { 0x0c000506, 0x24000001 }, - { 0x0c000507, 0x1400ffff }, - { 0x0c000508, 0x24000001 }, - { 0x0c000509, 0x1400ffff }, - { 0x0c00050a, 0x24000001 }, - { 0x0c00050b, 0x1400ffff }, - { 0x0c00050c, 0x24000001 }, - { 0x0c00050d, 0x1400ffff }, - { 0x0c00050e, 0x24000001 }, - { 0x0c00050f, 0x1400ffff }, - { 0x01000531, 0x24000030 }, - { 0x01000532, 0x24000030 }, - { 0x01000533, 0x24000030 }, - { 0x01000534, 0x24000030 }, - { 0x01000535, 0x24000030 }, - { 0x01000536, 0x24000030 }, - { 0x01000537, 0x24000030 }, - { 0x01000538, 0x24000030 }, - { 0x01000539, 0x24000030 }, - { 0x0100053a, 0x24000030 }, - { 0x0100053b, 0x24000030 }, - { 0x0100053c, 0x24000030 }, - { 0x0100053d, 0x24000030 }, - { 0x0100053e, 0x24000030 }, - { 0x0100053f, 0x24000030 }, - { 0x01000540, 0x24000030 }, - { 0x01000541, 0x24000030 }, - { 0x01000542, 0x24000030 }, - { 0x01000543, 0x24000030 }, - { 0x01000544, 0x24000030 }, - { 0x01000545, 0x24000030 }, - { 0x01000546, 0x24000030 }, - { 0x01000547, 0x24000030 }, - { 0x01000548, 0x24000030 }, - { 0x01000549, 0x24000030 }, - { 0x0100054a, 0x24000030 }, - { 0x0100054b, 0x24000030 }, - { 0x0100054c, 0x24000030 }, - { 0x0100054d, 0x24000030 }, - { 0x0100054e, 0x24000030 }, - { 0x0100054f, 0x24000030 }, - { 0x01000550, 0x24000030 }, - { 0x01000551, 0x24000030 }, - { 0x01000552, 0x24000030 }, - { 0x01000553, 0x24000030 }, - { 0x01000554, 0x24000030 }, - { 0x01000555, 0x24000030 }, - { 0x01000556, 0x24000030 }, - { 0x01000559, 0x18000000 }, - { 0x0180055a, 0x54000005 }, - { 0x01000561, 0x1400ffd0 }, - { 0x01000562, 0x1400ffd0 }, - { 0x01000563, 0x1400ffd0 }, - { 0x01000564, 0x1400ffd0 }, - { 0x01000565, 0x1400ffd0 }, - { 0x01000566, 0x1400ffd0 }, - { 0x01000567, 0x1400ffd0 }, - { 0x01000568, 0x1400ffd0 }, - { 0x01000569, 0x1400ffd0 }, - { 0x0100056a, 0x1400ffd0 }, - { 0x0100056b, 0x1400ffd0 }, - { 0x0100056c, 0x1400ffd0 }, - { 0x0100056d, 0x1400ffd0 }, - { 0x0100056e, 0x1400ffd0 }, - { 0x0100056f, 0x1400ffd0 }, - { 0x01000570, 0x1400ffd0 }, - { 0x01000571, 0x1400ffd0 }, - { 0x01000572, 0x1400ffd0 }, - { 0x01000573, 0x1400ffd0 }, - { 0x01000574, 0x1400ffd0 }, - { 0x01000575, 0x1400ffd0 }, - { 0x01000576, 0x1400ffd0 }, - { 0x01000577, 0x1400ffd0 }, - { 0x01000578, 0x1400ffd0 }, - { 0x01000579, 0x1400ffd0 }, - { 0x0100057a, 0x1400ffd0 }, - { 0x0100057b, 0x1400ffd0 }, - { 0x0100057c, 0x1400ffd0 }, - { 0x0100057d, 0x1400ffd0 }, - { 0x0100057e, 0x1400ffd0 }, - { 0x0100057f, 0x1400ffd0 }, - { 0x01000580, 0x1400ffd0 }, - { 0x01000581, 0x1400ffd0 }, - { 0x01000582, 0x1400ffd0 }, - { 0x01000583, 0x1400ffd0 }, - { 0x01000584, 0x1400ffd0 }, - { 0x01000585, 0x1400ffd0 }, - { 0x01000586, 0x1400ffd0 }, - { 0x01000587, 0x14000000 }, - { 0x09000589, 0x54000000 }, - { 0x0100058a, 0x44000000 }, - { 0x19800591, 0x30000028 }, - { 0x198005bb, 0x30000002 }, - { 0x190005be, 0x54000000 }, - { 0x190005bf, 0x30000000 }, - { 0x190005c0, 0x54000000 }, - { 0x198005c1, 0x30000001 }, - { 0x190005c3, 0x54000000 }, - { 0x198005c4, 0x30000001 }, - { 0x190005c6, 0x54000000 }, - { 0x190005c7, 0x30000000 }, - { 0x198005d0, 0x1c00001a }, - { 0x198005f0, 0x1c000002 }, - { 0x198005f3, 0x54000001 }, - { 0x09800600, 0x04000003 }, - { 0x0000060b, 0x5c000000 }, - { 0x0980060c, 0x54000001 }, - { 0x0080060e, 0x68000001 }, - { 0x00800610, 0x30000005 }, - { 0x0900061b, 0x54000000 }, - { 0x0080061e, 0x54000001 }, - { 0x00800621, 0x1c000019 }, - { 0x09000640, 0x18000000 }, - { 0x00800641, 0x1c000009 }, - { 0x1b80064b, 0x30000013 }, - { 0x09800660, 0x34000009 }, - { 0x0080066a, 0x54000003 }, - { 0x0080066e, 0x1c000001 }, - { 0x1b000670, 0x30000000 }, - { 0x00800671, 0x1c000062 }, - { 0x000006d4, 0x54000000 }, - { 0x000006d5, 0x1c000000 }, - { 0x008006d6, 0x30000006 }, - { 0x090006dd, 0x04000000 }, - { 0x000006de, 0x2c000000 }, - { 0x008006df, 0x30000005 }, - { 0x008006e5, 0x18000001 }, - { 0x008006e7, 0x30000001 }, - { 0x000006e9, 0x68000000 }, - { 0x008006ea, 0x30000003 }, - { 0x008006ee, 0x1c000001 }, - { 0x008006f0, 0x34000009 }, - { 0x008006fa, 0x1c000002 }, - { 0x008006fd, 0x68000001 }, - { 0x000006ff, 0x1c000000 }, - { 0x31800700, 0x5400000d }, - { 0x3100070f, 0x04000000 }, - { 0x31000710, 0x1c000000 }, - { 0x31000711, 0x30000000 }, - { 0x31800712, 0x1c00001d }, - { 0x31800730, 0x3000001a }, - { 0x3180074d, 0x1c000020 }, - { 0x37800780, 0x1c000025 }, - { 0x378007a6, 0x3000000a }, - { 0x370007b1, 0x1c000000 }, - { 0x0e800901, 0x30000001 }, - { 0x0e000903, 0x28000000 }, - { 0x0e800904, 0x1c000035 }, - { 0x0e00093c, 0x30000000 }, - { 0x0e00093d, 0x1c000000 }, - { 0x0e80093e, 0x28000002 }, - { 0x0e800941, 0x30000007 }, - { 0x0e800949, 0x28000003 }, - { 0x0e00094d, 0x30000000 }, - { 0x0e000950, 0x1c000000 }, - { 0x0e800951, 0x30000003 }, - { 0x0e800958, 0x1c000009 }, - { 0x0e800962, 0x30000001 }, - { 0x09800964, 0x54000001 }, - { 0x0e800966, 0x34000009 }, - { 0x09000970, 0x54000000 }, - { 0x0e00097d, 0x1c000000 }, - { 0x02000981, 0x30000000 }, - { 0x02800982, 0x28000001 }, - { 0x02800985, 0x1c000007 }, - { 0x0280098f, 0x1c000001 }, - { 0x02800993, 0x1c000015 }, - { 0x028009aa, 0x1c000006 }, - { 0x020009b2, 0x1c000000 }, - { 0x028009b6, 0x1c000003 }, - { 0x020009bc, 0x30000000 }, - { 0x020009bd, 0x1c000000 }, - { 0x028009be, 0x28000002 }, - { 0x028009c1, 0x30000003 }, - { 0x028009c7, 0x28000001 }, - { 0x028009cb, 0x28000001 }, - { 0x020009cd, 0x30000000 }, - { 0x020009ce, 0x1c000000 }, - { 0x020009d7, 0x28000000 }, - { 0x028009dc, 0x1c000001 }, - { 0x028009df, 0x1c000002 }, - { 0x028009e2, 0x30000001 }, - { 0x028009e6, 0x34000009 }, - { 0x028009f0, 0x1c000001 }, - { 0x028009f2, 0x5c000001 }, - { 0x028009f4, 0x3c000005 }, - { 0x020009fa, 0x68000000 }, - { 0x15800a01, 0x30000001 }, - { 0x15000a03, 0x28000000 }, - { 0x15800a05, 0x1c000005 }, - { 0x15800a0f, 0x1c000001 }, - { 0x15800a13, 0x1c000015 }, - { 0x15800a2a, 0x1c000006 }, - { 0x15800a32, 0x1c000001 }, - { 0x15800a35, 0x1c000001 }, - { 0x15800a38, 0x1c000001 }, - { 0x15000a3c, 0x30000000 }, - { 0x15800a3e, 0x28000002 }, - { 0x15800a41, 0x30000001 }, - { 0x15800a47, 0x30000001 }, - { 0x15800a4b, 0x30000002 }, - { 0x15800a59, 0x1c000003 }, - { 0x15000a5e, 0x1c000000 }, - { 0x15800a66, 0x34000009 }, - { 0x15800a70, 0x30000001 }, - { 0x15800a72, 0x1c000002 }, - { 0x14800a81, 0x30000001 }, - { 0x14000a83, 0x28000000 }, - { 0x14800a85, 0x1c000008 }, - { 0x14800a8f, 0x1c000002 }, - { 0x14800a93, 0x1c000015 }, - { 0x14800aaa, 0x1c000006 }, - { 0x14800ab2, 0x1c000001 }, - { 0x14800ab5, 0x1c000004 }, - { 0x14000abc, 0x30000000 }, - { 0x14000abd, 0x1c000000 }, - { 0x14800abe, 0x28000002 }, - { 0x14800ac1, 0x30000004 }, - { 0x14800ac7, 0x30000001 }, - { 0x14000ac9, 0x28000000 }, - { 0x14800acb, 0x28000001 }, - { 0x14000acd, 0x30000000 }, - { 0x14000ad0, 0x1c000000 }, - { 0x14800ae0, 0x1c000001 }, - { 0x14800ae2, 0x30000001 }, - { 0x14800ae6, 0x34000009 }, - { 0x14000af1, 0x5c000000 }, - { 0x2b000b01, 0x30000000 }, - { 0x2b800b02, 0x28000001 }, - { 0x2b800b05, 0x1c000007 }, - { 0x2b800b0f, 0x1c000001 }, - { 0x2b800b13, 0x1c000015 }, - { 0x2b800b2a, 0x1c000006 }, - { 0x2b800b32, 0x1c000001 }, - { 0x2b800b35, 0x1c000004 }, - { 0x2b000b3c, 0x30000000 }, - { 0x2b000b3d, 0x1c000000 }, - { 0x2b000b3e, 0x28000000 }, - { 0x2b000b3f, 0x30000000 }, - { 0x2b000b40, 0x28000000 }, - { 0x2b800b41, 0x30000002 }, - { 0x2b800b47, 0x28000001 }, - { 0x2b800b4b, 0x28000001 }, - { 0x2b000b4d, 0x30000000 }, - { 0x2b000b56, 0x30000000 }, - { 0x2b000b57, 0x28000000 }, - { 0x2b800b5c, 0x1c000001 }, - { 0x2b800b5f, 0x1c000002 }, - { 0x2b800b66, 0x34000009 }, - { 0x2b000b70, 0x68000000 }, - { 0x2b000b71, 0x1c000000 }, - { 0x35000b82, 0x30000000 }, - { 0x35000b83, 0x1c000000 }, - { 0x35800b85, 0x1c000005 }, - { 0x35800b8e, 0x1c000002 }, - { 0x35800b92, 0x1c000003 }, - { 0x35800b99, 0x1c000001 }, - { 0x35000b9c, 0x1c000000 }, - { 0x35800b9e, 0x1c000001 }, - { 0x35800ba3, 0x1c000001 }, - { 0x35800ba8, 0x1c000002 }, - { 0x35800bae, 0x1c00000b }, - { 0x35800bbe, 0x28000001 }, - { 0x35000bc0, 0x30000000 }, - { 0x35800bc1, 0x28000001 }, - { 0x35800bc6, 0x28000002 }, - { 0x35800bca, 0x28000002 }, - { 0x35000bcd, 0x30000000 }, - { 0x35000bd7, 0x28000000 }, - { 0x35800be6, 0x34000009 }, - { 0x35800bf0, 0x3c000002 }, - { 0x35800bf3, 0x68000005 }, - { 0x35000bf9, 0x5c000000 }, - { 0x35000bfa, 0x68000000 }, - { 0x36800c01, 0x28000002 }, - { 0x36800c05, 0x1c000007 }, - { 0x36800c0e, 0x1c000002 }, - { 0x36800c12, 0x1c000016 }, - { 0x36800c2a, 0x1c000009 }, - { 0x36800c35, 0x1c000004 }, - { 0x36800c3e, 0x30000002 }, - { 0x36800c41, 0x28000003 }, - { 0x36800c46, 0x30000002 }, - { 0x36800c4a, 0x30000003 }, - { 0x36800c55, 0x30000001 }, - { 0x36800c60, 0x1c000001 }, - { 0x36800c66, 0x34000009 }, - { 0x1c800c82, 0x28000001 }, - { 0x1c800c85, 0x1c000007 }, - { 0x1c800c8e, 0x1c000002 }, - { 0x1c800c92, 0x1c000016 }, - { 0x1c800caa, 0x1c000009 }, - { 0x1c800cb5, 0x1c000004 }, - { 0x1c000cbc, 0x30000000 }, - { 0x1c000cbd, 0x1c000000 }, - { 0x1c000cbe, 0x28000000 }, - { 0x1c000cbf, 0x30000000 }, - { 0x1c800cc0, 0x28000004 }, - { 0x1c000cc6, 0x30000000 }, - { 0x1c800cc7, 0x28000001 }, - { 0x1c800cca, 0x28000001 }, - { 0x1c800ccc, 0x30000001 }, - { 0x1c800cd5, 0x28000001 }, - { 0x1c000cde, 0x1c000000 }, - { 0x1c800ce0, 0x1c000001 }, - { 0x1c800ce6, 0x34000009 }, - { 0x24800d02, 0x28000001 }, - { 0x24800d05, 0x1c000007 }, - { 0x24800d0e, 0x1c000002 }, - { 0x24800d12, 0x1c000016 }, - { 0x24800d2a, 0x1c00000f }, - { 0x24800d3e, 0x28000002 }, - { 0x24800d41, 0x30000002 }, - { 0x24800d46, 0x28000002 }, - { 0x24800d4a, 0x28000002 }, - { 0x24000d4d, 0x30000000 }, - { 0x24000d57, 0x28000000 }, - { 0x24800d60, 0x1c000001 }, - { 0x24800d66, 0x34000009 }, - { 0x2f800d82, 0x28000001 }, - { 0x2f800d85, 0x1c000011 }, - { 0x2f800d9a, 0x1c000017 }, - { 0x2f800db3, 0x1c000008 }, - { 0x2f000dbd, 0x1c000000 }, - { 0x2f800dc0, 0x1c000006 }, - { 0x2f000dca, 0x30000000 }, - { 0x2f800dcf, 0x28000002 }, - { 0x2f800dd2, 0x30000002 }, - { 0x2f000dd6, 0x30000000 }, - { 0x2f800dd8, 0x28000007 }, - { 0x2f800df2, 0x28000001 }, - { 0x2f000df4, 0x54000000 }, - { 0x38800e01, 0x1c00002f }, - { 0x38000e31, 0x30000000 }, - { 0x38800e32, 0x1c000001 }, - { 0x38800e34, 0x30000006 }, - { 0x09000e3f, 0x5c000000 }, - { 0x38800e40, 0x1c000005 }, - { 0x38000e46, 0x18000000 }, - { 0x38800e47, 0x30000007 }, - { 0x38000e4f, 0x54000000 }, - { 0x38800e50, 0x34000009 }, - { 0x38800e5a, 0x54000001 }, - { 0x20800e81, 0x1c000001 }, - { 0x20000e84, 0x1c000000 }, - { 0x20800e87, 0x1c000001 }, - { 0x20000e8a, 0x1c000000 }, - { 0x20000e8d, 0x1c000000 }, - { 0x20800e94, 0x1c000003 }, - { 0x20800e99, 0x1c000006 }, - { 0x20800ea1, 0x1c000002 }, - { 0x20000ea5, 0x1c000000 }, - { 0x20000ea7, 0x1c000000 }, - { 0x20800eaa, 0x1c000001 }, - { 0x20800ead, 0x1c000003 }, - { 0x20000eb1, 0x30000000 }, - { 0x20800eb2, 0x1c000001 }, - { 0x20800eb4, 0x30000005 }, - { 0x20800ebb, 0x30000001 }, - { 0x20000ebd, 0x1c000000 }, - { 0x20800ec0, 0x1c000004 }, - { 0x20000ec6, 0x18000000 }, - { 0x20800ec8, 0x30000005 }, - { 0x20800ed0, 0x34000009 }, - { 0x20800edc, 0x1c000001 }, - { 0x39000f00, 0x1c000000 }, - { 0x39800f01, 0x68000002 }, - { 0x39800f04, 0x5400000e }, - { 0x39800f13, 0x68000004 }, - { 0x39800f18, 0x30000001 }, - { 0x39800f1a, 0x68000005 }, - { 0x39800f20, 0x34000009 }, - { 0x39800f2a, 0x3c000009 }, - { 0x39000f34, 0x68000000 }, - { 0x39000f35, 0x30000000 }, - { 0x39000f36, 0x68000000 }, - { 0x39000f37, 0x30000000 }, - { 0x39000f38, 0x68000000 }, - { 0x39000f39, 0x30000000 }, - { 0x39000f3a, 0x58000000 }, - { 0x39000f3b, 0x48000000 }, - { 0x39000f3c, 0x58000000 }, - { 0x39000f3d, 0x48000000 }, - { 0x39800f3e, 0x28000001 }, - { 0x39800f40, 0x1c000007 }, - { 0x39800f49, 0x1c000021 }, - { 0x39800f71, 0x3000000d }, - { 0x39000f7f, 0x28000000 }, - { 0x39800f80, 0x30000004 }, - { 0x39000f85, 0x54000000 }, - { 0x39800f86, 0x30000001 }, - { 0x39800f88, 0x1c000003 }, - { 0x39800f90, 0x30000007 }, - { 0x39800f99, 0x30000023 }, - { 0x39800fbe, 0x68000007 }, - { 0x39000fc6, 0x30000000 }, - { 0x39800fc7, 0x68000005 }, - { 0x39000fcf, 0x68000000 }, - { 0x39800fd0, 0x54000001 }, - { 0x26801000, 0x1c000021 }, - { 0x26801023, 0x1c000004 }, - { 0x26801029, 0x1c000001 }, - { 0x2600102c, 0x28000000 }, - { 0x2680102d, 0x30000003 }, - { 0x26001031, 0x28000000 }, - { 0x26001032, 0x30000000 }, - { 0x26801036, 0x30000001 }, - { 0x26001038, 0x28000000 }, - { 0x26001039, 0x30000000 }, - { 0x26801040, 0x34000009 }, - { 0x2680104a, 0x54000005 }, - { 0x26801050, 0x1c000005 }, - { 0x26801056, 0x28000001 }, - { 0x26801058, 0x30000001 }, - { 0x100010a0, 0x24001c60 }, - { 0x100010a1, 0x24001c60 }, - { 0x100010a2, 0x24001c60 }, - { 0x100010a3, 0x24001c60 }, - { 0x100010a4, 0x24001c60 }, - { 0x100010a5, 0x24001c60 }, - { 0x100010a6, 0x24001c60 }, - { 0x100010a7, 0x24001c60 }, - { 0x100010a8, 0x24001c60 }, - { 0x100010a9, 0x24001c60 }, - { 0x100010aa, 0x24001c60 }, - { 0x100010ab, 0x24001c60 }, - { 0x100010ac, 0x24001c60 }, - { 0x100010ad, 0x24001c60 }, - { 0x100010ae, 0x24001c60 }, - { 0x100010af, 0x24001c60 }, - { 0x100010b0, 0x24001c60 }, - { 0x100010b1, 0x24001c60 }, - { 0x100010b2, 0x24001c60 }, - { 0x100010b3, 0x24001c60 }, - { 0x100010b4, 0x24001c60 }, - { 0x100010b5, 0x24001c60 }, - { 0x100010b6, 0x24001c60 }, - { 0x100010b7, 0x24001c60 }, - { 0x100010b8, 0x24001c60 }, - { 0x100010b9, 0x24001c60 }, - { 0x100010ba, 0x24001c60 }, - { 0x100010bb, 0x24001c60 }, - { 0x100010bc, 0x24001c60 }, - { 0x100010bd, 0x24001c60 }, - { 0x100010be, 0x24001c60 }, - { 0x100010bf, 0x24001c60 }, - { 0x100010c0, 0x24001c60 }, - { 0x100010c1, 0x24001c60 }, - { 0x100010c2, 0x24001c60 }, - { 0x100010c3, 0x24001c60 }, - { 0x100010c4, 0x24001c60 }, - { 0x100010c5, 0x24001c60 }, - { 0x108010d0, 0x1c00002a }, - { 0x090010fb, 0x54000000 }, - { 0x100010fc, 0x18000000 }, - { 0x17801100, 0x1c000059 }, - { 0x1780115f, 0x1c000043 }, - { 0x178011a8, 0x1c000051 }, - { 0x0f801200, 0x1c000048 }, - { 0x0f80124a, 0x1c000003 }, - { 0x0f801250, 0x1c000006 }, - { 0x0f001258, 0x1c000000 }, - { 0x0f80125a, 0x1c000003 }, - { 0x0f801260, 0x1c000028 }, - { 0x0f80128a, 0x1c000003 }, - { 0x0f801290, 0x1c000020 }, - { 0x0f8012b2, 0x1c000003 }, - { 0x0f8012b8, 0x1c000006 }, - { 0x0f0012c0, 0x1c000000 }, - { 0x0f8012c2, 0x1c000003 }, - { 0x0f8012c8, 0x1c00000e }, - { 0x0f8012d8, 0x1c000038 }, - { 0x0f801312, 0x1c000003 }, - { 0x0f801318, 0x1c000042 }, - { 0x0f00135f, 0x30000000 }, - { 0x0f001360, 0x68000000 }, - { 0x0f801361, 0x54000007 }, - { 0x0f801369, 0x3c000013 }, - { 0x0f801380, 0x1c00000f }, - { 0x0f801390, 0x68000009 }, - { 0x088013a0, 0x1c000054 }, - { 0x07801401, 0x1c00026b }, - { 0x0780166d, 0x54000001 }, - { 0x0780166f, 0x1c000007 }, - { 0x28001680, 0x74000000 }, - { 0x28801681, 0x1c000019 }, - { 0x2800169b, 0x58000000 }, - { 0x2800169c, 0x48000000 }, - { 0x2d8016a0, 0x1c00004a }, - { 0x098016eb, 0x54000002 }, - { 0x2d8016ee, 0x38000002 }, - { 0x32801700, 0x1c00000c }, - { 0x3280170e, 0x1c000003 }, - { 0x32801712, 0x30000002 }, - { 0x18801720, 0x1c000011 }, - { 0x18801732, 0x30000002 }, - { 0x09801735, 0x54000001 }, - { 0x06801740, 0x1c000011 }, - { 0x06801752, 0x30000001 }, - { 0x33801760, 0x1c00000c }, - { 0x3380176e, 0x1c000002 }, - { 0x33801772, 0x30000001 }, - { 0x1f801780, 0x1c000033 }, - { 0x1f8017b4, 0x04000001 }, - { 0x1f0017b6, 0x28000000 }, - { 0x1f8017b7, 0x30000006 }, - { 0x1f8017be, 0x28000007 }, - { 0x1f0017c6, 0x30000000 }, - { 0x1f8017c7, 0x28000001 }, - { 0x1f8017c9, 0x3000000a }, - { 0x1f8017d4, 0x54000002 }, - { 0x1f0017d7, 0x18000000 }, - { 0x1f8017d8, 0x54000002 }, - { 0x1f0017db, 0x5c000000 }, - { 0x1f0017dc, 0x1c000000 }, - { 0x1f0017dd, 0x30000000 }, - { 0x1f8017e0, 0x34000009 }, - { 0x1f8017f0, 0x3c000009 }, - { 0x25801800, 0x54000005 }, - { 0x25001806, 0x44000000 }, - { 0x25801807, 0x54000003 }, - { 0x2580180b, 0x30000002 }, - { 0x2500180e, 0x74000000 }, - { 0x25801810, 0x34000009 }, - { 0x25801820, 0x1c000022 }, - { 0x25001843, 0x18000000 }, - { 0x25801844, 0x1c000033 }, - { 0x25801880, 0x1c000028 }, - { 0x250018a9, 0x30000000 }, - { 0x22801900, 0x1c00001c }, - { 0x22801920, 0x30000002 }, - { 0x22801923, 0x28000003 }, - { 0x22801927, 0x30000001 }, - { 0x22801929, 0x28000002 }, - { 0x22801930, 0x28000001 }, - { 0x22001932, 0x30000000 }, - { 0x22801933, 0x28000005 }, - { 0x22801939, 0x30000002 }, - { 0x22001940, 0x68000000 }, - { 0x22801944, 0x54000001 }, - { 0x22801946, 0x34000009 }, - { 0x34801950, 0x1c00001d }, - { 0x34801970, 0x1c000004 }, - { 0x27801980, 0x1c000029 }, - { 0x278019b0, 0x28000010 }, - { 0x278019c1, 0x1c000006 }, - { 0x278019c8, 0x28000001 }, - { 0x278019d0, 0x34000009 }, - { 0x278019de, 0x54000001 }, - { 0x1f8019e0, 0x6800001f }, - { 0x05801a00, 0x1c000016 }, - { 0x05801a17, 0x30000001 }, - { 0x05801a19, 0x28000002 }, - { 0x05801a1e, 0x54000001 }, - { 0x21801d00, 0x1400002b }, - { 0x21801d2c, 0x18000035 }, - { 0x21801d62, 0x14000015 }, - { 0x0c001d78, 0x18000000 }, - { 0x21801d79, 0x14000021 }, - { 0x21801d9b, 0x18000024 }, - { 0x1b801dc0, 0x30000003 }, - { 0x21001e00, 0x24000001 }, - { 0x21001e01, 0x1400ffff }, - { 0x21001e02, 0x24000001 }, - { 0x21001e03, 0x1400ffff }, - { 0x21001e04, 0x24000001 }, - { 0x21001e05, 0x1400ffff }, - { 0x21001e06, 0x24000001 }, - { 0x21001e07, 0x1400ffff }, - { 0x21001e08, 0x24000001 }, - { 0x21001e09, 0x1400ffff }, - { 0x21001e0a, 0x24000001 }, - { 0x21001e0b, 0x1400ffff }, - { 0x21001e0c, 0x24000001 }, - { 0x21001e0d, 0x1400ffff }, - { 0x21001e0e, 0x24000001 }, - { 0x21001e0f, 0x1400ffff }, - { 0x21001e10, 0x24000001 }, - { 0x21001e11, 0x1400ffff }, - { 0x21001e12, 0x24000001 }, - { 0x21001e13, 0x1400ffff }, - { 0x21001e14, 0x24000001 }, - { 0x21001e15, 0x1400ffff }, - { 0x21001e16, 0x24000001 }, - { 0x21001e17, 0x1400ffff }, - { 0x21001e18, 0x24000001 }, - { 0x21001e19, 0x1400ffff }, - { 0x21001e1a, 0x24000001 }, - { 0x21001e1b, 0x1400ffff }, - { 0x21001e1c, 0x24000001 }, - { 0x21001e1d, 0x1400ffff }, - { 0x21001e1e, 0x24000001 }, - { 0x21001e1f, 0x1400ffff }, - { 0x21001e20, 0x24000001 }, - { 0x21001e21, 0x1400ffff }, - { 0x21001e22, 0x24000001 }, - { 0x21001e23, 0x1400ffff }, - { 0x21001e24, 0x24000001 }, - { 0x21001e25, 0x1400ffff }, - { 0x21001e26, 0x24000001 }, - { 0x21001e27, 0x1400ffff }, - { 0x21001e28, 0x24000001 }, - { 0x21001e29, 0x1400ffff }, - { 0x21001e2a, 0x24000001 }, - { 0x21001e2b, 0x1400ffff }, - { 0x21001e2c, 0x24000001 }, - { 0x21001e2d, 0x1400ffff }, - { 0x21001e2e, 0x24000001 }, - { 0x21001e2f, 0x1400ffff }, - { 0x21001e30, 0x24000001 }, - { 0x21001e31, 0x1400ffff }, - { 0x21001e32, 0x24000001 }, - { 0x21001e33, 0x1400ffff }, - { 0x21001e34, 0x24000001 }, - { 0x21001e35, 0x1400ffff }, - { 0x21001e36, 0x24000001 }, - { 0x21001e37, 0x1400ffff }, - { 0x21001e38, 0x24000001 }, - { 0x21001e39, 0x1400ffff }, - { 0x21001e3a, 0x24000001 }, - { 0x21001e3b, 0x1400ffff }, - { 0x21001e3c, 0x24000001 }, - { 0x21001e3d, 0x1400ffff }, - { 0x21001e3e, 0x24000001 }, - { 0x21001e3f, 0x1400ffff }, - { 0x21001e40, 0x24000001 }, - { 0x21001e41, 0x1400ffff }, - { 0x21001e42, 0x24000001 }, - { 0x21001e43, 0x1400ffff }, - { 0x21001e44, 0x24000001 }, - { 0x21001e45, 0x1400ffff }, - { 0x21001e46, 0x24000001 }, - { 0x21001e47, 0x1400ffff }, - { 0x21001e48, 0x24000001 }, - { 0x21001e49, 0x1400ffff }, - { 0x21001e4a, 0x24000001 }, - { 0x21001e4b, 0x1400ffff }, - { 0x21001e4c, 0x24000001 }, - { 0x21001e4d, 0x1400ffff }, - { 0x21001e4e, 0x24000001 }, - { 0x21001e4f, 0x1400ffff }, - { 0x21001e50, 0x24000001 }, - { 0x21001e51, 0x1400ffff }, - { 0x21001e52, 0x24000001 }, - { 0x21001e53, 0x1400ffff }, - { 0x21001e54, 0x24000001 }, - { 0x21001e55, 0x1400ffff }, - { 0x21001e56, 0x24000001 }, - { 0x21001e57, 0x1400ffff }, - { 0x21001e58, 0x24000001 }, - { 0x21001e59, 0x1400ffff }, - { 0x21001e5a, 0x24000001 }, - { 0x21001e5b, 0x1400ffff }, - { 0x21001e5c, 0x24000001 }, - { 0x21001e5d, 0x1400ffff }, - { 0x21001e5e, 0x24000001 }, - { 0x21001e5f, 0x1400ffff }, - { 0x21001e60, 0x24000001 }, - { 0x21001e61, 0x1400ffff }, - { 0x21001e62, 0x24000001 }, - { 0x21001e63, 0x1400ffff }, - { 0x21001e64, 0x24000001 }, - { 0x21001e65, 0x1400ffff }, - { 0x21001e66, 0x24000001 }, - { 0x21001e67, 0x1400ffff }, - { 0x21001e68, 0x24000001 }, - { 0x21001e69, 0x1400ffff }, - { 0x21001e6a, 0x24000001 }, - { 0x21001e6b, 0x1400ffff }, - { 0x21001e6c, 0x24000001 }, - { 0x21001e6d, 0x1400ffff }, - { 0x21001e6e, 0x24000001 }, - { 0x21001e6f, 0x1400ffff }, - { 0x21001e70, 0x24000001 }, - { 0x21001e71, 0x1400ffff }, - { 0x21001e72, 0x24000001 }, - { 0x21001e73, 0x1400ffff }, - { 0x21001e74, 0x24000001 }, - { 0x21001e75, 0x1400ffff }, - { 0x21001e76, 0x24000001 }, - { 0x21001e77, 0x1400ffff }, - { 0x21001e78, 0x24000001 }, - { 0x21001e79, 0x1400ffff }, - { 0x21001e7a, 0x24000001 }, - { 0x21001e7b, 0x1400ffff }, - { 0x21001e7c, 0x24000001 }, - { 0x21001e7d, 0x1400ffff }, - { 0x21001e7e, 0x24000001 }, - { 0x21001e7f, 0x1400ffff }, - { 0x21001e80, 0x24000001 }, - { 0x21001e81, 0x1400ffff }, - { 0x21001e82, 0x24000001 }, - { 0x21001e83, 0x1400ffff }, - { 0x21001e84, 0x24000001 }, - { 0x21001e85, 0x1400ffff }, - { 0x21001e86, 0x24000001 }, - { 0x21001e87, 0x1400ffff }, - { 0x21001e88, 0x24000001 }, - { 0x21001e89, 0x1400ffff }, - { 0x21001e8a, 0x24000001 }, - { 0x21001e8b, 0x1400ffff }, - { 0x21001e8c, 0x24000001 }, - { 0x21001e8d, 0x1400ffff }, - { 0x21001e8e, 0x24000001 }, - { 0x21001e8f, 0x1400ffff }, - { 0x21001e90, 0x24000001 }, - { 0x21001e91, 0x1400ffff }, - { 0x21001e92, 0x24000001 }, - { 0x21001e93, 0x1400ffff }, - { 0x21001e94, 0x24000001 }, - { 0x21001e95, 0x1400ffff }, - { 0x21801e96, 0x14000004 }, - { 0x21001e9b, 0x1400ffc5 }, - { 0x21001ea0, 0x24000001 }, - { 0x21001ea1, 0x1400ffff }, - { 0x21001ea2, 0x24000001 }, - { 0x21001ea3, 0x1400ffff }, - { 0x21001ea4, 0x24000001 }, - { 0x21001ea5, 0x1400ffff }, - { 0x21001ea6, 0x24000001 }, - { 0x21001ea7, 0x1400ffff }, - { 0x21001ea8, 0x24000001 }, - { 0x21001ea9, 0x1400ffff }, - { 0x21001eaa, 0x24000001 }, - { 0x21001eab, 0x1400ffff }, - { 0x21001eac, 0x24000001 }, - { 0x21001ead, 0x1400ffff }, - { 0x21001eae, 0x24000001 }, - { 0x21001eaf, 0x1400ffff }, - { 0x21001eb0, 0x24000001 }, - { 0x21001eb1, 0x1400ffff }, - { 0x21001eb2, 0x24000001 }, - { 0x21001eb3, 0x1400ffff }, - { 0x21001eb4, 0x24000001 }, - { 0x21001eb5, 0x1400ffff }, - { 0x21001eb6, 0x24000001 }, - { 0x21001eb7, 0x1400ffff }, - { 0x21001eb8, 0x24000001 }, - { 0x21001eb9, 0x1400ffff }, - { 0x21001eba, 0x24000001 }, - { 0x21001ebb, 0x1400ffff }, - { 0x21001ebc, 0x24000001 }, - { 0x21001ebd, 0x1400ffff }, - { 0x21001ebe, 0x24000001 }, - { 0x21001ebf, 0x1400ffff }, - { 0x21001ec0, 0x24000001 }, - { 0x21001ec1, 0x1400ffff }, - { 0x21001ec2, 0x24000001 }, - { 0x21001ec3, 0x1400ffff }, - { 0x21001ec4, 0x24000001 }, - { 0x21001ec5, 0x1400ffff }, - { 0x21001ec6, 0x24000001 }, - { 0x21001ec7, 0x1400ffff }, - { 0x21001ec8, 0x24000001 }, - { 0x21001ec9, 0x1400ffff }, - { 0x21001eca, 0x24000001 }, - { 0x21001ecb, 0x1400ffff }, - { 0x21001ecc, 0x24000001 }, - { 0x21001ecd, 0x1400ffff }, - { 0x21001ece, 0x24000001 }, - { 0x21001ecf, 0x1400ffff }, - { 0x21001ed0, 0x24000001 }, - { 0x21001ed1, 0x1400ffff }, - { 0x21001ed2, 0x24000001 }, - { 0x21001ed3, 0x1400ffff }, - { 0x21001ed4, 0x24000001 }, - { 0x21001ed5, 0x1400ffff }, - { 0x21001ed6, 0x24000001 }, - { 0x21001ed7, 0x1400ffff }, - { 0x21001ed8, 0x24000001 }, - { 0x21001ed9, 0x1400ffff }, - { 0x21001eda, 0x24000001 }, - { 0x21001edb, 0x1400ffff }, - { 0x21001edc, 0x24000001 }, - { 0x21001edd, 0x1400ffff }, - { 0x21001ede, 0x24000001 }, - { 0x21001edf, 0x1400ffff }, - { 0x21001ee0, 0x24000001 }, - { 0x21001ee1, 0x1400ffff }, - { 0x21001ee2, 0x24000001 }, - { 0x21001ee3, 0x1400ffff }, - { 0x21001ee4, 0x24000001 }, - { 0x21001ee5, 0x1400ffff }, - { 0x21001ee6, 0x24000001 }, - { 0x21001ee7, 0x1400ffff }, - { 0x21001ee8, 0x24000001 }, - { 0x21001ee9, 0x1400ffff }, - { 0x21001eea, 0x24000001 }, - { 0x21001eeb, 0x1400ffff }, - { 0x21001eec, 0x24000001 }, - { 0x21001eed, 0x1400ffff }, - { 0x21001eee, 0x24000001 }, - { 0x21001eef, 0x1400ffff }, - { 0x21001ef0, 0x24000001 }, - { 0x21001ef1, 0x1400ffff }, - { 0x21001ef2, 0x24000001 }, - { 0x21001ef3, 0x1400ffff }, - { 0x21001ef4, 0x24000001 }, - { 0x21001ef5, 0x1400ffff }, - { 0x21001ef6, 0x24000001 }, - { 0x21001ef7, 0x1400ffff }, - { 0x21001ef8, 0x24000001 }, - { 0x21001ef9, 0x1400ffff }, - { 0x13001f00, 0x14000008 }, - { 0x13001f01, 0x14000008 }, - { 0x13001f02, 0x14000008 }, - { 0x13001f03, 0x14000008 }, - { 0x13001f04, 0x14000008 }, - { 0x13001f05, 0x14000008 }, - { 0x13001f06, 0x14000008 }, - { 0x13001f07, 0x14000008 }, - { 0x13001f08, 0x2400fff8 }, - { 0x13001f09, 0x2400fff8 }, - { 0x13001f0a, 0x2400fff8 }, - { 0x13001f0b, 0x2400fff8 }, - { 0x13001f0c, 0x2400fff8 }, - { 0x13001f0d, 0x2400fff8 }, - { 0x13001f0e, 0x2400fff8 }, - { 0x13001f0f, 0x2400fff8 }, - { 0x13001f10, 0x14000008 }, - { 0x13001f11, 0x14000008 }, - { 0x13001f12, 0x14000008 }, - { 0x13001f13, 0x14000008 }, - { 0x13001f14, 0x14000008 }, - { 0x13001f15, 0x14000008 }, - { 0x13001f18, 0x2400fff8 }, - { 0x13001f19, 0x2400fff8 }, - { 0x13001f1a, 0x2400fff8 }, - { 0x13001f1b, 0x2400fff8 }, - { 0x13001f1c, 0x2400fff8 }, - { 0x13001f1d, 0x2400fff8 }, - { 0x13001f20, 0x14000008 }, - { 0x13001f21, 0x14000008 }, - { 0x13001f22, 0x14000008 }, - { 0x13001f23, 0x14000008 }, - { 0x13001f24, 0x14000008 }, - { 0x13001f25, 0x14000008 }, - { 0x13001f26, 0x14000008 }, - { 0x13001f27, 0x14000008 }, - { 0x13001f28, 0x2400fff8 }, - { 0x13001f29, 0x2400fff8 }, - { 0x13001f2a, 0x2400fff8 }, - { 0x13001f2b, 0x2400fff8 }, - { 0x13001f2c, 0x2400fff8 }, - { 0x13001f2d, 0x2400fff8 }, - { 0x13001f2e, 0x2400fff8 }, - { 0x13001f2f, 0x2400fff8 }, - { 0x13001f30, 0x14000008 }, - { 0x13001f31, 0x14000008 }, - { 0x13001f32, 0x14000008 }, - { 0x13001f33, 0x14000008 }, - { 0x13001f34, 0x14000008 }, - { 0x13001f35, 0x14000008 }, - { 0x13001f36, 0x14000008 }, - { 0x13001f37, 0x14000008 }, - { 0x13001f38, 0x2400fff8 }, - { 0x13001f39, 0x2400fff8 }, - { 0x13001f3a, 0x2400fff8 }, - { 0x13001f3b, 0x2400fff8 }, - { 0x13001f3c, 0x2400fff8 }, - { 0x13001f3d, 0x2400fff8 }, - { 0x13001f3e, 0x2400fff8 }, - { 0x13001f3f, 0x2400fff8 }, - { 0x13001f40, 0x14000008 }, - { 0x13001f41, 0x14000008 }, - { 0x13001f42, 0x14000008 }, - { 0x13001f43, 0x14000008 }, - { 0x13001f44, 0x14000008 }, - { 0x13001f45, 0x14000008 }, - { 0x13001f48, 0x2400fff8 }, - { 0x13001f49, 0x2400fff8 }, - { 0x13001f4a, 0x2400fff8 }, - { 0x13001f4b, 0x2400fff8 }, - { 0x13001f4c, 0x2400fff8 }, - { 0x13001f4d, 0x2400fff8 }, - { 0x13001f50, 0x14000000 }, - { 0x13001f51, 0x14000008 }, - { 0x13001f52, 0x14000000 }, - { 0x13001f53, 0x14000008 }, - { 0x13001f54, 0x14000000 }, - { 0x13001f55, 0x14000008 }, - { 0x13001f56, 0x14000000 }, - { 0x13001f57, 0x14000008 }, - { 0x13001f59, 0x2400fff8 }, - { 0x13001f5b, 0x2400fff8 }, - { 0x13001f5d, 0x2400fff8 }, - { 0x13001f5f, 0x2400fff8 }, - { 0x13001f60, 0x14000008 }, - { 0x13001f61, 0x14000008 }, - { 0x13001f62, 0x14000008 }, - { 0x13001f63, 0x14000008 }, - { 0x13001f64, 0x14000008 }, - { 0x13001f65, 0x14000008 }, - { 0x13001f66, 0x14000008 }, - { 0x13001f67, 0x14000008 }, - { 0x13001f68, 0x2400fff8 }, - { 0x13001f69, 0x2400fff8 }, - { 0x13001f6a, 0x2400fff8 }, - { 0x13001f6b, 0x2400fff8 }, - { 0x13001f6c, 0x2400fff8 }, - { 0x13001f6d, 0x2400fff8 }, - { 0x13001f6e, 0x2400fff8 }, - { 0x13001f6f, 0x2400fff8 }, - { 0x13001f70, 0x1400004a }, - { 0x13001f71, 0x1400004a }, - { 0x13001f72, 0x14000056 }, - { 0x13001f73, 0x14000056 }, - { 0x13001f74, 0x14000056 }, - { 0x13001f75, 0x14000056 }, - { 0x13001f76, 0x14000064 }, - { 0x13001f77, 0x14000064 }, - { 0x13001f78, 0x14000080 }, - { 0x13001f79, 0x14000080 }, - { 0x13001f7a, 0x14000070 }, - { 0x13001f7b, 0x14000070 }, - { 0x13001f7c, 0x1400007e }, - { 0x13001f7d, 0x1400007e }, - { 0x13001f80, 0x14000008 }, - { 0x13001f81, 0x14000008 }, - { 0x13001f82, 0x14000008 }, - { 0x13001f83, 0x14000008 }, - { 0x13001f84, 0x14000008 }, - { 0x13001f85, 0x14000008 }, - { 0x13001f86, 0x14000008 }, - { 0x13001f87, 0x14000008 }, - { 0x13001f88, 0x2000fff8 }, - { 0x13001f89, 0x2000fff8 }, - { 0x13001f8a, 0x2000fff8 }, - { 0x13001f8b, 0x2000fff8 }, - { 0x13001f8c, 0x2000fff8 }, - { 0x13001f8d, 0x2000fff8 }, - { 0x13001f8e, 0x2000fff8 }, - { 0x13001f8f, 0x2000fff8 }, - { 0x13001f90, 0x14000008 }, - { 0x13001f91, 0x14000008 }, - { 0x13001f92, 0x14000008 }, - { 0x13001f93, 0x14000008 }, - { 0x13001f94, 0x14000008 }, - { 0x13001f95, 0x14000008 }, - { 0x13001f96, 0x14000008 }, - { 0x13001f97, 0x14000008 }, - { 0x13001f98, 0x2000fff8 }, - { 0x13001f99, 0x2000fff8 }, - { 0x13001f9a, 0x2000fff8 }, - { 0x13001f9b, 0x2000fff8 }, - { 0x13001f9c, 0x2000fff8 }, - { 0x13001f9d, 0x2000fff8 }, - { 0x13001f9e, 0x2000fff8 }, - { 0x13001f9f, 0x2000fff8 }, - { 0x13001fa0, 0x14000008 }, - { 0x13001fa1, 0x14000008 }, - { 0x13001fa2, 0x14000008 }, - { 0x13001fa3, 0x14000008 }, - { 0x13001fa4, 0x14000008 }, - { 0x13001fa5, 0x14000008 }, - { 0x13001fa6, 0x14000008 }, - { 0x13001fa7, 0x14000008 }, - { 0x13001fa8, 0x2000fff8 }, - { 0x13001fa9, 0x2000fff8 }, - { 0x13001faa, 0x2000fff8 }, - { 0x13001fab, 0x2000fff8 }, - { 0x13001fac, 0x2000fff8 }, - { 0x13001fad, 0x2000fff8 }, - { 0x13001fae, 0x2000fff8 }, - { 0x13001faf, 0x2000fff8 }, - { 0x13001fb0, 0x14000008 }, - { 0x13001fb1, 0x14000008 }, - { 0x13001fb2, 0x14000000 }, - { 0x13001fb3, 0x14000009 }, - { 0x13001fb4, 0x14000000 }, - { 0x13801fb6, 0x14000001 }, - { 0x13001fb8, 0x2400fff8 }, - { 0x13001fb9, 0x2400fff8 }, - { 0x13001fba, 0x2400ffb6 }, - { 0x13001fbb, 0x2400ffb6 }, - { 0x13001fbc, 0x2000fff7 }, - { 0x13001fbd, 0x60000000 }, - { 0x13001fbe, 0x1400e3db }, - { 0x13801fbf, 0x60000002 }, - { 0x13001fc2, 0x14000000 }, - { 0x13001fc3, 0x14000009 }, - { 0x13001fc4, 0x14000000 }, - { 0x13801fc6, 0x14000001 }, - { 0x13001fc8, 0x2400ffaa }, - { 0x13001fc9, 0x2400ffaa }, - { 0x13001fca, 0x2400ffaa }, - { 0x13001fcb, 0x2400ffaa }, - { 0x13001fcc, 0x2000fff7 }, - { 0x13801fcd, 0x60000002 }, - { 0x13001fd0, 0x14000008 }, - { 0x13001fd1, 0x14000008 }, - { 0x13801fd2, 0x14000001 }, - { 0x13801fd6, 0x14000001 }, - { 0x13001fd8, 0x2400fff8 }, - { 0x13001fd9, 0x2400fff8 }, - { 0x13001fda, 0x2400ff9c }, - { 0x13001fdb, 0x2400ff9c }, - { 0x13801fdd, 0x60000002 }, - { 0x13001fe0, 0x14000008 }, - { 0x13001fe1, 0x14000008 }, - { 0x13801fe2, 0x14000002 }, - { 0x13001fe5, 0x14000007 }, - { 0x13801fe6, 0x14000001 }, - { 0x13001fe8, 0x2400fff8 }, - { 0x13001fe9, 0x2400fff8 }, - { 0x13001fea, 0x2400ff90 }, - { 0x13001feb, 0x2400ff90 }, - { 0x13001fec, 0x2400fff9 }, - { 0x13801fed, 0x60000002 }, - { 0x13001ff2, 0x14000000 }, - { 0x13001ff3, 0x14000009 }, - { 0x13001ff4, 0x14000000 }, - { 0x13801ff6, 0x14000001 }, - { 0x13001ff8, 0x2400ff80 }, - { 0x13001ff9, 0x2400ff80 }, - { 0x13001ffa, 0x2400ff82 }, - { 0x13001ffb, 0x2400ff82 }, - { 0x13001ffc, 0x2000fff7 }, - { 0x13801ffd, 0x60000001 }, - { 0x09802000, 0x7400000a }, - { 0x0980200b, 0x04000004 }, - { 0x09802010, 0x44000005 }, - { 0x09802016, 0x54000001 }, - { 0x09002018, 0x50000000 }, - { 0x09002019, 0x4c000000 }, - { 0x0900201a, 0x58000000 }, - { 0x0980201b, 0x50000001 }, - { 0x0900201d, 0x4c000000 }, - { 0x0900201e, 0x58000000 }, - { 0x0900201f, 0x50000000 }, - { 0x09802020, 0x54000007 }, - { 0x09002028, 0x6c000000 }, - { 0x09002029, 0x70000000 }, - { 0x0980202a, 0x04000004 }, - { 0x0900202f, 0x74000000 }, - { 0x09802030, 0x54000008 }, - { 0x09002039, 0x50000000 }, - { 0x0900203a, 0x4c000000 }, - { 0x0980203b, 0x54000003 }, - { 0x0980203f, 0x40000001 }, - { 0x09802041, 0x54000002 }, - { 0x09002044, 0x64000000 }, - { 0x09002045, 0x58000000 }, - { 0x09002046, 0x48000000 }, - { 0x09802047, 0x5400000a }, - { 0x09002052, 0x64000000 }, - { 0x09002053, 0x54000000 }, - { 0x09002054, 0x40000000 }, - { 0x09802055, 0x54000009 }, - { 0x0900205f, 0x74000000 }, - { 0x09802060, 0x04000003 }, - { 0x0980206a, 0x04000005 }, - { 0x09002070, 0x3c000000 }, - { 0x21002071, 0x14000000 }, - { 0x09802074, 0x3c000005 }, - { 0x0980207a, 0x64000002 }, - { 0x0900207d, 0x58000000 }, - { 0x0900207e, 0x48000000 }, - { 0x2100207f, 0x14000000 }, - { 0x09802080, 0x3c000009 }, - { 0x0980208a, 0x64000002 }, - { 0x0900208d, 0x58000000 }, - { 0x0900208e, 0x48000000 }, - { 0x21802090, 0x18000004 }, - { 0x098020a0, 0x5c000015 }, - { 0x1b8020d0, 0x3000000c }, - { 0x1b8020dd, 0x2c000003 }, - { 0x1b0020e1, 0x30000000 }, - { 0x1b8020e2, 0x2c000002 }, - { 0x1b8020e5, 0x30000006 }, - { 0x09802100, 0x68000001 }, - { 0x09002102, 0x24000000 }, - { 0x09802103, 0x68000003 }, - { 0x09002107, 0x24000000 }, - { 0x09802108, 0x68000001 }, - { 0x0900210a, 0x14000000 }, - { 0x0980210b, 0x24000002 }, - { 0x0980210e, 0x14000001 }, - { 0x09802110, 0x24000002 }, - { 0x09002113, 0x14000000 }, - { 0x09002114, 0x68000000 }, - { 0x09002115, 0x24000000 }, - { 0x09802116, 0x68000002 }, - { 0x09802119, 0x24000004 }, - { 0x0980211e, 0x68000005 }, - { 0x09002124, 0x24000000 }, - { 0x09002125, 0x68000000 }, - { 0x13002126, 0x2400e2a3 }, - { 0x09002127, 0x68000000 }, - { 0x09002128, 0x24000000 }, - { 0x09002129, 0x68000000 }, - { 0x2100212a, 0x2400df41 }, - { 0x2100212b, 0x2400dfba }, - { 0x0980212c, 0x24000001 }, - { 0x0900212e, 0x68000000 }, - { 0x0900212f, 0x14000000 }, - { 0x09802130, 0x24000001 }, - { 0x09002132, 0x68000000 }, - { 0x09002133, 0x24000000 }, - { 0x09002134, 0x14000000 }, - { 0x09802135, 0x1c000003 }, - { 0x09002139, 0x14000000 }, - { 0x0980213a, 0x68000001 }, - { 0x0980213c, 0x14000001 }, - { 0x0980213e, 0x24000001 }, - { 0x09802140, 0x64000004 }, - { 0x09002145, 0x24000000 }, - { 0x09802146, 0x14000003 }, - { 0x0900214a, 0x68000000 }, - { 0x0900214b, 0x64000000 }, - { 0x0900214c, 0x68000000 }, - { 0x09802153, 0x3c00000c }, - { 0x09002160, 0x38000010 }, - { 0x09002161, 0x38000010 }, - { 0x09002162, 0x38000010 }, - { 0x09002163, 0x38000010 }, - { 0x09002164, 0x38000010 }, - { 0x09002165, 0x38000010 }, - { 0x09002166, 0x38000010 }, - { 0x09002167, 0x38000010 }, - { 0x09002168, 0x38000010 }, - { 0x09002169, 0x38000010 }, - { 0x0900216a, 0x38000010 }, - { 0x0900216b, 0x38000010 }, - { 0x0900216c, 0x38000010 }, - { 0x0900216d, 0x38000010 }, - { 0x0900216e, 0x38000010 }, - { 0x0900216f, 0x38000010 }, - { 0x09002170, 0x3800fff0 }, - { 0x09002171, 0x3800fff0 }, - { 0x09002172, 0x3800fff0 }, - { 0x09002173, 0x3800fff0 }, - { 0x09002174, 0x3800fff0 }, - { 0x09002175, 0x3800fff0 }, - { 0x09002176, 0x3800fff0 }, - { 0x09002177, 0x3800fff0 }, - { 0x09002178, 0x3800fff0 }, - { 0x09002179, 0x3800fff0 }, - { 0x0900217a, 0x3800fff0 }, - { 0x0900217b, 0x3800fff0 }, - { 0x0900217c, 0x3800fff0 }, - { 0x0900217d, 0x3800fff0 }, - { 0x0900217e, 0x3800fff0 }, - { 0x0900217f, 0x3800fff0 }, - { 0x09802180, 0x38000003 }, - { 0x09802190, 0x64000004 }, - { 0x09802195, 0x68000004 }, - { 0x0980219a, 0x64000001 }, - { 0x0980219c, 0x68000003 }, - { 0x090021a0, 0x64000000 }, - { 0x098021a1, 0x68000001 }, - { 0x090021a3, 0x64000000 }, - { 0x098021a4, 0x68000001 }, - { 0x090021a6, 0x64000000 }, - { 0x098021a7, 0x68000006 }, - { 0x090021ae, 0x64000000 }, - { 0x098021af, 0x6800001e }, - { 0x098021ce, 0x64000001 }, - { 0x098021d0, 0x68000001 }, - { 0x090021d2, 0x64000000 }, - { 0x090021d3, 0x68000000 }, - { 0x090021d4, 0x64000000 }, - { 0x098021d5, 0x6800001e }, - { 0x098021f4, 0x6400010b }, - { 0x09802300, 0x68000007 }, - { 0x09802308, 0x64000003 }, - { 0x0980230c, 0x68000013 }, - { 0x09802320, 0x64000001 }, - { 0x09802322, 0x68000006 }, - { 0x09002329, 0x58000000 }, - { 0x0900232a, 0x48000000 }, - { 0x0980232b, 0x68000050 }, - { 0x0900237c, 0x64000000 }, - { 0x0980237d, 0x6800001d }, - { 0x0980239b, 0x64000018 }, - { 0x090023b4, 0x58000000 }, - { 0x090023b5, 0x48000000 }, - { 0x090023b6, 0x54000000 }, - { 0x098023b7, 0x68000024 }, - { 0x09802400, 0x68000026 }, - { 0x09802440, 0x6800000a }, - { 0x09802460, 0x3c00003b }, - { 0x0980249c, 0x68000019 }, - { 0x090024b6, 0x6800001a }, - { 0x090024b7, 0x6800001a }, - { 0x090024b8, 0x6800001a }, - { 0x090024b9, 0x6800001a }, - { 0x090024ba, 0x6800001a }, - { 0x090024bb, 0x6800001a }, - { 0x090024bc, 0x6800001a }, - { 0x090024bd, 0x6800001a }, - { 0x090024be, 0x6800001a }, - { 0x090024bf, 0x6800001a }, - { 0x090024c0, 0x6800001a }, - { 0x090024c1, 0x6800001a }, - { 0x090024c2, 0x6800001a }, - { 0x090024c3, 0x6800001a }, - { 0x090024c4, 0x6800001a }, - { 0x090024c5, 0x6800001a }, - { 0x090024c6, 0x6800001a }, - { 0x090024c7, 0x6800001a }, - { 0x090024c8, 0x6800001a }, - { 0x090024c9, 0x6800001a }, - { 0x090024ca, 0x6800001a }, - { 0x090024cb, 0x6800001a }, - { 0x090024cc, 0x6800001a }, - { 0x090024cd, 0x6800001a }, - { 0x090024ce, 0x6800001a }, - { 0x090024cf, 0x6800001a }, - { 0x090024d0, 0x6800ffe6 }, - { 0x090024d1, 0x6800ffe6 }, - { 0x090024d2, 0x6800ffe6 }, - { 0x090024d3, 0x6800ffe6 }, - { 0x090024d4, 0x6800ffe6 }, - { 0x090024d5, 0x6800ffe6 }, - { 0x090024d6, 0x6800ffe6 }, - { 0x090024d7, 0x6800ffe6 }, - { 0x090024d8, 0x6800ffe6 }, - { 0x090024d9, 0x6800ffe6 }, - { 0x090024da, 0x6800ffe6 }, - { 0x090024db, 0x6800ffe6 }, - { 0x090024dc, 0x6800ffe6 }, - { 0x090024dd, 0x6800ffe6 }, - { 0x090024de, 0x6800ffe6 }, - { 0x090024df, 0x6800ffe6 }, - { 0x090024e0, 0x6800ffe6 }, - { 0x090024e1, 0x6800ffe6 }, - { 0x090024e2, 0x6800ffe6 }, - { 0x090024e3, 0x6800ffe6 }, - { 0x090024e4, 0x6800ffe6 }, - { 0x090024e5, 0x6800ffe6 }, - { 0x090024e6, 0x6800ffe6 }, - { 0x090024e7, 0x6800ffe6 }, - { 0x090024e8, 0x6800ffe6 }, - { 0x090024e9, 0x6800ffe6 }, - { 0x098024ea, 0x3c000015 }, - { 0x09802500, 0x680000b6 }, - { 0x090025b7, 0x64000000 }, - { 0x098025b8, 0x68000008 }, - { 0x090025c1, 0x64000000 }, - { 0x098025c2, 0x68000035 }, - { 0x098025f8, 0x64000007 }, - { 0x09802600, 0x6800006e }, - { 0x0900266f, 0x64000000 }, - { 0x09802670, 0x6800002c }, - { 0x098026a0, 0x68000011 }, - { 0x09802701, 0x68000003 }, - { 0x09802706, 0x68000003 }, - { 0x0980270c, 0x6800001b }, - { 0x09802729, 0x68000022 }, - { 0x0900274d, 0x68000000 }, - { 0x0980274f, 0x68000003 }, - { 0x09002756, 0x68000000 }, - { 0x09802758, 0x68000006 }, - { 0x09802761, 0x68000006 }, - { 0x09002768, 0x58000000 }, - { 0x09002769, 0x48000000 }, - { 0x0900276a, 0x58000000 }, - { 0x0900276b, 0x48000000 }, - { 0x0900276c, 0x58000000 }, - { 0x0900276d, 0x48000000 }, - { 0x0900276e, 0x58000000 }, - { 0x0900276f, 0x48000000 }, - { 0x09002770, 0x58000000 }, - { 0x09002771, 0x48000000 }, - { 0x09002772, 0x58000000 }, - { 0x09002773, 0x48000000 }, - { 0x09002774, 0x58000000 }, - { 0x09002775, 0x48000000 }, - { 0x09802776, 0x3c00001d }, - { 0x09002794, 0x68000000 }, - { 0x09802798, 0x68000017 }, - { 0x098027b1, 0x6800000d }, - { 0x098027c0, 0x64000004 }, - { 0x090027c5, 0x58000000 }, - { 0x090027c6, 0x48000000 }, - { 0x098027d0, 0x64000015 }, - { 0x090027e6, 0x58000000 }, - { 0x090027e7, 0x48000000 }, - { 0x090027e8, 0x58000000 }, - { 0x090027e9, 0x48000000 }, - { 0x090027ea, 0x58000000 }, - { 0x090027eb, 0x48000000 }, - { 0x098027f0, 0x6400000f }, - { 0x04802800, 0x680000ff }, - { 0x09802900, 0x64000082 }, - { 0x09002983, 0x58000000 }, - { 0x09002984, 0x48000000 }, - { 0x09002985, 0x58000000 }, - { 0x09002986, 0x48000000 }, - { 0x09002987, 0x58000000 }, - { 0x09002988, 0x48000000 }, - { 0x09002989, 0x58000000 }, - { 0x0900298a, 0x48000000 }, - { 0x0900298b, 0x58000000 }, - { 0x0900298c, 0x48000000 }, - { 0x0900298d, 0x58000000 }, - { 0x0900298e, 0x48000000 }, - { 0x0900298f, 0x58000000 }, - { 0x09002990, 0x48000000 }, - { 0x09002991, 0x58000000 }, - { 0x09002992, 0x48000000 }, - { 0x09002993, 0x58000000 }, - { 0x09002994, 0x48000000 }, - { 0x09002995, 0x58000000 }, - { 0x09002996, 0x48000000 }, - { 0x09002997, 0x58000000 }, - { 0x09002998, 0x48000000 }, - { 0x09802999, 0x6400003e }, - { 0x090029d8, 0x58000000 }, - { 0x090029d9, 0x48000000 }, - { 0x090029da, 0x58000000 }, - { 0x090029db, 0x48000000 }, - { 0x098029dc, 0x6400001f }, - { 0x090029fc, 0x58000000 }, - { 0x090029fd, 0x48000000 }, - { 0x098029fe, 0x64000101 }, - { 0x09802b00, 0x68000013 }, - { 0x11002c00, 0x24000030 }, - { 0x11002c01, 0x24000030 }, - { 0x11002c02, 0x24000030 }, - { 0x11002c03, 0x24000030 }, - { 0x11002c04, 0x24000030 }, - { 0x11002c05, 0x24000030 }, - { 0x11002c06, 0x24000030 }, - { 0x11002c07, 0x24000030 }, - { 0x11002c08, 0x24000030 }, - { 0x11002c09, 0x24000030 }, - { 0x11002c0a, 0x24000030 }, - { 0x11002c0b, 0x24000030 }, - { 0x11002c0c, 0x24000030 }, - { 0x11002c0d, 0x24000030 }, - { 0x11002c0e, 0x24000030 }, - { 0x11002c0f, 0x24000030 }, - { 0x11002c10, 0x24000030 }, - { 0x11002c11, 0x24000030 }, - { 0x11002c12, 0x24000030 }, - { 0x11002c13, 0x24000030 }, - { 0x11002c14, 0x24000030 }, - { 0x11002c15, 0x24000030 }, - { 0x11002c16, 0x24000030 }, - { 0x11002c17, 0x24000030 }, - { 0x11002c18, 0x24000030 }, - { 0x11002c19, 0x24000030 }, - { 0x11002c1a, 0x24000030 }, - { 0x11002c1b, 0x24000030 }, - { 0x11002c1c, 0x24000030 }, - { 0x11002c1d, 0x24000030 }, - { 0x11002c1e, 0x24000030 }, - { 0x11002c1f, 0x24000030 }, - { 0x11002c20, 0x24000030 }, - { 0x11002c21, 0x24000030 }, - { 0x11002c22, 0x24000030 }, - { 0x11002c23, 0x24000030 }, - { 0x11002c24, 0x24000030 }, - { 0x11002c25, 0x24000030 }, - { 0x11002c26, 0x24000030 }, - { 0x11002c27, 0x24000030 }, - { 0x11002c28, 0x24000030 }, - { 0x11002c29, 0x24000030 }, - { 0x11002c2a, 0x24000030 }, - { 0x11002c2b, 0x24000030 }, - { 0x11002c2c, 0x24000030 }, - { 0x11002c2d, 0x24000030 }, - { 0x11002c2e, 0x24000030 }, - { 0x11002c30, 0x1400ffd0 }, - { 0x11002c31, 0x1400ffd0 }, - { 0x11002c32, 0x1400ffd0 }, - { 0x11002c33, 0x1400ffd0 }, - { 0x11002c34, 0x1400ffd0 }, - { 0x11002c35, 0x1400ffd0 }, - { 0x11002c36, 0x1400ffd0 }, - { 0x11002c37, 0x1400ffd0 }, - { 0x11002c38, 0x1400ffd0 }, - { 0x11002c39, 0x1400ffd0 }, - { 0x11002c3a, 0x1400ffd0 }, - { 0x11002c3b, 0x1400ffd0 }, - { 0x11002c3c, 0x1400ffd0 }, - { 0x11002c3d, 0x1400ffd0 }, - { 0x11002c3e, 0x1400ffd0 }, - { 0x11002c3f, 0x1400ffd0 }, - { 0x11002c40, 0x1400ffd0 }, - { 0x11002c41, 0x1400ffd0 }, - { 0x11002c42, 0x1400ffd0 }, - { 0x11002c43, 0x1400ffd0 }, - { 0x11002c44, 0x1400ffd0 }, - { 0x11002c45, 0x1400ffd0 }, - { 0x11002c46, 0x1400ffd0 }, - { 0x11002c47, 0x1400ffd0 }, - { 0x11002c48, 0x1400ffd0 }, - { 0x11002c49, 0x1400ffd0 }, - { 0x11002c4a, 0x1400ffd0 }, - { 0x11002c4b, 0x1400ffd0 }, - { 0x11002c4c, 0x1400ffd0 }, - { 0x11002c4d, 0x1400ffd0 }, - { 0x11002c4e, 0x1400ffd0 }, - { 0x11002c4f, 0x1400ffd0 }, - { 0x11002c50, 0x1400ffd0 }, - { 0x11002c51, 0x1400ffd0 }, - { 0x11002c52, 0x1400ffd0 }, - { 0x11002c53, 0x1400ffd0 }, - { 0x11002c54, 0x1400ffd0 }, - { 0x11002c55, 0x1400ffd0 }, - { 0x11002c56, 0x1400ffd0 }, - { 0x11002c57, 0x1400ffd0 }, - { 0x11002c58, 0x1400ffd0 }, - { 0x11002c59, 0x1400ffd0 }, - { 0x11002c5a, 0x1400ffd0 }, - { 0x11002c5b, 0x1400ffd0 }, - { 0x11002c5c, 0x1400ffd0 }, - { 0x11002c5d, 0x1400ffd0 }, - { 0x11002c5e, 0x1400ffd0 }, - { 0x0a002c80, 0x24000001 }, - { 0x0a002c81, 0x1400ffff }, - { 0x0a002c82, 0x24000001 }, - { 0x0a002c83, 0x1400ffff }, - { 0x0a002c84, 0x24000001 }, - { 0x0a002c85, 0x1400ffff }, - { 0x0a002c86, 0x24000001 }, - { 0x0a002c87, 0x1400ffff }, - { 0x0a002c88, 0x24000001 }, - { 0x0a002c89, 0x1400ffff }, - { 0x0a002c8a, 0x24000001 }, - { 0x0a002c8b, 0x1400ffff }, - { 0x0a002c8c, 0x24000001 }, - { 0x0a002c8d, 0x1400ffff }, - { 0x0a002c8e, 0x24000001 }, - { 0x0a002c8f, 0x1400ffff }, - { 0x0a002c90, 0x24000001 }, - { 0x0a002c91, 0x1400ffff }, - { 0x0a002c92, 0x24000001 }, - { 0x0a002c93, 0x1400ffff }, - { 0x0a002c94, 0x24000001 }, - { 0x0a002c95, 0x1400ffff }, - { 0x0a002c96, 0x24000001 }, - { 0x0a002c97, 0x1400ffff }, - { 0x0a002c98, 0x24000001 }, - { 0x0a002c99, 0x1400ffff }, - { 0x0a002c9a, 0x24000001 }, - { 0x0a002c9b, 0x1400ffff }, - { 0x0a002c9c, 0x24000001 }, - { 0x0a002c9d, 0x1400ffff }, - { 0x0a002c9e, 0x24000001 }, - { 0x0a002c9f, 0x1400ffff }, - { 0x0a002ca0, 0x24000001 }, - { 0x0a002ca1, 0x1400ffff }, - { 0x0a002ca2, 0x24000001 }, - { 0x0a002ca3, 0x1400ffff }, - { 0x0a002ca4, 0x24000001 }, - { 0x0a002ca5, 0x1400ffff }, - { 0x0a002ca6, 0x24000001 }, - { 0x0a002ca7, 0x1400ffff }, - { 0x0a002ca8, 0x24000001 }, - { 0x0a002ca9, 0x1400ffff }, - { 0x0a002caa, 0x24000001 }, - { 0x0a002cab, 0x1400ffff }, - { 0x0a002cac, 0x24000001 }, - { 0x0a002cad, 0x1400ffff }, - { 0x0a002cae, 0x24000001 }, - { 0x0a002caf, 0x1400ffff }, - { 0x0a002cb0, 0x24000001 }, - { 0x0a002cb1, 0x1400ffff }, - { 0x0a002cb2, 0x24000001 }, - { 0x0a002cb3, 0x1400ffff }, - { 0x0a002cb4, 0x24000001 }, - { 0x0a002cb5, 0x1400ffff }, - { 0x0a002cb6, 0x24000001 }, - { 0x0a002cb7, 0x1400ffff }, - { 0x0a002cb8, 0x24000001 }, - { 0x0a002cb9, 0x1400ffff }, - { 0x0a002cba, 0x24000001 }, - { 0x0a002cbb, 0x1400ffff }, - { 0x0a002cbc, 0x24000001 }, - { 0x0a002cbd, 0x1400ffff }, - { 0x0a002cbe, 0x24000001 }, - { 0x0a002cbf, 0x1400ffff }, - { 0x0a002cc0, 0x24000001 }, - { 0x0a002cc1, 0x1400ffff }, - { 0x0a002cc2, 0x24000001 }, - { 0x0a002cc3, 0x1400ffff }, - { 0x0a002cc4, 0x24000001 }, - { 0x0a002cc5, 0x1400ffff }, - { 0x0a002cc6, 0x24000001 }, - { 0x0a002cc7, 0x1400ffff }, - { 0x0a002cc8, 0x24000001 }, - { 0x0a002cc9, 0x1400ffff }, - { 0x0a002cca, 0x24000001 }, - { 0x0a002ccb, 0x1400ffff }, - { 0x0a002ccc, 0x24000001 }, - { 0x0a002ccd, 0x1400ffff }, - { 0x0a002cce, 0x24000001 }, - { 0x0a002ccf, 0x1400ffff }, - { 0x0a002cd0, 0x24000001 }, - { 0x0a002cd1, 0x1400ffff }, - { 0x0a002cd2, 0x24000001 }, - { 0x0a002cd3, 0x1400ffff }, - { 0x0a002cd4, 0x24000001 }, - { 0x0a002cd5, 0x1400ffff }, - { 0x0a002cd6, 0x24000001 }, - { 0x0a002cd7, 0x1400ffff }, - { 0x0a002cd8, 0x24000001 }, - { 0x0a002cd9, 0x1400ffff }, - { 0x0a002cda, 0x24000001 }, - { 0x0a002cdb, 0x1400ffff }, - { 0x0a002cdc, 0x24000001 }, - { 0x0a002cdd, 0x1400ffff }, - { 0x0a002cde, 0x24000001 }, - { 0x0a002cdf, 0x1400ffff }, - { 0x0a002ce0, 0x24000001 }, - { 0x0a002ce1, 0x1400ffff }, - { 0x0a002ce2, 0x24000001 }, - { 0x0a002ce3, 0x1400ffff }, - { 0x0a002ce4, 0x14000000 }, - { 0x0a802ce5, 0x68000005 }, - { 0x0a802cf9, 0x54000003 }, - { 0x0a002cfd, 0x3c000000 }, - { 0x0a802cfe, 0x54000001 }, - { 0x10002d00, 0x1400e3a0 }, - { 0x10002d01, 0x1400e3a0 }, - { 0x10002d02, 0x1400e3a0 }, - { 0x10002d03, 0x1400e3a0 }, - { 0x10002d04, 0x1400e3a0 }, - { 0x10002d05, 0x1400e3a0 }, - { 0x10002d06, 0x1400e3a0 }, - { 0x10002d07, 0x1400e3a0 }, - { 0x10002d08, 0x1400e3a0 }, - { 0x10002d09, 0x1400e3a0 }, - { 0x10002d0a, 0x1400e3a0 }, - { 0x10002d0b, 0x1400e3a0 }, - { 0x10002d0c, 0x1400e3a0 }, - { 0x10002d0d, 0x1400e3a0 }, - { 0x10002d0e, 0x1400e3a0 }, - { 0x10002d0f, 0x1400e3a0 }, - { 0x10002d10, 0x1400e3a0 }, - { 0x10002d11, 0x1400e3a0 }, - { 0x10002d12, 0x1400e3a0 }, - { 0x10002d13, 0x1400e3a0 }, - { 0x10002d14, 0x1400e3a0 }, - { 0x10002d15, 0x1400e3a0 }, - { 0x10002d16, 0x1400e3a0 }, - { 0x10002d17, 0x1400e3a0 }, - { 0x10002d18, 0x1400e3a0 }, - { 0x10002d19, 0x1400e3a0 }, - { 0x10002d1a, 0x1400e3a0 }, - { 0x10002d1b, 0x1400e3a0 }, - { 0x10002d1c, 0x1400e3a0 }, - { 0x10002d1d, 0x1400e3a0 }, - { 0x10002d1e, 0x1400e3a0 }, - { 0x10002d1f, 0x1400e3a0 }, - { 0x10002d20, 0x1400e3a0 }, - { 0x10002d21, 0x1400e3a0 }, - { 0x10002d22, 0x1400e3a0 }, - { 0x10002d23, 0x1400e3a0 }, - { 0x10002d24, 0x1400e3a0 }, - { 0x10002d25, 0x1400e3a0 }, - { 0x3a802d30, 0x1c000035 }, - { 0x3a002d6f, 0x18000000 }, - { 0x0f802d80, 0x1c000016 }, - { 0x0f802da0, 0x1c000006 }, - { 0x0f802da8, 0x1c000006 }, - { 0x0f802db0, 0x1c000006 }, - { 0x0f802db8, 0x1c000006 }, - { 0x0f802dc0, 0x1c000006 }, - { 0x0f802dc8, 0x1c000006 }, - { 0x0f802dd0, 0x1c000006 }, - { 0x0f802dd8, 0x1c000006 }, - { 0x09802e00, 0x54000001 }, - { 0x09002e02, 0x50000000 }, - { 0x09002e03, 0x4c000000 }, - { 0x09002e04, 0x50000000 }, - { 0x09002e05, 0x4c000000 }, - { 0x09802e06, 0x54000002 }, - { 0x09002e09, 0x50000000 }, - { 0x09002e0a, 0x4c000000 }, - { 0x09002e0b, 0x54000000 }, - { 0x09002e0c, 0x50000000 }, - { 0x09002e0d, 0x4c000000 }, - { 0x09802e0e, 0x54000008 }, - { 0x09002e17, 0x44000000 }, - { 0x09002e1c, 0x50000000 }, - { 0x09002e1d, 0x4c000000 }, - { 0x16802e80, 0x68000019 }, - { 0x16802e9b, 0x68000058 }, - { 0x16802f00, 0x680000d5 }, - { 0x09802ff0, 0x6800000b }, - { 0x09003000, 0x74000000 }, - { 0x09803001, 0x54000002 }, - { 0x09003004, 0x68000000 }, - { 0x16003005, 0x18000000 }, - { 0x09003006, 0x1c000000 }, - { 0x16003007, 0x38000000 }, - { 0x09003008, 0x58000000 }, - { 0x09003009, 0x48000000 }, - { 0x0900300a, 0x58000000 }, - { 0x0900300b, 0x48000000 }, - { 0x0900300c, 0x58000000 }, - { 0x0900300d, 0x48000000 }, - { 0x0900300e, 0x58000000 }, - { 0x0900300f, 0x48000000 }, - { 0x09003010, 0x58000000 }, - { 0x09003011, 0x48000000 }, - { 0x09803012, 0x68000001 }, - { 0x09003014, 0x58000000 }, - { 0x09003015, 0x48000000 }, - { 0x09003016, 0x58000000 }, - { 0x09003017, 0x48000000 }, - { 0x09003018, 0x58000000 }, - { 0x09003019, 0x48000000 }, - { 0x0900301a, 0x58000000 }, - { 0x0900301b, 0x48000000 }, - { 0x0900301c, 0x44000000 }, - { 0x0900301d, 0x58000000 }, - { 0x0980301e, 0x48000001 }, - { 0x09003020, 0x68000000 }, - { 0x16803021, 0x38000008 }, - { 0x1b80302a, 0x30000005 }, - { 0x09003030, 0x44000000 }, - { 0x09803031, 0x18000004 }, - { 0x09803036, 0x68000001 }, - { 0x16803038, 0x38000002 }, - { 0x1600303b, 0x18000000 }, - { 0x0900303c, 0x1c000000 }, - { 0x0900303d, 0x54000000 }, - { 0x0980303e, 0x68000001 }, - { 0x1a803041, 0x1c000055 }, - { 0x1b803099, 0x30000001 }, - { 0x0980309b, 0x60000001 }, - { 0x1a80309d, 0x18000001 }, - { 0x1a00309f, 0x1c000000 }, - { 0x090030a0, 0x44000000 }, - { 0x1d8030a1, 0x1c000059 }, - { 0x090030fb, 0x54000000 }, - { 0x098030fc, 0x18000002 }, - { 0x1d0030ff, 0x1c000000 }, - { 0x03803105, 0x1c000027 }, - { 0x17803131, 0x1c00005d }, - { 0x09803190, 0x68000001 }, - { 0x09803192, 0x3c000003 }, - { 0x09803196, 0x68000009 }, - { 0x038031a0, 0x1c000017 }, - { 0x098031c0, 0x6800000f }, - { 0x1d8031f0, 0x1c00000f }, - { 0x17803200, 0x6800001e }, - { 0x09803220, 0x3c000009 }, - { 0x0980322a, 0x68000019 }, - { 0x09003250, 0x68000000 }, - { 0x09803251, 0x3c00000e }, - { 0x17803260, 0x6800001f }, - { 0x09803280, 0x3c000009 }, - { 0x0980328a, 0x68000026 }, - { 0x098032b1, 0x3c00000e }, - { 0x098032c0, 0x6800003e }, - { 0x09803300, 0x680000ff }, - { 0x16803400, 0x1c0019b5 }, - { 0x09804dc0, 0x6800003f }, - { 0x16804e00, 0x1c0051bb }, - { 0x3c80a000, 0x1c000014 }, - { 0x3c00a015, 0x18000000 }, - { 0x3c80a016, 0x1c000476 }, - { 0x3c80a490, 0x68000036 }, - { 0x0980a700, 0x60000016 }, - { 0x3080a800, 0x1c000001 }, - { 0x3000a802, 0x28000000 }, - { 0x3080a803, 0x1c000002 }, - { 0x3000a806, 0x30000000 }, - { 0x3080a807, 0x1c000003 }, - { 0x3000a80b, 0x30000000 }, - { 0x3080a80c, 0x1c000016 }, - { 0x3080a823, 0x28000001 }, - { 0x3080a825, 0x30000001 }, - { 0x3000a827, 0x28000000 }, - { 0x3080a828, 0x68000003 }, - { 0x1780ac00, 0x1c002ba3 }, - { 0x0980d800, 0x1000037f }, - { 0x0980db80, 0x1000007f }, - { 0x0980dc00, 0x100003ff }, - { 0x0980e000, 0x0c0018ff }, - { 0x1680f900, 0x1c00012d }, - { 0x1680fa30, 0x1c00003a }, - { 0x1680fa70, 0x1c000069 }, - { 0x2180fb00, 0x14000006 }, - { 0x0180fb13, 0x14000004 }, - { 0x1900fb1d, 0x1c000000 }, - { 0x1900fb1e, 0x30000000 }, - { 0x1980fb1f, 0x1c000009 }, - { 0x1900fb29, 0x64000000 }, - { 0x1980fb2a, 0x1c00000c }, - { 0x1980fb38, 0x1c000004 }, - { 0x1900fb3e, 0x1c000000 }, - { 0x1980fb40, 0x1c000001 }, - { 0x1980fb43, 0x1c000001 }, - { 0x1980fb46, 0x1c00006b }, - { 0x0080fbd3, 0x1c00016a }, - { 0x0900fd3e, 0x58000000 }, - { 0x0900fd3f, 0x48000000 }, - { 0x0080fd50, 0x1c00003f }, - { 0x0080fd92, 0x1c000035 }, - { 0x0080fdf0, 0x1c00000b }, - { 0x0000fdfc, 0x5c000000 }, - { 0x0900fdfd, 0x68000000 }, - { 0x1b80fe00, 0x3000000f }, - { 0x0980fe10, 0x54000006 }, - { 0x0900fe17, 0x58000000 }, - { 0x0900fe18, 0x48000000 }, - { 0x0900fe19, 0x54000000 }, - { 0x1b80fe20, 0x30000003 }, - { 0x0900fe30, 0x54000000 }, - { 0x0980fe31, 0x44000001 }, - { 0x0980fe33, 0x40000001 }, - { 0x0900fe35, 0x58000000 }, - { 0x0900fe36, 0x48000000 }, - { 0x0900fe37, 0x58000000 }, - { 0x0900fe38, 0x48000000 }, - { 0x0900fe39, 0x58000000 }, - { 0x0900fe3a, 0x48000000 }, - { 0x0900fe3b, 0x58000000 }, - { 0x0900fe3c, 0x48000000 }, - { 0x0900fe3d, 0x58000000 }, - { 0x0900fe3e, 0x48000000 }, - { 0x0900fe3f, 0x58000000 }, - { 0x0900fe40, 0x48000000 }, - { 0x0900fe41, 0x58000000 }, - { 0x0900fe42, 0x48000000 }, - { 0x0900fe43, 0x58000000 }, - { 0x0900fe44, 0x48000000 }, - { 0x0980fe45, 0x54000001 }, - { 0x0900fe47, 0x58000000 }, - { 0x0900fe48, 0x48000000 }, - { 0x0980fe49, 0x54000003 }, - { 0x0980fe4d, 0x40000002 }, - { 0x0980fe50, 0x54000002 }, - { 0x0980fe54, 0x54000003 }, - { 0x0900fe58, 0x44000000 }, - { 0x0900fe59, 0x58000000 }, - { 0x0900fe5a, 0x48000000 }, - { 0x0900fe5b, 0x58000000 }, - { 0x0900fe5c, 0x48000000 }, - { 0x0900fe5d, 0x58000000 }, - { 0x0900fe5e, 0x48000000 }, - { 0x0980fe5f, 0x54000002 }, - { 0x0900fe62, 0x64000000 }, - { 0x0900fe63, 0x44000000 }, - { 0x0980fe64, 0x64000002 }, - { 0x0900fe68, 0x54000000 }, - { 0x0900fe69, 0x5c000000 }, - { 0x0980fe6a, 0x54000001 }, - { 0x0080fe70, 0x1c000004 }, - { 0x0080fe76, 0x1c000086 }, - { 0x0900feff, 0x04000000 }, - { 0x0980ff01, 0x54000002 }, - { 0x0900ff04, 0x5c000000 }, - { 0x0980ff05, 0x54000002 }, - { 0x0900ff08, 0x58000000 }, - { 0x0900ff09, 0x48000000 }, - { 0x0900ff0a, 0x54000000 }, - { 0x0900ff0b, 0x64000000 }, - { 0x0900ff0c, 0x54000000 }, - { 0x0900ff0d, 0x44000000 }, - { 0x0980ff0e, 0x54000001 }, - { 0x0980ff10, 0x34000009 }, - { 0x0980ff1a, 0x54000001 }, - { 0x0980ff1c, 0x64000002 }, - { 0x0980ff1f, 0x54000001 }, - { 0x2100ff21, 0x24000020 }, - { 0x2100ff22, 0x24000020 }, - { 0x2100ff23, 0x24000020 }, - { 0x2100ff24, 0x24000020 }, - { 0x2100ff25, 0x24000020 }, - { 0x2100ff26, 0x24000020 }, - { 0x2100ff27, 0x24000020 }, - { 0x2100ff28, 0x24000020 }, - { 0x2100ff29, 0x24000020 }, - { 0x2100ff2a, 0x24000020 }, - { 0x2100ff2b, 0x24000020 }, - { 0x2100ff2c, 0x24000020 }, - { 0x2100ff2d, 0x24000020 }, - { 0x2100ff2e, 0x24000020 }, - { 0x2100ff2f, 0x24000020 }, - { 0x2100ff30, 0x24000020 }, - { 0x2100ff31, 0x24000020 }, - { 0x2100ff32, 0x24000020 }, - { 0x2100ff33, 0x24000020 }, - { 0x2100ff34, 0x24000020 }, - { 0x2100ff35, 0x24000020 }, - { 0x2100ff36, 0x24000020 }, - { 0x2100ff37, 0x24000020 }, - { 0x2100ff38, 0x24000020 }, - { 0x2100ff39, 0x24000020 }, - { 0x2100ff3a, 0x24000020 }, - { 0x0900ff3b, 0x58000000 }, - { 0x0900ff3c, 0x54000000 }, - { 0x0900ff3d, 0x48000000 }, - { 0x0900ff3e, 0x60000000 }, - { 0x0900ff3f, 0x40000000 }, - { 0x0900ff40, 0x60000000 }, - { 0x2100ff41, 0x1400ffe0 }, - { 0x2100ff42, 0x1400ffe0 }, - { 0x2100ff43, 0x1400ffe0 }, - { 0x2100ff44, 0x1400ffe0 }, - { 0x2100ff45, 0x1400ffe0 }, - { 0x2100ff46, 0x1400ffe0 }, - { 0x2100ff47, 0x1400ffe0 }, - { 0x2100ff48, 0x1400ffe0 }, - { 0x2100ff49, 0x1400ffe0 }, - { 0x2100ff4a, 0x1400ffe0 }, - { 0x2100ff4b, 0x1400ffe0 }, - { 0x2100ff4c, 0x1400ffe0 }, - { 0x2100ff4d, 0x1400ffe0 }, - { 0x2100ff4e, 0x1400ffe0 }, - { 0x2100ff4f, 0x1400ffe0 }, - { 0x2100ff50, 0x1400ffe0 }, - { 0x2100ff51, 0x1400ffe0 }, - { 0x2100ff52, 0x1400ffe0 }, - { 0x2100ff53, 0x1400ffe0 }, - { 0x2100ff54, 0x1400ffe0 }, - { 0x2100ff55, 0x1400ffe0 }, - { 0x2100ff56, 0x1400ffe0 }, - { 0x2100ff57, 0x1400ffe0 }, - { 0x2100ff58, 0x1400ffe0 }, - { 0x2100ff59, 0x1400ffe0 }, - { 0x2100ff5a, 0x1400ffe0 }, - { 0x0900ff5b, 0x58000000 }, - { 0x0900ff5c, 0x64000000 }, - { 0x0900ff5d, 0x48000000 }, - { 0x0900ff5e, 0x64000000 }, - { 0x0900ff5f, 0x58000000 }, - { 0x0900ff60, 0x48000000 }, - { 0x0900ff61, 0x54000000 }, - { 0x0900ff62, 0x58000000 }, - { 0x0900ff63, 0x48000000 }, - { 0x0980ff64, 0x54000001 }, - { 0x1d80ff66, 0x1c000009 }, - { 0x0900ff70, 0x18000000 }, - { 0x1d80ff71, 0x1c00002c }, - { 0x0980ff9e, 0x18000001 }, - { 0x1780ffa0, 0x1c00001e }, - { 0x1780ffc2, 0x1c000005 }, - { 0x1780ffca, 0x1c000005 }, - { 0x1780ffd2, 0x1c000005 }, - { 0x1780ffda, 0x1c000002 }, - { 0x0980ffe0, 0x5c000001 }, - { 0x0900ffe2, 0x64000000 }, - { 0x0900ffe3, 0x60000000 }, - { 0x0900ffe4, 0x68000000 }, - { 0x0980ffe5, 0x5c000001 }, - { 0x0900ffe8, 0x68000000 }, - { 0x0980ffe9, 0x64000003 }, - { 0x0980ffed, 0x68000001 }, - { 0x0980fff9, 0x04000002 }, - { 0x0980fffc, 0x68000001 }, - { 0x23810000, 0x1c00000b }, - { 0x2381000d, 0x1c000019 }, - { 0x23810028, 0x1c000012 }, - { 0x2381003c, 0x1c000001 }, - { 0x2381003f, 0x1c00000e }, - { 0x23810050, 0x1c00000d }, - { 0x23810080, 0x1c00007a }, - { 0x09810100, 0x54000001 }, - { 0x09010102, 0x68000000 }, - { 0x09810107, 0x3c00002c }, - { 0x09810137, 0x68000008 }, - { 0x13810140, 0x38000034 }, - { 0x13810175, 0x3c000003 }, - { 0x13810179, 0x68000010 }, - { 0x1301018a, 0x3c000000 }, - { 0x29810300, 0x1c00001e }, - { 0x29810320, 0x3c000003 }, - { 0x12810330, 0x1c000019 }, - { 0x1201034a, 0x38000000 }, - { 0x3b810380, 0x1c00001d }, - { 0x3b01039f, 0x54000000 }, - { 0x2a8103a0, 0x1c000023 }, - { 0x2a8103c8, 0x1c000007 }, - { 0x2a0103d0, 0x68000000 }, - { 0x2a8103d1, 0x38000004 }, - { 0x0d010400, 0x24000028 }, - { 0x0d010401, 0x24000028 }, - { 0x0d010402, 0x24000028 }, - { 0x0d010403, 0x24000028 }, - { 0x0d010404, 0x24000028 }, - { 0x0d010405, 0x24000028 }, - { 0x0d010406, 0x24000028 }, - { 0x0d010407, 0x24000028 }, - { 0x0d010408, 0x24000028 }, - { 0x0d010409, 0x24000028 }, - { 0x0d01040a, 0x24000028 }, - { 0x0d01040b, 0x24000028 }, - { 0x0d01040c, 0x24000028 }, - { 0x0d01040d, 0x24000028 }, - { 0x0d01040e, 0x24000028 }, - { 0x0d01040f, 0x24000028 }, - { 0x0d010410, 0x24000028 }, - { 0x0d010411, 0x24000028 }, - { 0x0d010412, 0x24000028 }, - { 0x0d010413, 0x24000028 }, - { 0x0d010414, 0x24000028 }, - { 0x0d010415, 0x24000028 }, - { 0x0d010416, 0x24000028 }, - { 0x0d010417, 0x24000028 }, - { 0x0d010418, 0x24000028 }, - { 0x0d010419, 0x24000028 }, - { 0x0d01041a, 0x24000028 }, - { 0x0d01041b, 0x24000028 }, - { 0x0d01041c, 0x24000028 }, - { 0x0d01041d, 0x24000028 }, - { 0x0d01041e, 0x24000028 }, - { 0x0d01041f, 0x24000028 }, - { 0x0d010420, 0x24000028 }, - { 0x0d010421, 0x24000028 }, - { 0x0d010422, 0x24000028 }, - { 0x0d010423, 0x24000028 }, - { 0x0d010424, 0x24000028 }, - { 0x0d010425, 0x24000028 }, - { 0x0d010426, 0x24000028 }, - { 0x0d010427, 0x24000028 }, - { 0x0d010428, 0x1400ffd8 }, - { 0x0d010429, 0x1400ffd8 }, - { 0x0d01042a, 0x1400ffd8 }, - { 0x0d01042b, 0x1400ffd8 }, - { 0x0d01042c, 0x1400ffd8 }, - { 0x0d01042d, 0x1400ffd8 }, - { 0x0d01042e, 0x1400ffd8 }, - { 0x0d01042f, 0x1400ffd8 }, - { 0x0d010430, 0x1400ffd8 }, - { 0x0d010431, 0x1400ffd8 }, - { 0x0d010432, 0x1400ffd8 }, - { 0x0d010433, 0x1400ffd8 }, - { 0x0d010434, 0x1400ffd8 }, - { 0x0d010435, 0x1400ffd8 }, - { 0x0d010436, 0x1400ffd8 }, - { 0x0d010437, 0x1400ffd8 }, - { 0x0d010438, 0x1400ffd8 }, - { 0x0d010439, 0x1400ffd8 }, - { 0x0d01043a, 0x1400ffd8 }, - { 0x0d01043b, 0x1400ffd8 }, - { 0x0d01043c, 0x1400ffd8 }, - { 0x0d01043d, 0x1400ffd8 }, - { 0x0d01043e, 0x1400ffd8 }, - { 0x0d01043f, 0x1400ffd8 }, - { 0x0d010440, 0x1400ffd8 }, - { 0x0d010441, 0x1400ffd8 }, - { 0x0d010442, 0x1400ffd8 }, - { 0x0d010443, 0x1400ffd8 }, - { 0x0d010444, 0x1400ffd8 }, - { 0x0d010445, 0x1400ffd8 }, - { 0x0d010446, 0x1400ffd8 }, - { 0x0d010447, 0x1400ffd8 }, - { 0x0d010448, 0x1400ffd8 }, - { 0x0d010449, 0x1400ffd8 }, - { 0x0d01044a, 0x1400ffd8 }, - { 0x0d01044b, 0x1400ffd8 }, - { 0x0d01044c, 0x1400ffd8 }, - { 0x0d01044d, 0x1400ffd8 }, - { 0x0d01044e, 0x1400ffd8 }, - { 0x0d01044f, 0x1400ffd8 }, - { 0x2e810450, 0x1c00004d }, - { 0x2c8104a0, 0x34000009 }, - { 0x0b810800, 0x1c000005 }, - { 0x0b010808, 0x1c000000 }, - { 0x0b81080a, 0x1c00002b }, - { 0x0b810837, 0x1c000001 }, - { 0x0b01083c, 0x1c000000 }, - { 0x0b01083f, 0x1c000000 }, - { 0x1e010a00, 0x1c000000 }, - { 0x1e810a01, 0x30000002 }, - { 0x1e810a05, 0x30000001 }, - { 0x1e810a0c, 0x30000003 }, - { 0x1e810a10, 0x1c000003 }, - { 0x1e810a15, 0x1c000002 }, - { 0x1e810a19, 0x1c00001a }, - { 0x1e810a38, 0x30000002 }, - { 0x1e010a3f, 0x30000000 }, - { 0x1e810a40, 0x3c000007 }, - { 0x1e810a50, 0x54000008 }, - { 0x0981d000, 0x680000f5 }, - { 0x0981d100, 0x68000026 }, - { 0x0981d12a, 0x6800003a }, - { 0x0981d165, 0x28000001 }, - { 0x1b81d167, 0x30000002 }, - { 0x0981d16a, 0x68000002 }, - { 0x0981d16d, 0x28000005 }, - { 0x0981d173, 0x04000007 }, - { 0x1b81d17b, 0x30000007 }, - { 0x0981d183, 0x68000001 }, - { 0x1b81d185, 0x30000006 }, - { 0x0981d18c, 0x6800001d }, - { 0x1b81d1aa, 0x30000003 }, - { 0x0981d1ae, 0x6800002f }, - { 0x1381d200, 0x68000041 }, - { 0x1381d242, 0x30000002 }, - { 0x1301d245, 0x68000000 }, - { 0x0981d300, 0x68000056 }, - { 0x0981d400, 0x24000019 }, - { 0x0981d41a, 0x14000019 }, - { 0x0981d434, 0x24000019 }, - { 0x0981d44e, 0x14000006 }, - { 0x0981d456, 0x14000011 }, - { 0x0981d468, 0x24000019 }, - { 0x0981d482, 0x14000019 }, - { 0x0901d49c, 0x24000000 }, - { 0x0981d49e, 0x24000001 }, - { 0x0901d4a2, 0x24000000 }, - { 0x0981d4a5, 0x24000001 }, - { 0x0981d4a9, 0x24000003 }, - { 0x0981d4ae, 0x24000007 }, - { 0x0981d4b6, 0x14000003 }, - { 0x0901d4bb, 0x14000000 }, - { 0x0981d4bd, 0x14000006 }, - { 0x0981d4c5, 0x1400000a }, - { 0x0981d4d0, 0x24000019 }, - { 0x0981d4ea, 0x14000019 }, - { 0x0981d504, 0x24000001 }, - { 0x0981d507, 0x24000003 }, - { 0x0981d50d, 0x24000007 }, - { 0x0981d516, 0x24000006 }, - { 0x0981d51e, 0x14000019 }, - { 0x0981d538, 0x24000001 }, - { 0x0981d53b, 0x24000003 }, - { 0x0981d540, 0x24000004 }, - { 0x0901d546, 0x24000000 }, - { 0x0981d54a, 0x24000006 }, - { 0x0981d552, 0x14000019 }, - { 0x0981d56c, 0x24000019 }, - { 0x0981d586, 0x14000019 }, - { 0x0981d5a0, 0x24000019 }, - { 0x0981d5ba, 0x14000019 }, - { 0x0981d5d4, 0x24000019 }, - { 0x0981d5ee, 0x14000019 }, - { 0x0981d608, 0x24000019 }, - { 0x0981d622, 0x14000019 }, - { 0x0981d63c, 0x24000019 }, - { 0x0981d656, 0x14000019 }, - { 0x0981d670, 0x24000019 }, - { 0x0981d68a, 0x1400001b }, - { 0x0981d6a8, 0x24000018 }, - { 0x0901d6c1, 0x64000000 }, - { 0x0981d6c2, 0x14000018 }, - { 0x0901d6db, 0x64000000 }, - { 0x0981d6dc, 0x14000005 }, - { 0x0981d6e2, 0x24000018 }, - { 0x0901d6fb, 0x64000000 }, - { 0x0981d6fc, 0x14000018 }, - { 0x0901d715, 0x64000000 }, - { 0x0981d716, 0x14000005 }, - { 0x0981d71c, 0x24000018 }, - { 0x0901d735, 0x64000000 }, - { 0x0981d736, 0x14000018 }, - { 0x0901d74f, 0x64000000 }, - { 0x0981d750, 0x14000005 }, - { 0x0981d756, 0x24000018 }, - { 0x0901d76f, 0x64000000 }, - { 0x0981d770, 0x14000018 }, - { 0x0901d789, 0x64000000 }, - { 0x0981d78a, 0x14000005 }, - { 0x0981d790, 0x24000018 }, - { 0x0901d7a9, 0x64000000 }, - { 0x0981d7aa, 0x14000018 }, - { 0x0901d7c3, 0x64000000 }, - { 0x0981d7c4, 0x14000005 }, - { 0x0981d7ce, 0x34000031 }, - { 0x16820000, 0x1c00a6d6 }, - { 0x1682f800, 0x1c00021d }, - { 0x090e0001, 0x04000000 }, - { 0x098e0020, 0x0400005f }, - { 0x1b8e0100, 0x300000ef }, - { 0x098f0000, 0x0c00fffd }, - { 0x09900000, 0x0c00fffd }, -}; diff --git a/js/src/yarr/wtfbridge.h b/js/src/yarr/wtfbridge.h new file mode 100644 index 000000000000..25a4bc5ee3d9 --- /dev/null +++ b/js/src/yarr/wtfbridge.h @@ -0,0 +1,321 @@ +/* -*- 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 ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 12, 2009. + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jswtfbridge_h__ +#define jswtfbridge_h__ + +/* + * WTF compatibility layer. This file provides various type and data + * definitions for use by Yarr. + */ + +#include "jsstr.h" +#include "jsprvtd.h" +#include "jstl.h" +#include "assembler/wtf/Platform.h" +#include "assembler/jit/ExecutableAllocator.h" + +namespace JSC { namespace Yarr { + +/* + * Basic type definitions. + */ + +typedef jschar UChar; +typedef JSLinearString UString; + +class Unicode { + public: + static UChar toUpper(UChar c) { return JS_TOUPPER(c); } + static UChar toLower(UChar c) { return JS_TOLOWER(c); } +}; + +/* + * Do-nothing smart pointer classes. These have a compatible interface + * with the smart pointers used by Yarr, but they don't actually do + * reference counting. + */ +template +class RefCounted { +}; + +template +class RefPtr { + T *ptr; + public: + RefPtr(T *p) { ptr = p; } + operator bool() const { return ptr != NULL; } + const T *operator ->() const { return ptr; } + T *get() { return ptr; } +}; + +template +class PassRefPtr { + T *ptr; + public: + PassRefPtr(T *p) { ptr = p; } + operator T*() { return ptr; } +}; + +template +class PassOwnPtr { + T *ptr; + public: + PassOwnPtr(T *p) { ptr = p; } + + T *get() { return ptr; } +}; + +template +class OwnPtr { + T *ptr; + public: + OwnPtr() : ptr(NULL) { } + OwnPtr(PassOwnPtr p) : ptr(p.get()) { } + + ~OwnPtr() { + if (ptr) + js::Foreground::delete_(ptr); + } + + OwnPtr &operator=(PassOwnPtr p) { + ptr = p.get(); + return *this; + } + + T *operator ->() { return ptr; } + + T *get() { return ptr; } + + T *release() { + T *result = ptr; + ptr = NULL; + return result; + } +}; + +template +PassRefPtr adoptRef(T *p) { return PassRefPtr(p); } + +template +PassOwnPtr adoptPtr(T *p) { return PassOwnPtr(p); } + +#define WTF_MAKE_FAST_ALLOCATED + +/* + * Vector class for Yarr. This wraps js::Vector and provides all + * the API method signatures used by Yarr. + */ +template +class Vector { + public: + js::Vector impl; + public: + Vector() {} + + Vector(const Vector &v) { + // XXX yarr-oom + (void) append(v); + } + + size_t size() const { + return impl.length(); + } + + T &operator[](size_t i) { + return impl[i]; + } + + const T &operator[](size_t i) const { + return impl[i]; + } + + T &at(size_t i) { + return impl[i]; + } + + const T *begin() const { + return impl.begin(); + } + + T &last() { + return impl.back(); + } + + bool isEmpty() const { + return impl.empty(); + } + + template + void append(const U &u) { + // XXX yarr-oom + (void) impl.append(static_cast(u)); + } + + template + void append(const Vector &v) { + // XXX yarr-oom + (void) impl.append(v.impl); + } + + void insert(size_t i, const T& t) { + // XXX yarr-oom + (void) impl.insert(&impl[i], t); + } + + void remove(size_t i) { + impl.erase(&impl[i]); + } + + void clear() { + return impl.clear(); + } + + void shrink(size_t newLength) { + // XXX yarr-oom + JS_ASSERT(newLength <= impl.length()); + (void) impl.resize(newLength); + } + + void deleteAllValues() { + for (T *p = impl.begin(); p != impl.end(); ++p) + js::Foreground::delete_(*p); + } +}; + +template +class Vector > { + public: + js::Vector impl; + public: + Vector() {} + + size_t size() const { + return impl.length(); + } + + void append(T *t) { + // XXX yarr-oom + (void) impl.append(t); + } + + PassOwnPtr operator[](size_t i) { + return PassOwnPtr(impl[i]); + } + + void clear() { + for (T **p = impl.begin(); p != impl.end(); ++p) + js::Foreground::delete_(*p); + return impl.clear(); + } +}; + +template +inline void +deleteAllValues(Vector &v) { + v.deleteAllValues(); +} + +/* + * Minimal JSGlobalData. This used by Yarr to get the allocator. + */ +class JSGlobalData { + public: + ExecutableAllocator *regexAllocator; + + JSGlobalData(ExecutableAllocator *regexAllocator) + : regexAllocator(regexAllocator) { } +}; + +/* + * Sentinel value used in Yarr. + */ +const size_t notFound = size_t(-1); + + /* + * Do-nothing version of a macro used by WTF to avoid unused + * parameter warnings. + */ +#define UNUSED_PARAM(e) + +} /* namespace Yarr */ + +/* + * Replacements for std:: functions used in Yarr. We put them in + * namespace JSC::std so that they can still be called as std::X + * in Yarr. + */ +namespace std { + +/* + * windows.h defines a 'min' macro that would mangle the function + * name. + */ +#if WTF_COMPILER_MSVC +# undef min +# undef max +#endif + +template +inline T +min(T t1, T t2) +{ + return JS_MIN(t1, t2); +} + +template +inline T +max(T t1, T t2) +{ + return JS_MAX(t1, t2); +} + +template +inline void +swap(T &t1, T &t2) +{ + T tmp = t1; + t1 = t2; + t2 = tmp; +} +} /* namespace std */ + +} /* namespace JSC */ + +#endif diff --git a/js/src/yarr/yarr/RegexJIT.cpp b/js/src/yarr/yarr/RegexJIT.cpp deleted file mode 100644 index 1571c35b7125..000000000000 --- a/js/src/yarr/yarr/RegexJIT.cpp +++ /dev/null @@ -1,1589 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#include "RegexJIT.h" - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/LinkBuffer.h" -#include "assembler/assembler/MacroAssembler.h" -#include "RegexCompiler.h" - -#include "yarr/pcre/pcre.h" // temporary, remove when fallback is removed. - -using namespace WTF; - -namespace JSC { namespace Yarr { - -class JSGlobalData; - -class RegexGenerator : private MacroAssembler { - friend void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); - -#if WTF_CPU_ARM - static const RegisterID input = ARMRegisters::r0; - static const RegisterID index = ARMRegisters::r1; - static const RegisterID length = ARMRegisters::r2; - static const RegisterID output = ARMRegisters::r4; - - static const RegisterID regT0 = ARMRegisters::r5; - static const RegisterID regT1 = ARMRegisters::r6; - - static const RegisterID returnRegister = ARMRegisters::r0; -#elif WTF_CPU_MIPS - static const RegisterID input = MIPSRegisters::a0; - static const RegisterID index = MIPSRegisters::a1; - static const RegisterID length = MIPSRegisters::a2; - static const RegisterID output = MIPSRegisters::a3; - - static const RegisterID regT0 = MIPSRegisters::t4; - static const RegisterID regT1 = MIPSRegisters::t5; - - static const RegisterID returnRegister = MIPSRegisters::v0; -#elif WTF_CPU_SPARC - static const RegisterID input = SparcRegisters::i0; - static const RegisterID index = SparcRegisters::i1; - static const RegisterID length = SparcRegisters::i2; - static const RegisterID output = SparcRegisters::i3; - - static const RegisterID regT0 = SparcRegisters::i4; - static const RegisterID regT1 = SparcRegisters::i5; - - static const RegisterID returnRegister = SparcRegisters::i0; -#elif WTF_CPU_X86 - static const RegisterID input = X86Registers::eax; - static const RegisterID index = X86Registers::edx; - static const RegisterID length = X86Registers::ecx; - static const RegisterID output = X86Registers::edi; - - static const RegisterID regT0 = X86Registers::ebx; - static const RegisterID regT1 = X86Registers::esi; - - static const RegisterID returnRegister = X86Registers::eax; -#elif WTF_CPU_X86_64 -#if WTF_PLATFORM_WIN - static const RegisterID input = X86Registers::ecx; - static const RegisterID index = X86Registers::edx; - static const RegisterID length = X86Registers::r8; - static const RegisterID output = X86Registers::r9; -#else - static const RegisterID input = X86Registers::edi; - static const RegisterID index = X86Registers::esi; - static const RegisterID length = X86Registers::edx; - static const RegisterID output = X86Registers::ecx; -#endif - - static const RegisterID regT0 = X86Registers::eax; - static const RegisterID regT1 = X86Registers::ebx; - - static const RegisterID returnRegister = X86Registers::eax; -#endif - - void optimizeAlternative(PatternAlternative* alternative) - { - if (!alternative->m_terms.length()) - return; - - for (unsigned i = 0; i < alternative->m_terms.length() - 1; ++i) { - PatternTerm& term = alternative->m_terms[i]; - PatternTerm& nextTerm = alternative->m_terms[i + 1]; - - if ((term.type == PatternTerm::TypeCharacterClass) - && (term.quantityType == QuantifierFixedCount) - && (nextTerm.type == PatternTerm::TypePatternCharacter) - && (nextTerm.quantityType == QuantifierFixedCount)) { - PatternTerm termCopy = term; - alternative->m_terms[i] = nextTerm; - alternative->m_terms[i + 1] = termCopy; - } - } - } - - void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) - { - do { - // pick which range we're going to generate - int which = count >> 1; - char lo = ranges[which].begin; - char hi = ranges[which].end; - - // check if there are any ranges or matches below lo. If not, just jl to failure - - // if there is anything else to check, check that first, if it falls through jmp to failure. - if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { - Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); - - // generate code for all ranges before this one - if (which) - matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); - - while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { - matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex]))); - ++*matchIndex; - } - failures.append(jump()); - - loOrAbove.link(this); - } else if (which) { - Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); - - matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); - failures.append(jump()); - - loOrAbove.link(this); - } else - failures.append(branch32(LessThan, character, Imm32((unsigned short)lo))); - - while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) - ++*matchIndex; - - matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi))); - // fall through to here, the value is above hi. - - // shuffle along & loop around if there are any more matches to handle. - unsigned next = which + 1; - ranges += next; - count -= next; - } while (count); - } - - void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass) - { - if (charClass->m_table) { - ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table)); - matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry)); - return; - } - Jump unicodeFail; - if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) { - Jump isAscii = branch32(LessThanOrEqual, character, Imm32(0x7f)); - - if (charClass->m_matchesUnicode.length()) { - for (unsigned i = 0; i < charClass->m_matchesUnicode.length(); ++i) { - UChar ch = charClass->m_matchesUnicode[i]; - matchDest.append(branch32(Equal, character, Imm32(ch))); - } - } - - if (charClass->m_rangesUnicode.length()) { - for (unsigned i = 0; i < charClass->m_rangesUnicode.length(); ++i) { - UChar lo = charClass->m_rangesUnicode[i].begin; - UChar hi = charClass->m_rangesUnicode[i].end; - - Jump below = branch32(LessThan, character, Imm32(lo)); - matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi))); - below.link(this); - } - } - - unicodeFail = jump(); - isAscii.link(this); - } - - if (charClass->m_ranges.length()) { - unsigned matchIndex = 0; - JumpList failures; - matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.length(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.length()); - while (matchIndex < charClass->m_matches.length()) - matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++]))); - - failures.link(this); - } else if (charClass->m_matches.length()) { - // optimization: gather 'a','A' etc back together, can mask & test once. - js::Vector matchesAZaz; - - for (unsigned i = 0; i < charClass->m_matches.length(); ++i) { - char ch = charClass->m_matches[i]; - if (m_pattern.m_ignoreCase) { - if (isASCIILower(ch)) { - matchesAZaz.append(ch); - continue; - } - if (isASCIIUpper(ch)) - continue; - } - matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch))); - } - - if (unsigned countAZaz = matchesAZaz.length()) { - or32(Imm32(32), character); - for (unsigned i = 0; i < countAZaz; ++i) - matchDest.append(branch32(Equal, character, Imm32(matchesAZaz[i]))); - } - } - - if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) - unicodeFail.link(this); - } - - // Jumps if input not available; will have (incorrectly) incremented already! - Jump jumpIfNoAvailableInput(unsigned countToCheck) - { - add32(Imm32(countToCheck), index); - return branch32(Above, index, length); - } - - Jump jumpIfAvailableInput(unsigned countToCheck) - { - add32(Imm32(countToCheck), index); - return branch32(BelowOrEqual, index, length); - } - - Jump checkInput() - { - return branch32(BelowOrEqual, index, length); - } - - Jump atEndOfInput() - { - return branch32(Equal, index, length); - } - - Jump notAtEndOfInput() - { - return branch32(NotEqual, index, length); - } - - Jump jumpIfCharEquals(UChar ch, int inputPosition) - { - return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); - } - - Jump jumpIfCharNotEquals(UChar ch, int inputPosition) - { - return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); - } - - void readCharacter(int inputPosition, RegisterID reg) - { - load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg); - } - - void storeToFrame(RegisterID reg, unsigned frameLocation) - { - poke(reg, frameLocation); - } - - void storeToFrame(Imm32 imm, unsigned frameLocation) - { - poke(imm, frameLocation); - } - - DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) - { - return storePtrWithPatch(ImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*))); - } - - void loadFromFrame(unsigned frameLocation, RegisterID reg) - { - peek(reg, frameLocation); - } - - void loadFromFrameAndJump(unsigned frameLocation) - { - jump(Address(stackPointerRegister, frameLocation * sizeof(void*))); - } - - struct AlternativeBacktrackRecord { - DataLabelPtr dataLabel; - Label backtrackLocation; - - AlternativeBacktrackRecord(DataLabelPtr dataLabel, Label backtrackLocation) - : dataLabel(dataLabel) - , backtrackLocation(backtrackLocation) - { - } - }; - - struct TermGenerationState { - TermGenerationState(PatternDisjunction* disjunction, unsigned checkedTotal) - : disjunction(disjunction) - , checkedTotal(checkedTotal) - { - } - - void resetAlternative() - { - isBackTrackGenerated = false; - alt = 0; - } - bool alternativeValid() - { - return alt < disjunction->m_alternatives.length(); - } - void nextAlternative() - { - ++alt; - } - PatternAlternative* alternative() - { - return disjunction->m_alternatives[alt]; - } - - void resetTerm() - { - ASSERT(alternativeValid()); - t = 0; - } - bool termValid() - { - ASSERT(alternativeValid()); - return t < alternative()->m_terms.length(); - } - void nextTerm() - { - ASSERT(alternativeValid()); - ++t; - } - PatternTerm& term() - { - ASSERT(alternativeValid()); - return alternative()->m_terms[t]; - } - bool isLastTerm() - { - ASSERT(alternativeValid()); - return (t + 1) == alternative()->m_terms.length(); - } - bool isMainDisjunction() - { - return !disjunction->m_parent; - } - - PatternTerm& lookaheadTerm() - { - ASSERT(alternativeValid()); - ASSERT((t + 1) < alternative()->m_terms.length()); - return alternative()->m_terms[t + 1]; - } - bool isSinglePatternCharacterLookaheadTerm() - { - ASSERT(alternativeValid()); - return ((t + 1) < alternative()->m_terms.length()) - && (lookaheadTerm().type == PatternTerm::TypePatternCharacter) - && (lookaheadTerm().quantityType == QuantifierFixedCount) - && (lookaheadTerm().quantityCount == 1); - } - - int inputOffset() - { - return term().inputPosition - checkedTotal; - } - - void jumpToBacktrack(Jump jump, MacroAssembler* masm) - { - if (isBackTrackGenerated) - jump.linkTo(backtrackLabel, masm); - else - backTrackJumps.append(jump); - } - void jumpToBacktrack(JumpList& jumps, MacroAssembler* masm) - { - if (isBackTrackGenerated) - jumps.linkTo(backtrackLabel, masm); - else - backTrackJumps.append(jumps); - } - bool plantJumpToBacktrackIfExists(MacroAssembler* masm) - { - if (isBackTrackGenerated) { - masm->jump(backtrackLabel); - return true; - } - return false; - } - void addBacktrackJump(Jump jump) - { - backTrackJumps.append(jump); - } - void setBacktrackGenerated(Label label) - { - isBackTrackGenerated = true; - backtrackLabel = label; - } - void linkAlternativeBacktracks(MacroAssembler* masm) - { - isBackTrackGenerated = false; - backTrackJumps.link(masm); - } - void linkAlternativeBacktracksTo(Label label, MacroAssembler* masm) - { - isBackTrackGenerated = false; - backTrackJumps.linkTo(label, masm); - } - void propagateBacktrackingFrom(TermGenerationState& nestedParenthesesState, MacroAssembler* masm) - { - jumpToBacktrack(nestedParenthesesState.backTrackJumps, masm); - if (nestedParenthesesState.isBackTrackGenerated) - setBacktrackGenerated(nestedParenthesesState.backtrackLabel); - } - - PatternDisjunction* disjunction; - int checkedTotal; - private: - unsigned alt; - unsigned t; - JumpList backTrackJumps; - Label backtrackLabel; - bool isBackTrackGenerated; - }; - - void generateAssertionBOL(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - if (m_pattern.m_multiline) { - const RegisterID character = regT0; - - JumpList matchDest; - if (!term.inputPosition) - matchDest.append(branch32(Equal, index, Imm32(state.checkedTotal))); - - readCharacter(state.inputOffset() - 1, character); - matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); - state.jumpToBacktrack(jump(), this); - - matchDest.link(this); - } else { - // Erk, really should poison out these alternatives early. :-/ - if (term.inputPosition) - state.jumpToBacktrack(jump(), this); - else - state.jumpToBacktrack(branch32(NotEqual, index, Imm32(state.checkedTotal)), this); - } - } - - void generateAssertionEOL(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - if (m_pattern.m_multiline) { - const RegisterID character = regT0; - - JumpList matchDest; - if (term.inputPosition == state.checkedTotal) - matchDest.append(atEndOfInput()); - - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); - state.jumpToBacktrack(jump(), this); - - matchDest.link(this); - } else { - if (term.inputPosition == state.checkedTotal) - state.jumpToBacktrack(notAtEndOfInput(), this); - // Erk, really should poison out these alternatives early. :-/ - else - state.jumpToBacktrack(jump(), this); - } - } - - // Also falls though on nextIsNotWordChar. - void matchAssertionWordchar(TermGenerationState& state, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - if (term.inputPosition == state.checkedTotal) - nextIsNotWordChar.append(atEndOfInput()); - - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass()); - } - - void generateAssertionWordBoundary(TermGenerationState& state) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - Jump atBegin; - JumpList matchDest; - if (!term.inputPosition) - atBegin = branch32(Equal, index, Imm32(state.checkedTotal)); - readCharacter(state.inputOffset() - 1, character); - matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass()); - if (!term.inputPosition) - atBegin.link(this); - - // We fall through to here if the last character was not a wordchar. - JumpList nonWordCharThenWordChar; - JumpList nonWordCharThenNonWordChar; - if (term.invertOrCapture) { - matchAssertionWordchar(state, nonWordCharThenNonWordChar, nonWordCharThenWordChar); - nonWordCharThenWordChar.append(jump()); - } else { - matchAssertionWordchar(state, nonWordCharThenWordChar, nonWordCharThenNonWordChar); - nonWordCharThenNonWordChar.append(jump()); - } - state.jumpToBacktrack(nonWordCharThenNonWordChar, this); - - // We jump here if the last character was a wordchar. - matchDest.link(this); - JumpList wordCharThenWordChar; - JumpList wordCharThenNonWordChar; - if (term.invertOrCapture) { - matchAssertionWordchar(state, wordCharThenNonWordChar, wordCharThenWordChar); - wordCharThenWordChar.append(jump()); - } else { - matchAssertionWordchar(state, wordCharThenWordChar, wordCharThenNonWordChar); - // This can fall-though! - } - - state.jumpToBacktrack(wordCharThenWordChar, this); - - nonWordCharThenWordChar.link(this); - wordCharThenNonWordChar.link(this); - } - - void generatePatternCharacterSingle(TermGenerationState& state) - { - const RegisterID character = regT0; - UChar ch = state.term().patternCharacter; - - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - state.jumpToBacktrack(jumpIfCharNotEquals(ch, state.inputOffset()), this); - } - } - - void generatePatternCharacterPair(TermGenerationState& state) - { - const RegisterID character = regT0; -#if WTF_CPU_BIG_ENDIAN - UChar ch2 = state.term().patternCharacter; - UChar ch1 = state.lookaheadTerm().patternCharacter; -#else - UChar ch1 = state.term().patternCharacter; - UChar ch2 = state.lookaheadTerm().patternCharacter; -#endif - - int mask = 0; - int chPair = ch1 | (ch2 << 16); - - if (m_pattern.m_ignoreCase) { - if (isASCIIAlpha(ch1)) - mask |= 32; - if (isASCIIAlpha(ch2)) - mask |= 32 << 16; - } - - if (mask) { - load32WithUnalignedHalfWords(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character); - or32(Imm32(mask), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(chPair | mask)), this); - } else - state.jumpToBacktrack(branch32WithUnalignedHalfWords(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this); - } - - void generatePatternCharacterFixed(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(index, countRegister); - sub32(Imm32(term.quantityCount), countRegister); - - Label loop(this); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); - or32(Imm32(32), character); - state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - state.jumpToBacktrack(branch16(NotEqual, BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), Imm32(ch)), this); - } - add32(Imm32(1), countRegister); - branch32(NotEqual, countRegister, index).linkTo(loop, this); - } - - void generatePatternCharacterGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(Imm32(0), countRegister); - - JumpList failures; - Label loop(this); - failures.append(atEndOfInput()); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - failures.append(jumpIfCharNotEquals(ch, state.inputOffset())); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - if (term.quantityCount != 0xffffffff) { - branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); - failures.append(jump()); - } else - jump(loop); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - state.jumpToBacktrack(branchTest32(Zero, countRegister), this); - sub32(Imm32(1), countRegister); - sub32(Imm32(1), index); - - failures.link(this); - - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generatePatternCharacterNonGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - UChar ch = term.patternCharacter; - - move(Imm32(0), countRegister); - - Jump firstTimeDoNothing = jump(); - - Label hardFail(this); - sub32(countRegister, index); - state.jumpToBacktrack(jump(), this); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - - atEndOfInput().linkTo(hardFail, this); - if (term.quantityCount != 0xffffffff) - branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); - if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { - readCharacter(state.inputOffset(), character); - or32(Imm32(32), character); - branch32(NotEqual, character, Imm32(Unicode::toLower(ch))).linkTo(hardFail, this); - } else { - ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); - jumpIfCharNotEquals(ch, state.inputOffset()).linkTo(hardFail, this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - - firstTimeDoNothing.link(this); - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateCharacterClassSingle(TermGenerationState& state) - { - const RegisterID character = regT0; - PatternTerm& term = state.term(); - - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - state.jumpToBacktrack(matchDest, this); - else { - state.jumpToBacktrack(jump(), this); - matchDest.link(this); - } - } - - void generateCharacterClassFixed(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(index, countRegister); - sub32(Imm32(term.quantityCount), countRegister); - - Label loop(this); - JumpList matchDest; - load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - state.jumpToBacktrack(matchDest, this); - else { - state.jumpToBacktrack(jump(), this); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - branch32(NotEqual, countRegister, index).linkTo(loop, this); - } - - void generateCharacterClassGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(Imm32(0), countRegister); - - JumpList failures; - Label loop(this); - failures.append(atEndOfInput()); - - if (term.invertOrCapture) { - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, failures, term.characterClass); - } else { - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - failures.append(jump()); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - if (term.quantityCount != 0xffffffff) { - branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); - failures.append(jump()); - } else - jump(loop); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - state.jumpToBacktrack(branchTest32(Zero, countRegister), this); - sub32(Imm32(1), countRegister); - sub32(Imm32(1), index); - - failures.link(this); - - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateCharacterClassNonGreedy(TermGenerationState& state) - { - const RegisterID character = regT0; - const RegisterID countRegister = regT1; - PatternTerm& term = state.term(); - - move(Imm32(0), countRegister); - - Jump firstTimeDoNothing = jump(); - - Label hardFail(this); - sub32(countRegister, index); - state.jumpToBacktrack(jump(), this); - - Label backtrackBegin(this); - loadFromFrame(term.frameLocation, countRegister); - - atEndOfInput().linkTo(hardFail, this); - branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); - - JumpList matchDest; - readCharacter(state.inputOffset(), character); - matchCharacterClass(character, matchDest, term.characterClass); - - if (term.invertOrCapture) - matchDest.linkTo(hardFail, this); - else { - jump(hardFail); - matchDest.link(this); - } - - add32(Imm32(1), countRegister); - add32(Imm32(1), index); - - firstTimeDoNothing.link(this); - storeToFrame(countRegister, term.frameLocation); - - state.setBacktrackGenerated(backtrackBegin); - } - - void generateParenthesesDisjunction(PatternTerm& parenthesesTerm, TermGenerationState& state, unsigned alternativeFrameLocation) - { - ASSERT((parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern) || (parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion)); - ASSERT(parenthesesTerm.quantityCount == 1); - - PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; - unsigned preCheckedCount = ((parenthesesTerm.quantityType == QuantifierFixedCount) && (parenthesesTerm.type != PatternTerm::TypeParentheticalAssertion)) ? disjunction->m_minimumSize : 0; - - if (disjunction->m_alternatives.length() == 1) { - state.resetAlternative(); - ASSERT(state.alternativeValid()); - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - int countToCheck = alternative->m_minimumSize - preCheckedCount; - if (countToCheck) { - ASSERT((parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion) || (parenthesesTerm.quantityType != QuantifierFixedCount)); - - // FIXME: This is quite horrible. The call to 'plantJumpToBacktrackIfExists' - // will be forced to always trampoline into here, just to decrement the index. - // Ick. - Jump skip = jump(); - - Label backtrackBegin(this); - sub32(Imm32(countToCheck), index); - state.addBacktrackJump(jump()); - - skip.link(this); - - state.setBacktrackGenerated(backtrackBegin); - - state.jumpToBacktrack(jumpIfNoAvailableInput(countToCheck), this); - state.checkedTotal += countToCheck; - } - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - state.checkedTotal -= countToCheck; - } else { - JumpList successes; - - for (state.resetAlternative(); state.alternativeValid(); state.nextAlternative()) { - - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - ASSERT(alternative->m_minimumSize >= preCheckedCount); - int countToCheck = alternative->m_minimumSize - preCheckedCount; - if (countToCheck) { - state.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); - state.checkedTotal += countToCheck; - } - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - // Matched an alternative. - DataLabelPtr dataLabel = storeToFrameWithPatch(alternativeFrameLocation); - successes.append(jump()); - - // Alternative did not match. - Label backtrackLocation(this); - - // Can we backtrack the alternative? - if so, do so. If not, just fall through to the next one. - state.plantJumpToBacktrackIfExists(this); - - state.linkAlternativeBacktracks(this); - - if (countToCheck) { - sub32(Imm32(countToCheck), index); - state.checkedTotal -= countToCheck; - } - - m_backtrackRecords.append(AlternativeBacktrackRecord(dataLabel, backtrackLocation)); - } - // We fall through to here when the last alternative fails. - // Add a backtrack out of here for the parenthese handling code to link up. - state.addBacktrackJump(jump()); - - // Generate a trampoline for the parens code to backtrack to, to retry the - // next alternative. - state.setBacktrackGenerated(label()); - loadFromFrameAndJump(alternativeFrameLocation); - - // FIXME: both of the above hooks are a little inefficient, in that you - // may end up trampolining here, just to trampoline back out to the - // parentheses code, or vice versa. We can probably eliminate a jump - // by restructuring, but coding this way for now for simplicity during - // development. - - successes.link(this); - } - } - - void generateParenthesesSingle(TermGenerationState& state) - { - const RegisterID indexTemporary = regT0; - PatternTerm& term = state.term(); - PatternDisjunction* disjunction = term.parentheses.disjunction; - ASSERT(term.quantityCount == 1); - - unsigned preCheckedCount = (term.quantityType == QuantifierFixedCount) ? disjunction->m_minimumSize : 0; - - unsigned parenthesesFrameLocation = term.frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation; - if (term.quantityType != QuantifierFixedCount) - alternativeFrameLocation += RegexStackSpaceForBackTrackInfoParenthesesOnce; - - // optimized case - no capture & no quantifier can be handled in a light-weight manner. - if (!term.invertOrCapture && (term.quantityType == QuantifierFixedCount)) { - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // this expects that any backtracks back out of the parentheses will be in the - // parenthesesState's backTrackJumps vector, and that if they need backtracking - // they will have set an entry point on the parenthesesState's backtrackLabel. - state.propagateBacktrackingFrom(parenthesesState, this); - } else { - Jump nonGreedySkipParentheses; - Label nonGreedyTryParentheses; - if (term.quantityType == QuantifierGreedy) - storeToFrame(index, parenthesesFrameLocation); - else if (term.quantityType == QuantifierNonGreedy) { - storeToFrame(Imm32(-1), parenthesesFrameLocation); - nonGreedySkipParentheses = jump(); - nonGreedyTryParentheses = label(); - storeToFrame(index, parenthesesFrameLocation); - } - - // store the match start index - if (term.invertOrCapture) { - int inputOffset = state.inputOffset() - preCheckedCount; - if (inputOffset) { - move(index, indexTemporary); - add32(Imm32(inputOffset), indexTemporary); - store32(indexTemporary, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); - } else - store32(index, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); - } - - // generate the body of the parentheses - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - - Jump success = (term.quantityType == QuantifierFixedCount) ? - jump() : - branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesFrameLocation * sizeof(void*)))); - - // A failure AFTER the parens jumps here - Label backtrackFromAfterParens(this); - - if (term.quantityType == QuantifierGreedy) { - // If this is -1 we have now tested with both with and without the parens. - loadFromFrame(parenthesesFrameLocation, indexTemporary); - state.jumpToBacktrack(branch32(Equal, indexTemporary, Imm32(-1)), this); - } else if (term.quantityType == QuantifierNonGreedy) { - // If this is -1 we have now tested without the parens, now test with. - loadFromFrame(parenthesesFrameLocation, indexTemporary); - branch32(Equal, indexTemporary, Imm32(-1)).linkTo(nonGreedyTryParentheses, this); - } - - parenthesesState.plantJumpToBacktrackIfExists(this); - // A failure WITHIN the parens jumps here - parenthesesState.linkAlternativeBacktracks(this); - if (term.invertOrCapture) { - store32(Imm32(-1), Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); -#if 0 - store32(Imm32(-1), Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); -#endif - } - - if (term.quantityType == QuantifierGreedy) - storeToFrame(Imm32(-1), parenthesesFrameLocation); - else - state.jumpToBacktrack(jump(), this); - - state.setBacktrackGenerated(backtrackFromAfterParens); - if (term.quantityType == QuantifierNonGreedy) - nonGreedySkipParentheses.link(this); - success.link(this); - - // store the match end index - if (term.invertOrCapture) { - int inputOffset = state.inputOffset(); - if (inputOffset) { - move(index, indexTemporary); - add32(Imm32(state.inputOffset()), indexTemporary); - store32(indexTemporary, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); - } else - store32(index, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); - } - } - } - - void generateParenthesesGreedyNoBacktrack(TermGenerationState& state) - { - PatternTerm& parenthesesTerm = state.term(); - PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; - ASSERT(parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern); - ASSERT(parenthesesTerm.quantityCount != 1); // Handled by generateParenthesesSingle. - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - - Label matchAgain(this); - - storeToFrame(index, parenthesesTerm.frameLocation); // Save the current index to check for zero len matches later. - - for (parenthesesState.resetAlternative(); parenthesesState.alternativeValid(); parenthesesState.nextAlternative()) { - - PatternAlternative* alternative = parenthesesState.alternative(); - optimizeAlternative(alternative); - - int countToCheck = alternative->m_minimumSize; - if (countToCheck) { - parenthesesState.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); - parenthesesState.checkedTotal += countToCheck; - } - - for (parenthesesState.resetTerm(); parenthesesState.termValid(); parenthesesState.nextTerm()) - generateTerm(parenthesesState); - - // If we get here, we matched! If the index advanced then try to match more since limit isn't supported yet. - branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesTerm.frameLocation * sizeof(void*))), matchAgain); - - // If we get here we matched, but we matched "" - cannot accept this alternative as is, so either backtrack, - // or fall through to try the next alternative if no backtrack is available. - parenthesesState.plantJumpToBacktrackIfExists(this); - - parenthesesState.linkAlternativeBacktracks(this); - // We get here if the alternative fails to match - fall through to the next iteration, or out of the loop. - - if (countToCheck) { - sub32(Imm32(countToCheck), index); - parenthesesState.checkedTotal -= countToCheck; - } - } - - // If the last alternative falls through to here, we have a failed match... - // Which means that we match whatever we have matched up to this point (even if nothing). - } - - void generateParentheticalAssertion(TermGenerationState& state) - { - PatternTerm& term = state.term(); - PatternDisjunction* disjunction = term.parentheses.disjunction; - ASSERT(term.quantityCount == 1); - ASSERT(term.quantityType == QuantifierFixedCount); - - unsigned parenthesesFrameLocation = term.frameLocation; - unsigned alternativeFrameLocation = parenthesesFrameLocation + RegexStackSpaceForBackTrackInfoParentheticalAssertion; - - int countCheckedAfterAssertion = state.checkedTotal - term.inputPosition; - - if (term.invertOrCapture) { - // Inverted case - storeToFrame(index, parenthesesFrameLocation); - - state.checkedTotal -= countCheckedAfterAssertion; - if (countCheckedAfterAssertion) - sub32(Imm32(countCheckedAfterAssertion), index); - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // Success! - which means - Fail! - loadFromFrame(parenthesesFrameLocation, index); - state.jumpToBacktrack(jump(), this); - - // And fail means success. - parenthesesState.linkAlternativeBacktracks(this); - loadFromFrame(parenthesesFrameLocation, index); - - state.checkedTotal += countCheckedAfterAssertion; - } else { - // Normal case - storeToFrame(index, parenthesesFrameLocation); - - state.checkedTotal -= countCheckedAfterAssertion; - if (countCheckedAfterAssertion) - sub32(Imm32(countCheckedAfterAssertion), index); - - TermGenerationState parenthesesState(disjunction, state.checkedTotal); - generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); - // Success! - which means - Success! - loadFromFrame(parenthesesFrameLocation, index); - Jump success = jump(); - - parenthesesState.linkAlternativeBacktracks(this); - loadFromFrame(parenthesesFrameLocation, index); - state.jumpToBacktrack(jump(), this); - - success.link(this); - - state.checkedTotal += countCheckedAfterAssertion; - } - } - - void generateTerm(TermGenerationState& state) - { - PatternTerm& term = state.term(); - - switch (term.type) { - case PatternTerm::TypeAssertionBOL: - generateAssertionBOL(state); - break; - - case PatternTerm::TypeAssertionEOL: - generateAssertionEOL(state); - break; - - case PatternTerm::TypeAssertionWordBoundary: - generateAssertionWordBoundary(state); - break; - - case PatternTerm::TypePatternCharacter: - switch (term.quantityType) { - case QuantifierFixedCount: - if (term.quantityCount == 1) { - if (state.isSinglePatternCharacterLookaheadTerm() && (state.lookaheadTerm().inputPosition == (term.inputPosition + 1))) { - generatePatternCharacterPair(state); - state.nextTerm(); - } else - generatePatternCharacterSingle(state); - } else - generatePatternCharacterFixed(state); - break; - case QuantifierGreedy: - generatePatternCharacterGreedy(state); - break; - case QuantifierNonGreedy: - generatePatternCharacterNonGreedy(state); - break; - } - break; - - case PatternTerm::TypeCharacterClass: - switch (term.quantityType) { - case QuantifierFixedCount: - if (term.quantityCount == 1) - generateCharacterClassSingle(state); - else - generateCharacterClassFixed(state); - break; - case QuantifierGreedy: - generateCharacterClassGreedy(state); - break; - case QuantifierNonGreedy: - generateCharacterClassNonGreedy(state); - break; - } - break; - - case PatternTerm::TypeBackReference: - m_shouldFallBack = true; - break; - - case PatternTerm::TypeForwardReference: - break; - - case PatternTerm::TypeParenthesesSubpattern: - if (term.quantityCount == 1 && !term.parentheses.isCopy) - generateParenthesesSingle(state); - else if (term.parentheses.isTerminal) - generateParenthesesGreedyNoBacktrack(state); - else - m_shouldFallBack = true; - break; - - case PatternTerm::TypeParentheticalAssertion: - generateParentheticalAssertion(state); - break; - } - } - - void generateDisjunction(PatternDisjunction* disjunction) - { - TermGenerationState state(disjunction, 0); - state.resetAlternative(); - - // check availability for the next alternative - int countCheckedForCurrentAlternative = 0; - int countToCheckForFirstAlternative = 0; - bool hasShorterAlternatives = false; - bool setRepeatAlternativeLabels = false; - JumpList notEnoughInputForPreviousAlternative; - Label firstAlternative; - Label firstAlternativeInputChecked; - - // The label 'firstAlternative' is used to plant a check to see if there is - // sufficient input available to run the first repeating alternative. - // The label 'firstAlternativeInputChecked' will jump directly to matching - // the first repeating alternative having skipped this check. - - if (state.alternativeValid()) { - PatternAlternative* alternative = state.alternative(); - if (!alternative->onceThrough()) { - firstAlternative = Label(this); - setRepeatAlternativeLabels = true; - } - countToCheckForFirstAlternative = alternative->m_minimumSize; - state.checkedTotal += countToCheckForFirstAlternative; - if (countToCheckForFirstAlternative) - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); - countCheckedForCurrentAlternative = countToCheckForFirstAlternative; - } - - if (setRepeatAlternativeLabels) - firstAlternativeInputChecked = Label(this); - - while (state.alternativeValid()) { - PatternAlternative* alternative = state.alternative(); - optimizeAlternative(alternative); - - // Track whether any alternatives are shorter than the first one. - if (!alternative->onceThrough()) - hasShorterAlternatives = hasShorterAlternatives || (countCheckedForCurrentAlternative < countToCheckForFirstAlternative); - - for (state.resetTerm(); state.termValid(); state.nextTerm()) - generateTerm(state); - - // If we get here, the alternative matched. - if (m_pattern.m_body->m_callFrameSize) - addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - ASSERT(index != returnRegister); - if (m_pattern.m_body->m_hasFixedSize) { - move(index, returnRegister); - if (alternative->m_minimumSize) - sub32(Imm32(alternative->m_minimumSize), returnRegister); - - store32(returnRegister, output); - } else - load32(Address(output), returnRegister); - - store32(index, Address(output, 4)); - - generateReturn(); - - state.nextAlternative(); - - // if there are any more alternatives, plant the check for input before looping. - if (state.alternativeValid()) { - PatternAlternative* nextAlternative = state.alternative(); - if (!setRepeatAlternativeLabels && !nextAlternative->onceThrough()) { - // We have handled non-repeating alternatives, jump to next iteration - // and loop over repeating alternatives. - state.jumpToBacktrack(jump(), this); - - countToCheckForFirstAlternative = nextAlternative->m_minimumSize; - - // If we get here, there the last input checked failed. - notEnoughInputForPreviousAlternative.link(this); - - state.linkAlternativeBacktracks(this); - - // Back up to start the looping alternatives. - if (countCheckedForCurrentAlternative) - sub32(Imm32(countCheckedForCurrentAlternative), index); - - firstAlternative = Label(this); - - state.checkedTotal = countToCheckForFirstAlternative; - if (countToCheckForFirstAlternative) - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); - - countCheckedForCurrentAlternative = countToCheckForFirstAlternative; - - firstAlternativeInputChecked = Label(this); - - setRepeatAlternativeLabels = true; - } else { - int countToCheckForNextAlternative = nextAlternative->m_minimumSize; - - if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one. - // If we get here, then the last input checked failed. - notEnoughInputForPreviousAlternative.link(this); - - // Check if sufficent input available to run the next alternative - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); - // We are now in the correct state to enter the next alternative; this add is only required - // to mirror and revert operation of the sub32, just below. - add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); - - // If we get here, then the last input checked passed. - state.linkAlternativeBacktracks(this); - // No need to check if we can run the next alternative, since it is shorter - - // just update index. - sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); - } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one. - // If we get here, then the last input checked failed. - // If there is insufficient input to run the current alternative, and the next alternative is longer, - // then there is definitely not enough input to run it - don't even check. Just adjust index, as if - // we had checked. - notEnoughInputForPreviousAlternative.link(this); - add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index); - notEnoughInputForPreviousAlternative.append(jump()); - - // The next alternative is longer than the current one; check the difference. - state.linkAlternativeBacktracks(this); - notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); - } else { // CASE 3: Both alternatives are the same length. - ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative); - - // If the next alterative is the same length as this one, then no need to check the input - - // if there was sufficent input to run the current alternative then there is sufficient - // input to run the next one; if not, there isn't. - state.linkAlternativeBacktracks(this); - } - state.checkedTotal -= countCheckedForCurrentAlternative; - countCheckedForCurrentAlternative = countToCheckForNextAlternative; - state.checkedTotal += countCheckedForCurrentAlternative; - } - } - } - - // If we get here, all Alternatives failed... - - state.checkedTotal -= countCheckedForCurrentAlternative; - - if (!setRepeatAlternativeLabels) { - // If there are no alternatives that need repeating (all are marked 'onceThrough') then just link - // the match failures to this point, and fall through to the return below. - state.linkAlternativeBacktracks(this); - notEnoughInputForPreviousAlternative.link(this); - } else { - // How much more input need there be to be able to retry from the first alternative? - // examples: - // /yarr_jit/ or /wrec|pcre/ - // In these examples we need check for one more input before looping. - // /yarr_jit|pcre/ - // In this case we need check for 5 more input to loop (+4 to allow for the first alterative - // being four longer than the last alternative checked, and another +1 to effectively move - // the start position along by one). - // /yarr|rules/ or /wrec|notsomuch/ - // In these examples, provided that there was sufficient input to have just been matching for - // the second alternative we can loop without checking for available input (since the second - // alternative is longer than the first). In the latter example we need to decrement index - // (by 4) so the start position is only progressed by 1 from the last iteration. - int incrementForNextIter = (countToCheckForFirstAlternative - countCheckedForCurrentAlternative) + 1; - - // First, deal with the cases where there was sufficient input to try the last alternative. - if (incrementForNextIter > 0) // We need to check for more input anyway, fall through to the checking below. - state.linkAlternativeBacktracks(this); - else if (m_pattern.m_body->m_hasFixedSize && !incrementForNextIter) // No need to update anything, link these backtracks straight to the to pof the loop! - state.linkAlternativeBacktracksTo(firstAlternativeInputChecked, this); - else { // no need to check the input, but we do have some bookkeeping to do first. - state.linkAlternativeBacktracks(this); - - // Where necessary update our preserved start position. - if (!m_pattern.m_body->m_hasFixedSize) { - move(index, regT0); - sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); - store32(regT0, Address(output)); - } - - // Update index if necessary, and loop (without checking). - if (incrementForNextIter) - add32(Imm32(incrementForNextIter), index); - jump().linkTo(firstAlternativeInputChecked, this); - } - - notEnoughInputForPreviousAlternative.link(this); - // Update our idea of the start position, if we're tracking this. - if (!m_pattern.m_body->m_hasFixedSize) { - if (countCheckedForCurrentAlternative - 1) { - move(index, regT0); - sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); - store32(regT0, Address(output)); - } else - store32(index, Address(output)); - } - - // Check if there is sufficent input to run the first alternative again. - jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this); - // No - insufficent input to run the first alteranative, are there any other alternatives we - // might need to check? If so, the last check will have left the index incremented by - // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative - // LESS input is available, to have the effect of just progressing the start position by 1 - // from the last iteration. If this check passes we can just jump up to the check associated - // with the first alternative in the loop. This is a bit sad, since we'll end up trying the - // first alternative again, and this check will fail (otherwise the check planted just above - // here would have passed). This is a bit sad, however it saves trying to do something more - // complex here in compilation, and in the common case we should end up coallescing the checks. - // - // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least - // of the minimum-alternative-lengths. E.g. if I have two alternatives of length 200 and 150, - // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there - // is sufficient input to run either alternative (constantly failing). If there had been only - // one alternative, or if the shorter alternative had come first, we would have terminated - // immediately. :-/ - if (hasShorterAlternatives) - jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this); - // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true, - // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... - // but since we're about to return a failure this doesn't really matter!) - } - - if (m_pattern.m_body->m_callFrameSize) - addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - move(Imm32(-1), returnRegister); - - generateReturn(); - } - - void generateEnter() - { -#if WTF_CPU_X86_64 - push(X86Registers::ebp); - move(stackPointerRegister, X86Registers::ebp); - push(X86Registers::ebx); -#elif WTF_CPU_X86 - push(X86Registers::ebp); - move(stackPointerRegister, X86Registers::ebp); - // TODO: do we need spill registers to fill the output pointer if there are no sub captures? - push(X86Registers::ebx); - push(X86Registers::edi); - push(X86Registers::esi); - // load output into edi (2 = saved ebp + return address). - #if WTF_COMPILER_MSVC || WTF_COMPILER_SUNPRO - loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); - loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); - loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); - loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); - #else - loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); - #endif -#elif WTF_CPU_ARM - push(ARMRegisters::r4); - push(ARMRegisters::r5); - push(ARMRegisters::r6); -#if WTF_CPU_ARM_TRADITIONAL - push(ARMRegisters::r8); // scratch register -#endif - move(ARMRegisters::r3, output); -#elif WTF_CPU_SPARC - save(Imm32(-m_pattern.m_body->m_callFrameSize * sizeof(void*))); - // set m_callFrameSize to 0 avoid and stack movement later. - m_pattern.m_body->m_callFrameSize = 0; -#elif WTF_CPU_MIPS - // Do nothing. -#endif - } - - void generateReturn() - { -#if WTF_CPU_X86_64 - pop(X86Registers::ebx); - pop(X86Registers::ebp); -#elif WTF_CPU_X86 - pop(X86Registers::esi); - pop(X86Registers::edi); - pop(X86Registers::ebx); - pop(X86Registers::ebp); -#elif WTF_CPU_ARM -#if WTF_CPU_ARM_TRADITIONAL - pop(ARMRegisters::r8); // scratch register -#endif - pop(ARMRegisters::r6); - pop(ARMRegisters::r5); - pop(ARMRegisters::r4); -#elif WTF_CPU_SPARC - ret_and_restore(); - return; -#elif WTF_CPU_MIPS - // Do nothing -#endif - ret(); - } - -public: - RegexGenerator(RegexPattern& pattern) - : m_pattern(pattern) - , m_shouldFallBack(false) - { - } - - void generate() - { - generateEnter(); - - if (!m_pattern.m_body->m_hasFixedSize) - store32(index, Address(output)); - - if (m_pattern.m_body->m_callFrameSize) - subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); - - generateDisjunction(m_pattern.m_body); - } - - void compile(ExecutableAllocator& allocator, RegexCodeBlock& jitObject) - { - generate(); - - if (oom()) { - m_shouldFallBack = true; - return; - } - - ExecutablePool *dummy; - bool ok; - LinkBuffer patchBuffer(this, &allocator, &dummy, &ok); - if (!ok) { - m_shouldFallBack = true; - return; - } - - for (unsigned i = 0; i < m_backtrackRecords.length(); ++i) - patchBuffer.patch(m_backtrackRecords[i].dataLabel, patchBuffer.locationOf(m_backtrackRecords[i].backtrackLocation)); - - jitObject.set(patchBuffer.finalizeCode()); - } - - bool shouldFallBack() - { - return m_shouldFallBack; - } - -private: - RegexPattern& m_pattern; - bool m_shouldFallBack; - js::Vector m_backtrackRecords; -}; - -void jitCompileRegex(ExecutableAllocator& allocator, RegexCodeBlock& jitObject, const UString&patternString, unsigned& numSubpatterns, int &error, bool &fellBack, bool ignoreCase, bool multiline -#ifdef ANDROID - , bool forceFallback -#endif -) -{ -#ifdef ANDROID - if (!forceFallback) { -#endif - fellBack = false; - RegexPattern pattern(ignoreCase, multiline); - if ((error = compileRegex(patternString, pattern))) - return; - numSubpatterns = pattern.m_numSubpatterns; - - if (!pattern.m_containsBackreferences) { - RegexGenerator generator(pattern); - generator.compile(allocator, jitObject); - if (!generator.shouldFallBack()) - return; - } -#ifdef ANDROID - } // forceFallback -#endif - - fellBack = true; - JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase; - JSRegExpMultilineOption multilineOption = multiline ? JSRegExpMultiline : JSRegExpSingleLine; - jitObject.setFallback(jsRegExpCompile(reinterpret_cast(const_cast(patternString).chars()), patternString.length(), ignoreCaseOption, multilineOption, &numSubpatterns, &error)); -} - -}} - -#endif diff --git a/js/src/yarr/yarr/RegexJIT.h b/js/src/yarr/yarr/RegexJIT.h deleted file mode 100644 index 60a51b484c02..000000000000 --- a/js/src/yarr/yarr/RegexJIT.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2009 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 RegexJIT_h -#define RegexJIT_h - -#if ENABLE_ASSEMBLER - -#include "assembler/assembler/MacroAssembler.h" -#include "assembler/assembler/MacroAssemblerCodeRef.h" -#include "assembler/jit/ExecutableAllocator.h" -#include "RegexPattern.h" -#include "yarr/jswtfbridge.h" - -#include "yarr/pcre/pcre.h" -struct JSRegExp; // temporary, remove when fallback is removed. - -#if WTF_CPU_X86 && !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO -#define YARR_CALL __attribute__ ((regparm (3))) -#else -#define YARR_CALL -#endif - -struct JSContext; - -namespace JSC { - -namespace Yarr { - -class RegexCodeBlock { - typedef int (*RegexJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; - -public: - RegexCodeBlock() - : m_fallback(0) - { - } - - ~RegexCodeBlock() - { - if (m_fallback) - jsRegExpFree(m_fallback); - if (m_ref.m_size) - m_ref.m_executablePool->release(); - } - - JSRegExp* getFallback() { return m_fallback; } - void setFallback(JSRegExp* fallback) { m_fallback = fallback; } - - bool operator!() { return (!m_ref.m_code.executableAddress() && !m_fallback); } - void set(MacroAssembler::CodeRef ref) { m_ref = ref; } - - int execute(const UChar* input, unsigned start, unsigned length, int* output) - { - void *code = m_ref.m_code.executableAddress(); - return JS_EXTENSION((reinterpret_cast(code))(input, start, length, output)); - } - -private: - MacroAssembler::CodeRef m_ref; - JSRegExp* m_fallback; -}; - -void jitCompileRegex(ExecutableAllocator &allocator, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, int& error, bool &fellBack, bool ignoreCase = false, bool multiline = false -#ifdef ANDROID - , bool forceFallback = false -#endif -); - -inline int executeRegex(JSContext *cx, RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize) -{ - if (JSRegExp* fallback = jitObject.getFallback()) { - int result = jsRegExpExecute(cx, fallback, input, length, start, output, outputArraySize); - - if (result == JSRegExpErrorHitLimit) - return HitRecursionLimit; - - // -1 represents no-match for both PCRE and YARR. - JS_ASSERT(result >= -1); - return result; - } - - return jitObject.execute(input, start, length, output); -} - -} } // namespace JSC::Yarr - -#endif /* ENABLE_ASSEMBLER */ - -#endif // RegexJIT_h diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 50711ae8a547..7341d40d7f65 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -2032,7 +2032,7 @@ POSSIBILITY OF SUCH DAMAGE.

Apple License

-

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr/wtf, js/src/yarr/yarr, and widget/src/cocoa.

+

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr, and widget/src/cocoa.

 Copyright (C) 2008, 2009 Apple Inc. All rights reserved.

From 37f53056c80618086add6d9ca1b419508d5f7fe8 Mon Sep 17 00:00:00 2001
From: David Mandelin 
Date: Mon, 23 May 2011 17:54:42 -0700
Subject: [PATCH 104/145] Backed out changeset 119f17b3f03a -- still failing TB

---
 js/src/Makefile.in                            |   37 +-
 .../assembler/AbstractMacroAssembler.h        |   63 +-
 js/src/assembler/assembler/MacroAssembler.h   |   32 +-
 .../assembler/assembler/MacroAssemblerARM.cpp |    2 +-
 .../assembler/assembler/MacroAssemblerARM.h   |   50 +-
 .../assembler/assembler/MacroAssemblerARMv7.h |   48 +-
 .../assembler/MacroAssemblerCodeRef.h         |   17 +-
 .../assembler/assembler/MacroAssemblerSparc.h |   48 +-
 .../assembler/assembler/MacroAssemblerX86.h   |   14 +-
 .../assembler/MacroAssemblerX86Common.h       |   44 +-
 .../assembler/MacroAssemblerX86_64.h          |   16 +-
 js/src/assembler/jit/ExecutableAllocator.h    |   20 +-
 .../assembler/jit/ExecutableAllocatorOS2.cpp  |    2 +-
 .../jit/ExecutableAllocatorPosix.cpp          |    4 +-
 .../jit/ExecutableAllocatorSymbian.cpp        |    2 +-
 .../assembler/jit/ExecutableAllocatorWin.cpp  |    2 +-
 js/src/assembler/wtf/Platform.h               |  989 ++----
 .../jit-test/tests/basic/bug632964-regexp.js  |    3 +
 js/src/jscompartment.cpp                      |   11 +-
 js/src/jscompartment.h                        |   10 +-
 js/src/jsregexp.cpp                           |   46 +-
 js/src/jsregexpinlines.h                      |  119 +-
 js/src/jsvector.h                             |   22 +-
 js/src/methodjit/Compiler.cpp                 |   10 +-
 js/src/methodjit/MethodJIT.cpp                |    7 +-
 js/src/methodjit/TrampolineCompiler.cpp       |    2 +-
 js/src/yarr/BumpPointerAllocator.h            |  254 --
 js/src/yarr/Makefile                          |    5 +
 js/src/yarr/OSAllocator.h                     |  103 -
 js/src/yarr/OSAllocatorPosix.cpp              |  129 -
 js/src/yarr/OSAllocatorWin.cpp                |   89 -
 js/src/yarr/PageAllocation.h                  |  131 -
 js/src/yarr/PageBlock.cpp                     |   88 -
 js/src/yarr/PageBlock.h                       |   91 -
 js/src/yarr/VMTags.h                          |   90 -
 js/src/yarr/Yarr.h                            |   72 -
 js/src/yarr/YarrInterpreter.cpp               | 1914 -----------
 js/src/yarr/YarrInterpreter.h                 |  380 ---
 js/src/yarr/YarrJIT.cpp                       | 2405 -------------
 js/src/yarr/YarrJIT.h                         |   93 -
 js/src/yarr/jswtfbridge.h                     |   61 +
 js/src/yarr/pcre/AUTHORS                      |   12 +
 js/src/yarr/pcre/COPYING                      |   35 +
 js/src/yarr/pcre/chartables.c                 |   96 +
 js/src/yarr/pcre/dftables                     |  273 ++
 js/src/yarr/pcre/pcre.h                       |   68 +
 js/src/yarr/pcre/pcre.pri                     |   12 +
 js/src/yarr/pcre/pcre_compile.cpp             | 2702 +++++++++++++++
 js/src/yarr/pcre/pcre_exec.cpp                | 2193 ++++++++++++
 js/src/yarr/pcre/pcre_internal.h              |  434 +++
 js/src/yarr/pcre/pcre_tables.cpp              |   71 +
 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp     |   98 +
 js/src/yarr/pcre/pcre_xclass.cpp              |  114 +
 js/src/yarr/pcre/ucpinternal.h                |  126 +
 js/src/yarr/pcre/ucptable.cpp                 | 2968 +++++++++++++++++
 js/src/yarr/{ => wtf}/ASCIICType.h            |   33 +-
 js/src/yarr/wtfbridge.h                       |  321 --
 js/src/yarr/{ => yarr}/RegExpJitTables.h      |    0
 .../RegexCommon.h}                            |   56 +-
 .../RegexCompiler.cpp}                        |  568 +---
 .../RegexCompiler.h}                          |   25 +-
 js/src/yarr/yarr/RegexJIT.cpp                 | 1589 +++++++++
 js/src/yarr/yarr/RegexJIT.h                   |  112 +
 .../yarr/{YarrParser.h => yarr/RegexParser.h} |  260 +-
 .../{YarrPattern.h => yarr/RegexPattern.h}    |  218 +-
 toolkit/content/license.html                  |    2 +-
 66 files changed, 12046 insertions(+), 7865 deletions(-)
 delete mode 100644 js/src/yarr/BumpPointerAllocator.h
 create mode 100644 js/src/yarr/Makefile
 delete mode 100644 js/src/yarr/OSAllocator.h
 delete mode 100644 js/src/yarr/OSAllocatorPosix.cpp
 delete mode 100644 js/src/yarr/OSAllocatorWin.cpp
 delete mode 100644 js/src/yarr/PageAllocation.h
 delete mode 100644 js/src/yarr/PageBlock.cpp
 delete mode 100644 js/src/yarr/PageBlock.h
 delete mode 100644 js/src/yarr/VMTags.h
 delete mode 100644 js/src/yarr/Yarr.h
 delete mode 100644 js/src/yarr/YarrInterpreter.cpp
 delete mode 100644 js/src/yarr/YarrInterpreter.h
 delete mode 100644 js/src/yarr/YarrJIT.cpp
 delete mode 100644 js/src/yarr/YarrJIT.h
 create mode 100644 js/src/yarr/jswtfbridge.h
 create mode 100644 js/src/yarr/pcre/AUTHORS
 create mode 100644 js/src/yarr/pcre/COPYING
 create mode 100644 js/src/yarr/pcre/chartables.c
 create mode 100644 js/src/yarr/pcre/dftables
 create mode 100644 js/src/yarr/pcre/pcre.h
 create mode 100644 js/src/yarr/pcre/pcre.pri
 create mode 100644 js/src/yarr/pcre/pcre_compile.cpp
 create mode 100644 js/src/yarr/pcre/pcre_exec.cpp
 create mode 100644 js/src/yarr/pcre/pcre_internal.h
 create mode 100644 js/src/yarr/pcre/pcre_tables.cpp
 create mode 100644 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp
 create mode 100644 js/src/yarr/pcre/pcre_xclass.cpp
 create mode 100644 js/src/yarr/pcre/ucpinternal.h
 create mode 100644 js/src/yarr/pcre/ucptable.cpp
 rename js/src/yarr/{ => wtf}/ASCIICType.h (81%)
 delete mode 100644 js/src/yarr/wtfbridge.h
 rename js/src/yarr/{ => yarr}/RegExpJitTables.h (100%)
 rename js/src/yarr/{YarrSyntaxChecker.cpp => yarr/RegexCommon.h} (52%)
 rename js/src/yarr/{YarrPattern.cpp => yarr/RegexCompiler.cpp} (52%)
 rename js/src/yarr/{YarrSyntaxChecker.h => yarr/RegexCompiler.h} (74%)
 create mode 100644 js/src/yarr/yarr/RegexJIT.cpp
 create mode 100644 js/src/yarr/yarr/RegexJIT.h
 rename js/src/yarr/{YarrParser.h => yarr/RegexParser.h} (81%)
 rename js/src/yarr/{YarrPattern.h => yarr/RegexPattern.h} (70%)

diff --git a/js/src/Makefile.in b/js/src/Makefile.in
index 07bfdda59c82..8023b1750b05 100644
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -362,6 +362,7 @@ CPPSRCS += 	MethodJIT.cpp \
 		Retcon.cpp \
 		TrampolineCompiler.cpp \
 		$(NULL)
+#		PICStubCompiler.cpp \
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
 ifeq (x86_64, $(TARGET_CPU))
@@ -419,17 +420,14 @@ ifeq (,$(filter arm% sparc %86 x86_64,$(TARGET_CPU)))
 
 VPATH +=	$(srcdir)/assembler \
 		$(srcdir)/assembler/wtf \
-		$(srcdir)/yarr\
+		$(srcdir)/yarr/pcre \
 		$(NULL)
 
-CPPSRCS += \
-		Assertions.cpp \
-		OSAllocatorPosix.cpp \
-		OSAllocatorWin.cpp \
-		PageBlock.cpp \
-		YarrInterpreter.cpp \
-		YarrPattern.cpp \
-		YarrSyntaxChecker.cpp \
+CPPSRCS += 	pcre_compile.cpp \
+                pcre_exec.cpp \
+                pcre_tables.cpp \
+                pcre_xclass.cpp \
+                pcre_ucp_searchfuncs.cpp \
 		$(NULL)
 else
 
@@ -442,6 +440,9 @@ VPATH += 	$(srcdir)/assembler \
 		$(srcdir)/assembler/assembler \
 		$(srcdir)/methodjit \
 		$(srcdir)/yarr \
+		$(srcdir)/yarr/yarr \
+		$(srcdir)/yarr/pcre \
+		$(srcdir)/yarr/wtf \
 		$(NONE)
 
 CPPSRCS += 	Assertions.cpp \
@@ -450,16 +451,16 @@ CPPSRCS += 	Assertions.cpp \
 		ExecutableAllocatorOS2.cpp \
 		ExecutableAllocator.cpp \
 		ARMAssembler.cpp \
-        Logging.cpp \
+                Logging.cpp \
 		MacroAssemblerARM.cpp \
 		MacroAssemblerX86Common.cpp \
-		OSAllocatorPosix.cpp \
-		OSAllocatorWin.cpp \
-		PageBlock.cpp \
-		YarrInterpreter.cpp \
-		YarrJIT.cpp \
-		YarrPattern.cpp \
-		YarrSyntaxChecker.cpp \
+		RegexCompiler.cpp \
+		RegexJIT.cpp \
+		pcre_compile.cpp \
+                pcre_exec.cpp \
+                pcre_tables.cpp \
+                pcre_xclass.cpp \
+                pcre_ucp_searchfuncs.cpp \
 		$(NONE)
 
 ifeq (86, $(findstring 86,$(TARGET_CPU)))
@@ -652,7 +653,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
 
 	# We desire these numbers to go down, not up. See "User guide to memory
 	# management within SpiderMonkey" in jsutil.h.
-	$(srcdir)/config/check_source_count.py OffTheBooks:: 53 \
+	$(srcdir)/config/check_source_count.py OffTheBooks:: 52 \
 		"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
 	# This should go to zero, if possible.
 	$(srcdir)/config/check_source_count.py UnwantedForeground:: 34 \
diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h
index 3c14c80bd4b0..260380acd307 100644
--- a/js/src/assembler/assembler/AbstractMacroAssembler.h
+++ b/js/src/assembler/assembler/AbstractMacroAssembler.h
@@ -166,13 +166,13 @@ public:
         void* m_ptr;
     };
 
-    // TrustedImmPtr:
+    // ImmPtr:
     //
     // A pointer sized immediate operand to an instruction - this is wrapped
     // in a class requiring explicit construction in order to differentiate
     // from pointers used as absolute addresses to memory operations
-    struct TrustedImmPtr {
-        explicit TrustedImmPtr(const void* value)
+    struct ImmPtr {
+        explicit ImmPtr(const void* value)
             : m_value(value)
         {
         }
@@ -185,21 +185,14 @@ public:
         const void* m_value;
     };
 
-    struct ImmPtr : public TrustedImmPtr {
-        explicit ImmPtr(const void* value)
-            : TrustedImmPtr(value)
-        {
-        }
-    };
- 
-    // TrustedImm32:
+    // Imm32:
     //
     // A 32bit immediate operand to an instruction - this is wrapped in a
     // class requiring explicit construction in order to prevent RegisterIDs
     // (which are implemented as an enum) from accidentally being passed as
     // immediate values.
-    struct TrustedImm32 {
-        explicit TrustedImm32(int32_t value)
+    struct Imm32 {
+        explicit Imm32(int32_t value)
             : m_value(value)
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(false)
@@ -208,7 +201,7 @@ public:
         }
 
 #if !WTF_CPU_X86_64
-        explicit TrustedImm32(TrustedImmPtr ptr)
+        explicit Imm32(ImmPtr ptr)
             : m_value(ptr.asIntptr())
 #if WTF_CPU_ARM || WTF_CPU_MIPS
             , m_isPointer(true)
@@ -230,20 +223,6 @@ public:
 #endif
     };
 
-
-    struct Imm32 : public TrustedImm32 {
-        explicit Imm32(int32_t value)
-            : TrustedImm32(value)
-        {
-        }
-#if !WTF_CPU_X86_64
-        explicit Imm32(TrustedImmPtr ptr)
-            : TrustedImm32(ptr)
-        {
-        }
-#endif
-    };
-
     struct ImmDouble {
         union {
             struct {
@@ -262,6 +241,7 @@ public:
         }
     };
 
+
     // Section 2: MacroAssembler code buffer handles
     //
     // The following types are used to reference items in the code buffer
@@ -293,7 +273,7 @@ public:
         
         bool isUsed() const { return m_label.isUsed(); }
         void used() { m_label.used(); }
-        bool isSet() const { return m_label.isValid(); }
+        bool isValid() const { return m_label.isValid(); }
     private:
         JmpDst m_label;
     };
@@ -316,8 +296,6 @@ public:
         {
         }
         
-        bool isSet() const { return m_label.isValid(); }
-
     private:
         JmpDst m_label;
     };
@@ -433,20 +411,6 @@ public:
     public:
         typedef js::Vector JumpVector;
 
-        JumpList() {}
-
-        JumpList(const JumpList &other)
-        {
-            m_jumps.append(other.m_jumps);
-        }
-
-        JumpList &operator=(const JumpList &other)
-        {
-            m_jumps.clear();
-            m_jumps.append(other.m_jumps);
-            return *this;
-        }
-
         void link(AbstractMacroAssembler* masm)
         {
             size_t size = m_jumps.length();
@@ -468,22 +432,17 @@ public:
             m_jumps.append(jump);
         }
         
-        void append(const JumpList& other)
+        void append(JumpList& other)
         {
             m_jumps.append(other.m_jumps.begin(), other.m_jumps.length());
         }
 
-        void clear()
-        {
-            m_jumps.clear();
-        }
-
         bool empty()
         {
             return !m_jumps.length();
         }
         
-        const JumpVector& jumps() const { return m_jumps; }
+        const JumpVector& jumps() { return m_jumps; }
 
     private:
         JumpVector m_jumps;
diff --git a/js/src/assembler/assembler/MacroAssembler.h b/js/src/assembler/assembler/MacroAssembler.h
index 8a73863515c8..73bda22a8ee2 100644
--- a/js/src/assembler/assembler/MacroAssembler.h
+++ b/js/src/assembler/assembler/MacroAssembler.h
@@ -95,12 +95,12 @@ public:
         storePtr(src, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(TrustedImm32 value, int index = 0)
+    void poke(Imm32 value, int index = 0)
     {
         store32(value, Address(stackPointerRegister, (index * sizeof(void*))));
     }
 
-    void poke(TrustedImmPtr imm, int index = 0)
+    void poke(ImmPtr imm, int index = 0)
     {
         storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*))));
     }
@@ -117,7 +117,7 @@ public:
         branch32(cond, op1, op2).linkTo(target, this);
     }
 
-    void branch32(Condition cond, RegisterID op1, TrustedImm32 imm, Label target)
+    void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target)
     {
         branch32(cond, op1, imm).linkTo(target, this);
     }
@@ -177,11 +177,21 @@ public:
         and32(src, dest);
     }
 
+    void andPtr(Address address, RegisterID srcDest)
+    {
+        and32(address, srcDest);
+    }
+
     void andPtr(Imm32 imm, RegisterID srcDest)
     {
         and32(imm, srcDest);
     }
 
+    void andPtr(ImmPtr ptr, RegisterID srcDest)
+    {
+        and32(Imm32(ptr), srcDest);
+    }
+
     void notPtr(RegisterID srcDest)
     {
         not32(srcDest);
@@ -202,6 +212,11 @@ public:
         or32(imm, dest);
     }
 
+    void orPtr(Address address, RegisterID srcDest)
+    {
+        or32(address, srcDest);
+    }
+
     void subPtr(RegisterID src, RegisterID dest)
     {
         sub32(src, dest);
@@ -263,22 +278,27 @@ public:
         store32(src, address);
     }
 
+    void storePtr(RegisterID src, BaseIndex address)
+    {
+        store32(src, address);
+    }
+
     void storePtr(RegisterID src, void* address)
     {
         store32(src, address);
     }
 
-    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
+    void storePtr(ImmPtr imm, ImplicitAddress address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(TrustedImmPtr imm, BaseIndex address)
+    void storePtr(ImmPtr imm, BaseIndex address)
     {
         store32(Imm32(imm), address);
     }
 
-    void storePtr(TrustedImmPtr imm, void* address)
+    void storePtr(ImmPtr imm, void* address)
     {
         store32(Imm32(imm), address);
     }
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.cpp b/js/src/assembler/assembler/MacroAssemblerARM.cpp
index 065c98197395..14b4166b7ea9 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.cpp
+++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp
@@ -34,7 +34,7 @@
 
 #include "MacroAssemblerARM.h"
 
-#if WTF_OS_LINUX || WTF_OS_ANDROID
+#if WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID
 #include 
 #include 
 #include 
diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h
index 2630bce7a909..7413411f4500 100644
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -91,14 +91,14 @@ public:
         m_assembler.adds_r(dest, dest, src);
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         add32(imm, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -173,7 +173,7 @@ public:
         m_assembler.orrs_r(dest, dest, src);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -211,12 +211,12 @@ public:
         m_assembler.subs_r(dest, dest, src);
     }
 
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
 
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         load32(address, ARMRegisters::S1);
         sub32(imm, ARMRegisters::S1);
@@ -240,7 +240,7 @@ public:
         m_assembler.eors_r(dest, dest, src);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -380,7 +380,7 @@ public:
         m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset);
     }
 
-    void store32(TrustedImm32 imm, BaseIndex address)
+    void store32(Imm32 imm, BaseIndex address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -389,7 +389,7 @@ public:
         store32(ARMRegisters::S1, address);
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
@@ -404,7 +404,7 @@ public:
         m_assembler.dtr_u(false, src, ARMRegisters::S0, 0);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address));
         if (imm.m_isPointer)
@@ -436,7 +436,7 @@ public:
         push(ARMRegisters::S0);
     }
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(dest, imm.m_value);
@@ -449,7 +449,7 @@ public:
         m_assembler.mov_r(dest, src);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -485,7 +485,7 @@ public:
         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0)
     {
         ASSERT(left != ARMRegisters::S0);
         if (right.m_isPointer) {
@@ -500,21 +500,21 @@ public:
     // number of instructions emitted is constant, regardless of the argument
     // values. For ARM, this is identical to branch32WithPatch, except that it
     // does not generate a DataLabel32.
-    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
     // As branch32_force32, but allow the value ('right') to be patched.
-    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left != ARMRegisters::S1);
         dataLabel = moveWithPatch(right, ARMRegisters::S1);
         return branch32(cond, left, ARMRegisters::S1, true);
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
     {
         ASSERT(left.base != ARMRegisters::S1);
         load32(left, ARMRegisters::S1);
@@ -534,19 +534,19 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -828,7 +828,7 @@ public:
         setTest32(cond, address, mask, dest);
     }
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
     }
@@ -850,7 +850,7 @@ public:
         move(ARMRegisters::S1, dest);
     }
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -859,7 +859,7 @@ public:
         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr));
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
@@ -880,7 +880,7 @@ public:
         return branch32(cond, ARMRegisters::S1, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         load32(left.m_ptr, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -908,14 +908,14 @@ public:
         return Call::fromTailJump(oldJump);
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         DataLabelPtr dataLabel(this);
         m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value));
         return dataLabel;
     }
 
-    DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
+    DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
     {
         DataLabel32 dataLabel(this);
         m_assembler.ldr_un_imm(dest, initialValue.m_value);
@@ -937,7 +937,7 @@ public:
         return jump;
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
         store32(ARMRegisters::S1, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h
index 2bdb6e8fdb5e..5492f8246a06 100644
--- a/js/src/assembler/assembler/MacroAssemblerARMv7.h
+++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h
@@ -52,7 +52,7 @@ class MacroAssemblerARMv7 : public AbstractMacroAssembler {
     struct ArmAddress {
         enum AddressType {
             HasOffset,
-            HasIndex
+            HasIndex,
         } type;
         RegisterID base;
         union {
@@ -113,7 +113,7 @@ public:
         DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
         DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
         DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
-        DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE
+        DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
     };
 
     static const RegisterID stackPointerRegister = ARMRegisters::sp;
@@ -131,12 +131,12 @@ public:
         m_assembler.add(dest, dest, src);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         add32(imm, dest, dest);
     }
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -147,7 +147,7 @@ public:
         }
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -170,7 +170,7 @@ public:
         add32(dataTempRegister, dest);
     }
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -239,7 +239,7 @@ public:
         m_assembler.orr(dest, dest, src);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -285,7 +285,7 @@ public:
         m_assembler.sub(dest, dest, src);
     }
 
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -296,7 +296,7 @@ public:
         }
     }
 
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         load32(address, dataTempRegister);
 
@@ -319,7 +319,7 @@ public:
         sub32(dataTempRegister, dest);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         load32(address.m_ptr, dataTempRegister);
 
@@ -341,7 +341,7 @@ public:
         m_assembler.eor(dest, dest, src);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
         if (armImm.isValid())
@@ -486,7 +486,7 @@ public:
         store32(src, setupArmAddress(address));
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, setupArmAddress(address));
@@ -498,7 +498,7 @@ public:
         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         move(imm, dataTempRegister);
         store32(dataTempRegister, address);
@@ -667,7 +667,7 @@ public:
     //
     // Move values in registers.
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         uint32_t value = imm.m_value;
 
@@ -693,7 +693,7 @@ public:
         m_assembler.mov(dest, src);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         move(Imm32(imm), dest);
     }
@@ -780,7 +780,7 @@ public:
         return Jump(makeBranch(cond));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right)
     {
         compare32(left, right);
         return Jump(makeBranch(cond));
@@ -798,21 +798,21 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left, addressTempRegister);
         return branch32(cond, addressTempRegister, right);
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32WithUnalignedHalfWords(left, addressTempRegister);
@@ -825,7 +825,7 @@ public:
         return branch32(cond, dataTempRegister, right);
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
         load32(left.m_ptr, addressTempRegister);
@@ -1065,13 +1065,13 @@ public:
         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
     }
 
-    DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
+    DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst)
     {
         moveFixedWidthEncoding(imm, dst);
         return DataLabel32(this);
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
+    DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst)
     {
         moveFixedWidthEncoding(Imm32(imm), dst);
         return DataLabelPtr(this);
@@ -1090,7 +1090,7 @@ public:
         return branch32(cond, addressTempRegister, dataTempRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
         store32(dataTempRegister, address);
@@ -1179,7 +1179,7 @@ protected:
         return addressTempRegister;
     }
 
-    void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
+    void moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
     {
         uint32_t value = imm.m_value;
         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
diff --git a/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
index 6acdfd67a74d..841fa9647128 100644
--- a/js/src/assembler/assembler/MacroAssemblerCodeRef.h
+++ b/js/src/assembler/assembler/MacroAssemblerCodeRef.h
@@ -180,8 +180,7 @@ private:
 class MacroAssemblerCodeRef {
 public:
     MacroAssemblerCodeRef()
-        : m_executablePool(NULL),
-          m_size(0)
+        : m_size(0)
     {
     }
 
@@ -192,20 +191,6 @@ public:
     {
     }
 
-    // Release the code memory in this code ref.
-    void release()
-    {
-        if (!m_executablePool)
-            return;
-
-#if defined DEBUG && (defined WTF_CPU_X86 || defined WTF_CPU_X86_64) 
-        void *addr = m_code.executableAddress();
-        memset(addr, 0xcc, m_size);
-#endif
-        m_executablePool->release();
-        m_executablePool = NULL;
-    }
-
     MacroAssemblerCodePtr m_code;
     ExecutablePool* m_executablePool;
     size_t m_size;
diff --git a/js/src/assembler/assembler/MacroAssemblerSparc.h b/js/src/assembler/assembler/MacroAssemblerSparc.h
index 91a8f0e16163..3bdd2d871b1b 100644
--- a/js/src/assembler/assembler/MacroAssemblerSparc.h
+++ b/js/src/assembler/assembler/MacroAssemblerSparc.h
@@ -97,14 +97,14 @@ namespace JSC {
             m_assembler.addcc_r(dest, src, dest);
         }
 
-        void add32(TrustedImm32 imm, Address address)
+        void add32(Imm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             add32(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
         }
 
-        void add32(TrustedImm32 imm, RegisterID dest)
+        void add32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(dest, imm.m_value, dest);
@@ -126,7 +126,7 @@ namespace JSC {
             m_assembler.andcc_r(dest, SparcRegisters::g2, dest);
         }
 
-        void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+        void add32(Imm32 imm, RegisterID src, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.addcc_imm(src, imm.m_value, dest);
@@ -194,7 +194,7 @@ namespace JSC {
             m_assembler.orcc_r(dest, src, dest);
         }
 
-        void or32(TrustedImm32 imm, RegisterID dest)
+        void or32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.orcc_imm(dest, imm.m_value, dest);
@@ -240,7 +240,7 @@ namespace JSC {
             m_assembler.subcc_r(dest, src, dest);
         }
 
-        void sub32(TrustedImm32 imm, RegisterID dest)
+        void sub32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.subcc_imm(dest, imm.m_value, dest);
@@ -250,7 +250,7 @@ namespace JSC {
             }
         }
 
-        void sub32(TrustedImm32 imm, Address address)
+        void sub32(Imm32 imm, Address address)
         {
             load32(address, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -268,7 +268,7 @@ namespace JSC {
             m_assembler.xorcc_r(src, dest, dest);
         }
 
-        void xor32(TrustedImm32 imm, RegisterID dest)
+        void xor32(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.xorcc_imm(dest, imm.m_value, dest);
@@ -548,7 +548,7 @@ namespace JSC {
             m_assembler.stw_r(src, address.base, SparcRegisters::g2);
         }
 
-        void store32(TrustedImm32 imm, BaseIndex address)
+        void store32(Imm32 imm, BaseIndex address)
         {
             m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
             add32(Imm32(address.offset), SparcRegisters::g2);
@@ -556,7 +556,7 @@ namespace JSC {
             m_assembler.stw_r(SparcRegisters::g3, SparcRegisters::g2, address.base);
         }
 
-        void store32(TrustedImm32 imm, ImplicitAddress address)
+        void store32(Imm32 imm, ImplicitAddress address)
         {
             m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -568,7 +568,7 @@ namespace JSC {
             m_assembler.stw_r(src, SparcRegisters::g0, SparcRegisters::g3);
         }
 
-        void store32(TrustedImm32 imm, void* address)
+        void store32(Imm32 imm, void* address)
         {
             move(imm, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
@@ -598,7 +598,7 @@ namespace JSC {
             push(SparcRegisters::g2);
         }
 
-        void move(TrustedImm32 imm, RegisterID dest)
+        void move(Imm32 imm, RegisterID dest)
         {
             if (m_assembler.isimm13(imm.m_value))
                 m_assembler.or_imm(SparcRegisters::g0, imm.m_value, dest);
@@ -611,7 +611,7 @@ namespace JSC {
             m_assembler.or_r(src, SparcRegisters::g0, dest);
         }
 
-        void move(TrustedImmPtr imm, RegisterID dest)
+        void move(ImmPtr imm, RegisterID dest)
         {
             move(Imm32(imm), dest);
         }
@@ -641,20 +641,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32_force32(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32_force32(Condition cond, RegisterID left, Imm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
             m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
         {
             m_assembler.move_nocheck(right.m_value, SparcRegisters::g2);
             return branch32(cond, left, SparcRegisters::g2);
         }
 
-        Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+        Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
         {
             // Always use move_nocheck, since the value is to be patched.
             dataLabel = DataLabel32(this);
@@ -669,7 +669,7 @@ namespace JSC {
             return Jump(m_assembler.branch(SparcCondition(cond)));
         }
 
-        Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+        Jump branch32(Condition cond, RegisterID left, Imm32 right)
         {
             if (m_assembler.isimm13(right.m_value))
                 m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0);
@@ -692,20 +692,20 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, Address left, TrustedImm32 right)
+        Jump branch32(Condition cond, Address left, Imm32 right)
         {
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+        Jump branch32(Condition cond, BaseIndex left, Imm32 right)
         {
 
             load32(left, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+        Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
         {
             load32WithUnalignedHalfWords(left, SparcRegisters::g4);
             return branch32(cond, SparcRegisters::g4, right);
@@ -1052,7 +1052,7 @@ namespace JSC {
             store32(SparcRegisters::g2, address.m_ptr);
         }
 
-        void sub32(TrustedImm32 imm, AbsoluteAddress address)
+        void sub32(Imm32 imm, AbsoluteAddress address)
         {
             load32(address.m_ptr, SparcRegisters::g2);
             sub32(imm, SparcRegisters::g2);
@@ -1071,7 +1071,7 @@ namespace JSC {
             return branch32(cond, SparcRegisters::g2, right);
         }
 
-        Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+        Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
         {
             load32(left.m_ptr, SparcRegisters::g2);
             return branch32(cond, SparcRegisters::g2, right);
@@ -1099,7 +1099,7 @@ namespace JSC {
             return Call::fromTailJump(oldJump);
         }
 
-        DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+        DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
         {
             DataLabelPtr dataLabel(this);
             Imm32 imm = Imm32(initialValue);
@@ -1107,7 +1107,7 @@ namespace JSC {
             return dataLabel;
         }
 
-        DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
+        DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest)
         {
             DataLabel32 dataLabel(this);
             m_assembler.move_nocheck(initialValue.m_value, dest);
@@ -1129,7 +1129,7 @@ namespace JSC {
             return jump;
         }
 
-        DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+        DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
         {
             DataLabelPtr dataLabel = moveWithPatch(initialValue, SparcRegisters::g2);
             store32(SparcRegisters::g2, address);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86.h b/js/src/assembler/assembler/MacroAssemblerX86.h
index c6ab40f587fa..ee61b895a8fe 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+    void add32(Imm32 imm, RegisterID src, RegisterID dest)
     {
         m_assembler.leal_mr(imm.m_value, src, dest);
     }
@@ -90,12 +90,12 @@ public:
         m_assembler.andl_im(imm.m_value, address.m_ptr);
     }
     
-    void or32(TrustedImm32 imm, AbsoluteAddress address)
+    void or32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.orl_im(imm.m_value, address.m_ptr);
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         m_assembler.subl_im(imm.m_value, address.m_ptr);
     }
@@ -148,7 +148,7 @@ public:
         addDouble(Address(srcDest), dest);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         m_assembler.movl_i32m(imm.m_value, address);
     }
@@ -164,7 +164,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
+    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.m_ptr);
         return Jump(m_assembler.jCC(x86Condition(cond)));
@@ -186,7 +186,7 @@ public:
     }
 
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movl_i32r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -206,7 +206,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base);
         return DataLabelPtr(this);
diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h
index fa1b7ba8cb10..1ead9665f4e2 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86Common.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h
@@ -116,12 +116,12 @@ public:
         m_assembler.addl_rr(src, dest);
     }
 
-    void add32(TrustedImm32 imm, Address address)
+    void add32(Imm32 imm, Address address)
     {
         m_assembler.addl_im(imm.m_value, address.offset, address.base);
     }
 
-    void add32(TrustedImm32 imm, RegisterID dest)
+    void add32(Imm32 imm, RegisterID dest)
     {
         m_assembler.addl_ir(imm.m_value, dest);
     }
@@ -234,7 +234,7 @@ public:
         m_assembler.orl_rr(src, dest);
     }
 
-    void or32(TrustedImm32 imm, RegisterID dest)
+    void or32(Imm32 imm, RegisterID dest)
     {
         m_assembler.orl_ir(imm.m_value, dest);
     }
@@ -249,7 +249,7 @@ public:
         m_assembler.orl_mr(src.offset, src.base, dest);
     }
 
-    void or32(TrustedImm32 imm, Address address)
+    void or32(Imm32 imm, Address address)
     {
         m_assembler.orl_im(imm.m_value, address.offset, address.base);
     }
@@ -313,12 +313,12 @@ public:
         m_assembler.subl_rr(src, dest);
     }
     
-    void sub32(TrustedImm32 imm, RegisterID dest)
+    void sub32(Imm32 imm, RegisterID dest)
     {
         m_assembler.subl_ir(imm.m_value, dest);
     }
     
-    void sub32(TrustedImm32 imm, Address address)
+    void sub32(Imm32 imm, Address address)
     {
         m_assembler.subl_im(imm.m_value, address.offset, address.base);
     }
@@ -339,12 +339,12 @@ public:
         m_assembler.xorl_rr(src, dest);
     }
 
-    void xor32(TrustedImm32 imm, Address dest)
+    void xor32(Imm32 imm, Address dest)
     {
         m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
     }
 
-    void xor32(TrustedImm32 imm, RegisterID dest)
+    void xor32(Imm32 imm, RegisterID dest)
     {
         m_assembler.xorl_ir(imm.m_value, dest);
     }
@@ -468,7 +468,7 @@ public:
         m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(TrustedImm32 imm, BaseIndex address)
+    void store32(Imm32 imm, BaseIndex address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
@@ -483,7 +483,7 @@ public:
         m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
 
-    void store32(TrustedImm32 imm, ImplicitAddress address)
+    void store32(Imm32 imm, ImplicitAddress address)
     {
         m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
     }
@@ -748,7 +748,7 @@ public:
     //
     // Move values in registers.
 
-    void move(TrustedImm32 imm, RegisterID dest)
+    void move(Imm32 imm, RegisterID dest)
     {
         // Note: on 64-bit the Imm32 value is zero extended into the register, it
         // may be useful to have a separate version that sign extends the value?
@@ -767,7 +767,7 @@ public:
             m_assembler.movq_rr(src, dest);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         m_assembler.movq_i64r(imm.asIntptr(), dest);
     }
@@ -798,7 +798,7 @@ public:
             m_assembler.movl_rr(src, dest);
     }
 
-    void move(TrustedImmPtr imm, RegisterID dest)
+    void move(ImmPtr imm, RegisterID dest)
     {
         m_assembler.movl_i32r(imm.asIntptr(), dest);
     }
@@ -852,7 +852,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32(Condition cond, RegisterID left, Imm32 right)
     {
         if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
             m_assembler.testl_rr(left, left);
@@ -864,14 +864,14 @@ public:
     // Branch based on a 32-bit comparison, forcing the size of the
     // immediate operand to 32 bits in the native code stream to ensure that
     // the length of code emitted by this instruction is consistent.
-    Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
+    Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right)
     {
         m_assembler.cmpl_ir_force32(right.m_value, left);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
     // Branch and record a label after the comparison.
-    Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel)
     {
         // Always use cmpl, since the value is to be patched.
         m_assembler.cmpl_ir_force32(right.m_value, left);
@@ -879,7 +879,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithPatch(Condition cond, Address left, TrustedImm32 right, DataLabel32 &dataLabel)
+    Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel)
     {
         m_assembler.cmpl_im_force32(right.m_value, left.offset, left.base);
         dataLabel = DataLabel32(this);
@@ -898,19 +898,19 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, Address left, TrustedImm32 right)
+    Jump branch32(Condition cond, Address left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
     {
         m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
+    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
     {
         return branch32(cond, left, right);
     }
@@ -1369,7 +1369,7 @@ private:
     }
 
 #if WTF_CPU_X86
-#if WTF_OS_MAC_OS_X
+#if WTF_PLATFORM_MAC
 
     // All X86 Macs are guaranteed to support at least SSE2
     static bool isSSEPresent()
@@ -1382,7 +1382,7 @@ private:
         return true;
     }
 
-#else // OS(MAC_OS_X)
+#else // PLATFORM(MAC)
 
     static bool isSSEPresent()
     {
diff --git a/js/src/assembler/assembler/MacroAssemblerX86_64.h b/js/src/assembler/assembler/MacroAssemblerX86_64.h
index a5038a930e56..7dadc6bcaf2e 100644
--- a/js/src/assembler/assembler/MacroAssemblerX86_64.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h
@@ -60,7 +60,7 @@ public:
     using MacroAssemblerX86Common::storeDouble;
     using MacroAssemblerX86Common::convertInt32ToDouble;
 
-    void add32(TrustedImm32 imm, AbsoluteAddress address)
+    void add32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         add32(imm, Address(scratchRegister));
@@ -72,13 +72,13 @@ public:
         and32(imm, Address(scratchRegister));
     }
     
-    void or32(TrustedImm32 imm, AbsoluteAddress address)
+    void or32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         or32(imm, Address(scratchRegister));
     }
 
-    void sub32(TrustedImm32 imm, AbsoluteAddress address)
+    void sub32(Imm32 imm, AbsoluteAddress address)
     {
         move(ImmPtr(address.m_ptr), scratchRegister);
         sub32(imm, Address(scratchRegister));
@@ -114,7 +114,7 @@ public:
         m_assembler.cvtsq2sd_rr(srcDest, dest);
     }
 
-    void store32(TrustedImm32 imm, void* address)
+    void store32(Imm32 imm, void* address)
     {
         move(X86Registers::eax, scratchRegister);
         move(imm, X86Registers::eax);
@@ -311,7 +311,7 @@ public:
         m_assembler.movq_rm(src, address.offset, address.base);
     }
 
-    void storePtr(TrustedImmPtr imm, BaseIndex address)
+    void storePtr(ImmPtr imm, BaseIndex address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -341,7 +341,7 @@ public:
         }
     }
 
-    void storePtr(TrustedImmPtr imm, ImplicitAddress address)
+    void storePtr(ImmPtr imm, ImplicitAddress address)
     {
         intptr_t value = intptr_t(imm.m_value);
 
@@ -487,7 +487,7 @@ public:
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
-    DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
+    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
     {
         m_assembler.movq_i64r(initialValue.asIntptr(), dest);
         return DataLabelPtr(this);
@@ -505,7 +505,7 @@ public:
         return branchPtr(cond, left, scratchRegister);
     }
 
-    DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
+    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
     {
         DataLabelPtr label = moveWithPatch(initialValue, scratchRegister);
         storePtr(scratchRegister, address);
diff --git a/js/src/assembler/jit/ExecutableAllocator.h b/js/src/assembler/jit/ExecutableAllocator.h
index 9cca26f48c99..a54a4dab143b 100644
--- a/js/src/assembler/jit/ExecutableAllocator.h
+++ b/js/src/assembler/jit/ExecutableAllocator.h
@@ -52,16 +52,16 @@ extern  "C" void sync_instruction_memory(caddr_t v, u_int len);
 #endif
 #endif
 
-#if WTF_OS_IOS
+#if WTF_PLATFORM_IPHONE
 #include 
 #include 
 #endif
 
-#if WTF_OS_SYMBIAN
+#if WTF_PLATFORM_SYMBIAN
 #include 
 #endif
 
-#if WTF_CPU_MIPS && WTF_OS_LINUX
+#if WTF_CPU_MIPS && WTF_PLATFORM_LINUX
 #include 
 #endif
 
@@ -90,7 +90,7 @@ private:
     struct Allocation {
         char* pages;
         size_t size;
-#if WTF_OS_SYMBIAN
+#if WTF_PLATFORM_SYMBIAN
         RChunk* chunk;
 #endif
     };
@@ -269,7 +269,6 @@ private:
         return pool;
     }
 
-public:
     ExecutablePool* poolForSize(size_t n)
     {
 #ifndef DEBUG_STRESS_JSC_ALLOCATOR
@@ -328,6 +327,7 @@ public:
         return pool;
     }
 
+public:
 #if ENABLE_ASSEMBLER_WX_EXCLUSIVE
     static void makeWritable(void* start, size_t size)
     {
@@ -374,13 +374,13 @@ public:
         _flush_cache(reinterpret_cast(code), size, BCACHE);
 #endif
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_OS_IOS
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
     static void cacheFlush(void* code, size_t size)
     {
         sys_dcache_flush(code, size);
         sys_icache_invalidate(code, size);
     }
-#elif WTF_CPU_ARM_THUMB2 && WTF_IOS
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_LINUX
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
@@ -396,14 +396,14 @@ public:
             : "r" (code), "r" (reinterpret_cast(code) + size)
             : "r0", "r1", "r2");
     }
-#elif WTF_OS_SYMBIAN
+#elif WTF_PLATFORM_SYMBIAN
     static void cacheFlush(void* code, size_t size)
     {
         User::IMB_Range(code, static_cast(code) + size);
     }
-#elif WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
     static __asm void cacheFlush(void* code, size_t size);
-#elif WTF_CPU_ARM_TRADITIONAL && (WTF_OS_LINUX || WTF_OS_ANDROID) && WTF_COMPILER_GCC
+#elif WTF_CPU_ARM_TRADITIONAL && (WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID) && WTF_COMPILER_GCC
     static void cacheFlush(void* code, size_t size)
     {
         asm volatile (
diff --git a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
index 675b604ae914..ef9e27d92b47 100644
--- a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_OS2
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_OS2
 
 #define INCL_DOS
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
index e334626ccc2f..50efd932e02a 100644
--- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp
@@ -25,7 +25,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
 
 #include 
 #include 
@@ -74,7 +74,7 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe
 }
 #endif
 
-#if WTF_CPU_ARM_TRADITIONAL && WTF_OS_LINUX && WTF_COMPILER_RVCT
+#if WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT
 __asm void ExecutableAllocator::cacheFlush(void* code, size_t size)
 {
     ARM
diff --git a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
index f51c0d507877..c66fa80fff12 100644
--- a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp
@@ -22,7 +22,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_SYMBIAN
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_SYMBIAN
 
 #include 
 #include 
diff --git a/js/src/assembler/jit/ExecutableAllocatorWin.cpp b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
index da6e756cfa66..f5775608f36f 100644
--- a/js/src/assembler/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp
@@ -26,7 +26,7 @@
 
 #include "ExecutableAllocator.h"
 
-#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
+#if ENABLE_ASSEMBLER && WTF_PLATFORM_WIN_OS
 
 #include "jswin.h"
 
diff --git a/js/src/assembler/wtf/Platform.h b/js/src/assembler/wtf/Platform.h
index 217c9b8a1eec..68713cd4c810 100644
--- a/js/src/assembler/wtf/Platform.h
+++ b/js/src/assembler/wtf/Platform.h
@@ -1,7 +1,6 @@
 /*
  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc.  All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,267 +27,206 @@
 #ifndef WTF_Platform_h
 #define WTF_Platform_h
 
+/* Either XX(YY) --> WTF_XX_YY  or  XX(YY) --> XX_YY, depending on XX
+
+   PLATFORM(YY) --> WTF_PLATFORM_YY
+   COMPILER(YY) --> WTF_COMPILER_YY
+   CPU(YY)      --> WTF_CPU_YY
+   OS(YY)       --> WTF_OS_YY
+   USE(YY)      --> WTF_USE_YY
+
+   HAVE(YY)     --> HAVE_YY
+   ENABLE(YY)   --> ENABLE_YY
+*/
+
 /* ==== PLATFORM handles OS, operating environment, graphics API, and
    CPU. This macro will be phased out in favor of platform adaptation
    macros, policy decision macros, and top-level port definitions. ==== */
-#define PLATFORM(WTF_FEATURE) (defined WTF_PLATFORM_##WTF_FEATURE  && WTF_PLATFORM_##WTF_FEATURE)
+//#define PLATFORM(WTF_FEATURE) (defined(WTF_PLATFORM_##WTF_FEATURE)  && WTF_PLATFORM_##WTF_FEATURE)
 
 
 /* ==== Platform adaptation macros: these describe properties of the target environment. ==== */
 
 /* COMPILER() - the compiler being used to build the project */
-#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE  && WTF_COMPILER_##WTF_FEATURE)
+//#define COMPILER(WTF_FEATURE) (defined(WTF_COMPILER_##WTF_FEATURE)  && WTF_COMPILER_##WTF_FEATURE)
 /* CPU() - the target CPU architecture */
-#define CPU(WTF_FEATURE) (defined WTF_CPU_##WTF_FEATURE  && WTF_CPU_##WTF_FEATURE)
+//#define CPU(WTF_FEATURE) (defined(WTF_CPU_##WTF_FEATURE)  && WTF_CPU_##WTF_FEATURE)
 /* HAVE() - specific system features (headers, functions or similar) that are present or not */
-#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE  && HAVE_##WTF_FEATURE)
+//#define HAVE(WTF_FEATURE) (defined(HAVE_##WTF_FEATURE)  && HAVE_##WTF_FEATURE)
 /* OS() - underlying operating system; only to be used for mandated low-level services like 
    virtual memory, not to choose a GUI toolkit */
-#define OS(WTF_FEATURE) (defined WTF_OS_##WTF_FEATURE  && WTF_OS_##WTF_FEATURE)
+//#define OS(WTF_FEATURE) (defined(WTF_OS_##WTF_FEATURE)  && WTF_OS_##WTF_FEATURE)
 
 
 /* ==== Policy decision macros: these define policy choices for a particular port. ==== */
 
 /* USE() - use a particular third-party library or optional OS service */
-#define USE(WTF_FEATURE) (defined WTF_USE_##WTF_FEATURE  && WTF_USE_##WTF_FEATURE)
+//#define USE(WTF_FEATURE) (defined(WTF_USE_##WTF_FEATURE)  && WTF_USE_##WTF_FEATURE)
 /* ENABLE() - turn on a specific feature of WebKit */
-#define ENABLE(WTF_FEATURE) (defined ENABLE_##WTF_FEATURE  && ENABLE_##WTF_FEATURE)
+//#define ENABLE(WTF_FEATURE) (defined(ENABLE_##WTF_FEATURE)  && ENABLE_##WTF_FEATURE)
 
 
 
 /* ==== COMPILER() - the compiler being used to build the project ==== */
 
-/* WTF_COMPILER_MSVC Microsoft Visual C++ */
-/* WTF_COMPILER_MSVC7_OR_LOWER Microsoft Visual C++ 2003 or lower*/
-/* WTF_COMPILER_MSVC9_OR_LOWER Microsoft Visual C++ 2008 or lower*/
+/* COMPILER(MSVC) Microsoft Visual C++ */
+/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/
 #if defined(_MSC_VER)
 #define WTF_COMPILER_MSVC 1
 #if _MSC_VER < 1400
-#define WTF_COMPILER_MSVC7_OR_LOWER 1
-#elif _MSC_VER < 1600
-#define WTF_COMPILER_MSVC9_OR_LOWER 1
+#define WTF_COMPILER_MSVC7 1
 #endif
 #endif
 
-/* WTF_COMPILER_RVCT  - ARM RealView Compilation Tools */
-/* WTF_COMPILER_RVCT4_OR_GREATER - ARM RealView Compilation Tools 4.0 or greater */
+/* COMPILER(RVCT)  - ARM RealView Compilation Tools */
 #if defined(__CC_ARM) || defined(__ARMCC__)
 #define WTF_COMPILER_RVCT 1
-#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) (__ARMCC_VERSION >= (major * 100000 + minor * 10000 + patch * 1000 + build))
-#else
-/* Define this for !RVCT compilers, just so we can write things like RVCT_VERSION_AT_LEAST(3, 0, 0, 0). */
-#define RVCT_VERSION_AT_LEAST(major, minor, patch, build) 0
 #endif
 
-/* WTF_COMPILER_GCC - GNU Compiler Collection */
+/* COMPILER(GCC) - GNU Compiler Collection */
 /* --gnu option of the RVCT compiler also defines __GNUC__ */
 #if defined(__GNUC__) && !WTF_COMPILER_RVCT
 #define WTF_COMPILER_GCC 1
 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch))
-#else
-/* Define this for !GCC compilers, just so we can write things like GCC_VERSION_AT_LEAST(4, 1, 0). */
-#define GCC_VERSION_AT_LEAST(major, minor, patch) 0
 #endif
 
-/* WTF_COMPILER_MINGW - MinGW GCC */
-/* WTF_COMPILER_MINGW64 - mingw-w64 GCC - only used as additional check to exclude mingw.org specific functions */
-#if defined(__MINGW32__)
+/* COMPILER(MINGW) - MinGW GCC */
+#if defined(MINGW) || defined(__MINGW32__)
 #define WTF_COMPILER_MINGW 1
-#include <_mingw.h> /* private MinGW header */
-    #if defined(__MINGW64_VERSION_MAJOR) /* best way to check for mingw-w64 vs mingw.org */
-        #define WTF_COMPILER_MINGW64 1
-    #endif /* __MINGW64_VERSION_MAJOR */
-#endif /* __MINGW32__ */
+#endif
 
-/* WTF_COMPILER_WINSCW - CodeWarrior for Symbian emulator */
+/* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */
 #if defined(__WINSCW__)
 #define WTF_COMPILER_WINSCW 1
-/* cross-compiling, it is not really windows */
-#undef WIN32
-#undef _WIN32
 #endif
 
-/* WTF_COMPILER_INTEL - Intel C++ Compiler */
-#if defined(__INTEL_COMPILER)
-#define WTF_COMPILER_INTEL 1
+/* COMPILER(SUNPRO) - Sun Studio for Solaris */
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#define WTF_COMPILER_SUNPRO 1
 #endif
 
-/* WTF_COMPILER_SUNCC */
-#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
-#define WTF_COMPILER_SUNCC 1
-#endif
 
 /* ==== CPU() - the target CPU architecture ==== */
 
-/* This also defines WTF_CPU_BIG_ENDIAN or WTF_CPU_MIDDLE_ENDIAN or neither, as appropriate. */
+/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */
 
-/* WTF_CPU_ALPHA - DEC Alpha */
+
+/* CPU(ALPHA) - DEC Alpha */
 #if defined(__alpha__)
 #define WTF_CPU_ALPHA 1
 #endif
 
-/* WTF_CPU_IA64 - Itanium / IA-64 */
+/* CPU(IA64) - Itanium / IA-64 */
 #if defined(__ia64__)
 #define WTF_CPU_IA64 1
-/* 32-bit mode on Itanium */
-#if !defined(__LP64__)
-#define WTF_CPU_IA64_32 1
-#endif
 #endif
 
-/* WTF_CPU_MIPS - MIPS 32-bit */
-/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now.  */
-#if (defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_)) \
-    && defined(_ABIO32)
-#define WTF_CPU_MIPS 1
-#if defined(__MIPSEB__)
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-#define WTF_MIPS_PIC (defined __PIC__)
-#define WTF_MIPS_ARCH __mips
-#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v)
-#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v)
-#define WTF_MIPS_ARCH_REV __mips_isa_rev
-#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
-#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float)
-#define WTF_MIPS_FP64 (defined __mips_fpr && __mips_fpr == 64)
-/* MIPS requires allocators to use aligned memory */
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-#endif /* MIPS */
-
-/* WTF_CPU_PPC - PowerPC 32-bit */
+/* CPU(PPC) - PowerPC 32-bit */
 #if   defined(__ppc__)     \
-    || defined(__PPC__)     \
-    || defined(__powerpc__) \
-    || defined(__powerpc)   \
-    || defined(__POWERPC__) \
-    || defined(_M_PPC)      \
-    || defined(__PPC)
+   || defined(__PPC__)     \
+   || defined(__powerpc__) \
+   || defined(__powerpc)   \
+   || defined(__POWERPC__) \
+   || defined(_M_PPC)      \
+   || defined(__PPC)
 #define WTF_CPU_PPC 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_PPC64 - PowerPC 64-bit */
+/* CPU(PPC64) - PowerPC 64-bit */
 #if   defined(__ppc64__) \
-    || defined(__PPC64__)
+   || defined(__PPC64__)
 #define WTF_CPU_PPC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SH4 - SuperH SH-4 */
+/* CPU(SH4) - SuperH SH-4 */
 #if defined(__SH4__)
 #define WTF_CPU_SH4 1
 #endif
 
-/* WTF_CPU_SPARC32 - SPARC 32-bit */
+/* CPU(SPARC32) - SPARC 32-bit */
 #if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8)
 #define WTF_CPU_SPARC32 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SPARC64 - SPARC 64-bit */
+/* CPU(SPARC64) - SPARC 64-bit */
 #if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9)
 #define WTF_CPU_SPARC64 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
-/* WTF_CPU_SPARC - any SPARC, true for WTF_CPU_SPARC32 and WTF_CPU_SPARC64 */
+/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */
 #if WTF_CPU_SPARC32 || WTF_CPU_SPARC64
 #define WTF_CPU_SPARC 1
 #endif
 
-/* WTF_CPU_S390X - S390 64-bit */
-#if defined(__s390x__)
-#define WTF_CPU_S390X 1
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-
-/* WTF_CPU_S390 - S390 32-bit */
-#if defined(__s390__)
-#define WTF_CPU_S390 1
-#define WTF_CPU_BIG_ENDIAN 1
-#endif
-
-/* WTF_CPU_X86 - i386 / x86 32-bit */
+/* CPU(X86) - i386 / x86 32-bit */
 #if   defined(__i386__) \
-    || defined(i386)     \
-    || defined(_M_IX86)  \
-    || defined(_X86_)    \
-    || defined(__THW_INTEL)
+   || defined(i386)     \
+   || defined(_M_IX86)  \
+   || defined(_X86_)    \
+   || defined(__THW_INTEL)
 #define WTF_CPU_X86 1
 #endif
 
-/* WTF_CPU_X86_64 - AMD64 / Intel64 / x86_64 64-bit */
+/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */
 #if   defined(__x86_64__) \
-    || defined(_M_X64)
+   || defined(_M_X64)
 #define WTF_CPU_X86_64 1
 #endif
 
-/* WTF_CPU_ARM - ARM, any version*/
+/* CPU(ARM) - ARM, any version*/
 #if   defined(arm) \
-    || defined(__arm__) \
-    || defined(ARM) \
-    || defined(_ARM_)
+   || defined(__arm__)
 #define WTF_CPU_ARM 1
 
-#if defined(__ARMEB__) || (WTF_COMPILER_RVCT && defined(__BIG_ENDIAN))
+#if defined(__ARMEB__)
 #define WTF_CPU_BIG_ENDIAN 1
 
 #elif !defined(__ARM_EABI__) \
-    && !defined(__EABI__) \
-    && !defined(__VFP_FP__) \
-    && !defined(_WIN32_WCE) \
-    && !defined(ANDROID)
+   && !defined(__EABI__) \
+   && !defined(__VFP_FP__) \
+   && !defined(ANDROID)
 #define WTF_CPU_MIDDLE_ENDIAN 1
 
 #endif
 
-#define WTF_ARM_ARCH_AT_LEAST(N) (CPU(ARM) && WTF_ARM_ARCH_VERSION >= N)
+#define WTF_ARM_ARCH_AT_LEAST(N) (WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= N)
 
 /* Set WTF_ARM_ARCH_VERSION */
 #if   defined(__ARM_ARCH_4__) \
-    || defined(__ARM_ARCH_4T__) \
-    || defined(__MARM_ARMV4__) \
-    || defined(_ARMV4I_)
+   || defined(__ARM_ARCH_4T__) \
+   || defined(__MARM_ARMV4__) \
+   || defined(_ARMV4I_)
 #define WTF_ARM_ARCH_VERSION 4
 
 #elif defined(__ARM_ARCH_5__) \
-    || defined(__ARM_ARCH_5T__) \
-    || defined(__MARM_ARMV5__)
+   || defined(__ARM_ARCH_5T__) \
+   || defined(__ARM_ARCH_5E__) \
+   || defined(__ARM_ARCH_5TE__) \
+   || defined(__ARM_ARCH_5TEJ__) \
+   || defined(__MARM_ARMV5__)
 #define WTF_ARM_ARCH_VERSION 5
 
-#elif defined(__ARM_ARCH_5E__) \
-    || defined(__ARM_ARCH_5TE__) \
-    || defined(__ARM_ARCH_5TEJ__)
-#define WTF_ARM_ARCH_VERSION 5
-/*ARMv5TE requires allocators to use aligned memory*/
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-
 #elif defined(__ARM_ARCH_6__) \
-    || defined(__ARM_ARCH_6J__) \
-    || defined(__ARM_ARCH_6K__) \
-    || defined(__ARM_ARCH_6Z__) \
-    || defined(__ARM_ARCH_6ZK__) \
-    || defined(__ARM_ARCH_6T2__) \
-    || defined(__ARMV6__)
+   || defined(__ARM_ARCH_6J__) \
+   || defined(__ARM_ARCH_6K__) \
+   || defined(__ARM_ARCH_6Z__) \
+   || defined(__ARM_ARCH_6ZK__) \
+   || defined(__ARM_ARCH_6T2__) \
+   || defined(__ARMV6__)
 #define WTF_ARM_ARCH_VERSION 6
 
 #elif defined(__ARM_ARCH_7A__) \
-    || defined(__ARM_ARCH_7R__)
+   || defined(__ARM_ARCH_7R__)
 #define WTF_ARM_ARCH_VERSION 7
 
 /* RVCT sets _TARGET_ARCH_ARM */
 #elif defined(__TARGET_ARCH_ARM)
 #define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM
 
-#if defined(__TARGET_ARCH_5E) \
-    || defined(__TARGET_ARCH_5TE) \
-    || defined(__TARGET_ARCH_5TEJ)
-/*ARMv5TE requires allocators to use aligned memory*/
-#define WTF_USE_ARENA_ALLOC_ALIGNMENT_INTEGER 1
-#endif
-
 #else
 #define WTF_ARM_ARCH_VERSION 0
 
@@ -299,22 +237,22 @@
 #define WTF_THUMB_ARCH_VERSION 1
 
 #elif defined(__ARM_ARCH_5T__) \
-    || defined(__ARM_ARCH_5TE__) \
-    || defined(__ARM_ARCH_5TEJ__)
+   || defined(__ARM_ARCH_5TE__) \
+   || defined(__ARM_ARCH_5TEJ__)
 #define WTF_THUMB_ARCH_VERSION 2
 
 #elif defined(__ARM_ARCH_6J__) \
-    || defined(__ARM_ARCH_6K__) \
-    || defined(__ARM_ARCH_6Z__) \
-    || defined(__ARM_ARCH_6ZK__) \
-    || defined(__ARM_ARCH_6M__)
+   || defined(__ARM_ARCH_6K__) \
+   || defined(__ARM_ARCH_6Z__) \
+   || defined(__ARM_ARCH_6ZK__) \
+   || defined(__ARM_ARCH_6M__)
 #define WTF_THUMB_ARCH_VERSION 3
 
 #elif defined(__ARM_ARCH_6T2__) \
-    || defined(__ARM_ARCH_7__) \
-    || defined(__ARM_ARCH_7A__) \
-    || defined(__ARM_ARCH_7R__) \
-    || defined(__ARM_ARCH_7M__)
+   || defined(__ARM_ARCH_7__) \
+   || defined(__ARM_ARCH_7A__) \
+   || defined(__ARM_ARCH_7R__) \
+   || defined(__ARM_ARCH_7M__)
 #define WTF_THUMB_ARCH_VERSION 4
 
 /* RVCT sets __TARGET_ARCH_THUMB */
@@ -326,22 +264,22 @@
 #endif
 
 
-/* WTF_CPU_ARMV5_OR_LOWER - ARM instruction set v5 or earlier */
+/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */
 /* On ARMv5 and below the natural alignment is required. 
    And there are some other differences for v5 or earlier. */
-#if !defined(ARMV5_OR_LOWER) && !WTF_ARM_ARCH_AT_LEAST(6)
+#if !defined(ARMV5_OR_LOWER) /* && !CPU_ARM_ARCH_AT_LEAST(6) */
 #define WTF_CPU_ARMV5_OR_LOWER 1
 #endif
 
 
-/* WTF_CPU_ARM_TRADITIONAL - Thumb2 is not available, only traditional ARM (v4 or greater) */
-/* WTF_CPU_ARM_THUMB2 - Thumb2 instruction set is available */
+/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */
+/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */
 /* Only one of these will be defined. */
 #if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
 #  if defined(thumb2) || defined(__thumb2__) \
-    || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
-#    define WTF_CPU_ARM_TRADITIONAL 0
-#    define WTF_CPU_ARM_THUMB2 1
+  || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
+#    define WTF_CPU_ARM_TRADITIONAL 1
+#    define WTF_CPU_ARM_THUMB2 0
 #  elif WTF_ARM_ARCH_AT_LEAST(4)
 #    define WTF_CPU_ARM_TRADITIONAL 1
 #    define WTF_CPU_ARM_THUMB2 0
@@ -350,36 +288,19 @@
 #  endif
 #elif WTF_CPU_ARM_TRADITIONAL && WTF_CPU_ARM_THUMB2 /* Sanity Check */
 #  error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms"
-#endif /* !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) */
-
-#if defined(__ARM_NEON__) && !defined(WTF_CPU_ARM_NEON)
-#define WTF_CPU_ARM_NEON 1
-#endif
+#endif // !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
 
 #endif /* ARM */
 
-#if WTF_CPU_ARM || WTF_CPU_MIPS
-#define WTF_CPU_NEEDS_ALIGNED_ACCESS 1
-#endif
 
-/* ==== OS() - underlying operating system; only to be used for mandated low-level services like 
-   virtual memory, not to choose a GUI toolkit ==== */
 
-/* WTF_OS_ANDROID - Android */
-#ifdef ANDROID
-#define WTF_OS_ANDROID 1
-#endif
+/* Operating systems - low-level dependencies */
 
-/* WTF_OS_AIX - AIX */
-#ifdef _AIX
-#define WTF_OS_AIX 1
-#endif
-
-/* WTF_OS_DARWIN - Any Darwin-based OS, including Mac OS X and iPhone OS */
+/* PLATFORM(DARWIN) */
+/* Operating system level dependencies for Mac OS X / Darwin that should */
+/* be used regardless of operating environment */
 #ifdef __APPLE__
-#define WTF_OS_DARWIN 1
-
-/* FIXME: BUILDING_ON_.., and TARGETING... macros should be folded into the OS() system */
+#define WTF_PLATFORM_DARWIN 1
 #include 
 #if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
 #define BUILDING_ON_TIGER 1
@@ -396,97 +317,98 @@
 #define TARGETING_SNOW_LEOPARD 1
 #endif
 #include 
-
 #endif
 
-/* WTF_OS_IOS - iOS */
-/* WTF_OS_MAC_OS_X - Mac OS X (not including iOS) */
-#if WTF_OS_DARWIN && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED)  \
-    || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)                   \
-    || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR))
-#define WTF_OS_IOS 1
-#elif WTF_OS_DARWIN && defined(TARGET_OS_MAC) && TARGET_OS_MAC
-#define WTF_OS_MAC_OS_X 1
-#endif
-
-/* WTF_OS_FREEBSD - FreeBSD */
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#define WTF_OS_FREEBSD 1
-#endif
-
-/* WTF_OS_HAIKU - Haiku */
-#ifdef __HAIKU__
-#define WTF_OS_HAIKU 1
-#endif
-
-/* WTF_OS_LINUX - Linux */
-#ifdef __linux__
-#define WTF_OS_LINUX 1
-#endif
-
-/* WTF_OS_NETBSD - NetBSD */
-#if defined(__NetBSD__)
-#define WTF_OS_NETBSD 1
-#endif
-
-/* WTF_OS_OPENBSD - OpenBSD */
-#ifdef __OpenBSD__
-#define WTF_OS_OPENBSD 1
-#endif
-
-/* WTF_OS_QNX - QNX */
-#if defined(__QNXNTO__)
-#define WTF_OS_QNX 1
-#endif
-
-/* WTF_OS_SOLARIS - Solaris */
-#if defined(sun) || defined(__sun)
-#define WTF_OS_SOLARIS 1
-#endif
-
-/* WTF_OS_WINCE - Windows CE; note that for this platform WTF_OS_WINDOWS is also defined */
-#if defined(_WIN32_WCE)
-#define WTF_OS_WINCE 1
-#endif
-
-/* WTF_OS_WINDOWS - Any version of Windows */
+/* PLATFORM(WIN_OS) */
+/* Operating system level dependencies for Windows that should be used */
+/* regardless of operating environment */
 #if defined(WIN32) || defined(_WIN32)
-#define WTF_OS_WINDOWS 1
+#define WTF_PLATFORM_WIN_OS 1
+#endif
+
+/* PLATFORM(LINUX) */
+/* Operating system level dependencies for Linux-like systems that */
+/* should be used regardless of operating environment */
+#ifdef __linux__
+#define WTF_PLATFORM_LINUX 1
+#endif
+
+/* PLATFORM(FREEBSD) */
+/* Operating system level dependencies for FreeBSD-like systems that */
+/* should be used regardless of operating environment */
+#ifdef __FreeBSD__
+#define WTF_PLATFORM_FREEBSD 1
+#endif
+
+/* PLATFORM(OPENBSD) */
+/* Operating system level dependencies for OpenBSD systems that */
+/* should be used regardless of operating environment */
+#ifdef __OpenBSD__
+#define WTF_PLATFORM_OPENBSD 1
+#endif
+
+/* PLATFORM(SOLARIS) */
+/* Operating system level dependencies for Solaris that should be used */
+/* regardless of operating environment */
+#if defined(sun) || defined(__sun)
+#define WTF_PLATFORM_SOLARIS 1
+#endif
+
+/* PLATFORM(OS2) */
+/* Operating system level dependencies for OS/2 that should be used */
+/* regardless of operating environment */
+#if defined(OS2) || defined(__OS2__)
+#define WTF_PLATFORM_OS2 1
 #endif
 
-/* WTF_OS_SYMBIAN - Symbian */
 #if defined (__SYMBIAN32__)
-#define WTF_OS_SYMBIAN 1
+/* we are cross-compiling, it is not really windows */
+#undef WTF_PLATFORM_WIN_OS
+#undef WTF_PLATFORM_WIN
+#define WTF_PLATFORM_SYMBIAN 1
 #endif
 
-/* WTF_OS_UNIX - Any Unix-like system */
-#if   WTF_OS_AIX              \
-    || WTF_OS_ANDROID          \
-    || WTF_OS_DARWIN           \
-    || WTF_OS_FREEBSD          \
-    || WTF_OS_HAIKU            \
-    || WTF_OS_LINUX            \
-    || WTF_OS_NETBSD           \
-    || WTF_OS_OPENBSD          \
-    || WTF_OS_QNX              \
-    || WTF_OS_SOLARIS          \
-    || WTF_OS_SYMBIAN          \
-    || defined(unix)        \
-    || defined(__unix)      \
-    || defined(__unix__)
-#define WTF_OS_UNIX 1
+
+/* PLATFORM(NETBSD) */
+/* Operating system level dependencies for NetBSD that should be used */
+/* regardless of operating environment */
+#if defined(__NetBSD__)
+#define WTF_PLATFORM_NETBSD 1
+#endif
+
+/* PLATFORM(QNX) */
+/* Operating system level dependencies for QNX that should be used */
+/* regardless of operating environment */
+#if defined(__QNXNTO__)
+#define WTF_PLATFORM_QNX 1
+#endif
+
+/* PLATFORM(UNIX) */
+/* Operating system level dependencies for Unix-like systems that */
+/* should be used regardless of operating environment */
+#if   WTF_PLATFORM_DARWIN     \
+   || WTF_PLATFORM_FREEBSD    \
+   || WTF_PLATFORM_SYMBIAN    \
+   || WTF_PLATFORM_NETBSD     \
+   || defined(unix)        \
+   || defined(__unix)      \
+   || defined(__unix__)    \
+   || defined(_AIX)        \
+   || defined(__HAIKU__)   \
+   || defined(__QNXNTO__)  \
+   || defined(ANDROID)
+#define WTF_PLATFORM_UNIX 1
 #endif
 
 /* Operating environments */
 
-/* FIXME: these are all mixes of OS, operating environment and policy choices. */
-/* WTF_PLATFORM_CHROMIUM */
-/* WTF_PLATFORM_QT */
-/* WTF_PLATFORM_WX */
-/* WTF_PLATFORM_GTK */
-/* WTF_PLATFORM_HAIKU */
-/* WTF_PLATFORM_MAC */
-/* WTF_PLATFORM_WIN */
+/* PLATFORM(CHROMIUM) */
+/* PLATFORM(QT) */
+/* PLATFORM(WX) */
+/* PLATFORM(GTK) */
+/* PLATFORM(HAIKU) */
+/* PLATFORM(MAC) */
+/* PLATFORM(WIN) */
 #if defined(BUILDING_CHROMIUM__)
 #define WTF_PLATFORM_CHROMIUM 1
 #elif defined(BUILDING_QT__)
@@ -497,229 +419,142 @@
 #define WTF_PLATFORM_GTK 1
 #elif defined(BUILDING_HAIKU__)
 #define WTF_PLATFORM_HAIKU 1
-#elif defined(BUILDING_BREWMP__)
-#define WTF_PLATFORM_BREWMP 1
-#if defined(AEE_SIMULATOR)
-#define WTF_PLATFORM_BREWMP_SIMULATOR 1
-#else
-#define WTF_PLATFORM_BREWMP_SIMULATOR 0
-#endif
-#undef WTF_OS_WINDOWS
-#undef WTF_PLATFORM_WIN
-#elif WTF_OS_DARWIN
+#elif WTF_PLATFORM_DARWIN
 #define WTF_PLATFORM_MAC 1
-#elif WTF_OS_WINDOWS
+#elif WTF_PLATFORM_WIN_OS
 #define WTF_PLATFORM_WIN 1
 #endif
 
-/* WTF_PLATFORM_IOS */
-/* FIXME: this is sometimes used as an OS switch and sometimes for higher-level things */
+/* PLATFORM(IPHONE) */
 #if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
-#define WTF_PLATFORM_IOS 1
+#define WTF_PLATFORM_IPHONE 1
 #endif
 
-/* WTF_PLATFORM_IOS_SIMULATOR */
+/* PLATFORM(IPHONE_SIMULATOR) */
 #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
-#define WTF_PLATFORM_IOS 1
-#define WTF_PLATFORM_IOS_SIMULATOR 1
+#define WTF_PLATFORM_IPHONE 1
+#define WTF_PLATFORM_IPHONE_SIMULATOR 1
 #else
-#define WTF_PLATFORM_IOS_SIMULATOR 0
+#define WTF_PLATFORM_IPHONE_SIMULATOR 0
 #endif
 
-#if !defined(WTF_PLATFORM_IOS)
-#define WTF_PLATFORM_IOS 0
+#if !defined(WTF_PLATFORM_IPHONE)
+#define WTF_PLATFORM_IPHONE 0
 #endif
 
-/* WTF_PLATFORM_ANDROID */
-/* FIXME: this is sometimes used as an OS() switch, and other times to drive
-   policy choices */
+/* PLATFORM(ANDROID) */
 #if defined(ANDROID)
 #define WTF_PLATFORM_ANDROID 1
 #endif
 
 /* Graphics engines */
 
-/* WTF_USE_CG and WTF_PLATFORM_CI */
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS
-#define WTF_USE_CG 1
+/* PLATFORM(CG) and PLATFORM(CI) */
+#if WTF_PLATFORM_MAC || WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CG 1
 #endif
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_IOS || (WTF_PLATFORM_WIN && WTF_USE_CG)
-#define WTF_USE_CA 1
+#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CI 1
 #endif
 
-/* WTF_USE_SKIA for Win/Linux, CG for Mac */
+/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */
 #if WTF_PLATFORM_CHROMIUM
-#if WTF_OS_DARWIN
-#define WTF_USE_CG 1
+#if WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CG 1
+#define WTF_PLATFORM_CI 1
 #define WTF_USE_ATSUI 1
 #define WTF_USE_CORE_TEXT 1
-#define WTF_USE_ICCJPEG 1
 #else
-#define WTF_USE_SKIA 1
-#define WTF_USE_CHROMIUM_NET 1
+#define WTF_PLATFORM_SKIA 1
 #endif
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define WTF_USE_SKIA 1
-#endif
-
 #if WTF_PLATFORM_GTK
-#define WTF_USE_CAIRO 1
+#define WTF_PLATFORM_CAIRO 1
 #endif
 
 
-#if WTF_OS_WINCE
-#include 
-#define WTF_USE_MERSENNE_TWISTER_19937 1
-#endif
-
-#if WTF_PLATFORM_QT && WTF_OS_UNIX && !WTF_OS_SYMBIAN && !WTF_OS_DARWIN
-#define WTF_USE_PTHREAD_BASED_QT 1
-#endif
-
-#if (WTF_PLATFORM_GTK || WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || (WTF_PLATFORM_QT && (WTF_OS_DARWIN || WTF_USE_PTHREAD_BASED_QT) && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
+#if (WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_OS2 || (WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS)
 #define ENABLE_JSC_MULTIPLE_THREADS 1
 #endif
 
-#if ENABLE_JSC_MULTIPLE_THREADS
-#define ENABLE_WTF_MULTIPLE_THREADS 1
-#endif
-
 /* On Windows, use QueryPerformanceCounter by default */
-#if WTF_OS_WINDOWS
+#if WTF_PLATFORM_WIN_OS
 #define WTF_USE_QUERY_PERFORMANCE_COUNTER  1
 #endif
 
-#if WTF_OS_WINCE && !WTF_PLATFORM_QT
-#define NOMINMAX       /* Windows min and max conflict with standard macros */
-#define NOSHLWAPI      /* shlwapi.h not available on WinCe */
-
-/* MSDN documentation says these functions are provided with uspce.lib.  But we cannot find this file. */
-#define __usp10__      /* disable "usp10.h" */
-
-#define _INC_ASSERT    /* disable "assert.h" */
-#define assert(x)
-
-#endif  /* WTF_OS_WINCE && !WTF_PLATFORM_QT */
-
 #if WTF_PLATFORM_QT
 #define WTF_USE_QT4_UNICODE 1
-#elif WTF_OS_WINCE
-#define WTF_USE_WINCE_UNICODE 1
-#elif WTF_PLATFORM_BREWMP
-#define WTF_USE_BREWMP_UNICODE 1
 #elif WTF_PLATFORM_GTK
 /* The GTK+ Unicode backend is configurable */
 #else
 #define WTF_USE_ICU_UNICODE 1
 #endif
 
-#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS
+#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE
+#define WTF_PLATFORM_CF 1
+#define WTF_USE_PTHREADS 1
+#define HAVE_PTHREAD_RWLOCK 1
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && WTF_CPU_X86_64
 #define WTF_USE_PLUGIN_HOST_PROCESS 1
 #endif
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-#define ENABLE_GESTURE_EVENTS 1
-#define ENABLE_RUBBER_BANDING 1
-#define WTF_USE_WK_SCROLLBAR_PAINTER 1
-#endif
-#if !defined(ENABLE_JAVA_BRIDGE)
-#define ENABLE_JAVA_BRIDGE 1
+#if !defined(ENABLE_MAC_JAVA_BRIDGE)
+#define ENABLE_MAC_JAVA_BRIDGE 1
 #endif
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 1
 #endif
-#define WTF_USE_CF 1
-#define WTF_USE_PTHREADS 1
-#define HAVE_PTHREAD_RWLOCK 1
 #define HAVE_READLINE 1
 #define HAVE_RUNLOOP_TIMER 1
-#define ENABLE_FULLSCREEN_API 1
-#define ENABLE_SMOOTH_SCROLLING 1
-#define ENABLE_WEB_ARCHIVE 1
-#endif /* WTF_PLATFORM_MAC && !WTF_PLATFORM_IOS */
+#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */
 
-#if WTF_PLATFORM_CHROMIUM && WTF_OS_DARWIN
-#define WTF_USE_CF 1
+#if WTF_PLATFORM_CHROMIUM && WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define ENABLE_SINGLE_THREADED 1
+#if WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #endif
 
-#if WTF_PLATFORM_QT && WTF_OS_DARWIN
-#define WTF_USE_CF 1
-#endif
-
-#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER) && !WTF_PLATFORM_GTK && !WTF_PLATFORM_QT
-#define ENABLE_PURGEABLE_MEMORY 1
-#endif
-
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define ENABLE_CONTEXT_MENUS 0
 #define ENABLE_DRAG_SUPPORT 0
-#define ENABLE_DATA_TRANSFER_ITEMS 0
 #define ENABLE_FTPDIR 1
 #define ENABLE_GEOLOCATION 1
 #define ENABLE_ICONDATABASE 0
 #define ENABLE_INSPECTOR 0
-#define ENABLE_JAVA_BRIDGE 0
+#define ENABLE_MAC_JAVA_BRIDGE 0
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #define ENABLE_ORIENTATION_EVENTS 1
 #define ENABLE_REPAINT_THROTTLING 1
 #define HAVE_READLINE 1
-#define WTF_USE_CF 1
+#define WTF_PLATFORM_CF 1
 #define WTF_USE_PTHREADS 1
 #define HAVE_PTHREAD_RWLOCK 1
-#define ENABLE_WEB_ARCHIVE 1
 #endif
 
 #if WTF_PLATFORM_ANDROID
 #define WTF_USE_PTHREADS 1
+#define WTF_PLATFORM_SGL 1
 #define USE_SYSTEM_MALLOC 1
-#define ENABLE_JAVA_BRIDGE 1
+#define ENABLE_MAC_JAVA_BRIDGE 1
 #define LOG_DISABLED 1
-/* Prevents Webkit from drawing the caret in textfields and textareas
-   This prevents unnecessary invals. */
+// Prevents Webkit from drawing the caret in textfields and textareas
+// This prevents unnecessary invals.
 #define ENABLE_TEXT_CARET 1
 #define ENABLE_JAVASCRIPT_DEBUGGER 0
-#if !defined(ENABLE_JIT) && !ENABLE_ANDROID_JSC_JIT
-#define ENABLE_JIT 0
-#endif
 #endif
 
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE
-#define WTF_USE_CF 1
-#define WTF_USE_PTHREADS 0
-#endif
-
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !defined(WIN_CAIRO)
-#define WTF_USE_CFNETWORK 1
-#endif
-
-#if WTF_USE_CFNETWORK || WTF_PLATFORM_MAC
-#define WTF_USE_CFURLCACHE 1
-#define WTF_USE_CFURLSTORAGESESSIONS 1
-#endif
-
-#if WTF_PLATFORM_WIN && !WTF_OS_WINCE && !WTF_PLATFORM_CHROMIUM && !WTF_PLATFORM_QT
-#define ENABLE_WEB_ARCHIVE 1
+#if WTF_PLATFORM_WIN
+#define WTF_USE_WININET 1
 #endif
 
 #if WTF_PLATFORM_WX
 #define ENABLE_ASSEMBLER 1
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
-#if WTF_OS_DARWIN
-#define WTF_USE_CF 1
-#ifndef BUILDING_ON_TIGER
-#define WTF_USE_CORE_TEXT 1
-#define ENABLE_WEB_ARCHIVE 1
-#else
-#define WTF_USE_ATSUI 1
-#endif
+#if WTF_PLATFORM_DARWIN
+#define WTF_PLATFORM_CF 1
 #endif
 #endif
 
@@ -739,39 +574,25 @@
 #define ENABLE_NETSCAPE_PLUGIN_API 0
 #endif
 
-#if WTF_PLATFORM_BREWMP
-#define USE_SYSTEM_MALLOC 1
-#endif
-
-#if WTF_PLATFORM_BREWMP_SIMULATOR
-#define ENABLE_JIT 0
-#endif
-
 #if !defined(HAVE_ACCESSIBILITY)
-#if WTF_PLATFORM_IOS || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
+#if WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM
 #define HAVE_ACCESSIBILITY 1
 #endif
 #endif /* !defined(HAVE_ACCESSIBILITY) */
 
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
+#if WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN
 #define HAVE_SIGNAL_H 1
 #endif
 
-#if !defined(HAVE_STRNSTR)
-#if WTF_OS_DARWIN || WTF_OS_FREEBSD
-#define HAVE_STRNSTR 1
-#endif
-#endif
-
-#if !WTF_OS_WINDOWS && !WTF_OS_SOLARIS && !WTF_OS_QNX \
-    && !WTF_OS_SYMBIAN && !WTF_OS_HAIKU && !WTF_OS_RVCT \
-    && !WTF_OS_ANDROID && !WTF_PLATFORM_BREWMP
+#if !WTF_PLATFORM_WIN_OS && !WTF_PLATFORM_SOLARIS && !WTF_PLATFORM_QNX \
+    && !WTF_PLATFORM_SYMBIAN && !WTF_PLATFORM_HAIKU && !WTF_COMPILER_RVCT \
+    && !WTF_PLATFORM_ANDROID && !WTF_PLATFORM_OS2
 #define HAVE_TM_GMTOFF 1
 #define HAVE_TM_ZONE 1
 #define HAVE_TIMEGM 1
-#endif
+#endif     
 
-#if WTF_OS_DARWIN
+#if WTF_PLATFORM_DARWIN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 1
@@ -782,37 +603,23 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 #define HAVE_SYS_TIMEB_H 1
-#define WTF_USE_ACCELERATE 1
 
-#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD)
-
-#define HAVE_DISPATCH_H 1
-#define HAVE_HOSTED_CORE_ANIMATION 1
-
-#if !WTF_PLATFORM_IOS
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !WTF_PLATFORM_IPHONE && !WTF_PLATFORM_QT
 #define HAVE_MADV_FREE_REUSE 1
 #define HAVE_MADV_FREE 1
 #define HAVE_PTHREAD_SETNAME_NP 1
 #endif
 
-#endif
-
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define HAVE_MADV_FREE 1
 #endif
 
-#elif WTF_OS_WINDOWS
+#elif WTF_PLATFORM_WIN_OS
 
-#if WTF_OS_WINCE
-#define HAVE_ERRNO_H 0
-#else
 #define HAVE_SYS_TIMEB_H 1
-#define HAVE_ALIGNED_MALLOC 1
-#define HAVE_ISDEBUGGERPRESENT 1
-#endif
 #define HAVE_VIRTUALALLOC 1
 
-#elif WTF_OS_SYMBIAN
+#elif WTF_PLATFORM_SYMBIAN
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 0
@@ -825,11 +632,7 @@
 #define HAVE_SYS_PARAM_H 1
 #endif
 
-#elif WTF_PLATFORM_BREWMP
-
-#define HAVE_ERRNO_H 1
-
-#elif WTF_OS_QNX
+#elif WTF_PLATFORM_QNX
 
 #define HAVE_ERRNO_H 1
 #define HAVE_MMAP 1
@@ -838,7 +641,7 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
-#elif WTF_OS_ANDROID
+#elif WTF_PLATFORM_ANDROID
 
 #define HAVE_ERRNO_H 1
 #define HAVE_LANGINFO_H 0
@@ -848,13 +651,23 @@
 #define HAVE_SYS_PARAM_H 1
 #define HAVE_SYS_TIME_H 1
 
+#elif WTF_PLATFORM_OS2
+
+#define HAVE_MMAP 1
+#define ENABLE_ASSEMBLER 1
+#define HAVE_ERRNO_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIMEB_H 1
+
 #else
 
 /* FIXME: is this actually used or do other platforms generate their own config.h? */
 
 #define HAVE_ERRNO_H 1
 /* As long as Haiku doesn't have a complete support of locale this will be disabled. */
-#if !WTF_OS_HAIKU
+#if !WTF_PLATFORM_HAIKU
 #define HAVE_LANGINFO_H 1
 #endif
 #define HAVE_MMAP 1
@@ -867,14 +680,6 @@
 
 /* ENABLE macro defaults */
 
-#if WTF_PLATFORM_QT
-/* We must not customize the global operator new and delete for the Qt port. */
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 0
-#if !WTF_OS_UNIX || WTF_OS_SYMBIAN
-#define USE_SYSTEM_MALLOC 1
-#endif
-#endif
-
 /* fastMalloc match validation allows for runtime verification that
    new is matched by delete, fastMalloc is matched by fastFree, etc. */
 #if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION)
@@ -905,10 +710,6 @@
 #define ENABLE_DRAG_SUPPORT 1
 #endif
 
-#if !defined(ENABLE_DATA_TRANSFER_ITEMS)
-#define ENABLE_DATA_TRANSFER_ITEMS 0
-#endif
-
 #if !defined(ENABLE_DASHBOARD_SUPPORT)
 #define ENABLE_DASHBOARD_SUPPORT 0
 #endif
@@ -917,22 +718,14 @@
 #define ENABLE_INSPECTOR 1
 #endif
 
-#if !defined(ENABLE_JAVA_BRIDGE)
-#define ENABLE_JAVA_BRIDGE 0
+#if !defined(ENABLE_MAC_JAVA_BRIDGE)
+#define ENABLE_MAC_JAVA_BRIDGE 0
 #endif
 
 #if !defined(ENABLE_NETSCAPE_PLUGIN_API)
 #define ENABLE_NETSCAPE_PLUGIN_API 1
 #endif
 
-#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE)
-#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0
-#endif
-
-#if !defined(ENABLE_PURGEABLE_MEMORY)
-#define ENABLE_PURGEABLE_MEMORY 0
-#endif
-
 #if !defined(WTF_USE_PLUGIN_HOST_PROCESS)
 #define WTF_USE_PLUGIN_HOST_PROCESS 0
 #endif
@@ -945,11 +738,6 @@
 #define ENABLE_OPCODE_STATS 0
 #endif
 
-#if !defined(ENABLE_GLOBAL_FASTMALLOC_NEW)
-#define ENABLE_GLOBAL_FASTMALLOC_NEW 1
-#endif
-
-#define ENABLE_DEBUG_WITH_BREAKPOINT 0
 #define ENABLE_SAMPLING_COUNTERS 0
 #define ENABLE_SAMPLING_FLAGS 0
 #define ENABLE_OPCODE_SAMPLING 0
@@ -965,18 +753,10 @@
 #define ENABLE_GEOLOCATION 0
 #endif
 
-#if !defined(ENABLE_GESTURE_RECOGNIZER)
-#define ENABLE_GESTURE_RECOGNIZER 0
-#endif
-
 #if !defined(ENABLE_NOTIFICATIONS)
 #define ENABLE_NOTIFICATIONS 0
 #endif
 
-#if WTF_PLATFORM_IOS
-#define ENABLE_TEXT_CARET 0
-#endif
-
 #if !defined(ENABLE_TEXT_CARET)
 #define ENABLE_TEXT_CARET 1
 #endif
@@ -985,88 +765,80 @@
 #define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0
 #endif
 
-#if !defined(ENABLE_FULLSCREEN_API)
-#define ENABLE_FULLSCREEN_API 0
-#endif
-
-#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64)
-#if (WTF_CPU_X86_64 && (WTF_OS_UNIX || WTF_OS_WINDOWS)) \
-    || (WTF_CPU_IA64 && !WTF_CPU_IA64_32) \
-    || WTF_CPU_ALPHA \
-    || WTF_CPU_SPARC64 \
-    || WTF_CPU_S390X \
-    || WTF_CPU_PPC64
+#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
+#if (WTF_CPU_X86_64 && (WTF_PLATFORM_UNIX || WTF_PLATFORM_WIN_OS)) || WTF_CPU_IA64 || WTF_CPU_ALPHA
 #define WTF_USE_JSVALUE64 1
+#elif WTF_CPU_ARM || WTF_CPU_PPC64
+#define WTF_USE_JSVALUE32 1
+#elif WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW
+/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
+on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
+#define WTF_USE_JSVALUE32 1
 #else
 #define WTF_USE_JSVALUE32_64 1
 #endif
-#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32_64) */
+#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */
 
 #if !defined(ENABLE_REPAINT_THROTTLING)
 #define ENABLE_REPAINT_THROTTLING 0
 #endif
 
-/* Disable the JIT on versions of GCC prior to 4.1 */
-#if !defined(ENABLE_JIT) && WTF_COMPILER_GCC && !GCC_VERSION_AT_LEAST(4, 1, 0)
-#define ENABLE_JIT 0
+#if !defined(ENABLE_JIT)
+
+/* The JIT is tested & working on x86_64 Mac */
+#if WTF_CPU_X86_64 && WTF_PLATFORM_MAC
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 Mac */
+#elif WTF_CPU_X86 && WTF_PLATFORM_MAC
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 OS/2 */
+#elif WTF_CPU_X86 && WTF_PLATFORM_OS2
+    #define ENABLE_JIT 1
+/* The JIT is tested & working on x86 Windows */
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN
+    #define ENABLE_JIT 1
+#elif WTF_CPU_SPARC
+    #define ENABLE_JIT 1
 #endif
 
-/* JIT is not implemented for 64 bit on MSVC */
-#if !defined(ENABLE_JIT) && WTF_COMPILER_MSVC && WTF_CPU_X86_64
-#define ENABLE_JIT 0
+#if WTF_PLATFORM_QT
+#if WTF_CPU_X86_64 && WTF_PLATFORM_DARWIN
+    #define ENABLE_JIT 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_DARWIN
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
+#elif WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100
+    #define ENABLE_JIT 1
+    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX
+    #define ENABLE_JIT 1
 #endif
+#endif /* PLATFORM(QT) */
 
-/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */
-#if !defined(ENABLE_JIT) \
-    && (WTF_CPU_X86 || WTF_CPU_X86_64 || WTF_CPU_ARM || WTF_CPU_MIPS) \
-    && (WTF_OS_DARWIN || !WTF_COMPILER_GCC || GCC_VERSION_AT_LEAST(4, 1, 0)) \
-    && !WTF_OS_WINCE
-#define ENABLE_JIT 1
-#endif
+#endif /* !defined(ENABLE_JIT) */
 
-/* Currently only implemented for JSVALUE64, only tested on WTF_PLATFORM_MAC */
-#if ENABLE_JIT && WTF_USE_JSVALUE64 && WTF_PLATFORM_MAC
-#define ENABLE_DFG_JIT 1
-/* Enabled with restrictions to circumvent known performance regressions. */
-#define ENABLE_DFG_JIT_RESTRICTIONS 1
-#endif
-
-/* Ensure that either the JIT or the interpreter has been enabled. */
-#if !defined(ENABLE_INTERPRETER) && !ENABLE_JIT
-#define ENABLE_INTERPRETER 1
-#endif
-#if !(ENABLE_JIT || ENABLE_INTERPRETER)
-#error You have to have at least one execution model enabled to build JSC
-#endif
-
-#if WTF_CPU_SH4 && WTF_PLATFORM_QT
-#define ENABLE_JIT 1
-#define ENABLE_YARR 1
-#define ENABLE_YARR_JIT 1
-#define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1
-#define ENABLE_ASSEMBLER 1
-#endif
-
-/* Configure the JIT */
 #if ENABLE_JIT
-    #if WTF_CPU_ARM
-    #if !defined(ENABLE_JIT_USE_SOFT_MODULO) && WTF_ARM_ARCH_AT_LEAST(5)
-    #define ENABLE_JIT_USE_SOFT_MODULO 1
-    #endif
-    #endif
-
-    #ifndef ENABLE_JIT_OPTIMIZE_CALL
-    #define ENABLE_JIT_OPTIMIZE_CALL 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
-    #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
-    #define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
-    #endif
-    #ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
-    #define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
-    #endif
+#ifndef ENABLE_JIT_OPTIMIZE_CALL
+#define ENABLE_JIT_OPTIMIZE_CALL 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL
+#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS
+#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1
+#endif
+#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS
+#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1
+#endif
 #endif
 
 #if WTF_CPU_X86 && WTF_COMPILER_MSVC
@@ -1077,89 +849,80 @@
 #define JSC_HOST_CALL
 #endif
 
-/* Configure the interpreter */
-#if WTF_COMPILER_GCC || (RVCT_VERSION_AT_LEAST(4, 0, 0, 0) && defined(__GNUC__))
+#if WTF_COMPILER_GCC && !ENABLE_JIT
 #define HAVE_COMPUTED_GOTO 1
 #endif
-#if HAVE_COMPUTED_GOTO && ENABLE_INTERPRETER
-#define ENABLE_COMPUTED_GOTO_INTERPRETER 1
+
+#if ENABLE_JIT && defined(COVERAGE)
+    #define WTF_USE_INTERPRETER 0
+#else
+    #define WTF_USE_INTERPRETER 1
 #endif
 
-/* Regular Expression Tracing - Set to 1 to trace RegExp's in jsc.  Results dumped at exit */
-#define ENABLE_REGEXP_TRACING 0
+/* Yet Another Regex Runtime. */
+#if !defined(ENABLE_YARR_JIT)
 
-/* Yet Another Regex Runtime - turned on by default for JIT enabled ports. */
-#if WTF_PLATFORM_CHROMIUM
-#define ENABLE_YARR_JIT 0
-
-#elif ENABLE_JIT && !defined(ENABLE_YARR_JIT)
+/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */
+#if (WTF_CPU_X86 \
+ || WTF_CPU_X86_64 \
+ || WTF_CPU_SPARC \
+ || WTF_CPU_ARM_TRADITIONAL \
+ || WTF_CPU_ARM_THUMB2 \
+ || WTF_CPU_X86)
 #define ENABLE_YARR_JIT 1
-
-/* Setting this flag compares JIT results with interpreter results. */
-#define ENABLE_YARR_JIT_DEBUG 0
+#else
+#define ENABLE_YARR_JIT 0
 #endif
 
-#if ENABLE_JIT || ENABLE_YARR_JIT
+#endif /* !defined(ENABLE_YARR_JIT) */
+
+#if (ENABLE_JIT || ENABLE_YARR_JIT)
 #define ENABLE_ASSEMBLER 1
 #endif
 /* Setting this flag prevents the assembler from using RWX memory; this may improve
    security but currectly comes at a significant performance cost. */
-#if WTF_PLATFORM_IOS
+#if WTF_PLATFORM_IPHONE
 #define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1
-#endif
-
-/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in.
-   On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */
-#if ENABLE_ASSEMBLER
-#if WTF_CPU_X86_64
-#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1
 #else
-#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1
-#endif
+#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0
 #endif
 
-#if !defined(ENABLE_PAN_SCROLLING) && WTF_OS_WINDOWS
+#if !defined(ENABLE_PAN_SCROLLING) && WTF_PLATFORM_WIN_OS
 #define ENABLE_PAN_SCROLLING 1
 #endif
 
-#if !defined(ENABLE_SMOOTH_SCROLLING)
-#define ENABLE_SMOOTH_SCROLLING 0
-#endif
-
-#if !defined(ENABLE_WEB_ARCHIVE)
-#define ENABLE_WEB_ARCHIVE 0
-#endif
-
-/* Use the QXmlStreamReader implementation for XMLDocumentParser */
+/* Use the QXmlStreamReader implementation for XMLTokenizer */
 /* Use the QXmlQuery implementation for XSLTProcessor */
 #if WTF_PLATFORM_QT
 #define WTF_USE_QXMLSTREAM 1
 #define WTF_USE_QXMLQUERY 1
 #endif
 
-#if WTF_PLATFORM_MAC
-/* Complex text framework */
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
-#define WTF_USE_ATSUI 0
-#define WTF_USE_CORE_TEXT 1
-#else
-#define WTF_USE_ATSUI 1
-#define WTF_USE_CORE_TEXT 0
-#endif
+#if !WTF_PLATFORM_QT
+#define WTF_USE_FONT_FAST_PATH 1
 #endif
 
 /* Accelerated compositing */
-#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER)) || WTF_PLATFORM_IOS || WTF_PLATFORM_QT || (WTF_PLATFORM_WIN && !WTF_OS_WINCE &&!defined(WIN_CAIRO))
+#if WTF_PLATFORM_MAC
+#if !defined(BUILDING_ON_TIGER)
+#define WTF_USE_ACCELERATED_COMPOSITING 1
+#endif
+#endif
+
+#if WTF_PLATFORM_IPHONE
 #define WTF_USE_ACCELERATED_COMPOSITING 1
 #endif
 
-#if (WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || WTF_PLATFORM_IOS
-#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1
-#endif
-
-#if WTF_PLATFORM_MAC && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-#define WTF_USE_AVFOUNDATION 1
-#endif
+/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with
+   with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and
+   off in one place. */
+//#if WTF_PLATFORM_WIN
+//#include "QuartzCorePresent.h"
+//#if QUARTZCORE_PRESENT
+//#define WTF_USE_ACCELERATED_COMPOSITING 1
+//#define ENABLE_3D_RENDERING 1
+//#endif
+//#endif
 
 #if WTF_COMPILER_GCC
 #define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result))
@@ -1167,7 +930,7 @@
 #define WARN_UNUSED_RETURN
 #endif
 
-#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_OS_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
+#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_PLATFORM_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK))
 #define ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH 1
 #endif
 
@@ -1176,46 +939,4 @@
 
 #define ENABLE_JSC_ZOMBIES 0
 
-/* FIXME: Eventually we should enable this for all platforms and get rid of the define. */
-#if WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_QT
-#define WTF_USE_PLATFORM_STRATEGIES 1
-#endif
-
-#if WTF_PLATFORM_WIN
-#define WTF_USE_CROSS_PLATFORM_CONTEXT_MENUS 1
-#endif
-
-/* Geolocation request policy. pre-emptive policy is to acquire user permission before acquiring location.
-   Client based implementations will have option to choose between pre-emptive and nonpre-emptive permission policy.
-   pre-emptive permission policy is enabled by default for all client-based implementations. */
-#if ENABLE_CLIENT_BASED_GEOLOCATION
-#define WTF_USE_PREEMPT_GEOLOCATION_PERMISSION 1
-#endif
-
-#if WTF_CPU_ARM_THUMB2
-#define ENABLE_BRANCH_COMPACTION 1
-#endif
-
-#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
-#define ENABLE_THREADING_OPENMP 1
-#endif
-
-#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE_SINGLE_THREADED && (ENABLE_THREADING_GENERIC || ENABLE_THREADING_LIBDISPATCH || ENABLE_THREADING_OPENMP)
-#define ENABLE_PARALLEL_JOBS 1
-#endif
-
-#if ENABLE_GLIB_SUPPORT
-#include "GTypedefs.h"
-#endif
-
-/* FIXME: This define won't be needed once #27551 is fully landed. However, 
-   since most ports try to support sub-project independence, adding new headers
-   to WTF causes many ports to break, and so this way we can address the build
-   breakages one port at a time. */
-#define WTF_USE_EXPORT_MACROS 0
-
-#if WTF_PLATFORM_QT || WTF_PLATFORM_GTK
-#define WTF_USE_UNIX_DOMAIN_SOCKETS 1
-#endif
-
 #endif /* WTF_Platform_h */
diff --git a/js/src/jit-test/tests/basic/bug632964-regexp.js b/js/src/jit-test/tests/basic/bug632964-regexp.js
index 75612dbc735d..7151d3713647 100644
--- a/js/src/jit-test/tests/basic/bug632964-regexp.js
+++ b/js/src/jit-test/tests/basic/bug632964-regexp.js
@@ -1,3 +1,5 @@
+// |jit-test| error: InternalError: regular expression too complex
+
 var sText = "s";
 
 for (var i = 0; i < 250000; ++i)
@@ -10,5 +12,6 @@ var match = sText.match(/s(\s|.)*?e/gi);
 //var match = sText.match(/s([\s\S]*?)e/gi);
 //var match = sText.match(/s(?:[\s\S]*?)e/gi);
 var end = new Date();
+print(end - start);
 
 assertEq(match.length, 1);
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index c88fae9fdaf0..ecc336cdc4c3 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -48,7 +48,6 @@
 #include "jstracer.h"
 #include "jswrapper.h"
 #include "assembler/wtf/Platform.h"
-#include "yarr/BumpPointerAllocator.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
@@ -74,9 +73,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     active(false),
 #ifdef JS_METHODJIT
     jaegerCompartment(NULL),
-#endif
-#if ENABLE_YARR_JIT
-    regExpAllocator(NULL),
 #endif
     propertyTree(thisForCtor()),
     emptyArgumentsShape(NULL),
@@ -88,6 +84,9 @@ JSCompartment::JSCompartment(JSRuntime *rt)
     initialRegExpShape(NULL),
     initialStringShape(NULL),
     debugMode(rt->debugMode),
+#if ENABLE_YARR_JIT
+    regExpAllocator(NULL),
+#endif
     mathCache(NULL)
 {
     JS_INIT_CLIST(&scripts);
@@ -136,9 +135,11 @@ JSCompartment::init()
         return false;
 #endif
 
-    regExpAllocator = rt->new_();
+#if ENABLE_YARR_JIT
+    regExpAllocator = rt->new_();
     if (!regExpAllocator)
         return false;
+#endif
 
     if (!backEdgeTable.init())
         return false;
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 8827a275f796..5b3f16643050 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -54,8 +54,11 @@
 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
 #endif
 
-namespace JSC { class ExecutableAllocator; }
-namespace WTF { class BumpPointerAllocator; }
+namespace JSC {
+
+class ExecutableAllocator;
+
+}
 
 namespace js {
 
@@ -417,7 +420,6 @@ struct JS_FRIEND_API(JSCompartment) {
      */
     size_t getMjitCodeSize() const;
 #endif
-    WTF::BumpPointerAllocator    *regExpAllocator;
 
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
@@ -464,6 +466,8 @@ struct JS_FRIEND_API(JSCompartment) {
     bool                         debugMode;  // true iff debug mode on
     JSCList                      scripts;    // scripts in this compartment
 
+    JSC::ExecutableAllocator     *regExpAllocator;
+
     js::NativeIterCache          nativeIterCache;
 
     typedef js::Maybe LazyToSourceCache;
diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp
index 3d9f09f56559..0df8ae536a47 100644
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -59,6 +59,8 @@
 #include "jsobjinlines.h"
 #include "jsregexpinlines.h"
 
+#include "yarr/RegexParser.h"
+
 #ifdef JS_TRACER
 #include "jstracer.h"
 using namespace nanojit;
@@ -191,11 +193,11 @@ js_ObjectIsRegExp(JSObject *obj)
  */
 
 void
-RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error)
+RegExp::handleYarrError(JSContext *cx, int error)
 {
     switch (error) {
       case JSC::Yarr::NoError:
-        JS_NOT_REACHED("Called reportYarrError with value for no error");
+        JS_NOT_REACHED("Precondition violation: an error must have occurred.");
         return;
 #define COMPILE_EMSG(__code, __msg) \
       case JSC::Yarr::__code: \
@@ -208,16 +210,49 @@ RegExp::reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error)
       COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN);
       COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */
       COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE);
       COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE);
-      COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
+      COMPILE_EMSG(CharacterClassRangeSingleChar, JSMSG_BAD_CLASS_RANGE);
       COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
+      COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
+      COMPILE_EMSG(HitRecursionLimit, JSMSG_REGEXP_TOO_COMPLEX);
 #undef COMPILE_EMSG
       default:
-        JS_NOT_REACHED("Unknown Yarr error code");
+        JS_NOT_REACHED("Precondition violation: unknown Yarr error code.");
     }
 }
 
+void
+RegExp::handlePCREError(JSContext *cx, int error)
+{
+#define REPORT(msg_) \
+    JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \
+    return
+    switch (error) {
+      case -2: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 0: JS_NOT_REACHED("Precondition violation: an error must have occurred.");
+      case 1: REPORT(JSMSG_TRAILING_SLASH);
+      case 2: REPORT(JSMSG_TRAILING_SLASH);
+      case 3: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 4: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 5: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 6: REPORT(JSMSG_BAD_CLASS_RANGE);
+      case 7: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 8: REPORT(JSMSG_BAD_CLASS_RANGE);
+      case 9: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 10: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
+      case 11: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 12: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
+      case 13: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 14: REPORT(JSMSG_MISSING_PAREN);
+      case 15: REPORT(JSMSG_BAD_BACKREF);
+      case 16: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 17: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      default:
+        JS_NOT_REACHED("Precondition violation: unknown PCRE error code.");
+    }
+#undef REPORT
+}
+
 bool
 RegExp::parseFlags(JSContext *cx, JSString *flagStr, uintN *flagsOut)
 {
@@ -894,4 +929,3 @@ js_InitRegExpClass(JSContext *cx, JSObject *global)
 
     return proto;
 }
-
diff --git a/js/src/jsregexpinlines.h b/js/src/jsregexpinlines.h
index 305cf1590462..70db45413e1d 100644
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -48,13 +48,12 @@
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
-#include "methodjit/MethodJIT.h"
 #include "assembler/wtf/Platform.h"
-#include "yarr/BumpPointerAllocator.h"
 
-#include "yarr/Yarr.h"
 #if ENABLE_YARR_JIT
-#include "yarr/YarrJIT.h"
+#include "yarr/yarr/RegexJIT.h"
+#else
+#include "yarr/pcre/pcre.h"
 #endif
 
 namespace js {
@@ -96,10 +95,10 @@ regexp_statics_construct(JSContext *cx, GlobalObject *parent)
 class RegExp
 {
 #if ENABLE_YARR_JIT
-    /* native code is valid only if codeBlock.isFallBack() == false */
-    JSC::Yarr::YarrCodeBlock    codeBlock;
+    JSC::Yarr::RegexCodeBlock   compiled;
+#else
+    JSRegExp                    *compiled;
 #endif
-    JSC::Yarr::BytecodePattern  *byteCode;
     JSLinearString              *source;
     size_t                      refCount;
     unsigned                    parenCount; /* Must be |unsigned| to interface with YARR. */
@@ -112,11 +111,7 @@ class RegExp
 #endif
 
     RegExp(JSLinearString *source, uint32 flags, JSCompartment *compartment)
-      :
-#if ENABLE_YARR_JIT
-        codeBlock(),
-#endif
-        byteCode(NULL), source(source), refCount(1), parenCount(0), flags(flags)
+      : compiled(), source(source), refCount(1), parenCount(0), flags(flags)
 #ifdef DEBUG
         , compartment(compartment)
 #endif
@@ -125,18 +120,17 @@ class RegExp
     JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
 
     ~RegExp() {
-#if ENABLE_YARR_JIT
-        codeBlock.release();
+#if !ENABLE_YARR_JIT
+        if (compiled)
+            jsRegExpFree(compiled);
 #endif
-        // YYY
-        if (byteCode)
-            delete byteCode;
     }
 
     bool compileHelper(JSContext *cx, JSLinearString &pattern);
     bool compile(JSContext *cx);
     static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
-    void reportYarrError(JSContext *cx, JSC::Yarr::ErrorCode error);
+    void handlePCREError(JSContext *cx, int error);
+    void handleYarrError(JSContext *cx, int error);
     static inline bool initArena(JSContext *cx);
     static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
     static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
@@ -324,6 +318,9 @@ inline bool
 RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
                         size_t *lastIndex, bool test, Value *rval)
 {
+#if !ENABLE_YARR_JIT
+    JS_ASSERT(compiled);
+#endif
     const size_t pairCount = parenCount + 1;
     const size_t bufCount = pairCount * 3; /* Should be x2, but PCRE has... needs. */
     const size_t matchItemCount = pairCount * 2;
@@ -363,20 +360,27 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
         inputOffset = *lastIndex;
     }
 
-    int result;
 #if ENABLE_YARR_JIT
-    if (!codeBlock.isFallBack())
-        result = JSC::Yarr::execute(codeBlock, chars, *lastIndex - inputOffset, len, buf);
-    else
-        result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
+    int result = JSC::Yarr::executeRegex(cx, compiled, chars, *lastIndex - inputOffset, len, buf,
+                                         bufCount);
 #else
-    result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
+    int result = jsRegExpExecute(cx, compiled, chars, len, *lastIndex - inputOffset, buf, 
+                                 bufCount);
 #endif
     if (result == -1) {
         *rval = NullValue();
         return true;
     }
 
+    if (result < 0) {
+#if ENABLE_YARR_JIT
+        handleYarrError(cx, result);
+#else
+        handlePCREError(cx, result);
+#endif
+        return false;
+    }
+
     /* 
      * Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so
      * just do another pass.
@@ -456,44 +460,53 @@ RegExp::createObjectNoStatics(JSContext *cx, const jschar *chars, size_t length,
     return obj;
 }
 
-/*
- * This function should be deleted once we can. See bug 604774.
- */
-static inline bool
-EnableYarrJIT(JSContext *cx)
+#ifdef ANDROID
+static bool
+YarrJITIsBroken(JSContext *cx)
 {
-#if defined ANDROID && defined(JS_TRACER) && defined(JS_METHODJIT)
-    return cx->traceJitEnabled || cx->methodJitEnabled;
+#if defined(JS_TRACER) && defined(JS_METHODJIT)
+    /* FIXME/bug 604774: dead code walking.
+     *
+     * If both JITs are disabled, assume they were disabled because
+     * we're running on a blacklisted device.
+     */
+    return !cx->traceJitEnabled && !cx->methodJitEnabled;
 #else
-    return true;
+    return false;
 #endif
 }
+#endif  /* ANDROID */
 
 inline bool
 RegExp::compileHelper(JSContext *cx, JSLinearString &pattern)
 {
-    JSC::Yarr::ErrorCode yarrError;
-    JSC::Yarr::YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError);
-    if (yarrError) {
-        reportYarrError(cx, yarrError);
-        return false;
-    }
-    parenCount = yarrPattern.m_numSubpatterns;
-
-#if ENABLE_YARR_JIT && defined(JS_METHODJIT)
-    if (EnableYarrJIT(cx) && !yarrPattern.m_containsBackreferences) {
-        JSC::Yarr::JSGlobalData globalData(cx->compartment->jaegerCompartment->execAlloc());
-        JSC::Yarr::jitCompile(yarrPattern, &globalData, codeBlock);
-        if (!codeBlock.isFallBack())
-            return true;
-    } else {
-        codeBlock.setFallBack(true);
-    }
+#if ENABLE_YARR_JIT
+    bool fellBack = false;
+    int error = 0;
+    jitCompileRegex(*cx->compartment->regExpAllocator, compiled, pattern, parenCount, error, fellBack, ignoreCase(), multiline()
+#ifdef ANDROID
+                    /* Temporary gross hack to work around buggy kernels. */
+                    , YarrJITIsBroken(cx)
+#endif
+);
+    if (!error)
+        return true;
+    if (fellBack)
+        handlePCREError(cx, error);
+    else
+        handleYarrError(cx, error);
+    return false;
+#else
+    int error = 0;
+    compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
+                               ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
+                               multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
+                               &parenCount, &error);
+    if (!error)
+        return true;
+    handlePCREError(cx, error);
+    return false;
 #endif
-
-    byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
-
-    return true;
 }
 
 inline bool
diff --git a/js/src/jsvector.h b/js/src/jsvector.h
index 4eaf58b6a4e7..3d413c1f64b6 100644
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -208,30 +208,12 @@ class Vector : private AllocPolicy
 
     /* compute constants */
 
-    /*
-     * Consider element size to be 1 for buffer sizing if there are
-     * 0 inline elements. This allows us to compile when the definition
-     * of the element type is not visible here.
-     *
-     * Explicit specialization is only allowed at namespace scope, so
-     * in order to keep everything here, we use a dummy template
-     * parameter with partial specialization.
-     */
-    template 
-    struct ElemSize {
-        static const size_t result = sizeof(T);
-    };
-    template 
-    struct ElemSize<0, Dummy> {
-        static const size_t result = 1;
-    };
-
     static const size_t sInlineCapacity =
-        tl::Min::result>::result;
+        tl::Min::result;
 
     /* Calculate inline buffer size; avoid 0-sized array. */
     static const size_t sInlineBytes =
-        tl::Max<1, sInlineCapacity * ElemSize::result>::result;
+        tl::Max<1, sInlineCapacity * sizeof(T)>::result;
 
     /* member data */
 
diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp
index b03c6afa0990..603d76a59c88 100644
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -503,7 +503,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             analyze::Bytecode *opinfo = analysis->maybeCode(i);
             if (opinfo && opinfo->safePoint) {
                 Label L = jumpMap[i];
-                JS_ASSERT(L.isSet());
+                JS_ASSERT(L.isValid());
                 jitNmap[ix].bcOff = i;
                 jitNmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L));
                 ix++;
@@ -625,7 +625,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
     cursor += sizeof(ic::EqualityICInfo) * jit->nEqualityICs;
     for (size_t i = 0; i < jit->nEqualityICs; i++) {
         uint32 offs = uint32(equalityICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isSet());
+        JS_ASSERT(jumpMap[offs].isValid());
         jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]);
         jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry);
         jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall);
@@ -650,7 +650,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
             continue;
 
         uint32 offs = uint32(traceICs[i].jumpTarget - script->code);
-        JS_ASSERT(jumpMap[offs].isSet());
+        JS_ASSERT(jumpMap[offs].isValid());
         jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint);
         jitTraceICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]);
         jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
@@ -800,7 +800,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
 
     for (size_t i = 0; i < jumpTableOffsets.length(); i++) {
         uint32 offset = jumpTableOffsets[i];
-        JS_ASSERT(jumpMap[offset].isSet());
+        JS_ASSERT(jumpMap[offset].isValid());
         jumpVec[i] = (void *)(result + masm.distanceOf(jumpMap[offset]));
     }
 
@@ -2089,7 +2089,7 @@ JSC::MacroAssembler::Label
 mjit::Compiler::labelOf(jsbytecode *pc)
 {
     uint32 offs = uint32(pc - script->code);
-    JS_ASSERT(jumpMap[offs].isSet());
+    JS_ASSERT(jumpMap[offs].isValid());
     return jumpMap[offs];
 }
 
diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp
index b55b0dba48a5..bd738b92ba2b 100644
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -846,7 +846,12 @@ static inline void Destroy(T &t)
 
 mjit::JITScript::~JITScript()
 {
-    code.release();
+#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) 
+    void *addr = code.m_code.executableAddress();
+    memset(addr, 0xcc, code.m_size);
+#endif
+
+    code.m_executablePool->release();
 
 #if defined JS_POLYIC
     ic::GetElementIC *getElems_ = getElems();
diff --git a/js/src/methodjit/TrampolineCompiler.cpp b/js/src/methodjit/TrampolineCompiler.cpp
index 77bb148ba311..a6ac9d709f0e 100644
--- a/js/src/methodjit/TrampolineCompiler.cpp
+++ b/js/src/methodjit/TrampolineCompiler.cpp
@@ -93,7 +93,7 @@ TrampolineCompiler::compileTrampoline(Trampolines::TrampolinePtr *where,
 
     Label entry = masm.label();
     CHECK_RESULT(generator(masm));
-    JS_ASSERT(entry.isSet());
+    JS_ASSERT(entry.isValid());
 
     bool ok;
     JSC::LinkBuffer buffer(&masm, execAlloc, poolp, &ok);
diff --git a/js/src/yarr/BumpPointerAllocator.h b/js/src/yarr/BumpPointerAllocator.h
deleted file mode 100644
index 8ef5a780f9d8..000000000000
--- a/js/src/yarr/BumpPointerAllocator.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/* -*- 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) 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef BumpPointerAllocator_h
-#define BumpPointerAllocator_h
-
-#include "PageAllocation.h"
-
-namespace WTF {
-
-#define MINIMUM_BUMP_POOL_SIZE 0x1000
-
-class BumpPointerPool {
-public:
-    // ensureCapacity will check whether the current pool has capacity to
-    // allocate 'size' bytes of memory  If it does not, it will attempt to
-    // allocate a new pool (which will be added to this one in a chain).
-    //
-    // If allocation fails (out of memory) this method will return null.
-    // If the return value is non-null, then callers should update any
-    // references they have to this current (possibly full) BumpPointerPool
-    // to instead point to the newly returned BumpPointerPool.
-    BumpPointerPool* ensureCapacity(size_t size)
-    {
-        void* allocationEnd = static_cast(m_current) + size;
-        ASSERT(allocationEnd > m_current); // check for overflow
-        if (allocationEnd <= static_cast(this))
-            return this;
-        return ensureCapacityCrossPool(this, size);
-    }
-
-    // alloc should only be called after calling ensureCapacity; as such
-    // alloc will never fail.
-    void* alloc(size_t size)
-    {
-        void* current = m_current;
-        void* allocationEnd = static_cast(current) + size;
-        ASSERT(allocationEnd > current); // check for overflow
-        ASSERT(allocationEnd <= static_cast(this));
-        m_current = allocationEnd;
-        return current;
-    }
-
-    // The dealloc method releases memory allocated using alloc.  Memory
-    // must be released in a LIFO fashion, e.g. if the client calls alloc
-    // four times, returning pointer A, B, C, D, then the only valid order
-    // in which these may be deallocaed is D, C, B, A.
-    //
-    // The client may optionally skip some deallocations.  In the example
-    // above, it would be valid to only explicitly dealloc C, A (D being
-    // dealloced along with C, B along with A).
-    //
-    // If pointer was not allocated from this pool (or pools) then dealloc
-    // will CRASH().  Callers should update any references they have to
-    // this current BumpPointerPool to instead point to the returned
-    // BumpPointerPool.
-    BumpPointerPool* dealloc(void* position)
-    {
-        if ((position >= m_start) && (position <= static_cast(this))) {
-            ASSERT(position <= m_current);
-            m_current = position;
-            return this;
-        }
-        return deallocCrossPool(this, position);
-    }
-
-private:
-    // Placement operator new, returns the last 'size' bytes of allocation for use as this.
-    void* operator new(size_t size, const PageAllocation& allocation)
-    {
-        ASSERT(size < allocation.size());
-        return reinterpret_cast(reinterpret_cast(allocation.base()) + allocation.size()) - size;
-    }
-
-    BumpPointerPool(const PageAllocation& allocation)
-        : m_current(allocation.base())
-        , m_start(allocation.base())
-        , m_next(0)
-        , m_previous(0)
-        , m_allocation(allocation)
-    {
-    }
-
-    static BumpPointerPool* create(size_t minimumCapacity = 0)
-    {
-        // Add size of BumpPointerPool object, check for overflow.
-        minimumCapacity += sizeof(BumpPointerPool);
-        if (minimumCapacity < sizeof(BumpPointerPool))
-            return 0;
-
-        size_t poolSize = MINIMUM_BUMP_POOL_SIZE;
-        while (poolSize < minimumCapacity) {
-            poolSize <<= 1;
-            // The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2!
-            ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1)));
-            if (!poolSize)
-                return 0;
-        }
-
-        PageAllocation allocation = PageAllocation::allocate(poolSize);
-        if (!!allocation)
-            return new(allocation) BumpPointerPool(allocation);
-        return 0;
-    }
-
-    void shrink()
-    {
-        ASSERT(!m_previous);
-        m_current = m_start;
-        while (m_next) {
-            BumpPointerPool* nextNext = m_next->m_next;
-            m_next->destroy();
-            m_next = nextNext;
-        }
-    }
-
-    void destroy()
-    {
-        m_allocation.deallocate();
-    }
-
-    static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size)
-    {
-        // The pool passed should not have capacity, so we'll start with the next one.
-        ASSERT(previousPool);
-        ASSERT((static_cast(previousPool->m_current) + size) > previousPool->m_current); // check for overflow
-        ASSERT((static_cast(previousPool->m_current) + size) > static_cast(previousPool));
-        BumpPointerPool* pool = previousPool->m_next;
-
-        while (true) {
-            if (!pool) {
-                // We've run to the end; allocate a new pool.
-                pool = BumpPointerPool::create(size);
-                previousPool->m_next = pool;
-                pool->m_previous = previousPool;
-                return pool;
-            }
-
-            // 
-            void* current = pool->m_current;
-            void* allocationEnd = static_cast(current) + size;
-            ASSERT(allocationEnd > current); // check for overflow
-            if (allocationEnd <= static_cast(pool))
-                return pool;
-        }
-    }
-
-    static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position)
-    {
-        // Should only be called if position is not in the current pool.
-        ASSERT((position < pool->m_start) || (position > static_cast(pool)));
-
-        while (true) {
-            // Unwind the current pool to the start, move back in the chain to the previous pool.
-            pool->m_current = pool->m_start;
-            pool = pool->m_previous;
-
-            // position was nowhere in the chain!
-            if (!pool)
-                CRASH();
-
-            if ((position >= pool->m_start) && (position <= static_cast(pool))) {
-                ASSERT(position <= pool->m_current);
-                pool->m_current = position;
-                return pool;
-            }
-        }
-    }
-
-    void* m_current;
-    void* m_start;
-    BumpPointerPool* m_next;
-    BumpPointerPool* m_previous;
-    PageAllocation m_allocation;
-
-    friend class BumpPointerAllocator;
-};
-
-// A BumpPointerAllocator manages a set of BumpPointerPool objects, which
-// can be used for LIFO (stack like) allocation.
-//
-// To begin allocating using this class call startAllocator().  The result
-// of this method will be null if the initial pool allocation fails, or a
-// pointer to a BumpPointerPool object that can be used to perform
-// allocations.  Whilst running no memory will be released until
-// stopAllocator() is called.  At this point all allocations made through
-// this allocator will be reaped, and underlying memory may be freed.
-//
-// (In practice we will still hold on to the initial pool to allow allocation
-// to be quickly restared, but aditional pools will be freed).
-//
-// This allocator is non-renetrant, it is encumbant on the clients to ensure
-// startAllocator() is not called again until stopAllocator() has been called.
-class BumpPointerAllocator {
-public:
-    BumpPointerAllocator()
-        : m_head(0)
-    {
-    }
-
-    ~BumpPointerAllocator()
-    {
-        if (m_head)
-            m_head->destroy();
-    }
-
-    BumpPointerPool* startAllocator()
-    {
-        if (!m_head)
-            m_head = BumpPointerPool::create();
-        return m_head;
-    }
-
-    void stopAllocator()
-    {
-        if (m_head)
-            m_head->shrink();
-    }
-
-private:
-    BumpPointerPool* m_head;
-};
-
-}
-
-using WTF::BumpPointerAllocator;
-
-#endif // BumpPointerAllocator_h
diff --git a/js/src/yarr/Makefile b/js/src/yarr/Makefile
new file mode 100644
index 000000000000..c824cdb96b6c
--- /dev/null
+++ b/js/src/yarr/Makefile
@@ -0,0 +1,5 @@
+INCLUDES := -I. -Iyarr -Iwtf -I../assembler/assembler -I../assembler
+
+all: 
+	$(CXX) -g3 -c $(INCLUDES) yarr/*.cpp
+	$(CXX) -g3 $(INCLUDES) TestMain.cpp *.o
diff --git a/js/src/yarr/OSAllocator.h b/js/src/yarr/OSAllocator.h
deleted file mode 100644
index ecfdc3b042ec..000000000000
--- a/js/src/yarr/OSAllocator.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef OSAllocator_h
-#define OSAllocator_h
-
-#include 
-#include "wtfbridge.h"
-#include "assembler/wtf/VMTags.h"
-#include "assembler/wtf/Assertions.h"
-
-namespace WTF {
-
-class OSAllocator {
-public:
-    enum Usage {
-        UnknownUsage = -1,
-        FastMallocPages = VM_TAG_FOR_TCMALLOC_MEMORY,
-        JSGCHeapPages = VM_TAG_FOR_COLLECTOR_MEMORY,
-        JSVMStackPages = VM_TAG_FOR_REGISTERFILE_MEMORY,
-        JSJITCodePages = VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY
-    };
-
-    // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state,
-    // releaseDecommitted should be called on a region of VM allocated by a single reservation,
-    // the memory must all currently be in a decommitted state.
-    static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void releaseDecommitted(void*, size_t);
-
-    // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should
-    // never be accessed, since the OS may not have attached physical memory for these regions).
-    // Clients should only call commit on uncommitted regions and decommit on committed regions.
-    static void commit(void*, size_t, bool writable, bool executable);
-    static void decommit(void*, size_t);
-
-    // These methods are symmetric; reserveAndCommit allocates VM in an committed state,
-    // decommitAndRelease should be called on a region of VM allocated by a single reservation,
-    // the memory must all currently be in a committed state.
-    static void* reserveAndCommit(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void decommitAndRelease(void* base, size_t size);
-
-    // These methods are akin to reserveAndCommit/decommitAndRelease, above - however rather than
-    // committing/decommitting the entire region additional parameters allow a subregion to be
-    // specified.
-    static void* reserveAndCommit(size_t reserveSize, size_t commitSize, Usage = UnknownUsage, bool writable = true, bool executable = false);
-    static void decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize);
-};
-
-inline void* OSAllocator::reserveAndCommit(size_t reserveSize, size_t commitSize, Usage usage, bool writable, bool executable)
-{
-    void* base = reserveUncommitted(reserveSize, usage, writable, executable);
-    commit(base, commitSize, writable, executable);
-    return base;
-}
-
-inline void OSAllocator::decommitAndRelease(void* releaseBase, size_t releaseSize, void* decommitBase, size_t decommitSize)
-{
-    ASSERT(decommitBase >= releaseBase && (static_cast(decommitBase) + decommitSize) <= (static_cast(releaseBase) + releaseSize));
-#if WTF_OS_WINCE || WTF_OS_SYMBIAN
-    // On most platforms we can actually skip this final decommit; releasing the VM will
-    // implicitly decommit any physical memory in the region. This is not true on WINCE.
-    // On Symbian, this makes implementation simpler and better aligned with the RChunk API
-    decommit(decommitBase, decommitSize);
-#endif
-    releaseDecommitted(releaseBase, releaseSize);
-}
-
-inline void OSAllocator::decommitAndRelease(void* base, size_t size)
-{
-    decommitAndRelease(base, size, base, size);
-}
-
-} // namespace WTF
-
-using WTF::OSAllocator;
-
-#endif // OSAllocator_h
diff --git a/js/src/yarr/OSAllocatorPosix.cpp b/js/src/yarr/OSAllocatorPosix.cpp
deleted file mode 100644
index 57c240b22fe5..000000000000
--- a/js/src/yarr/OSAllocatorPosix.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_ASSEMBLER && WTF_OS_UNIX && !WTF_OS_SYMBIAN
-
-#include "OSAllocator.h"
-
-#include 
-#include 
-#include "wtf/Assertions.h"
-
-namespace WTF {
-
-void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
-{
-    void* result = reserveAndCommit(bytes, usage, writable, executable);
-#if HAVE_MADV_FREE_REUSE
-    // To support the "reserve then commit" model, we have to initially decommit.
-    while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
-#endif
-    return result;
-}
-
-void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable)
-{
-    // All POSIX reservations start out logically committed.
-    int protection = PROT_READ;
-    if (writable)
-        protection |= PROT_WRITE;
-    if (executable)
-        protection |= PROT_EXEC;
-
-    int flags = MAP_PRIVATE | MAP_ANON;
-
-#if WTF_OS_DARWIN && !defined(BUILDING_ON_TIGER)
-    int fd = usage;
-#else
-    int fd = -1;
-#endif
-
-    void* result = 0;
-#if (WTF_OS_DARWIN && WTF_CPU_X86_64)
-    if (executable) {
-        // Cook up an address to allocate at, using the following recipe:
-        //   17 bits of zero, stay in userspace kids.
-        //   26 bits of randomness for ASLR.
-        //   21 bits of zero, at least stay aligned within one level of the pagetables.
-        //
-        // But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
-        // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus
-        // 2^24, which should put up somewhere in the middle of userspace (in the address range
-        // 0x200000000000 .. 0x5fffffffffff).
-        intptr_t randomLocation = 0;
-        randomLocation = arc4random() & ((1 << 25) - 1);
-        randomLocation += (1 << 24);
-        randomLocation <<= 21;
-        result = reinterpret_cast(randomLocation);
-    }
-#endif
-
-    result = mmap(result, bytes, protection, flags, fd, 0);
-    if (result == MAP_FAILED)
-        CRASH();
-    return result;
-}
-
-void OSAllocator::commit(void* address, size_t bytes, bool, bool)
-{
-#if HAVE_MADV_FREE_REUSE
-    while (madvise(address, bytes, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
-#else
-    // Non-MADV_FREE_REUSE reservations automatically commit on demand.
-    UNUSED_PARAM(address);
-    UNUSED_PARAM(bytes);
-#endif
-}
-
-void OSAllocator::decommit(void* address, size_t bytes)
-{
-#if HAVE_MADV_FREE_REUSE
-    while (madvise(address, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
-#elif HAVE_MADV_FREE
-    while (madvise(address, bytes, MADV_FREE) == -1 && errno == EAGAIN) { }
-#elif HAVE_MADV_DONTNEED
-    while (madvise(address, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
-#else
-    UNUSED_PARAM(address);
-    UNUSED_PARAM(bytes);
-#endif
-}
-
-void OSAllocator::releaseDecommitted(void* address, size_t bytes)
-{
-    int result = munmap(address, bytes);
-    if (result == -1)
-        CRASH();
-}
-
-} // namespace WTF
-
-#endif
diff --git a/js/src/yarr/OSAllocatorWin.cpp b/js/src/yarr/OSAllocatorWin.cpp
deleted file mode 100644
index 08df9e98aefb..000000000000
--- a/js/src/yarr/OSAllocatorWin.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_ASSEMBLER && WTF_OS_WINDOWS
-
-#include "windows.h"
-#include "wtf/Assertions.h"
-
-#include "OSAllocator.h"
-
-namespace WTF {
-
-static inline DWORD protection(bool writable, bool executable)
-{
-    return executable ?
-        (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) :
-        (writable ? PAGE_READWRITE : PAGE_READONLY);
-}
-
-void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable));
-    if (!result)
-        CRASH();
-    return result;
-}
-
-void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable));
-    if (!result)
-        CRASH();
-    return result;
-}
-
-void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
-{
-    void* result = VirtualAlloc(address, bytes, MEM_COMMIT, protection(writable, executable));
-    if (!result)
-        CRASH();
-}
-
-void OSAllocator::decommit(void* address, size_t bytes)
-{
-    bool result = VirtualFree(address, bytes, MEM_DECOMMIT);
-    if (!result)
-        CRASH();
-}
-
-void OSAllocator::releaseDecommitted(void* address, size_t bytes)
-{
-    // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx,
-    // dwSize must be 0 if dwFreeType is MEM_RELEASE.
-    bool result = VirtualFree(address, 0, MEM_RELEASE);
-    if (!result)
-        CRASH();
-}
-
-} // namespace WTF
-
-#endif
diff --git a/js/src/yarr/PageAllocation.h b/js/src/yarr/PageAllocation.h
deleted file mode 100644
index a86f37116e50..000000000000
--- a/js/src/yarr/PageAllocation.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- 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) 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PageAllocation_h
-#define PageAllocation_h
-
-#include "wtfbridge.h"
-#include "OSAllocator.h"
-#include "PageBlock.h"
-#include "assembler/wtf/VMTags.h"
-
-#if WTF_OS_DARWIN
-#include 
-#include 
-#endif
-
-#if WTF_OS_HAIKU
-#include 
-#endif
-
-#if WTF_OS_WINDOWS
-#include 
-#include 
-#endif
-
-#if WTF_OS_SYMBIAN
-#include 
-#include 
-#endif
-
-#if WTF_HAVE_ERRNO_H
-#include 
-#endif
-
-#if WTF_HAVE_MMAP
-#include 
-#include 
-#endif
-
-namespace WTF {
-
-/*
-    PageAllocation
-
-    The PageAllocation class provides a cross-platform memory allocation interface
-    with similar capabilities to posix mmap/munmap.  Memory is allocated by calling
-    PageAllocation::allocate, and deallocated by calling deallocate on the
-    PageAllocation object.  The PageAllocation holds the allocation's base pointer
-    and size.
-
-    The allocate method is passed the size required (which must be a multiple of
-    the system page size, which can be accessed using PageAllocation::pageSize).
-    Callers may also optinally provide a flag indicating the usage (for use by
-    system memory usage tracking tools, where implemented), and boolean values
-    specifying the required protection (defaulting to writable, non-executable).
-*/
-
-class PageAllocation : private PageBlock {
-public:
-    PageAllocation()
-    {
-    }
-
-    using PageBlock::size;
-    using PageBlock::base;
-
-#ifndef __clang__
-    using PageBlock::operator bool;
-#else
-    // FIXME: This is a workaround for , wherein Clang incorrectly emits an access
-    // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool".
-    operator bool() const { return PageBlock::operator bool(); }
-#endif
-
-    static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false)
-    {
-        ASSERT(isPageAligned(size));
-        return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size);
-    }
-
-    void deallocate()
-    {
-        // Clear base & size before calling release; if this is *inside* allocation
-        // then we won't be able to clear then after deallocating the memory.
-        PageAllocation tmp;
-        JSC::std::swap(tmp, *this);
-
-        ASSERT(tmp);
-        ASSERT(!*this);
-
-        OSAllocator::decommitAndRelease(tmp.base(), tmp.size());
-    }
-
-private:
-    PageAllocation(void* base, size_t size)
-        : PageBlock(base, size)
-    {
-    }
-};
-
-} // namespace WTF
-
-using WTF::PageAllocation;
-
-#endif // PageAllocation_h
diff --git a/js/src/yarr/PageBlock.cpp b/js/src/yarr/PageBlock.cpp
deleted file mode 100644
index 0f435b772860..000000000000
--- a/js/src/yarr/PageBlock.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "PageBlock.h"
-#include "wtf/Assertions.h"
-
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
-#include 
-#endif
-
-#if WTF_OS_WINDOWS
-#include 
-#include 
-#endif
-
-#if WTF_OS_SYMBIAN
-#include 
-#include 
-#endif
-
-namespace WTF {
-
-static size_t s_pageSize;
-
-#if WTF_OS_UNIX && !WTF_OS_SYMBIAN
-
-inline size_t systemPageSize()
-{
-    return getpagesize();
-}
-
-#elif WTF_OS_WINDOWS
-
-inline size_t systemPageSize()
-{
-    static size_t size = 0;
-    SYSTEM_INFO system_info;
-    GetSystemInfo(&system_info);
-    size = system_info.dwPageSize;
-    return size;
-}
-
-#elif WTF_OS_SYMBIAN
-
-inline size_t systemPageSize()
-{
-    static TInt page_size = 0;
-    UserHal::PageSizeInBytes(page_size);
-    return page_size;
-}
-
-#endif
-
-size_t pageSize()
-{
-    if (!s_pageSize)
-        s_pageSize = systemPageSize();
-    ASSERT(isPowerOfTwo(s_pageSize));
-    return s_pageSize;
-}
-
-} // namespace WTF
diff --git a/js/src/yarr/PageBlock.h b/js/src/yarr/PageBlock.h
deleted file mode 100644
index 33751315e049..000000000000
--- a/js/src/yarr/PageBlock.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- 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) 2010 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PageBlock_h
-#define PageBlock_h
-
-#include 
-#include "jsstdint.h"
-#include "assembler/wtf/Platform.h"
-
-namespace WTF {
-
-size_t pageSize();
-inline bool isPageAligned(void* address) { return !(reinterpret_cast(address) & (pageSize() - 1)); }
-inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
-inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
-
-class PageBlock {
-public:
-    PageBlock();
-    PageBlock(const PageBlock&);
-    PageBlock(void*, size_t);
-    
-    void* base() const { return m_base; }
-    size_t size() const { return m_size; }
-
-    operator bool() const { return !!m_base; }
-
-    bool contains(void* containedBase, size_t containedSize)
-    {
-        return containedBase >= m_base
-            && (static_cast(containedBase) + containedSize) <= (static_cast(m_base) + m_size);
-    }
-
-private:
-    void* m_base;
-    size_t m_size;
-};
-
-inline PageBlock::PageBlock()
-    : m_base(0)
-    , m_size(0)
-{
-}
-
-inline PageBlock::PageBlock(const PageBlock& other)
-    : m_base(other.m_base)
-    , m_size(other.m_size)
-{
-}
-
-inline PageBlock::PageBlock(void* base, size_t size)
-    : m_base(base)
-    , m_size(size)
-{
-}
-
-} // namespace WTF
-
-using WTF::pageSize;
-using WTF::isPageAligned;
-using WTF::isPageAligned;
-using WTF::isPowerOfTwo;
-
-#endif // PageBlock_h
diff --git a/js/src/yarr/VMTags.h b/js/src/yarr/VMTags.h
deleted file mode 100644
index fe6a006d3601..000000000000
--- a/js/src/yarr/VMTags.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2009 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 VMTags_h
-#define VMTags_h
-
-// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map
-// in order to aid tools that inspect system memory use. 
-#if WTF_OS_DARWIN
-
-#include 
-
-#if !defined(TARGETING_TIGER)
-
-#if defined(VM_MEMORY_TCMALLOC)
-#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
-#else
-#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53)
-#endif // defined(VM_MEMORY_TCMALLOC)
-
-#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-#else
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64)
-#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR)
-
-#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-#else
-#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65)
-#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE)
-
-#else // !defined(TARGETING_TIGER)
-
-// mmap on Tiger fails with tags that work on Leopard, so fall
-// back to Tiger-compatible tags (that also work on Leopard)
-// when targeting Tiger.
-#define VM_TAG_FOR_TCMALLOC_MEMORY -1
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
-#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
-
-#endif // !defined(TARGETING_TIGER)
-
-// Tags for vm_map and vm_allocate work on both Tiger and Leopard.
-
-#if defined(VM_MEMORY_JAVASCRIPT_CORE)
-#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE)
-#else
-#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63)
-#endif // defined(VM_MEMORY_JAVASCRIPT_CORE)
-
-#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-#else
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69)
-#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
-
-#else // OS(DARWIN)
-
-#define VM_TAG_FOR_TCMALLOC_MEMORY -1
-#define VM_TAG_FOR_COLLECTOR_MEMORY -1
-#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1
-#define VM_TAG_FOR_REGISTERFILE_MEMORY -1
-#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1
-
-#endif // OS(DARWIN)
-
-#endif // VMTags_h
diff --git a/js/src/yarr/Yarr.h b/js/src/yarr/Yarr.h
deleted file mode 100644
index 40ebcca096af..000000000000
--- a/js/src/yarr/Yarr.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- 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.
- *
- * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef Yarr_h
-#define Yarr_h
-
-#include 
-
-#include "YarrInterpreter.h"
-#include "YarrPattern.h"
-
-namespace JSC { namespace Yarr {
-
-#define YarrStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoBackReference 2
-#define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
-#define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1
-#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
-#define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1
-#define YarrStackSpaceForBackTrackInfoParentheses 2
-
-static const unsigned quantifyInfinite = UINT_MAX;
-
-// The below limit restricts the number of "recursive" match calls in order to
-// avoid spending exponential time on complex regular expressions.
-static const unsigned matchLimit = 1000000;
-
-enum JSRegExpResult {
-    JSRegExpMatch = 1,
-    JSRegExpNoMatch = 0,
-    JSRegExpErrorNoMatch = -1,
-    JSRegExpErrorHitLimit = -2,
-    JSRegExpErrorNoMemory = -3,
-    JSRegExpErrorInternal = -4
-};
-
-PassOwnPtr byteCompile(YarrPattern&, BumpPointerAllocator*);
-int interpret(BytecodePattern*, const UChar* input, unsigned start, unsigned length, int* output);
-
-} } // namespace JSC::Yarr
-
-#endif // Yarr_h
-
diff --git a/js/src/yarr/YarrInterpreter.cpp b/js/src/yarr/YarrInterpreter.cpp
deleted file mode 100644
index 3458cad37037..000000000000
--- a/js/src/yarr/YarrInterpreter.cpp
+++ /dev/null
@@ -1,1914 +0,0 @@
-/* -*- 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
- *
- * 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.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "YarrInterpreter.h"
-
-#include "Yarr.h"
-#include "BumpPointerAllocator.h"
-
-#ifndef NDEBUG
-#include 
-#endif
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-class Interpreter {
-public:
-    struct ParenthesesDisjunctionContext;
-
-    struct BackTrackInfoPatternCharacter {
-        uintptr_t matchAmount;
-    };
-    struct BackTrackInfoCharacterClass {
-        uintptr_t matchAmount;
-    };
-    struct BackTrackInfoBackReference {
-        uintptr_t begin; // Not really needed for greedy quantifiers.
-        uintptr_t matchAmount; // Not really needed for fixed quantifiers.
-    };
-    struct BackTrackInfoAlternative {
-        uintptr_t offset;
-    };
-    struct BackTrackInfoParentheticalAssertion {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParenthesesOnce {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParenthesesTerminal {
-        uintptr_t begin;
-    };
-    struct BackTrackInfoParentheses {
-        uintptr_t matchAmount;
-        ParenthesesDisjunctionContext* lastContext;
-    };
-
-    static inline void appendParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack, ParenthesesDisjunctionContext* context)
-    {
-        context->next = backTrack->lastContext;
-        backTrack->lastContext = context;
-        ++backTrack->matchAmount;
-    }
-
-    static inline void popParenthesesDisjunctionContext(BackTrackInfoParentheses* backTrack)
-    {
-        ASSERT(backTrack->matchAmount);
-        ASSERT(backTrack->lastContext);
-        backTrack->lastContext = backTrack->lastContext->next;
-        --backTrack->matchAmount;
-    }
-
-    struct DisjunctionContext
-    {
-        DisjunctionContext()
-            : term(0)
-        {
-        }
-
-        void* operator new(size_t, void* where)
-        {
-            return where;
-        }
-
-        int term;
-        unsigned matchBegin;
-        unsigned matchEnd;
-        uintptr_t frame[1];
-    };
-
-    DisjunctionContext* allocDisjunctionContext(ByteDisjunction* disjunction)
-    {
-        size_t size = sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
-        allocatorPool = allocatorPool->ensureCapacity(size);
-        if (!allocatorPool)
-            CRASH();
-        return new(allocatorPool->alloc(size)) DisjunctionContext();
-    }
-
-    void freeDisjunctionContext(DisjunctionContext* context)
-    {
-        allocatorPool = allocatorPool->dealloc(context);
-    }
-
-    struct ParenthesesDisjunctionContext
-    {
-        ParenthesesDisjunctionContext(int* output, ByteTerm& term)
-            : next(0)
-        {
-            unsigned firstSubpatternId = term.atom.subpatternId;
-            unsigned numNestedSubpatterns = term.atom.parenthesesDisjunction->m_numSubpatterns;
-
-            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) {
-                subpatternBackup[i] = output[(firstSubpatternId << 1) + i];
-                output[(firstSubpatternId << 1) + i] = -1;
-            }
-
-            new(getDisjunctionContext(term)) DisjunctionContext();
-        }
-
-        void* operator new(size_t, void* where)
-        {
-            return where;
-        }
-
-        void restoreOutput(int* output, unsigned firstSubpatternId, unsigned numNestedSubpatterns)
-        {
-            for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i)
-                output[(firstSubpatternId << 1) + i] = subpatternBackup[i];
-        }
-
-        DisjunctionContext* getDisjunctionContext(ByteTerm& term)
-        {
-            return reinterpret_cast(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1]));
-        }
-
-        ParenthesesDisjunctionContext* next;
-        int subpatternBackup[1];
-    };
-
-    ParenthesesDisjunctionContext* allocParenthesesDisjunctionContext(ByteDisjunction* disjunction, int* output, ByteTerm& term)
-    {
-        size_t size = sizeof(ParenthesesDisjunctionContext) - sizeof(int) + (term.atom.parenthesesDisjunction->m_numSubpatterns << 1) * sizeof(int) + sizeof(DisjunctionContext) - sizeof(uintptr_t) + disjunction->m_frameSize * sizeof(uintptr_t);
-        allocatorPool = allocatorPool->ensureCapacity(size);
-        if (!allocatorPool)
-            CRASH();
-        return new(allocatorPool->alloc(size)) ParenthesesDisjunctionContext(output, term);
-    }
-
-    void freeParenthesesDisjunctionContext(ParenthesesDisjunctionContext* context)
-    {
-        allocatorPool = allocatorPool->dealloc(context);
-    }
-
-    class InputStream {
-    public:
-        InputStream(const UChar* input, unsigned start, unsigned length)
-            : input(input)
-            , pos(start)
-            , length(length)
-        {
-        }
-
-        void next()
-        {
-            ++pos;
-        }
-
-        void rewind(unsigned amount)
-        {
-            ASSERT(pos >= amount);
-            pos -= amount;
-        }
-
-        int read()
-        {
-            ASSERT(pos < length);
-            if (pos < length)
-                return input[pos];
-            return -1;
-        }
-
-        int readPair()
-        {
-            ASSERT(pos + 1 < length);
-            return input[pos] | input[pos + 1] << 16;
-        }
-
-        int readChecked(int position)
-        {
-            ASSERT(position < 0);
-            ASSERT(static_cast(-position) <= pos);
-            unsigned p = pos + position;
-            ASSERT(p < length);
-            return input[p];
-        }
-
-        int reread(unsigned from)
-        {
-            ASSERT(from < length);
-            return input[from];
-        }
-
-        int prev()
-        {
-            ASSERT(!(pos > length));
-            if (pos && length)
-                return input[pos - 1];
-            return -1;
-        }
-
-        unsigned getPos()
-        {
-            return pos;
-        }
-
-        void setPos(unsigned p)
-        {
-            pos = p;
-        }
-
-        bool atStart()
-        {
-            return pos == 0;
-        }
-
-        bool atEnd()
-        {
-            return pos == length;
-        }
-
-        bool checkInput(int count)
-        {
-            if ((pos + count) <= length) {
-                pos += count;
-                return true;
-            }
-            return false;
-        }
-
-        void uncheckInput(int count)
-        {
-            pos -= count;
-        }
-
-        bool atStart(int position)
-        {
-            return (pos + position) == 0;
-        }
-
-        bool atEnd(int position)
-        {
-            return (pos + position) == length;
-        }
-
-        bool isNotAvailableInput(int position)
-        {
-            return (pos + position) > length;
-        }
-
-    private:
-        const UChar* input;
-        unsigned pos;
-        unsigned length;
-    };
-
-    bool testCharacterClass(CharacterClass* characterClass, int ch)
-    {
-        if (ch & 0xFF80) {
-            for (unsigned i = 0; i < characterClass->m_matchesUnicode.size(); ++i)
-                if (ch == characterClass->m_matchesUnicode[i])
-                    return true;
-            for (unsigned i = 0; i < characterClass->m_rangesUnicode.size(); ++i)
-                if ((ch >= characterClass->m_rangesUnicode[i].begin) && (ch <= characterClass->m_rangesUnicode[i].end))
-                    return true;
-        } else {
-            for (unsigned i = 0; i < characterClass->m_matches.size(); ++i)
-                if (ch == characterClass->m_matches[i])
-                    return true;
-            for (unsigned i = 0; i < characterClass->m_ranges.size(); ++i)
-                if ((ch >= characterClass->m_ranges[i].begin) && (ch <= characterClass->m_ranges[i].end))
-                    return true;
-        }
-
-        return false;
-    }
-
-    bool checkCharacter(int testChar, int inputPosition)
-    {
-        return testChar == input.readChecked(inputPosition);
-    }
-
-    bool checkCasedCharacter(int loChar, int hiChar, int inputPosition)
-    {
-        int ch = input.readChecked(inputPosition);
-        return (loChar == ch) || (hiChar == ch);
-    }
-
-    bool checkCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition)
-    {
-        bool match = testCharacterClass(characterClass, input.readChecked(inputPosition));
-        return invert ? !match : match;
-    }
-
-    bool tryConsumeBackReference(int matchBegin, int matchEnd, int inputOffset)
-    {
-        int matchSize = matchEnd - matchBegin;
-
-        if (!input.checkInput(matchSize))
-            return false;
-
-        if (pattern->m_ignoreCase) {
-            for (int i = 0; i < matchSize; ++i) {
-                int ch = input.reread(matchBegin + i);
-
-                int lo = Unicode::toLower(ch);
-                int hi = Unicode::toUpper(ch);
-
-                if ((lo != hi) ? (!checkCasedCharacter(lo, hi, inputOffset - matchSize + i)) : (!checkCharacter(ch, inputOffset - matchSize + i))) {
-                    input.uncheckInput(matchSize);
-                    return false;
-                }
-            }
-        } else {
-            for (int i = 0; i < matchSize; ++i) {
-                if (!checkCharacter(input.reread(matchBegin + i), inputOffset - matchSize + i)) {
-                    input.uncheckInput(matchSize);
-                    return false;
-                }
-            }
-        }
-
-        return true;
-    }
-
-    bool matchAssertionBOL(ByteTerm& term)
-    {
-        return (input.atStart(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition - 1)));
-    }
-
-    bool matchAssertionEOL(ByteTerm& term)
-    {
-        if (term.inputPosition)
-            return (input.atEnd(term.inputPosition)) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.readChecked(term.inputPosition)));
-
-        return (input.atEnd()) || (pattern->m_multiline && testCharacterClass(pattern->newlineCharacterClass, input.read()));
-    }
-
-    bool matchAssertionWordBoundary(ByteTerm& term)
-    {
-        bool prevIsWordchar = !input.atStart(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition - 1));
-        bool readIsWordchar;
-        if (term.inputPosition)
-            readIsWordchar = !input.atEnd(term.inputPosition) && testCharacterClass(pattern->wordcharCharacterClass, input.readChecked(term.inputPosition));
-        else
-            readIsWordchar = !input.atEnd() && testCharacterClass(pattern->wordcharCharacterClass, input.read());
-
-        bool wordBoundary = prevIsWordchar != readIsWordchar;
-        return term.invert() ? !wordBoundary : wordBoundary;
-    }
-
-    bool backtrackPatternCharacter(ByteTerm& term, DisjunctionContext* context)
-    {
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCharacter(term.atom.patternCharacter, term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool backtrackPatternCasedCharacter(ByteTerm& term, DisjunctionContext* context)
-    {
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchCharacterClass(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeCharacterClass);
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
-                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + matchAmount))
-                    return false;
-            }
-            return true;
-        }
-
-        case QuantifierGreedy: {
-            unsigned matchAmount = 0;
-            while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            return true;
-        }
-
-        case QuantifierNonGreedy:
-            backTrack->matchAmount = 0;
-            return true;
-        }
-
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool backtrackCharacterClass(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeCharacterClass);
-        BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.uncheckInput(1);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
-                ++backTrack->matchAmount;
-                if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - 1))
-                    return true;
-            }
-            input.uncheckInput(backTrack->matchAmount);
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchBackReference(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeBackReference);
-        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        int matchBegin = output[(term.atom.subpatternId << 1)];
-        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
-
-        // If the end position of the referenced match hasn't set yet then the backreference in the same parentheses where it references to that.
-        // In this case the result of match is empty string like when it references to a parentheses with zero-width match.
-        // Eg.: /(a\1)/
-        if (matchEnd == -1)
-            return true;
-
-        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
-
-        if (matchBegin == matchEnd)
-            return true;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            backTrack->begin = input.getPos();
-            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
-                if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
-                    input.setPos(backTrack->begin);
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        case QuantifierGreedy: {
-            unsigned matchAmount = 0;
-            while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
-                ++matchAmount;
-            backTrack->matchAmount = matchAmount;
-            return true;
-        }
-
-        case QuantifierNonGreedy:
-            backTrack->begin = input.getPos();
-            backTrack->matchAmount = 0;
-            return true;
-        }
-
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool backtrackBackReference(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeBackReference);
-        BackTrackInfoBackReference* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        int matchBegin = output[(term.atom.subpatternId << 1)];
-        int matchEnd = output[(term.atom.subpatternId << 1) + 1];
-        ASSERT((matchBegin == -1) || (matchBegin <= matchEnd));
-
-        if (matchBegin == matchEnd)
-            return false;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount:
-            // for quantityCount == 1, could rewind.
-            input.setPos(backTrack->begin);
-            break;
-
-        case QuantifierGreedy:
-            if (backTrack->matchAmount) {
-                --backTrack->matchAmount;
-                input.rewind(matchEnd - matchBegin);
-                return true;
-            }
-            break;
-
-        case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
-                ++backTrack->matchAmount;
-                return true;
-            }
-            input.setPos(backTrack->begin);
-            break;
-        }
-
-        return false;
-    }
-
-    void recordParenthesesMatch(ByteTerm& term, ParenthesesDisjunctionContext* context)
-    {
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = context->getDisjunctionContext(term)->matchBegin + term.inputPosition;
-            output[(subpatternId << 1) + 1] = context->getDisjunctionContext(term)->matchEnd + term.inputPosition;
-        }
-    }
-    void resetMatches(ByteTerm& term, ParenthesesDisjunctionContext* context)
-    {
-        unsigned firstSubpatternId = term.atom.subpatternId;
-        unsigned count = term.atom.parenthesesDisjunction->m_numSubpatterns;
-        context->restoreOutput(output, firstSubpatternId, count);
-    }
-    JSRegExpResult parenthesesDoBacktrack(ByteTerm& term, BackTrackInfoParentheses* backTrack)
-    {
-        while (backTrack->matchAmount) {
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-
-            JSRegExpResult result = matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true);
-            if (result == JSRegExpMatch)
-                return JSRegExpMatch;
-
-            resetMatches(term, context);
-            popParenthesesDisjunctionContext(backTrack);
-            freeParenthesesDisjunctionContext(context);
-
-            if (result != JSRegExpNoMatch)
-                return result;
-        }
-
-        return JSRegExpNoMatch;
-    }
-
-    bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy: {
-            // set this speculatively; if we get to the parens end this will be true.
-            backTrack->begin = input.getPos();
-            break;
-        }
-        case QuantifierNonGreedy: {
-            backTrack->begin = notFound;
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        }
-        case QuantifierFixedCount:
-            break;
-        }
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = input.getPos() + term.inputPosition;
-        }
-
-        return true;
-    }
-
-    bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
-        }
-
-        if (term.atom.quantityType == QuantifierFixedCount)
-            return true;
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        return backTrack->begin != input.getPos();
-    }
-
-    bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        if (term.capture()) {
-            unsigned subpatternId = term.atom.subpatternId;
-            output[(subpatternId << 1)] = -1;
-            output[(subpatternId << 1) + 1] = -1;
-        }
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy:
-            // if we backtrack to this point, there is another chance - try matching nothing.
-            ASSERT(backTrack->begin != notFound);
-            backTrack->begin = notFound;
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        case QuantifierNonGreedy:
-            ASSERT(backTrack->begin != notFound);
-        case QuantifierFixedCount:
-            break;
-        }
-
-        return false;
-    }
-
-    bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        switch (term.atom.quantityType) {
-        case QuantifierGreedy:
-            if (backTrack->begin == notFound) {
-                context->term -= term.atom.parenthesesWidth;
-                return false;
-            }
-        case QuantifierNonGreedy:
-            if (backTrack->begin == notFound) {
-                backTrack->begin = input.getPos();
-                if (term.capture()) {
-                    // Technically this access to inputPosition should be accessing the begin term's
-                    // inputPosition, but for repeats other than fixed these values should be
-                    // the same anyway! (We don't pre-check for greedy or non-greedy matches.)
-                    ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-                    ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition);
-                    unsigned subpatternId = term.atom.subpatternId;
-                    output[subpatternId << 1] = input.getPos() + term.inputPosition;
-                }
-                context->term -= term.atom.parenthesesWidth;
-                return true;
-            }
-        case QuantifierFixedCount:
-            break;
-        }
-
-        return false;
-    }
-
-    bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-        ASSERT(term.atom.quantityType == QuantifierGreedy);
-        ASSERT(term.atom.quantityCount == quantifyInfinite);
-        ASSERT(!term.capture());
-
-        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        backTrack->begin = input.getPos();
-        return true;
-    }
-
-    bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd);
-
-        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        // Empty match is a failed match.
-        if (backTrack->begin == input.getPos())
-            return false;
-
-        // Successful match! Okay, what's next? - loop around and try to match moar!
-        context->term -= (term.atom.parenthesesWidth + 1);
-        return true;
-    }
-
-    bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-        ASSERT(term.atom.quantityType == QuantifierGreedy);
-        ASSERT(term.atom.quantityCount == quantifyInfinite);
-        ASSERT(!term.capture());
-
-        // If we backtrack to this point, we have failed to match this iteration of the parens.
-        // Since this is greedy / zero minimum a failed is also accepted as a match!
-        context->term += term.atom.parenthesesWidth;
-        return true;
-    }
-
-    bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*)
-    {
-        // 'Terminal' parentheses are at the end of the regex, and as such a match past end
-        // should always be returned as a successful match - we should never backtrack to here.
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        backTrack->begin = input.getPos();
-        return true;
-    }
-
-    bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        input.setPos(backTrack->begin);
-
-        // We've reached the end of the parens; if they are inverted, this is failure.
-        if (term.invert()) {
-            context->term -= term.atom.parenthesesWidth;
-            return false;
-        }
-
-        return true;
-    }
-
-    bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
-        ASSERT(term.atom.quantityCount == 1);
-
-        // We've failed to match parens; if they are inverted, this is win!
-        if (term.invert()) {
-            context->term += term.atom.parenthesesWidth;
-            return true;
-        }
-
-        return false;
-    }
-
-    bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
-        ASSERT(term.atom.quantityCount == 1);
-
-        BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-
-        input.setPos(backTrack->begin);
-
-        context->term -= term.atom.parenthesesWidth;
-        return false;
-    }
-
-    JSRegExpResult matchParentheses(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
-
-        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
-
-        backTrack->matchAmount = 0;
-        backTrack->lastContext = 0;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            // While we haven't yet reached our fixed limit,
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                // Try to do a match, and it it succeeds, add it to the list.
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    // The match failed; try to find an alternate point to carry on from.
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result == JSRegExpNoMatch) {
-                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
-                        if (backtrackResult != JSRegExpMatch)
-                            return backtrackResult;
-                    } else
-                        return result;
-                }
-            }
-
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-            recordParenthesesMatch(term, context);
-            return JSRegExpMatch;
-        }
-
-        case QuantifierGreedy: {
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result != JSRegExpNoMatch)
-                        return result;
-
-                    break;
-                }
-            }
-
-            if (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                recordParenthesesMatch(term, context);
-            }
-            return JSRegExpMatch;
-        }
-
-        case QuantifierNonGreedy:
-            return JSRegExpMatch;
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    // Rules for backtracking differ depending on whether this is greedy or non-greedy.
-    //
-    // Greedy matches never should try just adding more - you should already have done
-    // the 'more' cases.  Always backtrack, at least a leetle bit.  However cases where
-    // you backtrack an item off the list needs checking, since we'll never have matched
-    // the one less case.  Tracking forwards, still add as much as possible.
-    //
-    // Non-greedy, we've already done the one less case, so don't match on popping.
-    // We haven't done the one more case, so always try to add that.
-    //
-    JSRegExpResult backtrackParentheses(ByteTerm& term, DisjunctionContext* context)
-    {
-        ASSERT(term.type == ByteTerm::TypeParenthesesSubpattern);
-
-        BackTrackInfoParentheses* backTrack = reinterpret_cast(context->frame + term.frameLocation);
-        ByteDisjunction* disjunctionBody = term.atom.parenthesesDisjunction;
-
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-
-            ParenthesesDisjunctionContext* context = 0;
-            JSRegExpResult result = parenthesesDoBacktrack(term, backTrack);
-
-            if (result != JSRegExpMatch)
-                return result;
-
-            // While we haven't yet reached our fixed limit,
-            while (backTrack->matchAmount < term.atom.quantityCount) {
-                // Try to do a match, and it it succeeds, add it to the list.
-                context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-
-                if (result == JSRegExpMatch)
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                else {
-                    // The match failed; try to find an alternate point to carry on from.
-                    resetMatches(term, context);
-                    freeParenthesesDisjunctionContext(context);
-
-                    if (result == JSRegExpNoMatch) {
-                        JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
-                        if (backtrackResult != JSRegExpMatch)
-                            return backtrackResult;
-                    } else
-                        return result;
-                }
-            }
-
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
-            context = backTrack->lastContext;
-            recordParenthesesMatch(term, context);
-            return JSRegExpMatch;
-        }
-
-        case QuantifierGreedy: {
-            if (!backTrack->matchAmount)
-                return JSRegExpNoMatch;
-
-            ParenthesesDisjunctionContext* context = backTrack->lastContext;
-            JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
-            if (result == JSRegExpMatch) {
-                while (backTrack->matchAmount < term.atom.quantityCount) {
-                    ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                    JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                    if (parenthesesResult == JSRegExpMatch)
-                        appendParenthesesDisjunctionContext(backTrack, context);
-                    else {
-                        resetMatches(term, context);
-                        freeParenthesesDisjunctionContext(context);
-
-                        if (parenthesesResult != JSRegExpNoMatch)
-                            return parenthesesResult;
-
-                        break;
-                    }
-                }
-            } else {
-                resetMatches(term, context);
-                popParenthesesDisjunctionContext(backTrack);
-                freeParenthesesDisjunctionContext(context);
-
-                if (result != JSRegExpNoMatch)
-                    return result;
-            }
-
-            if (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                recordParenthesesMatch(term, context);
-            }
-            return JSRegExpMatch;
-        }
-
-        case QuantifierNonGreedy: {
-            // If we've not reached the limit, try to add one more match.
-            if (backTrack->matchAmount < term.atom.quantityCount) {
-                ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch) {
-                    appendParenthesesDisjunctionContext(backTrack, context);
-                    recordParenthesesMatch(term, context);
-                    return JSRegExpMatch;
-                }
-
-                resetMatches(term, context);
-                freeParenthesesDisjunctionContext(context);
-
-                if (result != JSRegExpNoMatch)
-                    return result;
-            }
-
-            // Nope - okay backtrack looking for an alternative.
-            while (backTrack->matchAmount) {
-                ParenthesesDisjunctionContext* context = backTrack->lastContext;
-                JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
-                if (result == JSRegExpMatch) {
-                    // successful backtrack! we're back in the game!
-                    if (backTrack->matchAmount) {
-                        context = backTrack->lastContext;
-                        recordParenthesesMatch(term, context);
-                    }
-                    return JSRegExpMatch;
-                }
-
-                // pop a match off the stack
-                resetMatches(term, context);
-                popParenthesesDisjunctionContext(backTrack);
-                freeParenthesesDisjunctionContext(context);
-
-                return result;
-            }
-
-            return JSRegExpNoMatch;
-        }
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    void lookupForBeginChars()
-    {
-        int character;
-        bool firstSingleCharFound;
-
-        while (true) {
-            if (input.isNotAvailableInput(2))
-                return;
-
-            firstSingleCharFound = false;
-
-            character = input.readPair();
-
-            for (unsigned i = 0; i < pattern->m_beginChars.size(); ++i) {
-                BeginChar bc = pattern->m_beginChars[i];
-
-                if (!firstSingleCharFound && bc.value <= 0xFFFF) {
-                    firstSingleCharFound = true;
-                    character &= 0xFFFF;
-                }
-
-                if ((character | bc.mask) == bc.value)
-                    return;
-            }
-
-            input.next();
-        }
-    }
-
-#define MATCH_NEXT() { ++context->term; goto matchAgain; }
-#define BACKTRACK() { --context->term; goto backtrack; }
-#define currentTerm() (disjunction->terms[context->term])
-    JSRegExpResult matchDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false, bool isBody = false)
-    {
-        if (!--remainingMatchCount)
-            return JSRegExpErrorHitLimit;
-
-        if (btrack)
-            BACKTRACK();
-
-        if (pattern->m_containsBeginChars && isBody)
-            lookupForBeginChars();
-
-        context->matchBegin = input.getPos();
-        context->term = 0;
-
-    matchAgain:
-        ASSERT(context->term < static_cast(disjunction->terms.size()));
-
-        switch (currentTerm().type) {
-        case ByteTerm::TypeSubpatternBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeSubpatternEnd:
-            context->matchEnd = input.getPos();
-            return JSRegExpMatch;
-
-        case ByteTerm::TypeBodyAlternativeBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeBodyAlternativeDisjunction:
-        case ByteTerm::TypeBodyAlternativeEnd:
-            context->matchEnd = input.getPos();
-            return JSRegExpMatch;
-
-        case ByteTerm::TypeAlternativeBegin:
-            MATCH_NEXT();
-        case ByteTerm::TypeAlternativeDisjunction:
-        case ByteTerm::TypeAlternativeEnd: {
-            int offset = currentTerm().alternative.end;
-            BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->offset = offset;
-            context->term += offset;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypeAssertionBOL:
-            if (matchAssertionBOL(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeAssertionEOL:
-            if (matchAssertionEOL(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeAssertionWordBoundary:
-            if (matchAssertionWordBoundary(currentTerm()))
-                MATCH_NEXT();
-            BACKTRACK();
-
-        case ByteTerm::TypePatternCharacterOnce:
-        case ByteTerm::TypePatternCharacterFixed: {
-            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
-                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + matchAmount))
-                    BACKTRACK();
-            }
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCharacterGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            unsigned matchAmount = 0;
-            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCharacterNonGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->matchAmount = 0;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypePatternCasedCharacterOnce:
-        case ByteTerm::TypePatternCasedCharacterFixed: {
-            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
-                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + matchAmount))
-                    BACKTRACK();
-            }
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCasedCharacterGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            unsigned matchAmount = 0;
-            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
-                if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - 1)) {
-                    input.uncheckInput(1);
-                    break;
-                }
-                ++matchAmount;
-            }
-            backTrack->matchAmount = matchAmount;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypePatternCasedCharacterNonGreedy: {
-            BackTrackInfoPatternCharacter* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-            backTrack->matchAmount = 0;
-            MATCH_NEXT();
-        }
-
-        case ByteTerm::TypeCharacterClass:
-            if (matchCharacterClass(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeBackReference:
-            if (matchBackReference(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpattern: {
-            JSRegExpResult result = matchParentheses(currentTerm(), context);
-
-            if (result == JSRegExpMatch) {
-                MATCH_NEXT();
-            }  else if (result != JSRegExpNoMatch)
-                return result;
-
-            BACKTRACK();
-        }
-        case ByteTerm::TypeParenthesesSubpatternOnceBegin:
-            if (matchParenthesesOnceBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternOnceEnd:
-            if (matchParenthesesOnceEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
-            if (matchParenthesesTerminalBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
-            if (matchParenthesesTerminalEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParentheticalAssertionBegin:
-            if (matchParentheticalAssertionBegin(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-        case ByteTerm::TypeParentheticalAssertionEnd:
-            if (matchParentheticalAssertionEnd(currentTerm(), context))
-                MATCH_NEXT();
-            BACKTRACK();
-
-        case ByteTerm::TypeCheckInput:
-            if (input.checkInput(currentTerm().checkInputCount))
-                MATCH_NEXT();
-            BACKTRACK();
-
-            case ByteTerm::TypeUncheckInput:
-                input.uncheckInput(currentTerm().checkInputCount);
-                MATCH_NEXT();
-        }
-
-        // We should never fall-through to here.
-        ASSERT_NOT_REACHED();
-
-    backtrack:
-        ASSERT(context->term < static_cast(disjunction->terms.size()));
-
-        switch (currentTerm().type) {
-        case ByteTerm::TypeSubpatternBegin:
-            return JSRegExpNoMatch;
-        case ByteTerm::TypeSubpatternEnd:
-            ASSERT_NOT_REACHED();
-
-        case ByteTerm::TypeBodyAlternativeBegin:
-        case ByteTerm::TypeBodyAlternativeDisjunction: {
-            int offset = currentTerm().alternative.next;
-            context->term += offset;
-            if (offset > 0)
-                MATCH_NEXT();
-
-            if (input.atEnd())
-                return JSRegExpNoMatch;
-
-            input.next();
-
-            if (pattern->m_containsBeginChars && isBody)
-                lookupForBeginChars();
-
-            context->matchBegin = input.getPos();
-
-            if (currentTerm().alternative.onceThrough)
-                context->term += currentTerm().alternative.next;
-
-            MATCH_NEXT();
-        }
-        case ByteTerm::TypeBodyAlternativeEnd:
-            ASSERT_NOT_REACHED();
-
-            case ByteTerm::TypeAlternativeBegin:
-            case ByteTerm::TypeAlternativeDisjunction: {
-                int offset = currentTerm().alternative.next;
-                context->term += offset;
-                if (offset > 0)
-                    MATCH_NEXT();
-                BACKTRACK();
-            }
-            case ByteTerm::TypeAlternativeEnd: {
-                // We should never backtrack back into an alternative of the main body of the regex.
-                BackTrackInfoAlternative* backTrack = reinterpret_cast(context->frame + currentTerm().frameLocation);
-                unsigned offset = backTrack->offset;
-                context->term -= offset;
-                BACKTRACK();
-            }
-
-            case ByteTerm::TypeAssertionBOL:
-            case ByteTerm::TypeAssertionEOL:
-            case ByteTerm::TypeAssertionWordBoundary:
-                BACKTRACK();
-
-            case ByteTerm::TypePatternCharacterOnce:
-            case ByteTerm::TypePatternCharacterFixed:
-            case ByteTerm::TypePatternCharacterGreedy:
-            case ByteTerm::TypePatternCharacterNonGreedy:
-                if (backtrackPatternCharacter(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypePatternCasedCharacterOnce:
-            case ByteTerm::TypePatternCasedCharacterFixed:
-            case ByteTerm::TypePatternCasedCharacterGreedy:
-            case ByteTerm::TypePatternCasedCharacterNonGreedy:
-                if (backtrackPatternCasedCharacter(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeCharacterClass:
-                if (backtrackCharacterClass(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeBackReference:
-                if (backtrackBackReference(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpattern: {
-                JSRegExpResult result = backtrackParentheses(currentTerm(), context);
-
-                if (result == JSRegExpMatch) {
-                    MATCH_NEXT();
-                } else if (result != JSRegExpNoMatch)
-                    return result;
-
-                BACKTRACK();
-            }
-            case ByteTerm::TypeParenthesesSubpatternOnceBegin:
-                if (backtrackParenthesesOnceBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternOnceEnd:
-                if (backtrackParenthesesOnceEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
-                if (backtrackParenthesesTerminalBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
-                if (backtrackParenthesesTerminalEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParentheticalAssertionBegin:
-                if (backtrackParentheticalAssertionBegin(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-            case ByteTerm::TypeParentheticalAssertionEnd:
-                if (backtrackParentheticalAssertionEnd(currentTerm(), context))
-                    MATCH_NEXT();
-                BACKTRACK();
-
-            case ByteTerm::TypeCheckInput:
-                input.uncheckInput(currentTerm().checkInputCount);
-                BACKTRACK();
-
-            case ByteTerm::TypeUncheckInput:
-                input.checkInput(currentTerm().checkInputCount);
-                BACKTRACK();
-        }
-
-        ASSERT_NOT_REACHED();
-        return JSRegExpErrorNoMatch;
-    }
-
-    JSRegExpResult matchNonZeroDisjunction(ByteDisjunction* disjunction, DisjunctionContext* context, bool btrack = false)
-    {
-        JSRegExpResult result = matchDisjunction(disjunction, context, btrack);
-
-        if (result == JSRegExpMatch) {
-            while (context->matchBegin == context->matchEnd) {
-                result = matchDisjunction(disjunction, context, true);
-                if (result != JSRegExpMatch)
-                    return result;
-            }
-            return JSRegExpMatch;
-        }
-
-        return result;
-    }
-
-    int interpret()
-    {
-        allocatorPool = pattern->m_allocator->startAllocator();
-        if (!allocatorPool)
-            CRASH();
-
-        for (unsigned i = 0; i < ((pattern->m_body->m_numSubpatterns + 1) << 1); ++i)
-            output[i] = -1;
-
-        DisjunctionContext* context = allocDisjunctionContext(pattern->m_body.get());
-
-        JSRegExpResult result = matchDisjunction(pattern->m_body.get(), context, false, true);
-        if (result == JSRegExpMatch) {
-            output[0] = context->matchBegin;
-            output[1] = context->matchEnd;
-        }
-
-        freeDisjunctionContext(context);
-
-        pattern->m_allocator->stopAllocator();
-
-        // RegExp.cpp currently expects all error to be converted to -1.
-        ASSERT((result == JSRegExpMatch) == (output[0] != -1));
-        return output[0];
-    }
-
-    Interpreter(BytecodePattern* pattern, int* output, const UChar* inputChar, unsigned start, unsigned length)
-        : pattern(pattern)
-        , output(output)
-        , input(inputChar, start, length)
-        , allocatorPool(0)
-        , remainingMatchCount(matchLimit)
-    {
-    }
-
-private:
-    BytecodePattern* pattern;
-    int* output;
-    InputStream input;
-    BumpPointerPool* allocatorPool;
-    unsigned remainingMatchCount;
-};
-
-
-
-class ByteCompiler {
-    struct ParenthesesStackEntry {
-        unsigned beginTerm;
-        unsigned savedAlternativeIndex;
-        // For js::Vector. Does not create a valid object.
-        ParenthesesStackEntry() {}
-        ParenthesesStackEntry(unsigned beginTerm, unsigned savedAlternativeIndex/*, unsigned subpatternId, bool capture = false*/)
-            : beginTerm(beginTerm)
-            , savedAlternativeIndex(savedAlternativeIndex)
-        {
-        }
-    };
-
-public:
-    ByteCompiler(YarrPattern& pattern)
-        : m_pattern(pattern)
-    {
-        m_currentAlternativeIndex = 0;
-    }
-
-    PassOwnPtr compile(BumpPointerAllocator* allocator)
-    {
-        regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize, m_pattern.m_body->m_alternatives[0]->onceThrough());
-        emitDisjunction(m_pattern.m_body);
-        regexEnd();
-
-        return adoptPtr(js::OffTheBooks::new_(m_bodyDisjunction.release(), m_allParenthesesInfo, m_pattern, allocator));
-    }
-
-    void checkInput(unsigned count)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count));
-    }
-
-    void uncheckInput(unsigned count)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::UncheckInput(count));
-    }
-    
-    void assertionBOL(int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition));
-    }
-
-    void assertionEOL(int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition));
-    }
-
-    void assertionWordBoundary(bool invert, int inputPosition)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition));
-    }
-
-    void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        if (m_pattern.m_ignoreCase) {
-            UChar lo = Unicode::toLower(ch);
-            UChar hi = Unicode::toUpper(ch);
-
-            if (lo != hi) {
-                m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType));
-                return;
-            }
-        }
-
-        m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType));
-    }
-
-    void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition));
-
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-    }
-
-    void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        ASSERT(subpatternId);
-
-        m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition));
-
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin,
-        // then fix this up at the end! - simplifying this should make it much clearer.
-        // https://bugs.webkit.org/show_bug.cgi?id=50136
-
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation)
-    {
-        int beginTerm = m_bodyDisjunction->terms.size();
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, false, invert, 0));
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
-
-        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
-        m_currentAlternativeIndex = beginTerm + 1;
-    }
-
-    void atomParentheticalAssertionEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin);
-
-        bool invert = m_bodyDisjunction->terms[beginTerm].invert();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, false, invert, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    unsigned popParenthesesStack()
-    {
-        ASSERT(m_parenthesesStack.size());
-        int stackEnd = m_parenthesesStack.size() - 1;
-        unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm;
-        m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex;
-        m_parenthesesStack.shrink(stackEnd);
-
-        ASSERT(beginTerm < m_bodyDisjunction->terms.size());
-        ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size());
-
-        return beginTerm;
-    }
-
-#ifndef NDEBUG
-    void dumpDisjunction(ByteDisjunction* disjunction)
-    {
-        printf("ByteDisjunction(%p):\n\t", (void *) disjunction);
-        for (unsigned i = 0; i < disjunction->terms.size(); ++i)
-            printf("{ %d } ", disjunction->terms[i].type);
-        printf("\n");
-    }
-#endif
-
-    void closeAlternative(int beginTerm)
-    {
-        int origBeginTerm = beginTerm;
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin);
-        int endIndex = m_bodyDisjunction->terms.size();
-
-        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
-
-        if (!m_bodyDisjunction->terms[beginTerm].alternative.next)
-            m_bodyDisjunction->terms.remove(beginTerm);
-        else {
-            while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
-                beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
-                ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction);
-                m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
-                m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-            }
-
-            m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
-
-            m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd());
-            m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
-        }
-    }
-
-    void closeBodyAlternative()
-    {
-        int beginTerm = 0;
-        int origBeginTerm = 0;
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin);
-        int endIndex = m_bodyDisjunction->terms.size();
-
-        unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation;
-
-        while (m_bodyDisjunction->terms[beginTerm].alternative.next) {
-            beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next;
-            ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction);
-            m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm;
-            m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-        }
-
-        m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm;
-
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd());
-        m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-
-        ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
-
-        bool capture = parenthesesBegin.capture();
-        unsigned subpatternId = parenthesesBegin.atom.subpatternId;
-
-        unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
-        ByteDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(numSubpatterns, callFrameSize);
-
-        parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
-        for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
-            parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
-        parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
-
-        m_bodyDisjunction->terms.shrink(beginTerm);
-
-        m_allParenthesesInfo.append(parenthesesDisjunction);
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, inputPosition));
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
-    }
-
-    void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-
-        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-    {
-        unsigned beginTerm = popParenthesesStack();
-        closeAlternative(beginTerm + 1);
-        unsigned endTerm = m_bodyDisjunction->terms.size();
-
-        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
-
-        bool capture = m_bodyDisjunction->terms[beginTerm].capture();
-        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
-
-        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, capture, false, inputPosition));
-        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
-        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
-
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
-        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
-    }
-
-    void regexBegin(unsigned numSubpatterns, unsigned callFrameSize, bool onceThrough)
-    {
-        m_bodyDisjunction = adoptPtr(js::OffTheBooks::new_(numSubpatterns, callFrameSize));
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin(onceThrough));
-        m_bodyDisjunction->terms[0].frameLocation = 0;
-        m_currentAlternativeIndex = 0;
-    }
-
-    void regexEnd()
-    {
-        closeBodyAlternative();
-    }
-
-    void alternativeBodyDisjunction(bool onceThrough)
-    {
-        int newAlternativeIndex = m_bodyDisjunction->terms.size();
-        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
-        m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction(onceThrough));
-
-        m_currentAlternativeIndex = newAlternativeIndex;
-    }
-
-    void alternativeDisjunction()
-    {
-        int newAlternativeIndex = m_bodyDisjunction->terms.size();
-        m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex;
-        m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction());
-
-        m_currentAlternativeIndex = newAlternativeIndex;
-    }
-
-    void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0)
-    {
-        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
-            unsigned currentCountAlreadyChecked = inputCountAlreadyChecked;
-
-            PatternAlternative* alternative = disjunction->m_alternatives[alt];
-
-            if (alt) {
-                if (disjunction == m_pattern.m_body)
-                    alternativeBodyDisjunction(alternative->onceThrough());
-                else
-                    alternativeDisjunction();
-            }
-
-            unsigned minimumSize = alternative->m_minimumSize;
-            int countToCheck = minimumSize - parenthesesInputCountAlreadyChecked;
-
-            ASSERT(countToCheck >= 0);
-            if (countToCheck) {
-                checkInput(countToCheck);
-                currentCountAlreadyChecked += countToCheck;
-            }
-
-            for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
-                PatternTerm& term = alternative->m_terms[i];
-
-                switch (term.type) {
-                case PatternTerm::TypeAssertionBOL:
-                    assertionBOL(term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypeAssertionEOL:
-                    assertionEOL(term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypeAssertionWordBoundary:
-                    assertionWordBoundary(term.invert(), term.inputPosition - currentCountAlreadyChecked);
-                    break;
-
-                case PatternTerm::TypePatternCharacter:
-                    atomPatternCharacter(term.patternCharacter, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                    break;
-
-                case PatternTerm::TypeCharacterClass:
-                    atomCharacterClass(term.characterClass, term.invert(), term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                    break;
-
-                case PatternTerm::TypeBackReference:
-                    atomBackReference(term.backReferenceSubpatternId, term.inputPosition - currentCountAlreadyChecked, term.frameLocation, term.quantityCount, term.quantityType);
-                        break;
-
-                case PatternTerm::TypeForwardReference:
-                    break;
-
-                case PatternTerm::TypeParenthesesSubpattern: {
-                    unsigned disjunctionAlreadyCheckedCount = 0;
-                    if (term.quantityCount == 1 && !term.parentheses.isCopy) {
-                        unsigned alternativeFrameLocation = term.frameLocation;
-                        // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame.
-                        if (term.quantityType == QuantifierFixedCount)
-                            disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize;
-                        else
-                            alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, alternativeFrameLocation);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
-                        atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
-                    } else if (term.parentheses.isTerminal) {
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
-                        atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
-                    } else {
-                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
-                        atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0);
-                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
-                        atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
-                    }
-                    break;
-                }
-
-                case PatternTerm::TypeParentheticalAssertion: {
-                    unsigned alternativeFrameLocation = term.frameLocation + YarrStackSpaceForBackTrackInfoParentheticalAssertion;
-
-                    ASSERT(currentCountAlreadyChecked >= static_cast(term.inputPosition));
-                    int positiveInputOffset = currentCountAlreadyChecked - term.inputPosition;
-                    int uncheckAmount = positiveInputOffset - term.parentheses.disjunction->m_minimumSize;
-
-                    if (uncheckAmount > 0) {
-                        uncheckInput(uncheckAmount);
-                        currentCountAlreadyChecked -= uncheckAmount;
-                    } else
-                        uncheckAmount = 0;
-
-                    atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation);
-                    emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount);
-                    atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType);
-                    if (uncheckAmount) {
-                        checkInput(uncheckAmount);
-                        currentCountAlreadyChecked += uncheckAmount;
-                    }
-                    break;
-                }
-                }
-            }
-        }
-    }
-
-private:
-    YarrPattern& m_pattern;
-    OwnPtr m_bodyDisjunction;
-    unsigned m_currentAlternativeIndex;
-    Vector m_parenthesesStack;
-    Vector m_allParenthesesInfo;
-};
-
-PassOwnPtr byteCompile(YarrPattern& pattern, BumpPointerAllocator* allocator)
-{
-    return ByteCompiler(pattern).compile(allocator);
-}
-
-int interpret(BytecodePattern* bytecode, const UChar* input, unsigned start, unsigned length, int* output)
-{
-    return Interpreter(bytecode, output, input, start, length).interpret();
-}
-
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoPatternCharacter) == (YarrStackSpaceForBackTrackInfoPatternCharacter * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoPatternCharacter);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoCharacterClass) == (YarrStackSpaceForBackTrackInfoCharacterClass * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoCharacterClass);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoBackReference) == (YarrStackSpaceForBackTrackInfoBackReference * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoBackReference);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce);
-COMPILE_ASSERT(sizeof(Interpreter::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);
-
-
-} }
diff --git a/js/src/yarr/YarrInterpreter.h b/js/src/yarr/YarrInterpreter.h
deleted file mode 100644
index 32b72858cad1..000000000000
--- a/js/src/yarr/YarrInterpreter.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/* -*- 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, 2010 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef YarrInterpreter_h
-#define YarrInterpreter_h
-
-#include "YarrPattern.h"
-
-namespace WTF {
-class BumpPointerAllocator;
-}
-using WTF::BumpPointerAllocator;
-
-namespace JSC { namespace Yarr {
-
-class ByteDisjunction;
-
-struct ByteTerm {
-    enum Type {
-        TypeBodyAlternativeBegin,
-        TypeBodyAlternativeDisjunction,
-        TypeBodyAlternativeEnd,
-        TypeAlternativeBegin,
-        TypeAlternativeDisjunction,
-        TypeAlternativeEnd,
-        TypeSubpatternBegin,
-        TypeSubpatternEnd,
-        TypeAssertionBOL,
-        TypeAssertionEOL,
-        TypeAssertionWordBoundary,
-        TypePatternCharacterOnce,
-        TypePatternCharacterFixed,
-        TypePatternCharacterGreedy,
-        TypePatternCharacterNonGreedy,
-        TypePatternCasedCharacterOnce,
-        TypePatternCasedCharacterFixed,
-        TypePatternCasedCharacterGreedy,
-        TypePatternCasedCharacterNonGreedy,
-        TypeCharacterClass,
-        TypeBackReference,
-        TypeParenthesesSubpattern,
-        TypeParenthesesSubpatternOnceBegin,
-        TypeParenthesesSubpatternOnceEnd,
-        TypeParenthesesSubpatternTerminalBegin,
-        TypeParenthesesSubpatternTerminalEnd,
-        TypeParentheticalAssertionBegin,
-        TypeParentheticalAssertionEnd,
-        TypeCheckInput,
-        TypeUncheckInput
-    } type;
-    union {
-        struct {
-            union {
-                UChar patternCharacter;
-                struct {
-                    UChar lo;
-                    UChar hi;
-                } casedCharacter;
-                CharacterClass* characterClass;
-                unsigned subpatternId;
-            };
-            union {
-                ByteDisjunction* parenthesesDisjunction;
-                unsigned parenthesesWidth;
-            };
-            QuantifierType quantityType;
-            unsigned quantityCount;
-        } atom;
-        struct {
-            int next;
-            int end;
-            bool onceThrough;
-        } alternative;
-        unsigned checkInputCount;
-    };
-    unsigned frameLocation;
-    bool m_capture : 1;
-    bool m_invert : 1;
-    int inputPosition;
-
-    // For js::Vector. Does not create a valid object.
-    ByteTerm()
-    {
-    }
-
-    ByteTerm(UChar ch, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-        : frameLocation(frameLocation)
-        , m_capture(false)
-        , m_invert(false)
-    {
-        switch (quantityType) {
-        case QuantifierFixedCount:
-            type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed;
-            break;
-        case QuantifierGreedy:
-            type = ByteTerm::TypePatternCharacterGreedy;
-            break;
-        case QuantifierNonGreedy:
-            type = ByteTerm::TypePatternCharacterNonGreedy;
-            break;
-        }
-
-        atom.patternCharacter = ch;
-        atom.quantityType = quantityType;
-        atom.quantityCount = quantityCount;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(UChar lo, UChar hi, int inputPos, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
-        : frameLocation(frameLocation)
-        , m_capture(false)
-        , m_invert(false)
-    {
-        switch (quantityType) {
-        case QuantifierFixedCount:
-            type = (quantityCount == 1) ? ByteTerm::TypePatternCasedCharacterOnce : ByteTerm::TypePatternCasedCharacterFixed;
-            break;
-        case QuantifierGreedy:
-            type = ByteTerm::TypePatternCasedCharacterGreedy;
-            break;
-        case QuantifierNonGreedy:
-            type = ByteTerm::TypePatternCasedCharacterNonGreedy;
-            break;
-        }
-
-        atom.casedCharacter.lo = lo;
-        atom.casedCharacter.hi = hi;
-        atom.quantityType = quantityType;
-        atom.quantityCount = quantityCount;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(CharacterClass* characterClass, bool invert, int inputPos)
-        : type(ByteTerm::TypeCharacterClass)
-        , m_capture(false)
-        , m_invert(invert)
-    {
-        atom.characterClass = characterClass;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-
-    ByteTerm(Type type, unsigned subpatternId, ByteDisjunction* parenthesesInfo, bool capture, int inputPos)
-        : type(type)
-        , m_capture(capture)
-        , m_invert(false)
-    {
-        atom.subpatternId = subpatternId;
-        atom.parenthesesDisjunction = parenthesesInfo;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-    
-    ByteTerm(Type type, bool invert = false)
-        : type(type)
-        , m_capture(false)
-        , m_invert(invert)
-    {
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-    }
-
-    ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, int inputPos)
-        : type(type)
-        , m_capture(capture)
-        , m_invert(invert)
-    {
-        atom.subpatternId = subpatternId;
-        atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
-        inputPosition = inputPos;
-    }
-
-    static ByteTerm BOL(int inputPos)
-    {
-        ByteTerm term(TypeAssertionBOL);
-        term.inputPosition = inputPos;
-        return term;
-    }
-
-    static ByteTerm CheckInput(unsigned count)
-    {
-        ByteTerm term(TypeCheckInput);
-        term.checkInputCount = count;
-        return term;
-    }
-
-    static ByteTerm UncheckInput(unsigned count)
-    {
-        ByteTerm term(TypeUncheckInput);
-        term.checkInputCount = count;
-        return term;
-    }
-    
-    static ByteTerm EOL(int inputPos)
-    {
-        ByteTerm term(TypeAssertionEOL);
-        term.inputPosition = inputPos;
-        return term;
-    }
-
-    static ByteTerm WordBoundary(bool invert, int inputPos)
-    {
-        ByteTerm term(TypeAssertionWordBoundary, invert);
-        term.inputPosition = inputPos;
-        return term;
-    }
-    
-    static ByteTerm BackReference(unsigned subpatternId, int inputPos)
-    {
-        return ByteTerm(TypeBackReference, subpatternId, false, false, inputPos);
-    }
-
-    static ByteTerm BodyAlternativeBegin(bool onceThrough)
-    {
-        ByteTerm term(TypeBodyAlternativeBegin);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = onceThrough;
-        return term;
-    }
-
-    static ByteTerm BodyAlternativeDisjunction(bool onceThrough)
-    {
-        ByteTerm term(TypeBodyAlternativeDisjunction);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = onceThrough;
-        return term;
-    }
-
-    static ByteTerm BodyAlternativeEnd()
-    {
-        ByteTerm term(TypeBodyAlternativeEnd);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeBegin()
-    {
-        ByteTerm term(TypeAlternativeBegin);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeDisjunction()
-    {
-        ByteTerm term(TypeAlternativeDisjunction);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm AlternativeEnd()
-    {
-        ByteTerm term(TypeAlternativeEnd);
-        term.alternative.next = 0;
-        term.alternative.end = 0;
-        term.alternative.onceThrough = false;
-        return term;
-    }
-
-    static ByteTerm SubpatternBegin()
-    {
-        return ByteTerm(TypeSubpatternBegin);
-    }
-
-    static ByteTerm SubpatternEnd()
-    {
-        return ByteTerm(TypeSubpatternEnd);
-    }
-
-    bool invert()
-    {
-        return m_invert;
-    }
-
-    bool capture()
-    {
-        return m_capture;
-    }
-};
-
-class ByteDisjunction {
-    WTF_MAKE_FAST_ALLOCATED
-public:
-    ByteDisjunction(unsigned numSubpatterns, unsigned frameSize)
-        : m_numSubpatterns(numSubpatterns)
-        , m_frameSize(frameSize)
-    {
-    }
-
-    Vector terms;
-    unsigned m_numSubpatterns;
-    unsigned m_frameSize;
-};
-
-struct BytecodePattern {
-    WTF_MAKE_FAST_ALLOCATED
-public:
-    BytecodePattern(PassOwnPtr body, Vector allParenthesesInfo, YarrPattern& pattern, BumpPointerAllocator* allocator)
-        : m_body(body)
-        , m_ignoreCase(pattern.m_ignoreCase)
-        , m_multiline(pattern.m_multiline)
-        , m_containsBeginChars(pattern.m_containsBeginChars)
-        , m_allocator(allocator)
-    {
-        newlineCharacterClass = pattern.newlineCharacterClass();
-        wordcharCharacterClass = pattern.wordcharCharacterClass();
-
-        m_allParenthesesInfo.append(allParenthesesInfo);
-        m_userCharacterClasses.append(pattern.m_userCharacterClasses);
-        // 'Steal' the YarrPattern's CharacterClasses!  We clear its
-        // array, so that it won't delete them on destruction.  We'll
-        // take responsibility for that.
-        pattern.m_userCharacterClasses.clear();
-
-        m_beginChars.append(pattern.m_beginChars);
-    }
-
-    ~BytecodePattern()
-    {
-        deleteAllValues(m_allParenthesesInfo);
-        deleteAllValues(m_userCharacterClasses);
-    }
-
-    OwnPtr m_body;
-    bool m_ignoreCase;
-    bool m_multiline;
-    bool m_containsBeginChars;
-    // Each BytecodePattern is associated with a RegExp, each RegExp is associated
-    // with a JSGlobalData.  Cache a pointer to out JSGlobalData's m_regExpAllocator.
-    BumpPointerAllocator* m_allocator;
-
-    CharacterClass* newlineCharacterClass;
-    CharacterClass* wordcharCharacterClass;
-
-    Vector m_beginChars;
-
-private:
-    Vector m_allParenthesesInfo;
-    Vector m_userCharacterClasses;
-};
-
-} } // namespace JSC::Yarr
-
-#endif // YarrInterpreter_h
diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp
deleted file mode 100644
index c0187f240b6d..000000000000
--- a/js/src/yarr/YarrJIT.cpp
+++ /dev/null
@@ -1,2405 +0,0 @@
-/* -*- 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.
- *
- * 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "YarrJIT.h"
-
-#include "assembler/assembler/LinkBuffer.h"
-#include "Yarr.h"
-
-#if ENABLE_YARR_JIT
-
-using namespace WTF;
-
-namespace JSC { namespace Yarr {
-
-class YarrGenerator : private MacroAssembler {
-    friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
-
-#if WTF_CPU_ARM
-    static const RegisterID input = ARMRegisters::r0;
-    static const RegisterID index = ARMRegisters::r1;
-    static const RegisterID length = ARMRegisters::r2;
-    static const RegisterID output = ARMRegisters::r4;
-
-    static const RegisterID regT0 = ARMRegisters::r5;
-    static const RegisterID regT1 = ARMRegisters::r6;
-
-    static const RegisterID returnRegister = ARMRegisters::r0;
-#elif WTF_CPU_MIPS
-    static const RegisterID input = MIPSRegisters::a0;
-    static const RegisterID index = MIPSRegisters::a1;
-    static const RegisterID length = MIPSRegisters::a2;
-    static const RegisterID output = MIPSRegisters::a3;
-
-    static const RegisterID regT0 = MIPSRegisters::t4;
-    static const RegisterID regT1 = MIPSRegisters::t5;
-
-    static const RegisterID returnRegister = MIPSRegisters::v0;
-#elif WTF_CPU_SH4
-    static const RegisterID input = SH4Registers::r4;
-    static const RegisterID index = SH4Registers::r5;
-    static const RegisterID length = SH4Registers::r6;
-    static const RegisterID output = SH4Registers::r7;
-
-    static const RegisterID regT0 = SH4Registers::r0;
-    static const RegisterID regT1 = SH4Registers::r1;
-
-    static const RegisterID returnRegister = SH4Registers::r0;
-#elif WTF_CPU_X86
-    static const RegisterID input = X86Registers::eax;
-    static const RegisterID index = X86Registers::edx;
-    static const RegisterID length = X86Registers::ecx;
-    static const RegisterID output = X86Registers::edi;
-
-    static const RegisterID regT0 = X86Registers::ebx;
-    static const RegisterID regT1 = X86Registers::esi;
-
-    static const RegisterID returnRegister = X86Registers::eax;
-#elif WTF_CPU_X86_64
-    static const RegisterID input = X86Registers::edi;
-    static const RegisterID index = X86Registers::esi;
-    static const RegisterID length = X86Registers::edx;
-    static const RegisterID output = X86Registers::ecx;
-
-    static const RegisterID regT0 = X86Registers::eax;
-    static const RegisterID regT1 = X86Registers::ebx;
-
-    static const RegisterID returnRegister = X86Registers::eax;
-#endif
-
-    void optimizeAlternative(PatternAlternative* alternative)
-    {
-        if (!alternative->m_terms.size())
-            return;
-
-        for (unsigned i = 0; i < alternative->m_terms.size() - 1; ++i) {
-            PatternTerm& term = alternative->m_terms[i];
-            PatternTerm& nextTerm = alternative->m_terms[i + 1];
-
-            if ((term.type == PatternTerm::TypeCharacterClass)
-                && (term.quantityType == QuantifierFixedCount)
-                && (nextTerm.type == PatternTerm::TypePatternCharacter)
-                && (nextTerm.quantityType == QuantifierFixedCount)) {
-                PatternTerm termCopy = term;
-                alternative->m_terms[i] = nextTerm;
-                alternative->m_terms[i + 1] = termCopy;
-            }
-        }
-    }
-
-    void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount)
-    {
-        do {
-            // pick which range we're going to generate
-            int which = count >> 1;
-            char lo = ranges[which].begin;
-            char hi = ranges[which].end;
-
-            // check if there are any ranges or matches below lo.  If not, just jl to failure -
-            // if there is anything else to check, check that first, if it falls through jmp to failure.
-            if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
-                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
-
-                // generate code for all ranges before this one
-                if (which)
-                    matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
-
-                while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) {
-                    matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex])));
-                    ++*matchIndex;
-                }
-                failures.append(jump());
-
-                loOrAbove.link(this);
-            } else if (which) {
-                Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo));
-
-                matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount);
-                failures.append(jump());
-
-                loOrAbove.link(this);
-            } else
-                failures.append(branch32(LessThan, character, Imm32((unsigned short)lo)));
-
-            while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi))
-                ++*matchIndex;
-
-            matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi)));
-            // fall through to here, the value is above hi.
-
-            // shuffle along & loop around if there are any more matches to handle.
-            unsigned next = which + 1;
-            ranges += next;
-            count -= next;
-        } while (count);
-    }
-
-    void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass)
-    {
-        if (charClass->m_table) {
-            ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table));
-            matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry));
-            return;
-        }
-        Jump unicodeFail;
-        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size()) {
-            Jump isAscii = branch32(LessThanOrEqual, character, TrustedImm32(0x7f));
-
-            if (charClass->m_matchesUnicode.size()) {
-                for (unsigned i = 0; i < charClass->m_matchesUnicode.size(); ++i) {
-                    UChar ch = charClass->m_matchesUnicode[i];
-                    matchDest.append(branch32(Equal, character, Imm32(ch)));
-                }
-            }
-
-            if (charClass->m_rangesUnicode.size()) {
-                for (unsigned i = 0; i < charClass->m_rangesUnicode.size(); ++i) {
-                    UChar lo = charClass->m_rangesUnicode[i].begin;
-                    UChar hi = charClass->m_rangesUnicode[i].end;
-
-                    Jump below = branch32(LessThan, character, Imm32(lo));
-                    matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi)));
-                    below.link(this);
-                }
-            }
-
-            unicodeFail = jump();
-            isAscii.link(this);
-        }
-
-        if (charClass->m_ranges.size()) {
-            unsigned matchIndex = 0;
-            JumpList failures;
-            matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.size(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.size());
-            while (matchIndex < charClass->m_matches.size())
-                matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++])));
-
-            failures.link(this);
-        } else if (charClass->m_matches.size()) {
-            // optimization: gather 'a','A' etc back together, can mask & test once.
-            Vector matchesAZaz;
-
-            for (unsigned i = 0; i < charClass->m_matches.size(); ++i) {
-                char ch = charClass->m_matches[i];
-                if (m_pattern.m_ignoreCase) {
-                    if (isASCIILower(ch)) {
-                        matchesAZaz.append(ch);
-                        continue;
-                    }
-                    if (isASCIIUpper(ch))
-                        continue;
-                }
-                matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch)));
-            }
-
-            if (unsigned countAZaz = matchesAZaz.size()) {
-                or32(TrustedImm32(32), character);
-                for (unsigned i = 0; i < countAZaz; ++i)
-                    matchDest.append(branch32(Equal, character, TrustedImm32(matchesAZaz[i])));
-            }
-        }
-
-        if (charClass->m_matchesUnicode.size() || charClass->m_rangesUnicode.size())
-            unicodeFail.link(this);
-    }
-
-    // Jumps if input not available; will have (incorrectly) incremented already!
-    Jump jumpIfNoAvailableInput(unsigned countToCheck = 0)
-    {
-        if (countToCheck)
-            add32(Imm32(countToCheck), index);
-        return branch32(Above, index, length);
-    }
-
-    Jump jumpIfAvailableInput(unsigned countToCheck)
-    {
-        add32(Imm32(countToCheck), index);
-        return branch32(BelowOrEqual, index, length);
-    }
-
-    Jump checkInput()
-    {
-        return branch32(BelowOrEqual, index, length);
-    }
-
-    Jump atEndOfInput()
-    {
-        return branch32(Equal, index, length);
-    }
-
-    Jump notAtEndOfInput()
-    {
-        return branch32(NotEqual, index, length);
-    }
-
-    Jump jumpIfCharEquals(UChar ch, int inputPosition)
-    {
-        return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
-    }
-
-    Jump jumpIfCharNotEquals(UChar ch, int inputPosition)
-    {
-        return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch));
-    }
-
-    void readCharacter(int inputPosition, RegisterID reg)
-    {
-        load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg);
-    }
-
-    void storeToFrame(RegisterID reg, unsigned frameLocation)
-    {
-        poke(reg, frameLocation);
-    }
-
-    void storeToFrame(TrustedImm32 imm, unsigned frameLocation)
-    {
-        poke(imm, frameLocation);
-    }
-
-    DataLabelPtr storeToFrameWithPatch(unsigned frameLocation)
-    {
-        return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*)));
-    }
-
-    void loadFromFrame(unsigned frameLocation, RegisterID reg)
-    {
-        peek(reg, frameLocation);
-    }
-
-    void loadFromFrameAndJump(unsigned frameLocation)
-    {
-        jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
-    }
-
-    enum YarrOpCode {
-        // These nodes wrap body alternatives - those in the main disjunction,
-        // rather than subpatterns or assertions. These are chained together in
-        // a doubly linked list, with a 'begin' node for the first alternative,
-        // a 'next' node for each subsequent alternative, and an 'end' node at
-        // the end. In the case of repeating alternatives, the 'end' node also
-        // has a reference back to 'begin'.
-        OpBodyAlternativeBegin,
-        OpBodyAlternativeNext,
-        OpBodyAlternativeEnd,
-        // Similar to the body alternatives, but used for subpatterns with two
-        // or more alternatives.
-        OpNestedAlternativeBegin,
-        OpNestedAlternativeNext,
-        OpNestedAlternativeEnd,
-        // Used for alternatives in subpatterns where there is only a single
-        // alternative (backtrackingis easier in these cases), or for alternatives
-        // which never need to be backtracked (those in parenthetical assertions,
-        // terminal subpatterns).
-        OpSimpleNestedAlternativeBegin,
-        OpSimpleNestedAlternativeNext,
-        OpSimpleNestedAlternativeEnd,
-        // Used to wrap 'Once' subpattern matches (quantityCount == 1).
-        OpParenthesesSubpatternOnceBegin,
-        OpParenthesesSubpatternOnceEnd,
-        // Used to wrap 'Terminal' subpattern matches (at the end of the regexp).
-        OpParenthesesSubpatternTerminalBegin,
-        OpParenthesesSubpatternTerminalEnd,
-        // Used to wrap parenthetical assertions.
-        OpParentheticalAssertionBegin,
-        OpParentheticalAssertionEnd,
-        // Wraps all simple terms (pattern characters, character classes).
-        OpTerm,
-        // Where an expression contains only 'once through' body alternatives
-        // and no repeating ones, this op is used to return match failure.
-        OpMatchFailed
-    };
-
-    // This structure is used to hold the compiled opcode information,
-    // including reference back to the original PatternTerm/PatternAlternatives,
-    // and JIT compilation data structures.
-    struct YarrOp {
-        explicit YarrOp(PatternTerm* term)
-            : m_op(OpTerm)
-            , m_term(term)
-            , m_isDeadCode(false)
-        {
-        }
-
-        explicit YarrOp(YarrOpCode op)
-            : m_op(op)
-            , m_isDeadCode(false)
-        {
-        }
-
-        // The operation, as a YarrOpCode, and also a reference to the PatternTerm.
-        YarrOpCode m_op;
-        PatternTerm* m_term;
-
-        // For alternatives, this holds the PatternAlternative and doubly linked
-        // references to this alternative's siblings. In the case of the
-        // OpBodyAlternativeEnd node at the end of a section of repeating nodes,
-        // m_nextOp will reference the OpBodyAlternativeBegin node of the first
-        // repeating alternative.
-        PatternAlternative* m_alternative;
-        size_t m_previousOp;
-        size_t m_nextOp;
-
-        // Used to record a set of Jumps out of the generated code, typically
-        // used for jumps out to backtracking code, and a single reentry back
-        // into the code for a node (likely where a backtrack will trigger
-        // rematching).
-        Label m_reentry;
-        JumpList m_jumps;
-
-        // This flag is used to null out the second pattern character, when
-        // two are fused to match a pair together.
-        bool m_isDeadCode;
-
-        // Currently used in the case of some of the more complex management of
-        // 'm_checked', to cache the offset used in this alternative, to avoid
-        // recalculating it.
-        int m_checkAdjust;
-
-        // Used by OpNestedAlternativeNext/End to hold the pointer to the
-        // value that will be pushed into the pattern's frame to return to,
-        // upon backtracking back into the disjunction.
-        DataLabelPtr m_returnAddress;
-    };
-
-    // BacktrackingState
-    // This class encapsulates information about the state of code generation
-    // whilst generating the code for backtracking, when a term fails to match.
-    // Upon entry to code generation of the backtracking code for a given node,
-    // the Backtracking state will hold references to all control flow sources
-    // that are outputs in need of further backtracking from the prior node
-    // generated (which is the subsequent operation in the regular expression,
-    // and in the m_ops Vector, since we generated backtracking backwards).
-    // These references to control flow take the form of:
-    //  - A jump list of jumps, to be linked to code that will backtrack them
-    //    further.
-    //  - A set of DataLabelPtr values, to be populated with values to be
-    //    treated effectively as return addresses backtracking into complex
-    //    subpatterns.
-    //  - A flag indicating that the current sequence of generated code up to
-    //    this point requires backtracking.
-    class BacktrackingState {
-    public:
-        BacktrackingState()
-            : m_pendingFallthrough(false)
-        {
-        }
-
-        // Add a jump or jumps, a return address, or set the flag indicating
-        // that the current 'fallthrough' control flow requires backtracking.
-        void append(const Jump& jump)
-        {
-            m_laterFailures.append(jump);
-        }
-        void append(JumpList& jumpList)
-        {
-            m_laterFailures.append(jumpList);
-        }
-        void append(const DataLabelPtr& returnAddress)
-        {
-            m_pendingReturns.append(returnAddress);
-        }
-        void fallthrough()
-        {
-            ASSERT(!m_pendingFallthrough);
-            m_pendingFallthrough = true;
-        }
-
-        // These methods clear the backtracking state, either linking to the
-        // current location, a provided label, or copying the backtracking out
-        // to a JumpList. All actions may require code generation to take place,
-        // and as such are passed a pointer to the assembler.
-        void link(MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                Label here(assembler);
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
-                m_pendingReturns.clear();
-            }
-            m_laterFailures.link(assembler);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-        void linkTo(Label label, MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], label));
-                m_pendingReturns.clear();
-            }
-            if (m_pendingFallthrough)
-                assembler->jump(label);
-            m_laterFailures.linkTo(label, assembler);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-        void takeBacktracksToJumpList(JumpList& jumpList, MacroAssembler* assembler)
-        {
-            if (m_pendingReturns.size()) {
-                Label here(assembler);
-                for (unsigned i = 0; i < m_pendingReturns.size(); ++i)
-                    m_backtrackRecords.append(ReturnAddressRecord(m_pendingReturns[i], here));
-                m_pendingReturns.clear();
-                m_pendingFallthrough = true;
-            }
-            if (m_pendingFallthrough)
-                jumpList.append(assembler->jump());
-            jumpList.append(m_laterFailures);
-            m_laterFailures.clear();
-            m_pendingFallthrough = false;
-        }
-
-        bool isEmpty()
-        {
-            return m_laterFailures.empty() && m_pendingReturns.isEmpty() && !m_pendingFallthrough;
-        }
-
-        // Called at the end of code generation to link all return addresses.
-        void linkDataLabels(LinkBuffer& linkBuffer)
-        {
-            ASSERT(isEmpty());
-            for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
-                linkBuffer.patch(m_backtrackRecords[i].m_dataLabel, linkBuffer.locationOf(m_backtrackRecords[i].m_backtrackLocation));
-        }
-
-    private:
-        struct ReturnAddressRecord {
-            ReturnAddressRecord(DataLabelPtr dataLabel, Label backtrackLocation)
-                : m_dataLabel(dataLabel)
-                , m_backtrackLocation(backtrackLocation)
-            {
-            }
-
-            DataLabelPtr m_dataLabel;
-            Label m_backtrackLocation;
-        };
-
-        JumpList m_laterFailures;
-        bool m_pendingFallthrough;
-        Vector m_pendingReturns;
-        Vector m_backtrackRecords;
-    };
-
-    // Generation methods:
-    // ===================
-
-    // This method provides a default implementation of backtracking common
-    // to many terms; terms commonly jump out of the forwards  matching path
-    // on any failed conditions, and add these jumps to the m_jumps list. If
-    // no special handling is required we can often just backtrack to m_jumps.
-    void backtrackTermDefault(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        m_backtrackingState.append(op.m_jumps);
-    }
-
-    void generateAssertionBOL(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        if (m_pattern.m_multiline) {
-            const RegisterID character = regT0;
-
-            JumpList matchDest;
-            if (!term->inputPosition)
-                matchDest.append(branch32(Equal, index, Imm32(m_checked)));
-
-            readCharacter((term->inputPosition - m_checked) - 1, character);
-            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
-            op.m_jumps.append(jump());
-
-            matchDest.link(this);
-        } else {
-            // Erk, really should poison out these alternatives early. :-/
-            if (term->inputPosition)
-                op.m_jumps.append(jump());
-            else
-                op.m_jumps.append(branch32(NotEqual, index, Imm32(m_checked)));
-        }
-    }
-    void backtrackAssertionBOL(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateAssertionEOL(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        if (m_pattern.m_multiline) {
-            const RegisterID character = regT0;
-
-            JumpList matchDest;
-            if (term->inputPosition == m_checked)
-                matchDest.append(atEndOfInput());
-
-            readCharacter((term->inputPosition - m_checked), character);
-            matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass());
-            op.m_jumps.append(jump());
-
-            matchDest.link(this);
-        } else {
-            if (term->inputPosition == m_checked)
-                op.m_jumps.append(notAtEndOfInput());
-            // Erk, really should poison out these alternatives early. :-/
-            else
-                op.m_jumps.append(jump());
-        }
-    }
-    void backtrackAssertionEOL(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    // Also falls though on nextIsNotWordChar.
-    void matchAssertionWordchar(size_t opIndex, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        if (term->inputPosition == m_checked)
-            nextIsNotWordChar.append(atEndOfInput());
-
-        readCharacter((term->inputPosition - m_checked), character);
-        matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass());
-    }
-
-    void generateAssertionWordBoundary(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        Jump atBegin;
-        JumpList matchDest;
-        if (!term->inputPosition)
-            atBegin = branch32(Equal, index, Imm32(m_checked));
-        readCharacter((term->inputPosition - m_checked) - 1, character);
-        matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass());
-        if (!term->inputPosition)
-            atBegin.link(this);
-
-        // We fall through to here if the last character was not a wordchar.
-        JumpList nonWordCharThenWordChar;
-        JumpList nonWordCharThenNonWordChar;
-        if (term->invert()) {
-            matchAssertionWordchar(opIndex, nonWordCharThenNonWordChar, nonWordCharThenWordChar);
-            nonWordCharThenWordChar.append(jump());
-        } else {
-            matchAssertionWordchar(opIndex, nonWordCharThenWordChar, nonWordCharThenNonWordChar);
-            nonWordCharThenNonWordChar.append(jump());
-        }
-        op.m_jumps.append(nonWordCharThenNonWordChar);
-
-        // We jump here if the last character was a wordchar.
-        matchDest.link(this);
-        JumpList wordCharThenWordChar;
-        JumpList wordCharThenNonWordChar;
-        if (term->invert()) {
-            matchAssertionWordchar(opIndex, wordCharThenNonWordChar, wordCharThenWordChar);
-            wordCharThenWordChar.append(jump());
-        } else {
-            matchAssertionWordchar(opIndex, wordCharThenWordChar, wordCharThenNonWordChar);
-            // This can fall-though!
-        }
-
-        op.m_jumps.append(wordCharThenWordChar);
-
-        nonWordCharThenWordChar.link(this);
-        wordCharThenNonWordChar.link(this);
-    }
-    void backtrackAssertionWordBoundary(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterOnce(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-
-        // m_ops always ends with a OpBodyAlternativeEnd or OpMatchFailed
-        // node, so there must always be at least one more node.
-        ASSERT(opIndex + 1 < m_ops.size());
-        YarrOp& nextOp = m_ops[opIndex + 1];
-
-        if (op.m_isDeadCode)
-            return;
-
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-
-        if (nextOp.m_op == OpTerm) {
-            PatternTerm* nextTerm = nextOp.m_term;
-            if (nextTerm->type == PatternTerm::TypePatternCharacter
-                && nextTerm->quantityType == QuantifierFixedCount
-                && nextTerm->quantityCount == 1
-                && nextTerm->inputPosition == (term->inputPosition + 1)) {
-
-                UChar ch2 = nextTerm->patternCharacter;
-
-                int mask = 0;
-                int chPair = ch | (ch2 << 16);
-
-                if (m_pattern.m_ignoreCase) {
-                    if (isASCIIAlpha(ch))
-                        mask |= 32;
-                    if (isASCIIAlpha(ch2))
-                        mask |= 32 << 16;
-                }
-
-                BaseIndex address(input, index, TimesTwo, (term->inputPosition - m_checked) * sizeof(UChar));
-                if (mask) {
-                    load32WithUnalignedHalfWords(address, character);
-                    or32(Imm32(mask), character);
-                    op.m_jumps.append(branch32(NotEqual, character, Imm32(chPair | mask)));
-                } else
-                    op.m_jumps.append(branch32WithUnalignedHalfWords(NotEqual, address, Imm32(chPair)));
-
-                nextOp.m_isDeadCode = true;
-                return;
-            }
-        }
-
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            op.m_jumps.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-    }
-    void backtrackPatternCharacterOnce(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterFixed(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(index, countRegister);
-        sub32(Imm32(term->quantityCount), countRegister);
-
-        Label loop(this);
-        BaseIndex address(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar));
-
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            load16(address, character);
-            or32(TrustedImm32(32), character);
-            op.m_jumps.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            op.m_jumps.append(branch16(NotEqual, address, Imm32(ch)));
-        }
-        add32(TrustedImm32(1), countRegister);
-        branch32(NotEqual, countRegister, index).linkTo(loop, this);
-    }
-    void backtrackPatternCharacterFixed(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generatePatternCharacterGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-
-        JumpList failures;
-        Label loop(this);
-        failures.append(atEndOfInput());
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            failures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-        if (term->quantityCount == quantifyInfinite)
-            jump(loop);
-        else
-            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
-
-        failures.link(this);
-        op.m_reentry = label();
-
-        storeToFrame(countRegister, term->frameLocation);
-
-    }
-    void backtrackPatternCharacterGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-        m_backtrackingState.append(branchTest32(Zero, countRegister));
-        sub32(TrustedImm32(1), countRegister);
-        sub32(TrustedImm32(1), index);
-        jump(op.m_reentry);
-    }
-
-    void generatePatternCharacterNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-        op.m_reentry = label();
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackPatternCharacterNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-        UChar ch = term->patternCharacter;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        JumpList nonGreedyFailures;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-
-        nonGreedyFailures.append(atEndOfInput());
-        if (term->quantityCount != quantifyInfinite)
-            nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
-        if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) {
-            readCharacter(term->inputPosition - m_checked, character);
-            or32(TrustedImm32(32), character);
-            nonGreedyFailures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))));
-        } else {
-            ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch)));
-            nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked));
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-
-        jump(op.m_reentry);
-
-        nonGreedyFailures.link(this);
-        sub32(countRegister, index);
-        m_backtrackingState.fallthrough();
-    }
-
-    void generateCharacterClassOnce(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-
-        JumpList matchDest;
-        readCharacter((term->inputPosition - m_checked), character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            op.m_jumps.append(matchDest);
-        else {
-            op.m_jumps.append(jump());
-            matchDest.link(this);
-        }
-    }
-    void backtrackCharacterClassOnce(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateCharacterClassFixed(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(index, countRegister);
-        sub32(Imm32(term->quantityCount), countRegister);
-
-        Label loop(this);
-        JumpList matchDest;
-        load16(BaseIndex(input, countRegister, TimesTwo, (term->inputPosition - m_checked + term->quantityCount) * sizeof(UChar)), character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            op.m_jumps.append(matchDest);
-        else {
-            op.m_jumps.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        branch32(NotEqual, countRegister, index).linkTo(loop, this);
-    }
-    void backtrackCharacterClassFixed(size_t opIndex)
-    {
-        backtrackTermDefault(opIndex);
-    }
-
-    void generateCharacterClassGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-
-        JumpList failures;
-        Label loop(this);
-        failures.append(atEndOfInput());
-
-        if (term->invert()) {
-            readCharacter(term->inputPosition - m_checked, character);
-            matchCharacterClass(character, failures, term->characterClass);
-        } else {
-            JumpList matchDest;
-            readCharacter(term->inputPosition - m_checked, character);
-            matchCharacterClass(character, matchDest, term->characterClass);
-            failures.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-        if (term->quantityCount != quantifyInfinite) {
-            branch32(NotEqual, countRegister, Imm32(term->quantityCount)).linkTo(loop, this);
-            failures.append(jump());
-        } else
-            jump(loop);
-
-        failures.link(this);
-        op.m_reentry = label();
-
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackCharacterClassGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        m_backtrackingState.link(this);
-
-        loadFromFrame(term->frameLocation, countRegister);
-        m_backtrackingState.append(branchTest32(Zero, countRegister));
-        sub32(TrustedImm32(1), countRegister);
-        sub32(TrustedImm32(1), index);
-        jump(op.m_reentry);
-    }
-
-    void generateCharacterClassNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID countRegister = regT1;
-
-        move(TrustedImm32(0), countRegister);
-        op.m_reentry = label();
-        storeToFrame(countRegister, term->frameLocation);
-    }
-    void backtrackCharacterClassNonGreedy(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        const RegisterID character = regT0;
-        const RegisterID countRegister = regT1;
-
-        JumpList nonGreedyFailures;
-
-        m_backtrackingState.link(this);
-
-        Label backtrackBegin(this);
-        loadFromFrame(term->frameLocation, countRegister);
-
-        nonGreedyFailures.append(atEndOfInput());
-        nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount)));
-
-        JumpList matchDest;
-        readCharacter(term->inputPosition - m_checked, character);
-        matchCharacterClass(character, matchDest, term->characterClass);
-
-        if (term->invert())
-            nonGreedyFailures.append(matchDest);
-        else {
-            nonGreedyFailures.append(jump());
-            matchDest.link(this);
-        }
-
-        add32(TrustedImm32(1), countRegister);
-        add32(TrustedImm32(1), index);
-
-        jump(op.m_reentry);
-
-        nonGreedyFailures.link(this);
-        sub32(countRegister, index);
-        m_backtrackingState.fallthrough();
-    }
-
-    // Code generation/backtracking for simple terms
-    // (pattern characters, character classes, and assertions).
-    // These methods farm out work to the set of functions above.
-    void generateTerm(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        switch (term->type) {
-        case PatternTerm::TypePatternCharacter:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    generatePatternCharacterOnce(opIndex);
-                else
-                    generatePatternCharacterFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                generatePatternCharacterGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                generatePatternCharacterNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeCharacterClass:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    generateCharacterClassOnce(opIndex);
-                else
-                    generateCharacterClassFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                generateCharacterClassGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                generateCharacterClassNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeAssertionBOL:
-            generateAssertionBOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionEOL:
-            generateAssertionEOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionWordBoundary:
-            generateAssertionWordBoundary(opIndex);
-            break;
-
-        case PatternTerm::TypeForwardReference:
-            break;
-
-        case PatternTerm::TypeParenthesesSubpattern:
-        case PatternTerm::TypeParentheticalAssertion:
-            ASSERT_NOT_REACHED();
-        case PatternTerm::TypeBackReference:
-            m_shouldFallBack = true;
-            break;
-        }
-    }
-    void backtrackTerm(size_t opIndex)
-    {
-        YarrOp& op = m_ops[opIndex];
-        PatternTerm* term = op.m_term;
-
-        switch (term->type) {
-        case PatternTerm::TypePatternCharacter:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    backtrackPatternCharacterOnce(opIndex);
-                else
-                    backtrackPatternCharacterFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                backtrackPatternCharacterGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                backtrackPatternCharacterNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeCharacterClass:
-            switch (term->quantityType) {
-            case QuantifierFixedCount:
-                if (term->quantityCount == 1)
-                    backtrackCharacterClassOnce(opIndex);
-                else
-                    backtrackCharacterClassFixed(opIndex);
-                break;
-            case QuantifierGreedy:
-                backtrackCharacterClassGreedy(opIndex);
-                break;
-            case QuantifierNonGreedy:
-                backtrackCharacterClassNonGreedy(opIndex);
-                break;
-            }
-            break;
-
-        case PatternTerm::TypeAssertionBOL:
-            backtrackAssertionBOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionEOL:
-            backtrackAssertionEOL(opIndex);
-            break;
-
-        case PatternTerm::TypeAssertionWordBoundary:
-            backtrackAssertionWordBoundary(opIndex);
-            break;
-
-        case PatternTerm::TypeForwardReference:
-            break;
-
-        case PatternTerm::TypeParenthesesSubpattern:
-        case PatternTerm::TypeParentheticalAssertion:
-            ASSERT_NOT_REACHED();
-        case PatternTerm::TypeBackReference:
-            m_shouldFallBack = true;
-            break;
-        }
-    }
-
-    void generate()
-    {
-        // Forwards generate the matching code.
-        ASSERT(m_ops.size());
-        size_t opIndex = 0;
-
-        do {
-            YarrOp& op = m_ops[opIndex];
-            switch (op.m_op) {
-
-            case OpTerm:
-                generateTerm(opIndex);
-                break;
-
-            // OpBodyAlternativeBegin/Next/End
-            //
-            // These nodes wrap the set of alternatives in the body of the regular expression.
-            // There may be either one or two chains of OpBodyAlternative nodes, one representing
-            // the 'once through' sequence of alternatives (if any exist), and one representing
-            // the repeating alternatives (again, if any exist).
-            //
-            // Upon normal entry to the Begin alternative, we will check that input is available.
-            // Reentry to the Begin alternative will take place after the check has taken place,
-            // and will assume that the input position has already been progressed as appropriate.
-            //
-            // Entry to subsequent Next/End alternatives occurs when the prior alternative has
-            // successfully completed a match - return a success state from JIT code.
-            //
-            // Next alternatives allow for reentry optimized to suit backtracking from its
-            // preceding alternative. It expects the input position to still be set to a position
-            // appropriate to its predecessor, and it will only perform an input check if the
-            // predecessor had a minimum size less than its own.
-            //
-            // In the case 'once through' expressions, the End node will also have a reentry
-            // point to jump to when the last alternative fails. Again, this expects the input
-            // position to still reflect that expected by the prior alternative.
-            case OpBodyAlternativeBegin: {
-                PatternAlternative* alternative = op.m_alternative;
-
-                // Upon entry at the head of the set of alternatives, check if input is available
-                // to run the first alternative. (This progresses the input position).
-                op.m_jumps.append(jumpIfNoAvailableInput(alternative->m_minimumSize));
-                // We will reenter after the check, and assume the input position to have been
-                // set as appropriate to this alternative.
-                op.m_reentry = label();
-
-                m_checked += alternative->m_minimumSize;
-                break;
-            }
-            case OpBodyAlternativeNext:
-            case OpBodyAlternativeEnd: {
-                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                PatternAlternative* alternative = op.m_alternative;
-
-                // If we get here, the prior alternative matched - return success.
-                
-                // Adjust the stack pointer to remove the pattern's frame.
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-
-                // Load appropriate values into the return register and the first output
-                // slot, and return. In the case of pattern with a fixed size, we will
-                // not have yet set the value in the first 
-                ASSERT(index != returnRegister);
-                if (m_pattern.m_body->m_hasFixedSize) {
-                    move(index, returnRegister);
-                    if (priorAlternative->m_minimumSize)
-                        sub32(Imm32(priorAlternative->m_minimumSize), returnRegister);
-                    store32(returnRegister, output);
-                } else
-                    load32(Address(output), returnRegister);
-                store32(index, Address(output, 4));
-                generateReturn();
-
-                // This is the divide between the tail of the prior alternative, above, and
-                // the head of the subsequent alternative, below.
-
-                if (op.m_op == OpBodyAlternativeNext) {
-                    // This is the reentry point for the Next alternative. We expect any code
-                    // that jumps here to do so with the input position matching that of the
-                    // PRIOR alteranative, and we will only check input availability if we
-                    // need to progress it forwards.
-                    op.m_reentry = label();
-                    if (int delta = alternative->m_minimumSize - priorAlternative->m_minimumSize) {
-                        add32(Imm32(delta), index);
-                        if (delta > 0)
-                            op.m_jumps.append(jumpIfNoAvailableInput());
-                    }
-                } else if (op.m_nextOp == notFound) {
-                    // This is the reentry point for the End of 'once through' alternatives,
-                    // jumped to when the las alternative fails to match.
-                    op.m_reentry = label();
-                    sub32(Imm32(priorAlternative->m_minimumSize), index);
-                }
-
-                if (op.m_op == OpBodyAlternativeNext)
-                    m_checked += alternative->m_minimumSize;
-                m_checked -= priorAlternative->m_minimumSize;
-                break;
-            }
-
-            // OpSimpleNestedAlternativeBegin/Next/End
-            // OpNestedAlternativeBegin/Next/End
-            //
-            // These nodes are used to handle sets of alternatives that are nested within
-            // subpatterns and parenthetical assertions. The 'simple' forms are used where
-            // we do not need to be able to backtrack back into any alternative other than
-            // the last, the normal forms allow backtracking into any alternative.
-            //
-            // Each Begin/Next node is responsible for planting an input check to ensure
-            // sufficient input is available on entry. Next nodes additionally need to
-            // jump to the end - Next nodes use the End node's m_jumps list to hold this
-            // set of jumps.
-            //
-            // In the non-simple forms, successful alternative matches must store a
-            // 'return address' using a DataLabelPtr, used to store the address to jump
-            // to when backtracking, to get to the code for the appropriate alternative.
-            case OpSimpleNestedAlternativeBegin:
-            case OpNestedAlternativeBegin: {
-                PatternTerm* term = op.m_term;
-                PatternAlternative* alternative = op.m_alternative;
-                PatternDisjunction* disjunction = term->parentheses.disjunction;
-
-                // Calculate how much input we need to check for, and if non-zero check.
-                op.m_checkAdjust = alternative->m_minimumSize;
-                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
-                    op.m_checkAdjust -= disjunction->m_minimumSize;
-                if (op.m_checkAdjust)
-                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
- 
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeNext:
-            case OpNestedAlternativeNext: {
-                PatternTerm* term = op.m_term;
-                PatternAlternative* alternative = op.m_alternative;
-                PatternDisjunction* disjunction = term->parentheses.disjunction;
-
-                // In the non-simple case, store a 'return address' so we can backtrack correctly.
-                if (op.m_op == OpNestedAlternativeNext) {
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
-                }
-
-                // If we reach here then the last alternative has matched - jump to the
-                // End node, to skip over any further alternatives.
-                //
-                // FIXME: this is logically O(N^2) (though N can be expected to be very
-                // small). We could avoid this either by adding an extra jump to the JIT
-                // data structures, or by making backtracking code that jumps to Next
-                // alternatives are responsible for checking that input is available (if
-                // we didn't need to plant the input checks, then m_jumps would be free).
-                YarrOp* endOp = &m_ops[op.m_nextOp];
-                while (endOp->m_nextOp != notFound) {
-                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
-                    endOp = &m_ops[endOp->m_nextOp];
-                }
-                ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
-                endOp->m_jumps.append(jump());
-
-                // This is the entry point for the next alternative.
-                op.m_reentry = label();
-
-                // Calculate how much input we need to check for, and if non-zero check.
-                op.m_checkAdjust = alternative->m_minimumSize;
-                if ((term->quantityType == QuantifierFixedCount) && (term->type != PatternTerm::TypeParentheticalAssertion))
-                    op.m_checkAdjust -= disjunction->m_minimumSize;
-                if (op.m_checkAdjust)
-                    op.m_jumps.append(jumpIfNoAvailableInput(op.m_checkAdjust));
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeEnd:
-            case OpNestedAlternativeEnd: {
-                PatternTerm* term = op.m_term;
-
-                // In the non-simple case, store a 'return address' so we can backtrack correctly.
-                if (op.m_op == OpNestedAlternativeEnd) {
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
-                }
-
-                // If this set of alternatives contains more than one alternative,
-                // then the Next nodes will have planted jumps to the End, and added
-                // them to this node's m_jumps list.
-                op.m_jumps.link(this);
-                op.m_jumps.clear();
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                break;
-            }
-
-            // OpParenthesesSubpatternOnceBegin/End
-            //
-            // These nodes support (optionally) capturing subpatterns, that have a
-            // quantity count of 1 (this covers fixed once, and ?/?? quantifiers). 
-            case OpParenthesesSubpatternOnceBegin: {
-                PatternTerm* term = op.m_term;
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                const RegisterID indexTemporary = regT0;
-                ASSERT(term->quantityCount == 1);
-
-                // Upon entry to a Greedy quantified set of parenthese store the index.
-                // We'll use this for two purposes:
-                //  - To indicate which iteration we are on of mathing the remainder of
-                //    the expression after the parentheses - the first, including the
-                //    match within the parentheses, or the second having skipped over them.
-                //  - To check for empty matches, which must be rejected.
-                //
-                // At the head of a NonGreedy set of parentheses we'll immediately set the
-                // value on the stack to -1 (indicating a match skipping the subpattern),
-                // and plant a jump to the end. We'll also plant a label to backtrack to
-                // to reenter the subpattern later, with a store to set up index on the
-                // second iteration.
-                //
-                // FIXME: for capturing parens, could use the index in the capture array?
-                if (term->quantityType == QuantifierGreedy)
-                    storeToFrame(index, parenthesesFrameLocation);
-                else if (term->quantityType == QuantifierNonGreedy) {
-                    storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
-                    op.m_jumps.append(jump());
-                    op.m_reentry = label();
-                    storeToFrame(index, parenthesesFrameLocation);
-                }
-
-                // If the parenthese are capturing, store the starting index value to the
-                // captures array, offsetting as necessary.
-                //
-                // FIXME: could avoid offsetting this value in JIT code, apply
-                // offsets only afterwards, at the point the results array is
-                // being accessed.
-                if (term->capture()) {
-                    int offsetId = term->parentheses.subpatternId << 1;
-                    int inputOffset = term->inputPosition - m_checked;
-                    if (term->quantityType == QuantifierFixedCount)
-                        inputOffset -= term->parentheses.disjunction->m_minimumSize;
-                    if (inputOffset) {
-                        move(index, indexTemporary);
-                        add32(Imm32(inputOffset), indexTemporary);
-                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
-                    } else
-                        store32(index, Address(output, offsetId * sizeof(int)));
-                }
-                break;
-            }
-            case OpParenthesesSubpatternOnceEnd: {
-                PatternTerm* term = op.m_term;
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                const RegisterID indexTemporary = regT0;
-                ASSERT(term->quantityCount == 1);
-
-                // For Greedy/NonGreedy quantified parentheses, we must reject zero length
-                // matches. If the minimum size is know to be non-zero we need not check.
-                if (term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize)
-                    op.m_jumps.append(branch32(Equal, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*))));
-
-                // If the parenthese are capturing, store the ending index value to the
-                // captures array, offsetting as necessary.
-                //
-                // FIXME: could avoid offsetting this value in JIT code, apply
-                // offsets only afterwards, at the point the results array is
-                // being accessed.
-                if (term->capture()) {
-                    int offsetId = (term->parentheses.subpatternId << 1) + 1;
-                    int inputOffset = term->inputPosition - m_checked;
-                    if (inputOffset) {
-                        move(index, indexTemporary);
-                        add32(Imm32(inputOffset), indexTemporary);
-                        store32(indexTemporary, Address(output, offsetId * sizeof(int)));
-                    } else
-                        store32(index, Address(output, offsetId * sizeof(int)));
-                }
-
-                // If the parentheses are quantified Greedy then add a label to jump back
-                // to if get a failed match from after the parentheses. For NonGreedy
-                // parentheses, link the jump from before the subpattern to here.
-                if (term->quantityType == QuantifierGreedy)
-                    op.m_reentry = label();
-                else if (term->quantityType == QuantifierNonGreedy) {
-                    YarrOp& beginOp = m_ops[op.m_previousOp];
-                    beginOp.m_jumps.link(this);
-                }
-                break;
-            }
-
-            // OpParenthesesSubpatternTerminalBegin/End
-            case OpParenthesesSubpatternTerminalBegin: {
-                PatternTerm* term = op.m_term;
-                ASSERT(term->quantityType == QuantifierGreedy);
-                ASSERT(term->quantityCount == quantifyInfinite);
-                ASSERT(!term->capture());
-
-                // Upon entry set a label to loop back to.
-                op.m_reentry = label();
-
-                // Store the start index of the current match; we need to reject zero
-                // length matches.
-                storeToFrame(index, term->frameLocation);
-                break;
-            }
-            case OpParenthesesSubpatternTerminalEnd: {
-                PatternTerm* term = op.m_term;
-
-                // Check for zero length matches - if the match is non-zero, then we
-                // can accept it & loop back up to the head of the subpattern.
-                YarrOp& beginOp = m_ops[op.m_previousOp];
-                branch32(NotEqual, index, Address(stackPointerRegister, term->frameLocation * sizeof(void*)), beginOp.m_reentry);
-
-                // Reject the match - backtrack back into the subpattern.
-                op.m_jumps.append(jump());
-
-                // This is the entry point to jump to when we stop matching - we will
-                // do so once the subpattern cannot match any more.
-                op.m_reentry = label();
-                break;
-            }
-
-            // OpParentheticalAssertionBegin/End
-            case OpParentheticalAssertionBegin: {
-                PatternTerm* term = op.m_term;
-
-                // Store the current index - assertions should not update index, so
-                // we will need to restore it upon a successful match.
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                storeToFrame(index, parenthesesFrameLocation);
-
-                // Check 
-                op.m_checkAdjust = m_checked - term->inputPosition;
-                if (op.m_checkAdjust)
-                    sub32(Imm32(op.m_checkAdjust), index);
-
-                m_checked -= op.m_checkAdjust;
-                break;
-            }
-            case OpParentheticalAssertionEnd: {
-                PatternTerm* term = op.m_term;
-
-                // Restore the input index value.
-                unsigned parenthesesFrameLocation = term->frameLocation;
-                loadFromFrame(parenthesesFrameLocation, index);
-
-                // If inverted, a successful match of the assertion must be treated
-                // as a failure, so jump to backtracking.
-                if (term->invert()) {
-                    op.m_jumps.append(jump());
-                    op.m_reentry = label();
-                }
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked += lastOp.m_checkAdjust;
-                break;
-            }
-
-            case OpMatchFailed:
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-                move(TrustedImm32(-1), returnRegister);
-                generateReturn();
-                break;
-            }
-
-            ++opIndex;
-        } while (opIndex < m_ops.size());
-    }
-
-    void backtrack()
-    {
-        // Backwards generate the backtracking code.
-        size_t opIndex = m_ops.size();
-        ASSERT(opIndex);
-
-        do {
-            --opIndex;
-            YarrOp& op = m_ops[opIndex];
-            switch (op.m_op) {
-
-            case OpTerm:
-                backtrackTerm(opIndex);
-                break;
-
-            // OpBodyAlternativeBegin/Next/End
-            //
-            // For each Begin/Next node representing an alternative, we need to decide what to do
-            // in two circumstances:
-            //  - If we backtrack back into this node, from within the alternative.
-            //  - If the input check at the head of the alternative fails (if this exists).
-            //
-            // We treat these two cases differently since in the former case we have slightly
-            // more information - since we are backtracking out of a prior alternative we know
-            // that at least enough input was available to run it. For example, given the regular
-            // expression /a|b/, if we backtrack out of the first alternative (a failed pattern
-            // character match of 'a'), then we need not perform an additional input availability
-            // check before running the second alternative.
-            //
-            // Backtracking required differs for the last alternative, which in the case of the
-            // repeating set of alternatives must loop. The code generated for the last alternative
-            // will also be used to handle all input check failures from any prior alternatives -
-            // these require similar functionality, in seeking the next available alternative for
-            // which there is sufficient input.
-            //
-            // Since backtracking of all other alternatives simply requires us to link backtracks
-            // to the reentry point for the subsequent alternative, we will only be generating any
-            // code when backtracking the last alternative.
-            case OpBodyAlternativeBegin:
-            case OpBodyAlternativeNext: {
-                PatternAlternative* alternative = op.m_alternative;
-
-                if (op.m_op == OpBodyAlternativeNext) {
-                    PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                    m_checked += priorAlternative->m_minimumSize;
-                }
-                m_checked -= alternative->m_minimumSize;
-
-                // Is this the last alternative? If not, then if we backtrack to this point we just
-                // need to jump to try to match the next alternative.
-                if (m_ops[op.m_nextOp].m_op != OpBodyAlternativeEnd) {
-                    m_backtrackingState.linkTo(m_ops[op.m_nextOp].m_reentry, this);
-                    break;
-                }
-                YarrOp& endOp = m_ops[op.m_nextOp];
-
-                YarrOp* beginOp = &op;
-                while (beginOp->m_op != OpBodyAlternativeBegin) {
-                    ASSERT(beginOp->m_op == OpBodyAlternativeNext);
-                    beginOp = &m_ops[beginOp->m_previousOp];
-                }
-
-                bool onceThrough = endOp.m_nextOp == notFound;
-
-                // First, generate code to handle cases where we backtrack out of an attempted match
-                // of the last alternative. If this is a 'once through' set of alternatives then we
-                // have nothing to do - link this straight through to the End.
-                if (onceThrough)
-                    m_backtrackingState.linkTo(endOp.m_reentry, this);
-                else {
-                    // Okay, we're going to need to loop. Calculate the delta between where the input
-                    // position was, and where we want it to be allowing for the fact that we need to
-                    // increment by 1. E.g. for the regexp /a|x/ we need to increment the position by
-                    // 1 between loop iterations, but for /abcd|xyz/ we need to increment by two when
-                    // looping from the last alternative to the first, for /a|xyz/ we need to decrement
-                    // by 1, and for /a|xy/ we don't need to move the input position at all.
-                    int deltaLastAlternativeToFirstAlternativePlusOne = (beginOp->m_alternative->m_minimumSize - alternative->m_minimumSize) + 1;
-
-                    // If we don't need to move the input poistion, and the pattern has a fixed size
-                    // (in which case we omit the store of the start index until the pattern has matched)
-                    // then we can just link the backtrack out of the last alternative straight to the
-                    // head of the first alternative.
-                    if (!deltaLastAlternativeToFirstAlternativePlusOne && m_pattern.m_body->m_hasFixedSize)
-                        m_backtrackingState.linkTo(beginOp->m_reentry, this);
-                    else {
-                        // We need to generate a trampoline of code to execute before looping back
-                        // around to the first alternative.
-                        m_backtrackingState.link(this);
-
-                        // If the pattern size is not fixed, then store the start index, for use if we match.
-                        if (!m_pattern.m_body->m_hasFixedSize) {
-                            if (alternative->m_minimumSize == 1)
-                                store32(index, Address(output));
-                            else {
-                                move(index, regT0);
-                                if (alternative->m_minimumSize)
-                                    sub32(Imm32(alternative->m_minimumSize - 1), regT0);
-                                else
-                                    add32(Imm32(1), regT0);
-                                store32(regT0, Address(output));
-                            }
-                        }
-
-                        if (deltaLastAlternativeToFirstAlternativePlusOne)
-                            add32(Imm32(deltaLastAlternativeToFirstAlternativePlusOne), index);
-
-                        // Loop. Since this code is only reached when we backtrack out of the last
-                        // alternative (and NOT linked to from the input check upon entry to the
-                        // last alternative) we know that there must be at least enough input as
-                        // required by the last alternative. As such, we only need to check if the
-                        // first will require more to run - if the same or less is required we can
-                        // unconditionally jump.
-                        if (deltaLastAlternativeToFirstAlternativePlusOne > 0)
-                            checkInput().linkTo(beginOp->m_reentry, this);
-                        else
-                            jump(beginOp->m_reentry);
-                    }
-                }
-
-                // We can reach this point in the code in two ways:
-                //  - Fallthrough from the code above (a repeating alternative backtracked out of its
-                //    last alternative, and did not have sufficent input to run the first).
-                //  - We will loop back up to the following label when a releating alternative loops,
-                //    following a failed input check.
-                //
-                // Either way, we have just failed the input check for the first alternative.
-                Label firstInputCheckFailed(this);
-
-                // Generate code to handle input check failures from alternatives except the last.
-                // prevOp is the alternative we're handling a bail out from (initially Begin), and
-                // nextOp is the alternative we will be attempting to reenter into.
-                // 
-                // We will link input check failures from the forwards matching path back to the code
-                // that can handle them.
-                YarrOp* prevOp = beginOp;
-                YarrOp* nextOp = &m_ops[beginOp->m_nextOp];
-                while (nextOp->m_op != OpBodyAlternativeEnd) {
-                    prevOp->m_jumps.link(this);
-
-                    int delta = nextOp->m_alternative->m_minimumSize - prevOp->m_alternative->m_minimumSize;
-                    if (delta)
-                        add32(Imm32(delta), index);
-
-                    // We only get here if an input check fails, it is only worth checking again
-                    // if the next alternative has a minimum size less than the last.
-                    if (delta < 0) {
-                        // FIXME: if we added an extra label to YarrOp, we could avoid needing to
-                        // subtract delta back out, and reduce this code. Should performance test
-                        // the benefit of this.
-                        Jump fail = jumpIfNoAvailableInput();
-                        sub32(Imm32(delta), index);
-                        jump(nextOp->m_reentry);
-                        fail.link(this);
-                    }
-                    prevOp = nextOp;
-                    nextOp = &m_ops[nextOp->m_nextOp];
-                }
-
-                // We fall through to here if there is insufficient input to run the last alternative.
-
-                // If there is insufficient input to run the last alternative, then for 'once through'
-                // alternatives we are done - just jump back up into the forwards matching path at the End.
-                if (onceThrough) {
-                    op.m_jumps.linkTo(endOp.m_reentry, this);
-                    jump(endOp.m_reentry);
-                    break;
-                }
-
-                // For repeating alternatives, link any input check failure from the last alternative to
-                // this point.
-                op.m_jumps.link(this);
-
-                bool needsToUpdateMatchStart = !m_pattern.m_body->m_hasFixedSize;
-
-                // Check for cases where input position is already incremented by 1 for the last
-                // alternative (this is particularly useful where the minimum size of the body
-                // disjunction is 0, e.g. /a*|b/).
-                if (needsToUpdateMatchStart && alternative->m_minimumSize == 1) {
-                    // index is already incremented by 1, so just store it now!
-                    store32(index, Address(output));
-                    needsToUpdateMatchStart = false;
-                }
-
-                // Check whether there is sufficient input to loop. Increment the input position by
-                // one, and check. Also add in the minimum disjunction size before checking - there
-                // is no point in looping if we're just going to fail all the input checks around
-                // the next iteration.
-                int deltaLastAlternativeToBodyMinimumPlusOne = (m_pattern.m_body->m_minimumSize + 1) - alternative->m_minimumSize;
-                if (deltaLastAlternativeToBodyMinimumPlusOne)
-                    add32(Imm32(deltaLastAlternativeToBodyMinimumPlusOne), index);
-                Jump matchFailed = jumpIfNoAvailableInput();
-
-                if (needsToUpdateMatchStart) {
-                    if (!m_pattern.m_body->m_minimumSize)
-                        store32(index, Address(output));
-                    else {
-                        move(index, regT0);
-                        sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0);
-                        store32(regT0, Address(output));
-                    }
-                }
-
-                // Calculate how much more input the first alternative requires than the minimum
-                // for the body as a whole. If no more is needed then we dont need an additional
-                // input check here - jump straight back up to the start of the first alternative.
-                int deltaBodyMinimumToFirstAlternative = beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize;
-                if (!deltaBodyMinimumToFirstAlternative)
-                    jump(beginOp->m_reentry);
-                else {
-                    add32(Imm32(deltaBodyMinimumToFirstAlternative), index);
-                    checkInput().linkTo(beginOp->m_reentry, this);
-                    jump(firstInputCheckFailed);
-                }
-
-                // We jump to here if we iterate to the point that there is insufficient input to
-                // run any matches, and need to return a failure state from JIT code.
-                matchFailed.link(this);
-
-                if (m_pattern.m_body->m_callFrameSize)
-                    addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-                move(TrustedImm32(-1), returnRegister);
-                generateReturn();
-                break;
-            }
-            case OpBodyAlternativeEnd: {
-                // We should never backtrack back into a body disjunction.
-                ASSERT(m_backtrackingState.isEmpty());
-
-                PatternAlternative* priorAlternative = m_ops[op.m_previousOp].m_alternative;
-                m_checked += priorAlternative->m_minimumSize;
-                break;
-            }
-
-            // OpSimpleNestedAlternativeBegin/Next/End
-            // OpNestedAlternativeBegin/Next/End
-            //
-            // Generate code for when we backtrack back out of an alternative into
-            // a Begin or Next node, or when the entry input count check fails. If
-            // there are more alternatives we need to jump to the next alternative,
-            // if not we backtrack back out of the current set of parentheses.
-            //
-            // In the case of non-simple nested assertions we need to also link the
-            // 'return address' appropriately to backtrack back out into the correct
-            // alternative.
-            case OpSimpleNestedAlternativeBegin:
-            case OpSimpleNestedAlternativeNext:
-            case OpNestedAlternativeBegin:
-            case OpNestedAlternativeNext: {
-                YarrOp& nextOp = m_ops[op.m_nextOp];
-                bool isBegin = op.m_previousOp == notFound;
-                bool isLastAlternative = nextOp.m_nextOp == notFound;
-                ASSERT(isBegin == (op.m_op == OpSimpleNestedAlternativeBegin || op.m_op == OpNestedAlternativeBegin));
-                ASSERT(isLastAlternative == (nextOp.m_op == OpSimpleNestedAlternativeEnd || nextOp.m_op == OpNestedAlternativeEnd));
-
-                // Treat an input check failure the same as a failed match.
-                m_backtrackingState.append(op.m_jumps);
-
-                // Set the backtracks to jump to the appropriate place. We may need
-                // to link the backtracks in one of three different way depending on
-                // the type of alternative we are dealing with:
-                //  - A single alternative, with no simplings.
-                //  - The last alternative of a set of two or more.
-                //  - An alternative other than the last of a set of two or more.
-                //
-                // In the case of a single alternative on its own, we don't need to
-                // jump anywhere - if the alternative fails to match we can just
-                // continue to backtrack out of the parentheses without jumping.
-                //
-                // In the case of the last alternative in a set of more than one, we
-                // need to jump to return back out to the beginning. We'll do so by
-                // adding a jump to the End node's m_jumps list, and linking this
-                // when we come to generate the Begin node. For alternatives other
-                // than the last, we need to jump to the next alternative.
-                //
-                // If the alternative had adjusted the input position we must link
-                // backtracking to here, correct, and then jump on. If not we can
-                // link the backtracks directly to their destination.
-                if (op.m_checkAdjust) {
-                    // Handle the cases where we need to link the backtracks here.
-                    m_backtrackingState.link(this);
-                    sub32(Imm32(op.m_checkAdjust), index);
-                    if (!isLastAlternative) {
-                        // An alternative that is not the last should jump to its successor.
-                        jump(nextOp.m_reentry);
-                    } else if (!isBegin) {
-                        // The last of more than one alternatives must jump back to the begnning.
-                        nextOp.m_jumps.append(jump());
-                    } else {
-                        // A single alternative on its own can fall through.
-                        m_backtrackingState.fallthrough();
-                    }
-                } else {
-                    // Handle the cases where we can link the backtracks directly to their destinations.
-                    if (!isLastAlternative) {
-                        // An alternative that is not the last should jump to its successor.
-                        m_backtrackingState.linkTo(nextOp.m_reentry, this);
-                    } else if (!isBegin) {
-                        // The last of more than one alternatives must jump back to the begnning.
-                        m_backtrackingState.takeBacktracksToJumpList(nextOp.m_jumps, this);
-                    }
-                    // In the case of a single alternative on its own do nothing - it can fall through.
-                }
-
-                // At this point we've handled the backtracking back into this node.
-                // Now link any backtracks that need to jump to here.
-
-                // For non-simple alternatives, link the alternative's 'return address'
-                // so that we backtrack back out into the previous alternative.
-                if (op.m_op == OpNestedAlternativeNext)
-                    m_backtrackingState.append(op.m_returnAddress);
-
-                // If there is more than one alternative, then the last alternative will
-                // have planted a jump to be linked to the end. This jump was added to the
-                // End node's m_jumps list. If we are back at the beginning, link it here.
-                if (isBegin) {
-                    YarrOp* endOp = &m_ops[op.m_nextOp];
-                    while (endOp->m_nextOp != notFound) {
-                        ASSERT(endOp->m_op == OpSimpleNestedAlternativeNext || endOp->m_op == OpNestedAlternativeNext);
-                        endOp = &m_ops[endOp->m_nextOp];
-                    }
-                    ASSERT(endOp->m_op == OpSimpleNestedAlternativeEnd || endOp->m_op == OpNestedAlternativeEnd);
-                    m_backtrackingState.append(endOp->m_jumps);
-                }
-
-                if (!isBegin) {
-                    YarrOp& lastOp = m_ops[op.m_previousOp];
-                    m_checked += lastOp.m_checkAdjust;
-                }
-                m_checked -= op.m_checkAdjust;
-                break;
-            }
-            case OpSimpleNestedAlternativeEnd:
-            case OpNestedAlternativeEnd: {
-                PatternTerm* term = op.m_term;
-
-                // If we backtrack into the end of a simple subpattern do nothing;
-                // just continue through into the last alternative. If we backtrack
-                // into the end of a non-simple set of alterntives we need to jump
-                // to the backtracking return address set up during generation.
-                if (op.m_op == OpNestedAlternativeEnd) {
-                    m_backtrackingState.link(this);
-
-                    // Plant a jump to the return address.
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    loadFromFrameAndJump(alternativeFrameLocation);
-
-                    // Link the DataLabelPtr associated with the end of the last
-                    // alternative to this point.
-                    m_backtrackingState.append(op.m_returnAddress);
-                }
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked += lastOp.m_checkAdjust;
-                break;
-            }
-
-            // OpParenthesesSubpatternOnceBegin/End
-            //
-            // When we are backtracking back out of a capturing subpattern we need
-            // to clear the start index in the matches output array, to record that
-            // this subpattern has not been captured.
-            //
-            // When backtracking back out of a Greedy quantified subpattern we need
-            // to catch this, and try running the remainder of the alternative after
-            // the subpattern again, skipping the parentheses.
-            //
-            // Upon backtracking back into a quantified set of parentheses we need to
-            // check whether we were currently skipping the subpattern. If not, we
-            // can backtrack into them, if we were we need to either backtrack back
-            // out of the start of the parentheses, or jump back to the forwards
-            // matching start, depending of whether the match is Greedy or NonGreedy.
-            case OpParenthesesSubpatternOnceBegin: {
-                PatternTerm* term = op.m_term;
-                ASSERT(term->quantityCount == 1);
-
-                // We only need to backtrack to thispoint if capturing or greedy.
-                if (term->capture() || term->quantityType == QuantifierGreedy) {
-                    m_backtrackingState.link(this);
-
-                    // If capturing, clear the capture (we only need to reset start).
-                    if (term->capture())
-                        store32(TrustedImm32(-1), Address(output, (term->parentheses.subpatternId << 1) * sizeof(int)));
-
-                    // If Greedy, jump to the end.
-                    if (term->quantityType == QuantifierGreedy) {
-                        // Clear the flag in the stackframe indicating we ran through the subpattern.
-                        unsigned parenthesesFrameLocation = term->frameLocation;
-                        storeToFrame(TrustedImm32(-1), parenthesesFrameLocation);
-                        // Jump to after the parentheses, skipping the subpattern.
-                        jump(m_ops[op.m_nextOp].m_reentry);
-                        // A backtrack from after the parentheses, when skipping the subpattern,
-                        // will jump back to here.
-                        op.m_jumps.link(this);
-                    }
-
-                    m_backtrackingState.fallthrough();
-                }
-                break;
-            }
-            case OpParenthesesSubpatternOnceEnd: {
-                PatternTerm* term = op.m_term;
-
-                if (term->quantityType != QuantifierFixedCount) {
-                    m_backtrackingState.link(this);
-
-                    // Check whether we should backtrack back into the parentheses, or if we
-                    // are currently in a state where we had skipped over the subpattern
-                    // (in which case the flag value on the stack will be -1).
-                    unsigned parenthesesFrameLocation = term->frameLocation;
-                    Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1));
-
-                    if (term->quantityType == QuantifierGreedy) {
-                        // For Greedy parentheses, we skip after having already tried going
-                        // through the subpattern, so if we get here we're done.
-                        YarrOp& beginOp = m_ops[op.m_previousOp];
-                        beginOp.m_jumps.append(hadSkipped);
-                    } else {
-                        // For NonGreedy parentheses, we try skipping the subpattern first,
-                        // so if we get here we need to try running through the subpattern
-                        // next. Jump back to the start of the parentheses in the forwards
-                        // matching path.
-                        ASSERT(term->quantityType == QuantifierNonGreedy);
-                        YarrOp& beginOp = m_ops[op.m_previousOp];
-                        hadSkipped.linkTo(beginOp.m_reentry, this);
-                    }
-
-                    m_backtrackingState.fallthrough();
-                }
-
-                m_backtrackingState.append(op.m_jumps);
-                break;
-            }
-
-            // OpParenthesesSubpatternTerminalBegin/End
-            //
-            // Terminal subpatterns will always match - there is nothing after them to
-            // force a backtrack, and they have a minimum count of 0, and as such will
-            // always produce an acceptable result.
-            case OpParenthesesSubpatternTerminalBegin: {
-                // We will backtrack to this point once the subpattern cannot match any
-                // more. Since no match is accepted as a successful match (we are Greedy
-                // quantified with a minimum of zero) jump back to the forwards matching
-                // path at the end.
-                YarrOp& endOp = m_ops[op.m_nextOp];
-                m_backtrackingState.linkTo(endOp.m_reentry, this);
-                break;
-            }
-            case OpParenthesesSubpatternTerminalEnd:
-                // We should never be backtracking to here (hence the 'terminal' in the name).
-                ASSERT(m_backtrackingState.isEmpty());
-                m_backtrackingState.append(op.m_jumps);
-                break;
-
-            // OpParentheticalAssertionBegin/End
-            case OpParentheticalAssertionBegin: {
-                PatternTerm* term = op.m_term;
-                YarrOp& endOp = m_ops[op.m_nextOp];
-
-                // We need to handle the backtracks upon backtracking back out
-                // of a parenthetical assertion if either we need to correct
-                // the input index, or the assertion was inverted.
-                if (op.m_checkAdjust || term->invert()) {
-                     m_backtrackingState.link(this);
-
-                    if (op.m_checkAdjust)
-                        add32(Imm32(op.m_checkAdjust), index);
-
-                    // In an inverted assertion failure to match the subpattern
-                    // is treated as a successful match - jump to the end of the
-                    // subpattern. We already have adjusted the input position
-                    // back to that before the assertion, which is correct.
-                    if (term->invert())
-                        jump(endOp.m_reentry);
-
-                    m_backtrackingState.fallthrough();
-                }
-
-                // The End node's jump list will contain any backtracks into
-                // the end of the assertion. Also, if inverted, we will have
-                // added the failure caused by a successful match to this.
-                m_backtrackingState.append(endOp.m_jumps);
-
-                m_checked += op.m_checkAdjust;
-                break;
-            }
-            case OpParentheticalAssertionEnd: {
-                // FIXME: We should really be clearing any nested subpattern
-                // matches on bailing out from after the pattern. Firefox has
-                // this bug too (presumably because they use YARR!)
-
-                // Never backtrack into an assertion; later failures bail to before the begin.
-                m_backtrackingState.takeBacktracksToJumpList(op.m_jumps, this);
-
-                YarrOp& lastOp = m_ops[op.m_previousOp];
-                m_checked -= lastOp.m_checkAdjust;
-                break;
-            }
-
-            case OpMatchFailed:
-                break;
-            }
-
-        } while (opIndex);
-    }
-
-    // Compilation methods:
-    // ====================
-
-    // opCompileParenthesesSubpattern
-    // Emits ops for a subpattern (set of parentheses). These consist
-    // of a set of alternatives wrapped in an outer set of nodes for
-    // the parentheses.
-    // Supported types of parentheses are 'Once' (quantityCount == 1)
-    // and 'Terminal' (non-capturing parentheses quantified as greedy
-    // and infinite).
-    // Alternatives will use the 'Simple' set of ops if either the
-    // subpattern is terminal (in which case we will never need to
-    // backtrack), or if the subpattern only contains one alternative.
-    void opCompileParenthesesSubpattern(PatternTerm* term)
-    {
-        YarrOpCode parenthesesBeginOpCode;
-        YarrOpCode parenthesesEndOpCode;
-        YarrOpCode alternativeBeginOpCode = OpSimpleNestedAlternativeBegin;
-        YarrOpCode alternativeNextOpCode = OpSimpleNestedAlternativeNext;
-        YarrOpCode alternativeEndOpCode = OpSimpleNestedAlternativeEnd;
-
-        // We can currently only compile quantity 1 subpatterns that are
-        // not copies. We generate a copy in the case of a range quantifier,
-        // e.g. /(?:x){3,9}/, or /(?:x)+/ (These are effectively expanded to
-        // /(?:x){3,3}(?:x){0,6}/ and /(?:x)(?:x)*/ repectively). The problem
-        // comes where the subpattern is capturing, in which case we would
-        // need to restore the capture from the first subpattern upon a
-        // failure in the second.
-        if (term->quantityCount == 1 && !term->parentheses.isCopy) {
-            // Select the 'Once' nodes.
-            parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin;
-            parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd;
-
-            // If there is more than one alternative we cannot use the 'simple' nodes.
-            if (term->parentheses.disjunction->m_alternatives.size() != 1) {
-                alternativeBeginOpCode = OpNestedAlternativeBegin;
-                alternativeNextOpCode = OpNestedAlternativeNext;
-                alternativeEndOpCode = OpNestedAlternativeEnd;
-            }
-        } else if (term->parentheses.isTerminal) {
-            // Select the 'Terminal' nodes.
-            parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin;
-            parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd;
-        } else {
-            // This subpattern is not supported by the JIT.
-            m_shouldFallBack = true;
-            return;
-        }
-
-        size_t parenBegin = m_ops.size();
-        m_ops.append(parenthesesBeginOpCode);
-
-        m_ops.append(alternativeBeginOpCode);
-        m_ops.last().m_previousOp = notFound;
-        m_ops.last().m_term = term;
-        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
-        for (unsigned i = 0; i < alternatives.size(); ++i) {
-            size_t lastOpIndex = m_ops.size() - 1;
-
-            PatternAlternative* nestedAlternative = alternatives[i];
-            opCompileAlternative(nestedAlternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(alternativeNextOpCode));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = nestedAlternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            thisOp.m_term = term;
-        }
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == alternativeNextOpCode);
-        lastOp.m_op = alternativeEndOpCode;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = notFound;
-
-        size_t parenEnd = m_ops.size();
-        m_ops.append(parenthesesEndOpCode);
-
-        m_ops[parenBegin].m_term = term;
-        m_ops[parenBegin].m_previousOp = notFound;
-        m_ops[parenBegin].m_nextOp = parenEnd;
-        m_ops[parenEnd].m_term = term;
-        m_ops[parenEnd].m_previousOp = parenBegin;
-        m_ops[parenEnd].m_nextOp = notFound;
-    }
-
-    // opCompileParentheticalAssertion
-    // Emits ops for a parenthetical assertion. These consist of an
-    // OpSimpleNestedAlternativeBegin/Next/End set of nodes wrapping
-    // the alternatives, with these wrapped by an outer pair of
-    // OpParentheticalAssertionBegin/End nodes.
-    // We can always use the OpSimpleNestedAlternative nodes in the
-    // case of parenthetical assertions since these only ever match
-    // once, and will never backtrack back into the assertion.
-    void opCompileParentheticalAssertion(PatternTerm* term)
-    {
-        size_t parenBegin = m_ops.size();
-        m_ops.append(OpParentheticalAssertionBegin);
-
-        m_ops.append(OpSimpleNestedAlternativeBegin);
-        m_ops.last().m_previousOp = notFound;
-        m_ops.last().m_term = term;
-        Vector& alternatives =  term->parentheses.disjunction->m_alternatives;
-        for (unsigned i = 0; i < alternatives.size(); ++i) {
-            size_t lastOpIndex = m_ops.size() - 1;
-
-            PatternAlternative* nestedAlternative = alternatives[i];
-            opCompileAlternative(nestedAlternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(OpSimpleNestedAlternativeNext));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = nestedAlternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            thisOp.m_term = term;
-        }
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == OpSimpleNestedAlternativeNext);
-        lastOp.m_op = OpSimpleNestedAlternativeEnd;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = notFound;
-
-        size_t parenEnd = m_ops.size();
-        m_ops.append(OpParentheticalAssertionEnd);
-
-        m_ops[parenBegin].m_term = term;
-        m_ops[parenBegin].m_previousOp = notFound;
-        m_ops[parenBegin].m_nextOp = parenEnd;
-        m_ops[parenEnd].m_term = term;
-        m_ops[parenEnd].m_previousOp = parenBegin;
-        m_ops[parenEnd].m_nextOp = notFound;
-    }
-
-    // opCompileAlternative
-    // Called to emit nodes for all terms in an alternative.
-    void opCompileAlternative(PatternAlternative* alternative)
-    {
-        optimizeAlternative(alternative);
-
-        for (unsigned i = 0; i < alternative->m_terms.size(); ++i) {
-            PatternTerm* term = &alternative->m_terms[i];
-
-            switch (term->type) {
-            case PatternTerm::TypeParenthesesSubpattern:
-                opCompileParenthesesSubpattern(term);
-                break;
-
-            case PatternTerm::TypeParentheticalAssertion:
-                opCompileParentheticalAssertion(term);
-                break;
-
-            default:
-                m_ops.append(term);
-            }
-        }
-    }
-
-    // opCompileBody
-    // This method compiles the body disjunction of the regular expression.
-    // The body consists of two sets of alternatives - zero or more 'once
-    // through' (BOL anchored) alternatives, followed by zero or more
-    // repeated alternatives.
-    // For each of these two sets of alteratives, if not empty they will be
-    // wrapped in a set of OpBodyAlternativeBegin/Next/End nodes (with the
-    // 'begin' node referencing the first alternative, and 'next' nodes
-    // referencing any further alternatives. The begin/next/end nodes are
-    // linked together in a doubly linked list. In the case of repeating
-    // alternatives, the end node is also linked back to the beginning.
-    // If no repeating alternatives exist, then a OpMatchFailed node exists
-    // to return the failing result.
-    void opCompileBody(PatternDisjunction* disjunction)
-    {
-        Vector& alternatives =  disjunction->m_alternatives;
-        size_t currentAlternativeIndex = 0;
-
-        // Emit the 'once through' alternatives.
-        if (alternatives.size() && alternatives[0]->onceThrough()) {
-            m_ops.append(YarrOp(OpBodyAlternativeBegin));
-            m_ops.last().m_previousOp = notFound;
-
-            do {
-                size_t lastOpIndex = m_ops.size() - 1;
-                PatternAlternative* alternative = alternatives[currentAlternativeIndex];
-                opCompileAlternative(alternative);
-
-                size_t thisOpIndex = m_ops.size();
-                m_ops.append(YarrOp(OpBodyAlternativeNext));
-
-                YarrOp& lastOp = m_ops[lastOpIndex];
-                YarrOp& thisOp = m_ops[thisOpIndex];
-
-                lastOp.m_alternative = alternative;
-                lastOp.m_nextOp = thisOpIndex;
-                thisOp.m_previousOp = lastOpIndex;
-                
-                ++currentAlternativeIndex;
-            } while (currentAlternativeIndex < alternatives.size() && alternatives[currentAlternativeIndex]->onceThrough());
-
-            YarrOp& lastOp = m_ops.last();
-
-            ASSERT(lastOp.m_op == OpBodyAlternativeNext);
-            lastOp.m_op = OpBodyAlternativeEnd;
-            lastOp.m_alternative = 0;
-            lastOp.m_nextOp = notFound;
-        }
-
-        if (currentAlternativeIndex == alternatives.size()) {
-            m_ops.append(YarrOp(OpMatchFailed));
-            return;
-        }
-
-        // Emit the repeated alternatives.
-        size_t repeatLoop = m_ops.size();
-        m_ops.append(YarrOp(OpBodyAlternativeBegin));
-        m_ops.last().m_previousOp = notFound;
-        do {
-            size_t lastOpIndex = m_ops.size() - 1;
-            PatternAlternative* alternative = alternatives[currentAlternativeIndex];
-            ASSERT(!alternative->onceThrough());
-            opCompileAlternative(alternative);
-
-            size_t thisOpIndex = m_ops.size();
-            m_ops.append(YarrOp(OpBodyAlternativeNext));
-
-            YarrOp& lastOp = m_ops[lastOpIndex];
-            YarrOp& thisOp = m_ops[thisOpIndex];
-
-            lastOp.m_alternative = alternative;
-            lastOp.m_nextOp = thisOpIndex;
-            thisOp.m_previousOp = lastOpIndex;
-            
-            ++currentAlternativeIndex;
-        } while (currentAlternativeIndex < alternatives.size());
-        YarrOp& lastOp = m_ops.last();
-        ASSERT(lastOp.m_op == OpBodyAlternativeNext);
-        lastOp.m_op = OpBodyAlternativeEnd;
-        lastOp.m_alternative = 0;
-        lastOp.m_nextOp = repeatLoop;
-    }
-
-    void generateEnter()
-    {
-#if WTF_CPU_X86_64
-        push(X86Registers::ebp);
-        move(stackPointerRegister, X86Registers::ebp);
-        push(X86Registers::ebx);
-#elif WTF_CPU_X86
-        push(X86Registers::ebp);
-        move(stackPointerRegister, X86Registers::ebp);
-        // TODO: do we need spill registers to fill the output pointer if there are no sub captures?
-        push(X86Registers::ebx);
-        push(X86Registers::edi);
-        push(X86Registers::esi);
-        // load output into edi (2 = saved ebp + return address).
-    #if WTF_COMPILER_MSVC
-        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input);
-        loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index);
-        loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length);
-        loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output);
-    #else
-        loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
-    #endif
-#elif WTF_CPU_ARM
-        push(ARMRegisters::r4);
-        push(ARMRegisters::r5);
-        push(ARMRegisters::r6);
-#if WTF_CPU_ARM_TRADITIONAL
-        push(ARMRegisters::r8); // scratch register
-#endif
-        move(ARMRegisters::r3, output);
-#elif WTF_CPU_SH4
-        push(SH4Registers::r11);
-        push(SH4Registers::r13);
-#elif WTF_CPU_MIPS
-        // Do nothing.
-#endif
-    }
-
-    void generateReturn()
-    {
-#if WTF_CPU_X86_64
-        pop(X86Registers::ebx);
-        pop(X86Registers::ebp);
-#elif WTF_CPU_X86
-        pop(X86Registers::esi);
-        pop(X86Registers::edi);
-        pop(X86Registers::ebx);
-        pop(X86Registers::ebp);
-#elif WTF_CPU_ARM
-#if WTF_CPU_ARM_TRADITIONAL
-        pop(ARMRegisters::r8); // scratch register
-#endif
-        pop(ARMRegisters::r6);
-        pop(ARMRegisters::r5);
-        pop(ARMRegisters::r4);
-#elif WTF_CPU_SH4
-        pop(SH4Registers::r13);
-        pop(SH4Registers::r11);
-#elif WTF_CPU_MIPS
-        // Do nothing
-#endif
-        ret();
-    }
-
-public:
-    YarrGenerator(YarrPattern& pattern)
-        : m_pattern(pattern)
-        , m_shouldFallBack(false)
-        , m_checked(0)
-    {
-    }
-
-    void compile(JSGlobalData* globalData, YarrCodeBlock& jitObject)
-    {
-        generateEnter();
-
-        if (!m_pattern.m_body->m_hasFixedSize)
-            store32(index, Address(output));
-
-        if (m_pattern.m_body->m_callFrameSize)
-            subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
-
-        // Compile the pattern to the internal 'YarrOp' representation.
-        opCompileBody(m_pattern.m_body);
-
-        // If we encountered anything we can't handle in the JIT code
-        // (e.g. backreferences) then return early.
-        if (m_shouldFallBack) {
-            jitObject.setFallBack(true);
-            return;
-        }
-
-        generate();
-        backtrack();
-
-        // Link & finalize the code.
-        // XXX yarr-oom
-        ExecutablePool *pool;
-        bool ok;
-        LinkBuffer linkBuffer(this, globalData->regexAllocator, &pool, &ok);
-        m_backtrackingState.linkDataLabels(linkBuffer);
-        jitObject.set(linkBuffer.finalizeCode());
-        jitObject.setFallBack(m_shouldFallBack);
-    }
-
-private:
-    YarrPattern& m_pattern;
-
-    // Used to detect regular expression constructs that are not currently
-    // supported in the JIT; fall back to the interpreter when this is detected.
-    bool m_shouldFallBack;
-
-    // The regular expression expressed as a linear sequence of operations.
-    Vector m_ops;
-
-    // This records the current input offset being applied due to the current
-    // set of alternatives we are nested within. E.g. when matching the
-    // character 'b' within the regular expression /abc/, we will know that
-    // the minimum size for the alternative is 3, checked upon entry to the
-    // alternative, and that 'b' is at offset 1 from the start, and as such
-    // when matching 'b' we need to apply an offset of -2 to the load.
-    //
-    // FIXME: This should go away. Rather than tracking this value throughout
-    // code generation, we should gather this information up front & store it
-    // on the YarrOp structure.
-    int m_checked;
-
-    // This class records state whilst generating the backtracking path of code.
-    BacktrackingState m_backtrackingState;
-};
-
-void jitCompile(YarrPattern& pattern, JSGlobalData* globalData, YarrCodeBlock& jitObject)
-{
-    YarrGenerator(pattern).compile(globalData, jitObject);
-}
-
-int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output)
-{
-    return jitObject.execute(input, start, length, output);
-}
-
-}}
-
-#endif
diff --git a/js/src/yarr/YarrJIT.h b/js/src/yarr/YarrJIT.h
deleted file mode 100644
index 4f0f47f8c548..000000000000
--- a/js/src/yarr/YarrJIT.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- 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.
- *
- * 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. 
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef YarrJIT_h
-#define YarrJIT_h
-
-#include "assembler/wtf/Platform.h"
-
-#if ENABLE_YARR_JIT
-
-#include "assembler/assembler/MacroAssembler.h"
-#include "YarrPattern.h"
-
-#if WTF_CPU_X86 && !WTF_COMPILER_MSVC
-#define YARR_CALL __attribute__ ((regparm (3)))
-#else
-#define YARR_CALL
-#endif
-
-namespace JSC {
-
-class JSGlobalData;
-class ExecutablePool;
-
-namespace Yarr {
-
-class YarrCodeBlock {
-    typedef int (*YarrJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
-
-public:
-    YarrCodeBlock()
-        : m_needFallBack(false)
-    {
-    }
-
-    ~YarrCodeBlock()
-    {
-    }
-
-    void setFallBack(bool fallback) { m_needFallBack = fallback; }
-    bool isFallBack() { return m_needFallBack; }
-    void set(MacroAssembler::CodeRef ref) { m_ref = ref; }
-
-    int execute(const UChar* input, unsigned start, unsigned length, int* output)
-    {
-        return JS_EXTENSION((reinterpret_cast(m_ref.m_code.executableAddress()))(input, start, length, output));
-    }
-
-#if ENABLE_REGEXP_TRACING
-    void *getAddr() { return m_ref.m_code.executableAddress(); }
-#endif
-
-    void release() { m_ref.release(); }
-
-private:
-    MacroAssembler::CodeRef m_ref;
-    bool m_needFallBack;
-};
-
-void jitCompile(YarrPattern&, JSGlobalData*, YarrCodeBlock& jitObject);
-int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output);
-
-} } // namespace JSC::Yarr
-
-#endif
-
-#endif // YarrJIT_h
diff --git a/js/src/yarr/jswtfbridge.h b/js/src/yarr/jswtfbridge.h
new file mode 100644
index 000000000000..b38f76ead5a8
--- /dev/null
+++ b/js/src/yarr/jswtfbridge.h
@@ -0,0 +1,61 @@
+/* -*- 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 *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
+ * June 12, 2009.
+ *
+ * The Initial Developer of the Original Code is
+ *   the Mozilla Corporation.
+ *
+ * Contributor(s):
+ *   Chris Leary 
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jswtfbridge_h__
+#define jswtfbridge_h__
+
+/*
+ * The JS/WTF Bridge to Bona-fide Quality.
+ */
+
+#include "assembler/wtf/Platform.h"
+#include "jsstr.h"
+#include "jsprvtd.h"
+#include "jstl.h"
+
+typedef jschar UChar;
+typedef JSLinearString UString;
+
+class Unicode {
+  public:
+    static UChar toUpper(UChar c) { return JS_TOUPPER(c); }
+    static UChar toLower(UChar c) { return JS_TOLOWER(c); }
+};
+
+#endif
diff --git a/js/src/yarr/pcre/AUTHORS b/js/src/yarr/pcre/AUTHORS
new file mode 100644
index 000000000000..dbac2a54834b
--- /dev/null
+++ b/js/src/yarr/pcre/AUTHORS
@@ -0,0 +1,12 @@
+Originally written by:  Philip Hazel
+Email local part:       ph10
+Email domain:           cam.ac.uk
+
+University of Cambridge Computing Service,
+Cambridge, England. Phone: +44 1223 334714.
+
+Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
+
+Adapted for JavaScriptCore and WebKit by Apple Inc.
+
+Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/js/src/yarr/pcre/COPYING b/js/src/yarr/pcre/COPYING
new file mode 100644
index 000000000000..6ffdc24342d5
--- /dev/null
+++ b/js/src/yarr/pcre/COPYING
@@ -0,0 +1,35 @@
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+This is JavaScriptCore's variant of the PCRE library. While this library
+started out as a copy of PCRE, many of the features of PCRE have been
+removed.
+
+Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * 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.
+
+    * Neither the name of the University of Cambridge nor the name of Apple
+      Inc. nor the names of their contributors may be used to endorse or
+      promote products derived from this software without specific prior
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
diff --git a/js/src/yarr/pcre/chartables.c b/js/src/yarr/pcre/chartables.c
new file mode 100644
index 000000000000..5c99db0b980f
--- /dev/null
+++ b/js/src/yarr/pcre/chartables.c
@@ -0,0 +1,96 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* This file is automatically written by the dftables auxiliary 
+program. If you edit it by hand, you might like to edit the Makefile to 
+prevent its ever being regenerated.
+
+This file contains the default tables for characters with codes less than
+128 (ASCII characters). These tables are used when no external tables are
+passed to PCRE. */
+
+const unsigned char jsc_pcre_default_tables[480] = {
+
+/* This table is a lower casing table. */
+
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
+  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+/* This table is a case flipping table. */
+
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+  0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+  0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+  0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+  0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 
+  0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
+  0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 
+  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
+  0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+/* This table contains bit maps for various character classes.
+Each map is 32 bytes long and the bits run from the least
+significant end of each byte. The classes are: space, digit, word. */
+
+  0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 
+  0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* This table identifies various classes of character by individual bits:
+  0x01   white space character
+  0x08   hexadecimal digit
+  0x10   alphanumeric or '_'
+*/
+
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*   0-  7 */
+  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /*   8- 15 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  16- 23 */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  24- 31 */
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*    - '  */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  ( - /  */
+  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,  /*  0 - 7  */
+  0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /*  8 - ?  */
+  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  @ - G  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  H - O  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  P - W  */
+  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,  /*  X - _  */
+  0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10,  /*  ` - g  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  h - o  */
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  /*  p - w  */
+  0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /*  x -127 */
+
+
+/* End of chartables.c */
diff --git a/js/src/yarr/pcre/dftables b/js/src/yarr/pcre/dftables
new file mode 100644
index 000000000000..669b948ffc91
--- /dev/null
+++ b/js/src/yarr/pcre/dftables
@@ -0,0 +1,273 @@
+#!/usr/bin/perl -w
+#
+# This is JavaScriptCore's variant of the PCRE library. While this library
+# started out as a copy of PCRE, many of the features of PCRE have been
+# removed. This library now supports only the regular expression features
+# required by the JavaScript language specification, and has only the functions
+# needed by JavaScriptCore and the rest of WebKit.
+# 
+#                  Originally written by Philip Hazel
+#            Copyright (c) 1997-2006 University of Cambridge
+#  Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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:
+# 
+#     * Redistributions of source code must retain the above copyright notice,
+#       this list of conditions and the following disclaimer.
+# 
+#     * 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.
+# 
+#     * Neither the name of the University of Cambridge nor the names of its
+#       contributors may be used to endorse or promote products derived from
+#       this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
+# -----------------------------------------------------------------------------
+
+# This is a freestanding support program to generate a file containing
+# character tables. The tables are built according to the default C
+# locale.
+
+use strict;
+
+use File::Basename;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+
+sub readHeaderValues();
+
+my %pcre_internal;
+
+if (scalar(@ARGV) < 1) {
+    print STDERR "Usage: ", basename($0), " [--preprocessor=program] output-file\n";
+    exit 1;
+}
+
+my $outputFile;
+my $preprocessor;
+GetOptions('preprocessor=s' => \$preprocessor);
+if (not $preprocessor) {
+    $preprocessor = "cpp";
+}
+
+$outputFile = $ARGV[0];
+die('Must specify output file.') unless defined($outputFile);
+
+readHeaderValues();
+
+open(OUT, ">", $outputFile) or die "$!";
+binmode(OUT);
+
+printf(OUT
+    "/*************************************************\n" .
+    "*      Perl-Compatible Regular Expressions       *\n" .
+    "*************************************************/\n\n" .
+    "/* This file is automatically written by the dftables auxiliary \n" .
+    "program. If you edit it by hand, you might like to edit the Makefile to \n" .
+    "prevent its ever being regenerated.\n\n");
+printf(OUT
+    "This file contains the default tables for characters with codes less than\n" .
+    "128 (ASCII characters). These tables are used when no external tables are\n" .
+    "passed to PCRE. */\n\n" .
+    "const unsigned char jsc_pcre_default_tables[%d] = {\n\n" .
+    "/* This table is a lower casing table. */\n\n", $pcre_internal{tables_length});
+
+if ($pcre_internal{lcc_offset} != 0) {
+    die "lcc_offset != 0";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        printf(OUT "\n  ");
+    }
+    printf(OUT "0x%02X", ord(lc(chr($i))));
+    if ($i != 127) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT "/* This table is a case flipping table. */\n\n");
+
+if ($pcre_internal{fcc_offset} != 128) {
+  die "fcc_offset != 128";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        printf(OUT "\n  ");
+    }
+    my $c = chr($i);
+    printf(OUT "0x%02X", $c =~ /[[:lower:]]/ ? ord(uc($c)) : ord(lc($c)));
+    if ($i != 127) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT
+    "/* This table contains bit maps for various character classes.\n" .
+    "Each map is 32 bytes long and the bits run from the least\n" .
+    "significant end of each byte. The classes are: space, digit, word. */\n\n");
+
+if ($pcre_internal{cbits_offset} != $pcre_internal{fcc_offset} + 128) {
+    die "cbits_offset != fcc_offset + 128";
+}
+
+my @cbit_table = (0) x $pcre_internal{cbit_length};
+for (my $i = ord('0'); $i <= ord('9'); $i++) {
+    $cbit_table[$pcre_internal{cbit_digit} + $i / 8] |= 1 << ($i & 7);
+}
+$cbit_table[$pcre_internal{cbit_word} + ord('_') / 8] |= 1 << (ord('_') & 7);
+for (my $i = 0; $i < 128; $i++) {
+    my $c = chr($i);
+    if ($c =~ /[[:alnum:]]/) {
+        $cbit_table[$pcre_internal{cbit_word} + $i / 8] |= 1 << ($i & 7);
+    }
+    if ($c =~ /[[:space:]]/) {
+        $cbit_table[$pcre_internal{cbit_space} + $i / 8] |= 1 << ($i & 7);
+    }
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < $pcre_internal{cbit_length}; $i++) {
+    if (($i & 7) == 0 && $i != 0) {
+        if (($i & 31) == 0) {
+            printf(OUT "\n");
+        }
+        printf(OUT "\n  ");
+    }
+    printf(OUT "0x%02X", $cbit_table[$i]);
+    if ($i != $pcre_internal{cbit_length} - 1) {
+        printf(OUT ", ");
+    }
+}
+printf(OUT ",\n\n");
+
+printf(OUT
+    "/* This table identifies various classes of character by individual bits:\n" .
+    "  0x%02x   white space character\n" .
+    "  0x%02x   hexadecimal digit\n" .
+    "  0x%02x   alphanumeric or '_'\n*/\n\n",
+    $pcre_internal{ctype_space}, $pcre_internal{ctype_xdigit}, $pcre_internal{ctype_word});
+
+if ($pcre_internal{ctypes_offset} != $pcre_internal{cbits_offset} + $pcre_internal{cbit_length}) {
+    die "ctypes_offset != cbits_offset + cbit_length";
+}
+
+printf(OUT "  ");
+for (my $i = 0; $i < 128; $i++) {
+    my $x = 0;
+    my $c = chr($i);
+    if ($c =~ /[[:space:]]/) {
+        $x += $pcre_internal{ctype_space};
+    }
+    if ($c =~ /[[:xdigit:]]/) {
+        $x += $pcre_internal{ctype_xdigit};
+    }
+    if ($c =~ /[[:alnum:]_]/) {
+        $x += $pcre_internal{ctype_word};
+    }
+    printf(OUT "0x%02X", $x);
+    if ($i != 127) {
+        printf(OUT ", ");
+    } else {
+        printf(OUT "};");
+    }
+    if (($i & 7) == 7) {
+        printf(OUT " /* ");
+        my $d = chr($i - 7);
+        if ($d =~ /[[:print:]]/) {
+            printf(OUT " %c -", $i - 7);
+        } else {
+            printf(OUT "%3d-", $i - 7);
+        }
+        if ($c =~ m/[[:print:]]/) {
+            printf(OUT " %c ", $i);
+        } else {
+            printf(OUT "%3d", $i);
+        }
+        printf(OUT " */\n");
+        if ($i != 127) {
+            printf(OUT "  ");
+        }
+    }
+}
+
+if ($pcre_internal{tables_length} != $pcre_internal{ctypes_offset} + 128) {
+    die "tables_length != ctypes_offset + 128";
+}
+
+printf(OUT "\n\n/* End of chartables.c */\n");
+
+close(OUT);
+
+exit 0;
+
+sub readHeaderValues()
+{
+    my @variables = qw(
+        cbit_digit
+        cbit_length
+        cbit_space
+        cbit_word
+        cbits_offset
+        ctype_space
+        ctype_word
+        ctype_xdigit
+        ctypes_offset
+        fcc_offset
+        lcc_offset
+        tables_length
+    );
+
+    local $/ = undef;
+
+    my $headerPath = File::Spec->catfile(dirname($0), "pcre_internal.h");
+ 
+    my ($fh, $tempFile) = tempfile(
+        basename($0) . "-XXXXXXXX",
+        DIR => File::Spec->tmpdir(),
+        SUFFIX => ".in",
+        UNLINK => 0,
+    );
+
+    print $fh "#define DFTABLES\n\n";
+
+    open(HEADER, "<", $headerPath) or die "$!";
+    print $fh 
; + close(HEADER); + + print $fh "\n\n"; + + for my $v (@variables) { + print $fh "\$pcre_internal{\"$v\"} = $v;\n"; + } + + close($fh); + + open(CPP, "$preprocessor \"$tempFile\" |") or die "$!"; + my $content = ; + close(CPP); + + eval $content; + die "$@" if $@; + unlink $tempFile; +} diff --git a/js/src/yarr/pcre/pcre.h b/js/src/yarr/pcre/pcre.h new file mode 100644 index 000000000000..91d96b784905 --- /dev/null +++ b/js/src/yarr/pcre/pcre.h @@ -0,0 +1,68 @@ +/* This is the public header file for JavaScriptCore's variant of the PCRE +library. While this library started out as a copy of PCRE, many of the +features of PCRE have been removed. This library now supports only the +regular expression features required by the JavaScript language +specification, and has only the functions needed by JavaScriptCore and the +rest of WebKit. + + Copyright (c) 1997-2005 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +// FIXME: This file needs to be renamed to JSRegExp.h; it's no longer PCRE. + +#ifndef JSRegExp_h +#define JSRegExp_h + +#include "yarr/jswtfbridge.h" + +struct JSRegExp; +struct JSContext; + +enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase }; +enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline }; + +/* jsRegExpExecute error codes */ +const int JSRegExpErrorNoMatch = -1; +const int JSRegExpErrorHitLimit = -2; +const int JSRegExpErrorInternal = -4; + +JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, + JSRegExpIgnoreCaseOption, JSRegExpMultilineOption, + unsigned* numSubpatterns, int *error); + +int jsRegExpExecute(JSContext *, const JSRegExp*, + const UChar* subject, int subjectLength, int startOffset, + int* offsetsVector, int offsetsVectorLength); + +void jsRegExpFree(JSRegExp*); + +#endif diff --git a/js/src/yarr/pcre/pcre.pri b/js/src/yarr/pcre/pcre.pri new file mode 100644 index 000000000000..4f59e17f4d91 --- /dev/null +++ b/js/src/yarr/pcre/pcre.pri @@ -0,0 +1,12 @@ +# Perl Compatible Regular Expressions - Qt4 build info +VPATH += $$PWD +INCLUDEPATH += $$PWD $$OUTPUT_DIR/JavaScriptCore/tmp +DEPENDPATH += $$PWD + +SOURCES += \ + pcre_compile.cpp \ + pcre_exec.cpp \ + pcre_tables.cpp \ + pcre_ucp_searchfuncs.cpp \ + pcre_xclass.cpp + diff --git a/js/src/yarr/pcre/pcre_compile.cpp b/js/src/yarr/pcre/pcre_compile.cpp new file mode 100644 index 000000000000..8d273bcbe5a6 --- /dev/null +++ b/js/src/yarr/pcre/pcre_compile.cpp @@ -0,0 +1,2702 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + Copyright (C) 2007 Eric Seidel + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains the external function jsRegExpExecute(), along with +supporting internal functions that are not used by other modules. */ + +#include "pcre_internal.h" + +#include +#include "yarr/wtf/ASCIICType.h" +#include "jsvector.h" + +using namespace WTF; + +/* Negative values for the firstchar and reqchar variables */ + +#define REQ_UNSET (-2) +#define REQ_NONE (-1) + +/************************************************* +* Code parameters and static tables * +*************************************************/ + +/* Maximum number of items on the nested bracket stacks at compile time. This +applies to the nesting of all kinds of parentheses. It does not limit +un-nested, non-capturing parentheses. This number can be made bigger if +necessary - it is used to dimension one int and one unsigned char vector at +compile time. */ + +#define BRASTACK_SIZE 200 + +/* Table for handling escaped characters in the range '0'-'z'. Positive returns +are simple data values; negative values are for special things like \d and so +on. Zero means further processing is needed (for things like \x), or the escape +is invalid. */ + +static const short escapes[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ + 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ + '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ + 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */ + '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */ + 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */ + 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */ + 0, 0, 0 /* x - z */ +}; +static const unsigned OPCODE_LEN = 1; +static const unsigned BRAZERO_LEN = OPCODE_LEN; +static const unsigned BRA_NEST_SIZE = 2; +static const unsigned BRA_LEN = OPCODE_LEN + LINK_SIZE + BRA_NEST_SIZE; +static const unsigned KET_LEN = OPCODE_LEN + LINK_SIZE; + +/* Error code numbers. They are given names so that they can more easily be +tracked. */ + +enum ErrorCode { + ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, + ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17 +}; + +/* These are the error texts that correspond to the above error codes: + // 1 + "\\ at end of pattern\0" + "\\c at end of pattern\0" + "character value in \\x{...} sequence is too large\0" + "numbers out of order in {} quantifier\0" + // 5 + "number too big in {} quantifier\0" + "missing terminating ] for character class\0" + "internal error: code overflow\0" + "range out of order in character class\0" + "nothing to repeat\0" + // 10 + "unmatched parentheses\0" + "internal error: unexpected repeat\0" + "unrecognized character after (?\0" + "failed to get memory\0" + "missing )\0" + // 15 + "reference to non-existent subpattern\0" + "regular expression too large\0" + "parentheses nested too deeply" */ + +/* Structure for passing "static" information around between the functions +doing the compiling. */ + +struct CompileData { + CompileData() { + topBackref = 0; + backrefMap = 0; + reqVaryOpt = 0; + needOuterBracket = false; + numCapturingBrackets = 0; + } + int topBackref; /* Maximum back reference */ + unsigned backrefMap; /* Bitmap of low back refs */ + int reqVaryOpt; /* "After variable item" flag for reqByte */ + bool needOuterBracket; + int numCapturingBrackets; +}; + +/* Definitions to allow mutual recursion */ + +static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&); +static bool bracketIsAnchored(const unsigned char* code); +static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap); +static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert); + +/************************************************* +* Handle escapes * +*************************************************/ + +/* This function is called when a \ has been encountered. It either returns a +positive value for a simple escape such as \n, or a negative value which +encodes one of the more complicated things such as \d. When UTF-8 is enabled, +a positive value greater than 255 may be returned. On entry, ptr is pointing at +the \. On exit, it is on the final character of the escape sequence. + +Arguments: + ptrPtr points to the pattern position pointer + errorCodePtr points to the errorcode variable + bracount number of previous extracting brackets + options the options bits + isClass true if inside a character class + +Returns: zero or positive => a data character + negative => a special escape sequence + on error, error is set +*/ + +static int checkEscape(const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int bracount, bool isClass) +{ + const UChar* ptr = *ptrPtr + 1; + + /* If backslash is at the end of the pattern, it's an error. */ + if (ptr == patternEnd) { + *errorCodePtr = ERR1; + *ptrPtr = ptr; + return 0; + } + + int c = *ptr; + + /* Non-alphamerics are literals. For digits or letters, do an initial lookup in + a table. A non-zero result is something that can be returned immediately. + Otherwise further processing may be required. */ + + if (c < '0' || c > 'z') { /* Not alphameric */ + } else if (int escapeValue = escapes[c - '0']) { + c = escapeValue; + if (isClass) { + if (-c == ESC_b) + c = '\b'; /* \b is backslash in a class */ + else if (-c == ESC_B) + c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */ + } + /* Escapes that need further processing, or are illegal. */ + + } else { + switch (c) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* Escape sequences starting with a non-zero digit are backreferences, + unless there are insufficient brackets, in which case they are octal + escape sequences. Those sequences end on the first non-octal character + or when we overflow 0-255, whichever comes first. */ + + if (!isClass) { + const UChar* oldptr = ptr; + c -= '0'; + while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount) + c = c * 10 + *(++ptr) - '0'; + if (c <= bracount) { + c = -(ESC_REF + c); + break; + } + ptr = oldptr; /* Put the pointer back and fall through */ + } + + /* Handle an octal number following \. If the first digit is 8 or 9, + this is not octal. */ + + if ((c = *ptr) >= '8') { + c = '\\'; + ptr -= 1; + break; + } + + /* \0 always starts an octal number, but we may drop through to here with a + larger first octal digit. */ + + case '0': { + c -= '0'; + int i; + for (i = 1; i <= 2; ++i) { + if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7') + break; + int cc = c * 8 + ptr[i] - '0'; + if (cc > 255) + break; + c = cc; + } + ptr += i - 1; + break; + } + + case 'x': { + c = 0; + int i; + for (i = 1; i <= 2; ++i) { + if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { + c = 'x'; + i = 1; + break; + } + int cc = ptr[i]; + if (cc >= 'a') + cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); + } + ptr += i - 1; + break; + } + + case 'u': { + c = 0; + int i; + for (i = 1; i <= 4; ++i) { + if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { + c = 'u'; + i = 1; + break; + } + int cc = ptr[i]; + if (cc >= 'a') + cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); + } + ptr += i - 1; + break; + } + + case 'c': + if (++ptr == patternEnd) { + *errorCodePtr = ERR2; + return 0; + } + + c = *ptr; + + /* To match Firefox, inside a character class, we also accept + numbers and '_' as control characters */ + if ((!isClass && !isASCIIAlpha(c)) || (!isASCIIAlphanumeric(c) && c != '_')) { + c = '\\'; + ptr -= 2; + break; + } + + /* A letter is upper-cased; then the 0x40 bit is flipped. This coding + is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ + c = toASCIIUpper(c) ^ 0x40; + break; + } + } + + *ptrPtr = ptr; + return c; +} + +/************************************************* +* Check for counted repeat * +*************************************************/ + +/* This function is called when a '{' is encountered in a place where it might +start a quantifier. It looks ahead to see if it really is a quantifier or not. +It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} +where the ddds are digits. + +Arguments: + p pointer to the first char after '{' + +Returns: true or false +*/ + +static bool isCountedRepeat(const UChar* p, const UChar* patternEnd) +{ + if (p >= patternEnd || !isASCIIDigit(*p)) + return false; + p++; + while (p < patternEnd && isASCIIDigit(*p)) + p++; + if (p < patternEnd && *p == '}') + return true; + + if (p >= patternEnd || *p++ != ',') + return false; + if (p < patternEnd && *p == '}') + return true; + + if (p >= patternEnd || !isASCIIDigit(*p)) + return false; + p++; + while (p < patternEnd && isASCIIDigit(*p)) + p++; + + return (p < patternEnd && *p == '}'); +} + +/************************************************* +* Read repeat counts * +*************************************************/ + +/* Read an item of the form {n,m} and return the values. This is called only +after isCountedRepeat() has confirmed that a repeat-count quantifier exists, +so the syntax is guaranteed to be correct, but we need to check the values. + +Arguments: + p pointer to first char after '{' + minp pointer to int for min + maxp pointer to int for max + returned as -1 if no max + errorCodePtr points to error code variable + +Returns: pointer to '}' on success; + current ptr on error, with errorCodePtr set non-zero +*/ + +static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorCodePtr) +{ + int min = 0; + int max = -1; + + /* Read the minimum value and do a paranoid check: a negative value indicates + an integer overflow. */ + + while (isASCIIDigit(*p)) + min = min * 10 + *p++ - '0'; + if (min < 0 || min > 65535) { + *errorCodePtr = ERR5; + return p; + } + + /* Read the maximum value if there is one, and again do a paranoid on its size. + Also, max must not be less than min. */ + + if (*p == '}') + max = min; + else { + if (*(++p) != '}') { + max = 0; + while (isASCIIDigit(*p)) + max = max * 10 + *p++ - '0'; + if (max < 0 || max > 65535) { + *errorCodePtr = ERR5; + return p; + } + if (max < min) { + *errorCodePtr = ERR4; + return p; + } + } + } + + /* Fill in the required variables, and pass back the pointer to the terminating + '}'. */ + + *minp = min; + *maxp = max; + return p; +} + +/************************************************* +* Find first significant op code * +*************************************************/ + +/* This is called by several functions that scan a compiled expression looking +for a fixed first character, or an anchoring op code etc. It skips over things +that do not influence this. + +Arguments: + code pointer to the start of the group +Returns: pointer to the first significant opcode +*/ + +static const unsigned char* firstSignificantOpcode(const unsigned char* code) +{ + while (*code == OP_BRANUMBER) + code += 3; + return code; +} + +static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code) +{ + while (true) { + switch (*code) { + case OP_ASSERT_NOT: + advanceToEndOfBracket(code); + code += 1 + LINK_SIZE; + break; + case OP_WORD_BOUNDARY: + case OP_NOT_WORD_BOUNDARY: + ++code; + break; + case OP_BRANUMBER: + code += 3; + break; + default: + return code; + } + } +} + +/************************************************* +* Get othercase range * +*************************************************/ + +/* This function is passed the start and end of a class range, in UTF-8 mode +with UCP support. It searches up the characters, looking for internal ranges of +characters in the "other" case. Each call returns the next one, updating the +start address. + +Arguments: + cptr points to starting character value; updated + d end value + ocptr where to put start of othercase range + odptr where to put end of othercase range + +Yield: true when range returned; false when no more +*/ + +static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr) +{ + int c, othercase = 0; + + for (c = *cptr; c <= d; c++) { + if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) + break; + } + + if (c > d) + return false; + + *ocptr = othercase; + int next = othercase + 1; + + for (++c; c <= d; c++) { + if (jsc_pcre_ucp_othercase(c) != next) + break; + next++; + } + + *odptr = next - 1; + *cptr = c; + + return true; +} + +/************************************************* + * Convert character value to UTF-8 * + *************************************************/ + +/* This function takes an integer value in the range 0 - 0x7fffffff + and encodes it as a UTF-8 character in 0 to 6 bytes. + + Arguments: + cvalue the character value + buffer pointer to buffer for result - at least 6 bytes long + + Returns: number of characters placed in the buffer + */ + +static int encodeUTF8(int cvalue, unsigned char *buffer) +{ + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (cvalue <= jsc_pcre_utf8_table1[i]) + break; + buffer += i; + for (int j = i; j > 0; j--) { + *buffer-- = 0x80 | (cvalue & 0x3f); + cvalue >>= 6; + } + *buffer = jsc_pcre_utf8_table2[i] | cvalue; + return i + 1; +} + +/************************************************* +* Compile one branch * +*************************************************/ + +/* Scan the pattern, compiling it into the code vector. + +Arguments: + options the option bits + brackets points to number of extracting brackets used + codePtr points to the pointer to the current code point + ptrPtr points to the current pattern pointer + errorCodePtr points to error code variable + firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) + reqbyteptr set to the last literal character required, else < 0 + cd contains pointers to tables etc. + +Returns: true on success + false, with *errorCodePtr set non-zero on error +*/ + +static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected) +{ + return ((ptr + 1 < patternEnd) && ptr[1] == expected); +} + +static bool +compileBranch(int options, int* brackets, unsigned char** codePtr, + const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int *firstbyteptr, + int* reqbyteptr, CompileData& cd) +{ + int repeatType, opType; + int repeatMin = 0, repeat_max = 0; /* To please picky compilers */ + int bravalue = 0; + int reqvary, tempreqvary; + int c; + unsigned char* code = *codePtr; + unsigned char* tempcode; + bool didGroupSetFirstByte = false; + const UChar* ptr = *ptrPtr; + const UChar* tempptr; + unsigned char* previous = NULL; + unsigned char classbits[32]; + + bool class_utf8; + unsigned char* class_utf8data; + unsigned char utf8_char[6]; + + /* Initialize no first byte, no required byte. REQ_UNSET means "no char + matching encountered yet". It gets changed to REQ_NONE if we hit something that + matches a non-fixed char first char; reqByte just remains unset if we never + find one. + + When we hit a repeat whose minimum is zero, we may have to adjust these values + to take the zero repeat into account. This is implemented by setting them to + zeroFirstByte and zeroReqByte when such a repeat is encountered. The individual + item types that can be repeated set these backoff variables appropriately. */ + + int firstByte = REQ_UNSET; + int reqByte = REQ_UNSET; + int zeroReqByte = REQ_UNSET; + int zeroFirstByte = REQ_UNSET; + + /* The variable reqCaseOpt contains either the REQ_IGNORE_CASE value or zero, + according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit + value > 255. It is added into the firstByte or reqByte variables to record the + case status of the value. This is used only for ASCII characters. */ + + int reqCaseOpt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0; + + /* Switch on next character until the end of the branch */ + + for (;; ptr++) { + bool negateClass; + bool shouldFlipNegation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */ + int classCharCount; + int classLastChar; + int skipBytes; + int subReqByte; + int subFirstByte; + int mcLength; + unsigned char mcbuffer[8]; + + /* Next byte in the pattern */ + + c = ptr < patternEnd ? *ptr : 0; + + /* Fill in length of a previous callout, except when the next thing is + a quantifier. */ + + bool isQuantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd)); + + switch (c) { + /* The branch terminates at end of string, |, or ). */ + + case 0: + if (ptr < patternEnd) + goto NORMAL_CHAR; + // End of string; fall through + case '|': + case ')': + *firstbyteptr = firstByte; + *reqbyteptr = reqByte; + *codePtr = code; + *ptrPtr = ptr; + return true; + + /* Handle single-character metacharacters. In multiline mode, ^ disables + the setting of any following char as a first character. */ + + case '^': + if (options & MatchAcrossMultipleLinesOption) { + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + *code++ = OP_BOL; + } else + *code++ = OP_CIRC; + previous = NULL; + break; + + case '$': + previous = NULL; + if (options & MatchAcrossMultipleLinesOption) + *code++ = OP_EOL; + else + *code++ = OP_DOLL; + break; + + /* There can never be a first char if '.' is first, whatever happens about + repeats. The value of reqByte doesn't change either. */ + + case '.': + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + previous = code; + *code++ = OP_NOT_NEWLINE; + break; + + /* Character classes. If the included characters are all < 256, we build a + 32-byte bitmap of the permitted characters, except in the special case + where there is only one such character. For negated classes, we build the + map as usual, then invert it at the end. However, we use a different opcode + so that data characters > 255 can be handled correctly. + + If the class contains characters outside the 0-255 range, a different + opcode is compiled. It may optionally have a bit map for characters < 256, + but those above are are explicitly listed afterwards. A flag byte tells + whether the bitmap is present, and whether this is a negated class or not. + */ + + case '[': { + previous = code; + shouldFlipNegation = false; + + /* PCRE supports POSIX class stuff inside a class. Perl gives an error if + they are encountered at the top level, so we'll do that too. */ + + /* If the first character is '^', set the negation flag and skip it. */ + + if (ptr + 1 >= patternEnd) { + *errorCodePtr = ERR6; + return false; + } + + if (ptr[1] == '^') { + negateClass = true; + ++ptr; + } else + negateClass = false; + + /* Keep a count of chars with values < 256 so that we can optimize the case + of just a single character (as long as it's < 256). For higher valued UTF-8 + characters, we don't yet do any optimization. */ + + classCharCount = 0; + classLastChar = -1; + + class_utf8 = false; /* No chars >= 256 */ + class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ + + /* Initialize the 32-char bit map to all zeros. We have to build the + map in a temporary bit of store, in case the class contains only 1 + character (< 256), because in that case the compiled code doesn't use the + bit map. */ + + memset(classbits, 0, 32 * sizeof(unsigned char)); + + /* Process characters until ] is reached. The first pass + through the regex checked the overall syntax, so we don't need to be very + strict here. At the start of the loop, c contains the first byte of the + character. */ + + while ((++ptr < patternEnd) && (c = *ptr) != ']') { + /* Backslash may introduce a single character, or it may introduce one + of the specials, which just set a flag. Escaped items are checked for + validity in the pre-compiling pass. The sequence \b is a special case. + Inside a class (and only there) it is treated as backspace. Elsewhere + it marks a word boundary. Other escapes have preset maps ready to + or into the one we are building. We assume they have more than one + character in them, so set classCharCount bigger than one. */ + + if (c == '\\') { + c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); + if (c < 0) { + classCharCount += 2; /* Greater than 1 is what matters */ + switch (-c) { + case ESC_d: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_digit); + continue; + + case ESC_D: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_digit); + continue; + + case ESC_w: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_word); + continue; + + case ESC_W: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_word); + continue; + + case ESC_s: + for (c = 0; c < 32; c++) + classbits[c] |= classBitmapForChar(c + cbit_space); + continue; + + case ESC_S: + shouldFlipNegation = true; + for (c = 0; c < 32; c++) + classbits[c] |= ~classBitmapForChar(c + cbit_space); + continue; + + /* Unrecognized escapes are faulted if PCRE is running in its + strict mode. By default, for compatibility with Perl, they are + treated as literals. */ + + default: + c = *ptr; /* The final character */ + classCharCount -= 2; /* Undo the default count from above */ + } + } + + /* Fall through if we have a single character (c >= 0). This may be + > 256 in UTF-8 mode. */ + + } /* End of backslash handling */ + + /* A single character may be followed by '-' to form a range. However, + Perl does not permit ']' to be the end of the range. A '-' character + here is treated as a literal. */ + + if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') { + ptr += 2; + + int d = *ptr; + + /* The second part of a range can be a single-character escape, but + not any of the other escapes. Perl 5.6 treats a hyphen as a literal + in such circumstances. */ + + if (d == '\\') { + const UChar* oldptr = ptr; + d = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); + + /* \X is literal X; any other special means the '-' was literal */ + if (d < 0) { + ptr = oldptr - 2; + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + } + } + + /* The check that the two values are in the correct order happens in + the pre-pass. Optimize one-character ranges */ + + if (d == c) + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + + /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless + matching, we have to use an XCLASS with extra data items. Caseless + matching for characters > 127 is available only if UCP support is + available. */ + + if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) { + class_utf8 = true; + + /* With UCP support, we can find the other case equivalents of + the relevant characters. There may be several ranges. Optimize how + they fit with the basic range. */ + + if (options & IgnoreCaseOption) { + int occ, ocd; + int cc = c; + int origd = d; + while (getOthercaseRange(&cc, origd, &occ, &ocd)) { + if (occ >= c && ocd <= d) + continue; /* Skip embedded ranges */ + + if (occ < c && ocd >= c - 1) /* Extend the basic range */ + { /* if there is overlap, */ + c = occ; /* noting that if occ < c */ + continue; /* we can't have ocd > d */ + } /* because a subrange is */ + if (ocd > d && occ <= d + 1) /* always shorter than */ + { /* the basic range. */ + d = ocd; + continue; + } + + if (occ == ocd) + *class_utf8data++ = XCL_SINGLE; + else { + *class_utf8data++ = XCL_RANGE; + class_utf8data += encodeUTF8(occ, class_utf8data); + } + class_utf8data += encodeUTF8(ocd, class_utf8data); + } + } + + /* Now record the original range, possibly modified for UCP caseless + overlapping ranges. */ + + *class_utf8data++ = XCL_RANGE; + class_utf8data += encodeUTF8(c, class_utf8data); + class_utf8data += encodeUTF8(d, class_utf8data); + + /* With UCP support, we are done. Without UCP support, there is no + caseless matching for UTF-8 characters > 127; we can use the bit map + for the smaller ones. */ + + continue; /* With next character in the class */ + } + + /* We use the bit map for all cases when not in UTF-8 mode; else + ranges that lie entirely within 0-127 when there is UCP support; else + for partial ranges without UCP support. */ + + for (; c <= d; c++) { + classbits[c/8] |= (1 << (c&7)); + if (options & IgnoreCaseOption) { + int uc = flipCase(c); + classbits[uc/8] |= (1 << (uc&7)); + } + classCharCount++; /* in case a one-char range */ + classLastChar = c; + } + + continue; /* Go get the next char in the class */ + } + + /* Handle a lone single character - we can get here for a normal + non-escape char, or after \ that introduces a single character or for an + apparent range that isn't. */ + + LONE_SINGLE_CHARACTER: + + /* Handle a character that cannot go in the bit map */ + + if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) { + class_utf8 = true; + *class_utf8data++ = XCL_SINGLE; + class_utf8data += encodeUTF8(c, class_utf8data); + + if (options & IgnoreCaseOption) { + int othercase; + if ((othercase = jsc_pcre_ucp_othercase(c)) >= 0) { + *class_utf8data++ = XCL_SINGLE; + class_utf8data += encodeUTF8(othercase, class_utf8data); + } + } + } else { + /* Handle a single-byte character */ + classbits[c/8] |= (1 << (c&7)); + if (options & IgnoreCaseOption) { + c = flipCase(c); + classbits[c/8] |= (1 << (c&7)); + } + classCharCount++; + classLastChar = c; + } + } + + /* If classCharCount is 1, we saw precisely one character whose value is + less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we + can optimize the negative case only if there were no characters >= 128 + because OP_NOT and the related opcodes like OP_NOTSTAR operate on + single-bytes only. This is an historical hangover. Maybe one day we can + tidy these opcodes to handle multi-byte characters. + + The optimization throws away the bit map. We turn the item into a + 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note + that OP_NOT does not support multibyte characters. In the positive case, it + can cause firstByte to be set. Otherwise, there can be no first char if + this item is first, whatever repeat count may follow. In the case of + reqByte, save the previous value for reinstating. */ + + if (classCharCount == 1 && (!class_utf8 && (!negateClass || classLastChar < 128))) { + zeroReqByte = reqByte; + + /* The OP_NOT opcode works on one-byte characters only. */ + + if (negateClass) { + if (firstByte == REQ_UNSET) + firstByte = REQ_NONE; + zeroFirstByte = firstByte; + *code++ = OP_NOT; + *code++ = classLastChar; + break; + } + + /* For a single, positive character, get the value into c, and + then we can handle this with the normal one-character code. */ + + c = classLastChar; + goto NORMAL_CHAR; + } /* End of 1-char optimization */ + + /* The general case - not the one-char optimization. If this is the first + thing in the branch, there can be no first char setting, whatever the + repeat count. Any reqByte setting must remain unchanged after any kind of + repeat. */ + + if (firstByte == REQ_UNSET) firstByte = REQ_NONE; + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + + /* If there are characters with values > 255, we have to compile an + extended class, with its own opcode. If there are no characters < 256, + we can omit the bitmap. */ + + if (class_utf8 && !shouldFlipNegation) { + *class_utf8data++ = XCL_END; /* Marks the end of extra data */ + *code++ = OP_XCLASS; + code += LINK_SIZE; + *code = negateClass? XCL_NOT : 0; + + /* If the map is required, install it, and move on to the end of + the extra data */ + + if (classCharCount > 0) { + *code++ |= XCL_MAP; + memcpy(code, classbits, 32); + code = class_utf8data; + } + + /* If the map is not required, slide down the extra data. */ + + else { + int len = class_utf8data - (code + 33); + memmove(code + 1, code + 33, len); + code += len + 1; + } + + /* Now fill in the complete length of the item */ + + putLinkValue(previous + 1, code - previous); + break; /* End of class handling */ + } + + /* If there are no characters > 255, negate the 32-byte map if necessary, + and copy it into the code vector. If this is the first thing in the branch, + there can be no first char setting, whatever the repeat count. Any reqByte + setting must remain unchanged after any kind of repeat. */ + + *code++ = (negateClass == shouldFlipNegation) ? OP_CLASS : OP_NCLASS; + if (negateClass) + for (c = 0; c < 32; c++) + code[c] = ~classbits[c]; + else + memcpy(code, classbits, 32); + code += 32; + break; + } + + /* Various kinds of repeat; '{' is not necessarily a quantifier, but this + has been tested above. */ + + case '{': + if (!isQuantifier) + goto NORMAL_CHAR; + ptr = readRepeatCounts(ptr + 1, &repeatMin, &repeat_max, errorCodePtr); + if (*errorCodePtr) + goto FAILED; + goto REPEAT; + + case '*': + repeatMin = 0; + repeat_max = -1; + goto REPEAT; + + case '+': + repeatMin = 1; + repeat_max = -1; + goto REPEAT; + + case '?': + repeatMin = 0; + repeat_max = 1; + + REPEAT: + if (!previous) { + *errorCodePtr = ERR9; + goto FAILED; + } + + if (repeatMin == 0) { + firstByte = zeroFirstByte; /* Adjust for zero repeat */ + reqByte = zeroReqByte; /* Ditto */ + } + + /* Remember whether this is a variable length repeat */ + + reqvary = (repeatMin == repeat_max) ? 0 : REQ_VARY; + + opType = 0; /* Default single-char op codes */ + + /* Save start of previous item, in case we have to move it up to make space + for an inserted OP_ONCE for the additional '+' extension. */ + /* FIXME: Probably don't need this because we don't use OP_ONCE. */ + + tempcode = previous; + + /* If the next character is '+', we have a possessive quantifier. This + implies greediness, whatever the setting of the PCRE_UNGREEDY option. + If the next character is '?' this is a minimizing repeat, by default, + but if PCRE_UNGREEDY is set, it works the other way round. We change the + repeat type to the non-default. */ + + if (safelyCheckNextChar(ptr, patternEnd, '?')) { + repeatType = 1; + ptr++; + } else + repeatType = 0; + + /* If previous was a character match, abolish the item and generate a + repeat item instead. If a char item has a minumum of more than one, ensure + that it is set in reqByte - it might not be if a sequence such as x{3} is + the first thing in a branch because the x will have gone into firstByte + instead. */ + + if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) { + /* Deal with UTF-8 characters that take up more than one byte. It's + easier to write this out separately than try to macrify it. Use c to + hold the length of the character in bytes, plus 0x80 to flag that it's a + length rather than a small character. */ + + if (code[-1] & 0x80) { + unsigned char *lastchar = code - 1; + while((*lastchar & 0xc0) == 0x80) + lastchar--; + c = code - lastchar; /* Length of UTF-8 character */ + memcpy(utf8_char, lastchar, c); /* Save the char */ + c |= 0x80; /* Flag c as a length */ + } + else { + c = code[-1]; + if (repeatMin > 1) + reqByte = c | reqCaseOpt | cd.reqVaryOpt; + } + + goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ + } + + else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) { + c = previous[1]; + if (repeatMin > 1) + reqByte = c | reqCaseOpt | cd.reqVaryOpt; + goto OUTPUT_SINGLE_REPEAT; + } + + /* If previous was a single negated character ([^a] or similar), we use + one of the special opcodes, replacing it. The code is shared with single- + character repeats by setting opt_type to add a suitable offset into + repeatType. OP_NOT is currently used only for single-byte chars. */ + + else if (*previous == OP_NOT) { + opType = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ + c = previous[1]; + goto OUTPUT_SINGLE_REPEAT; + } + + /* If previous was a character type match (\d or similar), abolish it and + create a suitable repeat item. The code is shared with single-character + repeats by setting opType to add a suitable offset into repeatType. */ + + else if (*previous <= OP_NOT_NEWLINE) { + opType = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ + c = *previous; + + OUTPUT_SINGLE_REPEAT: + int prop_type = -1; + int prop_value = -1; + + unsigned char* oldcode = code; + code = previous; /* Usually overwrite previous item */ + + /* If the maximum is zero then the minimum must also be zero; Perl allows + this case, so we do too - by simply omitting the item altogether. */ + + if (repeat_max == 0) + goto END_REPEAT; + + /* Combine the opType with the repeatType */ + + repeatType += opType; + + /* A minimum of zero is handled either as the special case * or ?, or as + an UPTO, with the maximum given. */ + + if (repeatMin == 0) { + if (repeat_max == -1) + *code++ = OP_STAR + repeatType; + else if (repeat_max == 1) + *code++ = OP_QUERY + repeatType; + else { + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* A repeat minimum of 1 is optimized into some special cases. If the + maximum is unlimited, we use OP_PLUS. Otherwise, the original item it + left in place and, if the maximum is greater than 1, we use OP_UPTO with + one less than the maximum. */ + + else if (repeatMin == 1) { + if (repeat_max == -1) + *code++ = OP_PLUS + repeatType; + else { + code = oldcode; /* leave previous item in place */ + if (repeat_max == 1) + goto END_REPEAT; + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max - 1); + } + } + + /* The case {n,n} is just an EXACT, while the general case {n,m} is + handled as an EXACT followed by an UPTO. */ + + else { + *code++ = OP_EXACT + opType; /* NB EXACT doesn't have repeatType */ + put2ByteValueAndAdvance(code, repeatMin); + + /* If the maximum is unlimited, insert an OP_STAR. Before doing so, + we have to insert the character for the previous code. For a repeated + Unicode property match, there are two extra bytes that define the + required property. In UTF-8 mode, long characters have their length in + c, with the 0x80 bit as a flag. */ + + if (repeat_max < 0) { + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else { + *code++ = c; + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + } + *code++ = OP_STAR + repeatType; + } + + /* Else insert an UPTO if the max is greater than the min, again + preceded by the character, for the previously inserted code. */ + + else if (repeat_max != repeatMin) { + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else + *code++ = c; + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + repeat_max -= repeatMin; + *code++ = OP_UPTO + repeatType; + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* The character or character type itself comes last in all cases. */ + + if (c >= 128) { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } else + *code++ = c; + + /* For a repeated Unicode property match, there are two extra bytes that + define the required property. */ + + if (prop_type >= 0) { + *code++ = prop_type; + *code++ = prop_value; + } + } + + /* If previous was a character class or a back reference, we put the repeat + stuff after it, but just skip the item if the repeat was {0,0}. */ + + else if (*previous == OP_CLASS || + *previous == OP_NCLASS || + *previous == OP_XCLASS || + *previous == OP_REF) + { + if (repeat_max == 0) { + code = previous; + goto END_REPEAT; + } + + if (repeatMin == 0 && repeat_max == -1) + *code++ = OP_CRSTAR + repeatType; + else if (repeatMin == 1 && repeat_max == -1) + *code++ = OP_CRPLUS + repeatType; + else if (repeatMin == 0 && repeat_max == 1) + *code++ = OP_CRQUERY + repeatType; + else { + *code++ = OP_CRRANGE + repeatType; + put2ByteValueAndAdvance(code, repeatMin); + if (repeat_max == -1) + repeat_max = 0; /* 2-byte encoding for max */ + put2ByteValueAndAdvance(code, repeat_max); + } + } + + /* If previous was a bracket group, we may have to replicate it in certain + cases. */ + + else if (*previous >= OP_BRA) { + int ketoffset = 0; + int len = code - previous; + unsigned char* bralink = NULL; + int nested = get2ByteValue(previous + 1 + LINK_SIZE); + + /* If the maximum repeat count is unlimited, find the end of the bracket + by scanning through from the start, and compute the offset back to it + from the current code pointer. There may be an OP_OPT setting following + the final KET, so we can't find the end just by going back from the code + pointer. */ + + if (repeat_max == -1) { + const unsigned char* ket = previous; + advanceToEndOfBracket(ket); + ketoffset = code - ket; + } + + /* The case of a zero minimum is special because of the need to stick + OP_BRAZERO in front of it, and because the group appears once in the + data, whereas in other cases it appears the minimum number of times. For + this reason, it is simplest to treat this case separately, as otherwise + the code gets far too messy. There are several special subcases when the + minimum is zero. */ + + if (repeatMin == 0) { + /* If the maximum is also zero, we just omit the group from the output + altogether. */ + + if (repeat_max == 0) { + code = previous; + goto END_REPEAT; + } + + /* If the maximum is 1 or unlimited, we just have to stick in the + BRAZERO and do no more at this point. However, we do need to adjust + any OP_RECURSE calls inside the group that refer to the group itself or + any internal group, because the offset is from the start of the whole + regex. Temporarily terminate the pattern while doing this. */ + + if (repeat_max <= 1) { + *code = OP_END; + memmove(previous+1, previous, len); + code++; + *previous++ = OP_BRAZERO + repeatType; + } + + /* If the maximum is greater than 1 and limited, we have to replicate + in a nested fashion, sticking OP_BRAZERO before each set of brackets. + The first one has to be handled carefully because it's the original + copy, which has to be moved up. The remainder can be handled by code + that is common with the non-zero minimum case below. We have to + adjust the value of repeat_max, since one less copy is required. */ + + else { + *code = OP_END; + memmove(previous + 4 + LINK_SIZE, previous, len); + code += 4 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeatType; + *previous++ = OP_BRA; + + /* We chain together the bracket offset fields that have to be + filled in later when the ends of the brackets are reached. */ + + int offset = (!bralink) ? 0 : previous - bralink; + bralink = previous; + putLinkValueAllowZeroAndAdvance(previous, offset); + put2ByteValueAndAdvance(previous, nested); + } + + repeat_max--; + } + + /* If the minimum is greater than zero, replicate the group as many + times as necessary, and adjust the maximum to the number of subsequent + copies that we need. If we set a first char from the group, and didn't + set a required char, copy the latter from the former. */ + + else { + if (repeatMin > 1) { + if (didGroupSetFirstByte && reqByte < 0) + reqByte = firstByte; + for (int i = 1; i < repeatMin; i++) { + memcpy(code, previous, len); + code += len; + } + } + if (repeat_max > 0) + repeat_max -= repeatMin; + } + + /* This code is common to both the zero and non-zero minimum cases. If + the maximum is limited, it replicates the group in a nested fashion, + remembering the bracket starts on a stack. In the case of a zero minimum, + the first one was set up above. In all cases the repeat_max now specifies + the number of additional copies needed. */ + + if (repeat_max >= 0) { + for (int i = repeat_max - 1; i >= 0; i--) { + *code++ = OP_BRAZERO + repeatType; + + /* All but the final copy start a new nesting, maintaining the + chain of brackets outstanding. */ + + if (i != 0) { + *code++ = OP_BRA; + int offset = (!bralink) ? 0 : code - bralink; + bralink = code; + putLinkValueAllowZeroAndAdvance(code, offset); + put2ByteValueAndAdvance(code, nested); + } + + memcpy(code, previous, len); + code += len; + } + + /* Now chain through the pending brackets, and fill in their length + fields (which are holding the chain links pro tem). */ + + while (bralink) { + int offset = code - bralink + 1; + unsigned char* bra = code - offset; + int oldlinkoffset = getLinkValueAllowZero(bra + 1); + bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset; + *code++ = OP_KET; + putLinkValueAndAdvance(code, offset); + putLinkValue(bra + 1, offset); + } + } + + /* If the maximum is unlimited, set a repeater in the final copy. We + can't just offset backwards from the current code point, because we + don't know if there's been an options resetting after the ket. The + correct offset was computed above. */ + + else + code[-ketoffset] = OP_KETRMAX + repeatType; + } + + // A quantifier after an assertion is mostly meaningless, but it + // can nullify the assertion if it has a 0 minimum. + else if (*previous == OP_ASSERT || *previous == OP_ASSERT_NOT) { + if (repeatMin == 0) { + code = previous; + goto END_REPEAT; + } + } + + /* Else there's some kind of shambles */ + + else { + *errorCodePtr = ERR11; + goto FAILED; + } + + /* In all case we no longer have a previous item. We also set the + "follows varying string" flag for subsequently encountered reqbytes if + it isn't already set and we have just passed a varying length item. */ + + END_REPEAT: + previous = NULL; + cd.reqVaryOpt |= reqvary; + break; + + /* Start of nested bracket sub-expression, or comment or lookahead or + lookbehind or option setting or condition. First deal with special things + that can come after a bracket; all are introduced by ?, and the appearance + of any of them means that this is not a referencing group. They were + checked for validity in the first pass over the string, so we don't have to + check for syntax errors here. */ + + case '(': + { + skipBytes = 2; + unsigned minBracket = *brackets + 1; + if (*(++ptr) == '?') { + switch (*(++ptr)) { + case ':': /* Non-extracting bracket */ + bravalue = OP_BRA; + ptr++; + break; + + case '=': /* Positive lookahead */ + bravalue = OP_ASSERT; + ptr++; + break; + + case '!': /* Negative lookahead */ + bravalue = OP_ASSERT_NOT; + ptr++; + break; + + /* Character after (? not specially recognized */ + + default: + *errorCodePtr = ERR12; + goto FAILED; + } + } + + /* Else we have a referencing group; adjust the opcode. If the bracket + number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and + arrange for the true number to follow later, in an OP_BRANUMBER item. */ + + else { + if (++(*brackets) > EXTRACT_BASIC_MAX) { + bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; + code[3 + LINK_SIZE] = OP_BRANUMBER; + put2ByteValue(code + 4 + LINK_SIZE, *brackets); + skipBytes = 5; + } + else + bravalue = OP_BRA + *brackets; + } + + /* Process nested bracketed re. We copy code into a non-variable + in order to be able to pass its address because some compilers + complain otherwise. Pass in a new setting for the ims options + if they have changed. */ + + previous = code; + *code = bravalue; + tempcode = code; + tempreqvary = cd.reqVaryOpt; /* Save value before bracket */ + { + unsigned bracketsBeforeRecursion = *brackets; + if (!compileBracket( + options, + brackets, /* Extracting bracket count */ + &tempcode, /* Where to put code (updated) */ + &ptr, /* Input pointer (updated) */ + patternEnd, + errorCodePtr, /* Where to put an error message */ + skipBytes, /* Skip over OP_BRANUMBER */ + &subFirstByte, /* For possible first char */ + &subReqByte, /* For possible last char */ + cd)) /* Tables block */ + goto FAILED; + unsigned enclosedBrackets = (*brackets - bracketsBeforeRecursion); + unsigned limitBracket = minBracket + enclosedBrackets + (bravalue > OP_BRA); + if (!((minBracket & 0xff) == minBracket && (limitBracket & 0xff) == limitBracket)) { + *errorCodePtr = ERR17; + return false; + } + JS_ASSERT(minBracket <= limitBracket); + put2ByteValue(code + 1 + LINK_SIZE, minBracket << 8 | limitBracket); + } + + /* At the end of compiling, code is still pointing to the start of the + group, while tempcode has been updated to point past the end of the group + and any option resetting that may follow it. The pattern pointer (ptr) + is on the bracket. */ + + /* Handle updating of the required and first characters. Update for normal + brackets of all kinds, and conditions with two branches (see code above). + If the bracket is followed by a quantifier with zero repeat, we have to + back off. Hence the definition of zeroReqByte and zeroFirstByte outside the + main loop so that they can be accessed for the back off. */ + + zeroReqByte = reqByte; + zeroFirstByte = firstByte; + didGroupSetFirstByte = false; + + if (bravalue >= OP_BRA) { + /* If we have not yet set a firstByte in this branch, take it from the + subpattern, remembering that it was set here so that a repeat of more + than one can replicate it as reqByte if necessary. If the subpattern has + no firstByte, set "none" for the whole branch. In both cases, a zero + repeat forces firstByte to "none". */ + + if (firstByte == REQ_UNSET) { + if (subFirstByte >= 0) { + firstByte = subFirstByte; + didGroupSetFirstByte = true; + } + else + firstByte = REQ_NONE; + zeroFirstByte = REQ_NONE; + } + + /* If firstByte was previously set, convert the subpattern's firstByte + into reqByte if there wasn't one, using the vary flag that was in + existence beforehand. */ + + else if (subFirstByte >= 0 && subReqByte < 0) + subReqByte = subFirstByte | tempreqvary; + + /* If the subpattern set a required byte (or set a first byte that isn't + really the first byte - see above), set it. */ + + if (subReqByte >= 0) + reqByte = subReqByte; + } + + /* For a forward assertion, we take the reqByte, if set. This can be + helpful if the pattern that follows the assertion doesn't set a different + char. For example, it's useful for /(?=abcde).+/. We can't set firstByte + for an assertion, however because it leads to incorrect effect for patterns + such as /(?=a)a.+/ when the "real" "a" would then become a reqByte instead + of a firstByte. This is overcome by a scan at the end if there's no + firstByte, looking for an asserted first char. */ + + else if (bravalue == OP_ASSERT && subReqByte >= 0) + reqByte = subReqByte; + + /* Now update the main code pointer to the end of the group. */ + + code = tempcode; + + /* Error if hit end of pattern */ + + if (ptr >= patternEnd || *ptr != ')') { + *errorCodePtr = ERR14; + goto FAILED; + } + break; + + } + /* Check \ for being a real metacharacter; if not, fall through and handle + it as a data character at the start of a string. Escape items are checked + for validity in the pre-compiling pass. */ + + case '\\': + tempptr = ptr; + c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, false); + + /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values + are arranged to be the negation of the corresponding OP_values. For the + back references, the values are ESC_REF plus the reference number. Only + back references and those types that consume a character may be repeated. + We can test for values between ESC_b and ESC_w for the latter; this may + have to change if any new ones are ever created. */ + + if (c < 0) { + /* For metasequences that actually match a character, we disable the + setting of a first character if it hasn't already been set. */ + + if (firstByte == REQ_UNSET && -c > ESC_b && -c <= ESC_w) + firstByte = REQ_NONE; + + /* Set values to reset to if this is followed by a zero repeat. */ + + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + + /* Back references are handled specially */ + + if (-c >= ESC_REF) { + int number = -c - ESC_REF; + previous = code; + *code++ = OP_REF; + put2ByteValueAndAdvance(code, number); + } + + /* For the rest, we can obtain the OP value by negating the escape + value */ + + else { + previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL; + *code++ = -c; + } + continue; + } + + /* Fall through. */ + + /* Handle a literal character. It is guaranteed not to be whitespace or # + when the extended flag is set. If we are in UTF-8 mode, it may be a + multi-byte literal character. */ + + default: + NORMAL_CHAR: + + previous = code; + + if (c < 128) { + mcLength = 1; + mcbuffer[0] = c; + + if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') { + *code++ = OP_ASCII_LETTER_IGNORING_CASE; + *code++ = c | 0x20; + } else { + *code++ = OP_ASCII_CHAR; + *code++ = c; + } + } else { + mcLength = encodeUTF8(c, mcbuffer); + + *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR; + for (c = 0; c < mcLength; c++) + *code++ = mcbuffer[c]; + } + + /* Set the first and required bytes appropriately. If no previous first + byte, set it from this character, but revert to none on a zero repeat. + Otherwise, leave the firstByte value alone, and don't change it on a zero + repeat. */ + + if (firstByte == REQ_UNSET) { + zeroFirstByte = REQ_NONE; + zeroReqByte = reqByte; + + /* If the character is more than one byte long, we can set firstByte + only if it is not to be matched caselessly. */ + + if (mcLength == 1 || reqCaseOpt == 0) { + firstByte = mcbuffer[0] | reqCaseOpt; + if (mcLength != 1) + reqByte = code[-1] | cd.reqVaryOpt; + } + else + firstByte = reqByte = REQ_NONE; + } + + /* firstByte was previously set; we can set reqByte only the length is + 1 or the matching is caseful. */ + + else { + zeroFirstByte = firstByte; + zeroReqByte = reqByte; + if (mcLength == 1 || reqCaseOpt == 0) + reqByte = code[-1] | reqCaseOpt | cd.reqVaryOpt; + } + + break; /* End of literal character handling */ + } + } /* end of big loop */ + + /* Control never reaches here by falling through, only by a goto for all the + error states. Pass back the position in the pattern so that it can be displayed + to the user for diagnosing the error. */ + +FAILED: + *ptrPtr = ptr; + return false; +} + +/************************************************* +* Compile sequence of alternatives * +*************************************************/ + +/* On entry, ptr is pointing past the bracket character, but on return +it points to the closing bracket, or vertical bar, or end of string. +The code variable is pointing at the byte into which the BRA operator has been +stored. If the ims options are changed at the start (for a (?ims: group) or +during any branch, we need to insert an OP_OPT item at the start of every +following branch to ensure they get set correctly at run time, and also pass +the new options into every subsequent branch compile. + +Argument: + options option bits, including any changes for this subpattern + brackets -> int containing the number of extracting brackets used + codePtr -> the address of the current code pointer + ptrPtr -> the address of the current pattern pointer + errorCodePtr -> pointer to error code variable + skipBytes skip this many bytes at start (for OP_BRANUMBER) + firstbyteptr place to put the first required character, or a negative number + reqbyteptr place to put the last required character, or a negative number + cd points to the data block with tables pointers etc. + +Returns: true on success +*/ + +static bool +compileBracket(int options, int* brackets, unsigned char** codePtr, + const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int skipBytes, + int* firstbyteptr, int* reqbyteptr, CompileData& cd) +{ + const UChar* ptr = *ptrPtr; + unsigned char* code = *codePtr; + unsigned char* lastBranch = code; + unsigned char* start_bracket = code; + int firstByte = REQ_UNSET; + int reqByte = REQ_UNSET; + + /* Offset is set zero to mark that this bracket is still open */ + + putLinkValueAllowZero(code + 1, 0); + code += 1 + LINK_SIZE + skipBytes; + + /* Loop for each alternative branch */ + + while (true) { + /* Now compile the branch */ + + int branchFirstByte; + int branchReqByte; + if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorCodePtr, + &branchFirstByte, &branchReqByte, cd)) { + *ptrPtr = ptr; + return false; + } + + /* If this is the first branch, the firstByte and reqByte values for the + branch become the values for the regex. */ + + if (*lastBranch != OP_ALT) { + firstByte = branchFirstByte; + reqByte = branchReqByte; + } + + /* If this is not the first branch, the first char and reqByte have to + match the values from all the previous branches, except that if the previous + value for reqByte didn't have REQ_VARY set, it can still match, and we set + REQ_VARY for the regex. */ + + else { + /* If we previously had a firstByte, but it doesn't match the new branch, + we have to abandon the firstByte for the regex, but if there was previously + no reqByte, it takes on the value of the old firstByte. */ + + if (firstByte >= 0 && firstByte != branchFirstByte) { + if (reqByte < 0) + reqByte = firstByte; + firstByte = REQ_NONE; + } + + /* If we (now or from before) have no firstByte, a firstByte from the + branch becomes a reqByte if there isn't a branch reqByte. */ + + if (firstByte < 0 && branchFirstByte >= 0 && branchReqByte < 0) + branchReqByte = branchFirstByte; + + /* Now ensure that the reqbytes match */ + + if ((reqByte & ~REQ_VARY) != (branchReqByte & ~REQ_VARY)) + reqByte = REQ_NONE; + else + reqByte |= branchReqByte; /* To "or" REQ_VARY */ + } + + /* Reached end of expression, either ')' or end of pattern. Go back through + the alternative branches and reverse the chain of offsets, with the field in + the BRA item now becoming an offset to the first alternative. If there are + no alternatives, it points to the end of the group. The length in the + terminating ket is always the length of the whole bracketed item. + Return leaving the pointer at the terminating char. */ + + if (ptr >= patternEnd || *ptr != '|') { + int length = code - lastBranch; + do { + int prevLength = getLinkValueAllowZero(lastBranch + 1); + putLinkValue(lastBranch + 1, length); + length = prevLength; + lastBranch -= length; + } while (length > 0); + + /* Fill in the ket */ + + *code = OP_KET; + putLinkValue(code + 1, code - start_bracket); + code += 1 + LINK_SIZE; + + /* Set values to pass back */ + + *codePtr = code; + *ptrPtr = ptr; + *firstbyteptr = firstByte; + *reqbyteptr = reqByte; + return true; + } + + /* Another branch follows; insert an "or" node. Its length field points back + to the previous branch while the bracket remains open. At the end the chain + is reversed. It's done like this so that the start of the bracket has a + zero offset until it is closed, making it possible to detect recursion. */ + + *code = OP_ALT; + putLinkValue(code + 1, code - lastBranch); + lastBranch = code; + code += 1 + LINK_SIZE; + ptr++; + } + JS_NOT_REACHED("No fallthru."); +} + +/************************************************* +* Check for anchored expression * +*************************************************/ + +/* Try to find out if this is an anchored regular expression. Consider each +alternative branch. If they all start OP_CIRC, or with a bracket +all of whose alternatives start OP_CIRC (recurse ad lib), then +it's anchored. + +Arguments: + code points to start of expression (the bracket) + captureMap a bitmap of which brackets we are inside while testing; this + handles up to substring 31; all brackets after that share + the zero bit + backrefMap the back reference bitmap +*/ + +static bool branchIsAnchored(const unsigned char* code) +{ + const unsigned char* scode = firstSignificantOpcode(code); + int op = *scode; + + /* Brackets */ + if (op >= OP_BRA || op == OP_ASSERT) + return bracketIsAnchored(scode); + + /* Check for explicit anchoring */ + return op == OP_CIRC; +} + +static bool bracketIsAnchored(const unsigned char* code) +{ + do { + if (!branchIsAnchored(code + 1 + LINK_SIZE)) + return false; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); /* Loop for each alternative */ + return true; +} + +/************************************************* +* Check for starting with ^ or .* * +*************************************************/ + +/* This is called to find out if every branch starts with ^ or .* so that +"first char" processing can be done to speed things up in multiline +matching and for non-DOTALL patterns that start with .* (which must start at +the beginning or after \n) + +Except when the .* appears inside capturing parentheses, and there is a +subsequent back reference to those parentheses. By keeping a bitmap of the +first 31 back references, we can catch some of the more common cases more +precisely; all the greater back references share a single bit. + +Arguments: + code points to start of expression (the bracket) + captureMap a bitmap of which brackets we are inside while testing; this + handles up to substring 31; all brackets after that share + the zero bit + backrefMap the back reference bitmap +*/ + +static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) +{ + const unsigned char* scode = firstSignificantOpcode(code); + int op = *scode; + + /* Capturing brackets */ + if (op > OP_BRA) { + int captureNum = op - OP_BRA; + if (captureNum > EXTRACT_BASIC_MAX) + captureNum = get2ByteValue(scode + 2 + LINK_SIZE); + int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1; + return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap); + } + + /* Other brackets */ + if (op == OP_BRA || op == OP_ASSERT) + return bracketNeedsLineStart(scode, captureMap, backrefMap); + + /* .* means "start at start or after \n" if it isn't in brackets that + may be referenced. */ + + if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) + return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap); + + /* Explicit ^ */ + return op == OP_CIRC || op == OP_BOL; +} + +static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) +{ + do { + if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap)) + return false; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); /* Loop for each alternative */ + return true; +} + +/************************************************* +* Check for asserted fixed first char * +*************************************************/ + +/* During compilation, the "first char" settings from forward assertions are +discarded, because they can cause conflicts with actual literals that follow. +However, if we end up without a first char setting for an unanchored pattern, +it is worth scanning the regex to see if there is an initial asserted first +char. If all branches start with the same asserted char, or with a bracket all +of whose alternatives start with the same asserted char (recurse ad lib), then +we return that char, otherwise -1. + +Arguments: + code points to start of expression (the bracket) + options pointer to the options (used to check casing changes) + inassert true if in an assertion + +Returns: -1 or the fixed first char +*/ + +static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert) +{ + const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code); + int op = *scode; + + if (op >= OP_BRA) + op = OP_BRA; + + switch (op) { + default: + return -1; + + case OP_BRA: + case OP_ASSERT: + return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT); + + case OP_EXACT: + scode += 2; + /* Fall through */ + + case OP_CHAR: + case OP_CHAR_IGNORING_CASE: + case OP_ASCII_CHAR: + case OP_ASCII_LETTER_IGNORING_CASE: + case OP_PLUS: + case OP_MINPLUS: + if (!inassert) + return -1; + return scode[1]; + } +} + +static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert) +{ + int c = -1; + do { + int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert); + if (d < 0) + return -1; + if (c < 0) + c = d; + else if (c != d) + return -1; + code += getLinkValue(code + 1); + } while (*code == OP_ALT); + return c; +} + +static inline int multiplyWithOverflowCheck(int a, int b) +{ + if (!a || !b) + return 0; + if (a > MAX_PATTERN_SIZE / b) + return -1; + return a * b; +} + +static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase, + CompileData& cd, ErrorCode& errorcode) +{ + /* Make a pass over the pattern to compute the + amount of store required to hold the compiled code. This does not have to be + perfect as long as errors are overestimates. */ + + if (patternLength > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + + int length = BRA_LEN; /* For initial BRA. */ + int branch_extra = 0; + int lastitemlength = 0; + unsigned brastackptr = 0; + int brastack[BRASTACK_SIZE]; + unsigned char bralenstack[BRASTACK_SIZE]; + int bracount = 0; + + const UChar* ptr = (const UChar*)(pattern - 1); + const UChar* patternEnd = (const UChar*)(pattern + patternLength); + + while (++ptr < patternEnd) { + int minRepeats = 0, maxRepeats = 0; + int c = *ptr; + + switch (c) { + /* A backslashed item may be an escaped data character or it may be a + character type. */ + + case '\\': + c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false); + if (errorcode != 0) + return -1; + + lastitemlength = 1; /* Default length of last item for repeats */ + + if (c >= 0) { /* Data character */ + length += 2; /* For a one-byte character */ + + if (c > 127) { + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (c <= jsc_pcre_utf8_table1[i]) break; + length += i; + lastitemlength += i; + } + + continue; + } + + /* Other escapes need one byte */ + + length++; + + /* A back reference needs an additional 2 bytes, plus either one or 5 + bytes for a repeat. We also need to keep the value of the highest + back reference. */ + + if (c <= -ESC_REF) { + int refnum = -c - ESC_REF; + cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1; + if (refnum > cd.topBackref) + cd.topBackref = refnum; + length += 2; /* For single back reference */ + if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode) + return -1; + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + else + length += 5; + if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; + } + } + continue; + + case '^': /* Single-byte metacharacters */ + case '.': + case '$': + length++; + lastitemlength = 1; + continue; + + case '*': /* These repeats won't be after brackets; */ + case '+': /* those are handled separately */ + case '?': + length++; + goto POSSESSIVE; + + /* This covers the cases of braced repeats after a single char, metachar, + class, or back reference. */ + + case '{': + if (!isCountedRepeat(ptr + 1, patternEnd)) + goto NORMAL_CHAR; + ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode); + if (errorcode != 0) + return -1; + + /* These special cases just insert one extra opcode */ + + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + + /* These cases might insert additional copies of a preceding character. */ + + else { + if (minRepeats != 1) { + length -= lastitemlength; /* Uncount the original char or metachar */ + if (minRepeats > 0) + length += 5 + lastitemlength; + } + length += lastitemlength + ((maxRepeats > 0) ? 5 : 1); + } + + if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; /* Needs no extra length */ + + POSSESSIVE: /* Test for possessive quantifier */ + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */ + } + continue; + + /* An alternation contains an offset to the next branch or ket. If any ims + options changed in the previous branch(es), and/or if we are in a + lookbehind assertion, extra space will be needed at the start of the + branch. This is handled by branch_extra. */ + + case '|': + if (brastackptr == 0) + cd.needOuterBracket = true; + length += 1 + LINK_SIZE + branch_extra; + continue; + + /* A character class uses 33 characters provided that all the character + values are less than 256. Otherwise, it uses a bit map for low valued + characters, and individual items for others. Don't worry about character + types that aren't allowed in classes - they'll get picked up during the + compile. A character class that contains only one single-byte character + uses 2 or 3 bytes, depending on whether it is negated or not. Notice this + where we can. (In UTF-8 mode we can do this only for chars < 128.) */ + + case '[': { + int class_optcount; + if (*(++ptr) == '^') { + class_optcount = 10; /* Greater than one */ + ptr++; + } + else + class_optcount = 0; + + bool class_utf8 = false; + + for (; ptr < patternEnd && *ptr != ']'; ++ptr) { + /* Check for escapes */ + + if (*ptr == '\\') { + c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); + if (errorcode != 0) + return -1; + + /* Handle escapes that turn into characters */ + + if (c >= 0) + goto NON_SPECIAL_CHARACTER; + + /* Escapes that are meta-things. The normal ones just affect the + bit map, but Unicode properties require an XCLASS extended item. */ + + else + class_optcount = 10; /* \d, \s etc; make sure > 1 */ + } + + /* Anything else increments the possible optimization count. We have to + detect ranges here so that we can compute the number of extra ranges for + caseless wide characters when UCP support is available. If there are wide + characters, we are going to have to use an XCLASS, even for single + characters. */ + + else { + c = *ptr; + + /* Come here from handling \ above when it escapes to a char value */ + + NON_SPECIAL_CHARACTER: + class_optcount++; + + int d = -1; + if (safelyCheckNextChar(ptr, patternEnd, '-')) { + const UChar* hyptr = ptr++; + if (safelyCheckNextChar(ptr, patternEnd, '\\')) { + ptr++; + d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); + if (errorcode != 0) + return -1; + } + else if ((ptr + 1 < patternEnd) && ptr[1] != ']') + d = *++ptr; + if (d < 0) + ptr = hyptr; /* go back to hyphen as data */ + } + + /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or > + 127 for caseless matching, we will need to use an XCLASS. */ + + if (d >= 0) { + class_optcount = 10; /* Ensure > 1 */ + if (d < c) { + errorcode = ERR8; + return -1; + } + + if ((d > 255 || (ignoreCase && d > 127))) { + unsigned char buffer[6]; + if (!class_utf8) /* Allow for XCLASS overhead */ + { + class_utf8 = true; + length += LINK_SIZE + 2; + } + + /* If we have UCP support, find out how many extra ranges are + needed to map the other case of characters within this range. We + have to mimic the range optimization here, because extending the + range upwards might push d over a boundary that makes it use + another byte in the UTF-8 representation. */ + + if (ignoreCase) { + int occ, ocd; + int cc = c; + int origd = d; + while (getOthercaseRange(&cc, origd, &occ, &ocd)) { + if (occ >= c && ocd <= d) + continue; /* Skip embedded */ + + if (occ < c && ocd >= c - 1) /* Extend the basic range */ + { /* if there is overlap, */ + c = occ; /* noting that if occ < c */ + continue; /* we can't have ocd > d */ + } /* because a subrange is */ + if (ocd > d && occ <= d + 1) /* always shorter than */ + { /* the basic range. */ + d = ocd; + continue; + } + + /* An extra item is needed */ + + length += 1 + encodeUTF8(occ, buffer) + + ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer)); + } + } + + /* The length of the (possibly extended) range */ + + length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer); + } + + } + + /* We have a single character. There is nothing to be done unless we + are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must + allow for an XCL_SINGLE item, doubled for caselessness if there is UCP + support. */ + + else { + if ((c > 255 || (ignoreCase && c > 127))) { + unsigned char buffer[6]; + class_optcount = 10; /* Ensure > 1 */ + if (!class_utf8) /* Allow for XCLASS overhead */ + { + class_utf8 = true; + length += LINK_SIZE + 2; + } + length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer)); + } + } + } + } + + if (ptr >= patternEnd) { /* Missing terminating ']' */ + errorcode = ERR6; + return -1; + } + + /* We can optimize when there was only one optimizable character. + Note that this does not detect the case of a negated single character. + In that case we do an incorrect length computation, but it's not a serious + problem because the computed length is too large rather than too small. */ + + if (class_optcount == 1) + goto NORMAL_CHAR; + + /* Here, we handle repeats for the class opcodes. */ + { + length += 33; + + /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, + we also need extra for wrapping the whole thing in a sub-pattern. */ + + if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode != 0) + return -1; + if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || + (minRepeats == 1 && maxRepeats == -1)) + length++; + else + length += 5; + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; + } else if (safelyCheckNextChar(ptr, patternEnd, '?')) + ptr++; + } + } + continue; + } + + /* Brackets may be genuine groups or special things */ + + case '(': { + int branch_newextra = 0; + int bracket_length = BRA_LEN; + bool capturing = false; + + /* Handle special forms of bracket, which all start (? */ + + if (safelyCheckNextChar(ptr, patternEnd, '?')) { + switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) { + /* Non-referencing groups and lookaheads just move the pointer on, and + then behave like a non-special bracket, except that they don't increment + the count of extracting brackets. Ditto for the "once only" bracket, + which is in Perl from version 5.005. */ + + case ':': + case '=': + case '!': + ptr += 2; + break; + + /* Else loop checking valid options until ) is met. Anything else is an + error. If we are without any brackets, i.e. at top level, the settings + act as if specified in the options, so massage the options immediately. + This is for backward compatibility with Perl 5.004. */ + + default: + errorcode = ERR12; + return -1; + } + } else + capturing = true; + + /* Capturing brackets must be counted so we can process escapes in a + Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need + an additional 3 bytes of memory per capturing bracket. */ + + if (capturing) { + bracount++; + if (bracount > EXTRACT_BASIC_MAX) + bracket_length += 3; + } + + /* Save length for computing whole length at end if there's a repeat that + requires duplication of the group. Also save the current value of + branch_extra, and start the new group with the new value. If non-zero, this + will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ + + if (brastackptr >= sizeof(brastack)/sizeof(int)) { + errorcode = ERR17; + return -1; + } + + bralenstack[brastackptr] = branch_extra; + branch_extra = branch_newextra; + + brastack[brastackptr++] = length; + length += bracket_length; + continue; + } + + /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we + have to replicate this bracket up to that many times. If brastackptr is + 0 this is an unmatched bracket which will generate an error, but take care + not to try to access brastack[-1] when computing the length and restoring + the branch_extra value. */ + + case ')': { + int duplength; + length += KET_LEN; + if (brastackptr > 0) { + duplength = length - brastack[--brastackptr]; + branch_extra = bralenstack[brastackptr]; + } + else + duplength = 0; + + /* Leave ptr at the final char; for readRepeatCounts this happens + automatically; for the others we need an increment. */ + + if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) { + ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); + if (errorcode) + return -1; + } else if (c == '*') { + minRepeats = 0; + maxRepeats = -1; + ptr++; + } else if (c == '+') { + minRepeats = 1; + maxRepeats = -1; + ptr++; + } else if (c == '?') { + minRepeats = 0; + maxRepeats = 1; + ptr++; + } else { + minRepeats = 1; + maxRepeats = 1; + } + + /* If the minimum is zero, we have to allow for an OP_BRAZERO before the + group, and if the maximum is greater than zero, we have to replicate + maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting + bracket set. */ + + int repeatsLength; + if (minRepeats == 0) { + length++; + if (maxRepeats > 0) { + repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + BRA_LEN + KET_LEN + OPCODE_LEN); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength; + if (length > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + } + } + + /* When the minimum is greater than zero, we have to replicate up to + minval-1 times, with no additions required in the copies. Then, if there + is a limited maximum we have to replicate up to maxval-1 times allowing + for a BRAZERO item before each optional copy and nesting brackets for all + but one of the optional copies. */ + + else { + repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength; + if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */ + repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + BRAZERO_LEN + BRA_LEN + KET_LEN); + if (repeatsLength < 0) { + errorcode = ERR16; + return -1; + } + length += repeatsLength - (2 + 2 * LINK_SIZE); + } + if (length > MAX_PATTERN_SIZE) { + errorcode = ERR16; + return -1; + } + } + + /* Allow space for once brackets for "possessive quantifier" */ + + if (safelyCheckNextChar(ptr, patternEnd, '+')) { + ptr++; + length += 2 + 2 * LINK_SIZE; + } + continue; + } + + /* Non-special character. It won't be space or # in extended mode, so it is + always a genuine character. If we are in a \Q...\E sequence, check for the + end; if not, we have a literal. */ + + default: + NORMAL_CHAR: + length += 2; /* For a one-byte character */ + lastitemlength = 1; /* Default length of last item for repeats */ + + if (c > 127) { + int i; + for (i = 0; i < jsc_pcre_utf8_table1_size; i++) + if (c <= jsc_pcre_utf8_table1[i]) + break; + length += i; + lastitemlength += i; + } + + continue; + } + } + + length += KET_LEN + OPCODE_LEN; /* For final KET and END */ + + cd.numCapturingBrackets = bracount; + return length; +} + +/************************************************* +* Compile a Regular Expression * +*************************************************/ + +/* This function takes a string and returns a pointer to a block of store +holding a compiled version of the expression. The original API for this +function had no error code return variable; it is retained for backwards +compatibility. The new function is given a new name. + +Arguments: + pattern the regular expression + options various option bits + errorCodePtr pointer to error code variable (pcre_compile2() only) + can be NULL if you don't want a code value + error pointer to pointer to error text + erroroffset ptr offset in pattern where error was detected + tables pointer to character tables or NULL + +Returns: pointer to compiled data block, or NULL on error, + with error and erroroffset set +*/ + +static inline JSRegExp* returnError(ErrorCode errorcode, int *error) +{ + *error = static_cast(errorcode); + return 0; +} + +JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, + JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline, + unsigned* numSubpatterns, int *error) +{ + /* We can't pass back an error message if error is NULL; I guess the best we + can do is just return NULL, but we can set a code value if there is a code pointer. */ + if (!error) + return 0; + *error = 0; + + CompileData cd; + + ErrorCode errorcode = ERR0; + /* Call this once just to count the brackets. */ + calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); + /* Call it again to compute the length. */ + int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); + if (errorcode) + return returnError(errorcode, error); + + if (length > MAX_PATTERN_SIZE) + return returnError(ERR16, error); + + size_t size = length + sizeof(JSRegExp); + JSRegExp* re = reinterpret_cast(js::OffTheBooks::array_new(size)); + if (!re) + return returnError(ERR13, error); + + re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0); + + /* The starting points of the name/number translation table and of the code are + passed around in the compile data block. */ + + const unsigned char* codeStart = (const unsigned char*)(re + 1); + + /* Set up a starting, non-extracting bracket, then compile the expression. On + error, errorcode will be set non-zero, so we don't need to look at the result + of the function here. */ + + const UChar* ptr = (const UChar*)pattern; + const UChar* patternEnd = pattern + patternLength; + unsigned char* code = const_cast(codeStart); + int firstByte, reqByte; + int bracketCount = 0; + if (!cd.needOuterBracket) + compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstByte, &reqByte, cd); + else { + *code = OP_BRA; + unsigned char * const codeBefore = code; + compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 2, &firstByte, &reqByte, cd); + JS_ASSERT((bracketCount & 0xff) == bracketCount); + put2ByteValue(codeBefore + 1 + LINK_SIZE, 0 << 8 | (bracketCount & 0xff)); + } + re->topBracket = bracketCount; + re->topBackref = cd.topBackref; + + /* If not reached end of pattern on success, there's an excess bracket. */ + + if (errorcode == 0 && ptr < patternEnd) + errorcode = ERR10; + + /* Fill in the terminating state and check for disastrous overflow, but + if debugging, leave the test till after things are printed out. */ + + *code++ = OP_END; + + JS_ASSERT(code - codeStart <= length); + if (code - codeStart > length) + errorcode = ERR7; + + /* Give an error if there's back reference to a non-existent capturing + subpattern. */ + + if (re->topBackref > re->topBracket) + errorcode = ERR15; + + /* Failed to compile, or error while post-processing */ + + if (errorcode != ERR0) { + js::Foreground::array_delete(reinterpret_cast(re)); + return returnError(errorcode, error); + } + + /* If the anchored option was not passed, set the flag if we can determine that + the pattern is anchored by virtue of ^ characters or \A or anything else (such + as starting with .* when DOTALL is set). + + Otherwise, if we know what the first character has to be, save it, because that + speeds up unanchored matches no end. If not, see if we can set the + UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches + start with ^. and also when all branches start with .* for non-DOTALL matches. + */ + + if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart)) + re->options |= IsAnchoredOption; + else { + if (firstByte < 0) { + firstByte = (cd.needOuterBracket + ? bracketFindFirstAssertedCharacter(codeStart, false) + : branchFindFirstAssertedCharacter(codeStart, false)) + | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0); + } + if (firstByte >= 0) { + int ch = firstByte & 255; + if (ch < 127) { + re->firstByte = ((firstByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstByte; + re->options |= UseFirstByteOptimizationOption; + } + } else { + if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap)) + re->options |= UseMultiLineFirstByteOptimizationOption; + } + } + + /* For an anchored pattern, we use the "required byte" only if it follows a + variable length item in the regex. Remove the caseless flag for non-caseable + bytes. */ + + if (reqByte >= 0 && (!(re->options & IsAnchoredOption) || (reqByte & REQ_VARY))) { + int ch = reqByte & 255; + if (ch < 127) { + re->reqByte = ((reqByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqByte & ~REQ_IGNORE_CASE) : reqByte; + re->options |= UseRequiredByteOptimizationOption; + } + } + + if (numSubpatterns) + *numSubpatterns = re->topBracket; + + return re; +} + +void jsRegExpFree(JSRegExp* re) +{ + js::Foreground::array_delete(reinterpret_cast(re)); +} diff --git a/js/src/yarr/pcre/pcre_exec.cpp b/js/src/yarr/pcre/pcre_exec.cpp new file mode 100644 index 000000000000..c2d154d67b8e --- /dev/null +++ b/js/src/yarr/pcre/pcre_exec.cpp @@ -0,0 +1,2193 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + Copyright (C) 2007 Eric Seidel + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains jsRegExpExecute(), the externally visible function +that does pattern matching using an NFA algorithm, following the rules from +the JavaScript specification. There are also some supporting functions. */ + +#include "pcre_internal.h" + +#include +#include "yarr/jswtfbridge.h" +#include "yarr/wtf/ASCIICType.h" +#include "jsarena.h" +#include "jscntxt.h" + +using namespace WTF; + +#if !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO +#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION +#endif + +/* Note: Webkit sources have USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP disabled. */ +/* Note: There are hardcoded constants all over the place, but in the port of + Yarr to TraceMonkey two bytes are added to the OP_BRA* opcodes, so the + instruction stream now looks like this at the start of a bracket group: + + OP_BRA* [link:LINK_SIZE] [minNestedBracket,maxNestedBracket:2] + + Both capturing and non-capturing brackets encode this information. */ + +/* Avoid warnings on Windows. */ +#undef min +#undef max + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION +typedef int ReturnLocation; +#else +typedef void* ReturnLocation; +#endif + +/* Node on a stack of brackets. This is used to detect and reject + matches of the empty string per ECMAScript repeat match rules. This + also prevents infinite loops on quantified empty matches. One node + represents the start state at the start of this bracket group. */ +struct BracketChainNode { + BracketChainNode* previousBracket; + const UChar* bracketStart; + /* True if the minimum number of matches was already satisfied + when we started matching this group. */ + bool minSatisfied; +}; + +struct MatchFrame { + ReturnLocation returnLocation; + struct MatchFrame* previousFrame; + int *savedOffsets; + /* The frame allocates saved offsets into the regular expression arena pool so + that they can be restored during backtracking. */ + size_t savedOffsetsSize; + JSArenaPool *regExpPool; + + MatchFrame() : savedOffsetsSize(0), regExpPool(0) {} + void init(JSArenaPool *regExpPool) { this->regExpPool = regExpPool; } + + /* Function arguments that may change */ + struct { + const UChar* subjectPtr; + const unsigned char* instructionPtr; + int offsetTop; + BracketChainNode* bracketChain; + } args; + + + /* PCRE uses "fake" recursion built off of gotos, thus + stack-based local variables are not safe to use. Instead we have to + store local variables on the current MatchFrame. */ + struct { + const unsigned char* data; + const unsigned char* startOfRepeatingBracket; + const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare + const unsigned char* instructionPtrAtStartOfOnce; + + int repeatOthercase; + int savedSubjectOffset; + + int ctype; + int fc; + int fi; + int length; + int max; + int number; + int offset; + int skipBytes; + int minBracket; + int limitBracket; + int bracketsBefore; + bool minSatisfied; + + BracketChainNode bracketChainNode; + } locals; + + void saveOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + JS_ASSERT(regExpPool); + JS_ASSERT(minBracket >= 0); + JS_ASSERT(limitBracket >= minBracket); + JS_ASSERT(offsetEnd >= 0); + if (minBracket == limitBracket) + return; + const size_t newSavedOffsetCount = 3 * (limitBracket - minBracket); + /* Increase saved offset space if necessary. */ + { + size_t targetSize = sizeof(*savedOffsets) * newSavedOffsetCount; + if (savedOffsetsSize < targetSize) { + JS_ARENA_ALLOCATE_CAST(savedOffsets, int *, regExpPool, targetSize); + JS_ASSERT(savedOffsets); /* FIXME: error code, bug 574459. */ + savedOffsetsSize = targetSize; + } + } + for (unsigned i = 0; i < unsigned(limitBracket - minBracket); ++i) { + int bracketIter = minBracket + i; + JS_ASSERT(2 * bracketIter + 1 <= offsetEnd); + int start = offsets[2 * bracketIter]; + int end = offsets[2 * bracketIter + 1]; + JS_ASSERT(bracketIter <= offsetEnd); + int offset = offsets[offsetEnd - bracketIter]; + DPRINTF(("saving bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); + JS_ASSERT(start <= end); + JS_ASSERT(i * 3 + 2 < newSavedOffsetCount); + savedOffsets[i * 3 + 0] = start; + savedOffsets[i * 3 + 1] = end; + savedOffsets[i * 3 + 2] = offset; + } + } + + void clobberOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + for (int i = 0; i < limitBracket - minBracket; ++i) { + int bracketIter = minBracket + i; + JS_ASSERT(2 * bracketIter + 1 < offsetEnd); + offsets[2 * bracketIter + 0] = -1; + offsets[2 * bracketIter + 1] = -1; + } + } + + void restoreOffsets(int minBracket, int limitBracket, int *offsets, int offsetEnd) { + JS_ASSERT(regExpPool); + JS_ASSERT_IF(limitBracket > minBracket, savedOffsets); + for (int i = 0; i < limitBracket - minBracket; ++i) { + int bracketIter = minBracket + i; + int start = savedOffsets[i * 3 + 0]; + int end = savedOffsets[i * 3 + 1]; + int offset = savedOffsets[i * 3 + 2]; + DPRINTF(("restoring bracket %d; start: %d; end: %d; offset: %d\n", bracketIter, start, end, offset)); + JS_ASSERT(start <= end); + offsets[2 * bracketIter + 0] = start; + offsets[2 * bracketIter + 1] = end; + offsets[offsetEnd - bracketIter] = offset; + } + } + + /* Extract the bracket data after the current opcode/link at |instructionPtr| into the locals. */ + void extractBrackets(const unsigned char *instructionPtr) { + uint16 bracketMess = get2ByteValue(instructionPtr + 1 + LINK_SIZE); + locals.minBracket = (bracketMess >> 8) & 0xff; + locals.limitBracket = (bracketMess & 0xff); + JS_ASSERT(locals.minBracket <= locals.limitBracket); + } + + /* At the start of a bracketed group, add the current subject pointer to the + stack of such pointers, to be re-instated at the end of the group when we hit + the closing ket. When match() is called in other circumstances, we don't add to + this stack. */ + void startNewGroup(bool minSatisfied) { + locals.bracketChainNode.previousBracket = args.bracketChain; + locals.bracketChainNode.bracketStart = args.subjectPtr; + locals.bracketChainNode.minSatisfied = minSatisfied; + args.bracketChain = &locals.bracketChainNode; + } +}; + +/* Structure for passing "static" information around between the functions +doing traditional NFA matching, so that they are thread-safe. */ + +struct MatchData { + int *offsetVector; /* Offset vector */ + int offsetEnd; /* One past the end */ + int offsetMax; /* The maximum usable for return data */ + bool offsetOverflow; /* Set if too many extractions */ + const UChar *startSubject; /* Start of the subject string */ + const UChar *endSubject; /* End of the subject string */ + const UChar *endMatchPtr; /* Subject position at end match */ + int endOffsetTop; /* Highwater mark at end of match */ + bool multiline; + bool ignoreCase; + + void setOffsetPair(size_t pairNum, int start, int end) { + JS_ASSERT(int(2 * pairNum + 1) < offsetEnd && int(pairNum) < offsetEnd); + JS_ASSERT(start <= end); + JS_ASSERT_IF(start < 0, start == end && start == -1); + DPRINTF(("setting offset pair at %u (%d, %d)\n", pairNum, start, end)); + offsetVector[2 * pairNum + 0] = start; + offsetVector[2 * pairNum + 1] = end; + } +}; + +/* The maximum remaining length of subject we are prepared to search for a +reqByte match. */ + +#define REQ_BYTE_MAX 1000 + +/* The below limit restricts the number of "recursive" match calls in order to +avoid spending exponential time on complex regular expressions. */ + +static const unsigned matchLimit = 1000000; + +/************************************************* +* Match a back-reference * +*************************************************/ + +/* If a back reference hasn't been set, the length that is passed is greater +than the number of characters left in the string, so the match fails. + +Arguments: + offset index into the offset vector + subjectPtr points into the subject + length length to be matched + md points to match data block + +Returns: true if matched +*/ + +static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md) +{ + const UChar* p = md.startSubject + md.offsetVector[offset]; + + /* Always fail if not enough characters left */ + + if (length > md.endSubject - subjectPtr) + return false; + + /* Separate the caselesss case for speed */ + + if (md.ignoreCase) { + while (length-- > 0) { + UChar c = *p++; + int othercase = jsc_pcre_ucp_othercase(c); + UChar d = *subjectPtr++; + if (c != d && othercase != d) + return false; + } + } + else { + while (length-- > 0) + if (*p++ != *subjectPtr++) + return false; + } + + return true; +} + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + +/* Use numbered labels and switch statement at the bottom of the match function. */ + +#define RMATCH_WHERE(num) num +#define RRETURN_LABEL RRETURN_SWITCH + +#else + +/* Use GCC's computed goto extension. */ + +/* For one test case this is more than 40% faster than the switch statement. +We could avoid the use of the num argument entirely by using local labels, +but using it for the GCC case as well as the non-GCC case allows us to share +a bit more code and notice if we use conflicting numbers.*/ + +#define RMATCH_WHERE(num) JS_EXTENSION(&&RRETURN_##num) +#define RRETURN_LABEL *stack.currentFrame->returnLocation + +#endif + +#define RECURSIVE_MATCH_COMMON(num) \ + goto RECURSE;\ + RRETURN_##num: \ + stack.popCurrentFrame(); + +#define RECURSIVE_MATCH(num, ra, rb) \ + do { \ + stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ + RECURSIVE_MATCH_COMMON(num) \ + } while (0) + +#define RECURSIVE_MATCH_NEW_GROUP(num, ra, rb, gm) \ + do { \ + stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \ + stack.currentFrame->startNewGroup(gm); \ + RECURSIVE_MATCH_COMMON(num) \ + } while (0) + +#define RRETURN do { JS_EXTENSION_(goto RRETURN_LABEL); } while (0) + +#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0) + +/************************************************* +* Match from current position * +*************************************************/ + +/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character +in the subject string, while substringStart holds the value of subjectPtr at the start of the +last bracketed group - used for breaking infinite loops matching zero-length +strings. This function is called recursively in many circumstances. Whenever it +returns a negative (error) response, the outer match() call must also return the +same response. + +Arguments: + subjectPtr pointer in subject + instructionPtr position in code + offsetTop current top pointer + md pointer to "static" info for the match + +Returns: 1 if matched ) these values are >= 0 + 0 if failed to match ) + a negative error value if aborted by an error condition + (e.g. stopped by repeated call or recursion limit) +*/ + +static const unsigned numFramesOnStack = 16; + +struct MatchStack { + JSArenaPool *regExpPool; + void *regExpPoolMark; + + MatchStack(JSArenaPool *regExpPool) + : regExpPool(regExpPool) + , regExpPoolMark(JS_ARENA_MARK(regExpPool)) + , framesEnd(frames + numFramesOnStack) + , currentFrame(frames) + , size(1) // match() creates accesses the first frame w/o calling pushNewFrame + { + JS_ASSERT((sizeof(frames) / sizeof(frames[0])) == numFramesOnStack); + JS_ASSERT(regExpPool); + for (size_t i = 0; i < numFramesOnStack; ++i) + frames[i].init(regExpPool); + } + + ~MatchStack() { JS_ARENA_RELEASE(regExpPool, regExpPoolMark); } + + MatchFrame frames[numFramesOnStack]; + MatchFrame* framesEnd; + MatchFrame* currentFrame; + unsigned size; + + bool canUseStackBufferForNextFrame() { + return size < numFramesOnStack; + } + + MatchFrame* allocateNextFrame() { + if (canUseStackBufferForNextFrame()) + return currentFrame + 1; + // FIXME: bug 574459 -- no NULL check + MatchFrame *frame = js::OffTheBooks::new_(); + frame->init(regExpPool); + return frame; + } + + void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation) { + MatchFrame* newframe = allocateNextFrame(); + newframe->previousFrame = currentFrame; + + newframe->args.subjectPtr = currentFrame->args.subjectPtr; + newframe->args.offsetTop = currentFrame->args.offsetTop; + newframe->args.instructionPtr = instructionPtr; + newframe->args.bracketChain = bracketChain; + newframe->returnLocation = returnLocation; + size++; + + currentFrame = newframe; + } + + void popCurrentFrame() { + MatchFrame* oldFrame = currentFrame; + currentFrame = currentFrame->previousFrame; + if (size > numFramesOnStack) + js::Foreground::delete_(oldFrame); + size--; + } + + void popAllFrames() { + while (size) + popCurrentFrame(); + } +}; + +static int matchError(int errorCode, MatchStack& stack) +{ + stack.popAllFrames(); + return errorCode; +} + +/* Get the next UTF-8 character, not advancing the pointer, incrementing length + if there are extra bytes. This is called when we know we are in UTF-8 mode. */ + +static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len) +{ + c = *subjectPtr; + if ((c & 0xc0) == 0xc0) { + int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + int gcss = 6 * gcaa; + c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; + for (int gcii = 1; gcii <= gcaa; gcii++) { + gcss -= 6; + c |= (subjectPtr[gcii] & 0x3f) << gcss; + } + len += gcaa; + } +} + +static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats) +{ + // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR + static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 }; + static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 }; + + JS_ASSERT(instructionOffset >= 0); + JS_ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR)); + + minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2 + minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset]; + maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset]; +} + +/* Helper class for passing a flag value from one op to the next that runs. + This allows us to set the flag in certain ops. When the flag is read, it + will be true only if the previous op set the flag, otherwise it is false. */ +class LinearFlag { +public: + LinearFlag() : flag(false) {} + + bool readAndClear() { + bool rv = flag; + flag = false; + return rv; + } + + void set() { + flag = true; + } + +private: + bool flag; +}; + +static int +match(JSArenaPool *regExpPool, const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md) +{ + bool isMatch = false; + int min; + bool minimize = false; /* Initialization not really needed, but some compilers think so. */ + unsigned remainingMatchCount = matchLimit; + int othercase; /* Declare here to avoid errors during jumps */ + bool minSatisfied; + + MatchStack stack(regExpPool); + LinearFlag minSatNextBracket; + + /* The opcode jump table. */ +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP +#define EMIT_JUMP_TABLE_ENTRY(opcode) JS_EXTENSION(&&LABEL_OP_##opcode) + static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) }; +#undef EMIT_JUMP_TABLE_ENTRY +#endif + + /* One-time setup of the opcode jump table. */ +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + for (int i = 255; !opcodeJumpTable[i]; i--) + opcodeJumpTable[i] = &&CAPTURING_BRACKET; +#endif + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + // Shark shows this as a hot line + // Using a static const here makes this line disappear, but makes later access hotter (not sure why) + stack.currentFrame->returnLocation = JS_EXTENSION(&&RETURN); +#else + stack.currentFrame->returnLocation = 0; +#endif + stack.currentFrame->args.subjectPtr = subjectPtr; + stack.currentFrame->args.instructionPtr = instructionPtr; + stack.currentFrame->args.offsetTop = offsetTop; + stack.currentFrame->args.bracketChain = 0; + stack.currentFrame->startNewGroup(false); + + /* This is where control jumps back to to effect "recursion" */ + +RECURSE: + if (!--remainingMatchCount) + return matchError(JSRegExpErrorHitLimit, stack); + + /* Now start processing the operations. */ + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + while (true) +#endif + { + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP +#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode +#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr] +#else +#define BEGIN_OPCODE(opcode) case OP_##opcode +#define NEXT_OPCODE continue +#endif +#define LOCALS(__ident) (stack.currentFrame->locals.__ident) + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + NEXT_OPCODE; +#else + switch (*stack.currentFrame->args.instructionPtr) +#endif + { + /* Non-capturing bracket: optimized */ + + BEGIN_OPCODE(BRA): + NON_CAPTURING_BRACKET: + DPRINTF(("start non-capturing bracket\n")); + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); + /* If we see no ALT, we have to skip three bytes of bracket data (link plus nested + bracket data. */ + stack.currentFrame->locals.skipBytes = 3; + /* We must compute this value at the top, before we move the instruction pointer. */ + stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); + do { + /* We need to extract this into a variable so we can correctly pass it by value + through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ + minSatisfied = stack.currentFrame->locals.minSatisfied; + RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); + if (isMatch) { + DPRINTF(("non-capturing bracket succeeded\n")); + RRETURN; + } + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + DPRINTF(("non-capturing bracket failed\n")); + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + RRETURN; + + /* Skip over large extraction number data if encountered. */ + + BEGIN_OPCODE(BRANUMBER): + stack.currentFrame->args.instructionPtr += 3; + NEXT_OPCODE; + + /* End of the pattern. */ + + BEGIN_OPCODE(END): + md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */ + md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */ + isMatch = true; + RRETURN; + + /* Assertion brackets. Check the alternative branches in turn - the + matching won't pass the KET for an assertion. If any one branch matches, + the assertion is true. Lookbehind assertions have an OP_REVERSE item at the + start of each branch to move the current point backwards, so the code at + this level is identical to the lookahead case. */ + + BEGIN_OPCODE(ASSERT): + { + uint16 bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); + LOCALS(minBracket) = (bracketMess >> 8) & 0xff; + LOCALS(limitBracket) = bracketMess & 0xff; + JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); + } + stack.currentFrame->locals.skipBytes = 3; + do { + RECURSIVE_MATCH_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); + if (isMatch) + break; + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + if (*stack.currentFrame->args.instructionPtr == OP_KET) { + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + RRETURN_NO_MATCH; + } + + /* Continue from after the assertion, updating the offsets high water + mark, since extracts may have been taken during the assertion. */ + + advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); + stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; + stack.currentFrame->args.offsetTop = md.endOffsetTop; + NEXT_OPCODE; + + /* Negative assertion: all branches must fail to match */ + + BEGIN_OPCODE(ASSERT_NOT): + stack.currentFrame->locals.skipBytes = 3; + { + unsigned bracketMess = get2ByteValue(stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE); + LOCALS(minBracket) = (bracketMess >> 8) & 0xff; + LOCALS(limitBracket) = bracketMess & 0xff; + } + JS_ASSERT(LOCALS(minBracket) <= LOCALS(limitBracket)); + do { + RECURSIVE_MATCH_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, NULL, false); + if (isMatch) + RRETURN_NO_MATCH; + stack.currentFrame->locals.skipBytes = 1; + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.skipBytes + LINK_SIZE; + NEXT_OPCODE; + + /* An alternation is the end of a branch; scan along to find the end of the + bracketed group and go to there. */ + + BEGIN_OPCODE(ALT): + advanceToEndOfBracket(stack.currentFrame->args.instructionPtr); + NEXT_OPCODE; + + /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating + that it may occur zero times. It may repeat infinitely, or not at all - + i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper + repeat limits are compiled as a number of copies, with the optional ones + preceded by BRAZERO or BRAMINZERO. */ + + BEGIN_OPCODE(BRAZERO): { + stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain, true); + if (isMatch) + RRETURN; + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); + stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE; + NEXT_OPCODE; + } + + BEGIN_OPCODE(BRAMINZERO): { + stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1; + advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket); + RECURSIVE_MATCH_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain, false); + if (isMatch) + RRETURN; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + } + + /* End of a group, repeated or non-repeating. If we are at the end of + an assertion "group", stop matching and return 1, but record the + current high water mark for use by positive assertions. Do this also + for the "once" (not-backup up) groups. */ + + BEGIN_OPCODE(KET): + BEGIN_OPCODE(KETRMIN): + BEGIN_OPCODE(KETRMAX): + stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart; + stack.currentFrame->locals.minSatisfied = stack.currentFrame->args.bracketChain->minSatisfied; + + /* Back up the stack of bracket start pointers. */ + + stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket; + + if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) { + md.endOffsetTop = stack.currentFrame->args.offsetTop; + isMatch = true; + RRETURN; + } + + /* In all other cases except a conditional group we have to check the + group number back at the start and if necessary complete handling an + extraction by setting the offsets and bumping the high water mark. */ + + stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA; + + /* For extended extraction brackets (large number), we have to fish out + the number from a dummy opcode at the start. */ + + if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) + stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 4 + LINK_SIZE); + stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; + + DPRINTF(("end bracket %d\n", stack.currentFrame->locals.number)); + + /* Test for a numbered group. This includes groups called as a result + of recursion. Note that whole-pattern recursion is coded as a recurse + into group 0, so it won't be picked up here. Instead, we catch it when + the OP_END is reached. */ + + if (stack.currentFrame->locals.number > 0) { + if (stack.currentFrame->locals.offset >= md.offsetMax) + md.offsetOverflow = true; + else { + int start = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; + int end = stack.currentFrame->args.subjectPtr - md.startSubject; + if (start == end && stack.currentFrame->locals.minSatisfied) { + DPRINTF(("empty string while group already matched; bailing")); + RRETURN_NO_MATCH; + } + DPRINTF(("saving; start: %d; end: %d\n", start, end)); + JS_ASSERT(start <= end); + md.setOffsetPair(stack.currentFrame->locals.number, start, end); + if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset) + stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2; + } + } + + /* For a non-repeating ket, just continue at this level. This also + happens for a repeating ket if no characters were matched in the group. + This is the forcible breaking of infinite loops as implemented in Perl + 5.005. If there is an options reset, it will get obeyed in the normal + course of events. */ + + if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + DPRINTF(("non-repeating ket or empty match\n")); + if (stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction && stack.currentFrame->locals.minSatisfied) { + DPRINTF(("empty string while group already matched; bailing")); + RRETURN_NO_MATCH; + } + stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE; + NEXT_OPCODE; + } + + /* The repeating kets try the rest of the pattern or restart from the + preceding bracket, in the appropriate order. */ + + stack.currentFrame->extractBrackets(LOCALS(instructionPtrAtStartOfOnce)); + JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); + if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) { + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + else + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + DPRINTF(("recursively matching lazy group\n")); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(17, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); + } else { /* OP_KETRMAX */ + stack.currentFrame->saveOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + stack.currentFrame->clobberOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + DPRINTF(("recursively matching greedy group\n")); + minSatNextBracket.set(); + RECURSIVE_MATCH_NEW_GROUP(18, LOCALS(instructionPtrAtStartOfOnce), stack.currentFrame->args.bracketChain, true); + if (isMatch) + RRETURN; + else + stack.currentFrame->restoreOffsets(LOCALS(minBracket), LOCALS(limitBracket), md.offsetVector, md.offsetEnd); + RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain); + } + RRETURN; + + /* Start of subject. */ + + BEGIN_OPCODE(CIRC): + if (stack.currentFrame->args.subjectPtr != md.startSubject) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* After internal newline if multiline. */ + + BEGIN_OPCODE(BOL): + if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1])) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* End of subject. */ + + BEGIN_OPCODE(DOLL): + if (stack.currentFrame->args.subjectPtr < md.endSubject) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Before internal newline if multiline. */ + + BEGIN_OPCODE(EOL): + if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Word boundary assertions */ + + BEGIN_OPCODE(NOT_WORD_BOUNDARY): + BEGIN_OPCODE(WORD_BOUNDARY): { + bool currentCharIsWordChar = false; + bool previousCharIsWordChar = false; + + if (stack.currentFrame->args.subjectPtr > md.startSubject) + previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]); + if (stack.currentFrame->args.subjectPtr < md.endSubject) + currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr); + + /* Now see if the situation is what we want */ + bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY); + if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar) + RRETURN_NO_MATCH; + NEXT_OPCODE; + } + + /* Match a single character type; inline for speed */ + + BEGIN_OPCODE(NOT_NEWLINE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isNewline(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_DIGIT): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(DIGIT): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_WHITESPACE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isSpaceChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(WHITESPACE): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(NOT_WORDCHAR): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (isWordChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + BEGIN_OPCODE(WORDCHAR): + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (!isWordChar(*stack.currentFrame->args.subjectPtr++)) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr++; + NEXT_OPCODE; + + /* Match a back reference, possibly repeatedly. Look past the end of the + item to see if there is repeat information following. The code is similar + to that for character classes, but repeated for efficiency. Then obey + similar code to character type repeats - written out again for speed. + However, if the referenced string is the empty string, always treat + it as matched, any number of times (otherwise there could be infinite + loops). */ + + BEGIN_OPCODE(REF): + stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */ + stack.currentFrame->args.instructionPtr += 3; /* Advance past item */ + + /* If the reference is unset, set the length to be longer than the amount + of subject left; this ensures that every attempt at a match fails. We + can't just fail here, because of the possibility of quantifiers with zero + minima. */ + + if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0) + stack.currentFrame->locals.length = 0; + else + stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset]; + + /* Set up for repetition, or handle the non-repeated case */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + NEXT_OPCODE; + } + + /* If the length of the reference is zero, just continue with the + main loop. */ + + if (stack.currentFrame->locals.length == 0) + NEXT_OPCODE; + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + + /* If min = max, continue at the same level without recursion. + They are not both allowed to be zero. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep trying and advancing the pointer */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + RRETURN; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + /* Control never reaches here */ + } + + /* If maximizing, find the longest string and work backwards */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md)) + break; + stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + + /* Match a bit-mapped character class, possibly repeatedly. This op code is + used when all the characters in the class have values in the range 0-255, + and either the matching is caseful, or the characters are in the range + 0-127 when UTF-8 processing is enabled. The only difference between + OP_CLASS and OP_NCLASS occurs when a data character outside the range is + encountered. + + First, look past the end of the item to see if there is repeat information + following. Then obey similar code to character type repeats - written out + again for speed. */ + + BEGIN_OPCODE(NCLASS): + BEGIN_OPCODE(CLASS): + stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */ + stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + min = stack.currentFrame->locals.max = 1; + break; + } + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int c = *stack.currentFrame->args.subjectPtr++; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + RRETURN_NO_MATCH; + } else { + if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) + RRETURN_NO_MATCH; + } + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + int c = *stack.currentFrame->args.subjectPtr++; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + RRETURN; + } else { + if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0) + RRETURN; + } + } + /* Control never reaches here */ + } + /* If maximizing, find the longest possible run, then work backwards. */ + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (c > 255) { + if (stack.currentFrame->locals.data[-1] == OP_CLASS) + break; + } else { + if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7)))) + break; + } + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + /* Control never reaches here */ + + /* Match an extended character class. */ + + BEGIN_OPCODE(XCLASS): + stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */ + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */ + + switch (*stack.currentFrame->args.instructionPtr) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max); + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE); + min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3); + if (stack.currentFrame->locals.max == 0) + stack.currentFrame->locals.max = INT_MAX; + stack.currentFrame->args.instructionPtr += 5; + break; + + default: /* No repeat follows */ + min = stack.currentFrame->locals.max = 1; + } + + /* First, ensure the minimum number of matches are present. */ + + for (int i = 1; i <= min; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int c = *stack.currentFrame->args.subjectPtr++; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + RRETURN_NO_MATCH; + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + int c = *stack.currentFrame->args.subjectPtr++; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + RRETURN; + } + /* Control never reaches here */ + } + + /* If maximizing, find the longest possible run, then work backwards. */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!jsc_pcre_xclass(c, stack.currentFrame->locals.data)) + break; + ++stack.currentFrame->args.subjectPtr; + } + for(;;) { + RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + RRETURN; + } + + /* Control never reaches here */ + + /* Match a single character, casefully */ + + BEGIN_OPCODE(CHAR): + stack.currentFrame->locals.length = 1; + stack.currentFrame->args.instructionPtr++; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++) + RRETURN_NO_MATCH; + NEXT_OPCODE; + + /* Match a single character, caselessly */ + + BEGIN_OPCODE(CHAR_IGNORING_CASE): { + stack.currentFrame->locals.length = 1; + stack.currentFrame->args.instructionPtr++; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int dc = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fc != dc && jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc) + RRETURN_NO_MATCH; + NEXT_OPCODE; + } + + /* Match a single ASCII character. */ + + BEGIN_OPCODE(ASCII_CHAR): + if (md.endSubject == stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1]) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + stack.currentFrame->args.instructionPtr += 2; + NEXT_OPCODE; + + /* Match one of two cases of an ASCII letter. */ + + BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE): + if (md.endSubject == stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1]) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + stack.currentFrame->args.instructionPtr += 2; + NEXT_OPCODE; + + /* Match a single character repeatedly; different opcodes share code. */ + + BEGIN_OPCODE(EXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = false; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATCHAR; + + BEGIN_OPCODE(UPTO): + BEGIN_OPCODE(MINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATCHAR; + + BEGIN_OPCODE(STAR): + BEGIN_OPCODE(MINSTAR): + BEGIN_OPCODE(PLUS): + BEGIN_OPCODE(MINPLUS): + BEGIN_OPCODE(QUERY): + BEGIN_OPCODE(MINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single-character matches. We can give + up quickly if there are fewer than the minimum number of characters left in + the subject. */ + + REPEATCHAR: + + stack.currentFrame->locals.length = 1; + getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length); + if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length; + + if (stack.currentFrame->locals.fc <= 0xFFFF) { + othercase = md.ignoreCase ? jsc_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1; + + for (int i = 1; i <= min; i++) { + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + stack.currentFrame->locals.repeatOthercase = othercase; + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase) + RRETURN; + ++stack.currentFrame->args.subjectPtr; + } + /* Control never reaches here */ + } else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase) + break; + ++stack.currentFrame->args.subjectPtr; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + --stack.currentFrame->args.subjectPtr; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + } else { + /* No case on surrogate pairs, so no need to bother with "othercase". */ + + for (int i = 1; i <= min; i++) { + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + RRETURN_NO_MATCH; + stack.currentFrame->args.subjectPtr += 2; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + RRETURN; + stack.currentFrame->args.subjectPtr += 2; + } + /* Control never reaches here */ + } else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr > md.endSubject - 2) + break; + if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc) + break; + stack.currentFrame->args.subjectPtr += 2; + } + while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) { + RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + stack.currentFrame->args.subjectPtr -= 2; + } + RRETURN_NO_MATCH; + } + /* Control never reaches here */ + } + /* Control never reaches here */ + + /* Match a negated single one-byte character. */ + + BEGIN_OPCODE(NOT): { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN_NO_MATCH; + int b = stack.currentFrame->args.instructionPtr[1]; + int c = *stack.currentFrame->args.subjectPtr++; + stack.currentFrame->args.instructionPtr += 2; + if (md.ignoreCase) { + if (c < 128) + c = toLowerCase(c); + if (toLowerCase(b) == c) + RRETURN_NO_MATCH; + } else { + if (b == c) + RRETURN_NO_MATCH; + } + NEXT_OPCODE; + } + + /* Match a negated single one-byte character repeatedly. This is almost a + repeat of the code for a repeated single character, but I haven't found a + nice way of commoning these up that doesn't require a test of the + positive/negative option for each character match. Maybe that wouldn't add + very much to the time taken, but character matching *is* what this is all + about... */ + + BEGIN_OPCODE(NOTEXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = false; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATNOTCHAR; + + BEGIN_OPCODE(NOTUPTO): + BEGIN_OPCODE(NOTMINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATNOTCHAR; + + BEGIN_OPCODE(NOTSTAR): + BEGIN_OPCODE(NOTMINSTAR): + BEGIN_OPCODE(NOTPLUS): + BEGIN_OPCODE(NOTMINPLUS): + BEGIN_OPCODE(NOTQUERY): + BEGIN_OPCODE(NOTMINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single-byte matches. We can give up quickly + if there are fewer than the minimum number of bytes left in the + subject. */ + + REPEATNOTCHAR: + if (min > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++; + + /* The code is duplicated for the caseless and caseful cases, for speed, + since matching characters is likely to be quite common. First, ensure the + minimum number of matches are present. If min = max, continue at the same + level without recursing. Otherwise, if minimizing, keep trying the rest of + the expression and advancing one matching character if failing, up to the + maximum. Alternatively, if maximizing, find the maximum number of + characters and work backwards. */ + + DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max)); + + if (md.ignoreCase) { + if (stack.currentFrame->locals.fc < 128) + stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc); + + for (int i = 1; i <= min; i++) { + int d = *stack.currentFrame->args.subjectPtr++; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fc == d) + RRETURN_NO_MATCH; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + int d = *stack.currentFrame->args.subjectPtr++; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) + RRETURN; + } + /* Control never reaches here */ + } + + /* Maximize case */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int d = *stack.currentFrame->args.subjectPtr; + if (d < 128) + d = toLowerCase(d); + if (stack.currentFrame->locals.fc == d) + break; + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + /* Control never reaches here */ + } + + /* Caseful comparisons */ + + else { + for (int i = 1; i <= min; i++) { + int d = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fc == d) + RRETURN_NO_MATCH; + } + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + int d = *stack.currentFrame->args.subjectPtr++; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d) + RRETURN; + } + /* Control never reaches here */ + } + + /* Maximize case */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; + + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int d = *stack.currentFrame->args.subjectPtr; + if (stack.currentFrame->locals.fc == d) + break; + ++stack.currentFrame->args.subjectPtr; + } + for (;;) { + RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + RRETURN; + } + } + /* Control never reaches here */ + + /* Match a single character type repeatedly; several different opcodes + share code. This is very similar to the code for single characters, but we + repeat it in the interests of efficiency. */ + + BEGIN_OPCODE(TYPEEXACT): + min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = true; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATTYPE; + + BEGIN_OPCODE(TYPEUPTO): + BEGIN_OPCODE(TYPEMINUPTO): + min = 0; + stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1); + minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO; + stack.currentFrame->args.instructionPtr += 3; + goto REPEATTYPE; + + BEGIN_OPCODE(TYPESTAR): + BEGIN_OPCODE(TYPEMINSTAR): + BEGIN_OPCODE(TYPEPLUS): + BEGIN_OPCODE(TYPEMINPLUS): + BEGIN_OPCODE(TYPEQUERY): + BEGIN_OPCODE(TYPEMINQUERY): + repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max); + + /* Common code for all repeated single character type matches. Note that + in UTF-8 mode, '.' matches a character of any length, but for the other + character types, the valid characters are all one-byte long. */ + + REPEATTYPE: + stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */ + + /* First, ensure the minimum number of matches are present. Use inline + code for maximizing the speed, and do the type test once at the start + (i.e. keep it out of the loop). Also we can test that there are at least + the minimum number of characters before we start. */ + + if (min > md.endSubject - stack.currentFrame->args.subjectPtr) + RRETURN_NO_MATCH; + if (min > 0) { + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + for (int i = 1; i <= min; i++) { + if (isNewline(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_DIGIT: + for (int i = 1; i <= min; i++) { + if (isASCIIDigit(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_DIGIT: + for (int i = 1; i <= min; i++) { + if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WHITESPACE: + for (int i = 1; i <= min; i++) { + if (isSpaceChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WHITESPACE: + for (int i = 1; i <= min; i++) { + if (!isSpaceChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WORDCHAR: + for (int i = 1; i <= min; i++) { + if (isWordChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WORDCHAR: + for (int i = 1; i <= min; i++) { + if (!isWordChar(*stack.currentFrame->args.subjectPtr)) + RRETURN_NO_MATCH; + ++stack.currentFrame->args.subjectPtr; + } + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } /* End switch(stack.currentFrame->locals.ctype) */ + } + + /* If min = max, continue at the same level without recursing */ + + if (min == stack.currentFrame->locals.max) + NEXT_OPCODE; + + /* If minimizing, we have to test the rest of the pattern before each + subsequent match. */ + + if (minimize) { + for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) { + RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject) + RRETURN; + + int c = *stack.currentFrame->args.subjectPtr++; + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + if (isNewline(c)) + RRETURN; + break; + + case OP_NOT_DIGIT: + if (isASCIIDigit(c)) + RRETURN; + break; + + case OP_DIGIT: + if (!isASCIIDigit(c)) + RRETURN; + break; + + case OP_NOT_WHITESPACE: + if (isSpaceChar(c)) + RRETURN; + break; + + case OP_WHITESPACE: + if (!isSpaceChar(c)) + RRETURN; + break; + + case OP_NOT_WORDCHAR: + if (isWordChar(c)) + RRETURN; + break; + + case OP_WORDCHAR: + if (!isWordChar(c)) + RRETURN; + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } + } + /* Control never reaches here */ + } + + /* If maximizing it is worth using inline code for speed, doing the type + test once at the start (i.e. keep it out of the loop). */ + + else { + stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */ + + switch (stack.currentFrame->locals.ctype) { + case OP_NOT_NEWLINE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr)) + break; + stack.currentFrame->args.subjectPtr++; + } + break; + + case OP_NOT_DIGIT: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isASCIIDigit(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_DIGIT: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isASCIIDigit(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WHITESPACE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isSpaceChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WHITESPACE: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isSpaceChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_NOT_WORDCHAR: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (isWordChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + case OP_WORDCHAR: + for (int i = min; i < stack.currentFrame->locals.max; i++) { + if (stack.currentFrame->args.subjectPtr >= md.endSubject) + break; + int c = *stack.currentFrame->args.subjectPtr; + if (!isWordChar(c)) + break; + ++stack.currentFrame->args.subjectPtr; + } + break; + + default: + JS_NOT_REACHED("Invalid character type."); + return matchError(JSRegExpErrorInternal, stack); + } + + /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */ + + for (;;) { + RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain); + if (isMatch) + RRETURN; + if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) + break; /* Stop if tried at original pos */ + } + + /* Get here if we can't make it match with any permitted repetitions */ + + RRETURN; + } + /* Control never reaches here */ + + BEGIN_OPCODE(CRMINPLUS): + BEGIN_OPCODE(CRMINQUERY): + BEGIN_OPCODE(CRMINRANGE): + BEGIN_OPCODE(CRMINSTAR): + BEGIN_OPCODE(CRPLUS): + BEGIN_OPCODE(CRQUERY): + BEGIN_OPCODE(CRRANGE): + BEGIN_OPCODE(CRSTAR): + JS_NOT_REACHED("Invalid opcode."); + return matchError(JSRegExpErrorInternal, stack); + +#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP + CAPTURING_BRACKET: +#else + default: +#endif + /* Opening capturing bracket. If there is space in the offset vector, save + the current subject position in the working slot at the top of the vector. We + mustn't change the current values of the data slot, because they may be set + from a previous iteration of this group, and be referred to by a reference + inside the group. + + If the bracket fails to match, we need to restore this value and also the + values of the final offsets, in case they were set by a previous iteration of + the same bracket. + + If there isn't enough space in the offset vector, treat this as if it were a + non-capturing bracket. Don't worry about setting the flag for the error case + here; that is handled in the code for KET. */ + + JS_ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA); + + LOCALS(number) = *stack.currentFrame->args.instructionPtr - OP_BRA; + stack.currentFrame->extractBrackets(stack.currentFrame->args.instructionPtr); + DPRINTF(("opening capturing bracket %d\n", stack.currentFrame->locals.number)); + + /* For extended extraction brackets (large number), we have to fish out the + number from a dummy opcode at the start. */ + + if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX) + stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 4 + LINK_SIZE); + stack.currentFrame->locals.offset = 2 * stack.currentFrame->locals.number; + + JS_ASSERT_IF(LOCALS(number), LOCALS(minBracket) <= LOCALS(number) && LOCALS(number) < LOCALS(limitBracket)); + + if (stack.currentFrame->locals.offset < md.offsetMax) { + stack.currentFrame->locals.savedSubjectOffset = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number]; + DPRINTF(("setting subject offset for bracket to %d\n", stack.currentFrame->args.subjectPtr - md.startSubject)); + md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject; + stack.currentFrame->locals.skipBytes = 3; /* For OP_BRAs. */ + + /* We must compute this value at the top, before we move the instruction pointer. */ + stack.currentFrame->locals.minSatisfied = minSatNextBracket.readAndClear(); + do { + /* We need to extract this into a variable so we can correctly pass it by value + through RECURSIVE_MATCH_NEW_GROUP, which modifies currentFrame. */ + minSatisfied = stack.currentFrame->locals.minSatisfied; + RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + stack.currentFrame->locals.skipBytes + LINK_SIZE, stack.currentFrame->args.bracketChain, minSatisfied); + if (isMatch) + RRETURN; + stack.currentFrame->locals.skipBytes = 1; /* For OP_ALTs. */ + stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); + } while (*stack.currentFrame->args.instructionPtr == OP_ALT); + + DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number)); + for (size_t i = LOCALS(minBracket); i < size_t(LOCALS(limitBracket)); ++i) + md.setOffsetPair(i, -1, -1); + DPRINTF(("restoring subject offset for bracket to %d\n", stack.currentFrame->locals.savedSubjectOffset)); + md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.savedSubjectOffset; + + RRETURN; + } + + /* Insufficient room for saving captured contents */ + + goto NON_CAPTURING_BRACKET; + } + + /* Do not stick any code in here without much thought; it is assumed + that "continue" in the code above comes out to here to repeat the main + loop. */ + + } /* End of main loop */ + + JS_NOT_REACHED("Loop does not fallthru."); + +#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION + +RRETURN_SWITCH: + switch (stack.currentFrame->returnLocation) { + case 0: goto RETURN; + case 1: goto RRETURN_1; + case 2: goto RRETURN_2; + case 6: goto RRETURN_6; + case 7: goto RRETURN_7; + case 14: goto RRETURN_14; + case 15: goto RRETURN_15; + case 16: goto RRETURN_16; + case 17: goto RRETURN_17; + case 18: goto RRETURN_18; + case 19: goto RRETURN_19; + case 20: goto RRETURN_20; + case 21: goto RRETURN_21; + case 22: goto RRETURN_22; + case 24: goto RRETURN_24; + case 26: goto RRETURN_26; + case 27: goto RRETURN_27; + case 28: goto RRETURN_28; + case 29: goto RRETURN_29; + case 30: goto RRETURN_30; + case 31: goto RRETURN_31; + case 38: goto RRETURN_38; + case 40: goto RRETURN_40; + case 42: goto RRETURN_42; + case 44: goto RRETURN_44; + case 48: goto RRETURN_48; + case 52: goto RRETURN_52; + } + + JS_NOT_REACHED("Bad computed return location."); + return matchError(JSRegExpErrorInternal, stack); + +#endif + +RETURN: + return isMatch; +} + + +/************************************************* +* Execute a Regular Expression * +*************************************************/ + +/* This function applies a compiled re to a subject string and picks out +portions of the string if it matches. Two elements in the vector are set for +each substring: the offsets to the start and end of the substring. + +Arguments: + re points to the compiled expression + extra_data points to extra data or is NULL + subject points to the subject string + length length of subject string (may contain binary zeros) + start_offset where to start in the subject string + options option bits + offsets points to a vector of ints to be filled in with offsets + offsetCount the number of elements in the vector + +Returns: > 0 => success; value is the number of elements filled in + = 0 => success, but offsets is not big enough + -1 => failed to match + < -1 => some kind of unexpected problem +*/ + +static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int firstByte, bool firstByteIsCaseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart) +{ + // If firstByte is set, try scanning to the first instance of that byte + // no need to try and match against any earlier part of the subject string. + if (firstByte >= 0) { + UChar firstChar = firstByte; + if (firstByteIsCaseless) + while (subjectPtr < endSubject) { + int c = *subjectPtr; + if (c > 127) + break; + if (toLowerCase(c) == firstChar) + break; + subjectPtr++; + } + else { + while (subjectPtr < endSubject && *subjectPtr != firstChar) + subjectPtr++; + } + } else if (useMultiLineFirstCharOptimization) { + /* Or to just after \n for a multiline match if possible */ + // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07 + if (subjectPtr > originalSubjectStart) { + while (subjectPtr < endSubject && !isNewline(subjectPtr[-1])) + subjectPtr++; + } + } +} + +static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int reqByte, int reqByte2, bool reqByteIsCaseless, bool hasFirstByte, const UChar*& reqBytePtr) +{ + /* If reqByte is set, we know that that character must appear in the subject + for the match to succeed. If the first character is set, reqByte must be + later in the subject; otherwise the test starts at the match point. This + optimization can save a huge amount of backtracking in patterns with nested + unlimited repeats that aren't going to match. Writing separate code for + cased/caseless versions makes it go faster, as does using an autoincrement + and backing off on a match. + + HOWEVER: when the subject string is very, very long, searching to its end can + take a long time, and give bad performance on quite ordinary patterns. This + showed up when somebody was matching /^C/ on a 32-megabyte string... so we + don't do this when the string is sufficiently long. + */ + + if (reqByte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) { + const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0); + + /* We don't need to repeat the search if we haven't yet reached the + place we found it at last time. */ + + if (p > reqBytePtr) { + if (reqByteIsCaseless) { + while (p < endSubject) { + int pp = *p++; + if (pp == reqByte || pp == reqByte2) { + p--; + break; + } + } + } else { + while (p < endSubject) { + if (*p++ == reqByte) { + p--; + break; + } + } + } + + /* If we can't find the required character, break the matching loop */ + + if (p >= endSubject) + return true; + + /* If we have found the required character, save the point where we + found it, so that we don't search again next time round the loop if + the start hasn't passed this character yet. */ + + reqBytePtr = p; + } + } + return false; +} + +int jsRegExpExecute(JSContext *cx, const JSRegExp* re, + const UChar* subject, int length, int start_offset, int* offsets, + int offsetCount) +{ + JS_ASSERT(re); + JS_ASSERT(subject || !length); + JS_ASSERT(offsetCount >= 0); + JS_ASSERT(offsets || offsetCount == 0); + + MatchData matchBlock; + matchBlock.startSubject = subject; + matchBlock.endSubject = matchBlock.startSubject + length; + const UChar* endSubject = matchBlock.endSubject; + + matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption); + matchBlock.ignoreCase = (re->options & IgnoreCaseOption); + + /* Use the vector supplied, rounding down its size to a multiple of 3. */ + int ocount = offsetCount - (offsetCount % 3); + + matchBlock.offsetVector = offsets; + matchBlock.offsetEnd = ocount; + matchBlock.offsetMax = (2*ocount)/3; + matchBlock.offsetOverflow = false; + + /* Compute the minimum number of offsets that we need to reset each time. Doing + this makes a huge difference to execution time when there aren't many brackets + in the pattern. */ + + int resetCount = 2 + re->topBracket * 2; + if (resetCount > offsetCount) + resetCount = ocount; + + /* Reset the working variable associated with each extraction. These should + never be used unless previously set, but they get saved and restored, and so we + initialize them to avoid reading uninitialized locations. */ + + if (matchBlock.offsetVector) { + int* iptr = matchBlock.offsetVector + ocount; + int* iend = iptr - resetCount/2 + 1; + while (--iptr >= iend) + *iptr = -1; + } + + /* Set up the first character to match, if available. The firstByte value is + never set for an anchored regular expression, but the anchoring may be forced + at run time, so we have to test for anchoring. The first char may be unset for + an unanchored pattern, of course. If there's no first char and the pattern was + studied, there may be a bitmap of possible first characters. */ + + bool firstByteIsCaseless = false; + int firstByte = -1; + if (re->options & UseFirstByteOptimizationOption) { + firstByte = re->firstByte & 255; + if ((firstByteIsCaseless = (re->firstByte & REQ_IGNORE_CASE))) + firstByte = toLowerCase(firstByte); + } + + /* For anchored or unanchored matches, there may be a "last known required + character" set. */ + + bool reqByteIsCaseless = false; + int reqByte = -1; + int reqByte2 = -1; + if (re->options & UseRequiredByteOptimizationOption) { + reqByte = re->reqByte & 255; + reqByteIsCaseless = (re->reqByte & REQ_IGNORE_CASE); + reqByte2 = flipCase(reqByte); + } + + /* Loop for handling unanchored repeated matching attempts; for anchored regexs + the loop runs just once. */ + + const UChar* startMatch = subject + start_offset; + const UChar* reqBytePtr = startMatch - 1; + bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption; + + do { + /* Reset the maximum number of extractions we might see. */ + if (matchBlock.offsetVector) { + int* iptr = matchBlock.offsetVector; + int* iend = iptr + resetCount; + while (iptr < iend) + *iptr++ = -1; + } + + tryFirstByteOptimization(startMatch, endSubject, firstByte, firstByteIsCaseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset); + if (tryRequiredByteOptimization(startMatch, endSubject, reqByte, reqByte2, reqByteIsCaseless, firstByte >= 0, reqBytePtr)) + break; + + /* When a match occurs, substrings will be set for all internal extractions; + we just need to set up the whole thing as substring 0 before returning. If + there were too many extractions, set the return code to zero. In the case + where we had to get some local store to hold offsets for backreferences, copy + those back references that we can. In this case there need not be overflow + if certain parts of the pattern were not used. */ + + /* The code starts after the JSRegExp block and the capture name table. */ + const unsigned char* start_code = (const unsigned char*)(re + 1); + + int returnCode = match(&cx->regExpPool, startMatch, start_code, 2, matchBlock); + + /* When the result is no match, advance the pointer to the next character + and continue. */ + if (returnCode == 0) { + startMatch++; + continue; + } + + if (returnCode != 1) { + JS_ASSERT(returnCode == JSRegExpErrorHitLimit); + DPRINTF((">>>> error: returning %d\n", returnCode)); + return returnCode; + } + + /* We have a match! */ + + returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2; + + if (offsetCount < 2) + returnCode = 0; + else { + offsets[0] = startMatch - matchBlock.startSubject; + offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject; + } + + JS_ASSERT(returnCode >= 0); + DPRINTF((">>>> returning %d\n", returnCode)); + return returnCode; + } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject); + + DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); + return JSRegExpErrorNoMatch; +} diff --git a/js/src/yarr/pcre/pcre_internal.h b/js/src/yarr/pcre/pcre_internal.h new file mode 100644 index 000000000000..d677cfcfa255 --- /dev/null +++ b/js/src/yarr/pcre/pcre_internal.h @@ -0,0 +1,434 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This header contains definitions that are shared between the different +modules, but which are not relevant to the exported API. This includes some +functions whose names all begin with "_pcre_". */ + +#ifndef PCRE_INTERNAL_H +#define PCRE_INTERNAL_H + +/* Bit definitions for entries in the pcre_ctypes table. */ + +#define ctype_space 0x01 +#define ctype_xdigit 0x08 +#define ctype_word 0x10 /* alphameric or '_' */ + +/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set +of bits for a class map. Some classes are built by combining these tables. */ + +#define cbit_space 0 /* \s */ +#define cbit_digit 32 /* \d */ +#define cbit_word 64 /* \w */ +#define cbit_length 96 /* Length of the cbits table */ + +/* Offsets of the various tables from the base tables pointer, and +total length. */ + +#define lcc_offset 0 +#define fcc_offset 128 +#define cbits_offset 256 +#define ctypes_offset (cbits_offset + cbit_length) +#define tables_length (ctypes_offset + 128) + +#ifndef DFTABLES + +#include "pcre.h" + +/* The value of LINK_SIZE determines the number of bytes used to store links as +offsets within the compiled regex. The default is 2, which allows for compiled +patterns up to 64K long. */ + +#define LINK_SIZE 3 + +/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef +inline, and there are *still* stupid compilers about that don't like indented +pre-processor statements, or at least there were when I first wrote this. After +all, it had only been about 10 years then... */ + +#ifdef DEBUG +#define DPRINTF(p) /*printf p; fflush(stdout);*/ +#else +#define DPRINTF(p) /*nothing*/ +#endif + +/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored +in big-endian order) by default. These are used, for example, to link from the +start of a subpattern to its alternatives and its end. The use of 2 bytes per +offset limits the size of the compiled regex to around 64K, which is big enough +for almost everybody. However, I received a request for an even bigger limit. +For this reason, and also to make the code easier to maintain, the storing and +loading of offsets from the byte string is now handled by the functions that are +defined here. */ + +/* PCRE uses some other 2-byte quantities that do not change when the size of +offsets changes. There are used for repeat counts and for other things such as +capturing parenthesis numbers in back references. */ + +static inline void put2ByteValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value >= 0 && value <= 0xFFFF); + opcodePtr[0] = value >> 8; + opcodePtr[1] = value; +} + +static inline void put3ByteValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value >= 0 && value <= 0xFFFFFF); + opcodePtr[0] = value >> 16; + opcodePtr[1] = value >> 8; + opcodePtr[2] = value; +} + +static inline int get2ByteValue(const unsigned char* opcodePtr) +{ + return (opcodePtr[0] << 8) | opcodePtr[1]; +} + +static inline int get3ByteValue(const unsigned char* opcodePtr) +{ + return (opcodePtr[0] << 16) | (opcodePtr[1] << 8) | opcodePtr[2]; +} + +static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + put2ByteValue(opcodePtr, value); + opcodePtr += 2; +} + +static inline void put3ByteValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + put3ByteValue(opcodePtr, value); + opcodePtr += 3; +} + +static inline void putLinkValueAllowZero(unsigned char* opcodePtr, int value) +{ +#if LINK_SIZE == 3 + put3ByteValue(opcodePtr, value); +#elif LINK_SIZE == 2 + put2ByteValue(opcodePtr, value); +#else +# error LINK_SIZE not supported. +#endif +} + +static inline int getLinkValueAllowZero(const unsigned char* opcodePtr) +{ +#if LINK_SIZE == 3 + return get3ByteValue(opcodePtr); +#elif LINK_SIZE == 2 + return get2ByteValue(opcodePtr); +#else +# error LINK_SIZE not supported. +#endif +} + +#define MAX_PATTERN_SIZE 1024 * 1024 // Derived by empirical testing of compile time in PCRE and WREC. +JS_STATIC_ASSERT(MAX_PATTERN_SIZE < (1 << (8 * LINK_SIZE))); + +static inline void putLinkValue(unsigned char* opcodePtr, int value) +{ + JS_ASSERT(value); + putLinkValueAllowZero(opcodePtr, value); +} + +static inline int getLinkValue(const unsigned char* opcodePtr) +{ + int value = getLinkValueAllowZero(opcodePtr); + JS_ASSERT(value); + return value; +} + +static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr, int value) +{ + putLinkValue(opcodePtr, value); + opcodePtr += LINK_SIZE; +} + +static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr, int value) +{ + putLinkValueAllowZero(opcodePtr, value); + opcodePtr += LINK_SIZE; +} + +// FIXME: These are really more of a "compiled regexp state" than "regexp options" +enum RegExpOptions { + UseFirstByteOptimizationOption = 0x40000000, /* firstByte is set */ + UseRequiredByteOptimizationOption = 0x20000000, /* reqByte is set */ + UseMultiLineFirstByteOptimizationOption = 0x10000000, /* start after \n for multiline */ + IsAnchoredOption = 0x02000000, /* can't use partial with this regex */ + IgnoreCaseOption = 0x00000001, + MatchAcrossMultipleLinesOption = 0x00000002 +}; + +/* Flags added to firstByte or reqByte; a "non-literal" item is either a +variable-length repeat, or a anything other than literal characters. */ + +#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */ +#define REQ_VARY 0x0200 /* reqByte followed non-literal item */ + +/* Miscellaneous definitions */ + +/* Flag bits and data types for the extended class (OP_XCLASS) for classes that +contain UTF-8 characters with values greater than 255. */ + +#define XCL_NOT 0x01 /* Flag: this is a negative class */ +#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ + +#define XCL_END 0 /* Marks end of individual items */ +#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ +#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ + +/* These are escaped items that aren't just an encoding of a particular data +value such as \n. They must have non-zero values, as check_escape() returns +their negation. Also, they must appear in the same order as in the opcode +definitions below, up to ESC_w. The final one must be +ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two +tests in the code for an escape > ESC_b and <= ESC_w to +detect the types that may be repeated. These are the types that consume +characters. If any new escapes are put in between that don't consume a +character, that code will have to change. */ + +enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF }; + +/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets +that extract substrings. Starting from 1 (i.e. after OP_END), the values up to +OP_EOD must correspond in order to the list of escapes immediately above. +Note that whenever this list is updated, the two macro definitions that follow +must also be updated to match. */ + +#define FOR_EACH_OPCODE(macro) \ + macro(END) \ + \ + , macro(NOT_WORD_BOUNDARY) \ + , macro(WORD_BOUNDARY) \ + , macro(NOT_DIGIT) \ + , macro(DIGIT) \ + , macro(NOT_WHITESPACE) \ + , macro(WHITESPACE) \ + , macro(NOT_WORDCHAR) \ + , macro(WORDCHAR) \ + \ + , macro(NOT_NEWLINE) \ + \ + , macro(CIRC) \ + , macro(DOLL) \ + , macro(BOL) \ + , macro(EOL) \ + , macro(CHAR) \ + , macro(CHAR_IGNORING_CASE) \ + , macro(ASCII_CHAR) \ + , macro(ASCII_LETTER_IGNORING_CASE) \ + , macro(NOT) \ + \ + , macro(STAR) \ + , macro(MINSTAR) \ + , macro(PLUS) \ + , macro(MINPLUS) \ + , macro(QUERY) \ + , macro(MINQUERY) \ + , macro(UPTO) \ + , macro(MINUPTO) \ + , macro(EXACT) \ + \ + , macro(NOTSTAR) \ + , macro(NOTMINSTAR) \ + , macro(NOTPLUS) \ + , macro(NOTMINPLUS) \ + , macro(NOTQUERY) \ + , macro(NOTMINQUERY) \ + , macro(NOTUPTO) \ + , macro(NOTMINUPTO) \ + , macro(NOTEXACT) \ + \ + , macro(TYPESTAR) \ + , macro(TYPEMINSTAR) \ + , macro(TYPEPLUS) \ + , macro(TYPEMINPLUS) \ + , macro(TYPEQUERY) \ + , macro(TYPEMINQUERY) \ + , macro(TYPEUPTO) \ + , macro(TYPEMINUPTO) \ + , macro(TYPEEXACT) \ + \ + , macro(CRSTAR) \ + , macro(CRMINSTAR) \ + , macro(CRPLUS) \ + , macro(CRMINPLUS) \ + , macro(CRQUERY) \ + , macro(CRMINQUERY) \ + , macro(CRRANGE) \ + , macro(CRMINRANGE) \ + \ + , macro(CLASS) \ + , macro(NCLASS) \ + , macro(XCLASS) \ + \ + , macro(REF) \ + \ + , macro(ALT) \ + , macro(KET) \ + , macro(KETRMAX) \ + , macro(KETRMIN) \ + \ + , macro(ASSERT) \ + , macro(ASSERT_NOT) \ + \ + , macro(BRAZERO) \ + , macro(BRAMINZERO) \ + , macro(BRANUMBER) \ + , macro(BRA) + +#define OPCODE_ENUM_VALUE(opcode) OP_##opcode +enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) }; + +/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and +study.c that all opcodes are less than 128 in value. This makes handling UTF-8 +character sequences easier. */ + +/* The highest extraction number before we have to start using additional +bytes. (Originally PCRE didn't have support for extraction counts higher than +this number.) The value is limited by the number of opcodes left after OP_BRA, +i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional +opcodes. */ + +/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above +are in conflict! */ + +#define EXTRACT_BASIC_MAX 100 + +/* The code vector runs on as long as necessary after the end. */ + +struct JSRegExp { + unsigned options; + + unsigned short topBracket; + unsigned short topBackref; + + unsigned short firstByte; + unsigned short reqByte; +}; + +/* Internal shared data tables. These are tables that are used by more than one + of the exported public functions. They have to be "external" in the C sense, + but are not part of the PCRE public API. The data for these tables is in the + pcre_tables.c module. */ + +#define jsc_pcre_utf8_table1_size 6 + +extern const int jsc_pcre_utf8_table1[6]; +extern const int jsc_pcre_utf8_table2[6]; +extern const int jsc_pcre_utf8_table3[6]; +extern const unsigned char jsc_pcre_utf8_table4[0x40]; + +extern const unsigned char jsc_pcre_default_tables[tables_length]; + +static inline unsigned char toLowerCase(unsigned char c) +{ + static const unsigned char* lowerCaseChars = jsc_pcre_default_tables + lcc_offset; + return lowerCaseChars[c]; +} + +static inline unsigned char flipCase(unsigned char c) +{ + static const unsigned char* flippedCaseChars = jsc_pcre_default_tables + fcc_offset; + return flippedCaseChars[c]; +} + +static inline unsigned char classBitmapForChar(unsigned char c) +{ + static const unsigned char* charClassBitmaps = jsc_pcre_default_tables + cbits_offset; + return charClassBitmaps[c]; +} + +static inline unsigned char charTypeForChar(unsigned char c) +{ + const unsigned char* charTypeMap = jsc_pcre_default_tables + ctypes_offset; + return charTypeMap[c]; +} + +static inline bool isWordChar(UChar c) +{ + return c < 128 && (charTypeForChar(c) & ctype_word); +} + +static inline bool isSpaceChar(UChar c) +{ + return (c < 128 && (charTypeForChar(c) & ctype_space)) || c == 0x00A0; +} + +static inline bool isNewline(UChar nl) +{ + return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029); +} + +static inline bool isBracketStartOpcode(unsigned char opcode) +{ + if (opcode >= OP_BRA) + return true; + switch (opcode) { + case OP_ASSERT: + case OP_ASSERT_NOT: + return true; + default: + return false; + } +} + +static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr) +{ + JS_ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT); + do + opcodePtr += getLinkValue(opcodePtr + 1); + while (*opcodePtr == OP_ALT); +} + +/* Internal shared functions. These are functions that are used in more +that one of the source files. They have to have external linkage, but +but are not part of the public API and so not exported from the library. */ + +extern int jsc_pcre_ucp_othercase(unsigned); +extern bool jsc_pcre_xclass(int, const unsigned char*); + +#endif + +#endif + +/* End of pcre_internal.h */ diff --git a/js/src/yarr/pcre/pcre_tables.cpp b/js/src/yarr/pcre/pcre_tables.cpp new file mode 100644 index 000000000000..b1ac229d5912 --- /dev/null +++ b/js/src/yarr/pcre/pcre_tables.cpp @@ -0,0 +1,71 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains some fixed tables that are used by more than one of the +PCRE code modules. */ + +#include "pcre_internal.h" + +/************************************************* +* Tables for UTF-8 support * +*************************************************/ + +/* These are the breakpoints for different numbers of bytes in a UTF-8 +character. */ + +const int jsc_pcre_utf8_table1[6] = + { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; + +/* These are the indicator bits and the mask for the data bits to set in the +first byte of a character, indexed by the number of additional bytes. */ + +const int jsc_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; +const int jsc_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +/* Table of the number of extra characters, indexed by the first character +masked with 0x3f. The highest number for a valid UTF-8 character is in fact +0x3d. */ + +const unsigned char jsc_pcre_utf8_table4[0x40] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; + +#include "chartables.c" diff --git a/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp new file mode 100644 index 000000000000..b97db921c981 --- /dev/null +++ b/js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp @@ -0,0 +1,98 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + + +/* This module contains code for searching the table of Unicode character +properties. */ + +#include "pcre_internal.h" + +#include "ucpinternal.h" /* Internal table details */ +#include "ucptable.cpp" /* The table itself */ + +/************************************************* +* Search table and return other case * +*************************************************/ + +/* If the given character is a letter, and there is another case for the +letter, return the other case. Otherwise, return -1. + +Arguments: + c the character value + +Returns: the other case or -1 if none +*/ + +int jsc_pcre_ucp_othercase(unsigned c) +{ + int bot = 0; + int top = sizeof(ucp_table) / sizeof(cnode); + int mid; + + /* The table is searched using a binary chop. You might think that using + intermediate variables to hold some of the common expressions would speed + things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it + makes things a lot slower. */ + + for (;;) { + if (top <= bot) + return -1; + mid = (bot + top) >> 1; + if (c == (ucp_table[mid].f0 & f0_charmask)) + break; + if (c < (ucp_table[mid].f0 & f0_charmask)) + top = mid; + else { + if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask))) + break; + bot = mid + 1; + } + } + + /* Found an entry in the table. Return -1 for a range entry. Otherwise return + the other case if there is one, else -1. */ + + if (ucp_table[mid].f0 & f0_rangeflag) + return -1; + + int offset = ucp_table[mid].f1 & f1_casemask; + if (offset & f1_caseneg) + offset |= f1_caseneg; + return !offset ? -1 : c + offset; +} diff --git a/js/src/yarr/pcre/pcre_xclass.cpp b/js/src/yarr/pcre/pcre_xclass.cpp new file mode 100644 index 000000000000..8e59018ead0c --- /dev/null +++ b/js/src/yarr/pcre/pcre_xclass.cpp @@ -0,0 +1,114 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007, 2008, 2009 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/* This module contains an internal function that is used to match an extended +class (one that contains characters whose values are > 255). */ + +#include "pcre_internal.h" + +/************************************************* +* Match character against an XCLASS * +*************************************************/ + +/* This function is called to match a character against an extended class that +might contain values > 255. + +Arguments: + c the character + data points to the flag byte of the XCLASS data + +Returns: true if character matches, else false +*/ + +/* Get the next UTF-8 character, advancing the pointer. This is called when we + know we are in UTF-8 mode. */ + +static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr) +{ + c = *subjectPtr++; + if ((c & 0xc0) == 0xc0) { + int gcaa = jsc_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + int gcss = 6 * gcaa; + c = (c & jsc_pcre_utf8_table3[gcaa]) << gcss; + while (gcaa-- > 0) { + gcss -= 6; + c |= (*subjectPtr++ & 0x3f) << gcss; + } + } +} + +bool jsc_pcre_xclass(int c, const unsigned char* data) +{ + bool negated = (*data & XCL_NOT); + + /* Character values < 256 are matched against a bitmap, if one is present. If + not, we still carry on, because there may be ranges that start below 256 in the + additional data. */ + + if (c < 256) { + if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) + return !negated; /* char found */ + } + + /* First skip the bit map if present. Then match against the list of Unicode + properties or large chars or ranges that end with a large char. We won't ever + encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ + + if ((*data++ & XCL_MAP) != 0) + data += 32; + + int t; + while ((t = *data++) != XCL_END) { + if (t == XCL_SINGLE) { + int x; + getUTF8CharAndAdvancePointer(x, data); + if (c == x) + return !negated; + } + else if (t == XCL_RANGE) { + int x, y; + getUTF8CharAndAdvancePointer(x, data); + getUTF8CharAndAdvancePointer(y, data); + if (c >= x && c <= y) + return !negated; + } + } + + return negated; /* char did not match */ +} diff --git a/js/src/yarr/pcre/ucpinternal.h b/js/src/yarr/pcre/ucpinternal.h new file mode 100644 index 000000000000..c8bc4aab679c --- /dev/null +++ b/js/src/yarr/pcre/ucpinternal.h @@ -0,0 +1,126 @@ +/* This is JavaScriptCore's variant of the PCRE library. While this library +started out as a copy of PCRE, many of the features of PCRE have been +removed. This library now supports only the regular expression features +required by the JavaScript language specification, and has only the functions +needed by JavaScriptCore and the rest of WebKit. + + Originally written by Philip Hazel + Copyright (c) 1997-2006 University of Cambridge + Copyright (C) 2002, 2004, 2006, 2007 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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. +----------------------------------------------------------------------------- +*/ + +/************************************************* +* Unicode Property Table handler * +*************************************************/ + +/* Internal header file defining the layout of the bits in each pair of 32-bit +words that form a data item in the table. */ + +typedef struct cnode { + unsigned f0; + unsigned f1; +} cnode; + +/* Things for the f0 field */ + +#define f0_scriptmask 0xff000000 /* Mask for script field */ +#define f0_scriptshift 24 /* Shift for script value */ +#define f0_rangeflag 0x00f00000 /* Flag for a range item */ +#define f0_charmask 0x001fffff /* Mask for code point value */ + +/* Things for the f1 field */ + +#define f1_typemask 0xfc000000 /* Mask for char type field */ +#define f1_typeshift 26 /* Shift for the type field */ +#define f1_rangemask 0x0000ffff /* Mask for a range offset */ +#define f1_casemask 0x0000ffff /* Mask for a case offset */ +#define f1_caseneg 0xffff8000 /* Bits for negation */ + +/* The data consists of a vector of structures of type cnode. The two unsigned +32-bit integers are used as follows: + +(f0) (1) The most significant byte holds the script number. The numbers are + defined by the enum in ucp.h. + + (2) The 0x00800000 bit is set if this entry defines a range of characters. + It is not set if this entry defines a single character + + (3) The 0x00600000 bits are spare. + + (4) The 0x001fffff bits contain the code point. No Unicode code point will + ever be greater than 0x0010ffff, so this should be OK for ever. + +(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are + defined by an enum in ucp.h. + + (2) The 0x03ff0000 bits are spare. + + (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of + range if this entry defines a range, OR the *signed* offset to the + character's "other case" partner if this entry defines a single + character. There is no partner if the value is zero. + +------------------------------------------------------------------------------- +| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) | +------------------------------------------------------------------------------- + | | | | | + | | |-> spare | |-> spare + | | | + | |-> spare |-> spare + | + |-> range flag + +The upper/lower casing information is set only for characters that come in +pairs. The non-one-to-one mappings in the Unicode data are ignored. + +When searching the data, proceed as follows: + +(1) Set up for a binary chop search. + +(2) If the top is not greater than the bottom, the character is not in the + table. Its type must therefore be "Cn" ("Undefined"). + +(3) Find the middle vector element. + +(4) Extract the code point and compare. If equal, we are done. + +(5) If the test character is smaller, set the top to the current point, and + goto (2). + +(6) If the current entry defines a range, compute the last character by adding + the offset, and see if the test character is within the range. If it is, + we are done. + +(7) Otherwise, set the bottom to one element past the current point and goto + (2). +*/ + +/* End of ucpinternal.h */ diff --git a/js/src/yarr/pcre/ucptable.cpp b/js/src/yarr/pcre/ucptable.cpp new file mode 100644 index 000000000000..011f7f572443 --- /dev/null +++ b/js/src/yarr/pcre/ucptable.cpp @@ -0,0 +1,2968 @@ +/* This source module is automatically generated from the Unicode +property table. See ucpinternal.h for a description of the layout. */ + +static const cnode ucp_table[] = { + { 0x09800000, 0x0000001f }, + { 0x09000020, 0x74000000 }, + { 0x09800021, 0x54000002 }, + { 0x09000024, 0x5c000000 }, + { 0x09800025, 0x54000002 }, + { 0x09000028, 0x58000000 }, + { 0x09000029, 0x48000000 }, + { 0x0900002a, 0x54000000 }, + { 0x0900002b, 0x64000000 }, + { 0x0900002c, 0x54000000 }, + { 0x0900002d, 0x44000000 }, + { 0x0980002e, 0x54000001 }, + { 0x09800030, 0x34000009 }, + { 0x0980003a, 0x54000001 }, + { 0x0980003c, 0x64000002 }, + { 0x0980003f, 0x54000001 }, + { 0x21000041, 0x24000020 }, + { 0x21000042, 0x24000020 }, + { 0x21000043, 0x24000020 }, + { 0x21000044, 0x24000020 }, + { 0x21000045, 0x24000020 }, + { 0x21000046, 0x24000020 }, + { 0x21000047, 0x24000020 }, + { 0x21000048, 0x24000020 }, + { 0x21000049, 0x24000020 }, + { 0x2100004a, 0x24000020 }, + { 0x2100004b, 0x24000020 }, + { 0x2100004c, 0x24000020 }, + { 0x2100004d, 0x24000020 }, + { 0x2100004e, 0x24000020 }, + { 0x2100004f, 0x24000020 }, + { 0x21000050, 0x24000020 }, + { 0x21000051, 0x24000020 }, + { 0x21000052, 0x24000020 }, + { 0x21000053, 0x24000020 }, + { 0x21000054, 0x24000020 }, + { 0x21000055, 0x24000020 }, + { 0x21000056, 0x24000020 }, + { 0x21000057, 0x24000020 }, + { 0x21000058, 0x24000020 }, + { 0x21000059, 0x24000020 }, + { 0x2100005a, 0x24000020 }, + { 0x0900005b, 0x58000000 }, + { 0x0900005c, 0x54000000 }, + { 0x0900005d, 0x48000000 }, + { 0x0900005e, 0x60000000 }, + { 0x0900005f, 0x40000000 }, + { 0x09000060, 0x60000000 }, + { 0x21000061, 0x1400ffe0 }, + { 0x21000062, 0x1400ffe0 }, + { 0x21000063, 0x1400ffe0 }, + { 0x21000064, 0x1400ffe0 }, + { 0x21000065, 0x1400ffe0 }, + { 0x21000066, 0x1400ffe0 }, + { 0x21000067, 0x1400ffe0 }, + { 0x21000068, 0x1400ffe0 }, + { 0x21000069, 0x1400ffe0 }, + { 0x2100006a, 0x1400ffe0 }, + { 0x2100006b, 0x1400ffe0 }, + { 0x2100006c, 0x1400ffe0 }, + { 0x2100006d, 0x1400ffe0 }, + { 0x2100006e, 0x1400ffe0 }, + { 0x2100006f, 0x1400ffe0 }, + { 0x21000070, 0x1400ffe0 }, + { 0x21000071, 0x1400ffe0 }, + { 0x21000072, 0x1400ffe0 }, + { 0x21000073, 0x1400ffe0 }, + { 0x21000074, 0x1400ffe0 }, + { 0x21000075, 0x1400ffe0 }, + { 0x21000076, 0x1400ffe0 }, + { 0x21000077, 0x1400ffe0 }, + { 0x21000078, 0x1400ffe0 }, + { 0x21000079, 0x1400ffe0 }, + { 0x2100007a, 0x1400ffe0 }, + { 0x0900007b, 0x58000000 }, + { 0x0900007c, 0x64000000 }, + { 0x0900007d, 0x48000000 }, + { 0x0900007e, 0x64000000 }, + { 0x0980007f, 0x00000020 }, + { 0x090000a0, 0x74000000 }, + { 0x090000a1, 0x54000000 }, + { 0x098000a2, 0x5c000003 }, + { 0x098000a6, 0x68000001 }, + { 0x090000a8, 0x60000000 }, + { 0x090000a9, 0x68000000 }, + { 0x210000aa, 0x14000000 }, + { 0x090000ab, 0x50000000 }, + { 0x090000ac, 0x64000000 }, + { 0x090000ad, 0x04000000 }, + { 0x090000ae, 0x68000000 }, + { 0x090000af, 0x60000000 }, + { 0x090000b0, 0x68000000 }, + { 0x090000b1, 0x64000000 }, + { 0x098000b2, 0x3c000001 }, + { 0x090000b4, 0x60000000 }, + { 0x090000b5, 0x140002e7 }, + { 0x090000b6, 0x68000000 }, + { 0x090000b7, 0x54000000 }, + { 0x090000b8, 0x60000000 }, + { 0x090000b9, 0x3c000000 }, + { 0x210000ba, 0x14000000 }, + { 0x090000bb, 0x4c000000 }, + { 0x098000bc, 0x3c000002 }, + { 0x090000bf, 0x54000000 }, + { 0x210000c0, 0x24000020 }, + { 0x210000c1, 0x24000020 }, + { 0x210000c2, 0x24000020 }, + { 0x210000c3, 0x24000020 }, + { 0x210000c4, 0x24000020 }, + { 0x210000c5, 0x24000020 }, + { 0x210000c6, 0x24000020 }, + { 0x210000c7, 0x24000020 }, + { 0x210000c8, 0x24000020 }, + { 0x210000c9, 0x24000020 }, + { 0x210000ca, 0x24000020 }, + { 0x210000cb, 0x24000020 }, + { 0x210000cc, 0x24000020 }, + { 0x210000cd, 0x24000020 }, + { 0x210000ce, 0x24000020 }, + { 0x210000cf, 0x24000020 }, + { 0x210000d0, 0x24000020 }, + { 0x210000d1, 0x24000020 }, + { 0x210000d2, 0x24000020 }, + { 0x210000d3, 0x24000020 }, + { 0x210000d4, 0x24000020 }, + { 0x210000d5, 0x24000020 }, + { 0x210000d6, 0x24000020 }, + { 0x090000d7, 0x64000000 }, + { 0x210000d8, 0x24000020 }, + { 0x210000d9, 0x24000020 }, + { 0x210000da, 0x24000020 }, + { 0x210000db, 0x24000020 }, + { 0x210000dc, 0x24000020 }, + { 0x210000dd, 0x24000020 }, + { 0x210000de, 0x24000020 }, + { 0x210000df, 0x14000000 }, + { 0x210000e0, 0x1400ffe0 }, + { 0x210000e1, 0x1400ffe0 }, + { 0x210000e2, 0x1400ffe0 }, + { 0x210000e3, 0x1400ffe0 }, + { 0x210000e4, 0x1400ffe0 }, + { 0x210000e5, 0x1400ffe0 }, + { 0x210000e6, 0x1400ffe0 }, + { 0x210000e7, 0x1400ffe0 }, + { 0x210000e8, 0x1400ffe0 }, + { 0x210000e9, 0x1400ffe0 }, + { 0x210000ea, 0x1400ffe0 }, + { 0x210000eb, 0x1400ffe0 }, + { 0x210000ec, 0x1400ffe0 }, + { 0x210000ed, 0x1400ffe0 }, + { 0x210000ee, 0x1400ffe0 }, + { 0x210000ef, 0x1400ffe0 }, + { 0x210000f0, 0x1400ffe0 }, + { 0x210000f1, 0x1400ffe0 }, + { 0x210000f2, 0x1400ffe0 }, + { 0x210000f3, 0x1400ffe0 }, + { 0x210000f4, 0x1400ffe0 }, + { 0x210000f5, 0x1400ffe0 }, + { 0x210000f6, 0x1400ffe0 }, + { 0x090000f7, 0x64000000 }, + { 0x210000f8, 0x1400ffe0 }, + { 0x210000f9, 0x1400ffe0 }, + { 0x210000fa, 0x1400ffe0 }, + { 0x210000fb, 0x1400ffe0 }, + { 0x210000fc, 0x1400ffe0 }, + { 0x210000fd, 0x1400ffe0 }, + { 0x210000fe, 0x1400ffe0 }, + { 0x210000ff, 0x14000079 }, + { 0x21000100, 0x24000001 }, + { 0x21000101, 0x1400ffff }, + { 0x21000102, 0x24000001 }, + { 0x21000103, 0x1400ffff }, + { 0x21000104, 0x24000001 }, + { 0x21000105, 0x1400ffff }, + { 0x21000106, 0x24000001 }, + { 0x21000107, 0x1400ffff }, + { 0x21000108, 0x24000001 }, + { 0x21000109, 0x1400ffff }, + { 0x2100010a, 0x24000001 }, + { 0x2100010b, 0x1400ffff }, + { 0x2100010c, 0x24000001 }, + { 0x2100010d, 0x1400ffff }, + { 0x2100010e, 0x24000001 }, + { 0x2100010f, 0x1400ffff }, + { 0x21000110, 0x24000001 }, + { 0x21000111, 0x1400ffff }, + { 0x21000112, 0x24000001 }, + { 0x21000113, 0x1400ffff }, + { 0x21000114, 0x24000001 }, + { 0x21000115, 0x1400ffff }, + { 0x21000116, 0x24000001 }, + { 0x21000117, 0x1400ffff }, + { 0x21000118, 0x24000001 }, + { 0x21000119, 0x1400ffff }, + { 0x2100011a, 0x24000001 }, + { 0x2100011b, 0x1400ffff }, + { 0x2100011c, 0x24000001 }, + { 0x2100011d, 0x1400ffff }, + { 0x2100011e, 0x24000001 }, + { 0x2100011f, 0x1400ffff }, + { 0x21000120, 0x24000001 }, + { 0x21000121, 0x1400ffff }, + { 0x21000122, 0x24000001 }, + { 0x21000123, 0x1400ffff }, + { 0x21000124, 0x24000001 }, + { 0x21000125, 0x1400ffff }, + { 0x21000126, 0x24000001 }, + { 0x21000127, 0x1400ffff }, + { 0x21000128, 0x24000001 }, + { 0x21000129, 0x1400ffff }, + { 0x2100012a, 0x24000001 }, + { 0x2100012b, 0x1400ffff }, + { 0x2100012c, 0x24000001 }, + { 0x2100012d, 0x1400ffff }, + { 0x2100012e, 0x24000001 }, + { 0x2100012f, 0x1400ffff }, + { 0x21000130, 0x2400ff39 }, + { 0x21000131, 0x1400ff18 }, + { 0x21000132, 0x24000001 }, + { 0x21000133, 0x1400ffff }, + { 0x21000134, 0x24000001 }, + { 0x21000135, 0x1400ffff }, + { 0x21000136, 0x24000001 }, + { 0x21000137, 0x1400ffff }, + { 0x21000138, 0x14000000 }, + { 0x21000139, 0x24000001 }, + { 0x2100013a, 0x1400ffff }, + { 0x2100013b, 0x24000001 }, + { 0x2100013c, 0x1400ffff }, + { 0x2100013d, 0x24000001 }, + { 0x2100013e, 0x1400ffff }, + { 0x2100013f, 0x24000001 }, + { 0x21000140, 0x1400ffff }, + { 0x21000141, 0x24000001 }, + { 0x21000142, 0x1400ffff }, + { 0x21000143, 0x24000001 }, + { 0x21000144, 0x1400ffff }, + { 0x21000145, 0x24000001 }, + { 0x21000146, 0x1400ffff }, + { 0x21000147, 0x24000001 }, + { 0x21000148, 0x1400ffff }, + { 0x21000149, 0x14000000 }, + { 0x2100014a, 0x24000001 }, + { 0x2100014b, 0x1400ffff }, + { 0x2100014c, 0x24000001 }, + { 0x2100014d, 0x1400ffff }, + { 0x2100014e, 0x24000001 }, + { 0x2100014f, 0x1400ffff }, + { 0x21000150, 0x24000001 }, + { 0x21000151, 0x1400ffff }, + { 0x21000152, 0x24000001 }, + { 0x21000153, 0x1400ffff }, + { 0x21000154, 0x24000001 }, + { 0x21000155, 0x1400ffff }, + { 0x21000156, 0x24000001 }, + { 0x21000157, 0x1400ffff }, + { 0x21000158, 0x24000001 }, + { 0x21000159, 0x1400ffff }, + { 0x2100015a, 0x24000001 }, + { 0x2100015b, 0x1400ffff }, + { 0x2100015c, 0x24000001 }, + { 0x2100015d, 0x1400ffff }, + { 0x2100015e, 0x24000001 }, + { 0x2100015f, 0x1400ffff }, + { 0x21000160, 0x24000001 }, + { 0x21000161, 0x1400ffff }, + { 0x21000162, 0x24000001 }, + { 0x21000163, 0x1400ffff }, + { 0x21000164, 0x24000001 }, + { 0x21000165, 0x1400ffff }, + { 0x21000166, 0x24000001 }, + { 0x21000167, 0x1400ffff }, + { 0x21000168, 0x24000001 }, + { 0x21000169, 0x1400ffff }, + { 0x2100016a, 0x24000001 }, + { 0x2100016b, 0x1400ffff }, + { 0x2100016c, 0x24000001 }, + { 0x2100016d, 0x1400ffff }, + { 0x2100016e, 0x24000001 }, + { 0x2100016f, 0x1400ffff }, + { 0x21000170, 0x24000001 }, + { 0x21000171, 0x1400ffff }, + { 0x21000172, 0x24000001 }, + { 0x21000173, 0x1400ffff }, + { 0x21000174, 0x24000001 }, + { 0x21000175, 0x1400ffff }, + { 0x21000176, 0x24000001 }, + { 0x21000177, 0x1400ffff }, + { 0x21000178, 0x2400ff87 }, + { 0x21000179, 0x24000001 }, + { 0x2100017a, 0x1400ffff }, + { 0x2100017b, 0x24000001 }, + { 0x2100017c, 0x1400ffff }, + { 0x2100017d, 0x24000001 }, + { 0x2100017e, 0x1400ffff }, + { 0x2100017f, 0x1400fed4 }, + { 0x21000180, 0x14000000 }, + { 0x21000181, 0x240000d2 }, + { 0x21000182, 0x24000001 }, + { 0x21000183, 0x1400ffff }, + { 0x21000184, 0x24000001 }, + { 0x21000185, 0x1400ffff }, + { 0x21000186, 0x240000ce }, + { 0x21000187, 0x24000001 }, + { 0x21000188, 0x1400ffff }, + { 0x21000189, 0x240000cd }, + { 0x2100018a, 0x240000cd }, + { 0x2100018b, 0x24000001 }, + { 0x2100018c, 0x1400ffff }, + { 0x2100018d, 0x14000000 }, + { 0x2100018e, 0x2400004f }, + { 0x2100018f, 0x240000ca }, + { 0x21000190, 0x240000cb }, + { 0x21000191, 0x24000001 }, + { 0x21000192, 0x1400ffff }, + { 0x21000193, 0x240000cd }, + { 0x21000194, 0x240000cf }, + { 0x21000195, 0x14000061 }, + { 0x21000196, 0x240000d3 }, + { 0x21000197, 0x240000d1 }, + { 0x21000198, 0x24000001 }, + { 0x21000199, 0x1400ffff }, + { 0x2100019a, 0x140000a3 }, + { 0x2100019b, 0x14000000 }, + { 0x2100019c, 0x240000d3 }, + { 0x2100019d, 0x240000d5 }, + { 0x2100019e, 0x14000082 }, + { 0x2100019f, 0x240000d6 }, + { 0x210001a0, 0x24000001 }, + { 0x210001a1, 0x1400ffff }, + { 0x210001a2, 0x24000001 }, + { 0x210001a3, 0x1400ffff }, + { 0x210001a4, 0x24000001 }, + { 0x210001a5, 0x1400ffff }, + { 0x210001a6, 0x240000da }, + { 0x210001a7, 0x24000001 }, + { 0x210001a8, 0x1400ffff }, + { 0x210001a9, 0x240000da }, + { 0x218001aa, 0x14000001 }, + { 0x210001ac, 0x24000001 }, + { 0x210001ad, 0x1400ffff }, + { 0x210001ae, 0x240000da }, + { 0x210001af, 0x24000001 }, + { 0x210001b0, 0x1400ffff }, + { 0x210001b1, 0x240000d9 }, + { 0x210001b2, 0x240000d9 }, + { 0x210001b3, 0x24000001 }, + { 0x210001b4, 0x1400ffff }, + { 0x210001b5, 0x24000001 }, + { 0x210001b6, 0x1400ffff }, + { 0x210001b7, 0x240000db }, + { 0x210001b8, 0x24000001 }, + { 0x210001b9, 0x1400ffff }, + { 0x210001ba, 0x14000000 }, + { 0x210001bb, 0x1c000000 }, + { 0x210001bc, 0x24000001 }, + { 0x210001bd, 0x1400ffff }, + { 0x210001be, 0x14000000 }, + { 0x210001bf, 0x14000038 }, + { 0x218001c0, 0x1c000003 }, + { 0x210001c4, 0x24000002 }, + { 0x210001c5, 0x2000ffff }, + { 0x210001c6, 0x1400fffe }, + { 0x210001c7, 0x24000002 }, + { 0x210001c8, 0x2000ffff }, + { 0x210001c9, 0x1400fffe }, + { 0x210001ca, 0x24000002 }, + { 0x210001cb, 0x2000ffff }, + { 0x210001cc, 0x1400fffe }, + { 0x210001cd, 0x24000001 }, + { 0x210001ce, 0x1400ffff }, + { 0x210001cf, 0x24000001 }, + { 0x210001d0, 0x1400ffff }, + { 0x210001d1, 0x24000001 }, + { 0x210001d2, 0x1400ffff }, + { 0x210001d3, 0x24000001 }, + { 0x210001d4, 0x1400ffff }, + { 0x210001d5, 0x24000001 }, + { 0x210001d6, 0x1400ffff }, + { 0x210001d7, 0x24000001 }, + { 0x210001d8, 0x1400ffff }, + { 0x210001d9, 0x24000001 }, + { 0x210001da, 0x1400ffff }, + { 0x210001db, 0x24000001 }, + { 0x210001dc, 0x1400ffff }, + { 0x210001dd, 0x1400ffb1 }, + { 0x210001de, 0x24000001 }, + { 0x210001df, 0x1400ffff }, + { 0x210001e0, 0x24000001 }, + { 0x210001e1, 0x1400ffff }, + { 0x210001e2, 0x24000001 }, + { 0x210001e3, 0x1400ffff }, + { 0x210001e4, 0x24000001 }, + { 0x210001e5, 0x1400ffff }, + { 0x210001e6, 0x24000001 }, + { 0x210001e7, 0x1400ffff }, + { 0x210001e8, 0x24000001 }, + { 0x210001e9, 0x1400ffff }, + { 0x210001ea, 0x24000001 }, + { 0x210001eb, 0x1400ffff }, + { 0x210001ec, 0x24000001 }, + { 0x210001ed, 0x1400ffff }, + { 0x210001ee, 0x24000001 }, + { 0x210001ef, 0x1400ffff }, + { 0x210001f0, 0x14000000 }, + { 0x210001f1, 0x24000002 }, + { 0x210001f2, 0x2000ffff }, + { 0x210001f3, 0x1400fffe }, + { 0x210001f4, 0x24000001 }, + { 0x210001f5, 0x1400ffff }, + { 0x210001f6, 0x2400ff9f }, + { 0x210001f7, 0x2400ffc8 }, + { 0x210001f8, 0x24000001 }, + { 0x210001f9, 0x1400ffff }, + { 0x210001fa, 0x24000001 }, + { 0x210001fb, 0x1400ffff }, + { 0x210001fc, 0x24000001 }, + { 0x210001fd, 0x1400ffff }, + { 0x210001fe, 0x24000001 }, + { 0x210001ff, 0x1400ffff }, + { 0x21000200, 0x24000001 }, + { 0x21000201, 0x1400ffff }, + { 0x21000202, 0x24000001 }, + { 0x21000203, 0x1400ffff }, + { 0x21000204, 0x24000001 }, + { 0x21000205, 0x1400ffff }, + { 0x21000206, 0x24000001 }, + { 0x21000207, 0x1400ffff }, + { 0x21000208, 0x24000001 }, + { 0x21000209, 0x1400ffff }, + { 0x2100020a, 0x24000001 }, + { 0x2100020b, 0x1400ffff }, + { 0x2100020c, 0x24000001 }, + { 0x2100020d, 0x1400ffff }, + { 0x2100020e, 0x24000001 }, + { 0x2100020f, 0x1400ffff }, + { 0x21000210, 0x24000001 }, + { 0x21000211, 0x1400ffff }, + { 0x21000212, 0x24000001 }, + { 0x21000213, 0x1400ffff }, + { 0x21000214, 0x24000001 }, + { 0x21000215, 0x1400ffff }, + { 0x21000216, 0x24000001 }, + { 0x21000217, 0x1400ffff }, + { 0x21000218, 0x24000001 }, + { 0x21000219, 0x1400ffff }, + { 0x2100021a, 0x24000001 }, + { 0x2100021b, 0x1400ffff }, + { 0x2100021c, 0x24000001 }, + { 0x2100021d, 0x1400ffff }, + { 0x2100021e, 0x24000001 }, + { 0x2100021f, 0x1400ffff }, + { 0x21000220, 0x2400ff7e }, + { 0x21000221, 0x14000000 }, + { 0x21000222, 0x24000001 }, + { 0x21000223, 0x1400ffff }, + { 0x21000224, 0x24000001 }, + { 0x21000225, 0x1400ffff }, + { 0x21000226, 0x24000001 }, + { 0x21000227, 0x1400ffff }, + { 0x21000228, 0x24000001 }, + { 0x21000229, 0x1400ffff }, + { 0x2100022a, 0x24000001 }, + { 0x2100022b, 0x1400ffff }, + { 0x2100022c, 0x24000001 }, + { 0x2100022d, 0x1400ffff }, + { 0x2100022e, 0x24000001 }, + { 0x2100022f, 0x1400ffff }, + { 0x21000230, 0x24000001 }, + { 0x21000231, 0x1400ffff }, + { 0x21000232, 0x24000001 }, + { 0x21000233, 0x1400ffff }, + { 0x21800234, 0x14000005 }, + { 0x2100023a, 0x24000000 }, + { 0x2100023b, 0x24000001 }, + { 0x2100023c, 0x1400ffff }, + { 0x2100023d, 0x2400ff5d }, + { 0x2100023e, 0x24000000 }, + { 0x2180023f, 0x14000001 }, + { 0x21000241, 0x24000053 }, + { 0x21800250, 0x14000002 }, + { 0x21000253, 0x1400ff2e }, + { 0x21000254, 0x1400ff32 }, + { 0x21000255, 0x14000000 }, + { 0x21000256, 0x1400ff33 }, + { 0x21000257, 0x1400ff33 }, + { 0x21000258, 0x14000000 }, + { 0x21000259, 0x1400ff36 }, + { 0x2100025a, 0x14000000 }, + { 0x2100025b, 0x1400ff35 }, + { 0x2180025c, 0x14000003 }, + { 0x21000260, 0x1400ff33 }, + { 0x21800261, 0x14000001 }, + { 0x21000263, 0x1400ff31 }, + { 0x21800264, 0x14000003 }, + { 0x21000268, 0x1400ff2f }, + { 0x21000269, 0x1400ff2d }, + { 0x2180026a, 0x14000004 }, + { 0x2100026f, 0x1400ff2d }, + { 0x21800270, 0x14000001 }, + { 0x21000272, 0x1400ff2b }, + { 0x21800273, 0x14000001 }, + { 0x21000275, 0x1400ff2a }, + { 0x21800276, 0x14000009 }, + { 0x21000280, 0x1400ff26 }, + { 0x21800281, 0x14000001 }, + { 0x21000283, 0x1400ff26 }, + { 0x21800284, 0x14000003 }, + { 0x21000288, 0x1400ff26 }, + { 0x21000289, 0x14000000 }, + { 0x2100028a, 0x1400ff27 }, + { 0x2100028b, 0x1400ff27 }, + { 0x2180028c, 0x14000005 }, + { 0x21000292, 0x1400ff25 }, + { 0x21000293, 0x14000000 }, + { 0x21000294, 0x1400ffad }, + { 0x21800295, 0x1400001a }, + { 0x218002b0, 0x18000011 }, + { 0x098002c2, 0x60000003 }, + { 0x098002c6, 0x1800000b }, + { 0x098002d2, 0x6000000d }, + { 0x218002e0, 0x18000004 }, + { 0x098002e5, 0x60000008 }, + { 0x090002ee, 0x18000000 }, + { 0x098002ef, 0x60000010 }, + { 0x1b800300, 0x30000044 }, + { 0x1b000345, 0x30000054 }, + { 0x1b800346, 0x30000029 }, + { 0x13800374, 0x60000001 }, + { 0x1300037a, 0x18000000 }, + { 0x0900037e, 0x54000000 }, + { 0x13800384, 0x60000001 }, + { 0x13000386, 0x24000026 }, + { 0x09000387, 0x54000000 }, + { 0x13000388, 0x24000025 }, + { 0x13000389, 0x24000025 }, + { 0x1300038a, 0x24000025 }, + { 0x1300038c, 0x24000040 }, + { 0x1300038e, 0x2400003f }, + { 0x1300038f, 0x2400003f }, + { 0x13000390, 0x14000000 }, + { 0x13000391, 0x24000020 }, + { 0x13000392, 0x24000020 }, + { 0x13000393, 0x24000020 }, + { 0x13000394, 0x24000020 }, + { 0x13000395, 0x24000020 }, + { 0x13000396, 0x24000020 }, + { 0x13000397, 0x24000020 }, + { 0x13000398, 0x24000020 }, + { 0x13000399, 0x24000020 }, + { 0x1300039a, 0x24000020 }, + { 0x1300039b, 0x24000020 }, + { 0x1300039c, 0x24000020 }, + { 0x1300039d, 0x24000020 }, + { 0x1300039e, 0x24000020 }, + { 0x1300039f, 0x24000020 }, + { 0x130003a0, 0x24000020 }, + { 0x130003a1, 0x24000020 }, + { 0x130003a3, 0x24000020 }, + { 0x130003a4, 0x24000020 }, + { 0x130003a5, 0x24000020 }, + { 0x130003a6, 0x24000020 }, + { 0x130003a7, 0x24000020 }, + { 0x130003a8, 0x24000020 }, + { 0x130003a9, 0x24000020 }, + { 0x130003aa, 0x24000020 }, + { 0x130003ab, 0x24000020 }, + { 0x130003ac, 0x1400ffda }, + { 0x130003ad, 0x1400ffdb }, + { 0x130003ae, 0x1400ffdb }, + { 0x130003af, 0x1400ffdb }, + { 0x130003b0, 0x14000000 }, + { 0x130003b1, 0x1400ffe0 }, + { 0x130003b2, 0x1400ffe0 }, + { 0x130003b3, 0x1400ffe0 }, + { 0x130003b4, 0x1400ffe0 }, + { 0x130003b5, 0x1400ffe0 }, + { 0x130003b6, 0x1400ffe0 }, + { 0x130003b7, 0x1400ffe0 }, + { 0x130003b8, 0x1400ffe0 }, + { 0x130003b9, 0x1400ffe0 }, + { 0x130003ba, 0x1400ffe0 }, + { 0x130003bb, 0x1400ffe0 }, + { 0x130003bc, 0x1400ffe0 }, + { 0x130003bd, 0x1400ffe0 }, + { 0x130003be, 0x1400ffe0 }, + { 0x130003bf, 0x1400ffe0 }, + { 0x130003c0, 0x1400ffe0 }, + { 0x130003c1, 0x1400ffe0 }, + { 0x130003c2, 0x1400ffe1 }, + { 0x130003c3, 0x1400ffe0 }, + { 0x130003c4, 0x1400ffe0 }, + { 0x130003c5, 0x1400ffe0 }, + { 0x130003c6, 0x1400ffe0 }, + { 0x130003c7, 0x1400ffe0 }, + { 0x130003c8, 0x1400ffe0 }, + { 0x130003c9, 0x1400ffe0 }, + { 0x130003ca, 0x1400ffe0 }, + { 0x130003cb, 0x1400ffe0 }, + { 0x130003cc, 0x1400ffc0 }, + { 0x130003cd, 0x1400ffc1 }, + { 0x130003ce, 0x1400ffc1 }, + { 0x130003d0, 0x1400ffc2 }, + { 0x130003d1, 0x1400ffc7 }, + { 0x138003d2, 0x24000002 }, + { 0x130003d5, 0x1400ffd1 }, + { 0x130003d6, 0x1400ffca }, + { 0x130003d7, 0x14000000 }, + { 0x130003d8, 0x24000001 }, + { 0x130003d9, 0x1400ffff }, + { 0x130003da, 0x24000001 }, + { 0x130003db, 0x1400ffff }, + { 0x130003dc, 0x24000001 }, + { 0x130003dd, 0x1400ffff }, + { 0x130003de, 0x24000001 }, + { 0x130003df, 0x1400ffff }, + { 0x130003e0, 0x24000001 }, + { 0x130003e1, 0x1400ffff }, + { 0x0a0003e2, 0x24000001 }, + { 0x0a0003e3, 0x1400ffff }, + { 0x0a0003e4, 0x24000001 }, + { 0x0a0003e5, 0x1400ffff }, + { 0x0a0003e6, 0x24000001 }, + { 0x0a0003e7, 0x1400ffff }, + { 0x0a0003e8, 0x24000001 }, + { 0x0a0003e9, 0x1400ffff }, + { 0x0a0003ea, 0x24000001 }, + { 0x0a0003eb, 0x1400ffff }, + { 0x0a0003ec, 0x24000001 }, + { 0x0a0003ed, 0x1400ffff }, + { 0x0a0003ee, 0x24000001 }, + { 0x0a0003ef, 0x1400ffff }, + { 0x130003f0, 0x1400ffaa }, + { 0x130003f1, 0x1400ffb0 }, + { 0x130003f2, 0x14000007 }, + { 0x130003f3, 0x14000000 }, + { 0x130003f4, 0x2400ffc4 }, + { 0x130003f5, 0x1400ffa0 }, + { 0x130003f6, 0x64000000 }, + { 0x130003f7, 0x24000001 }, + { 0x130003f8, 0x1400ffff }, + { 0x130003f9, 0x2400fff9 }, + { 0x130003fa, 0x24000001 }, + { 0x130003fb, 0x1400ffff }, + { 0x130003fc, 0x14000000 }, + { 0x138003fd, 0x24000002 }, + { 0x0c000400, 0x24000050 }, + { 0x0c000401, 0x24000050 }, + { 0x0c000402, 0x24000050 }, + { 0x0c000403, 0x24000050 }, + { 0x0c000404, 0x24000050 }, + { 0x0c000405, 0x24000050 }, + { 0x0c000406, 0x24000050 }, + { 0x0c000407, 0x24000050 }, + { 0x0c000408, 0x24000050 }, + { 0x0c000409, 0x24000050 }, + { 0x0c00040a, 0x24000050 }, + { 0x0c00040b, 0x24000050 }, + { 0x0c00040c, 0x24000050 }, + { 0x0c00040d, 0x24000050 }, + { 0x0c00040e, 0x24000050 }, + { 0x0c00040f, 0x24000050 }, + { 0x0c000410, 0x24000020 }, + { 0x0c000411, 0x24000020 }, + { 0x0c000412, 0x24000020 }, + { 0x0c000413, 0x24000020 }, + { 0x0c000414, 0x24000020 }, + { 0x0c000415, 0x24000020 }, + { 0x0c000416, 0x24000020 }, + { 0x0c000417, 0x24000020 }, + { 0x0c000418, 0x24000020 }, + { 0x0c000419, 0x24000020 }, + { 0x0c00041a, 0x24000020 }, + { 0x0c00041b, 0x24000020 }, + { 0x0c00041c, 0x24000020 }, + { 0x0c00041d, 0x24000020 }, + { 0x0c00041e, 0x24000020 }, + { 0x0c00041f, 0x24000020 }, + { 0x0c000420, 0x24000020 }, + { 0x0c000421, 0x24000020 }, + { 0x0c000422, 0x24000020 }, + { 0x0c000423, 0x24000020 }, + { 0x0c000424, 0x24000020 }, + { 0x0c000425, 0x24000020 }, + { 0x0c000426, 0x24000020 }, + { 0x0c000427, 0x24000020 }, + { 0x0c000428, 0x24000020 }, + { 0x0c000429, 0x24000020 }, + { 0x0c00042a, 0x24000020 }, + { 0x0c00042b, 0x24000020 }, + { 0x0c00042c, 0x24000020 }, + { 0x0c00042d, 0x24000020 }, + { 0x0c00042e, 0x24000020 }, + { 0x0c00042f, 0x24000020 }, + { 0x0c000430, 0x1400ffe0 }, + { 0x0c000431, 0x1400ffe0 }, + { 0x0c000432, 0x1400ffe0 }, + { 0x0c000433, 0x1400ffe0 }, + { 0x0c000434, 0x1400ffe0 }, + { 0x0c000435, 0x1400ffe0 }, + { 0x0c000436, 0x1400ffe0 }, + { 0x0c000437, 0x1400ffe0 }, + { 0x0c000438, 0x1400ffe0 }, + { 0x0c000439, 0x1400ffe0 }, + { 0x0c00043a, 0x1400ffe0 }, + { 0x0c00043b, 0x1400ffe0 }, + { 0x0c00043c, 0x1400ffe0 }, + { 0x0c00043d, 0x1400ffe0 }, + { 0x0c00043e, 0x1400ffe0 }, + { 0x0c00043f, 0x1400ffe0 }, + { 0x0c000440, 0x1400ffe0 }, + { 0x0c000441, 0x1400ffe0 }, + { 0x0c000442, 0x1400ffe0 }, + { 0x0c000443, 0x1400ffe0 }, + { 0x0c000444, 0x1400ffe0 }, + { 0x0c000445, 0x1400ffe0 }, + { 0x0c000446, 0x1400ffe0 }, + { 0x0c000447, 0x1400ffe0 }, + { 0x0c000448, 0x1400ffe0 }, + { 0x0c000449, 0x1400ffe0 }, + { 0x0c00044a, 0x1400ffe0 }, + { 0x0c00044b, 0x1400ffe0 }, + { 0x0c00044c, 0x1400ffe0 }, + { 0x0c00044d, 0x1400ffe0 }, + { 0x0c00044e, 0x1400ffe0 }, + { 0x0c00044f, 0x1400ffe0 }, + { 0x0c000450, 0x1400ffb0 }, + { 0x0c000451, 0x1400ffb0 }, + { 0x0c000452, 0x1400ffb0 }, + { 0x0c000453, 0x1400ffb0 }, + { 0x0c000454, 0x1400ffb0 }, + { 0x0c000455, 0x1400ffb0 }, + { 0x0c000456, 0x1400ffb0 }, + { 0x0c000457, 0x1400ffb0 }, + { 0x0c000458, 0x1400ffb0 }, + { 0x0c000459, 0x1400ffb0 }, + { 0x0c00045a, 0x1400ffb0 }, + { 0x0c00045b, 0x1400ffb0 }, + { 0x0c00045c, 0x1400ffb0 }, + { 0x0c00045d, 0x1400ffb0 }, + { 0x0c00045e, 0x1400ffb0 }, + { 0x0c00045f, 0x1400ffb0 }, + { 0x0c000460, 0x24000001 }, + { 0x0c000461, 0x1400ffff }, + { 0x0c000462, 0x24000001 }, + { 0x0c000463, 0x1400ffff }, + { 0x0c000464, 0x24000001 }, + { 0x0c000465, 0x1400ffff }, + { 0x0c000466, 0x24000001 }, + { 0x0c000467, 0x1400ffff }, + { 0x0c000468, 0x24000001 }, + { 0x0c000469, 0x1400ffff }, + { 0x0c00046a, 0x24000001 }, + { 0x0c00046b, 0x1400ffff }, + { 0x0c00046c, 0x24000001 }, + { 0x0c00046d, 0x1400ffff }, + { 0x0c00046e, 0x24000001 }, + { 0x0c00046f, 0x1400ffff }, + { 0x0c000470, 0x24000001 }, + { 0x0c000471, 0x1400ffff }, + { 0x0c000472, 0x24000001 }, + { 0x0c000473, 0x1400ffff }, + { 0x0c000474, 0x24000001 }, + { 0x0c000475, 0x1400ffff }, + { 0x0c000476, 0x24000001 }, + { 0x0c000477, 0x1400ffff }, + { 0x0c000478, 0x24000001 }, + { 0x0c000479, 0x1400ffff }, + { 0x0c00047a, 0x24000001 }, + { 0x0c00047b, 0x1400ffff }, + { 0x0c00047c, 0x24000001 }, + { 0x0c00047d, 0x1400ffff }, + { 0x0c00047e, 0x24000001 }, + { 0x0c00047f, 0x1400ffff }, + { 0x0c000480, 0x24000001 }, + { 0x0c000481, 0x1400ffff }, + { 0x0c000482, 0x68000000 }, + { 0x0c800483, 0x30000003 }, + { 0x0c800488, 0x2c000001 }, + { 0x0c00048a, 0x24000001 }, + { 0x0c00048b, 0x1400ffff }, + { 0x0c00048c, 0x24000001 }, + { 0x0c00048d, 0x1400ffff }, + { 0x0c00048e, 0x24000001 }, + { 0x0c00048f, 0x1400ffff }, + { 0x0c000490, 0x24000001 }, + { 0x0c000491, 0x1400ffff }, + { 0x0c000492, 0x24000001 }, + { 0x0c000493, 0x1400ffff }, + { 0x0c000494, 0x24000001 }, + { 0x0c000495, 0x1400ffff }, + { 0x0c000496, 0x24000001 }, + { 0x0c000497, 0x1400ffff }, + { 0x0c000498, 0x24000001 }, + { 0x0c000499, 0x1400ffff }, + { 0x0c00049a, 0x24000001 }, + { 0x0c00049b, 0x1400ffff }, + { 0x0c00049c, 0x24000001 }, + { 0x0c00049d, 0x1400ffff }, + { 0x0c00049e, 0x24000001 }, + { 0x0c00049f, 0x1400ffff }, + { 0x0c0004a0, 0x24000001 }, + { 0x0c0004a1, 0x1400ffff }, + { 0x0c0004a2, 0x24000001 }, + { 0x0c0004a3, 0x1400ffff }, + { 0x0c0004a4, 0x24000001 }, + { 0x0c0004a5, 0x1400ffff }, + { 0x0c0004a6, 0x24000001 }, + { 0x0c0004a7, 0x1400ffff }, + { 0x0c0004a8, 0x24000001 }, + { 0x0c0004a9, 0x1400ffff }, + { 0x0c0004aa, 0x24000001 }, + { 0x0c0004ab, 0x1400ffff }, + { 0x0c0004ac, 0x24000001 }, + { 0x0c0004ad, 0x1400ffff }, + { 0x0c0004ae, 0x24000001 }, + { 0x0c0004af, 0x1400ffff }, + { 0x0c0004b0, 0x24000001 }, + { 0x0c0004b1, 0x1400ffff }, + { 0x0c0004b2, 0x24000001 }, + { 0x0c0004b3, 0x1400ffff }, + { 0x0c0004b4, 0x24000001 }, + { 0x0c0004b5, 0x1400ffff }, + { 0x0c0004b6, 0x24000001 }, + { 0x0c0004b7, 0x1400ffff }, + { 0x0c0004b8, 0x24000001 }, + { 0x0c0004b9, 0x1400ffff }, + { 0x0c0004ba, 0x24000001 }, + { 0x0c0004bb, 0x1400ffff }, + { 0x0c0004bc, 0x24000001 }, + { 0x0c0004bd, 0x1400ffff }, + { 0x0c0004be, 0x24000001 }, + { 0x0c0004bf, 0x1400ffff }, + { 0x0c0004c0, 0x24000000 }, + { 0x0c0004c1, 0x24000001 }, + { 0x0c0004c2, 0x1400ffff }, + { 0x0c0004c3, 0x24000001 }, + { 0x0c0004c4, 0x1400ffff }, + { 0x0c0004c5, 0x24000001 }, + { 0x0c0004c6, 0x1400ffff }, + { 0x0c0004c7, 0x24000001 }, + { 0x0c0004c8, 0x1400ffff }, + { 0x0c0004c9, 0x24000001 }, + { 0x0c0004ca, 0x1400ffff }, + { 0x0c0004cb, 0x24000001 }, + { 0x0c0004cc, 0x1400ffff }, + { 0x0c0004cd, 0x24000001 }, + { 0x0c0004ce, 0x1400ffff }, + { 0x0c0004d0, 0x24000001 }, + { 0x0c0004d1, 0x1400ffff }, + { 0x0c0004d2, 0x24000001 }, + { 0x0c0004d3, 0x1400ffff }, + { 0x0c0004d4, 0x24000001 }, + { 0x0c0004d5, 0x1400ffff }, + { 0x0c0004d6, 0x24000001 }, + { 0x0c0004d7, 0x1400ffff }, + { 0x0c0004d8, 0x24000001 }, + { 0x0c0004d9, 0x1400ffff }, + { 0x0c0004da, 0x24000001 }, + { 0x0c0004db, 0x1400ffff }, + { 0x0c0004dc, 0x24000001 }, + { 0x0c0004dd, 0x1400ffff }, + { 0x0c0004de, 0x24000001 }, + { 0x0c0004df, 0x1400ffff }, + { 0x0c0004e0, 0x24000001 }, + { 0x0c0004e1, 0x1400ffff }, + { 0x0c0004e2, 0x24000001 }, + { 0x0c0004e3, 0x1400ffff }, + { 0x0c0004e4, 0x24000001 }, + { 0x0c0004e5, 0x1400ffff }, + { 0x0c0004e6, 0x24000001 }, + { 0x0c0004e7, 0x1400ffff }, + { 0x0c0004e8, 0x24000001 }, + { 0x0c0004e9, 0x1400ffff }, + { 0x0c0004ea, 0x24000001 }, + { 0x0c0004eb, 0x1400ffff }, + { 0x0c0004ec, 0x24000001 }, + { 0x0c0004ed, 0x1400ffff }, + { 0x0c0004ee, 0x24000001 }, + { 0x0c0004ef, 0x1400ffff }, + { 0x0c0004f0, 0x24000001 }, + { 0x0c0004f1, 0x1400ffff }, + { 0x0c0004f2, 0x24000001 }, + { 0x0c0004f3, 0x1400ffff }, + { 0x0c0004f4, 0x24000001 }, + { 0x0c0004f5, 0x1400ffff }, + { 0x0c0004f6, 0x24000001 }, + { 0x0c0004f7, 0x1400ffff }, + { 0x0c0004f8, 0x24000001 }, + { 0x0c0004f9, 0x1400ffff }, + { 0x0c000500, 0x24000001 }, + { 0x0c000501, 0x1400ffff }, + { 0x0c000502, 0x24000001 }, + { 0x0c000503, 0x1400ffff }, + { 0x0c000504, 0x24000001 }, + { 0x0c000505, 0x1400ffff }, + { 0x0c000506, 0x24000001 }, + { 0x0c000507, 0x1400ffff }, + { 0x0c000508, 0x24000001 }, + { 0x0c000509, 0x1400ffff }, + { 0x0c00050a, 0x24000001 }, + { 0x0c00050b, 0x1400ffff }, + { 0x0c00050c, 0x24000001 }, + { 0x0c00050d, 0x1400ffff }, + { 0x0c00050e, 0x24000001 }, + { 0x0c00050f, 0x1400ffff }, + { 0x01000531, 0x24000030 }, + { 0x01000532, 0x24000030 }, + { 0x01000533, 0x24000030 }, + { 0x01000534, 0x24000030 }, + { 0x01000535, 0x24000030 }, + { 0x01000536, 0x24000030 }, + { 0x01000537, 0x24000030 }, + { 0x01000538, 0x24000030 }, + { 0x01000539, 0x24000030 }, + { 0x0100053a, 0x24000030 }, + { 0x0100053b, 0x24000030 }, + { 0x0100053c, 0x24000030 }, + { 0x0100053d, 0x24000030 }, + { 0x0100053e, 0x24000030 }, + { 0x0100053f, 0x24000030 }, + { 0x01000540, 0x24000030 }, + { 0x01000541, 0x24000030 }, + { 0x01000542, 0x24000030 }, + { 0x01000543, 0x24000030 }, + { 0x01000544, 0x24000030 }, + { 0x01000545, 0x24000030 }, + { 0x01000546, 0x24000030 }, + { 0x01000547, 0x24000030 }, + { 0x01000548, 0x24000030 }, + { 0x01000549, 0x24000030 }, + { 0x0100054a, 0x24000030 }, + { 0x0100054b, 0x24000030 }, + { 0x0100054c, 0x24000030 }, + { 0x0100054d, 0x24000030 }, + { 0x0100054e, 0x24000030 }, + { 0x0100054f, 0x24000030 }, + { 0x01000550, 0x24000030 }, + { 0x01000551, 0x24000030 }, + { 0x01000552, 0x24000030 }, + { 0x01000553, 0x24000030 }, + { 0x01000554, 0x24000030 }, + { 0x01000555, 0x24000030 }, + { 0x01000556, 0x24000030 }, + { 0x01000559, 0x18000000 }, + { 0x0180055a, 0x54000005 }, + { 0x01000561, 0x1400ffd0 }, + { 0x01000562, 0x1400ffd0 }, + { 0x01000563, 0x1400ffd0 }, + { 0x01000564, 0x1400ffd0 }, + { 0x01000565, 0x1400ffd0 }, + { 0x01000566, 0x1400ffd0 }, + { 0x01000567, 0x1400ffd0 }, + { 0x01000568, 0x1400ffd0 }, + { 0x01000569, 0x1400ffd0 }, + { 0x0100056a, 0x1400ffd0 }, + { 0x0100056b, 0x1400ffd0 }, + { 0x0100056c, 0x1400ffd0 }, + { 0x0100056d, 0x1400ffd0 }, + { 0x0100056e, 0x1400ffd0 }, + { 0x0100056f, 0x1400ffd0 }, + { 0x01000570, 0x1400ffd0 }, + { 0x01000571, 0x1400ffd0 }, + { 0x01000572, 0x1400ffd0 }, + { 0x01000573, 0x1400ffd0 }, + { 0x01000574, 0x1400ffd0 }, + { 0x01000575, 0x1400ffd0 }, + { 0x01000576, 0x1400ffd0 }, + { 0x01000577, 0x1400ffd0 }, + { 0x01000578, 0x1400ffd0 }, + { 0x01000579, 0x1400ffd0 }, + { 0x0100057a, 0x1400ffd0 }, + { 0x0100057b, 0x1400ffd0 }, + { 0x0100057c, 0x1400ffd0 }, + { 0x0100057d, 0x1400ffd0 }, + { 0x0100057e, 0x1400ffd0 }, + { 0x0100057f, 0x1400ffd0 }, + { 0x01000580, 0x1400ffd0 }, + { 0x01000581, 0x1400ffd0 }, + { 0x01000582, 0x1400ffd0 }, + { 0x01000583, 0x1400ffd0 }, + { 0x01000584, 0x1400ffd0 }, + { 0x01000585, 0x1400ffd0 }, + { 0x01000586, 0x1400ffd0 }, + { 0x01000587, 0x14000000 }, + { 0x09000589, 0x54000000 }, + { 0x0100058a, 0x44000000 }, + { 0x19800591, 0x30000028 }, + { 0x198005bb, 0x30000002 }, + { 0x190005be, 0x54000000 }, + { 0x190005bf, 0x30000000 }, + { 0x190005c0, 0x54000000 }, + { 0x198005c1, 0x30000001 }, + { 0x190005c3, 0x54000000 }, + { 0x198005c4, 0x30000001 }, + { 0x190005c6, 0x54000000 }, + { 0x190005c7, 0x30000000 }, + { 0x198005d0, 0x1c00001a }, + { 0x198005f0, 0x1c000002 }, + { 0x198005f3, 0x54000001 }, + { 0x09800600, 0x04000003 }, + { 0x0000060b, 0x5c000000 }, + { 0x0980060c, 0x54000001 }, + { 0x0080060e, 0x68000001 }, + { 0x00800610, 0x30000005 }, + { 0x0900061b, 0x54000000 }, + { 0x0080061e, 0x54000001 }, + { 0x00800621, 0x1c000019 }, + { 0x09000640, 0x18000000 }, + { 0x00800641, 0x1c000009 }, + { 0x1b80064b, 0x30000013 }, + { 0x09800660, 0x34000009 }, + { 0x0080066a, 0x54000003 }, + { 0x0080066e, 0x1c000001 }, + { 0x1b000670, 0x30000000 }, + { 0x00800671, 0x1c000062 }, + { 0x000006d4, 0x54000000 }, + { 0x000006d5, 0x1c000000 }, + { 0x008006d6, 0x30000006 }, + { 0x090006dd, 0x04000000 }, + { 0x000006de, 0x2c000000 }, + { 0x008006df, 0x30000005 }, + { 0x008006e5, 0x18000001 }, + { 0x008006e7, 0x30000001 }, + { 0x000006e9, 0x68000000 }, + { 0x008006ea, 0x30000003 }, + { 0x008006ee, 0x1c000001 }, + { 0x008006f0, 0x34000009 }, + { 0x008006fa, 0x1c000002 }, + { 0x008006fd, 0x68000001 }, + { 0x000006ff, 0x1c000000 }, + { 0x31800700, 0x5400000d }, + { 0x3100070f, 0x04000000 }, + { 0x31000710, 0x1c000000 }, + { 0x31000711, 0x30000000 }, + { 0x31800712, 0x1c00001d }, + { 0x31800730, 0x3000001a }, + { 0x3180074d, 0x1c000020 }, + { 0x37800780, 0x1c000025 }, + { 0x378007a6, 0x3000000a }, + { 0x370007b1, 0x1c000000 }, + { 0x0e800901, 0x30000001 }, + { 0x0e000903, 0x28000000 }, + { 0x0e800904, 0x1c000035 }, + { 0x0e00093c, 0x30000000 }, + { 0x0e00093d, 0x1c000000 }, + { 0x0e80093e, 0x28000002 }, + { 0x0e800941, 0x30000007 }, + { 0x0e800949, 0x28000003 }, + { 0x0e00094d, 0x30000000 }, + { 0x0e000950, 0x1c000000 }, + { 0x0e800951, 0x30000003 }, + { 0x0e800958, 0x1c000009 }, + { 0x0e800962, 0x30000001 }, + { 0x09800964, 0x54000001 }, + { 0x0e800966, 0x34000009 }, + { 0x09000970, 0x54000000 }, + { 0x0e00097d, 0x1c000000 }, + { 0x02000981, 0x30000000 }, + { 0x02800982, 0x28000001 }, + { 0x02800985, 0x1c000007 }, + { 0x0280098f, 0x1c000001 }, + { 0x02800993, 0x1c000015 }, + { 0x028009aa, 0x1c000006 }, + { 0x020009b2, 0x1c000000 }, + { 0x028009b6, 0x1c000003 }, + { 0x020009bc, 0x30000000 }, + { 0x020009bd, 0x1c000000 }, + { 0x028009be, 0x28000002 }, + { 0x028009c1, 0x30000003 }, + { 0x028009c7, 0x28000001 }, + { 0x028009cb, 0x28000001 }, + { 0x020009cd, 0x30000000 }, + { 0x020009ce, 0x1c000000 }, + { 0x020009d7, 0x28000000 }, + { 0x028009dc, 0x1c000001 }, + { 0x028009df, 0x1c000002 }, + { 0x028009e2, 0x30000001 }, + { 0x028009e6, 0x34000009 }, + { 0x028009f0, 0x1c000001 }, + { 0x028009f2, 0x5c000001 }, + { 0x028009f4, 0x3c000005 }, + { 0x020009fa, 0x68000000 }, + { 0x15800a01, 0x30000001 }, + { 0x15000a03, 0x28000000 }, + { 0x15800a05, 0x1c000005 }, + { 0x15800a0f, 0x1c000001 }, + { 0x15800a13, 0x1c000015 }, + { 0x15800a2a, 0x1c000006 }, + { 0x15800a32, 0x1c000001 }, + { 0x15800a35, 0x1c000001 }, + { 0x15800a38, 0x1c000001 }, + { 0x15000a3c, 0x30000000 }, + { 0x15800a3e, 0x28000002 }, + { 0x15800a41, 0x30000001 }, + { 0x15800a47, 0x30000001 }, + { 0x15800a4b, 0x30000002 }, + { 0x15800a59, 0x1c000003 }, + { 0x15000a5e, 0x1c000000 }, + { 0x15800a66, 0x34000009 }, + { 0x15800a70, 0x30000001 }, + { 0x15800a72, 0x1c000002 }, + { 0x14800a81, 0x30000001 }, + { 0x14000a83, 0x28000000 }, + { 0x14800a85, 0x1c000008 }, + { 0x14800a8f, 0x1c000002 }, + { 0x14800a93, 0x1c000015 }, + { 0x14800aaa, 0x1c000006 }, + { 0x14800ab2, 0x1c000001 }, + { 0x14800ab5, 0x1c000004 }, + { 0x14000abc, 0x30000000 }, + { 0x14000abd, 0x1c000000 }, + { 0x14800abe, 0x28000002 }, + { 0x14800ac1, 0x30000004 }, + { 0x14800ac7, 0x30000001 }, + { 0x14000ac9, 0x28000000 }, + { 0x14800acb, 0x28000001 }, + { 0x14000acd, 0x30000000 }, + { 0x14000ad0, 0x1c000000 }, + { 0x14800ae0, 0x1c000001 }, + { 0x14800ae2, 0x30000001 }, + { 0x14800ae6, 0x34000009 }, + { 0x14000af1, 0x5c000000 }, + { 0x2b000b01, 0x30000000 }, + { 0x2b800b02, 0x28000001 }, + { 0x2b800b05, 0x1c000007 }, + { 0x2b800b0f, 0x1c000001 }, + { 0x2b800b13, 0x1c000015 }, + { 0x2b800b2a, 0x1c000006 }, + { 0x2b800b32, 0x1c000001 }, + { 0x2b800b35, 0x1c000004 }, + { 0x2b000b3c, 0x30000000 }, + { 0x2b000b3d, 0x1c000000 }, + { 0x2b000b3e, 0x28000000 }, + { 0x2b000b3f, 0x30000000 }, + { 0x2b000b40, 0x28000000 }, + { 0x2b800b41, 0x30000002 }, + { 0x2b800b47, 0x28000001 }, + { 0x2b800b4b, 0x28000001 }, + { 0x2b000b4d, 0x30000000 }, + { 0x2b000b56, 0x30000000 }, + { 0x2b000b57, 0x28000000 }, + { 0x2b800b5c, 0x1c000001 }, + { 0x2b800b5f, 0x1c000002 }, + { 0x2b800b66, 0x34000009 }, + { 0x2b000b70, 0x68000000 }, + { 0x2b000b71, 0x1c000000 }, + { 0x35000b82, 0x30000000 }, + { 0x35000b83, 0x1c000000 }, + { 0x35800b85, 0x1c000005 }, + { 0x35800b8e, 0x1c000002 }, + { 0x35800b92, 0x1c000003 }, + { 0x35800b99, 0x1c000001 }, + { 0x35000b9c, 0x1c000000 }, + { 0x35800b9e, 0x1c000001 }, + { 0x35800ba3, 0x1c000001 }, + { 0x35800ba8, 0x1c000002 }, + { 0x35800bae, 0x1c00000b }, + { 0x35800bbe, 0x28000001 }, + { 0x35000bc0, 0x30000000 }, + { 0x35800bc1, 0x28000001 }, + { 0x35800bc6, 0x28000002 }, + { 0x35800bca, 0x28000002 }, + { 0x35000bcd, 0x30000000 }, + { 0x35000bd7, 0x28000000 }, + { 0x35800be6, 0x34000009 }, + { 0x35800bf0, 0x3c000002 }, + { 0x35800bf3, 0x68000005 }, + { 0x35000bf9, 0x5c000000 }, + { 0x35000bfa, 0x68000000 }, + { 0x36800c01, 0x28000002 }, + { 0x36800c05, 0x1c000007 }, + { 0x36800c0e, 0x1c000002 }, + { 0x36800c12, 0x1c000016 }, + { 0x36800c2a, 0x1c000009 }, + { 0x36800c35, 0x1c000004 }, + { 0x36800c3e, 0x30000002 }, + { 0x36800c41, 0x28000003 }, + { 0x36800c46, 0x30000002 }, + { 0x36800c4a, 0x30000003 }, + { 0x36800c55, 0x30000001 }, + { 0x36800c60, 0x1c000001 }, + { 0x36800c66, 0x34000009 }, + { 0x1c800c82, 0x28000001 }, + { 0x1c800c85, 0x1c000007 }, + { 0x1c800c8e, 0x1c000002 }, + { 0x1c800c92, 0x1c000016 }, + { 0x1c800caa, 0x1c000009 }, + { 0x1c800cb5, 0x1c000004 }, + { 0x1c000cbc, 0x30000000 }, + { 0x1c000cbd, 0x1c000000 }, + { 0x1c000cbe, 0x28000000 }, + { 0x1c000cbf, 0x30000000 }, + { 0x1c800cc0, 0x28000004 }, + { 0x1c000cc6, 0x30000000 }, + { 0x1c800cc7, 0x28000001 }, + { 0x1c800cca, 0x28000001 }, + { 0x1c800ccc, 0x30000001 }, + { 0x1c800cd5, 0x28000001 }, + { 0x1c000cde, 0x1c000000 }, + { 0x1c800ce0, 0x1c000001 }, + { 0x1c800ce6, 0x34000009 }, + { 0x24800d02, 0x28000001 }, + { 0x24800d05, 0x1c000007 }, + { 0x24800d0e, 0x1c000002 }, + { 0x24800d12, 0x1c000016 }, + { 0x24800d2a, 0x1c00000f }, + { 0x24800d3e, 0x28000002 }, + { 0x24800d41, 0x30000002 }, + { 0x24800d46, 0x28000002 }, + { 0x24800d4a, 0x28000002 }, + { 0x24000d4d, 0x30000000 }, + { 0x24000d57, 0x28000000 }, + { 0x24800d60, 0x1c000001 }, + { 0x24800d66, 0x34000009 }, + { 0x2f800d82, 0x28000001 }, + { 0x2f800d85, 0x1c000011 }, + { 0x2f800d9a, 0x1c000017 }, + { 0x2f800db3, 0x1c000008 }, + { 0x2f000dbd, 0x1c000000 }, + { 0x2f800dc0, 0x1c000006 }, + { 0x2f000dca, 0x30000000 }, + { 0x2f800dcf, 0x28000002 }, + { 0x2f800dd2, 0x30000002 }, + { 0x2f000dd6, 0x30000000 }, + { 0x2f800dd8, 0x28000007 }, + { 0x2f800df2, 0x28000001 }, + { 0x2f000df4, 0x54000000 }, + { 0x38800e01, 0x1c00002f }, + { 0x38000e31, 0x30000000 }, + { 0x38800e32, 0x1c000001 }, + { 0x38800e34, 0x30000006 }, + { 0x09000e3f, 0x5c000000 }, + { 0x38800e40, 0x1c000005 }, + { 0x38000e46, 0x18000000 }, + { 0x38800e47, 0x30000007 }, + { 0x38000e4f, 0x54000000 }, + { 0x38800e50, 0x34000009 }, + { 0x38800e5a, 0x54000001 }, + { 0x20800e81, 0x1c000001 }, + { 0x20000e84, 0x1c000000 }, + { 0x20800e87, 0x1c000001 }, + { 0x20000e8a, 0x1c000000 }, + { 0x20000e8d, 0x1c000000 }, + { 0x20800e94, 0x1c000003 }, + { 0x20800e99, 0x1c000006 }, + { 0x20800ea1, 0x1c000002 }, + { 0x20000ea5, 0x1c000000 }, + { 0x20000ea7, 0x1c000000 }, + { 0x20800eaa, 0x1c000001 }, + { 0x20800ead, 0x1c000003 }, + { 0x20000eb1, 0x30000000 }, + { 0x20800eb2, 0x1c000001 }, + { 0x20800eb4, 0x30000005 }, + { 0x20800ebb, 0x30000001 }, + { 0x20000ebd, 0x1c000000 }, + { 0x20800ec0, 0x1c000004 }, + { 0x20000ec6, 0x18000000 }, + { 0x20800ec8, 0x30000005 }, + { 0x20800ed0, 0x34000009 }, + { 0x20800edc, 0x1c000001 }, + { 0x39000f00, 0x1c000000 }, + { 0x39800f01, 0x68000002 }, + { 0x39800f04, 0x5400000e }, + { 0x39800f13, 0x68000004 }, + { 0x39800f18, 0x30000001 }, + { 0x39800f1a, 0x68000005 }, + { 0x39800f20, 0x34000009 }, + { 0x39800f2a, 0x3c000009 }, + { 0x39000f34, 0x68000000 }, + { 0x39000f35, 0x30000000 }, + { 0x39000f36, 0x68000000 }, + { 0x39000f37, 0x30000000 }, + { 0x39000f38, 0x68000000 }, + { 0x39000f39, 0x30000000 }, + { 0x39000f3a, 0x58000000 }, + { 0x39000f3b, 0x48000000 }, + { 0x39000f3c, 0x58000000 }, + { 0x39000f3d, 0x48000000 }, + { 0x39800f3e, 0x28000001 }, + { 0x39800f40, 0x1c000007 }, + { 0x39800f49, 0x1c000021 }, + { 0x39800f71, 0x3000000d }, + { 0x39000f7f, 0x28000000 }, + { 0x39800f80, 0x30000004 }, + { 0x39000f85, 0x54000000 }, + { 0x39800f86, 0x30000001 }, + { 0x39800f88, 0x1c000003 }, + { 0x39800f90, 0x30000007 }, + { 0x39800f99, 0x30000023 }, + { 0x39800fbe, 0x68000007 }, + { 0x39000fc6, 0x30000000 }, + { 0x39800fc7, 0x68000005 }, + { 0x39000fcf, 0x68000000 }, + { 0x39800fd0, 0x54000001 }, + { 0x26801000, 0x1c000021 }, + { 0x26801023, 0x1c000004 }, + { 0x26801029, 0x1c000001 }, + { 0x2600102c, 0x28000000 }, + { 0x2680102d, 0x30000003 }, + { 0x26001031, 0x28000000 }, + { 0x26001032, 0x30000000 }, + { 0x26801036, 0x30000001 }, + { 0x26001038, 0x28000000 }, + { 0x26001039, 0x30000000 }, + { 0x26801040, 0x34000009 }, + { 0x2680104a, 0x54000005 }, + { 0x26801050, 0x1c000005 }, + { 0x26801056, 0x28000001 }, + { 0x26801058, 0x30000001 }, + { 0x100010a0, 0x24001c60 }, + { 0x100010a1, 0x24001c60 }, + { 0x100010a2, 0x24001c60 }, + { 0x100010a3, 0x24001c60 }, + { 0x100010a4, 0x24001c60 }, + { 0x100010a5, 0x24001c60 }, + { 0x100010a6, 0x24001c60 }, + { 0x100010a7, 0x24001c60 }, + { 0x100010a8, 0x24001c60 }, + { 0x100010a9, 0x24001c60 }, + { 0x100010aa, 0x24001c60 }, + { 0x100010ab, 0x24001c60 }, + { 0x100010ac, 0x24001c60 }, + { 0x100010ad, 0x24001c60 }, + { 0x100010ae, 0x24001c60 }, + { 0x100010af, 0x24001c60 }, + { 0x100010b0, 0x24001c60 }, + { 0x100010b1, 0x24001c60 }, + { 0x100010b2, 0x24001c60 }, + { 0x100010b3, 0x24001c60 }, + { 0x100010b4, 0x24001c60 }, + { 0x100010b5, 0x24001c60 }, + { 0x100010b6, 0x24001c60 }, + { 0x100010b7, 0x24001c60 }, + { 0x100010b8, 0x24001c60 }, + { 0x100010b9, 0x24001c60 }, + { 0x100010ba, 0x24001c60 }, + { 0x100010bb, 0x24001c60 }, + { 0x100010bc, 0x24001c60 }, + { 0x100010bd, 0x24001c60 }, + { 0x100010be, 0x24001c60 }, + { 0x100010bf, 0x24001c60 }, + { 0x100010c0, 0x24001c60 }, + { 0x100010c1, 0x24001c60 }, + { 0x100010c2, 0x24001c60 }, + { 0x100010c3, 0x24001c60 }, + { 0x100010c4, 0x24001c60 }, + { 0x100010c5, 0x24001c60 }, + { 0x108010d0, 0x1c00002a }, + { 0x090010fb, 0x54000000 }, + { 0x100010fc, 0x18000000 }, + { 0x17801100, 0x1c000059 }, + { 0x1780115f, 0x1c000043 }, + { 0x178011a8, 0x1c000051 }, + { 0x0f801200, 0x1c000048 }, + { 0x0f80124a, 0x1c000003 }, + { 0x0f801250, 0x1c000006 }, + { 0x0f001258, 0x1c000000 }, + { 0x0f80125a, 0x1c000003 }, + { 0x0f801260, 0x1c000028 }, + { 0x0f80128a, 0x1c000003 }, + { 0x0f801290, 0x1c000020 }, + { 0x0f8012b2, 0x1c000003 }, + { 0x0f8012b8, 0x1c000006 }, + { 0x0f0012c0, 0x1c000000 }, + { 0x0f8012c2, 0x1c000003 }, + { 0x0f8012c8, 0x1c00000e }, + { 0x0f8012d8, 0x1c000038 }, + { 0x0f801312, 0x1c000003 }, + { 0x0f801318, 0x1c000042 }, + { 0x0f00135f, 0x30000000 }, + { 0x0f001360, 0x68000000 }, + { 0x0f801361, 0x54000007 }, + { 0x0f801369, 0x3c000013 }, + { 0x0f801380, 0x1c00000f }, + { 0x0f801390, 0x68000009 }, + { 0x088013a0, 0x1c000054 }, + { 0x07801401, 0x1c00026b }, + { 0x0780166d, 0x54000001 }, + { 0x0780166f, 0x1c000007 }, + { 0x28001680, 0x74000000 }, + { 0x28801681, 0x1c000019 }, + { 0x2800169b, 0x58000000 }, + { 0x2800169c, 0x48000000 }, + { 0x2d8016a0, 0x1c00004a }, + { 0x098016eb, 0x54000002 }, + { 0x2d8016ee, 0x38000002 }, + { 0x32801700, 0x1c00000c }, + { 0x3280170e, 0x1c000003 }, + { 0x32801712, 0x30000002 }, + { 0x18801720, 0x1c000011 }, + { 0x18801732, 0x30000002 }, + { 0x09801735, 0x54000001 }, + { 0x06801740, 0x1c000011 }, + { 0x06801752, 0x30000001 }, + { 0x33801760, 0x1c00000c }, + { 0x3380176e, 0x1c000002 }, + { 0x33801772, 0x30000001 }, + { 0x1f801780, 0x1c000033 }, + { 0x1f8017b4, 0x04000001 }, + { 0x1f0017b6, 0x28000000 }, + { 0x1f8017b7, 0x30000006 }, + { 0x1f8017be, 0x28000007 }, + { 0x1f0017c6, 0x30000000 }, + { 0x1f8017c7, 0x28000001 }, + { 0x1f8017c9, 0x3000000a }, + { 0x1f8017d4, 0x54000002 }, + { 0x1f0017d7, 0x18000000 }, + { 0x1f8017d8, 0x54000002 }, + { 0x1f0017db, 0x5c000000 }, + { 0x1f0017dc, 0x1c000000 }, + { 0x1f0017dd, 0x30000000 }, + { 0x1f8017e0, 0x34000009 }, + { 0x1f8017f0, 0x3c000009 }, + { 0x25801800, 0x54000005 }, + { 0x25001806, 0x44000000 }, + { 0x25801807, 0x54000003 }, + { 0x2580180b, 0x30000002 }, + { 0x2500180e, 0x74000000 }, + { 0x25801810, 0x34000009 }, + { 0x25801820, 0x1c000022 }, + { 0x25001843, 0x18000000 }, + { 0x25801844, 0x1c000033 }, + { 0x25801880, 0x1c000028 }, + { 0x250018a9, 0x30000000 }, + { 0x22801900, 0x1c00001c }, + { 0x22801920, 0x30000002 }, + { 0x22801923, 0x28000003 }, + { 0x22801927, 0x30000001 }, + { 0x22801929, 0x28000002 }, + { 0x22801930, 0x28000001 }, + { 0x22001932, 0x30000000 }, + { 0x22801933, 0x28000005 }, + { 0x22801939, 0x30000002 }, + { 0x22001940, 0x68000000 }, + { 0x22801944, 0x54000001 }, + { 0x22801946, 0x34000009 }, + { 0x34801950, 0x1c00001d }, + { 0x34801970, 0x1c000004 }, + { 0x27801980, 0x1c000029 }, + { 0x278019b0, 0x28000010 }, + { 0x278019c1, 0x1c000006 }, + { 0x278019c8, 0x28000001 }, + { 0x278019d0, 0x34000009 }, + { 0x278019de, 0x54000001 }, + { 0x1f8019e0, 0x6800001f }, + { 0x05801a00, 0x1c000016 }, + { 0x05801a17, 0x30000001 }, + { 0x05801a19, 0x28000002 }, + { 0x05801a1e, 0x54000001 }, + { 0x21801d00, 0x1400002b }, + { 0x21801d2c, 0x18000035 }, + { 0x21801d62, 0x14000015 }, + { 0x0c001d78, 0x18000000 }, + { 0x21801d79, 0x14000021 }, + { 0x21801d9b, 0x18000024 }, + { 0x1b801dc0, 0x30000003 }, + { 0x21001e00, 0x24000001 }, + { 0x21001e01, 0x1400ffff }, + { 0x21001e02, 0x24000001 }, + { 0x21001e03, 0x1400ffff }, + { 0x21001e04, 0x24000001 }, + { 0x21001e05, 0x1400ffff }, + { 0x21001e06, 0x24000001 }, + { 0x21001e07, 0x1400ffff }, + { 0x21001e08, 0x24000001 }, + { 0x21001e09, 0x1400ffff }, + { 0x21001e0a, 0x24000001 }, + { 0x21001e0b, 0x1400ffff }, + { 0x21001e0c, 0x24000001 }, + { 0x21001e0d, 0x1400ffff }, + { 0x21001e0e, 0x24000001 }, + { 0x21001e0f, 0x1400ffff }, + { 0x21001e10, 0x24000001 }, + { 0x21001e11, 0x1400ffff }, + { 0x21001e12, 0x24000001 }, + { 0x21001e13, 0x1400ffff }, + { 0x21001e14, 0x24000001 }, + { 0x21001e15, 0x1400ffff }, + { 0x21001e16, 0x24000001 }, + { 0x21001e17, 0x1400ffff }, + { 0x21001e18, 0x24000001 }, + { 0x21001e19, 0x1400ffff }, + { 0x21001e1a, 0x24000001 }, + { 0x21001e1b, 0x1400ffff }, + { 0x21001e1c, 0x24000001 }, + { 0x21001e1d, 0x1400ffff }, + { 0x21001e1e, 0x24000001 }, + { 0x21001e1f, 0x1400ffff }, + { 0x21001e20, 0x24000001 }, + { 0x21001e21, 0x1400ffff }, + { 0x21001e22, 0x24000001 }, + { 0x21001e23, 0x1400ffff }, + { 0x21001e24, 0x24000001 }, + { 0x21001e25, 0x1400ffff }, + { 0x21001e26, 0x24000001 }, + { 0x21001e27, 0x1400ffff }, + { 0x21001e28, 0x24000001 }, + { 0x21001e29, 0x1400ffff }, + { 0x21001e2a, 0x24000001 }, + { 0x21001e2b, 0x1400ffff }, + { 0x21001e2c, 0x24000001 }, + { 0x21001e2d, 0x1400ffff }, + { 0x21001e2e, 0x24000001 }, + { 0x21001e2f, 0x1400ffff }, + { 0x21001e30, 0x24000001 }, + { 0x21001e31, 0x1400ffff }, + { 0x21001e32, 0x24000001 }, + { 0x21001e33, 0x1400ffff }, + { 0x21001e34, 0x24000001 }, + { 0x21001e35, 0x1400ffff }, + { 0x21001e36, 0x24000001 }, + { 0x21001e37, 0x1400ffff }, + { 0x21001e38, 0x24000001 }, + { 0x21001e39, 0x1400ffff }, + { 0x21001e3a, 0x24000001 }, + { 0x21001e3b, 0x1400ffff }, + { 0x21001e3c, 0x24000001 }, + { 0x21001e3d, 0x1400ffff }, + { 0x21001e3e, 0x24000001 }, + { 0x21001e3f, 0x1400ffff }, + { 0x21001e40, 0x24000001 }, + { 0x21001e41, 0x1400ffff }, + { 0x21001e42, 0x24000001 }, + { 0x21001e43, 0x1400ffff }, + { 0x21001e44, 0x24000001 }, + { 0x21001e45, 0x1400ffff }, + { 0x21001e46, 0x24000001 }, + { 0x21001e47, 0x1400ffff }, + { 0x21001e48, 0x24000001 }, + { 0x21001e49, 0x1400ffff }, + { 0x21001e4a, 0x24000001 }, + { 0x21001e4b, 0x1400ffff }, + { 0x21001e4c, 0x24000001 }, + { 0x21001e4d, 0x1400ffff }, + { 0x21001e4e, 0x24000001 }, + { 0x21001e4f, 0x1400ffff }, + { 0x21001e50, 0x24000001 }, + { 0x21001e51, 0x1400ffff }, + { 0x21001e52, 0x24000001 }, + { 0x21001e53, 0x1400ffff }, + { 0x21001e54, 0x24000001 }, + { 0x21001e55, 0x1400ffff }, + { 0x21001e56, 0x24000001 }, + { 0x21001e57, 0x1400ffff }, + { 0x21001e58, 0x24000001 }, + { 0x21001e59, 0x1400ffff }, + { 0x21001e5a, 0x24000001 }, + { 0x21001e5b, 0x1400ffff }, + { 0x21001e5c, 0x24000001 }, + { 0x21001e5d, 0x1400ffff }, + { 0x21001e5e, 0x24000001 }, + { 0x21001e5f, 0x1400ffff }, + { 0x21001e60, 0x24000001 }, + { 0x21001e61, 0x1400ffff }, + { 0x21001e62, 0x24000001 }, + { 0x21001e63, 0x1400ffff }, + { 0x21001e64, 0x24000001 }, + { 0x21001e65, 0x1400ffff }, + { 0x21001e66, 0x24000001 }, + { 0x21001e67, 0x1400ffff }, + { 0x21001e68, 0x24000001 }, + { 0x21001e69, 0x1400ffff }, + { 0x21001e6a, 0x24000001 }, + { 0x21001e6b, 0x1400ffff }, + { 0x21001e6c, 0x24000001 }, + { 0x21001e6d, 0x1400ffff }, + { 0x21001e6e, 0x24000001 }, + { 0x21001e6f, 0x1400ffff }, + { 0x21001e70, 0x24000001 }, + { 0x21001e71, 0x1400ffff }, + { 0x21001e72, 0x24000001 }, + { 0x21001e73, 0x1400ffff }, + { 0x21001e74, 0x24000001 }, + { 0x21001e75, 0x1400ffff }, + { 0x21001e76, 0x24000001 }, + { 0x21001e77, 0x1400ffff }, + { 0x21001e78, 0x24000001 }, + { 0x21001e79, 0x1400ffff }, + { 0x21001e7a, 0x24000001 }, + { 0x21001e7b, 0x1400ffff }, + { 0x21001e7c, 0x24000001 }, + { 0x21001e7d, 0x1400ffff }, + { 0x21001e7e, 0x24000001 }, + { 0x21001e7f, 0x1400ffff }, + { 0x21001e80, 0x24000001 }, + { 0x21001e81, 0x1400ffff }, + { 0x21001e82, 0x24000001 }, + { 0x21001e83, 0x1400ffff }, + { 0x21001e84, 0x24000001 }, + { 0x21001e85, 0x1400ffff }, + { 0x21001e86, 0x24000001 }, + { 0x21001e87, 0x1400ffff }, + { 0x21001e88, 0x24000001 }, + { 0x21001e89, 0x1400ffff }, + { 0x21001e8a, 0x24000001 }, + { 0x21001e8b, 0x1400ffff }, + { 0x21001e8c, 0x24000001 }, + { 0x21001e8d, 0x1400ffff }, + { 0x21001e8e, 0x24000001 }, + { 0x21001e8f, 0x1400ffff }, + { 0x21001e90, 0x24000001 }, + { 0x21001e91, 0x1400ffff }, + { 0x21001e92, 0x24000001 }, + { 0x21001e93, 0x1400ffff }, + { 0x21001e94, 0x24000001 }, + { 0x21001e95, 0x1400ffff }, + { 0x21801e96, 0x14000004 }, + { 0x21001e9b, 0x1400ffc5 }, + { 0x21001ea0, 0x24000001 }, + { 0x21001ea1, 0x1400ffff }, + { 0x21001ea2, 0x24000001 }, + { 0x21001ea3, 0x1400ffff }, + { 0x21001ea4, 0x24000001 }, + { 0x21001ea5, 0x1400ffff }, + { 0x21001ea6, 0x24000001 }, + { 0x21001ea7, 0x1400ffff }, + { 0x21001ea8, 0x24000001 }, + { 0x21001ea9, 0x1400ffff }, + { 0x21001eaa, 0x24000001 }, + { 0x21001eab, 0x1400ffff }, + { 0x21001eac, 0x24000001 }, + { 0x21001ead, 0x1400ffff }, + { 0x21001eae, 0x24000001 }, + { 0x21001eaf, 0x1400ffff }, + { 0x21001eb0, 0x24000001 }, + { 0x21001eb1, 0x1400ffff }, + { 0x21001eb2, 0x24000001 }, + { 0x21001eb3, 0x1400ffff }, + { 0x21001eb4, 0x24000001 }, + { 0x21001eb5, 0x1400ffff }, + { 0x21001eb6, 0x24000001 }, + { 0x21001eb7, 0x1400ffff }, + { 0x21001eb8, 0x24000001 }, + { 0x21001eb9, 0x1400ffff }, + { 0x21001eba, 0x24000001 }, + { 0x21001ebb, 0x1400ffff }, + { 0x21001ebc, 0x24000001 }, + { 0x21001ebd, 0x1400ffff }, + { 0x21001ebe, 0x24000001 }, + { 0x21001ebf, 0x1400ffff }, + { 0x21001ec0, 0x24000001 }, + { 0x21001ec1, 0x1400ffff }, + { 0x21001ec2, 0x24000001 }, + { 0x21001ec3, 0x1400ffff }, + { 0x21001ec4, 0x24000001 }, + { 0x21001ec5, 0x1400ffff }, + { 0x21001ec6, 0x24000001 }, + { 0x21001ec7, 0x1400ffff }, + { 0x21001ec8, 0x24000001 }, + { 0x21001ec9, 0x1400ffff }, + { 0x21001eca, 0x24000001 }, + { 0x21001ecb, 0x1400ffff }, + { 0x21001ecc, 0x24000001 }, + { 0x21001ecd, 0x1400ffff }, + { 0x21001ece, 0x24000001 }, + { 0x21001ecf, 0x1400ffff }, + { 0x21001ed0, 0x24000001 }, + { 0x21001ed1, 0x1400ffff }, + { 0x21001ed2, 0x24000001 }, + { 0x21001ed3, 0x1400ffff }, + { 0x21001ed4, 0x24000001 }, + { 0x21001ed5, 0x1400ffff }, + { 0x21001ed6, 0x24000001 }, + { 0x21001ed7, 0x1400ffff }, + { 0x21001ed8, 0x24000001 }, + { 0x21001ed9, 0x1400ffff }, + { 0x21001eda, 0x24000001 }, + { 0x21001edb, 0x1400ffff }, + { 0x21001edc, 0x24000001 }, + { 0x21001edd, 0x1400ffff }, + { 0x21001ede, 0x24000001 }, + { 0x21001edf, 0x1400ffff }, + { 0x21001ee0, 0x24000001 }, + { 0x21001ee1, 0x1400ffff }, + { 0x21001ee2, 0x24000001 }, + { 0x21001ee3, 0x1400ffff }, + { 0x21001ee4, 0x24000001 }, + { 0x21001ee5, 0x1400ffff }, + { 0x21001ee6, 0x24000001 }, + { 0x21001ee7, 0x1400ffff }, + { 0x21001ee8, 0x24000001 }, + { 0x21001ee9, 0x1400ffff }, + { 0x21001eea, 0x24000001 }, + { 0x21001eeb, 0x1400ffff }, + { 0x21001eec, 0x24000001 }, + { 0x21001eed, 0x1400ffff }, + { 0x21001eee, 0x24000001 }, + { 0x21001eef, 0x1400ffff }, + { 0x21001ef0, 0x24000001 }, + { 0x21001ef1, 0x1400ffff }, + { 0x21001ef2, 0x24000001 }, + { 0x21001ef3, 0x1400ffff }, + { 0x21001ef4, 0x24000001 }, + { 0x21001ef5, 0x1400ffff }, + { 0x21001ef6, 0x24000001 }, + { 0x21001ef7, 0x1400ffff }, + { 0x21001ef8, 0x24000001 }, + { 0x21001ef9, 0x1400ffff }, + { 0x13001f00, 0x14000008 }, + { 0x13001f01, 0x14000008 }, + { 0x13001f02, 0x14000008 }, + { 0x13001f03, 0x14000008 }, + { 0x13001f04, 0x14000008 }, + { 0x13001f05, 0x14000008 }, + { 0x13001f06, 0x14000008 }, + { 0x13001f07, 0x14000008 }, + { 0x13001f08, 0x2400fff8 }, + { 0x13001f09, 0x2400fff8 }, + { 0x13001f0a, 0x2400fff8 }, + { 0x13001f0b, 0x2400fff8 }, + { 0x13001f0c, 0x2400fff8 }, + { 0x13001f0d, 0x2400fff8 }, + { 0x13001f0e, 0x2400fff8 }, + { 0x13001f0f, 0x2400fff8 }, + { 0x13001f10, 0x14000008 }, + { 0x13001f11, 0x14000008 }, + { 0x13001f12, 0x14000008 }, + { 0x13001f13, 0x14000008 }, + { 0x13001f14, 0x14000008 }, + { 0x13001f15, 0x14000008 }, + { 0x13001f18, 0x2400fff8 }, + { 0x13001f19, 0x2400fff8 }, + { 0x13001f1a, 0x2400fff8 }, + { 0x13001f1b, 0x2400fff8 }, + { 0x13001f1c, 0x2400fff8 }, + { 0x13001f1d, 0x2400fff8 }, + { 0x13001f20, 0x14000008 }, + { 0x13001f21, 0x14000008 }, + { 0x13001f22, 0x14000008 }, + { 0x13001f23, 0x14000008 }, + { 0x13001f24, 0x14000008 }, + { 0x13001f25, 0x14000008 }, + { 0x13001f26, 0x14000008 }, + { 0x13001f27, 0x14000008 }, + { 0x13001f28, 0x2400fff8 }, + { 0x13001f29, 0x2400fff8 }, + { 0x13001f2a, 0x2400fff8 }, + { 0x13001f2b, 0x2400fff8 }, + { 0x13001f2c, 0x2400fff8 }, + { 0x13001f2d, 0x2400fff8 }, + { 0x13001f2e, 0x2400fff8 }, + { 0x13001f2f, 0x2400fff8 }, + { 0x13001f30, 0x14000008 }, + { 0x13001f31, 0x14000008 }, + { 0x13001f32, 0x14000008 }, + { 0x13001f33, 0x14000008 }, + { 0x13001f34, 0x14000008 }, + { 0x13001f35, 0x14000008 }, + { 0x13001f36, 0x14000008 }, + { 0x13001f37, 0x14000008 }, + { 0x13001f38, 0x2400fff8 }, + { 0x13001f39, 0x2400fff8 }, + { 0x13001f3a, 0x2400fff8 }, + { 0x13001f3b, 0x2400fff8 }, + { 0x13001f3c, 0x2400fff8 }, + { 0x13001f3d, 0x2400fff8 }, + { 0x13001f3e, 0x2400fff8 }, + { 0x13001f3f, 0x2400fff8 }, + { 0x13001f40, 0x14000008 }, + { 0x13001f41, 0x14000008 }, + { 0x13001f42, 0x14000008 }, + { 0x13001f43, 0x14000008 }, + { 0x13001f44, 0x14000008 }, + { 0x13001f45, 0x14000008 }, + { 0x13001f48, 0x2400fff8 }, + { 0x13001f49, 0x2400fff8 }, + { 0x13001f4a, 0x2400fff8 }, + { 0x13001f4b, 0x2400fff8 }, + { 0x13001f4c, 0x2400fff8 }, + { 0x13001f4d, 0x2400fff8 }, + { 0x13001f50, 0x14000000 }, + { 0x13001f51, 0x14000008 }, + { 0x13001f52, 0x14000000 }, + { 0x13001f53, 0x14000008 }, + { 0x13001f54, 0x14000000 }, + { 0x13001f55, 0x14000008 }, + { 0x13001f56, 0x14000000 }, + { 0x13001f57, 0x14000008 }, + { 0x13001f59, 0x2400fff8 }, + { 0x13001f5b, 0x2400fff8 }, + { 0x13001f5d, 0x2400fff8 }, + { 0x13001f5f, 0x2400fff8 }, + { 0x13001f60, 0x14000008 }, + { 0x13001f61, 0x14000008 }, + { 0x13001f62, 0x14000008 }, + { 0x13001f63, 0x14000008 }, + { 0x13001f64, 0x14000008 }, + { 0x13001f65, 0x14000008 }, + { 0x13001f66, 0x14000008 }, + { 0x13001f67, 0x14000008 }, + { 0x13001f68, 0x2400fff8 }, + { 0x13001f69, 0x2400fff8 }, + { 0x13001f6a, 0x2400fff8 }, + { 0x13001f6b, 0x2400fff8 }, + { 0x13001f6c, 0x2400fff8 }, + { 0x13001f6d, 0x2400fff8 }, + { 0x13001f6e, 0x2400fff8 }, + { 0x13001f6f, 0x2400fff8 }, + { 0x13001f70, 0x1400004a }, + { 0x13001f71, 0x1400004a }, + { 0x13001f72, 0x14000056 }, + { 0x13001f73, 0x14000056 }, + { 0x13001f74, 0x14000056 }, + { 0x13001f75, 0x14000056 }, + { 0x13001f76, 0x14000064 }, + { 0x13001f77, 0x14000064 }, + { 0x13001f78, 0x14000080 }, + { 0x13001f79, 0x14000080 }, + { 0x13001f7a, 0x14000070 }, + { 0x13001f7b, 0x14000070 }, + { 0x13001f7c, 0x1400007e }, + { 0x13001f7d, 0x1400007e }, + { 0x13001f80, 0x14000008 }, + { 0x13001f81, 0x14000008 }, + { 0x13001f82, 0x14000008 }, + { 0x13001f83, 0x14000008 }, + { 0x13001f84, 0x14000008 }, + { 0x13001f85, 0x14000008 }, + { 0x13001f86, 0x14000008 }, + { 0x13001f87, 0x14000008 }, + { 0x13001f88, 0x2000fff8 }, + { 0x13001f89, 0x2000fff8 }, + { 0x13001f8a, 0x2000fff8 }, + { 0x13001f8b, 0x2000fff8 }, + { 0x13001f8c, 0x2000fff8 }, + { 0x13001f8d, 0x2000fff8 }, + { 0x13001f8e, 0x2000fff8 }, + { 0x13001f8f, 0x2000fff8 }, + { 0x13001f90, 0x14000008 }, + { 0x13001f91, 0x14000008 }, + { 0x13001f92, 0x14000008 }, + { 0x13001f93, 0x14000008 }, + { 0x13001f94, 0x14000008 }, + { 0x13001f95, 0x14000008 }, + { 0x13001f96, 0x14000008 }, + { 0x13001f97, 0x14000008 }, + { 0x13001f98, 0x2000fff8 }, + { 0x13001f99, 0x2000fff8 }, + { 0x13001f9a, 0x2000fff8 }, + { 0x13001f9b, 0x2000fff8 }, + { 0x13001f9c, 0x2000fff8 }, + { 0x13001f9d, 0x2000fff8 }, + { 0x13001f9e, 0x2000fff8 }, + { 0x13001f9f, 0x2000fff8 }, + { 0x13001fa0, 0x14000008 }, + { 0x13001fa1, 0x14000008 }, + { 0x13001fa2, 0x14000008 }, + { 0x13001fa3, 0x14000008 }, + { 0x13001fa4, 0x14000008 }, + { 0x13001fa5, 0x14000008 }, + { 0x13001fa6, 0x14000008 }, + { 0x13001fa7, 0x14000008 }, + { 0x13001fa8, 0x2000fff8 }, + { 0x13001fa9, 0x2000fff8 }, + { 0x13001faa, 0x2000fff8 }, + { 0x13001fab, 0x2000fff8 }, + { 0x13001fac, 0x2000fff8 }, + { 0x13001fad, 0x2000fff8 }, + { 0x13001fae, 0x2000fff8 }, + { 0x13001faf, 0x2000fff8 }, + { 0x13001fb0, 0x14000008 }, + { 0x13001fb1, 0x14000008 }, + { 0x13001fb2, 0x14000000 }, + { 0x13001fb3, 0x14000009 }, + { 0x13001fb4, 0x14000000 }, + { 0x13801fb6, 0x14000001 }, + { 0x13001fb8, 0x2400fff8 }, + { 0x13001fb9, 0x2400fff8 }, + { 0x13001fba, 0x2400ffb6 }, + { 0x13001fbb, 0x2400ffb6 }, + { 0x13001fbc, 0x2000fff7 }, + { 0x13001fbd, 0x60000000 }, + { 0x13001fbe, 0x1400e3db }, + { 0x13801fbf, 0x60000002 }, + { 0x13001fc2, 0x14000000 }, + { 0x13001fc3, 0x14000009 }, + { 0x13001fc4, 0x14000000 }, + { 0x13801fc6, 0x14000001 }, + { 0x13001fc8, 0x2400ffaa }, + { 0x13001fc9, 0x2400ffaa }, + { 0x13001fca, 0x2400ffaa }, + { 0x13001fcb, 0x2400ffaa }, + { 0x13001fcc, 0x2000fff7 }, + { 0x13801fcd, 0x60000002 }, + { 0x13001fd0, 0x14000008 }, + { 0x13001fd1, 0x14000008 }, + { 0x13801fd2, 0x14000001 }, + { 0x13801fd6, 0x14000001 }, + { 0x13001fd8, 0x2400fff8 }, + { 0x13001fd9, 0x2400fff8 }, + { 0x13001fda, 0x2400ff9c }, + { 0x13001fdb, 0x2400ff9c }, + { 0x13801fdd, 0x60000002 }, + { 0x13001fe0, 0x14000008 }, + { 0x13001fe1, 0x14000008 }, + { 0x13801fe2, 0x14000002 }, + { 0x13001fe5, 0x14000007 }, + { 0x13801fe6, 0x14000001 }, + { 0x13001fe8, 0x2400fff8 }, + { 0x13001fe9, 0x2400fff8 }, + { 0x13001fea, 0x2400ff90 }, + { 0x13001feb, 0x2400ff90 }, + { 0x13001fec, 0x2400fff9 }, + { 0x13801fed, 0x60000002 }, + { 0x13001ff2, 0x14000000 }, + { 0x13001ff3, 0x14000009 }, + { 0x13001ff4, 0x14000000 }, + { 0x13801ff6, 0x14000001 }, + { 0x13001ff8, 0x2400ff80 }, + { 0x13001ff9, 0x2400ff80 }, + { 0x13001ffa, 0x2400ff82 }, + { 0x13001ffb, 0x2400ff82 }, + { 0x13001ffc, 0x2000fff7 }, + { 0x13801ffd, 0x60000001 }, + { 0x09802000, 0x7400000a }, + { 0x0980200b, 0x04000004 }, + { 0x09802010, 0x44000005 }, + { 0x09802016, 0x54000001 }, + { 0x09002018, 0x50000000 }, + { 0x09002019, 0x4c000000 }, + { 0x0900201a, 0x58000000 }, + { 0x0980201b, 0x50000001 }, + { 0x0900201d, 0x4c000000 }, + { 0x0900201e, 0x58000000 }, + { 0x0900201f, 0x50000000 }, + { 0x09802020, 0x54000007 }, + { 0x09002028, 0x6c000000 }, + { 0x09002029, 0x70000000 }, + { 0x0980202a, 0x04000004 }, + { 0x0900202f, 0x74000000 }, + { 0x09802030, 0x54000008 }, + { 0x09002039, 0x50000000 }, + { 0x0900203a, 0x4c000000 }, + { 0x0980203b, 0x54000003 }, + { 0x0980203f, 0x40000001 }, + { 0x09802041, 0x54000002 }, + { 0x09002044, 0x64000000 }, + { 0x09002045, 0x58000000 }, + { 0x09002046, 0x48000000 }, + { 0x09802047, 0x5400000a }, + { 0x09002052, 0x64000000 }, + { 0x09002053, 0x54000000 }, + { 0x09002054, 0x40000000 }, + { 0x09802055, 0x54000009 }, + { 0x0900205f, 0x74000000 }, + { 0x09802060, 0x04000003 }, + { 0x0980206a, 0x04000005 }, + { 0x09002070, 0x3c000000 }, + { 0x21002071, 0x14000000 }, + { 0x09802074, 0x3c000005 }, + { 0x0980207a, 0x64000002 }, + { 0x0900207d, 0x58000000 }, + { 0x0900207e, 0x48000000 }, + { 0x2100207f, 0x14000000 }, + { 0x09802080, 0x3c000009 }, + { 0x0980208a, 0x64000002 }, + { 0x0900208d, 0x58000000 }, + { 0x0900208e, 0x48000000 }, + { 0x21802090, 0x18000004 }, + { 0x098020a0, 0x5c000015 }, + { 0x1b8020d0, 0x3000000c }, + { 0x1b8020dd, 0x2c000003 }, + { 0x1b0020e1, 0x30000000 }, + { 0x1b8020e2, 0x2c000002 }, + { 0x1b8020e5, 0x30000006 }, + { 0x09802100, 0x68000001 }, + { 0x09002102, 0x24000000 }, + { 0x09802103, 0x68000003 }, + { 0x09002107, 0x24000000 }, + { 0x09802108, 0x68000001 }, + { 0x0900210a, 0x14000000 }, + { 0x0980210b, 0x24000002 }, + { 0x0980210e, 0x14000001 }, + { 0x09802110, 0x24000002 }, + { 0x09002113, 0x14000000 }, + { 0x09002114, 0x68000000 }, + { 0x09002115, 0x24000000 }, + { 0x09802116, 0x68000002 }, + { 0x09802119, 0x24000004 }, + { 0x0980211e, 0x68000005 }, + { 0x09002124, 0x24000000 }, + { 0x09002125, 0x68000000 }, + { 0x13002126, 0x2400e2a3 }, + { 0x09002127, 0x68000000 }, + { 0x09002128, 0x24000000 }, + { 0x09002129, 0x68000000 }, + { 0x2100212a, 0x2400df41 }, + { 0x2100212b, 0x2400dfba }, + { 0x0980212c, 0x24000001 }, + { 0x0900212e, 0x68000000 }, + { 0x0900212f, 0x14000000 }, + { 0x09802130, 0x24000001 }, + { 0x09002132, 0x68000000 }, + { 0x09002133, 0x24000000 }, + { 0x09002134, 0x14000000 }, + { 0x09802135, 0x1c000003 }, + { 0x09002139, 0x14000000 }, + { 0x0980213a, 0x68000001 }, + { 0x0980213c, 0x14000001 }, + { 0x0980213e, 0x24000001 }, + { 0x09802140, 0x64000004 }, + { 0x09002145, 0x24000000 }, + { 0x09802146, 0x14000003 }, + { 0x0900214a, 0x68000000 }, + { 0x0900214b, 0x64000000 }, + { 0x0900214c, 0x68000000 }, + { 0x09802153, 0x3c00000c }, + { 0x09002160, 0x38000010 }, + { 0x09002161, 0x38000010 }, + { 0x09002162, 0x38000010 }, + { 0x09002163, 0x38000010 }, + { 0x09002164, 0x38000010 }, + { 0x09002165, 0x38000010 }, + { 0x09002166, 0x38000010 }, + { 0x09002167, 0x38000010 }, + { 0x09002168, 0x38000010 }, + { 0x09002169, 0x38000010 }, + { 0x0900216a, 0x38000010 }, + { 0x0900216b, 0x38000010 }, + { 0x0900216c, 0x38000010 }, + { 0x0900216d, 0x38000010 }, + { 0x0900216e, 0x38000010 }, + { 0x0900216f, 0x38000010 }, + { 0x09002170, 0x3800fff0 }, + { 0x09002171, 0x3800fff0 }, + { 0x09002172, 0x3800fff0 }, + { 0x09002173, 0x3800fff0 }, + { 0x09002174, 0x3800fff0 }, + { 0x09002175, 0x3800fff0 }, + { 0x09002176, 0x3800fff0 }, + { 0x09002177, 0x3800fff0 }, + { 0x09002178, 0x3800fff0 }, + { 0x09002179, 0x3800fff0 }, + { 0x0900217a, 0x3800fff0 }, + { 0x0900217b, 0x3800fff0 }, + { 0x0900217c, 0x3800fff0 }, + { 0x0900217d, 0x3800fff0 }, + { 0x0900217e, 0x3800fff0 }, + { 0x0900217f, 0x3800fff0 }, + { 0x09802180, 0x38000003 }, + { 0x09802190, 0x64000004 }, + { 0x09802195, 0x68000004 }, + { 0x0980219a, 0x64000001 }, + { 0x0980219c, 0x68000003 }, + { 0x090021a0, 0x64000000 }, + { 0x098021a1, 0x68000001 }, + { 0x090021a3, 0x64000000 }, + { 0x098021a4, 0x68000001 }, + { 0x090021a6, 0x64000000 }, + { 0x098021a7, 0x68000006 }, + { 0x090021ae, 0x64000000 }, + { 0x098021af, 0x6800001e }, + { 0x098021ce, 0x64000001 }, + { 0x098021d0, 0x68000001 }, + { 0x090021d2, 0x64000000 }, + { 0x090021d3, 0x68000000 }, + { 0x090021d4, 0x64000000 }, + { 0x098021d5, 0x6800001e }, + { 0x098021f4, 0x6400010b }, + { 0x09802300, 0x68000007 }, + { 0x09802308, 0x64000003 }, + { 0x0980230c, 0x68000013 }, + { 0x09802320, 0x64000001 }, + { 0x09802322, 0x68000006 }, + { 0x09002329, 0x58000000 }, + { 0x0900232a, 0x48000000 }, + { 0x0980232b, 0x68000050 }, + { 0x0900237c, 0x64000000 }, + { 0x0980237d, 0x6800001d }, + { 0x0980239b, 0x64000018 }, + { 0x090023b4, 0x58000000 }, + { 0x090023b5, 0x48000000 }, + { 0x090023b6, 0x54000000 }, + { 0x098023b7, 0x68000024 }, + { 0x09802400, 0x68000026 }, + { 0x09802440, 0x6800000a }, + { 0x09802460, 0x3c00003b }, + { 0x0980249c, 0x68000019 }, + { 0x090024b6, 0x6800001a }, + { 0x090024b7, 0x6800001a }, + { 0x090024b8, 0x6800001a }, + { 0x090024b9, 0x6800001a }, + { 0x090024ba, 0x6800001a }, + { 0x090024bb, 0x6800001a }, + { 0x090024bc, 0x6800001a }, + { 0x090024bd, 0x6800001a }, + { 0x090024be, 0x6800001a }, + { 0x090024bf, 0x6800001a }, + { 0x090024c0, 0x6800001a }, + { 0x090024c1, 0x6800001a }, + { 0x090024c2, 0x6800001a }, + { 0x090024c3, 0x6800001a }, + { 0x090024c4, 0x6800001a }, + { 0x090024c5, 0x6800001a }, + { 0x090024c6, 0x6800001a }, + { 0x090024c7, 0x6800001a }, + { 0x090024c8, 0x6800001a }, + { 0x090024c9, 0x6800001a }, + { 0x090024ca, 0x6800001a }, + { 0x090024cb, 0x6800001a }, + { 0x090024cc, 0x6800001a }, + { 0x090024cd, 0x6800001a }, + { 0x090024ce, 0x6800001a }, + { 0x090024cf, 0x6800001a }, + { 0x090024d0, 0x6800ffe6 }, + { 0x090024d1, 0x6800ffe6 }, + { 0x090024d2, 0x6800ffe6 }, + { 0x090024d3, 0x6800ffe6 }, + { 0x090024d4, 0x6800ffe6 }, + { 0x090024d5, 0x6800ffe6 }, + { 0x090024d6, 0x6800ffe6 }, + { 0x090024d7, 0x6800ffe6 }, + { 0x090024d8, 0x6800ffe6 }, + { 0x090024d9, 0x6800ffe6 }, + { 0x090024da, 0x6800ffe6 }, + { 0x090024db, 0x6800ffe6 }, + { 0x090024dc, 0x6800ffe6 }, + { 0x090024dd, 0x6800ffe6 }, + { 0x090024de, 0x6800ffe6 }, + { 0x090024df, 0x6800ffe6 }, + { 0x090024e0, 0x6800ffe6 }, + { 0x090024e1, 0x6800ffe6 }, + { 0x090024e2, 0x6800ffe6 }, + { 0x090024e3, 0x6800ffe6 }, + { 0x090024e4, 0x6800ffe6 }, + { 0x090024e5, 0x6800ffe6 }, + { 0x090024e6, 0x6800ffe6 }, + { 0x090024e7, 0x6800ffe6 }, + { 0x090024e8, 0x6800ffe6 }, + { 0x090024e9, 0x6800ffe6 }, + { 0x098024ea, 0x3c000015 }, + { 0x09802500, 0x680000b6 }, + { 0x090025b7, 0x64000000 }, + { 0x098025b8, 0x68000008 }, + { 0x090025c1, 0x64000000 }, + { 0x098025c2, 0x68000035 }, + { 0x098025f8, 0x64000007 }, + { 0x09802600, 0x6800006e }, + { 0x0900266f, 0x64000000 }, + { 0x09802670, 0x6800002c }, + { 0x098026a0, 0x68000011 }, + { 0x09802701, 0x68000003 }, + { 0x09802706, 0x68000003 }, + { 0x0980270c, 0x6800001b }, + { 0x09802729, 0x68000022 }, + { 0x0900274d, 0x68000000 }, + { 0x0980274f, 0x68000003 }, + { 0x09002756, 0x68000000 }, + { 0x09802758, 0x68000006 }, + { 0x09802761, 0x68000006 }, + { 0x09002768, 0x58000000 }, + { 0x09002769, 0x48000000 }, + { 0x0900276a, 0x58000000 }, + { 0x0900276b, 0x48000000 }, + { 0x0900276c, 0x58000000 }, + { 0x0900276d, 0x48000000 }, + { 0x0900276e, 0x58000000 }, + { 0x0900276f, 0x48000000 }, + { 0x09002770, 0x58000000 }, + { 0x09002771, 0x48000000 }, + { 0x09002772, 0x58000000 }, + { 0x09002773, 0x48000000 }, + { 0x09002774, 0x58000000 }, + { 0x09002775, 0x48000000 }, + { 0x09802776, 0x3c00001d }, + { 0x09002794, 0x68000000 }, + { 0x09802798, 0x68000017 }, + { 0x098027b1, 0x6800000d }, + { 0x098027c0, 0x64000004 }, + { 0x090027c5, 0x58000000 }, + { 0x090027c6, 0x48000000 }, + { 0x098027d0, 0x64000015 }, + { 0x090027e6, 0x58000000 }, + { 0x090027e7, 0x48000000 }, + { 0x090027e8, 0x58000000 }, + { 0x090027e9, 0x48000000 }, + { 0x090027ea, 0x58000000 }, + { 0x090027eb, 0x48000000 }, + { 0x098027f0, 0x6400000f }, + { 0x04802800, 0x680000ff }, + { 0x09802900, 0x64000082 }, + { 0x09002983, 0x58000000 }, + { 0x09002984, 0x48000000 }, + { 0x09002985, 0x58000000 }, + { 0x09002986, 0x48000000 }, + { 0x09002987, 0x58000000 }, + { 0x09002988, 0x48000000 }, + { 0x09002989, 0x58000000 }, + { 0x0900298a, 0x48000000 }, + { 0x0900298b, 0x58000000 }, + { 0x0900298c, 0x48000000 }, + { 0x0900298d, 0x58000000 }, + { 0x0900298e, 0x48000000 }, + { 0x0900298f, 0x58000000 }, + { 0x09002990, 0x48000000 }, + { 0x09002991, 0x58000000 }, + { 0x09002992, 0x48000000 }, + { 0x09002993, 0x58000000 }, + { 0x09002994, 0x48000000 }, + { 0x09002995, 0x58000000 }, + { 0x09002996, 0x48000000 }, + { 0x09002997, 0x58000000 }, + { 0x09002998, 0x48000000 }, + { 0x09802999, 0x6400003e }, + { 0x090029d8, 0x58000000 }, + { 0x090029d9, 0x48000000 }, + { 0x090029da, 0x58000000 }, + { 0x090029db, 0x48000000 }, + { 0x098029dc, 0x6400001f }, + { 0x090029fc, 0x58000000 }, + { 0x090029fd, 0x48000000 }, + { 0x098029fe, 0x64000101 }, + { 0x09802b00, 0x68000013 }, + { 0x11002c00, 0x24000030 }, + { 0x11002c01, 0x24000030 }, + { 0x11002c02, 0x24000030 }, + { 0x11002c03, 0x24000030 }, + { 0x11002c04, 0x24000030 }, + { 0x11002c05, 0x24000030 }, + { 0x11002c06, 0x24000030 }, + { 0x11002c07, 0x24000030 }, + { 0x11002c08, 0x24000030 }, + { 0x11002c09, 0x24000030 }, + { 0x11002c0a, 0x24000030 }, + { 0x11002c0b, 0x24000030 }, + { 0x11002c0c, 0x24000030 }, + { 0x11002c0d, 0x24000030 }, + { 0x11002c0e, 0x24000030 }, + { 0x11002c0f, 0x24000030 }, + { 0x11002c10, 0x24000030 }, + { 0x11002c11, 0x24000030 }, + { 0x11002c12, 0x24000030 }, + { 0x11002c13, 0x24000030 }, + { 0x11002c14, 0x24000030 }, + { 0x11002c15, 0x24000030 }, + { 0x11002c16, 0x24000030 }, + { 0x11002c17, 0x24000030 }, + { 0x11002c18, 0x24000030 }, + { 0x11002c19, 0x24000030 }, + { 0x11002c1a, 0x24000030 }, + { 0x11002c1b, 0x24000030 }, + { 0x11002c1c, 0x24000030 }, + { 0x11002c1d, 0x24000030 }, + { 0x11002c1e, 0x24000030 }, + { 0x11002c1f, 0x24000030 }, + { 0x11002c20, 0x24000030 }, + { 0x11002c21, 0x24000030 }, + { 0x11002c22, 0x24000030 }, + { 0x11002c23, 0x24000030 }, + { 0x11002c24, 0x24000030 }, + { 0x11002c25, 0x24000030 }, + { 0x11002c26, 0x24000030 }, + { 0x11002c27, 0x24000030 }, + { 0x11002c28, 0x24000030 }, + { 0x11002c29, 0x24000030 }, + { 0x11002c2a, 0x24000030 }, + { 0x11002c2b, 0x24000030 }, + { 0x11002c2c, 0x24000030 }, + { 0x11002c2d, 0x24000030 }, + { 0x11002c2e, 0x24000030 }, + { 0x11002c30, 0x1400ffd0 }, + { 0x11002c31, 0x1400ffd0 }, + { 0x11002c32, 0x1400ffd0 }, + { 0x11002c33, 0x1400ffd0 }, + { 0x11002c34, 0x1400ffd0 }, + { 0x11002c35, 0x1400ffd0 }, + { 0x11002c36, 0x1400ffd0 }, + { 0x11002c37, 0x1400ffd0 }, + { 0x11002c38, 0x1400ffd0 }, + { 0x11002c39, 0x1400ffd0 }, + { 0x11002c3a, 0x1400ffd0 }, + { 0x11002c3b, 0x1400ffd0 }, + { 0x11002c3c, 0x1400ffd0 }, + { 0x11002c3d, 0x1400ffd0 }, + { 0x11002c3e, 0x1400ffd0 }, + { 0x11002c3f, 0x1400ffd0 }, + { 0x11002c40, 0x1400ffd0 }, + { 0x11002c41, 0x1400ffd0 }, + { 0x11002c42, 0x1400ffd0 }, + { 0x11002c43, 0x1400ffd0 }, + { 0x11002c44, 0x1400ffd0 }, + { 0x11002c45, 0x1400ffd0 }, + { 0x11002c46, 0x1400ffd0 }, + { 0x11002c47, 0x1400ffd0 }, + { 0x11002c48, 0x1400ffd0 }, + { 0x11002c49, 0x1400ffd0 }, + { 0x11002c4a, 0x1400ffd0 }, + { 0x11002c4b, 0x1400ffd0 }, + { 0x11002c4c, 0x1400ffd0 }, + { 0x11002c4d, 0x1400ffd0 }, + { 0x11002c4e, 0x1400ffd0 }, + { 0x11002c4f, 0x1400ffd0 }, + { 0x11002c50, 0x1400ffd0 }, + { 0x11002c51, 0x1400ffd0 }, + { 0x11002c52, 0x1400ffd0 }, + { 0x11002c53, 0x1400ffd0 }, + { 0x11002c54, 0x1400ffd0 }, + { 0x11002c55, 0x1400ffd0 }, + { 0x11002c56, 0x1400ffd0 }, + { 0x11002c57, 0x1400ffd0 }, + { 0x11002c58, 0x1400ffd0 }, + { 0x11002c59, 0x1400ffd0 }, + { 0x11002c5a, 0x1400ffd0 }, + { 0x11002c5b, 0x1400ffd0 }, + { 0x11002c5c, 0x1400ffd0 }, + { 0x11002c5d, 0x1400ffd0 }, + { 0x11002c5e, 0x1400ffd0 }, + { 0x0a002c80, 0x24000001 }, + { 0x0a002c81, 0x1400ffff }, + { 0x0a002c82, 0x24000001 }, + { 0x0a002c83, 0x1400ffff }, + { 0x0a002c84, 0x24000001 }, + { 0x0a002c85, 0x1400ffff }, + { 0x0a002c86, 0x24000001 }, + { 0x0a002c87, 0x1400ffff }, + { 0x0a002c88, 0x24000001 }, + { 0x0a002c89, 0x1400ffff }, + { 0x0a002c8a, 0x24000001 }, + { 0x0a002c8b, 0x1400ffff }, + { 0x0a002c8c, 0x24000001 }, + { 0x0a002c8d, 0x1400ffff }, + { 0x0a002c8e, 0x24000001 }, + { 0x0a002c8f, 0x1400ffff }, + { 0x0a002c90, 0x24000001 }, + { 0x0a002c91, 0x1400ffff }, + { 0x0a002c92, 0x24000001 }, + { 0x0a002c93, 0x1400ffff }, + { 0x0a002c94, 0x24000001 }, + { 0x0a002c95, 0x1400ffff }, + { 0x0a002c96, 0x24000001 }, + { 0x0a002c97, 0x1400ffff }, + { 0x0a002c98, 0x24000001 }, + { 0x0a002c99, 0x1400ffff }, + { 0x0a002c9a, 0x24000001 }, + { 0x0a002c9b, 0x1400ffff }, + { 0x0a002c9c, 0x24000001 }, + { 0x0a002c9d, 0x1400ffff }, + { 0x0a002c9e, 0x24000001 }, + { 0x0a002c9f, 0x1400ffff }, + { 0x0a002ca0, 0x24000001 }, + { 0x0a002ca1, 0x1400ffff }, + { 0x0a002ca2, 0x24000001 }, + { 0x0a002ca3, 0x1400ffff }, + { 0x0a002ca4, 0x24000001 }, + { 0x0a002ca5, 0x1400ffff }, + { 0x0a002ca6, 0x24000001 }, + { 0x0a002ca7, 0x1400ffff }, + { 0x0a002ca8, 0x24000001 }, + { 0x0a002ca9, 0x1400ffff }, + { 0x0a002caa, 0x24000001 }, + { 0x0a002cab, 0x1400ffff }, + { 0x0a002cac, 0x24000001 }, + { 0x0a002cad, 0x1400ffff }, + { 0x0a002cae, 0x24000001 }, + { 0x0a002caf, 0x1400ffff }, + { 0x0a002cb0, 0x24000001 }, + { 0x0a002cb1, 0x1400ffff }, + { 0x0a002cb2, 0x24000001 }, + { 0x0a002cb3, 0x1400ffff }, + { 0x0a002cb4, 0x24000001 }, + { 0x0a002cb5, 0x1400ffff }, + { 0x0a002cb6, 0x24000001 }, + { 0x0a002cb7, 0x1400ffff }, + { 0x0a002cb8, 0x24000001 }, + { 0x0a002cb9, 0x1400ffff }, + { 0x0a002cba, 0x24000001 }, + { 0x0a002cbb, 0x1400ffff }, + { 0x0a002cbc, 0x24000001 }, + { 0x0a002cbd, 0x1400ffff }, + { 0x0a002cbe, 0x24000001 }, + { 0x0a002cbf, 0x1400ffff }, + { 0x0a002cc0, 0x24000001 }, + { 0x0a002cc1, 0x1400ffff }, + { 0x0a002cc2, 0x24000001 }, + { 0x0a002cc3, 0x1400ffff }, + { 0x0a002cc4, 0x24000001 }, + { 0x0a002cc5, 0x1400ffff }, + { 0x0a002cc6, 0x24000001 }, + { 0x0a002cc7, 0x1400ffff }, + { 0x0a002cc8, 0x24000001 }, + { 0x0a002cc9, 0x1400ffff }, + { 0x0a002cca, 0x24000001 }, + { 0x0a002ccb, 0x1400ffff }, + { 0x0a002ccc, 0x24000001 }, + { 0x0a002ccd, 0x1400ffff }, + { 0x0a002cce, 0x24000001 }, + { 0x0a002ccf, 0x1400ffff }, + { 0x0a002cd0, 0x24000001 }, + { 0x0a002cd1, 0x1400ffff }, + { 0x0a002cd2, 0x24000001 }, + { 0x0a002cd3, 0x1400ffff }, + { 0x0a002cd4, 0x24000001 }, + { 0x0a002cd5, 0x1400ffff }, + { 0x0a002cd6, 0x24000001 }, + { 0x0a002cd7, 0x1400ffff }, + { 0x0a002cd8, 0x24000001 }, + { 0x0a002cd9, 0x1400ffff }, + { 0x0a002cda, 0x24000001 }, + { 0x0a002cdb, 0x1400ffff }, + { 0x0a002cdc, 0x24000001 }, + { 0x0a002cdd, 0x1400ffff }, + { 0x0a002cde, 0x24000001 }, + { 0x0a002cdf, 0x1400ffff }, + { 0x0a002ce0, 0x24000001 }, + { 0x0a002ce1, 0x1400ffff }, + { 0x0a002ce2, 0x24000001 }, + { 0x0a002ce3, 0x1400ffff }, + { 0x0a002ce4, 0x14000000 }, + { 0x0a802ce5, 0x68000005 }, + { 0x0a802cf9, 0x54000003 }, + { 0x0a002cfd, 0x3c000000 }, + { 0x0a802cfe, 0x54000001 }, + { 0x10002d00, 0x1400e3a0 }, + { 0x10002d01, 0x1400e3a0 }, + { 0x10002d02, 0x1400e3a0 }, + { 0x10002d03, 0x1400e3a0 }, + { 0x10002d04, 0x1400e3a0 }, + { 0x10002d05, 0x1400e3a0 }, + { 0x10002d06, 0x1400e3a0 }, + { 0x10002d07, 0x1400e3a0 }, + { 0x10002d08, 0x1400e3a0 }, + { 0x10002d09, 0x1400e3a0 }, + { 0x10002d0a, 0x1400e3a0 }, + { 0x10002d0b, 0x1400e3a0 }, + { 0x10002d0c, 0x1400e3a0 }, + { 0x10002d0d, 0x1400e3a0 }, + { 0x10002d0e, 0x1400e3a0 }, + { 0x10002d0f, 0x1400e3a0 }, + { 0x10002d10, 0x1400e3a0 }, + { 0x10002d11, 0x1400e3a0 }, + { 0x10002d12, 0x1400e3a0 }, + { 0x10002d13, 0x1400e3a0 }, + { 0x10002d14, 0x1400e3a0 }, + { 0x10002d15, 0x1400e3a0 }, + { 0x10002d16, 0x1400e3a0 }, + { 0x10002d17, 0x1400e3a0 }, + { 0x10002d18, 0x1400e3a0 }, + { 0x10002d19, 0x1400e3a0 }, + { 0x10002d1a, 0x1400e3a0 }, + { 0x10002d1b, 0x1400e3a0 }, + { 0x10002d1c, 0x1400e3a0 }, + { 0x10002d1d, 0x1400e3a0 }, + { 0x10002d1e, 0x1400e3a0 }, + { 0x10002d1f, 0x1400e3a0 }, + { 0x10002d20, 0x1400e3a0 }, + { 0x10002d21, 0x1400e3a0 }, + { 0x10002d22, 0x1400e3a0 }, + { 0x10002d23, 0x1400e3a0 }, + { 0x10002d24, 0x1400e3a0 }, + { 0x10002d25, 0x1400e3a0 }, + { 0x3a802d30, 0x1c000035 }, + { 0x3a002d6f, 0x18000000 }, + { 0x0f802d80, 0x1c000016 }, + { 0x0f802da0, 0x1c000006 }, + { 0x0f802da8, 0x1c000006 }, + { 0x0f802db0, 0x1c000006 }, + { 0x0f802db8, 0x1c000006 }, + { 0x0f802dc0, 0x1c000006 }, + { 0x0f802dc8, 0x1c000006 }, + { 0x0f802dd0, 0x1c000006 }, + { 0x0f802dd8, 0x1c000006 }, + { 0x09802e00, 0x54000001 }, + { 0x09002e02, 0x50000000 }, + { 0x09002e03, 0x4c000000 }, + { 0x09002e04, 0x50000000 }, + { 0x09002e05, 0x4c000000 }, + { 0x09802e06, 0x54000002 }, + { 0x09002e09, 0x50000000 }, + { 0x09002e0a, 0x4c000000 }, + { 0x09002e0b, 0x54000000 }, + { 0x09002e0c, 0x50000000 }, + { 0x09002e0d, 0x4c000000 }, + { 0x09802e0e, 0x54000008 }, + { 0x09002e17, 0x44000000 }, + { 0x09002e1c, 0x50000000 }, + { 0x09002e1d, 0x4c000000 }, + { 0x16802e80, 0x68000019 }, + { 0x16802e9b, 0x68000058 }, + { 0x16802f00, 0x680000d5 }, + { 0x09802ff0, 0x6800000b }, + { 0x09003000, 0x74000000 }, + { 0x09803001, 0x54000002 }, + { 0x09003004, 0x68000000 }, + { 0x16003005, 0x18000000 }, + { 0x09003006, 0x1c000000 }, + { 0x16003007, 0x38000000 }, + { 0x09003008, 0x58000000 }, + { 0x09003009, 0x48000000 }, + { 0x0900300a, 0x58000000 }, + { 0x0900300b, 0x48000000 }, + { 0x0900300c, 0x58000000 }, + { 0x0900300d, 0x48000000 }, + { 0x0900300e, 0x58000000 }, + { 0x0900300f, 0x48000000 }, + { 0x09003010, 0x58000000 }, + { 0x09003011, 0x48000000 }, + { 0x09803012, 0x68000001 }, + { 0x09003014, 0x58000000 }, + { 0x09003015, 0x48000000 }, + { 0x09003016, 0x58000000 }, + { 0x09003017, 0x48000000 }, + { 0x09003018, 0x58000000 }, + { 0x09003019, 0x48000000 }, + { 0x0900301a, 0x58000000 }, + { 0x0900301b, 0x48000000 }, + { 0x0900301c, 0x44000000 }, + { 0x0900301d, 0x58000000 }, + { 0x0980301e, 0x48000001 }, + { 0x09003020, 0x68000000 }, + { 0x16803021, 0x38000008 }, + { 0x1b80302a, 0x30000005 }, + { 0x09003030, 0x44000000 }, + { 0x09803031, 0x18000004 }, + { 0x09803036, 0x68000001 }, + { 0x16803038, 0x38000002 }, + { 0x1600303b, 0x18000000 }, + { 0x0900303c, 0x1c000000 }, + { 0x0900303d, 0x54000000 }, + { 0x0980303e, 0x68000001 }, + { 0x1a803041, 0x1c000055 }, + { 0x1b803099, 0x30000001 }, + { 0x0980309b, 0x60000001 }, + { 0x1a80309d, 0x18000001 }, + { 0x1a00309f, 0x1c000000 }, + { 0x090030a0, 0x44000000 }, + { 0x1d8030a1, 0x1c000059 }, + { 0x090030fb, 0x54000000 }, + { 0x098030fc, 0x18000002 }, + { 0x1d0030ff, 0x1c000000 }, + { 0x03803105, 0x1c000027 }, + { 0x17803131, 0x1c00005d }, + { 0x09803190, 0x68000001 }, + { 0x09803192, 0x3c000003 }, + { 0x09803196, 0x68000009 }, + { 0x038031a0, 0x1c000017 }, + { 0x098031c0, 0x6800000f }, + { 0x1d8031f0, 0x1c00000f }, + { 0x17803200, 0x6800001e }, + { 0x09803220, 0x3c000009 }, + { 0x0980322a, 0x68000019 }, + { 0x09003250, 0x68000000 }, + { 0x09803251, 0x3c00000e }, + { 0x17803260, 0x6800001f }, + { 0x09803280, 0x3c000009 }, + { 0x0980328a, 0x68000026 }, + { 0x098032b1, 0x3c00000e }, + { 0x098032c0, 0x6800003e }, + { 0x09803300, 0x680000ff }, + { 0x16803400, 0x1c0019b5 }, + { 0x09804dc0, 0x6800003f }, + { 0x16804e00, 0x1c0051bb }, + { 0x3c80a000, 0x1c000014 }, + { 0x3c00a015, 0x18000000 }, + { 0x3c80a016, 0x1c000476 }, + { 0x3c80a490, 0x68000036 }, + { 0x0980a700, 0x60000016 }, + { 0x3080a800, 0x1c000001 }, + { 0x3000a802, 0x28000000 }, + { 0x3080a803, 0x1c000002 }, + { 0x3000a806, 0x30000000 }, + { 0x3080a807, 0x1c000003 }, + { 0x3000a80b, 0x30000000 }, + { 0x3080a80c, 0x1c000016 }, + { 0x3080a823, 0x28000001 }, + { 0x3080a825, 0x30000001 }, + { 0x3000a827, 0x28000000 }, + { 0x3080a828, 0x68000003 }, + { 0x1780ac00, 0x1c002ba3 }, + { 0x0980d800, 0x1000037f }, + { 0x0980db80, 0x1000007f }, + { 0x0980dc00, 0x100003ff }, + { 0x0980e000, 0x0c0018ff }, + { 0x1680f900, 0x1c00012d }, + { 0x1680fa30, 0x1c00003a }, + { 0x1680fa70, 0x1c000069 }, + { 0x2180fb00, 0x14000006 }, + { 0x0180fb13, 0x14000004 }, + { 0x1900fb1d, 0x1c000000 }, + { 0x1900fb1e, 0x30000000 }, + { 0x1980fb1f, 0x1c000009 }, + { 0x1900fb29, 0x64000000 }, + { 0x1980fb2a, 0x1c00000c }, + { 0x1980fb38, 0x1c000004 }, + { 0x1900fb3e, 0x1c000000 }, + { 0x1980fb40, 0x1c000001 }, + { 0x1980fb43, 0x1c000001 }, + { 0x1980fb46, 0x1c00006b }, + { 0x0080fbd3, 0x1c00016a }, + { 0x0900fd3e, 0x58000000 }, + { 0x0900fd3f, 0x48000000 }, + { 0x0080fd50, 0x1c00003f }, + { 0x0080fd92, 0x1c000035 }, + { 0x0080fdf0, 0x1c00000b }, + { 0x0000fdfc, 0x5c000000 }, + { 0x0900fdfd, 0x68000000 }, + { 0x1b80fe00, 0x3000000f }, + { 0x0980fe10, 0x54000006 }, + { 0x0900fe17, 0x58000000 }, + { 0x0900fe18, 0x48000000 }, + { 0x0900fe19, 0x54000000 }, + { 0x1b80fe20, 0x30000003 }, + { 0x0900fe30, 0x54000000 }, + { 0x0980fe31, 0x44000001 }, + { 0x0980fe33, 0x40000001 }, + { 0x0900fe35, 0x58000000 }, + { 0x0900fe36, 0x48000000 }, + { 0x0900fe37, 0x58000000 }, + { 0x0900fe38, 0x48000000 }, + { 0x0900fe39, 0x58000000 }, + { 0x0900fe3a, 0x48000000 }, + { 0x0900fe3b, 0x58000000 }, + { 0x0900fe3c, 0x48000000 }, + { 0x0900fe3d, 0x58000000 }, + { 0x0900fe3e, 0x48000000 }, + { 0x0900fe3f, 0x58000000 }, + { 0x0900fe40, 0x48000000 }, + { 0x0900fe41, 0x58000000 }, + { 0x0900fe42, 0x48000000 }, + { 0x0900fe43, 0x58000000 }, + { 0x0900fe44, 0x48000000 }, + { 0x0980fe45, 0x54000001 }, + { 0x0900fe47, 0x58000000 }, + { 0x0900fe48, 0x48000000 }, + { 0x0980fe49, 0x54000003 }, + { 0x0980fe4d, 0x40000002 }, + { 0x0980fe50, 0x54000002 }, + { 0x0980fe54, 0x54000003 }, + { 0x0900fe58, 0x44000000 }, + { 0x0900fe59, 0x58000000 }, + { 0x0900fe5a, 0x48000000 }, + { 0x0900fe5b, 0x58000000 }, + { 0x0900fe5c, 0x48000000 }, + { 0x0900fe5d, 0x58000000 }, + { 0x0900fe5e, 0x48000000 }, + { 0x0980fe5f, 0x54000002 }, + { 0x0900fe62, 0x64000000 }, + { 0x0900fe63, 0x44000000 }, + { 0x0980fe64, 0x64000002 }, + { 0x0900fe68, 0x54000000 }, + { 0x0900fe69, 0x5c000000 }, + { 0x0980fe6a, 0x54000001 }, + { 0x0080fe70, 0x1c000004 }, + { 0x0080fe76, 0x1c000086 }, + { 0x0900feff, 0x04000000 }, + { 0x0980ff01, 0x54000002 }, + { 0x0900ff04, 0x5c000000 }, + { 0x0980ff05, 0x54000002 }, + { 0x0900ff08, 0x58000000 }, + { 0x0900ff09, 0x48000000 }, + { 0x0900ff0a, 0x54000000 }, + { 0x0900ff0b, 0x64000000 }, + { 0x0900ff0c, 0x54000000 }, + { 0x0900ff0d, 0x44000000 }, + { 0x0980ff0e, 0x54000001 }, + { 0x0980ff10, 0x34000009 }, + { 0x0980ff1a, 0x54000001 }, + { 0x0980ff1c, 0x64000002 }, + { 0x0980ff1f, 0x54000001 }, + { 0x2100ff21, 0x24000020 }, + { 0x2100ff22, 0x24000020 }, + { 0x2100ff23, 0x24000020 }, + { 0x2100ff24, 0x24000020 }, + { 0x2100ff25, 0x24000020 }, + { 0x2100ff26, 0x24000020 }, + { 0x2100ff27, 0x24000020 }, + { 0x2100ff28, 0x24000020 }, + { 0x2100ff29, 0x24000020 }, + { 0x2100ff2a, 0x24000020 }, + { 0x2100ff2b, 0x24000020 }, + { 0x2100ff2c, 0x24000020 }, + { 0x2100ff2d, 0x24000020 }, + { 0x2100ff2e, 0x24000020 }, + { 0x2100ff2f, 0x24000020 }, + { 0x2100ff30, 0x24000020 }, + { 0x2100ff31, 0x24000020 }, + { 0x2100ff32, 0x24000020 }, + { 0x2100ff33, 0x24000020 }, + { 0x2100ff34, 0x24000020 }, + { 0x2100ff35, 0x24000020 }, + { 0x2100ff36, 0x24000020 }, + { 0x2100ff37, 0x24000020 }, + { 0x2100ff38, 0x24000020 }, + { 0x2100ff39, 0x24000020 }, + { 0x2100ff3a, 0x24000020 }, + { 0x0900ff3b, 0x58000000 }, + { 0x0900ff3c, 0x54000000 }, + { 0x0900ff3d, 0x48000000 }, + { 0x0900ff3e, 0x60000000 }, + { 0x0900ff3f, 0x40000000 }, + { 0x0900ff40, 0x60000000 }, + { 0x2100ff41, 0x1400ffe0 }, + { 0x2100ff42, 0x1400ffe0 }, + { 0x2100ff43, 0x1400ffe0 }, + { 0x2100ff44, 0x1400ffe0 }, + { 0x2100ff45, 0x1400ffe0 }, + { 0x2100ff46, 0x1400ffe0 }, + { 0x2100ff47, 0x1400ffe0 }, + { 0x2100ff48, 0x1400ffe0 }, + { 0x2100ff49, 0x1400ffe0 }, + { 0x2100ff4a, 0x1400ffe0 }, + { 0x2100ff4b, 0x1400ffe0 }, + { 0x2100ff4c, 0x1400ffe0 }, + { 0x2100ff4d, 0x1400ffe0 }, + { 0x2100ff4e, 0x1400ffe0 }, + { 0x2100ff4f, 0x1400ffe0 }, + { 0x2100ff50, 0x1400ffe0 }, + { 0x2100ff51, 0x1400ffe0 }, + { 0x2100ff52, 0x1400ffe0 }, + { 0x2100ff53, 0x1400ffe0 }, + { 0x2100ff54, 0x1400ffe0 }, + { 0x2100ff55, 0x1400ffe0 }, + { 0x2100ff56, 0x1400ffe0 }, + { 0x2100ff57, 0x1400ffe0 }, + { 0x2100ff58, 0x1400ffe0 }, + { 0x2100ff59, 0x1400ffe0 }, + { 0x2100ff5a, 0x1400ffe0 }, + { 0x0900ff5b, 0x58000000 }, + { 0x0900ff5c, 0x64000000 }, + { 0x0900ff5d, 0x48000000 }, + { 0x0900ff5e, 0x64000000 }, + { 0x0900ff5f, 0x58000000 }, + { 0x0900ff60, 0x48000000 }, + { 0x0900ff61, 0x54000000 }, + { 0x0900ff62, 0x58000000 }, + { 0x0900ff63, 0x48000000 }, + { 0x0980ff64, 0x54000001 }, + { 0x1d80ff66, 0x1c000009 }, + { 0x0900ff70, 0x18000000 }, + { 0x1d80ff71, 0x1c00002c }, + { 0x0980ff9e, 0x18000001 }, + { 0x1780ffa0, 0x1c00001e }, + { 0x1780ffc2, 0x1c000005 }, + { 0x1780ffca, 0x1c000005 }, + { 0x1780ffd2, 0x1c000005 }, + { 0x1780ffda, 0x1c000002 }, + { 0x0980ffe0, 0x5c000001 }, + { 0x0900ffe2, 0x64000000 }, + { 0x0900ffe3, 0x60000000 }, + { 0x0900ffe4, 0x68000000 }, + { 0x0980ffe5, 0x5c000001 }, + { 0x0900ffe8, 0x68000000 }, + { 0x0980ffe9, 0x64000003 }, + { 0x0980ffed, 0x68000001 }, + { 0x0980fff9, 0x04000002 }, + { 0x0980fffc, 0x68000001 }, + { 0x23810000, 0x1c00000b }, + { 0x2381000d, 0x1c000019 }, + { 0x23810028, 0x1c000012 }, + { 0x2381003c, 0x1c000001 }, + { 0x2381003f, 0x1c00000e }, + { 0x23810050, 0x1c00000d }, + { 0x23810080, 0x1c00007a }, + { 0x09810100, 0x54000001 }, + { 0x09010102, 0x68000000 }, + { 0x09810107, 0x3c00002c }, + { 0x09810137, 0x68000008 }, + { 0x13810140, 0x38000034 }, + { 0x13810175, 0x3c000003 }, + { 0x13810179, 0x68000010 }, + { 0x1301018a, 0x3c000000 }, + { 0x29810300, 0x1c00001e }, + { 0x29810320, 0x3c000003 }, + { 0x12810330, 0x1c000019 }, + { 0x1201034a, 0x38000000 }, + { 0x3b810380, 0x1c00001d }, + { 0x3b01039f, 0x54000000 }, + { 0x2a8103a0, 0x1c000023 }, + { 0x2a8103c8, 0x1c000007 }, + { 0x2a0103d0, 0x68000000 }, + { 0x2a8103d1, 0x38000004 }, + { 0x0d010400, 0x24000028 }, + { 0x0d010401, 0x24000028 }, + { 0x0d010402, 0x24000028 }, + { 0x0d010403, 0x24000028 }, + { 0x0d010404, 0x24000028 }, + { 0x0d010405, 0x24000028 }, + { 0x0d010406, 0x24000028 }, + { 0x0d010407, 0x24000028 }, + { 0x0d010408, 0x24000028 }, + { 0x0d010409, 0x24000028 }, + { 0x0d01040a, 0x24000028 }, + { 0x0d01040b, 0x24000028 }, + { 0x0d01040c, 0x24000028 }, + { 0x0d01040d, 0x24000028 }, + { 0x0d01040e, 0x24000028 }, + { 0x0d01040f, 0x24000028 }, + { 0x0d010410, 0x24000028 }, + { 0x0d010411, 0x24000028 }, + { 0x0d010412, 0x24000028 }, + { 0x0d010413, 0x24000028 }, + { 0x0d010414, 0x24000028 }, + { 0x0d010415, 0x24000028 }, + { 0x0d010416, 0x24000028 }, + { 0x0d010417, 0x24000028 }, + { 0x0d010418, 0x24000028 }, + { 0x0d010419, 0x24000028 }, + { 0x0d01041a, 0x24000028 }, + { 0x0d01041b, 0x24000028 }, + { 0x0d01041c, 0x24000028 }, + { 0x0d01041d, 0x24000028 }, + { 0x0d01041e, 0x24000028 }, + { 0x0d01041f, 0x24000028 }, + { 0x0d010420, 0x24000028 }, + { 0x0d010421, 0x24000028 }, + { 0x0d010422, 0x24000028 }, + { 0x0d010423, 0x24000028 }, + { 0x0d010424, 0x24000028 }, + { 0x0d010425, 0x24000028 }, + { 0x0d010426, 0x24000028 }, + { 0x0d010427, 0x24000028 }, + { 0x0d010428, 0x1400ffd8 }, + { 0x0d010429, 0x1400ffd8 }, + { 0x0d01042a, 0x1400ffd8 }, + { 0x0d01042b, 0x1400ffd8 }, + { 0x0d01042c, 0x1400ffd8 }, + { 0x0d01042d, 0x1400ffd8 }, + { 0x0d01042e, 0x1400ffd8 }, + { 0x0d01042f, 0x1400ffd8 }, + { 0x0d010430, 0x1400ffd8 }, + { 0x0d010431, 0x1400ffd8 }, + { 0x0d010432, 0x1400ffd8 }, + { 0x0d010433, 0x1400ffd8 }, + { 0x0d010434, 0x1400ffd8 }, + { 0x0d010435, 0x1400ffd8 }, + { 0x0d010436, 0x1400ffd8 }, + { 0x0d010437, 0x1400ffd8 }, + { 0x0d010438, 0x1400ffd8 }, + { 0x0d010439, 0x1400ffd8 }, + { 0x0d01043a, 0x1400ffd8 }, + { 0x0d01043b, 0x1400ffd8 }, + { 0x0d01043c, 0x1400ffd8 }, + { 0x0d01043d, 0x1400ffd8 }, + { 0x0d01043e, 0x1400ffd8 }, + { 0x0d01043f, 0x1400ffd8 }, + { 0x0d010440, 0x1400ffd8 }, + { 0x0d010441, 0x1400ffd8 }, + { 0x0d010442, 0x1400ffd8 }, + { 0x0d010443, 0x1400ffd8 }, + { 0x0d010444, 0x1400ffd8 }, + { 0x0d010445, 0x1400ffd8 }, + { 0x0d010446, 0x1400ffd8 }, + { 0x0d010447, 0x1400ffd8 }, + { 0x0d010448, 0x1400ffd8 }, + { 0x0d010449, 0x1400ffd8 }, + { 0x0d01044a, 0x1400ffd8 }, + { 0x0d01044b, 0x1400ffd8 }, + { 0x0d01044c, 0x1400ffd8 }, + { 0x0d01044d, 0x1400ffd8 }, + { 0x0d01044e, 0x1400ffd8 }, + { 0x0d01044f, 0x1400ffd8 }, + { 0x2e810450, 0x1c00004d }, + { 0x2c8104a0, 0x34000009 }, + { 0x0b810800, 0x1c000005 }, + { 0x0b010808, 0x1c000000 }, + { 0x0b81080a, 0x1c00002b }, + { 0x0b810837, 0x1c000001 }, + { 0x0b01083c, 0x1c000000 }, + { 0x0b01083f, 0x1c000000 }, + { 0x1e010a00, 0x1c000000 }, + { 0x1e810a01, 0x30000002 }, + { 0x1e810a05, 0x30000001 }, + { 0x1e810a0c, 0x30000003 }, + { 0x1e810a10, 0x1c000003 }, + { 0x1e810a15, 0x1c000002 }, + { 0x1e810a19, 0x1c00001a }, + { 0x1e810a38, 0x30000002 }, + { 0x1e010a3f, 0x30000000 }, + { 0x1e810a40, 0x3c000007 }, + { 0x1e810a50, 0x54000008 }, + { 0x0981d000, 0x680000f5 }, + { 0x0981d100, 0x68000026 }, + { 0x0981d12a, 0x6800003a }, + { 0x0981d165, 0x28000001 }, + { 0x1b81d167, 0x30000002 }, + { 0x0981d16a, 0x68000002 }, + { 0x0981d16d, 0x28000005 }, + { 0x0981d173, 0x04000007 }, + { 0x1b81d17b, 0x30000007 }, + { 0x0981d183, 0x68000001 }, + { 0x1b81d185, 0x30000006 }, + { 0x0981d18c, 0x6800001d }, + { 0x1b81d1aa, 0x30000003 }, + { 0x0981d1ae, 0x6800002f }, + { 0x1381d200, 0x68000041 }, + { 0x1381d242, 0x30000002 }, + { 0x1301d245, 0x68000000 }, + { 0x0981d300, 0x68000056 }, + { 0x0981d400, 0x24000019 }, + { 0x0981d41a, 0x14000019 }, + { 0x0981d434, 0x24000019 }, + { 0x0981d44e, 0x14000006 }, + { 0x0981d456, 0x14000011 }, + { 0x0981d468, 0x24000019 }, + { 0x0981d482, 0x14000019 }, + { 0x0901d49c, 0x24000000 }, + { 0x0981d49e, 0x24000001 }, + { 0x0901d4a2, 0x24000000 }, + { 0x0981d4a5, 0x24000001 }, + { 0x0981d4a9, 0x24000003 }, + { 0x0981d4ae, 0x24000007 }, + { 0x0981d4b6, 0x14000003 }, + { 0x0901d4bb, 0x14000000 }, + { 0x0981d4bd, 0x14000006 }, + { 0x0981d4c5, 0x1400000a }, + { 0x0981d4d0, 0x24000019 }, + { 0x0981d4ea, 0x14000019 }, + { 0x0981d504, 0x24000001 }, + { 0x0981d507, 0x24000003 }, + { 0x0981d50d, 0x24000007 }, + { 0x0981d516, 0x24000006 }, + { 0x0981d51e, 0x14000019 }, + { 0x0981d538, 0x24000001 }, + { 0x0981d53b, 0x24000003 }, + { 0x0981d540, 0x24000004 }, + { 0x0901d546, 0x24000000 }, + { 0x0981d54a, 0x24000006 }, + { 0x0981d552, 0x14000019 }, + { 0x0981d56c, 0x24000019 }, + { 0x0981d586, 0x14000019 }, + { 0x0981d5a0, 0x24000019 }, + { 0x0981d5ba, 0x14000019 }, + { 0x0981d5d4, 0x24000019 }, + { 0x0981d5ee, 0x14000019 }, + { 0x0981d608, 0x24000019 }, + { 0x0981d622, 0x14000019 }, + { 0x0981d63c, 0x24000019 }, + { 0x0981d656, 0x14000019 }, + { 0x0981d670, 0x24000019 }, + { 0x0981d68a, 0x1400001b }, + { 0x0981d6a8, 0x24000018 }, + { 0x0901d6c1, 0x64000000 }, + { 0x0981d6c2, 0x14000018 }, + { 0x0901d6db, 0x64000000 }, + { 0x0981d6dc, 0x14000005 }, + { 0x0981d6e2, 0x24000018 }, + { 0x0901d6fb, 0x64000000 }, + { 0x0981d6fc, 0x14000018 }, + { 0x0901d715, 0x64000000 }, + { 0x0981d716, 0x14000005 }, + { 0x0981d71c, 0x24000018 }, + { 0x0901d735, 0x64000000 }, + { 0x0981d736, 0x14000018 }, + { 0x0901d74f, 0x64000000 }, + { 0x0981d750, 0x14000005 }, + { 0x0981d756, 0x24000018 }, + { 0x0901d76f, 0x64000000 }, + { 0x0981d770, 0x14000018 }, + { 0x0901d789, 0x64000000 }, + { 0x0981d78a, 0x14000005 }, + { 0x0981d790, 0x24000018 }, + { 0x0901d7a9, 0x64000000 }, + { 0x0981d7aa, 0x14000018 }, + { 0x0901d7c3, 0x64000000 }, + { 0x0981d7c4, 0x14000005 }, + { 0x0981d7ce, 0x34000031 }, + { 0x16820000, 0x1c00a6d6 }, + { 0x1682f800, 0x1c00021d }, + { 0x090e0001, 0x04000000 }, + { 0x098e0020, 0x0400005f }, + { 0x1b8e0100, 0x300000ef }, + { 0x098f0000, 0x0c00fffd }, + { 0x09900000, 0x0c00fffd }, +}; diff --git a/js/src/yarr/ASCIICType.h b/js/src/yarr/wtf/ASCIICType.h similarity index 81% rename from js/src/yarr/ASCIICType.h rename to js/src/yarr/wtf/ASCIICType.h index a3ae9f4455e2..cf53d9ac0c87 100644 --- a/js/src/yarr/ASCIICType.h +++ b/js/src/yarr/wtf/ASCIICType.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) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +24,12 @@ * 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. - * - * ***** END LICENSE BLOCK ***** */ + */ #ifndef WTF_ASCIICType_h #define WTF_ASCIICType_h -#include "assembler/wtf/Assertions.h" +#include "yarr/jswtfbridge.h" // The behavior of many of the functions in the header is dependent // on the current locale. But in the WebKit project, all uses of those functions @@ -53,7 +49,6 @@ namespace WTF { inline bool isASCII(wchar_t c) { return !(c & ~0x7F); } #endif inline bool isASCII(int c) { return !(c & ~0x7F); } - inline bool isASCII(unsigned c) { return !(c & ~0x7F); } inline bool isASCIIAlpha(char c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } inline bool isASCIIAlpha(unsigned short c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } @@ -61,7 +56,6 @@ namespace WTF { inline bool isASCIIAlpha(wchar_t c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } #endif inline bool isASCIIAlpha(int c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } - inline bool isASCIIAlpha(unsigned c) { return (c | 0x20) >= 'a' && (c | 0x20) <= 'z'; } inline bool isASCIIAlphanumeric(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIAlphanumeric(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } @@ -69,7 +63,6 @@ namespace WTF { inline bool isASCIIAlphanumeric(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } #endif inline bool isASCIIAlphanumeric(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } - inline bool isASCIIAlphanumeric(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); } inline bool isASCIIDigit(unsigned short c) { return (c >= '0') & (c <= '9'); } @@ -77,7 +70,6 @@ namespace WTF { inline bool isASCIIDigit(wchar_t c) { return (c >= '0') & (c <= '9'); } #endif inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); } - inline bool isASCIIDigit(unsigned c) { return (c >= '0') & (c <= '9'); } inline bool isASCIIHexDigit(char c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } inline bool isASCIIHexDigit(unsigned short c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } @@ -85,7 +77,6 @@ namespace WTF { inline bool isASCIIHexDigit(wchar_t c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } #endif inline bool isASCIIHexDigit(int c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } - inline bool isASCIIHexDigit(unsigned c) { return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } inline bool isASCIIOctalDigit(char c) { return (c >= '0') & (c <= '7'); } inline bool isASCIIOctalDigit(unsigned short c) { return (c >= '0') & (c <= '7'); } @@ -93,7 +84,6 @@ namespace WTF { inline bool isASCIIOctalDigit(wchar_t c) { return (c >= '0') & (c <= '7'); } #endif inline bool isASCIIOctalDigit(int c) { return (c >= '0') & (c <= '7'); } - inline bool isASCIIOctalDigit(unsigned c) { return (c >= '0') & (c <= '7'); } inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; } inline bool isASCIILower(unsigned short c) { return c >= 'a' && c <= 'z'; } @@ -101,7 +91,6 @@ namespace WTF { inline bool isASCIILower(wchar_t c) { return c >= 'a' && c <= 'z'; } #endif inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; } - inline bool isASCIILower(unsigned c) { return c >= 'a' && c <= 'z'; } inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; } inline bool isASCIIUpper(unsigned short c) { return c >= 'A' && c <= 'Z'; } @@ -109,7 +98,6 @@ namespace WTF { inline bool isASCIIUpper(wchar_t c) { return c >= 'A' && c <= 'Z'; } #endif inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; } - inline bool isASCIIUpper(unsigned c) { return c >= 'A' && c <= 'Z'; } /* Statistics from a run of Apple's page load test for callers of isASCIISpace: @@ -130,7 +118,6 @@ namespace WTF { inline bool isASCIISpace(wchar_t c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } #endif inline bool isASCIISpace(int c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } - inline bool isASCIISpace(unsigned c) { return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9)); } inline char toASCIILower(char c) { return c | ((c >= 'A' && c <= 'Z') << 5); } inline unsigned short toASCIILower(unsigned short c) { return c | ((c >= 'A' && c <= 'Z') << 5); } @@ -138,24 +125,20 @@ namespace WTF { inline wchar_t toASCIILower(wchar_t c) { return c | ((c >= 'A' && c <= 'Z') << 5); } #endif inline int toASCIILower(int c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - inline unsigned toASCIILower(unsigned c) { return c | ((c >= 'A' && c <= 'Z') << 5); } - // FIXME: Why do these need static_cast? inline char toASCIIUpper(char c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } inline unsigned short toASCIIUpper(unsigned short c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) inline wchar_t toASCIIUpper(wchar_t c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } #endif inline int toASCIIUpper(int c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline unsigned toASCIIUpper(unsigned c) { return static_cast(c & ~((c >= 'a' && c <= 'z') << 5)); } - inline int toASCIIHexValue(char c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned short c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(char c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(unsigned short c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } #if !WTF_COMPILER_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - inline int toASCIIHexValue(wchar_t c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(wchar_t c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } #endif - inline int toASCIIHexValue(int c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } - inline int toASCIIHexValue(unsigned c) { ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } + inline int toASCIIHexValue(int c) { JS_ASSERT(isASCIIHexDigit(c)); return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF; } inline bool isASCIIPrintable(char c) { return c >= ' ' && c <= '~'; } inline bool isASCIIPrintable(unsigned short c) { return c >= ' ' && c <= '~'; } @@ -163,7 +146,7 @@ namespace WTF { inline bool isASCIIPrintable(wchar_t c) { return c >= ' ' && c <= '~'; } #endif inline bool isASCIIPrintable(int c) { return c >= ' ' && c <= '~'; } - inline bool isASCIIPrintable(unsigned c) { return c >= ' ' && c <= '~'; } + } using WTF::isASCII; diff --git a/js/src/yarr/wtfbridge.h b/js/src/yarr/wtfbridge.h deleted file mode 100644 index 25a4bc5ee3d9..000000000000 --- a/js/src/yarr/wtfbridge.h +++ /dev/null @@ -1,321 +0,0 @@ -/* -*- 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 ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released - * June 12, 2009. - * - * The Initial Developer of the Original Code is - * the Mozilla Corporation. - * - * Contributor(s): - * David Mandelin - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jswtfbridge_h__ -#define jswtfbridge_h__ - -/* - * WTF compatibility layer. This file provides various type and data - * definitions for use by Yarr. - */ - -#include "jsstr.h" -#include "jsprvtd.h" -#include "jstl.h" -#include "assembler/wtf/Platform.h" -#include "assembler/jit/ExecutableAllocator.h" - -namespace JSC { namespace Yarr { - -/* - * Basic type definitions. - */ - -typedef jschar UChar; -typedef JSLinearString UString; - -class Unicode { - public: - static UChar toUpper(UChar c) { return JS_TOUPPER(c); } - static UChar toLower(UChar c) { return JS_TOLOWER(c); } -}; - -/* - * Do-nothing smart pointer classes. These have a compatible interface - * with the smart pointers used by Yarr, but they don't actually do - * reference counting. - */ -template -class RefCounted { -}; - -template -class RefPtr { - T *ptr; - public: - RefPtr(T *p) { ptr = p; } - operator bool() const { return ptr != NULL; } - const T *operator ->() const { return ptr; } - T *get() { return ptr; } -}; - -template -class PassRefPtr { - T *ptr; - public: - PassRefPtr(T *p) { ptr = p; } - operator T*() { return ptr; } -}; - -template -class PassOwnPtr { - T *ptr; - public: - PassOwnPtr(T *p) { ptr = p; } - - T *get() { return ptr; } -}; - -template -class OwnPtr { - T *ptr; - public: - OwnPtr() : ptr(NULL) { } - OwnPtr(PassOwnPtr p) : ptr(p.get()) { } - - ~OwnPtr() { - if (ptr) - js::Foreground::delete_(ptr); - } - - OwnPtr &operator=(PassOwnPtr p) { - ptr = p.get(); - return *this; - } - - T *operator ->() { return ptr; } - - T *get() { return ptr; } - - T *release() { - T *result = ptr; - ptr = NULL; - return result; - } -}; - -template -PassRefPtr adoptRef(T *p) { return PassRefPtr(p); } - -template -PassOwnPtr adoptPtr(T *p) { return PassOwnPtr(p); } - -#define WTF_MAKE_FAST_ALLOCATED - -/* - * Vector class for Yarr. This wraps js::Vector and provides all - * the API method signatures used by Yarr. - */ -template -class Vector { - public: - js::Vector impl; - public: - Vector() {} - - Vector(const Vector &v) { - // XXX yarr-oom - (void) append(v); - } - - size_t size() const { - return impl.length(); - } - - T &operator[](size_t i) { - return impl[i]; - } - - const T &operator[](size_t i) const { - return impl[i]; - } - - T &at(size_t i) { - return impl[i]; - } - - const T *begin() const { - return impl.begin(); - } - - T &last() { - return impl.back(); - } - - bool isEmpty() const { - return impl.empty(); - } - - template - void append(const U &u) { - // XXX yarr-oom - (void) impl.append(static_cast(u)); - } - - template - void append(const Vector &v) { - // XXX yarr-oom - (void) impl.append(v.impl); - } - - void insert(size_t i, const T& t) { - // XXX yarr-oom - (void) impl.insert(&impl[i], t); - } - - void remove(size_t i) { - impl.erase(&impl[i]); - } - - void clear() { - return impl.clear(); - } - - void shrink(size_t newLength) { - // XXX yarr-oom - JS_ASSERT(newLength <= impl.length()); - (void) impl.resize(newLength); - } - - void deleteAllValues() { - for (T *p = impl.begin(); p != impl.end(); ++p) - js::Foreground::delete_(*p); - } -}; - -template -class Vector > { - public: - js::Vector impl; - public: - Vector() {} - - size_t size() const { - return impl.length(); - } - - void append(T *t) { - // XXX yarr-oom - (void) impl.append(t); - } - - PassOwnPtr operator[](size_t i) { - return PassOwnPtr(impl[i]); - } - - void clear() { - for (T **p = impl.begin(); p != impl.end(); ++p) - js::Foreground::delete_(*p); - return impl.clear(); - } -}; - -template -inline void -deleteAllValues(Vector &v) { - v.deleteAllValues(); -} - -/* - * Minimal JSGlobalData. This used by Yarr to get the allocator. - */ -class JSGlobalData { - public: - ExecutableAllocator *regexAllocator; - - JSGlobalData(ExecutableAllocator *regexAllocator) - : regexAllocator(regexAllocator) { } -}; - -/* - * Sentinel value used in Yarr. - */ -const size_t notFound = size_t(-1); - - /* - * Do-nothing version of a macro used by WTF to avoid unused - * parameter warnings. - */ -#define UNUSED_PARAM(e) - -} /* namespace Yarr */ - -/* - * Replacements for std:: functions used in Yarr. We put them in - * namespace JSC::std so that they can still be called as std::X - * in Yarr. - */ -namespace std { - -/* - * windows.h defines a 'min' macro that would mangle the function - * name. - */ -#if WTF_COMPILER_MSVC -# undef min -# undef max -#endif - -template -inline T -min(T t1, T t2) -{ - return JS_MIN(t1, t2); -} - -template -inline T -max(T t1, T t2) -{ - return JS_MAX(t1, t2); -} - -template -inline void -swap(T &t1, T &t2) -{ - T tmp = t1; - t1 = t2; - t2 = tmp; -} -} /* namespace std */ - -} /* namespace JSC */ - -#endif diff --git a/js/src/yarr/RegExpJitTables.h b/js/src/yarr/yarr/RegExpJitTables.h similarity index 100% rename from js/src/yarr/RegExpJitTables.h rename to js/src/yarr/yarr/RegExpJitTables.h diff --git a/js/src/yarr/YarrSyntaxChecker.cpp b/js/src/yarr/yarr/RegexCommon.h similarity index 52% rename from js/src/yarr/YarrSyntaxChecker.cpp rename to js/src/yarr/yarr/RegexCommon.h index f36ac5a3f5bc..3ae337ea62cc 100644 --- a/js/src/yarr/YarrSyntaxChecker.cpp +++ b/js/src/yarr/yarr/RegexCommon.h @@ -1,8 +1,5 @@ -/* -*- 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) 2011 Apple Inc. All rights reserved. +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,39 +21,30 @@ * 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 ***** */ + */ -#include "YarrSyntaxChecker.h" - -#include "YarrParser.h" +#ifndef RegexCommon_h +#define RegexCommon_h namespace JSC { namespace Yarr { -class SyntaxChecker { -public: - void assertionBOL() {} - void assertionEOL() {} - void assertionWordBoundary(bool) {} - void atomPatternCharacter(UChar) {} - void atomBuiltInCharacterClass(BuiltInCharacterClassID, bool) {} - void atomCharacterClassBegin(bool = false) {} - void atomCharacterClassAtom(UChar) {} - void atomCharacterClassRange(UChar, UChar) {} - void atomCharacterClassBuiltIn(BuiltInCharacterClassID, bool) {} - void atomCharacterClassEnd() {} - void atomParenthesesSubpatternBegin(bool = true) {} - void atomParentheticalAssertionBegin(bool = false) {} - void atomParenthesesEnd() {} - void atomBackReference(unsigned) {} - void quantifyAtom(unsigned, unsigned, bool) {} - void disjunction() {} +enum ErrorCode { + HitRecursionLimit = -2, + NoError = 0, + PatternTooLarge, + QuantifierOutOfOrder, + QuantifierWithoutAtom, + MissingParentheses, + ParenthesesUnmatched, + ParenthesesTypeInvalid, + CharacterClassUnmatched, + CharacterClassOutOfOrder, + CharacterClassRangeSingleChar, + EscapeUnterminated, + QuantifierTooLarge, + NumberOfErrorCodes }; -ErrorCode checkSyntax(const UString& pattern) -{ - SyntaxChecker syntaxChecker; - return parse(syntaxChecker, pattern); -} +}} -}} // JSC::YARR +#endif diff --git a/js/src/yarr/YarrPattern.cpp b/js/src/yarr/yarr/RegexCompiler.cpp similarity index 52% rename from js/src/yarr/YarrPattern.cpp rename to js/src/yarr/yarr/RegexCompiler.cpp index 10b7d8911987..9b60cbd4a78b 100644 --- a/js/src/yarr/YarrPattern.cpp +++ b/js/src/yarr/yarr/RegexCompiler.cpp @@ -1,9 +1,5 @@ -/* -*- 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 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,13 +21,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 ***** */ + */ -#include "YarrPattern.h" +#include "jsinttypes.h" +#include "RegexCompiler.h" -#include "Yarr.h" -#include "YarrParser.h" +#include "RegexPattern.h" using namespace WTF; @@ -39,6 +34,12 @@ namespace JSC { namespace Yarr { #include "RegExpJitTables.h" +#if WTF_CPU_SPARC +#define BASE_FRAME_SIZE 24 +#else +#define BASE_FRAME_SIZE 0 +#endif + class CharacterClassConstructor { public: CharacterClassConstructor(bool isCaseInsensitive = false) @@ -56,13 +57,13 @@ public: void append(const CharacterClass* other) { - for (size_t i = 0; i < other->m_matches.size(); ++i) + for (size_t i = 0; i < other->m_matches.length(); ++i) addSorted(m_matches, other->m_matches[i]); - for (size_t i = 0; i < other->m_ranges.size(); ++i) + for (size_t i = 0; i < other->m_ranges.length(); ++i) addSortedRange(m_ranges, other->m_ranges[i].begin, other->m_ranges[i].end); - for (size_t i = 0; i < other->m_matchesUnicode.size(); ++i) + for (size_t i = 0; i < other->m_matchesUnicode.length(); ++i) addSorted(m_matchesUnicode, other->m_matchesUnicode[i]); - for (size_t i = 0; i < other->m_rangesUnicode.size(); ++i) + for (size_t i = 0; i < other->m_rangesUnicode.length(); ++i) addSortedRange(m_rangesUnicode, other->m_rangesUnicode[i].begin, other->m_rangesUnicode[i].end); } @@ -100,18 +101,18 @@ public: { if (lo <= 0x7f) { char asciiLo = lo; - char asciiHi = std::min(hi, (UChar)0x7f); + char asciiHi = JS_MIN(hi, (UChar)0x7f); addSortedRange(m_ranges, lo, asciiHi); if (m_isCaseInsensitive) { if ((asciiLo <= 'Z') && (asciiHi >= 'A')) - addSortedRange(m_ranges, std::max(asciiLo, 'A')+('a'-'A'), std::min(asciiHi, 'Z')+('a'-'A')); + addSortedRange(m_ranges, JS_MAX(asciiLo, 'A')+('a'-'A'), JS_MIN(asciiHi, 'Z')+('a'-'A')); if ((asciiLo <= 'z') && (asciiHi >= 'a')) - addSortedRange(m_ranges, std::max(asciiLo, 'a')+('A'-'a'), std::min(asciiHi, 'z')+('A'-'a')); + addSortedRange(m_ranges, JS_MAX(asciiLo, 'a')+('A'-'a'), JS_MIN(asciiHi, 'z')+('A'-'a')); } } if (hi >= 0x80) { - uint32_t unicodeCurr = std::max(lo, (UChar)0x80); + uint32 unicodeCurr = JS_MAX(lo, (UChar)0x80); addSortedRange(m_rangesUnicode, unicodeCurr, hi); if (m_isCaseInsensitive) { @@ -121,7 +122,7 @@ public: // (if so we won't re-enter the loop, since the loop condition above // will definitely fail) - but this does mean we cannot use a UChar // to represent unicodeCurr, we must use a 32-bit value instead. - ASSERT(unicodeCurr <= 0xffff); + JS_ASSERT(unicodeCurr <= 0xffff); if (isUnicodeUpper(unicodeCurr)) { UChar lowerCaseRangeBegin = Unicode::toLower(unicodeCurr); @@ -144,7 +145,8 @@ public: CharacterClass* charClass() { - CharacterClass* characterClass = js::OffTheBooks::new_(PassRefPtr(0)); + // FIXME: bug 574459 -- no NULL check + CharacterClass* characterClass = js::OffTheBooks::new_((CharacterClassTable*)NULL); characterClass->m_matches.append(m_matches); characterClass->m_ranges.append(m_ranges); @@ -157,10 +159,12 @@ public: } private: - void addSorted(Vector& matches, UChar ch) + typedef js::Vector UChars; + typedef js::Vector CharacterRanges; + void addSorted(UChars& matches, UChar ch) { unsigned pos = 0; - unsigned range = matches.size(); + unsigned range = matches.length(); // binary chop, find position to insert char. while (range) { @@ -177,15 +181,15 @@ private: } } - if (pos == matches.size()) + if (pos == matches.length()) matches.append(ch); else - matches.insert(pos, ch); + matches.insert(matches.begin() + pos, ch); } - void addSortedRange(Vector& ranges, UChar lo, UChar hi) + void addSortedRange(CharacterRanges& ranges, UChar lo, UChar hi) { - unsigned end = ranges.size(); + unsigned end = ranges.length(); // Simple linear scan - I doubt there are that many ranges anyway... // feel free to fix this with something faster (eg binary chop). @@ -197,7 +201,7 @@ private: ranges[i].begin = lo; return; } - ranges.insert(i, CharacterRange(lo, hi)); + ranges.insert(ranges.begin() + i, CharacterRange(lo, hi)); return; } // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining @@ -205,17 +209,17 @@ private: // end of the last range they concatenate, which is just as good. if (lo <= (ranges[i].end + 1)) { // found an intersect! we'll replace this entry in the array. - ranges[i].begin = std::min(ranges[i].begin, lo); - ranges[i].end = std::max(ranges[i].end, hi); + ranges[i].begin = JS_MIN(ranges[i].begin, lo); + ranges[i].end = JS_MAX(ranges[i].end, hi); // now check if the new range can subsume any subsequent ranges. unsigned next = i+1; // each iteration of the loop we will either remove something from the list, or break the loop. - while (next < ranges.size()) { + while (next < ranges.length()) { if (ranges[next].begin <= (ranges[i].end + 1)) { // the next entry now overlaps / concatenates this one. - ranges[i].end = std::max(ranges[i].end, ranges[next].end); - ranges.remove(next); + ranges[i].end = JS_MAX(ranges[i].end, ranges[next].end); + ranges.erase(ranges.begin() + next); } else break; } @@ -230,131 +234,21 @@ private: bool m_isCaseInsensitive; - Vector m_matches; - Vector m_ranges; - Vector m_matchesUnicode; - Vector m_rangesUnicode; + UChars m_matches; + CharacterRanges m_ranges; + UChars m_matchesUnicode; + CharacterRanges m_rangesUnicode; }; -struct BeginCharHelper { - BeginCharHelper(Vector* beginChars, bool isCaseInsensitive = false) - : m_beginChars(beginChars) - , m_isCaseInsensitive(isCaseInsensitive) - {} - - void addBeginChar(BeginChar beginChar, Vector* hotTerms, QuantifierType quantityType, unsigned quantityCount) - { - if (quantityType == QuantifierFixedCount && quantityCount > 1) { - // We duplicate the first found character if the quantity of the term is more than one. eg.: /a{3}/ - beginChar.value |= beginChar.value << 16; - beginChar.mask |= beginChar.mask << 16; - addCharacter(beginChar); - } else if (quantityType == QuantifierFixedCount && quantityCount == 1 && hotTerms->size()) - // In case of characters with fixed quantifier we should check the next character as well. - linkHotTerms(beginChar, hotTerms); - else - // In case of greedy matching the next character checking is unnecessary therefore we just store - // the first character. - addCharacter(beginChar); - } - - // Merge two following BeginChars in the vector to reduce the number of character checks. - void merge(unsigned size) - { - for (unsigned i = 0; i < size; i++) { - BeginChar* curr = &m_beginChars->at(i); - BeginChar* next = &m_beginChars->at(i + 1); - - // If the current and the next size of value is different we should skip the merge process - // because the 16bit and 32bit values are unmergable. - if (curr->value <= 0xFFFF && next->value > 0xFFFF) - continue; - - unsigned diff = curr->value ^ next->value; - - curr->mask |= diff; - curr->value |= curr->mask; - - m_beginChars->remove(i + 1); - size--; - } - } - -private: - void addCharacter(BeginChar beginChar) - { - unsigned pos = 0; - unsigned range = m_beginChars->size(); - - // binary chop, find position to insert char. - while (range) { - unsigned index = range >> 1; - - int val = m_beginChars->at(pos+index).value - beginChar.value; - if (!val) - return; - if (val < 0) - range = index; - else { - pos += (index+1); - range -= (index+1); - } - } - - if (pos == m_beginChars->size()) - m_beginChars->append(beginChar); - else - m_beginChars->insert(pos, beginChar); - } - - // Create BeginChar objects by appending each terms from a hotTerms vector to an existing BeginChar object. - void linkHotTerms(BeginChar beginChar, Vector* hotTerms) - { - for (unsigned i = 0; i < hotTerms->size(); i++) { - PatternTerm hotTerm = hotTerms->at(i).term; - ASSERT(hotTerm.type == PatternTerm::TypePatternCharacter); - - UChar characterNext = hotTerm.patternCharacter; - - // Append a character to an existing BeginChar object. - if (characterNext <= 0x7f) { - unsigned mask = 0; - - if (m_isCaseInsensitive && isASCIIAlpha(characterNext)) { - mask = 32; - characterNext = toASCIILower(characterNext); - } - - addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask | (mask << 16))); - } else { - UChar upper, lower; - if (m_isCaseInsensitive && ((upper = Unicode::toUpper(characterNext)) != (lower = Unicode::toLower(characterNext)))) { - addCharacter(BeginChar(beginChar.value | (upper << 16), beginChar.mask)); - addCharacter(BeginChar(beginChar.value | (lower << 16), beginChar.mask)); - } else - addCharacter(BeginChar(beginChar.value | (characterNext << 16), beginChar.mask)); - } - } - } - - Vector* m_beginChars; - bool m_isCaseInsensitive; -}; - -class YarrPatternConstructor { +class RegexPatternConstructor { public: - YarrPatternConstructor(YarrPattern& pattern) + RegexPatternConstructor(RegexPattern& pattern) : m_pattern(pattern) , m_characterClassConstructor(pattern.m_ignoreCase) - , m_beginCharHelper(&pattern.m_beginChars, pattern.m_ignoreCase) - , m_invertParentheticalAssertion(false) { - m_pattern.m_body = js::OffTheBooks::new_(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); } - ~YarrPatternConstructor() + ~RegexPatternConstructor() { } @@ -362,19 +256,10 @@ public: { m_pattern.reset(); m_characterClassConstructor.reset(); - - m_pattern.m_body = js::OffTheBooks::new_(); - m_alternative = m_pattern.m_body->addNewAlternative(); - m_pattern.m_disjunctions.append(m_pattern.m_body); } void assertionBOL() { - if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) { - m_alternative->m_startsWithBOL = true; - m_alternative->m_containsBOL = true; - m_pattern.m_containsBOL = true; - } m_alternative->m_terms.append(PatternTerm::BOL()); } void assertionEOL() @@ -433,7 +318,7 @@ public: void atomCharacterClassBuiltIn(BuiltInCharacterClassID classID, bool invert) { - ASSERT(classID != NewlineClassID); + JS_ASSERT(classID != NewlineClassID); switch (classID) { case DigitClassID: @@ -449,7 +334,7 @@ public: break; default: - ASSERT_NOT_REACHED(); + JS_NOT_REACHED("Invalid character class."); } } @@ -466,56 +351,36 @@ public: if (capture) m_pattern.m_numSubpatterns++; + // FIXME: bug 574459 -- no NULL check PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative); m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture, false)); + m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, capture)); m_alternative = parenthesesDisjunction->addNewAlternative(); } void atomParentheticalAssertionBegin(bool invert = false) { + // FIXME: bug 574459 -- no NULL check PatternDisjunction* parenthesesDisjunction = js::OffTheBooks::new_(m_alternative); m_pattern.m_disjunctions.append(parenthesesDisjunction); - m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, false, invert)); + m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert)); m_alternative = parenthesesDisjunction->addNewAlternative(); - m_invertParentheticalAssertion = invert; } void atomParenthesesEnd() { - ASSERT(m_alternative->m_parent); - ASSERT(m_alternative->m_parent->m_parent); - - PatternDisjunction* parenthesesDisjunction = m_alternative->m_parent; + JS_ASSERT(m_alternative->m_parent); + JS_ASSERT(m_alternative->m_parent->m_parent); m_alternative = m_alternative->m_parent->m_parent; - - PatternTerm& lastTerm = m_alternative->lastTerm(); - - unsigned numParenAlternatives = parenthesesDisjunction->m_alternatives.size(); - unsigned numBOLAnchoredAlts = 0; - - for (unsigned i = 0; i < numParenAlternatives; i++) { - // Bubble up BOL flags - if (parenthesesDisjunction->m_alternatives[i]->m_startsWithBOL) - numBOLAnchoredAlts++; - } - - if (numBOLAnchoredAlts) { - m_alternative->m_containsBOL = true; - // If all the alternatives in parens start with BOL, then so does this one - if (numBOLAnchoredAlts == numParenAlternatives) - m_alternative->m_startsWithBOL = true; - } - - lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; - m_invertParentheticalAssertion = false; + + m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns; } void atomBackReference(unsigned subpatternId) { - ASSERT(subpatternId); + JS_ASSERT(subpatternId); m_pattern.m_containsBackreferences = true; - m_pattern.m_maxBackReference = std::max(m_pattern.m_maxBackReference, subpatternId); + m_pattern.m_maxBackReference = JS_MAX(m_pattern.m_maxBackReference, subpatternId); if (subpatternId > m_pattern.m_numSubpatterns) { m_alternative->m_terms.append(PatternTerm::ForwardReference()); @@ -523,14 +388,14 @@ public: } PatternAlternative* currentAlternative = m_alternative; - ASSERT(currentAlternative); + JS_ASSERT(currentAlternative); // Note to self: if we waited until the AST was baked, we could also remove forwards refs while ((currentAlternative = currentAlternative->m_parent->m_parent)) { PatternTerm& term = currentAlternative->lastTerm(); - ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); + JS_ASSERT((term.type == PatternTerm::TypeParenthesesSubpattern) || (term.type == PatternTerm::TypeParentheticalAssertion)); - if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.capture() && (subpatternId == term.parentheses.subpatternId)) { + if ((term.type == PatternTerm::TypeParenthesesSubpattern) && term.invertOrCapture && (subpatternId == term.subpatternId)) { m_alternative->m_terms.append(PatternTerm::ForwardReference()); return; } @@ -539,43 +404,37 @@ public: m_alternative->m_terms.append(PatternTerm(subpatternId)); } - // deep copy the argument disjunction. If filterStartsWithBOL is true, - // skip alternatives with m_startsWithBOL set true. - PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false) + PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction) { - PatternDisjunction* newDisjunction = 0; - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + // FIXME: bug 574459 -- no NULL check + PatternDisjunction* newDisjunction = js::OffTheBooks::new_(); + + newDisjunction->m_parent = disjunction->m_parent; + for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) { PatternAlternative* alternative = disjunction->m_alternatives[alt]; - if (!filterStartsWithBOL || !alternative->m_startsWithBOL) { - if (!newDisjunction) { - newDisjunction = new PatternDisjunction(); - newDisjunction->m_parent = disjunction->m_parent; - } - PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) - newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL)); - } + PatternAlternative* newAlternative = newDisjunction->addNewAlternative(); + for (unsigned i = 0; i < alternative->m_terms.length(); ++i) + newAlternative->m_terms.append(copyTerm(alternative->m_terms[i])); } - - if (newDisjunction) - m_pattern.m_disjunctions.append(newDisjunction); + + m_pattern.m_disjunctions.append(newDisjunction); return newDisjunction; } - - PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false) + + PatternTerm copyTerm(PatternTerm& term) { if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion)) return PatternTerm(term); - + PatternTerm termCopy = term; - termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL); + termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction); return termCopy; } - + void quantifyAtom(unsigned min, unsigned max, bool greedy) { - ASSERT(min <= max); - ASSERT(m_alternative->m_terms.size()); + JS_ASSERT(min <= max); + JS_ASSERT(m_alternative->m_terms.length()); if (!max) { m_alternative->removeLastTerm(); @@ -583,8 +442,8 @@ public: } PatternTerm& term = m_alternative->lastTerm(); - ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); - ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); + JS_ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary); + JS_ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount)); // For any assertion with a zero minimum, not matching is valid and has no effect, // remove it. Otherwise, we need to match as least once, but there is no point @@ -605,7 +464,7 @@ public: term.quantify(min, QuantifierFixedCount); m_alternative->m_terms.append(copyTerm(term)); // NOTE: this term is interesting from an analysis perspective, in that it can be ignored..... - m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); + m_alternative->lastTerm().quantify((max == UINT_MAX) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy); if (m_alternative->lastTerm().type == PatternTerm::TypeParenthesesSubpattern) m_alternative->lastTerm().parentheses.isCopy = true; } @@ -616,12 +475,26 @@ public: m_alternative = m_alternative->m_parent->addNewAlternative(); } + void regexBegin() + { + // FIXME: bug 574459 -- no NULL check + m_pattern.m_body = js::OffTheBooks::new_(); + m_alternative = m_pattern.m_body->addNewAlternative(); + m_pattern.m_disjunctions.append(m_pattern.m_body); + } + void regexEnd() + { + } + void regexError() + { + } + unsigned setupAlternativeOffsets(PatternAlternative* alternative, unsigned currentCallFrameSize, unsigned initialInputPosition) { alternative->m_hasFixedSize = true; unsigned currentInputPosition = initialInputPosition; - for (unsigned i = 0; i < alternative->m_terms.size(); ++i) { + for (unsigned i = 0; i < alternative->m_terms.length(); ++i) { PatternTerm& term = alternative->m_terms[i]; switch (term.type) { @@ -634,7 +507,7 @@ public: case PatternTerm::TypeBackReference: term.inputPosition = currentInputPosition; term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoBackReference; alternative->m_hasFixedSize = false; break; @@ -645,7 +518,7 @@ public: term.inputPosition = currentInputPosition; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoPatternCharacter; alternative->m_hasFixedSize = false; } else currentInputPosition += term.quantityCount; @@ -655,7 +528,7 @@ public: term.inputPosition = currentInputPosition; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; - currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoCharacterClass; alternative->m_hasFixedSize = false; } else currentInputPosition += term.quantityCount; @@ -666,20 +539,20 @@ public: term.frameLocation = currentCallFrameSize; if (term.quantityCount == 1 && !term.parentheses.isCopy) { if (term.quantityType != QuantifierFixedCount) - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesOnce; currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition); // If quantity is fixed, then pre-check its minimum size. if (term.quantityType == QuantifierFixedCount) currentInputPosition += term.parentheses.disjunction->m_minimumSize; term.inputPosition = currentInputPosition; } else if (term.parentheses.isTerminal) { - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParenthesesTerminal; currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition); term.inputPosition = currentInputPosition; } else { term.inputPosition = currentInputPosition; setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition); - currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses; + currentCallFrameSize += RegexStackSpaceForBackTrackInfoParentheses; } // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length. alternative->m_hasFixedSize = false; @@ -688,7 +561,7 @@ public: case PatternTerm::TypeParentheticalAssertion: term.inputPosition = currentInputPosition; term.frameLocation = currentCallFrameSize; - currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition); + currentCallFrameSize = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + RegexStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition); break; } } @@ -699,23 +572,23 @@ public: unsigned setupDisjunctionOffsets(PatternDisjunction* disjunction, unsigned initialCallFrameSize, unsigned initialInputPosition) { - if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.size() > 1)) - initialCallFrameSize += YarrStackSpaceForBackTrackInfoAlternative; + if ((disjunction != m_pattern.m_body) && (disjunction->m_alternatives.length() > 1)) + initialCallFrameSize += RegexStackSpaceForBackTrackInfoAlternative; unsigned minimumInputSize = UINT_MAX; unsigned maximumCallFrameSize = 0; bool hasFixedSize = true; - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { + for (unsigned alt = 0; alt < disjunction->m_alternatives.length(); ++alt) { PatternAlternative* alternative = disjunction->m_alternatives[alt]; unsigned currentAlternativeCallFrameSize = setupAlternativeOffsets(alternative, initialCallFrameSize, initialInputPosition); - minimumInputSize = std::min(minimumInputSize, alternative->m_minimumSize); - maximumCallFrameSize = std::max(maximumCallFrameSize, currentAlternativeCallFrameSize); + minimumInputSize = JS_MIN(minimumInputSize, alternative->m_minimumSize); + maximumCallFrameSize = JS_MAX(maximumCallFrameSize, currentAlternativeCallFrameSize); hasFixedSize &= alternative->m_hasFixedSize; } - ASSERT(minimumInputSize != UINT_MAX); - ASSERT(maximumCallFrameSize >= initialCallFrameSize); + JS_ASSERT(minimumInputSize != UINT_MAX); + JS_ASSERT(maximumCallFrameSize >= initialCallFrameSize); disjunction->m_hasFixedSize = hasFixedSize; disjunction->m_minimumSize = minimumInputSize; @@ -725,14 +598,13 @@ public: void setupOffsets() { - setupDisjunctionOffsets(m_pattern.m_body, 0, 0); + setupDisjunctionOffsets(m_pattern.m_body, BASE_FRAME_SIZE, 0); } // This optimization identifies sets of parentheses that we will never need to backtrack. // In these cases we do not need to store state from prior iterations. // We can presently avoid backtracking for: - // * where the parens are at the end of the regular expression (last term in any of the - // alternatives of the main body disjunction). + // * a set of parens at the end of the regular expression (last term in any of the alternatives of the main body disjunction). // * where the parens are non-capturing, and quantified unbounded greedy (*). // * where the parens do not contain any capturing subpatterns. void checkForTerminalParentheses() @@ -742,239 +614,57 @@ public: if (m_pattern.m_numSubpatterns) return; - Vector& alternatives = m_pattern.m_body->m_alternatives; - for (size_t i = 0; i < alternatives.size(); ++i) { - Vector& terms = alternatives[i]->m_terms; - if (terms.size()) { - PatternTerm& term = terms.last(); + js::Vector& alternatives = m_pattern.m_body->m_alternatives; + for (unsigned i =0; i < alternatives.length(); ++i) { + js::Vector& terms = alternatives[i]->m_terms; + if (terms.length()) { + PatternTerm& term = terms.back(); if (term.type == PatternTerm::TypeParenthesesSubpattern && term.quantityType == QuantifierGreedy - && term.quantityCount == quantifyInfinite + && term.quantityCount == UINT_MAX && !term.capture()) term.parentheses.isTerminal = true; } } } - void optimizeBOL() - { - // Look for expressions containing beginning of line (^) anchoring and unroll them. - // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops - // This code relies on the parsing code tagging alternatives with m_containsBOL and - // m_startsWithBOL and rolling those up to containing alternatives. - // At this point, this is only valid for non-multiline expressions. - PatternDisjunction* disjunction = m_pattern.m_body; - - if (!m_pattern.m_containsBOL || m_pattern.m_multiline) - return; - - PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true); - - // Set alternatives in disjunction to "onceThrough" - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) - disjunction->m_alternatives[alt]->setOnceThrough(); - - if (loopDisjunction) { - // Move alternatives from loopDisjunction to disjunction - for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt) - disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]); - - loopDisjunction->m_alternatives.clear(); - } - } - - // This function collects the terms which are potentially matching the first number of depth characters in the result. - // If this function returns false then it found at least one term which makes the beginning character - // look-up optimization inefficient. - bool setupDisjunctionBeginTerms(PatternDisjunction* disjunction, Vector* beginTerms, unsigned depth) - { - for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { - PatternAlternative* alternative = disjunction->m_alternatives[alt]; - - if (!setupAlternativeBeginTerms(alternative, beginTerms, 0, depth)) - return false; - } - - return true; - } - - bool setupAlternativeBeginTerms(PatternAlternative* alternative, Vector* beginTerms, unsigned termIndex, unsigned depth) - { - bool checkNext = true; - unsigned numTerms = alternative->m_terms.size(); - - while (checkNext && termIndex < numTerms) { - PatternTerm term = alternative->m_terms[termIndex]; - checkNext = false; - - switch (term.type) { - case PatternTerm::TypeAssertionBOL: - case PatternTerm::TypeAssertionEOL: - case PatternTerm::TypeAssertionWordBoundary: - return false; - - case PatternTerm::TypeBackReference: - case PatternTerm::TypeForwardReference: - return false; - - case PatternTerm::TypePatternCharacter: - if (termIndex != numTerms - 1) { - beginTerms->append(TermChain(term)); - termIndex++; - checkNext = true; - } else if (term.quantityType == QuantifierFixedCount) { - beginTerms->append(TermChain(term)); - if (depth < 2 && termIndex < numTerms - 1 && term.quantityCount == 1) - if (!setupAlternativeBeginTerms(alternative, &beginTerms->last().hotTerms, termIndex + 1, depth + 1)) - return false; - } - - break; - - case PatternTerm::TypeCharacterClass: - return false; - - case PatternTerm::TypeParentheticalAssertion: - if (term.invert()) - return false; - - case PatternTerm::TypeParenthesesSubpattern: - if (term.quantityType != QuantifierFixedCount) { - if (termIndex == numTerms - 1) - break; - - termIndex++; - checkNext = true; - } - - if (!setupDisjunctionBeginTerms(term.parentheses.disjunction, beginTerms, depth)) - return false; - - break; - } - } - - return true; - } - - void setupBeginChars() - { - Vector beginTerms; - bool containsFixedCharacter = false; - - if ((!m_pattern.m_body->m_hasFixedSize || m_pattern.m_body->m_alternatives.size() > 1) - && setupDisjunctionBeginTerms(m_pattern.m_body, &beginTerms, 0)) { - unsigned size = beginTerms.size(); - - // If we haven't collected any terms we should abort the preparation of beginning character look-up optimization. - if (!size) - return; - - m_pattern.m_containsBeginChars = true; - - for (unsigned i = 0; i < size; i++) { - PatternTerm term = beginTerms[i].term; - - // We have just collected PatternCharacter terms, other terms are not allowed. - ASSERT(term.type == PatternTerm::TypePatternCharacter); - - if (term.quantityType == QuantifierFixedCount) - containsFixedCharacter = true; - - UChar character = term.patternCharacter; - unsigned mask = 0; - - if (character <= 0x7f) { - if (m_pattern.m_ignoreCase && isASCIIAlpha(character)) { - mask = 32; - character = toASCIILower(character); - } - - m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } else { - UChar upper, lower; - if (m_pattern.m_ignoreCase && ((upper = Unicode::toUpper(character)) != (lower = Unicode::toLower(character)))) { - m_beginCharHelper.addBeginChar(BeginChar(upper, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - m_beginCharHelper.addBeginChar(BeginChar(lower, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } else - m_beginCharHelper.addBeginChar(BeginChar(character, mask), &beginTerms[i].hotTerms, term.quantityType, term.quantityCount); - } - } - - // If the pattern doesn't contain terms with fixed quantifiers then the beginning character look-up optimization is inefficient. - if (!containsFixedCharacter) { - m_pattern.m_containsBeginChars = false; - return; - } - - size = m_pattern.m_beginChars.size(); - - if (size > 2) - m_beginCharHelper.merge(size - 1); - else if (size <= 1) - m_pattern.m_containsBeginChars = false; - } - } - private: - YarrPattern& m_pattern; + RegexPattern& m_pattern; PatternAlternative* m_alternative; CharacterClassConstructor m_characterClassConstructor; - BeginCharHelper m_beginCharHelper; bool m_invertCharacterClass; - bool m_invertParentheticalAssertion; }; -ErrorCode YarrPattern::compile(const UString& patternString) -{ - YarrPatternConstructor constructor(*this); - if (ErrorCode error = parse(constructor, patternString)) +int compileRegex(const UString& patternString, RegexPattern& pattern) +{ + RegexPatternConstructor constructor(pattern); + + if (int error = parse(constructor, patternString)) return error; // If the pattern contains illegal backreferences reset & reparse. // Quoting Netscape's "What's new in JavaScript 1.2", // "Note: if the number of left parentheses is less than the number specified // in \#, the \# is taken as an octal escape as described in the next row." - if (containsIllegalBackReference()) { - unsigned numSubpatterns = m_numSubpatterns; + if (pattern.containsIllegalBackReference()) { + unsigned numSubpatterns = pattern.m_numSubpatterns; constructor.reset(); -#if !ASSERT_DISABLED - ErrorCode error = +#ifdef DEBUG + int error = #endif parse(constructor, patternString, numSubpatterns); - ASSERT(!error); - ASSERT(numSubpatterns == m_numSubpatterns); + JS_ASSERT(!error); + JS_ASSERT(numSubpatterns == pattern.m_numSubpatterns); } constructor.checkForTerminalParentheses(); - constructor.optimizeBOL(); - constructor.setupOffsets(); - constructor.setupBeginChars(); - return NoError; + return 0; } -YarrPattern::YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error) - : m_ignoreCase(ignoreCase) - , m_multiline(multiline) - , m_containsBackreferences(false) - , m_containsBeginChars(false) - , m_containsBOL(false) - , m_numSubpatterns(0) - , m_maxBackReference(0) - , newlineCached(0) - , digitsCached(0) - , spacesCached(0) - , wordcharCached(0) - , nondigitsCached(0) - , nonspacesCached(0) - , nonwordcharCached(0) -{ - *error = compile(pattern); -} } } diff --git a/js/src/yarr/YarrSyntaxChecker.h b/js/src/yarr/yarr/RegexCompiler.h similarity index 74% rename from js/src/yarr/YarrSyntaxChecker.h rename to js/src/yarr/yarr/RegexCompiler.h index 87f2ed5093b0..307c15866e59 100644 --- a/js/src/yarr/YarrSyntaxChecker.h +++ b/js/src/yarr/yarr/RegexCompiler.h @@ -1,8 +1,5 @@ -/* -*- 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) 2011 Apple Inc. All rights reserved. +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,20 +21,18 @@ * 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 YarrSyntaxChecker_h -#define YarrSyntaxChecker_h +#ifndef RegexCompiler_h +#define RegexCompiler_h -#include "wtfbridge.h" -#include "YarrParser.h" +#include "RegexParser.h" +#include "RegexPattern.h" namespace JSC { namespace Yarr { -ErrorCode checkSyntax(const UString& pattern); +int compileRegex(const UString& patternString, RegexPattern& pattern); -}} // JSC::YARR - -#endif // YarrSyntaxChecker_h +} } // namespace JSC::Yarr +#endif // RegexCompiler_h diff --git a/js/src/yarr/yarr/RegexJIT.cpp b/js/src/yarr/yarr/RegexJIT.cpp new file mode 100644 index 000000000000..1571c35b7125 --- /dev/null +++ b/js/src/yarr/yarr/RegexJIT.cpp @@ -0,0 +1,1589 @@ +/* + * Copyright (C) 2009 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. + */ + +#include "RegexJIT.h" + +#if ENABLE_ASSEMBLER + +#include "assembler/assembler/LinkBuffer.h" +#include "assembler/assembler/MacroAssembler.h" +#include "RegexCompiler.h" + +#include "yarr/pcre/pcre.h" // temporary, remove when fallback is removed. + +using namespace WTF; + +namespace JSC { namespace Yarr { + +class JSGlobalData; + +class RegexGenerator : private MacroAssembler { + friend void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); + +#if WTF_CPU_ARM + static const RegisterID input = ARMRegisters::r0; + static const RegisterID index = ARMRegisters::r1; + static const RegisterID length = ARMRegisters::r2; + static const RegisterID output = ARMRegisters::r4; + + static const RegisterID regT0 = ARMRegisters::r5; + static const RegisterID regT1 = ARMRegisters::r6; + + static const RegisterID returnRegister = ARMRegisters::r0; +#elif WTF_CPU_MIPS + static const RegisterID input = MIPSRegisters::a0; + static const RegisterID index = MIPSRegisters::a1; + static const RegisterID length = MIPSRegisters::a2; + static const RegisterID output = MIPSRegisters::a3; + + static const RegisterID regT0 = MIPSRegisters::t4; + static const RegisterID regT1 = MIPSRegisters::t5; + + static const RegisterID returnRegister = MIPSRegisters::v0; +#elif WTF_CPU_SPARC + static const RegisterID input = SparcRegisters::i0; + static const RegisterID index = SparcRegisters::i1; + static const RegisterID length = SparcRegisters::i2; + static const RegisterID output = SparcRegisters::i3; + + static const RegisterID regT0 = SparcRegisters::i4; + static const RegisterID regT1 = SparcRegisters::i5; + + static const RegisterID returnRegister = SparcRegisters::i0; +#elif WTF_CPU_X86 + static const RegisterID input = X86Registers::eax; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::ecx; + static const RegisterID output = X86Registers::edi; + + static const RegisterID regT0 = X86Registers::ebx; + static const RegisterID regT1 = X86Registers::esi; + + static const RegisterID returnRegister = X86Registers::eax; +#elif WTF_CPU_X86_64 +#if WTF_PLATFORM_WIN + static const RegisterID input = X86Registers::ecx; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::r8; + static const RegisterID output = X86Registers::r9; +#else + static const RegisterID input = X86Registers::edi; + static const RegisterID index = X86Registers::esi; + static const RegisterID length = X86Registers::edx; + static const RegisterID output = X86Registers::ecx; +#endif + + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::ebx; + + static const RegisterID returnRegister = X86Registers::eax; +#endif + + void optimizeAlternative(PatternAlternative* alternative) + { + if (!alternative->m_terms.length()) + return; + + for (unsigned i = 0; i < alternative->m_terms.length() - 1; ++i) { + PatternTerm& term = alternative->m_terms[i]; + PatternTerm& nextTerm = alternative->m_terms[i + 1]; + + if ((term.type == PatternTerm::TypeCharacterClass) + && (term.quantityType == QuantifierFixedCount) + && (nextTerm.type == PatternTerm::TypePatternCharacter) + && (nextTerm.quantityType == QuantifierFixedCount)) { + PatternTerm termCopy = term; + alternative->m_terms[i] = nextTerm; + alternative->m_terms[i + 1] = termCopy; + } + } + } + + void matchCharacterClassRange(RegisterID character, JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) + { + do { + // pick which range we're going to generate + int which = count >> 1; + char lo = ranges[which].begin; + char hi = ranges[which].end; + + // check if there are any ranges or matches below lo. If not, just jl to failure - + // if there is anything else to check, check that first, if it falls through jmp to failure. + if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { + Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); + + // generate code for all ranges before this one + if (which) + matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); + + while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { + matchDest.append(branch32(Equal, character, Imm32((unsigned short)matches[*matchIndex]))); + ++*matchIndex; + } + failures.append(jump()); + + loOrAbove.link(this); + } else if (which) { + Jump loOrAbove = branch32(GreaterThanOrEqual, character, Imm32((unsigned short)lo)); + + matchCharacterClassRange(character, failures, matchDest, ranges, which, matchIndex, matches, matchCount); + failures.append(jump()); + + loOrAbove.link(this); + } else + failures.append(branch32(LessThan, character, Imm32((unsigned short)lo))); + + while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) + ++*matchIndex; + + matchDest.append(branch32(LessThanOrEqual, character, Imm32((unsigned short)hi))); + // fall through to here, the value is above hi. + + // shuffle along & loop around if there are any more matches to handle. + unsigned next = which + 1; + ranges += next; + count -= next; + } while (count); + } + + void matchCharacterClass(RegisterID character, JumpList& matchDest, const CharacterClass* charClass) + { + if (charClass->m_table) { + ExtendedAddress tableEntry(character, reinterpret_cast(charClass->m_table->m_table)); + matchDest.append(branchTest8(charClass->m_table->m_inverted ? Zero : NonZero, tableEntry)); + return; + } + Jump unicodeFail; + if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) { + Jump isAscii = branch32(LessThanOrEqual, character, Imm32(0x7f)); + + if (charClass->m_matchesUnicode.length()) { + for (unsigned i = 0; i < charClass->m_matchesUnicode.length(); ++i) { + UChar ch = charClass->m_matchesUnicode[i]; + matchDest.append(branch32(Equal, character, Imm32(ch))); + } + } + + if (charClass->m_rangesUnicode.length()) { + for (unsigned i = 0; i < charClass->m_rangesUnicode.length(); ++i) { + UChar lo = charClass->m_rangesUnicode[i].begin; + UChar hi = charClass->m_rangesUnicode[i].end; + + Jump below = branch32(LessThan, character, Imm32(lo)); + matchDest.append(branch32(LessThanOrEqual, character, Imm32(hi))); + below.link(this); + } + } + + unicodeFail = jump(); + isAscii.link(this); + } + + if (charClass->m_ranges.length()) { + unsigned matchIndex = 0; + JumpList failures; + matchCharacterClassRange(character, failures, matchDest, charClass->m_ranges.begin(), charClass->m_ranges.length(), &matchIndex, charClass->m_matches.begin(), charClass->m_matches.length()); + while (matchIndex < charClass->m_matches.length()) + matchDest.append(branch32(Equal, character, Imm32((unsigned short)charClass->m_matches[matchIndex++]))); + + failures.link(this); + } else if (charClass->m_matches.length()) { + // optimization: gather 'a','A' etc back together, can mask & test once. + js::Vector matchesAZaz; + + for (unsigned i = 0; i < charClass->m_matches.length(); ++i) { + char ch = charClass->m_matches[i]; + if (m_pattern.m_ignoreCase) { + if (isASCIILower(ch)) { + matchesAZaz.append(ch); + continue; + } + if (isASCIIUpper(ch)) + continue; + } + matchDest.append(branch32(Equal, character, Imm32((unsigned short)ch))); + } + + if (unsigned countAZaz = matchesAZaz.length()) { + or32(Imm32(32), character); + for (unsigned i = 0; i < countAZaz; ++i) + matchDest.append(branch32(Equal, character, Imm32(matchesAZaz[i]))); + } + } + + if (charClass->m_matchesUnicode.length() || charClass->m_rangesUnicode.length()) + unicodeFail.link(this); + } + + // Jumps if input not available; will have (incorrectly) incremented already! + Jump jumpIfNoAvailableInput(unsigned countToCheck) + { + add32(Imm32(countToCheck), index); + return branch32(Above, index, length); + } + + Jump jumpIfAvailableInput(unsigned countToCheck) + { + add32(Imm32(countToCheck), index); + return branch32(BelowOrEqual, index, length); + } + + Jump checkInput() + { + return branch32(BelowOrEqual, index, length); + } + + Jump atEndOfInput() + { + return branch32(Equal, index, length); + } + + Jump notAtEndOfInput() + { + return branch32(NotEqual, index, length); + } + + Jump jumpIfCharEquals(UChar ch, int inputPosition) + { + return branch16(Equal, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); + } + + Jump jumpIfCharNotEquals(UChar ch, int inputPosition) + { + return branch16(NotEqual, BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), Imm32(ch)); + } + + void readCharacter(int inputPosition, RegisterID reg) + { + load16(BaseIndex(input, index, TimesTwo, inputPosition * sizeof(UChar)), reg); + } + + void storeToFrame(RegisterID reg, unsigned frameLocation) + { + poke(reg, frameLocation); + } + + void storeToFrame(Imm32 imm, unsigned frameLocation) + { + poke(imm, frameLocation); + } + + DataLabelPtr storeToFrameWithPatch(unsigned frameLocation) + { + return storePtrWithPatch(ImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*))); + } + + void loadFromFrame(unsigned frameLocation, RegisterID reg) + { + peek(reg, frameLocation); + } + + void loadFromFrameAndJump(unsigned frameLocation) + { + jump(Address(stackPointerRegister, frameLocation * sizeof(void*))); + } + + struct AlternativeBacktrackRecord { + DataLabelPtr dataLabel; + Label backtrackLocation; + + AlternativeBacktrackRecord(DataLabelPtr dataLabel, Label backtrackLocation) + : dataLabel(dataLabel) + , backtrackLocation(backtrackLocation) + { + } + }; + + struct TermGenerationState { + TermGenerationState(PatternDisjunction* disjunction, unsigned checkedTotal) + : disjunction(disjunction) + , checkedTotal(checkedTotal) + { + } + + void resetAlternative() + { + isBackTrackGenerated = false; + alt = 0; + } + bool alternativeValid() + { + return alt < disjunction->m_alternatives.length(); + } + void nextAlternative() + { + ++alt; + } + PatternAlternative* alternative() + { + return disjunction->m_alternatives[alt]; + } + + void resetTerm() + { + ASSERT(alternativeValid()); + t = 0; + } + bool termValid() + { + ASSERT(alternativeValid()); + return t < alternative()->m_terms.length(); + } + void nextTerm() + { + ASSERT(alternativeValid()); + ++t; + } + PatternTerm& term() + { + ASSERT(alternativeValid()); + return alternative()->m_terms[t]; + } + bool isLastTerm() + { + ASSERT(alternativeValid()); + return (t + 1) == alternative()->m_terms.length(); + } + bool isMainDisjunction() + { + return !disjunction->m_parent; + } + + PatternTerm& lookaheadTerm() + { + ASSERT(alternativeValid()); + ASSERT((t + 1) < alternative()->m_terms.length()); + return alternative()->m_terms[t + 1]; + } + bool isSinglePatternCharacterLookaheadTerm() + { + ASSERT(alternativeValid()); + return ((t + 1) < alternative()->m_terms.length()) + && (lookaheadTerm().type == PatternTerm::TypePatternCharacter) + && (lookaheadTerm().quantityType == QuantifierFixedCount) + && (lookaheadTerm().quantityCount == 1); + } + + int inputOffset() + { + return term().inputPosition - checkedTotal; + } + + void jumpToBacktrack(Jump jump, MacroAssembler* masm) + { + if (isBackTrackGenerated) + jump.linkTo(backtrackLabel, masm); + else + backTrackJumps.append(jump); + } + void jumpToBacktrack(JumpList& jumps, MacroAssembler* masm) + { + if (isBackTrackGenerated) + jumps.linkTo(backtrackLabel, masm); + else + backTrackJumps.append(jumps); + } + bool plantJumpToBacktrackIfExists(MacroAssembler* masm) + { + if (isBackTrackGenerated) { + masm->jump(backtrackLabel); + return true; + } + return false; + } + void addBacktrackJump(Jump jump) + { + backTrackJumps.append(jump); + } + void setBacktrackGenerated(Label label) + { + isBackTrackGenerated = true; + backtrackLabel = label; + } + void linkAlternativeBacktracks(MacroAssembler* masm) + { + isBackTrackGenerated = false; + backTrackJumps.link(masm); + } + void linkAlternativeBacktracksTo(Label label, MacroAssembler* masm) + { + isBackTrackGenerated = false; + backTrackJumps.linkTo(label, masm); + } + void propagateBacktrackingFrom(TermGenerationState& nestedParenthesesState, MacroAssembler* masm) + { + jumpToBacktrack(nestedParenthesesState.backTrackJumps, masm); + if (nestedParenthesesState.isBackTrackGenerated) + setBacktrackGenerated(nestedParenthesesState.backtrackLabel); + } + + PatternDisjunction* disjunction; + int checkedTotal; + private: + unsigned alt; + unsigned t; + JumpList backTrackJumps; + Label backtrackLabel; + bool isBackTrackGenerated; + }; + + void generateAssertionBOL(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + if (m_pattern.m_multiline) { + const RegisterID character = regT0; + + JumpList matchDest; + if (!term.inputPosition) + matchDest.append(branch32(Equal, index, Imm32(state.checkedTotal))); + + readCharacter(state.inputOffset() - 1, character); + matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); + state.jumpToBacktrack(jump(), this); + + matchDest.link(this); + } else { + // Erk, really should poison out these alternatives early. :-/ + if (term.inputPosition) + state.jumpToBacktrack(jump(), this); + else + state.jumpToBacktrack(branch32(NotEqual, index, Imm32(state.checkedTotal)), this); + } + } + + void generateAssertionEOL(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + if (m_pattern.m_multiline) { + const RegisterID character = regT0; + + JumpList matchDest; + if (term.inputPosition == state.checkedTotal) + matchDest.append(atEndOfInput()); + + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, m_pattern.newlineCharacterClass()); + state.jumpToBacktrack(jump(), this); + + matchDest.link(this); + } else { + if (term.inputPosition == state.checkedTotal) + state.jumpToBacktrack(notAtEndOfInput(), this); + // Erk, really should poison out these alternatives early. :-/ + else + state.jumpToBacktrack(jump(), this); + } + } + + // Also falls though on nextIsNotWordChar. + void matchAssertionWordchar(TermGenerationState& state, JumpList& nextIsWordChar, JumpList& nextIsNotWordChar) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + if (term.inputPosition == state.checkedTotal) + nextIsNotWordChar.append(atEndOfInput()); + + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, nextIsWordChar, m_pattern.wordcharCharacterClass()); + } + + void generateAssertionWordBoundary(TermGenerationState& state) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + Jump atBegin; + JumpList matchDest; + if (!term.inputPosition) + atBegin = branch32(Equal, index, Imm32(state.checkedTotal)); + readCharacter(state.inputOffset() - 1, character); + matchCharacterClass(character, matchDest, m_pattern.wordcharCharacterClass()); + if (!term.inputPosition) + atBegin.link(this); + + // We fall through to here if the last character was not a wordchar. + JumpList nonWordCharThenWordChar; + JumpList nonWordCharThenNonWordChar; + if (term.invertOrCapture) { + matchAssertionWordchar(state, nonWordCharThenNonWordChar, nonWordCharThenWordChar); + nonWordCharThenWordChar.append(jump()); + } else { + matchAssertionWordchar(state, nonWordCharThenWordChar, nonWordCharThenNonWordChar); + nonWordCharThenNonWordChar.append(jump()); + } + state.jumpToBacktrack(nonWordCharThenNonWordChar, this); + + // We jump here if the last character was a wordchar. + matchDest.link(this); + JumpList wordCharThenWordChar; + JumpList wordCharThenNonWordChar; + if (term.invertOrCapture) { + matchAssertionWordchar(state, wordCharThenNonWordChar, wordCharThenWordChar); + wordCharThenWordChar.append(jump()); + } else { + matchAssertionWordchar(state, wordCharThenWordChar, wordCharThenNonWordChar); + // This can fall-though! + } + + state.jumpToBacktrack(wordCharThenWordChar, this); + + nonWordCharThenWordChar.link(this); + wordCharThenNonWordChar.link(this); + } + + void generatePatternCharacterSingle(TermGenerationState& state) + { + const RegisterID character = regT0; + UChar ch = state.term().patternCharacter; + + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + state.jumpToBacktrack(jumpIfCharNotEquals(ch, state.inputOffset()), this); + } + } + + void generatePatternCharacterPair(TermGenerationState& state) + { + const RegisterID character = regT0; +#if WTF_CPU_BIG_ENDIAN + UChar ch2 = state.term().patternCharacter; + UChar ch1 = state.lookaheadTerm().patternCharacter; +#else + UChar ch1 = state.term().patternCharacter; + UChar ch2 = state.lookaheadTerm().patternCharacter; +#endif + + int mask = 0; + int chPair = ch1 | (ch2 << 16); + + if (m_pattern.m_ignoreCase) { + if (isASCIIAlpha(ch1)) + mask |= 32; + if (isASCIIAlpha(ch2)) + mask |= 32 << 16; + } + + if (mask) { + load32WithUnalignedHalfWords(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character); + or32(Imm32(mask), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(chPair | mask)), this); + } else + state.jumpToBacktrack(branch32WithUnalignedHalfWords(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this); + } + + void generatePatternCharacterFixed(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(index, countRegister); + sub32(Imm32(term.quantityCount), countRegister); + + Label loop(this); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); + or32(Imm32(32), character); + state.jumpToBacktrack(branch32(NotEqual, character, Imm32(Unicode::toLower(ch))), this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + state.jumpToBacktrack(branch16(NotEqual, BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), Imm32(ch)), this); + } + add32(Imm32(1), countRegister); + branch32(NotEqual, countRegister, index).linkTo(loop, this); + } + + void generatePatternCharacterGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(Imm32(0), countRegister); + + JumpList failures; + Label loop(this); + failures.append(atEndOfInput()); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + failures.append(branch32(NotEqual, character, Imm32(Unicode::toLower(ch)))); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + failures.append(jumpIfCharNotEquals(ch, state.inputOffset())); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + if (term.quantityCount != 0xffffffff) { + branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); + failures.append(jump()); + } else + jump(loop); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + state.jumpToBacktrack(branchTest32(Zero, countRegister), this); + sub32(Imm32(1), countRegister); + sub32(Imm32(1), index); + + failures.link(this); + + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generatePatternCharacterNonGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + UChar ch = term.patternCharacter; + + move(Imm32(0), countRegister); + + Jump firstTimeDoNothing = jump(); + + Label hardFail(this); + sub32(countRegister, index); + state.jumpToBacktrack(jump(), this); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + + atEndOfInput().linkTo(hardFail, this); + if (term.quantityCount != 0xffffffff) + branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); + if (m_pattern.m_ignoreCase && isASCIIAlpha(ch)) { + readCharacter(state.inputOffset(), character); + or32(Imm32(32), character); + branch32(NotEqual, character, Imm32(Unicode::toLower(ch))).linkTo(hardFail, this); + } else { + ASSERT(!m_pattern.m_ignoreCase || (Unicode::toLower(ch) == Unicode::toUpper(ch))); + jumpIfCharNotEquals(ch, state.inputOffset()).linkTo(hardFail, this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + + firstTimeDoNothing.link(this); + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateCharacterClassSingle(TermGenerationState& state) + { + const RegisterID character = regT0; + PatternTerm& term = state.term(); + + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + state.jumpToBacktrack(matchDest, this); + else { + state.jumpToBacktrack(jump(), this); + matchDest.link(this); + } + } + + void generateCharacterClassFixed(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(index, countRegister); + sub32(Imm32(term.quantityCount), countRegister); + + Label loop(this); + JumpList matchDest; + load16(BaseIndex(input, countRegister, TimesTwo, (state.inputOffset() + term.quantityCount) * sizeof(UChar)), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + state.jumpToBacktrack(matchDest, this); + else { + state.jumpToBacktrack(jump(), this); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + branch32(NotEqual, countRegister, index).linkTo(loop, this); + } + + void generateCharacterClassGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(Imm32(0), countRegister); + + JumpList failures; + Label loop(this); + failures.append(atEndOfInput()); + + if (term.invertOrCapture) { + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, failures, term.characterClass); + } else { + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + failures.append(jump()); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + if (term.quantityCount != 0xffffffff) { + branch32(NotEqual, countRegister, Imm32(term.quantityCount)).linkTo(loop, this); + failures.append(jump()); + } else + jump(loop); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + state.jumpToBacktrack(branchTest32(Zero, countRegister), this); + sub32(Imm32(1), countRegister); + sub32(Imm32(1), index); + + failures.link(this); + + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateCharacterClassNonGreedy(TermGenerationState& state) + { + const RegisterID character = regT0; + const RegisterID countRegister = regT1; + PatternTerm& term = state.term(); + + move(Imm32(0), countRegister); + + Jump firstTimeDoNothing = jump(); + + Label hardFail(this); + sub32(countRegister, index); + state.jumpToBacktrack(jump(), this); + + Label backtrackBegin(this); + loadFromFrame(term.frameLocation, countRegister); + + atEndOfInput().linkTo(hardFail, this); + branch32(Equal, countRegister, Imm32(term.quantityCount), hardFail); + + JumpList matchDest; + readCharacter(state.inputOffset(), character); + matchCharacterClass(character, matchDest, term.characterClass); + + if (term.invertOrCapture) + matchDest.linkTo(hardFail, this); + else { + jump(hardFail); + matchDest.link(this); + } + + add32(Imm32(1), countRegister); + add32(Imm32(1), index); + + firstTimeDoNothing.link(this); + storeToFrame(countRegister, term.frameLocation); + + state.setBacktrackGenerated(backtrackBegin); + } + + void generateParenthesesDisjunction(PatternTerm& parenthesesTerm, TermGenerationState& state, unsigned alternativeFrameLocation) + { + ASSERT((parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern) || (parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion)); + ASSERT(parenthesesTerm.quantityCount == 1); + + PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; + unsigned preCheckedCount = ((parenthesesTerm.quantityType == QuantifierFixedCount) && (parenthesesTerm.type != PatternTerm::TypeParentheticalAssertion)) ? disjunction->m_minimumSize : 0; + + if (disjunction->m_alternatives.length() == 1) { + state.resetAlternative(); + ASSERT(state.alternativeValid()); + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + int countToCheck = alternative->m_minimumSize - preCheckedCount; + if (countToCheck) { + ASSERT((parenthesesTerm.type == PatternTerm::TypeParentheticalAssertion) || (parenthesesTerm.quantityType != QuantifierFixedCount)); + + // FIXME: This is quite horrible. The call to 'plantJumpToBacktrackIfExists' + // will be forced to always trampoline into here, just to decrement the index. + // Ick. + Jump skip = jump(); + + Label backtrackBegin(this); + sub32(Imm32(countToCheck), index); + state.addBacktrackJump(jump()); + + skip.link(this); + + state.setBacktrackGenerated(backtrackBegin); + + state.jumpToBacktrack(jumpIfNoAvailableInput(countToCheck), this); + state.checkedTotal += countToCheck; + } + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + state.checkedTotal -= countToCheck; + } else { + JumpList successes; + + for (state.resetAlternative(); state.alternativeValid(); state.nextAlternative()) { + + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + ASSERT(alternative->m_minimumSize >= preCheckedCount); + int countToCheck = alternative->m_minimumSize - preCheckedCount; + if (countToCheck) { + state.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); + state.checkedTotal += countToCheck; + } + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + // Matched an alternative. + DataLabelPtr dataLabel = storeToFrameWithPatch(alternativeFrameLocation); + successes.append(jump()); + + // Alternative did not match. + Label backtrackLocation(this); + + // Can we backtrack the alternative? - if so, do so. If not, just fall through to the next one. + state.plantJumpToBacktrackIfExists(this); + + state.linkAlternativeBacktracks(this); + + if (countToCheck) { + sub32(Imm32(countToCheck), index); + state.checkedTotal -= countToCheck; + } + + m_backtrackRecords.append(AlternativeBacktrackRecord(dataLabel, backtrackLocation)); + } + // We fall through to here when the last alternative fails. + // Add a backtrack out of here for the parenthese handling code to link up. + state.addBacktrackJump(jump()); + + // Generate a trampoline for the parens code to backtrack to, to retry the + // next alternative. + state.setBacktrackGenerated(label()); + loadFromFrameAndJump(alternativeFrameLocation); + + // FIXME: both of the above hooks are a little inefficient, in that you + // may end up trampolining here, just to trampoline back out to the + // parentheses code, or vice versa. We can probably eliminate a jump + // by restructuring, but coding this way for now for simplicity during + // development. + + successes.link(this); + } + } + + void generateParenthesesSingle(TermGenerationState& state) + { + const RegisterID indexTemporary = regT0; + PatternTerm& term = state.term(); + PatternDisjunction* disjunction = term.parentheses.disjunction; + ASSERT(term.quantityCount == 1); + + unsigned preCheckedCount = (term.quantityType == QuantifierFixedCount) ? disjunction->m_minimumSize : 0; + + unsigned parenthesesFrameLocation = term.frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation; + if (term.quantityType != QuantifierFixedCount) + alternativeFrameLocation += RegexStackSpaceForBackTrackInfoParenthesesOnce; + + // optimized case - no capture & no quantifier can be handled in a light-weight manner. + if (!term.invertOrCapture && (term.quantityType == QuantifierFixedCount)) { + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // this expects that any backtracks back out of the parentheses will be in the + // parenthesesState's backTrackJumps vector, and that if they need backtracking + // they will have set an entry point on the parenthesesState's backtrackLabel. + state.propagateBacktrackingFrom(parenthesesState, this); + } else { + Jump nonGreedySkipParentheses; + Label nonGreedyTryParentheses; + if (term.quantityType == QuantifierGreedy) + storeToFrame(index, parenthesesFrameLocation); + else if (term.quantityType == QuantifierNonGreedy) { + storeToFrame(Imm32(-1), parenthesesFrameLocation); + nonGreedySkipParentheses = jump(); + nonGreedyTryParentheses = label(); + storeToFrame(index, parenthesesFrameLocation); + } + + // store the match start index + if (term.invertOrCapture) { + int inputOffset = state.inputOffset() - preCheckedCount; + if (inputOffset) { + move(index, indexTemporary); + add32(Imm32(inputOffset), indexTemporary); + store32(indexTemporary, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); + } else + store32(index, Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); + } + + // generate the body of the parentheses + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + + Jump success = (term.quantityType == QuantifierFixedCount) ? + jump() : + branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesFrameLocation * sizeof(void*)))); + + // A failure AFTER the parens jumps here + Label backtrackFromAfterParens(this); + + if (term.quantityType == QuantifierGreedy) { + // If this is -1 we have now tested with both with and without the parens. + loadFromFrame(parenthesesFrameLocation, indexTemporary); + state.jumpToBacktrack(branch32(Equal, indexTemporary, Imm32(-1)), this); + } else if (term.quantityType == QuantifierNonGreedy) { + // If this is -1 we have now tested without the parens, now test with. + loadFromFrame(parenthesesFrameLocation, indexTemporary); + branch32(Equal, indexTemporary, Imm32(-1)).linkTo(nonGreedyTryParentheses, this); + } + + parenthesesState.plantJumpToBacktrackIfExists(this); + // A failure WITHIN the parens jumps here + parenthesesState.linkAlternativeBacktracks(this); + if (term.invertOrCapture) { + store32(Imm32(-1), Address(output, (term.parentheses.subpatternId << 1) * sizeof(int))); +#if 0 + store32(Imm32(-1), Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); +#endif + } + + if (term.quantityType == QuantifierGreedy) + storeToFrame(Imm32(-1), parenthesesFrameLocation); + else + state.jumpToBacktrack(jump(), this); + + state.setBacktrackGenerated(backtrackFromAfterParens); + if (term.quantityType == QuantifierNonGreedy) + nonGreedySkipParentheses.link(this); + success.link(this); + + // store the match end index + if (term.invertOrCapture) { + int inputOffset = state.inputOffset(); + if (inputOffset) { + move(index, indexTemporary); + add32(Imm32(state.inputOffset()), indexTemporary); + store32(indexTemporary, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); + } else + store32(index, Address(output, ((term.parentheses.subpatternId << 1) + 1) * sizeof(int))); + } + } + } + + void generateParenthesesGreedyNoBacktrack(TermGenerationState& state) + { + PatternTerm& parenthesesTerm = state.term(); + PatternDisjunction* disjunction = parenthesesTerm.parentheses.disjunction; + ASSERT(parenthesesTerm.type == PatternTerm::TypeParenthesesSubpattern); + ASSERT(parenthesesTerm.quantityCount != 1); // Handled by generateParenthesesSingle. + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + + Label matchAgain(this); + + storeToFrame(index, parenthesesTerm.frameLocation); // Save the current index to check for zero len matches later. + + for (parenthesesState.resetAlternative(); parenthesesState.alternativeValid(); parenthesesState.nextAlternative()) { + + PatternAlternative* alternative = parenthesesState.alternative(); + optimizeAlternative(alternative); + + int countToCheck = alternative->m_minimumSize; + if (countToCheck) { + parenthesesState.addBacktrackJump(jumpIfNoAvailableInput(countToCheck)); + parenthesesState.checkedTotal += countToCheck; + } + + for (parenthesesState.resetTerm(); parenthesesState.termValid(); parenthesesState.nextTerm()) + generateTerm(parenthesesState); + + // If we get here, we matched! If the index advanced then try to match more since limit isn't supported yet. + branch32(NotEqual, index, Address(stackPointerRegister, (parenthesesTerm.frameLocation * sizeof(void*))), matchAgain); + + // If we get here we matched, but we matched "" - cannot accept this alternative as is, so either backtrack, + // or fall through to try the next alternative if no backtrack is available. + parenthesesState.plantJumpToBacktrackIfExists(this); + + parenthesesState.linkAlternativeBacktracks(this); + // We get here if the alternative fails to match - fall through to the next iteration, or out of the loop. + + if (countToCheck) { + sub32(Imm32(countToCheck), index); + parenthesesState.checkedTotal -= countToCheck; + } + } + + // If the last alternative falls through to here, we have a failed match... + // Which means that we match whatever we have matched up to this point (even if nothing). + } + + void generateParentheticalAssertion(TermGenerationState& state) + { + PatternTerm& term = state.term(); + PatternDisjunction* disjunction = term.parentheses.disjunction; + ASSERT(term.quantityCount == 1); + ASSERT(term.quantityType == QuantifierFixedCount); + + unsigned parenthesesFrameLocation = term.frameLocation; + unsigned alternativeFrameLocation = parenthesesFrameLocation + RegexStackSpaceForBackTrackInfoParentheticalAssertion; + + int countCheckedAfterAssertion = state.checkedTotal - term.inputPosition; + + if (term.invertOrCapture) { + // Inverted case + storeToFrame(index, parenthesesFrameLocation); + + state.checkedTotal -= countCheckedAfterAssertion; + if (countCheckedAfterAssertion) + sub32(Imm32(countCheckedAfterAssertion), index); + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // Success! - which means - Fail! + loadFromFrame(parenthesesFrameLocation, index); + state.jumpToBacktrack(jump(), this); + + // And fail means success. + parenthesesState.linkAlternativeBacktracks(this); + loadFromFrame(parenthesesFrameLocation, index); + + state.checkedTotal += countCheckedAfterAssertion; + } else { + // Normal case + storeToFrame(index, parenthesesFrameLocation); + + state.checkedTotal -= countCheckedAfterAssertion; + if (countCheckedAfterAssertion) + sub32(Imm32(countCheckedAfterAssertion), index); + + TermGenerationState parenthesesState(disjunction, state.checkedTotal); + generateParenthesesDisjunction(state.term(), parenthesesState, alternativeFrameLocation); + // Success! - which means - Success! + loadFromFrame(parenthesesFrameLocation, index); + Jump success = jump(); + + parenthesesState.linkAlternativeBacktracks(this); + loadFromFrame(parenthesesFrameLocation, index); + state.jumpToBacktrack(jump(), this); + + success.link(this); + + state.checkedTotal += countCheckedAfterAssertion; + } + } + + void generateTerm(TermGenerationState& state) + { + PatternTerm& term = state.term(); + + switch (term.type) { + case PatternTerm::TypeAssertionBOL: + generateAssertionBOL(state); + break; + + case PatternTerm::TypeAssertionEOL: + generateAssertionEOL(state); + break; + + case PatternTerm::TypeAssertionWordBoundary: + generateAssertionWordBoundary(state); + break; + + case PatternTerm::TypePatternCharacter: + switch (term.quantityType) { + case QuantifierFixedCount: + if (term.quantityCount == 1) { + if (state.isSinglePatternCharacterLookaheadTerm() && (state.lookaheadTerm().inputPosition == (term.inputPosition + 1))) { + generatePatternCharacterPair(state); + state.nextTerm(); + } else + generatePatternCharacterSingle(state); + } else + generatePatternCharacterFixed(state); + break; + case QuantifierGreedy: + generatePatternCharacterGreedy(state); + break; + case QuantifierNonGreedy: + generatePatternCharacterNonGreedy(state); + break; + } + break; + + case PatternTerm::TypeCharacterClass: + switch (term.quantityType) { + case QuantifierFixedCount: + if (term.quantityCount == 1) + generateCharacterClassSingle(state); + else + generateCharacterClassFixed(state); + break; + case QuantifierGreedy: + generateCharacterClassGreedy(state); + break; + case QuantifierNonGreedy: + generateCharacterClassNonGreedy(state); + break; + } + break; + + case PatternTerm::TypeBackReference: + m_shouldFallBack = true; + break; + + case PatternTerm::TypeForwardReference: + break; + + case PatternTerm::TypeParenthesesSubpattern: + if (term.quantityCount == 1 && !term.parentheses.isCopy) + generateParenthesesSingle(state); + else if (term.parentheses.isTerminal) + generateParenthesesGreedyNoBacktrack(state); + else + m_shouldFallBack = true; + break; + + case PatternTerm::TypeParentheticalAssertion: + generateParentheticalAssertion(state); + break; + } + } + + void generateDisjunction(PatternDisjunction* disjunction) + { + TermGenerationState state(disjunction, 0); + state.resetAlternative(); + + // check availability for the next alternative + int countCheckedForCurrentAlternative = 0; + int countToCheckForFirstAlternative = 0; + bool hasShorterAlternatives = false; + bool setRepeatAlternativeLabels = false; + JumpList notEnoughInputForPreviousAlternative; + Label firstAlternative; + Label firstAlternativeInputChecked; + + // The label 'firstAlternative' is used to plant a check to see if there is + // sufficient input available to run the first repeating alternative. + // The label 'firstAlternativeInputChecked' will jump directly to matching + // the first repeating alternative having skipped this check. + + if (state.alternativeValid()) { + PatternAlternative* alternative = state.alternative(); + if (!alternative->onceThrough()) { + firstAlternative = Label(this); + setRepeatAlternativeLabels = true; + } + countToCheckForFirstAlternative = alternative->m_minimumSize; + state.checkedTotal += countToCheckForFirstAlternative; + if (countToCheckForFirstAlternative) + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); + countCheckedForCurrentAlternative = countToCheckForFirstAlternative; + } + + if (setRepeatAlternativeLabels) + firstAlternativeInputChecked = Label(this); + + while (state.alternativeValid()) { + PatternAlternative* alternative = state.alternative(); + optimizeAlternative(alternative); + + // Track whether any alternatives are shorter than the first one. + if (!alternative->onceThrough()) + hasShorterAlternatives = hasShorterAlternatives || (countCheckedForCurrentAlternative < countToCheckForFirstAlternative); + + for (state.resetTerm(); state.termValid(); state.nextTerm()) + generateTerm(state); + + // If we get here, the alternative matched. + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + ASSERT(index != returnRegister); + if (m_pattern.m_body->m_hasFixedSize) { + move(index, returnRegister); + if (alternative->m_minimumSize) + sub32(Imm32(alternative->m_minimumSize), returnRegister); + + store32(returnRegister, output); + } else + load32(Address(output), returnRegister); + + store32(index, Address(output, 4)); + + generateReturn(); + + state.nextAlternative(); + + // if there are any more alternatives, plant the check for input before looping. + if (state.alternativeValid()) { + PatternAlternative* nextAlternative = state.alternative(); + if (!setRepeatAlternativeLabels && !nextAlternative->onceThrough()) { + // We have handled non-repeating alternatives, jump to next iteration + // and loop over repeating alternatives. + state.jumpToBacktrack(jump(), this); + + countToCheckForFirstAlternative = nextAlternative->m_minimumSize; + + // If we get here, there the last input checked failed. + notEnoughInputForPreviousAlternative.link(this); + + state.linkAlternativeBacktracks(this); + + // Back up to start the looping alternatives. + if (countCheckedForCurrentAlternative) + sub32(Imm32(countCheckedForCurrentAlternative), index); + + firstAlternative = Label(this); + + state.checkedTotal = countToCheckForFirstAlternative; + if (countToCheckForFirstAlternative) + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForFirstAlternative)); + + countCheckedForCurrentAlternative = countToCheckForFirstAlternative; + + firstAlternativeInputChecked = Label(this); + + setRepeatAlternativeLabels = true; + } else { + int countToCheckForNextAlternative = nextAlternative->m_minimumSize; + + if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one. + // If we get here, then the last input checked failed. + notEnoughInputForPreviousAlternative.link(this); + + // Check if sufficent input available to run the next alternative + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); + // We are now in the correct state to enter the next alternative; this add is only required + // to mirror and revert operation of the sub32, just below. + add32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); + + // If we get here, then the last input checked passed. + state.linkAlternativeBacktracks(this); + // No need to check if we can run the next alternative, since it is shorter - + // just update index. + sub32(Imm32(countCheckedForCurrentAlternative - countToCheckForNextAlternative), index); + } else if (countCheckedForCurrentAlternative < countToCheckForNextAlternative) { // CASE 2: next alternative is longer than the current one. + // If we get here, then the last input checked failed. + // If there is insufficient input to run the current alternative, and the next alternative is longer, + // then there is definitely not enough input to run it - don't even check. Just adjust index, as if + // we had checked. + notEnoughInputForPreviousAlternative.link(this); + add32(Imm32(countToCheckForNextAlternative - countCheckedForCurrentAlternative), index); + notEnoughInputForPreviousAlternative.append(jump()); + + // The next alternative is longer than the current one; check the difference. + state.linkAlternativeBacktracks(this); + notEnoughInputForPreviousAlternative.append(jumpIfNoAvailableInput(countToCheckForNextAlternative - countCheckedForCurrentAlternative)); + } else { // CASE 3: Both alternatives are the same length. + ASSERT(countCheckedForCurrentAlternative == countToCheckForNextAlternative); + + // If the next alterative is the same length as this one, then no need to check the input - + // if there was sufficent input to run the current alternative then there is sufficient + // input to run the next one; if not, there isn't. + state.linkAlternativeBacktracks(this); + } + state.checkedTotal -= countCheckedForCurrentAlternative; + countCheckedForCurrentAlternative = countToCheckForNextAlternative; + state.checkedTotal += countCheckedForCurrentAlternative; + } + } + } + + // If we get here, all Alternatives failed... + + state.checkedTotal -= countCheckedForCurrentAlternative; + + if (!setRepeatAlternativeLabels) { + // If there are no alternatives that need repeating (all are marked 'onceThrough') then just link + // the match failures to this point, and fall through to the return below. + state.linkAlternativeBacktracks(this); + notEnoughInputForPreviousAlternative.link(this); + } else { + // How much more input need there be to be able to retry from the first alternative? + // examples: + // /yarr_jit/ or /wrec|pcre/ + // In these examples we need check for one more input before looping. + // /yarr_jit|pcre/ + // In this case we need check for 5 more input to loop (+4 to allow for the first alterative + // being four longer than the last alternative checked, and another +1 to effectively move + // the start position along by one). + // /yarr|rules/ or /wrec|notsomuch/ + // In these examples, provided that there was sufficient input to have just been matching for + // the second alternative we can loop without checking for available input (since the second + // alternative is longer than the first). In the latter example we need to decrement index + // (by 4) so the start position is only progressed by 1 from the last iteration. + int incrementForNextIter = (countToCheckForFirstAlternative - countCheckedForCurrentAlternative) + 1; + + // First, deal with the cases where there was sufficient input to try the last alternative. + if (incrementForNextIter > 0) // We need to check for more input anyway, fall through to the checking below. + state.linkAlternativeBacktracks(this); + else if (m_pattern.m_body->m_hasFixedSize && !incrementForNextIter) // No need to update anything, link these backtracks straight to the to pof the loop! + state.linkAlternativeBacktracksTo(firstAlternativeInputChecked, this); + else { // no need to check the input, but we do have some bookkeeping to do first. + state.linkAlternativeBacktracks(this); + + // Where necessary update our preserved start position. + if (!m_pattern.m_body->m_hasFixedSize) { + move(index, regT0); + sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); + store32(regT0, Address(output)); + } + + // Update index if necessary, and loop (without checking). + if (incrementForNextIter) + add32(Imm32(incrementForNextIter), index); + jump().linkTo(firstAlternativeInputChecked, this); + } + + notEnoughInputForPreviousAlternative.link(this); + // Update our idea of the start position, if we're tracking this. + if (!m_pattern.m_body->m_hasFixedSize) { + if (countCheckedForCurrentAlternative - 1) { + move(index, regT0); + sub32(Imm32(countCheckedForCurrentAlternative - 1), regT0); + store32(regT0, Address(output)); + } else + store32(index, Address(output)); + } + + // Check if there is sufficent input to run the first alternative again. + jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this); + // No - insufficent input to run the first alteranative, are there any other alternatives we + // might need to check? If so, the last check will have left the index incremented by + // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative + // LESS input is available, to have the effect of just progressing the start position by 1 + // from the last iteration. If this check passes we can just jump up to the check associated + // with the first alternative in the loop. This is a bit sad, since we'll end up trying the + // first alternative again, and this check will fail (otherwise the check planted just above + // here would have passed). This is a bit sad, however it saves trying to do something more + // complex here in compilation, and in the common case we should end up coallescing the checks. + // + // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least + // of the minimum-alternative-lengths. E.g. if I have two alternatives of length 200 and 150, + // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there + // is sufficient input to run either alternative (constantly failing). If there had been only + // one alternative, or if the shorter alternative had come first, we would have terminated + // immediately. :-/ + if (hasShorterAlternatives) + jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this); + // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true, + // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... + // but since we're about to return a failure this doesn't really matter!) + } + + if (m_pattern.m_body->m_callFrameSize) + addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + move(Imm32(-1), returnRegister); + + generateReturn(); + } + + void generateEnter() + { +#if WTF_CPU_X86_64 + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + push(X86Registers::ebx); +#elif WTF_CPU_X86 + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + // TODO: do we need spill registers to fill the output pointer if there are no sub captures? + push(X86Registers::ebx); + push(X86Registers::edi); + push(X86Registers::esi); + // load output into edi (2 = saved ebp + return address). + #if WTF_COMPILER_MSVC || WTF_COMPILER_SUNPRO + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); + loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); + loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); + loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); + #else + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); + #endif +#elif WTF_CPU_ARM + push(ARMRegisters::r4); + push(ARMRegisters::r5); + push(ARMRegisters::r6); +#if WTF_CPU_ARM_TRADITIONAL + push(ARMRegisters::r8); // scratch register +#endif + move(ARMRegisters::r3, output); +#elif WTF_CPU_SPARC + save(Imm32(-m_pattern.m_body->m_callFrameSize * sizeof(void*))); + // set m_callFrameSize to 0 avoid and stack movement later. + m_pattern.m_body->m_callFrameSize = 0; +#elif WTF_CPU_MIPS + // Do nothing. +#endif + } + + void generateReturn() + { +#if WTF_CPU_X86_64 + pop(X86Registers::ebx); + pop(X86Registers::ebp); +#elif WTF_CPU_X86 + pop(X86Registers::esi); + pop(X86Registers::edi); + pop(X86Registers::ebx); + pop(X86Registers::ebp); +#elif WTF_CPU_ARM +#if WTF_CPU_ARM_TRADITIONAL + pop(ARMRegisters::r8); // scratch register +#endif + pop(ARMRegisters::r6); + pop(ARMRegisters::r5); + pop(ARMRegisters::r4); +#elif WTF_CPU_SPARC + ret_and_restore(); + return; +#elif WTF_CPU_MIPS + // Do nothing +#endif + ret(); + } + +public: + RegexGenerator(RegexPattern& pattern) + : m_pattern(pattern) + , m_shouldFallBack(false) + { + } + + void generate() + { + generateEnter(); + + if (!m_pattern.m_body->m_hasFixedSize) + store32(index, Address(output)); + + if (m_pattern.m_body->m_callFrameSize) + subPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister); + + generateDisjunction(m_pattern.m_body); + } + + void compile(ExecutableAllocator& allocator, RegexCodeBlock& jitObject) + { + generate(); + + if (oom()) { + m_shouldFallBack = true; + return; + } + + ExecutablePool *dummy; + bool ok; + LinkBuffer patchBuffer(this, &allocator, &dummy, &ok); + if (!ok) { + m_shouldFallBack = true; + return; + } + + for (unsigned i = 0; i < m_backtrackRecords.length(); ++i) + patchBuffer.patch(m_backtrackRecords[i].dataLabel, patchBuffer.locationOf(m_backtrackRecords[i].backtrackLocation)); + + jitObject.set(patchBuffer.finalizeCode()); + } + + bool shouldFallBack() + { + return m_shouldFallBack; + } + +private: + RegexPattern& m_pattern; + bool m_shouldFallBack; + js::Vector m_backtrackRecords; +}; + +void jitCompileRegex(ExecutableAllocator& allocator, RegexCodeBlock& jitObject, const UString&patternString, unsigned& numSubpatterns, int &error, bool &fellBack, bool ignoreCase, bool multiline +#ifdef ANDROID + , bool forceFallback +#endif +) +{ +#ifdef ANDROID + if (!forceFallback) { +#endif + fellBack = false; + RegexPattern pattern(ignoreCase, multiline); + if ((error = compileRegex(patternString, pattern))) + return; + numSubpatterns = pattern.m_numSubpatterns; + + if (!pattern.m_containsBackreferences) { + RegexGenerator generator(pattern); + generator.compile(allocator, jitObject); + if (!generator.shouldFallBack()) + return; + } +#ifdef ANDROID + } // forceFallback +#endif + + fellBack = true; + JSRegExpIgnoreCaseOption ignoreCaseOption = ignoreCase ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase; + JSRegExpMultilineOption multilineOption = multiline ? JSRegExpMultiline : JSRegExpSingleLine; + jitObject.setFallback(jsRegExpCompile(reinterpret_cast(const_cast(patternString).chars()), patternString.length(), ignoreCaseOption, multilineOption, &numSubpatterns, &error)); +} + +}} + +#endif diff --git a/js/src/yarr/yarr/RegexJIT.h b/js/src/yarr/yarr/RegexJIT.h new file mode 100644 index 000000000000..60a51b484c02 --- /dev/null +++ b/js/src/yarr/yarr/RegexJIT.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2009 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 RegexJIT_h +#define RegexJIT_h + +#if ENABLE_ASSEMBLER + +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/MacroAssemblerCodeRef.h" +#include "assembler/jit/ExecutableAllocator.h" +#include "RegexPattern.h" +#include "yarr/jswtfbridge.h" + +#include "yarr/pcre/pcre.h" +struct JSRegExp; // temporary, remove when fallback is removed. + +#if WTF_CPU_X86 && !WTF_COMPILER_MSVC && !WTF_COMPILER_SUNPRO +#define YARR_CALL __attribute__ ((regparm (3))) +#else +#define YARR_CALL +#endif + +struct JSContext; + +namespace JSC { + +namespace Yarr { + +class RegexCodeBlock { + typedef int (*RegexJITCode)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL; + +public: + RegexCodeBlock() + : m_fallback(0) + { + } + + ~RegexCodeBlock() + { + if (m_fallback) + jsRegExpFree(m_fallback); + if (m_ref.m_size) + m_ref.m_executablePool->release(); + } + + JSRegExp* getFallback() { return m_fallback; } + void setFallback(JSRegExp* fallback) { m_fallback = fallback; } + + bool operator!() { return (!m_ref.m_code.executableAddress() && !m_fallback); } + void set(MacroAssembler::CodeRef ref) { m_ref = ref; } + + int execute(const UChar* input, unsigned start, unsigned length, int* output) + { + void *code = m_ref.m_code.executableAddress(); + return JS_EXTENSION((reinterpret_cast(code))(input, start, length, output)); + } + +private: + MacroAssembler::CodeRef m_ref; + JSRegExp* m_fallback; +}; + +void jitCompileRegex(ExecutableAllocator &allocator, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, int& error, bool &fellBack, bool ignoreCase = false, bool multiline = false +#ifdef ANDROID + , bool forceFallback = false +#endif +); + +inline int executeRegex(JSContext *cx, RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize) +{ + if (JSRegExp* fallback = jitObject.getFallback()) { + int result = jsRegExpExecute(cx, fallback, input, length, start, output, outputArraySize); + + if (result == JSRegExpErrorHitLimit) + return HitRecursionLimit; + + // -1 represents no-match for both PCRE and YARR. + JS_ASSERT(result >= -1); + return result; + } + + return jitObject.execute(input, start, length, output); +} + +} } // namespace JSC::Yarr + +#endif /* ENABLE_ASSEMBLER */ + +#endif // RegexJIT_h diff --git a/js/src/yarr/YarrParser.h b/js/src/yarr/yarr/RegexParser.h similarity index 81% rename from js/src/yarr/YarrParser.h rename to js/src/yarr/yarr/RegexParser.h index f2b50dd867e3..1ae2c2fd049b 100644 --- a/js/src/yarr/YarrParser.h +++ b/js/src/yarr/yarr/RegexParser.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. * * Redistribution and use in source and binary forms, with or without @@ -24,18 +21,18 @@ * 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 YarrParser_h -#define YarrParser_h +#ifndef RegexParser_h +#define RegexParser_h -#include "Yarr.h" +#include +#include +#include "yarr/jswtfbridge.h" +#include "yarr/yarr/RegexCommon.h" namespace JSC { namespace Yarr { -#define REGEXP_ERROR_PREFIX "Invalid regular expression: " - enum BuiltInCharacterClassID { DigitClassID, SpaceClassID, @@ -48,7 +45,7 @@ template class Parser { private: template - friend ErrorCode parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit); + friend int parse(FriendDelegate& delegate, const UString& pattern, unsigned backReferenceLimit); /* * CharacterClassParserDelegate: @@ -64,8 +61,10 @@ private: CharacterClassParserDelegate(Delegate& delegate, ErrorCode& err) : m_delegate(delegate) , m_err(err) - , m_state(Empty) - , m_character(0) + , m_state(empty) +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 5 /* quell GCC overwarning */ + , m_character(0xFFFF) +#endif { } @@ -80,62 +79,56 @@ private: } /* - * atomPatternCharacter(): + * atomPatternCharacterUnescaped(): * - * This method is called either from parseCharacterClass() (for an unescaped - * character in a character class), or from parseEscape(). In the former case - * the value true will be passed for the argument 'hyphenIsRange', and in this - * mode we will allow a hypen to be treated as indicating a range (i.e. /[a-z]/ - * is different to /[a\-z]/). + * This method is called directly from parseCharacterClass(), to report a new + * pattern character token. This method differs from atomPatternCharacter(), + * which will be called from parseEscape(), since a hypen provided via this + * method may be indicating a character range, but a hyphen parsed by + * parseEscape() cannot be interpreted as doing so. */ - void atomPatternCharacter(UChar ch, bool hyphenIsRange = false) + void atomPatternCharacterUnescaped(UChar ch) { switch (m_state) { - case AfterCharacterClass: - // Following a builtin character class we need look out for a hyphen. - // We're looking for invalid ranges, such as /[\d-x]/ or /[\d-\d]/. - // If we see a hyphen following a charater class then unlike usual - // we'll report it to the delegate immediately, and put ourself into - // a poisoned state. Any following calls to add another character or - // character class will result in an error. (A hypen following a - // character-class is itself valid, but only at the end of a regex). - if (hyphenIsRange && ch == '-') { - m_delegate.atomCharacterClassAtom('-'); - m_state = AfterCharacterClassHyphen; - return; - } - // Otherwise just fall through - cached character so treat this as Empty. - - case Empty: + case empty: m_character = ch; - m_state = CachedCharacter; - return; + m_state = cachedCharacter; + break; - case CachedCharacter: - if (hyphenIsRange && ch == '-') - m_state = CachedCharacterHyphen; + case cachedCharacter: + if (ch == '-') + m_state = cachedCharacterHyphen; else { m_delegate.atomCharacterClassAtom(m_character); m_character = ch; } - return; + break; - case CachedCharacterHyphen: - if (ch < m_character) { + case cachedCharacterHyphen: + if (ch >= m_character) + m_delegate.atomCharacterClassRange(m_character, ch); + else m_err = CharacterClassOutOfOrder; - return; - } - m_delegate.atomCharacterClassRange(m_character, ch); - m_state = Empty; - return; - - case AfterCharacterClassHyphen: - m_delegate.atomCharacterClassAtom(ch); - m_state = Empty; - return; + m_state = empty; } } + /* + * atomPatternCharacter(): + * + * Adds a pattern character, called by parseEscape(), as such will not + * interpret a hyphen as indicating a character range. + */ + void atomPatternCharacter(UChar ch) + { + // Flush if a character is already pending to prevent the + // hyphen from begin interpreted as indicating a range. + if((ch == '-') && (m_state == cachedCharacter)) + flush(); + + atomPatternCharacterUnescaped(ch); + } + /* * atomBuiltInCharacterClass(): * @@ -143,28 +136,17 @@ private: */ void atomBuiltInCharacterClass(BuiltInCharacterClassID classID, bool invert) { - switch (m_state) { - case CachedCharacter: - // Flush the currently cached character, then fall through. - m_delegate.atomCharacterClassAtom(m_character); - - case Empty: - case AfterCharacterClass: - m_state = AfterCharacterClass; - m_delegate.atomCharacterClassBuiltIn(classID, invert); - return; - - case CachedCharacterHyphen: - // Error! We have a range that looks like [x-\d]. We require - // the end of the range to be a single character. - m_err = CharacterClassInvalidRange; - return; - - case AfterCharacterClassHyphen: - m_delegate.atomCharacterClassBuiltIn(classID, invert); - m_state = Empty; + if (m_state == cachedCharacterHyphen) { + // If the RHS of a range does not contain exacly one character then a SyntaxError + // must be thrown. SpiderMonkey only errors out in the [c-\s] case as an extension. + // (This assumes none of the built in character classes contain a single + // character.) + m_err = CharacterClassRangeSingleChar; + m_state = empty; return; } + flush(); + m_delegate.atomCharacterClassBuiltIn(classID, invert); } /* @@ -174,29 +156,31 @@ private: */ void end() { - if (m_state == CachedCharacter) - m_delegate.atomCharacterClassAtom(m_character); - else if (m_state == CachedCharacterHyphen) { - m_delegate.atomCharacterClassAtom(m_character); - m_delegate.atomCharacterClassAtom('-'); - } + flush(); m_delegate.atomCharacterClassEnd(); } // parseEscape() should never call these delegate methods when // invoked with inCharacterClass set. - void assertionWordBoundary(bool) { ASSERT_NOT_REACHED(); } - void atomBackReference(unsigned) { ASSERT_NOT_REACHED(); } + void assertionWordBoundary(bool) { JS_NOT_REACHED("parseEscape() should never call this"); } + void atomBackReference(unsigned) { JS_NOT_REACHED("parseEscape() should never call this"); } private: + void flush() + { + if (m_state != empty) // either cachedCharacter or cachedCharacterHyphen + m_delegate.atomCharacterClassAtom(m_character); + if (m_state == cachedCharacterHyphen) + m_delegate.atomCharacterClassAtom('-'); + m_state = empty; + } + Delegate& m_delegate; ErrorCode& m_err; enum CharacterClassConstructionState { - Empty, - CachedCharacter, - CachedCharacterHyphen, - AfterCharacterClass, - AfterCharacterClassHyphen + empty, + cachedCharacter, + cachedCharacterHyphen } m_state; UChar m_character; }; @@ -205,7 +189,7 @@ private: : m_delegate(delegate) , m_backReferenceLimit(backReferenceLimit) , m_err(NoError) - , m_data(pattern.chars()) + , m_data(const_cast(pattern).chars()) , m_size(pattern.length()) , m_index(0) , m_parenthesesNestingDepth(0) @@ -235,8 +219,8 @@ private: template bool parseEscape(EscapeDelegate& delegate) { - ASSERT(!m_err); - ASSERT(peek() == '\\'); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '\\'); consume(); if (atEndOfPattern()) { @@ -308,7 +292,7 @@ private: unsigned backReference; if (!consumeNumber(backReference)) - break; + return false; if (backReference <= m_backReferenceLimit) { delegate.atomBackReference(backReference); break; @@ -418,14 +402,14 @@ private: /* * parseCharacterClass(): * - * Helper for parseTokens(); calls dirctly and indirectly (via parseCharacterClassEscape) + * Helper for parseTokens(); calls directly and indirectly (via parseCharacterClassEscape) * to an instance of CharacterClassParserDelegate, to describe the character class to the * delegate. */ void parseCharacterClass() { - ASSERT(!m_err); - ASSERT(peek() == '['); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '['); consume(); CharacterClassParserDelegate characterClassConstructor(m_delegate, m_err); @@ -444,7 +428,7 @@ private: break; default: - characterClassConstructor.atomPatternCharacter(consume(), true); + characterClassConstructor.atomPatternCharacterUnescaped(consume()); } if (m_err) @@ -461,8 +445,8 @@ private: */ void parseParenthesesBegin() { - ASSERT(!m_err); - ASSERT(peek() == '('); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == '('); consume(); if (tryConsume('?')) { @@ -500,8 +484,8 @@ private: */ void parseParenthesesEnd() { - ASSERT(!m_err); - ASSERT(peek() == ')'); + JS_ASSERT(!m_err); + JS_ASSERT(peek() == ')'); consume(); if (m_parenthesesNestingDepth > 0) @@ -519,8 +503,8 @@ private: */ void parseQuantifier(bool lastTokenWasAnAtom, unsigned min, unsigned max) { - ASSERT(!m_err); - ASSERT(min <= max); + JS_ASSERT(!m_err); + JS_ASSERT(min <= max); if (lastTokenWasAnAtom) m_delegate.quantifyAtom(min, max, !tryConsume('?')); @@ -588,13 +572,13 @@ private: case '*': consume(); - parseQuantifier(lastTokenWasAnAtom, 0, quantifyInfinite); + parseQuantifier(lastTokenWasAnAtom, 0, UINT_MAX); lastTokenWasAnAtom = false; break; case '+': consume(); - parseQuantifier(lastTokenWasAnAtom, 1, quantifyInfinite); + parseQuantifier(lastTokenWasAnAtom, 1, UINT_MAX); lastTokenWasAnAtom = false; break; @@ -619,7 +603,7 @@ private: if (!consumeNumber(max)) break; } else { - max = quantifyInfinite; + max = UINT_MAX; } } @@ -652,18 +636,26 @@ private: /* * parse(): * - * This method calls parseTokens() to parse over the input and converts any + * This method calls regexBegin(), calls parseTokens() to parse over the input + * patterns, calls regexEnd() or regexError() as appropriate, and converts any * error code to a const char* for a result. */ - ErrorCode parse() + int parse() { + m_delegate.regexBegin(); + if (m_size > MAX_PATTERN_SIZE) m_err = PatternTooLarge; else parseTokens(); - ASSERT(atEndOfPattern() || m_err); + JS_ASSERT(atEndOfPattern() || m_err); - return m_err; + if (m_err) + m_delegate.regexError(); + else + m_delegate.regexEnd(); + + return static_cast(m_err); } @@ -683,13 +675,13 @@ private: bool atEndOfPattern() { - ASSERT(m_index <= m_size); + JS_ASSERT(m_index <= m_size); return m_index == m_size; } int peek() { - ASSERT(m_index < m_size); + JS_ASSERT(m_index < m_size); return m_data[m_index]; } @@ -700,40 +692,40 @@ private: unsigned peekDigit() { - ASSERT(peekIsDigit()); + JS_ASSERT(peekIsDigit()); return peek() - '0'; } int consume() { - ASSERT(m_index < m_size); + JS_ASSERT(m_index < m_size); return m_data[m_index++]; } unsigned consumeDigit() { - ASSERT(peekIsDigit()); + JS_ASSERT(peekIsDigit()); return consume() - '0'; } - bool consumeNumber(unsigned &accum) - { - accum = consumeDigit(); - while (peekIsDigit()) { - unsigned newValue = accum * 10 + peekDigit(); - if (newValue < accum) { /* Overflow check. */ - m_err = QuantifierTooLarge; - return false; - } - accum = newValue; - consume(); - } - return true; + bool consumeNumber(unsigned &accum) + { + accum = consumeDigit(); + while (peekIsDigit()) { + unsigned newValue = accum * 10 + peekDigit(); + if (newValue < accum) { /* Overflow check. */ + m_err = QuantifierTooLarge; + return false; + } + accum = newValue; + consume(); + } + return true; } unsigned consumeOctal() { - ASSERT(WTF::isASCIIOctalDigit(peek())); + JS_ASSERT(WTF::isASCIIOctalDigit(peek())); unsigned n = consumeDigit(); while (n < 32 && !atEndOfPattern() && WTF::isASCIIOctalDigit(peek())) @@ -806,6 +798,14 @@ private: * * void disjunction(); * + * void regexBegin(); + * void regexEnd(); + * void regexError(); + * + * Before any call recording tokens are made, regexBegin() will be called on the + * delegate once. Once parsing is complete either regexEnd() or regexError() will + * be called, as appropriate. + * * The regular expression is described by a sequence of assertion*() and atom*() * callbacks to the delegate, describing the terms in the regular expression. * Following an atom a quantifyAtom() call may occur to indicate that the previous @@ -836,11 +836,11 @@ private: */ template -ErrorCode parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = quantifyInfinite) +int parse(Delegate& delegate, const UString& pattern, unsigned backReferenceLimit = UINT_MAX) { return Parser(delegate, pattern, backReferenceLimit).parse(); } } } // namespace JSC::Yarr -#endif // YarrParser_h +#endif // RegexParser_h diff --git a/js/src/yarr/YarrPattern.h b/js/src/yarr/yarr/RegexPattern.h similarity index 70% rename from js/src/yarr/YarrPattern.h rename to js/src/yarr/yarr/RegexPattern.h index 38ae10fcf289..9d9b286a653e 100644 --- a/js/src/yarr/YarrPattern.h +++ b/js/src/yarr/yarr/RegexPattern.h @@ -1,9 +1,5 @@ -/* -*- 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 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,32 +21,26 @@ * 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 YarrPattern_h -#define YarrPattern_h +#ifndef RegexPattern_h +#define RegexPattern_h + +#include "jsvector.h" +#include "yarr/jswtfbridge.h" +#include "yarr/yarr/RegexCommon.h" -#include "wtfbridge.h" -#include "ASCIICType.h" namespace JSC { namespace Yarr { -enum ErrorCode { - NoError, - PatternTooLarge, - QuantifierOutOfOrder, - QuantifierWithoutAtom, - MissingParentheses, - ParenthesesUnmatched, - ParenthesesTypeInvalid, - CharacterClassUnmatched, - CharacterClassInvalidRange, - CharacterClassOutOfOrder, - EscapeUnterminated, - QuantifierTooLarge, - NumberOfErrorCodes -}; +#define RegexStackSpaceForBackTrackInfoPatternCharacter 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoCharacterClass 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoBackReference 2 +#define RegexStackSpaceForBackTrackInfoAlternative 1 // One per alternative. +#define RegexStackSpaceForBackTrackInfoParentheticalAssertion 1 +#define RegexStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers. +#define RegexStackSpaceForBackTrackInfoParenthesesTerminal 1 +#define RegexStackSpaceForBackTrackInfoParentheses 4 struct PatternDisjunction; @@ -65,42 +55,60 @@ struct CharacterRange { } }; -struct CharacterClassTable : RefCounted { - friend class js::OffTheBooks; +/* + * Wraps a table and indicates inversion. Can be efficiently borrowed + * between character classes, so it's refcounted. + */ +struct CharacterClassTable { + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + const char* m_table; bool m_inverted; - static PassRefPtr create(const char* table, bool inverted) + jsrefcount m_refcount; + + /* Ownership transferred to caller. */ + static CharacterClassTable *create(const char* table, bool inverted) { - return adoptRef(js::OffTheBooks::new_(table, inverted)); + // FIXME: bug 574459 -- no NULL checks done by any of the callers, all + // of which are in RegExpJitTables.h. + return js::OffTheBooks::new_(table, inverted); } + void incref() { JS_ATOMIC_INCREMENT(&m_refcount); } + void decref() { if (JS_ATOMIC_DECREMENT(&m_refcount) == 0) js::Foreground::delete_(this); } + private: CharacterClassTable(const char* table, bool inverted) : m_table(table) , m_inverted(inverted) + , m_refcount(0) { } }; struct CharacterClass { - WTF_MAKE_FAST_ALLOCATED -public: // All CharacterClass instances have to have the full set of matches and ranges, // they may have an optional table for faster lookups (which must match the // specified matches and ranges) - CharacterClass(PassRefPtr table) + CharacterClass(CharacterClassTable *table) : m_table(table) { + if (m_table) + m_table->incref(); } ~CharacterClass() { - js::Foreground::delete_(m_table.get()); + if (m_table) + m_table->decref(); } - Vector m_matches; - Vector m_ranges; - Vector m_matchesUnicode; - Vector m_rangesUnicode; - RefPtr m_table; + typedef js::Vector UChars; + typedef js::Vector CharacterRanges; + UChars m_matches; + CharacterRanges m_ranges; + UChars m_matchesUnicode; + CharacterRanges m_rangesUnicode; + CharacterClassTable *m_table; }; enum QuantifierType { @@ -121,12 +129,11 @@ struct PatternTerm { TypeParenthesesSubpattern, TypeParentheticalAssertion } type; - bool m_capture :1; - bool m_invert :1; + bool invertOrCapture; union { UChar patternCharacter; CharacterClass* characterClass; - unsigned backReferenceSubpatternId; + unsigned subpatternId; struct { PatternDisjunction* disjunction; unsigned subpatternId; @@ -140,21 +147,8 @@ struct PatternTerm { int inputPosition; unsigned frameLocation; - // No-argument constructor for js::Vector. - PatternTerm() - : type(PatternTerm::TypePatternCharacter) - , m_capture(false) - , m_invert(false) - { - patternCharacter = 0; - quantityType = QuantifierFixedCount; - quantityCount = 1; - } - PatternTerm(UChar ch) : type(PatternTerm::TypePatternCharacter) - , m_capture(false) - , m_invert(false) { patternCharacter = ch; quantityType = QuantifierFixedCount; @@ -163,18 +157,16 @@ struct PatternTerm { PatternTerm(CharacterClass* charClass, bool invert) : type(PatternTerm::TypeCharacterClass) - , m_capture(false) - , m_invert(invert) + , invertOrCapture(invert) { characterClass = charClass; quantityType = QuantifierFixedCount; quantityCount = 1; } - PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false) + PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool invertOrCapture) : type(type) - , m_capture(capture) - , m_invert(invert) + , invertOrCapture(invertOrCapture) { parentheses.disjunction = disjunction; parentheses.subpatternId = subpatternId; @@ -186,8 +178,7 @@ struct PatternTerm { PatternTerm(Type type, bool invert = false) : type(type) - , m_capture(false) - , m_invert(invert) + , invertOrCapture(invert) { quantityType = QuantifierFixedCount; quantityCount = 1; @@ -195,10 +186,9 @@ struct PatternTerm { PatternTerm(unsigned spatternId) : type(TypeBackReference) - , m_capture(false) - , m_invert(false) + , invertOrCapture(false) { - backReferenceSubpatternId = spatternId; + subpatternId = spatternId; quantityType = QuantifierFixedCount; quantityCount = 1; } @@ -225,12 +215,12 @@ struct PatternTerm { bool invert() { - return m_invert; + return invertOrCapture; } bool capture() { - return m_capture; + return invertOrCapture; } void quantify(unsigned count, QuantifierType type) @@ -241,8 +231,9 @@ struct PatternTerm { }; struct PatternAlternative { - WTF_MAKE_FAST_ALLOCATED -public: + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + PatternAlternative(PatternDisjunction* disjunction) : m_parent(disjunction) , m_onceThrough(false) @@ -254,14 +245,14 @@ public: PatternTerm& lastTerm() { - ASSERT(m_terms.size()); - return m_terms[m_terms.size() - 1]; + JS_ASSERT(m_terms.length()); + return m_terms[m_terms.length() - 1]; } void removeLastTerm() { - ASSERT(m_terms.size()); - m_terms.shrink(m_terms.size() - 1); + JS_ASSERT(m_terms.length()); + m_terms.popBack(); } void setOnceThrough() @@ -274,7 +265,7 @@ public: return m_onceThrough; } - Vector m_terms; + js::Vector m_terms; PatternDisjunction* m_parent; unsigned m_minimumSize; bool m_onceThrough : 1; @@ -283,9 +274,18 @@ public: bool m_containsBOL : 1; }; +template +static inline void +deleteAllValues(js::Vector &vector) +{ + for (T** t = vector.begin(); t < vector.end(); ++t) + js::Foreground::delete_(*t); +} + struct PatternDisjunction { - WTF_MAKE_FAST_ALLOCATED -public: + + JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR; + PatternDisjunction(PatternAlternative* parent = 0) : m_parent(parent) , m_hasFixedSize(false) @@ -299,12 +299,13 @@ public: PatternAlternative* addNewAlternative() { + // FIXME: bug 574459 -- no NULL check PatternAlternative* alternative = js::OffTheBooks::new_(this); m_alternatives.append(alternative); return alternative; } - Vector m_alternatives; + js::Vector m_alternatives; PatternAlternative* m_parent; unsigned m_minimumSize; unsigned m_callFrameSize; @@ -313,7 +314,7 @@ public: // You probably don't want to be calling these functions directly // (please to be calling newlineCharacterClass() et al on your -// friendly neighborhood YarrPattern instance to get nicely +// friendly neighborhood RegexPattern instance to get nicely // cached copies). CharacterClass* newlineCreate(); CharacterClass* digitsCreate(); @@ -323,34 +324,25 @@ CharacterClass* nondigitsCreate(); CharacterClass* nonspacesCreate(); CharacterClass* nonwordcharCreate(); -struct TermChain { - TermChain(PatternTerm term) - : term(term) - {} +struct RegexPattern { + RegexPattern(bool ignoreCase, bool multiline) + : m_ignoreCase(ignoreCase) + , m_multiline(multiline) + , m_containsBackreferences(false) + , m_containsBOL(false) + , m_numSubpatterns(0) + , m_maxBackReference(0) + , newlineCached(0) + , digitsCached(0) + , spacesCached(0) + , wordcharCached(0) + , nondigitsCached(0) + , nonspacesCached(0) + , nonwordcharCached(0) + { + } - PatternTerm term; - Vector hotTerms; -}; - -struct BeginChar { - BeginChar() - : value(0) - , mask(0) - {} - - BeginChar(unsigned value, unsigned mask) - : value(value) - , mask(mask) - {} - - unsigned value; - unsigned mask; -}; - -struct YarrPattern { - YarrPattern(const UString& pattern, bool ignoreCase, bool multiline, ErrorCode* error); - - ~YarrPattern() + ~RegexPattern() { deleteAllValues(m_disjunctions); deleteAllValues(m_userCharacterClasses); @@ -362,7 +354,6 @@ struct YarrPattern { m_maxBackReference = 0; m_containsBackreferences = false; - m_containsBeginChars = false; m_containsBOL = false; newlineCached = 0; @@ -377,7 +368,6 @@ struct YarrPattern { m_disjunctions.clear(); deleteAllValues(m_userCharacterClasses); m_userCharacterClasses.clear(); - m_beginChars.clear(); } bool containsIllegalBackReference() @@ -428,21 +418,19 @@ struct YarrPattern { return nonwordcharCached; } + typedef js::Vector PatternDisjunctions; + typedef js::Vector CharacterClasses; bool m_ignoreCase : 1; bool m_multiline : 1; bool m_containsBackreferences : 1; - bool m_containsBeginChars : 1; bool m_containsBOL : 1; unsigned m_numSubpatterns; unsigned m_maxBackReference; - PatternDisjunction* m_body; - Vector m_disjunctions; - Vector m_userCharacterClasses; - Vector m_beginChars; + PatternDisjunction *m_body; + PatternDisjunctions m_disjunctions; + CharacterClasses m_userCharacterClasses; private: - ErrorCode compile(const UString& patternString); - CharacterClass* newlineCached; CharacterClass* digitsCached; CharacterClass* spacesCached; @@ -454,4 +442,4 @@ private: } } // namespace JSC::Yarr -#endif // YarrPattern_h +#endif // RegexPattern_h diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 7341d40d7f65..50711ae8a547 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -2032,7 +2032,7 @@ POSSIBILITY OF SUCH DAMAGE.

Apple License

-

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr, and widget/src/cocoa.

+

This license applies to certain files in the directories js/src/assembler/assembler/, js/src/assembler/wtf/, js/src/yarr/wtf, js/src/yarr/yarr, and widget/src/cocoa.

 Copyright (C) 2008, 2009 Apple Inc. All rights reserved.

From ac141dc4f6e58bba2855be9277563b3ae223e5da Mon Sep 17 00:00:00 2001
From: Blake Kaplan 
Date: Mon, 23 May 2011 17:20:28 +0200
Subject: [PATCH 105/145] bug 658560 - Don't call WaiveXray on an object that's
 already in the right compartment as that will leak the
 WaiveXrayWrapperWrapper to the calling JS code. r=gal

--HG--
extra : rebase_source : 0fba697513ca5cd0984ed3999a7a8df7f005b343
---
 js/src/xpconnect/tests/chrome/Makefile.in     |  1 +
 .../xpconnect/tests/chrome/test_bug658560.xul | 41 +++++++++++++++++++
 js/src/xpconnect/tests/mochitest/Makefile.in  |  1 +
 .../tests/mochitest/file_bug658560.html       |  4 ++
 js/src/xpconnect/wrappers/WrapperFactory.cpp  | 15 ++++++-
 5 files changed, 61 insertions(+), 1 deletion(-)
 create mode 100644 js/src/xpconnect/tests/chrome/test_bug658560.xul
 create mode 100644 js/src/xpconnect/tests/mochitest/file_bug658560.html

diff --git a/js/src/xpconnect/tests/chrome/Makefile.in b/js/src/xpconnect/tests/chrome/Makefile.in
index d27b0dad6c35..020dd6063f62 100644
--- a/js/src/xpconnect/tests/chrome/Makefile.in
+++ b/js/src/xpconnect/tests/chrome/Makefile.in
@@ -65,6 +65,7 @@ _CHROME_FILES = \
 		file_bug618176.xul \
 		test_bug596580.xul \
 		test_bug654370.xul \
+		test_bug658560.xul \
 		$(NULL)
 
 # Disabled until this test gets updated to test the new proxy based
diff --git a/js/src/xpconnect/tests/chrome/test_bug658560.xul b/js/src/xpconnect/tests/chrome/test_bug658560.xul
new file mode 100644
index 000000000000..9dc8cdcecd84
--- /dev/null
+++ b/js/src/xpconnect/tests/chrome/test_bug658560.xul
@@ -0,0 +1,41 @@
+
+
+
+
+
+  
+  
+
+  
+  
+  Mozilla Bug 658560
+  
+
+  
+  
+
+