зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central and inbound
This commit is contained in:
Коммит
9521481921
|
@ -190,11 +190,11 @@ Section "MaintenanceService"
|
|||
${GetParameters} $0
|
||||
${GetOptions} "$0" "/Upgrade" $0
|
||||
${If} ${Errors}
|
||||
nsExec::Exec '"$INSTDIR\$TempMaintServiceName" install'
|
||||
ExecWait '"$INSTDIR\$TempMaintServiceName" install'
|
||||
${Else}
|
||||
; The upgrade cmdline is the same as install except
|
||||
; It will fail if the service isn't already installed.
|
||||
nsExec::Exec '"$INSTDIR\$TempMaintServiceName" upgrade'
|
||||
ExecWait '"$INSTDIR\$TempMaintServiceName" upgrade'
|
||||
${EndIf}
|
||||
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
@ -255,7 +255,7 @@ FunctionEnd
|
|||
|
||||
Section "Uninstall"
|
||||
; Delete the service so that no updates will be attempted
|
||||
nsExec::Exec '"$INSTDIR\maintenanceservice.exe" uninstall'
|
||||
ExecWait '"$INSTDIR\maintenanceservice.exe" uninstall'
|
||||
|
||||
Push "$INSTDIR\updater.ini"
|
||||
Call un.RenameDelete
|
||||
|
|
|
@ -2040,11 +2040,8 @@ public:
|
|||
*
|
||||
* @return whether aAttr was valid and can be cached.
|
||||
*/
|
||||
static AutocompleteAttrState
|
||||
SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult,
|
||||
AutocompleteAttrState aCachedState =
|
||||
eAutocompleteAttrState_Unknown);
|
||||
static AutocompleteAttrState SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult);
|
||||
|
||||
/**
|
||||
* This will parse aSource, to extract the value of the pseudo attribute
|
||||
|
|
|
@ -855,26 +855,8 @@ nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput)
|
|||
|
||||
nsContentUtils::AutocompleteAttrState
|
||||
nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
||||
nsAString& aResult,
|
||||
AutocompleteAttrState aCachedState)
|
||||
nsAString& aResult)
|
||||
{
|
||||
if (!aAttr ||
|
||||
aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) {
|
||||
return aCachedState;
|
||||
}
|
||||
|
||||
if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) {
|
||||
uint32_t atomCount = aAttr->GetAtomCount();
|
||||
for (uint32_t i = 0; i < atomCount; i++) {
|
||||
if (i != 0) {
|
||||
aResult.Append(' ');
|
||||
}
|
||||
aResult.Append(nsDependentAtomString(aAttr->AtomAt(i)));
|
||||
}
|
||||
nsContentUtils::ASCIIToLower(aResult);
|
||||
return aCachedState;
|
||||
}
|
||||
|
||||
AutocompleteAttrState state = InternalSerializeAutocompleteAttribute(aAttr, aResult);
|
||||
if (state == eAutocompleteAttrState_Valid) {
|
||||
ASCIIToLower(aResult);
|
||||
|
@ -891,7 +873,7 @@ nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
|
|||
*/
|
||||
nsContentUtils::AutocompleteAttrState
|
||||
nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
|
||||
nsAString& aResult)
|
||||
nsAString& aResult)
|
||||
{
|
||||
// No sandbox attribute so we are done
|
||||
if (!aAttrVal) {
|
||||
|
|
|
@ -1520,10 +1520,23 @@ HTMLInputElement::GetAutocomplete(nsAString& aValue)
|
|||
{
|
||||
aValue.Truncate(0);
|
||||
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
||||
if (!attributeVal ||
|
||||
mAutocompleteAttrState == nsContentUtils::eAutocompleteAttrState_Invalid) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (mAutocompleteAttrState == nsContentUtils::eAutocompleteAttrState_Valid) {
|
||||
uint32_t atomCount = attributeVal->GetAtomCount();
|
||||
for (uint32_t i = 0; i < atomCount; i++) {
|
||||
if (i != 0) {
|
||||
aValue.Append(' ');
|
||||
}
|
||||
aValue.Append(nsDependentAtomString(attributeVal->AtomAt(i)));
|
||||
}
|
||||
nsContentUtils::ASCIIToLower(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mAutocompleteAttrState =
|
||||
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
|
||||
mAutocompleteAttrState);
|
||||
mAutocompleteAttrState = nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,6 @@ HTMLSelectElement::HTMLSelectElement(already_AddRefed<nsINodeInfo>& aNodeInfo,
|
|||
FromParser aFromParser)
|
||||
: nsGenericHTMLFormElementWithState(aNodeInfo),
|
||||
mOptions(new HTMLOptionsCollection(MOZ_THIS_IN_INITIALIZER_LIST())),
|
||||
mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
|
||||
mIsDoneAddingChildren(!aFromParser),
|
||||
mDisabledChanged(false),
|
||||
mMutating(false),
|
||||
|
@ -178,16 +177,6 @@ HTMLSelectElement::SetCustomValidity(const nsAString& aError)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSelectElement::GetAutocomplete(DOMString& aValue)
|
||||
{
|
||||
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
||||
|
||||
mAutocompleteAttrState =
|
||||
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
|
||||
mAutocompleteAttrState);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
||||
{
|
||||
|
@ -1344,9 +1333,6 @@ HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
UpdateBarredFromConstraintValidation();
|
||||
} else if (aName == nsGkAtoms::required) {
|
||||
UpdateValueMissingValidityState();
|
||||
} else if (aName == nsGkAtoms::autocomplete) {
|
||||
// Clear the cached @autocomplete attribute state
|
||||
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
@ -1434,13 +1420,8 @@ HTMLSelectElement::ParseAttribute(int32_t aNamespaceID,
|
|||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (kNameSpaceID_None == aNamespaceID) {
|
||||
if (aAttribute == nsGkAtoms::size) {
|
||||
return aResult.ParsePositiveIntValue(aValue);
|
||||
} else if (aAttribute == nsGkAtoms::autocomplete) {
|
||||
aResult.ParseAtomArray(aValue);
|
||||
return true;
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::size && kNameSpaceID_None == aNamespaceID) {
|
||||
return aResult.ParsePositiveIntValue(aValue);
|
||||
}
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
class nsContentList;
|
||||
class nsIDOMHTMLOptionElement;
|
||||
|
@ -160,11 +159,6 @@ public:
|
|||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::autofocus, aVal, aRv);
|
||||
}
|
||||
void GetAutocomplete(DOMString& aValue);
|
||||
void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
|
||||
}
|
||||
bool Disabled() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::disabled);
|
||||
|
@ -611,7 +605,6 @@ protected:
|
|||
|
||||
/** The options[] array */
|
||||
nsRefPtr<HTMLOptionsCollection> mOptions;
|
||||
nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
|
||||
/** false if the parser is in the middle of adding children. */
|
||||
bool mIsDoneAddingChildren;
|
||||
/** true if our disabled state has changed from the default **/
|
||||
|
|
|
@ -13,8 +13,7 @@ Test @autocomplete on <input>
|
|||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<form>
|
||||
<input id="input-field" />
|
||||
<select id="select-field" />
|
||||
<input id="field" />
|
||||
</form>
|
||||
</div>
|
||||
<pre id="test">
|
||||
|
@ -70,8 +69,9 @@ var values = [
|
|||
];
|
||||
|
||||
var types = [undefined, "hidden", "text", "search"]; // Valid types for all non-multiline hints.
|
||||
var field = document.getElementById("field");
|
||||
|
||||
function checkAutocompleteValues(field, type) {
|
||||
function checkAutocompleteValues(type) {
|
||||
for (var test of values) {
|
||||
if (typeof(test[0]) === "undefined")
|
||||
field.removeAttribute("autocomplete");
|
||||
|
@ -83,18 +83,14 @@ function checkAutocompleteValues(field, type) {
|
|||
}
|
||||
|
||||
function start() {
|
||||
var inputField = document.getElementById("input-field");
|
||||
for (var type of types) {
|
||||
// Switch the input type
|
||||
if (typeof(type) === "undefined")
|
||||
inputField.removeAttribute("type");
|
||||
field.removeAttribute("type");
|
||||
else
|
||||
inputField.type = type;
|
||||
checkAutocompleteValues(inputField, type || "");
|
||||
field.type = type;
|
||||
checkAutocompleteValues(type || "");
|
||||
}
|
||||
|
||||
var selectField = document.getElementById("select-field");
|
||||
checkAutocompleteValues(selectField, "select");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
interface HTMLSelectElement : HTMLElement {
|
||||
[SetterThrows, Pure]
|
||||
attribute boolean autofocus;
|
||||
[Pref="dom.forms.autocomplete.experimental", SetterThrows, Pure]
|
||||
attribute DOMString autocomplete;
|
||||
[SetterThrows, Pure]
|
||||
attribute boolean disabled;
|
||||
[Pure]
|
||||
|
|
|
@ -126,8 +126,6 @@ TiledContentClient::UseTiledLayerBuffer(TiledBufferType aType)
|
|||
}
|
||||
|
||||
SharedFrameMetricsHelper::SharedFrameMetricsHelper()
|
||||
: mLastProgressiveUpdateWasLowPrecision(false)
|
||||
, mProgressiveUpdateWasInDanger(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(SharedFrameMetricsHelper);
|
||||
}
|
||||
|
@ -175,17 +173,6 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
|||
aCompositionBounds = ParentLayerRect(compositorMetrics.mCompositionBounds);
|
||||
aZoom = compositorMetrics.GetZoomToParent();
|
||||
|
||||
// Reset the checkerboard risk flag when switching to low precision
|
||||
// rendering.
|
||||
if (aLowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
|
||||
// Skip low precision rendering until we're at risk of checkerboarding.
|
||||
if (!mProgressiveUpdateWasInDanger) {
|
||||
return true;
|
||||
}
|
||||
mProgressiveUpdateWasInDanger = false;
|
||||
}
|
||||
mLastProgressiveUpdateWasLowPrecision = aLowPrecision;
|
||||
|
||||
// Always abort updates if the resolution has changed. There's no use
|
||||
// in drawing at the incorrect resolution.
|
||||
if (!FuzzyEquals(compositorMetrics.GetZoom().scale, contentMetrics.GetZoom().scale)) {
|
||||
|
@ -205,13 +192,20 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
|
|||
return false;
|
||||
}
|
||||
|
||||
// When not a low precision pass and the page is in danger of checker boarding
|
||||
// abort update.
|
||||
if (!aLowPrecision && !mProgressiveUpdateWasInDanger) {
|
||||
if (AboutToCheckerboard(contentMetrics, compositorMetrics)) {
|
||||
mProgressiveUpdateWasInDanger = true;
|
||||
return true;
|
||||
}
|
||||
bool scrollUpdatePending = contentMetrics.GetScrollOffsetUpdated() &&
|
||||
contentMetrics.GetScrollGeneration() != compositorMetrics.GetScrollGeneration();
|
||||
// If scrollUpdatePending is true, then that means the content-side
|
||||
// metrics has a new scroll offset that is going to be forced into the
|
||||
// compositor but it hasn't gotten there yet.
|
||||
// Even though right now comparing the metrics might indicate we're
|
||||
// about to checkerboard (and that's true), the checkerboarding will
|
||||
// disappear as soon as the new scroll offset update is processed
|
||||
// on the compositor side. To avoid leaving things in a low-precision
|
||||
// paint, we need to detect and handle this case (bug 1026756).
|
||||
if (!aLowPrecision && !scrollUpdatePending && AboutToCheckerboard(contentMetrics, compositorMetrics)) {
|
||||
TILING_PRLOG_OBJ(("TILING: Checkerboard abort content %s\n", tmpstr.get()), contentMetrics);
|
||||
TILING_PRLOG_OBJ(("TILING: Checkerboard abort compositor %s\n", tmpstr.get()), compositorMetrics);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Abort drawing stale low-precision content if there's a more recent
|
||||
|
|
|
@ -336,9 +336,6 @@ public:
|
|||
*/
|
||||
bool AboutToCheckerboard(const FrameMetrics& aContentMetrics,
|
||||
const FrameMetrics& aCompositorMetrics);
|
||||
private:
|
||||
bool mLastProgressiveUpdateWasLowPrecision;
|
||||
bool mProgressiveUpdateWasInDanger;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -755,7 +755,8 @@ NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label
|
|||
masm.passABIArg(current_character);
|
||||
masm.passABIArg(current_position);
|
||||
masm.passABIArg(temp1);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CaseInsensitiveCompareStrings));
|
||||
int (*fun)(const jschar*, const jschar*, size_t) = CaseInsensitiveCompareStrings;
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, fun));
|
||||
masm.storeCallResult(temp0);
|
||||
|
||||
masm.PopRegsInMask(volatileRegs);
|
||||
|
@ -812,9 +813,12 @@ NativeRegExpMacroAssembler::CheckBitInTable(uint8_t *table, Label *on_bit_set)
|
|||
{
|
||||
IonSpew(SPEW_PREFIX "CheckBitInTable");
|
||||
|
||||
JS_ASSERT(mode_ != ASCII); // Ascii case not handled here.
|
||||
|
||||
masm.movePtr(ImmPtr(table), temp0);
|
||||
|
||||
// kTableMask is currently 127, so we need to mask even if the input is
|
||||
// Latin1. V8 has the same issue.
|
||||
static_assert(JSString::MAX_LATIN1_CHAR > kTableMask,
|
||||
"No need to mask if MAX_LATIN1_CHAR <= kTableMask");
|
||||
masm.move32(Imm32(kTableSize - 1), temp1);
|
||||
masm.and32(current_character, temp1);
|
||||
|
||||
|
@ -875,7 +879,15 @@ NativeRegExpMacroAssembler::LoadCurrentCharacterUnchecked(int cp_offset, int cha
|
|||
IonSpew(SPEW_PREFIX "LoadCurrentCharacterUnchecked(%d, %d)", cp_offset, characters);
|
||||
|
||||
if (mode_ == ASCII) {
|
||||
MOZ_ASSUME_UNREACHABLE("Ascii loading not implemented");
|
||||
BaseIndex address(input_end_pointer, current_position, TimesOne, cp_offset);
|
||||
if (characters == 4) {
|
||||
masm.load32(address, current_character);
|
||||
} else if (characters == 2) {
|
||||
masm.load16ZeroExtend(address, current_character);
|
||||
} else {
|
||||
JS_ASSERT(characters = 1);
|
||||
masm.load8ZeroExtend(address, current_character);
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(mode_ == JSCHAR);
|
||||
JS_ASSERT(characters <= 2);
|
||||
|
|
|
@ -40,8 +40,8 @@ namespace irregexp {
|
|||
|
||||
struct InputOutputData
|
||||
{
|
||||
const jschar *inputStart;
|
||||
const jschar *inputEnd;
|
||||
const void *inputStart;
|
||||
const void *inputEnd;
|
||||
|
||||
// Index into inputStart (in chars) at which to begin matching.
|
||||
size_t startIndex;
|
||||
|
@ -52,7 +52,8 @@ struct InputOutputData
|
|||
// for global regexps.
|
||||
int32_t result;
|
||||
|
||||
InputOutputData(const jschar *inputStart, const jschar *inputEnd,
|
||||
template <typename CharT>
|
||||
InputOutputData(const CharT *inputStart, const CharT *inputEnd,
|
||||
size_t startIndex, MatchPairs *matches)
|
||||
: inputStart(inputStart),
|
||||
inputEnd(inputEnd),
|
||||
|
|
|
@ -1666,9 +1666,10 @@ irregexp::CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData
|
|||
return compiler.Assemble(cx, assembler, node, data->capture_count);
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
RegExpRunStatus
|
||||
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
|
||||
const jschar *chars, size_t start, size_t length, MatchPairs *matches)
|
||||
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
|
||||
size_t length, MatchPairs *matches)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
typedef void (*RegExpCodeSignature)(InputOutputData *);
|
||||
|
@ -1676,7 +1677,11 @@ irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
|
|||
InputOutputData data(chars, chars + length, start, matches);
|
||||
|
||||
RegExpCodeSignature function = reinterpret_cast<RegExpCodeSignature>(codeBlock->raw());
|
||||
CALL_GENERATED_REGEXP(function, &data);
|
||||
|
||||
{
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
CALL_GENERATED_REGEXP(function, &data);
|
||||
}
|
||||
|
||||
return (RegExpRunStatus) data.result;
|
||||
#else
|
||||
|
@ -1684,6 +1689,14 @@ irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
|
|||
#endif
|
||||
}
|
||||
|
||||
template RegExpRunStatus
|
||||
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const Latin1Char *chars, size_t start,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
template RegExpRunStatus
|
||||
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const jschar *chars, size_t start,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Tree to graph conversion
|
||||
|
||||
|
|
|
@ -108,13 +108,15 @@ CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
|
|||
|
||||
// Note: this may return RegExpRunStatus_Error if an interrupt was requested
|
||||
// while the code was executing.
|
||||
template <typename CharT>
|
||||
RegExpRunStatus
|
||||
ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
|
||||
const jschar *chars, size_t start, size_t length, MatchPairs *matches);
|
||||
ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
template <typename CharT>
|
||||
RegExpRunStatus
|
||||
InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
||||
const jschar *chars, size_t start, size_t length, MatchPairs *matches);
|
||||
InterpretCode(JSContext *cx, const uint8_t *byteCode, const CharT *chars, size_t start,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
#define FOR_EACH_NODE_TYPE(VISIT) \
|
||||
VISIT(End) \
|
||||
|
|
|
@ -104,13 +104,14 @@ Load16Aligned(const uint8_t* pc)
|
|||
|
||||
#define BYTECODE(name) case BC_##name:
|
||||
|
||||
template <typename CharT>
|
||||
RegExpRunStatus
|
||||
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
||||
const jschar *chars, size_t current, size_t length, MatchPairs *matches)
|
||||
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const CharT *chars, size_t current,
|
||||
size_t length, MatchPairs *matches)
|
||||
{
|
||||
const uint8_t* pc = byteCode;
|
||||
|
||||
jschar current_char = current ? chars[current - 1] : '\n';
|
||||
uint32_t current_char = current ? chars[current - 1] : '\n';
|
||||
|
||||
RegExpStackCursor stack(cx);
|
||||
|
||||
|
@ -226,8 +227,8 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
|||
if (pos + 2 > length) {
|
||||
pc = byteCode + Load32Aligned(pc + 4);
|
||||
} else {
|
||||
jschar next = chars[pos + 1];
|
||||
current_char = (chars[pos] | (next << (kBitsPerByte * sizeof(jschar))));
|
||||
CharT next = chars[pos + 1];
|
||||
current_char = (chars[pos] | (next << (kBitsPerByte * sizeof(CharT))));
|
||||
pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
|
||||
}
|
||||
break;
|
||||
|
@ -421,7 +422,7 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
|||
pc = byteCode + Load32Aligned(pc + 4);
|
||||
break;
|
||||
}
|
||||
if (CaseInsensitiveCompareStrings(chars + from, chars + current, len * 2)) {
|
||||
if (CaseInsensitiveCompareStrings(chars + from, chars + current, len * sizeof(CharT))) {
|
||||
current += len;
|
||||
pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
|
||||
} else {
|
||||
|
@ -456,3 +457,11 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
template RegExpRunStatus
|
||||
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const Latin1Char *chars, size_t current,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
||||
template RegExpRunStatus
|
||||
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const jschar *chars, size_t current,
|
||||
size_t length, MatchPairs *matches);
|
||||
|
|
|
@ -35,12 +35,13 @@
|
|||
using namespace js;
|
||||
using namespace js::irregexp;
|
||||
|
||||
template <typename CharT>
|
||||
int
|
||||
irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2,
|
||||
irregexp::CaseInsensitiveCompareStrings(const CharT *substring1, const CharT *substring2,
|
||||
size_t byteLength)
|
||||
{
|
||||
JS_ASSERT(byteLength % 2 == 0);
|
||||
size_t length = byteLength >> 1;
|
||||
JS_ASSERT(byteLength % sizeof(CharT) == 0);
|
||||
size_t length = byteLength / sizeof(CharT);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
jschar c1 = substring1[i];
|
||||
|
@ -56,6 +57,14 @@ irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *
|
|||
return 1;
|
||||
}
|
||||
|
||||
template int
|
||||
irregexp::CaseInsensitiveCompareStrings(const Latin1Char *substring1, const Latin1Char *substring2,
|
||||
size_t byteLength);
|
||||
|
||||
template int
|
||||
irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2,
|
||||
size_t byteLength);
|
||||
|
||||
InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(LifoAlloc *alloc, RegExpShared *shared,
|
||||
size_t numSavedRegisters)
|
||||
: RegExpMacroAssembler(*alloc, shared, numSavedRegisters),
|
||||
|
|
|
@ -217,8 +217,9 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
|
|||
RegExpShared *shared;
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
int
|
||||
CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2, size_t byteLength);
|
||||
CaseInsensitiveCompareStrings(const CharT *substring1, const CharT *substring2, size_t byteLength);
|
||||
|
||||
class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler : public RegExpMacroAssembler
|
||||
{
|
||||
|
|
|
@ -13,3 +13,21 @@ assertEq(re.source, "foo[bB]a\\r\u1200");
|
|||
assertEq(re.multiline, true);
|
||||
assertEq(re.ignoreCase, true);
|
||||
assertEq(re.sticky, false);
|
||||
|
||||
re = /b[aA]r/;
|
||||
|
||||
// Latin1
|
||||
assertEq(toLatin1("foobAr1234").search(re), 3);
|
||||
assertEq(toLatin1("bar1234").search(re), 0);
|
||||
assertEq(toLatin1("foobbr1234").search(re), -1);
|
||||
|
||||
// TwoByte
|
||||
assertEq("foobAr1234\u1200".search(re), 3);
|
||||
assertEq("bar1234\u1200".search(re), 0);
|
||||
assertEq("foobbr1234\u1200".search(re), -1);
|
||||
|
||||
re = /abcdefghijklm[0-5]/;
|
||||
assertEq(toLatin1("1abcdefghijklm4").search(re), 1);
|
||||
assertEq("\u12001abcdefghijklm0".search(re), 2);
|
||||
assertEq(toLatin1("1abcdefghijklm8").search(re), -1);
|
||||
assertEq("\u12001abcdefghijklm8".search(re), -1);
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
function testDollarReplacement() {
|
||||
// Latin1 input, pat and replacement
|
||||
var s = toLatin1("Foobarbaz123");
|
||||
var pat = toLatin1("bar");
|
||||
assertEq(s.replace(pat, toLatin1("AA")), "FooAAbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$$A")), "FooA$Abaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$`A")), "FooAFooAbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$&A")), "FooAbarAbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$'A")), "FooAbaz123Abaz123");
|
||||
|
||||
// Latin1 input and pat, TwoByte replacement
|
||||
assertEq(s.replace(pat, "A\u1200"), "FooA\u1200baz123");
|
||||
assertEq(s.replace(pat, "A$$\u1200"), "FooA$\u1200baz123");
|
||||
assertEq(s.replace(pat, "A$`\u1200"), "FooAFoo\u1200baz123");
|
||||
assertEq(s.replace(pat, "A$&\u1200"), "FooAbar\u1200baz123");
|
||||
assertEq(s.replace(pat, "A$'\u1200"), "FooAbaz123\u1200baz123");
|
||||
|
||||
// TwoByte input, Latin1 pat and replacement
|
||||
s = "Foobarbaz123\u1200";
|
||||
assertEq(s.replace(pat, toLatin1("A")), "FooAbaz123\u1200");
|
||||
assertEq(s.replace(pat, toLatin1("A$$")), "FooA$baz123\u1200");
|
||||
assertEq(s.replace(pat, toLatin1("A$`")), "FooAFoobaz123\u1200");
|
||||
assertEq(s.replace(pat, toLatin1("A$&")), "FooAbarbaz123\u1200");
|
||||
assertEq(s.replace(pat, toLatin1("A$'")), "FooAbaz123\u1200baz123\u1200");
|
||||
|
||||
// TwoByte input and pat, Latin1 replacement
|
||||
s = "Foobar\u1200baz123";
|
||||
pat += "\u1200";
|
||||
assertEq(s.replace(pat, toLatin1("AB")), "FooABbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$$B")), "FooA$Bbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$`B")), "FooAFooBbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$&B")), "FooAbar\u1200Bbaz123");
|
||||
assertEq(s.replace(pat, toLatin1("A$'B")), "FooAbaz123Bbaz123");
|
||||
|
||||
// TwoByte input, pat and replacement
|
||||
assertEq(s.replace(pat, "A\u1300"), "FooA\u1300baz123");
|
||||
assertEq(s.replace(pat, "A$$\u1300"), "FooA$\u1300baz123");
|
||||
assertEq(s.replace(pat, "A$`\u1300"), "FooAFoo\u1300baz123");
|
||||
assertEq(s.replace(pat, "A$&\u1300"), "FooAbar\u1200\u1300baz123");
|
||||
assertEq(s.replace(pat, "A$'\u1300"), "FooAbaz123\u1300baz123");
|
||||
}
|
||||
testDollarReplacement();
|
||||
|
||||
function testRegExp() {
|
||||
var s = toLatin1("Foobar123bar234");
|
||||
assertEq(s.replace(/bar\d\d/, "456"), "Foo4563bar234");
|
||||
|
||||
// Latin1 input and replacement
|
||||
var re1 = /bar\d\d/;
|
||||
var re2 = /bar\d\d/g;
|
||||
assertEq(s.replace(re1, toLatin1("789")), "Foo7893bar234");
|
||||
assertEq(s.replace(re2, toLatin1("789\u00ff")), "Foo789\u00ff3789\u00ff4");
|
||||
|
||||
// Latin1 input, TwoByte replacement
|
||||
assertEq(s.replace(re1, "789\u1200"), "Foo789\u12003bar234");
|
||||
assertEq(s.replace(re2, "789\u1200"), "Foo789\u12003789\u12004");
|
||||
|
||||
// TwoByte input, Latin1 replacement
|
||||
s += "\u1200";
|
||||
assertEq(s.replace(re1, toLatin1("7890")), "Foo78903bar234\u1200");
|
||||
assertEq(s.replace(re2, toLatin1("7890\u00ff")), "Foo7890\u00ff37890\u00ff4\u1200");
|
||||
|
||||
// TwoByte input and replacement
|
||||
assertEq(s.replace(re1, "789\u1200"), "Foo789\u12003bar234\u1200");
|
||||
assertEq(s.replace(re2, "789\u1200"), "Foo789\u12003789\u12004\u1200");
|
||||
}
|
||||
testRegExp();
|
||||
|
||||
function testRegExpDollar() {
|
||||
var s = toLatin1("Foobar123bar2345");
|
||||
|
||||
// Latin1 input and replacement
|
||||
var re1 = /bar\d\d/;
|
||||
var re2 = /bar(\d\d)/g;
|
||||
assertEq(s.replace(re1, toLatin1("--$&--")), "Foo--bar12--3bar2345");
|
||||
assertEq(s.replace(re2, toLatin1("--$'\u00ff--")), "Foo--3bar2345\xFF--3--45\xFF--45");
|
||||
assertEq(s.replace(re2, toLatin1("--$`--")), "Foo--Foo--3--Foobar123--45");
|
||||
|
||||
// Latin1 input, TwoByte replacement
|
||||
assertEq(s.replace(re1, "\u1200$$"), "Foo\u1200$3bar2345");
|
||||
assertEq(s.replace(re2, "\u1200$1"), "Foo\u1200123\u12002345");
|
||||
assertEq(s.replace(re2, "\u1200$'"), "Foo\u12003bar23453\u12004545");
|
||||
|
||||
// TwoByte input, Latin1 replacement
|
||||
s += "\u1200";
|
||||
assertEq(s.replace(re1, toLatin1("**$&**")), "Foo**bar12**3bar2345\u1200");
|
||||
assertEq(s.replace(re2, toLatin1("**$1**")), "Foo**12**3**23**45\u1200");
|
||||
assertEq(s.replace(re2, toLatin1("**$`**")), "Foo**Foo**3**Foobar123**45\u1200");
|
||||
assertEq(s.replace(re2, toLatin1("**$'$$**")), "Foo**3bar2345\u1200$**3**45\u1200$**45\u1200");
|
||||
|
||||
// TwoByte input and replacement
|
||||
assertEq(s.replace(re1, "**$&**\ueeee"), "Foo**bar12**\ueeee3bar2345\u1200");
|
||||
assertEq(s.replace(re2, "**$1**\ueeee"), "Foo**12**\ueeee3**23**\ueeee45\u1200");
|
||||
assertEq(s.replace(re2, "\ueeee**$`**"), "Foo\ueeee**Foo**3\ueeee**Foobar123**45\u1200");
|
||||
assertEq(s.replace(re2, "\ueeee**$'$$**"), "Foo\ueeee**3bar2345\u1200$**3\ueeee**45\u1200$**45\u1200");
|
||||
}
|
||||
testRegExpDollar();
|
||||
|
||||
function testFlattenPattern() {
|
||||
var s = "abcdef[g]abc";
|
||||
|
||||
// Latin1 pattern
|
||||
assertEq(s.replace(toLatin1("def[g]"), "--$&--", "gi"), "abc--def[g]--abc");
|
||||
|
||||
// TwoByte pattern
|
||||
s = "abcdef[g]\u1200abc";
|
||||
assertEq(s.replace("def[g]\u1200", "++$&++", "gi"), "abc++def[g]\u1200++abc");
|
||||
}
|
||||
testFlattenPattern();
|
||||
|
||||
function testReplaceEmpty() {
|
||||
// Latin1
|
||||
var s = toLatin1("--abcdefghijkl--abcdefghijkl--abcdefghijkl--abcdefghijkl");
|
||||
assertEq(s.replace(/abcd[eE]/g, ""), "--fghijkl--fghijkl--fghijkl--fghijkl");
|
||||
|
||||
s = "--abcdEf--";
|
||||
assertEq(s.replace(/abcd[eE]/g, ""), "--f--");
|
||||
|
||||
// TwoByte
|
||||
s = "--abcdefghijkl--abcdefghijkl--abcdefghijkl--abcdefghijkl\u1200";
|
||||
assertEq(s.replace(/abcd[eE]/g, ""), "--fghijkl--fghijkl--fghijkl--fghijkl\u1200");
|
||||
|
||||
s = "--abcdEf--\u1200";
|
||||
assertEq(s.replace(/abcd[eE]/g, ""), "--f--\u1200");
|
||||
}
|
||||
testReplaceEmpty();
|
|
@ -1491,8 +1491,8 @@ Simulator::setCallResult(int64_t res)
|
|||
int
|
||||
Simulator::readW(int32_t addr, SimInstruction *instr)
|
||||
{
|
||||
// The regexp engines emit unaligned loads, so we don't check for them here
|
||||
// like the other methods below.
|
||||
// The regexp engine emits unaligned loads, so we don't check for them here
|
||||
// like most of the other methods do.
|
||||
intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
|
@ -1512,13 +1512,10 @@ Simulator::writeW(int32_t addr, int value, SimInstruction *instr)
|
|||
uint16_t
|
||||
Simulator::readHU(int32_t addr, SimInstruction *instr)
|
||||
{
|
||||
if ((addr & 1) == 0) {
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
return 0;
|
||||
// The regexp engine emits unaligned loads, so we don't check for them here
|
||||
// like most of the other methods do.
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
int16_t
|
||||
|
|
321
js/src/jsstr.cpp
321
js/src/jsstr.cpp
|
@ -2020,25 +2020,40 @@ class MOZ_STACK_CLASS StringRegExpGuard
|
|||
*/
|
||||
static const size_t MAX_FLAT_PAT_LEN = 256;
|
||||
|
||||
static JSAtom *
|
||||
flattenPattern(JSContext *cx, JSAtom *patstr)
|
||||
template <typename CharT>
|
||||
static bool
|
||||
flattenPattern(StringBuffer &sb, const CharT *chars, size_t len)
|
||||
{
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.reserve(patstr->length()))
|
||||
return nullptr;
|
||||
|
||||
static const jschar ESCAPE_CHAR = '\\';
|
||||
const jschar *chars = patstr->chars();
|
||||
size_t len = patstr->length();
|
||||
for (const jschar *it = chars; it != chars + len; ++it) {
|
||||
static const char ESCAPE_CHAR = '\\';
|
||||
for (const CharT *it = chars; it < chars + len; ++it) {
|
||||
if (IsRegExpMetaChar(*it)) {
|
||||
if (!sb.append(ESCAPE_CHAR) || !sb.append(*it))
|
||||
return nullptr;
|
||||
return false;
|
||||
} else {
|
||||
if (!sb.append(*it))
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSAtom *
|
||||
flattenPattern(JSContext *cx, JSAtom *pat)
|
||||
{
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.reserve(pat->length()))
|
||||
return nullptr;
|
||||
|
||||
if (pat->hasLatin1Chars()) {
|
||||
AutoCheckCannotGC nogc;
|
||||
if (!flattenPattern(sb, pat->latin1Chars(nogc), pat->length()))
|
||||
return nullptr;
|
||||
} else {
|
||||
AutoCheckCannotGC nogc;
|
||||
if (!flattenPattern(sb, pat->twoByteChars(nogc), pat->length()))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sb.finishAtom();
|
||||
}
|
||||
|
||||
|
@ -2455,6 +2470,18 @@ class RopeBuilder {
|
|||
|
||||
namespace {
|
||||
|
||||
template <typename CharT>
|
||||
static uint32_t
|
||||
FindDollarIndex(const CharT *chars, size_t length)
|
||||
{
|
||||
if (const CharT *p = js_strchr_limit(chars, '$', chars + length)) {
|
||||
uint32_t dollarIndex = p - chars;
|
||||
MOZ_ASSERT(dollarIndex < length);
|
||||
return dollarIndex;
|
||||
}
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
struct ReplaceData
|
||||
{
|
||||
explicit ReplaceData(JSContext *cx)
|
||||
|
@ -2468,13 +2495,10 @@ struct ReplaceData
|
|||
elembase = nullptr;
|
||||
repstr = string;
|
||||
|
||||
const jschar *chars = repstr->chars();
|
||||
if (const jschar *p = js_strchr_limit(chars, '$', chars + repstr->length())) {
|
||||
dollarIndex = p - chars;
|
||||
MOZ_ASSERT(dollarIndex < repstr->length());
|
||||
} else {
|
||||
dollarIndex = UINT32_MAX;
|
||||
}
|
||||
AutoCheckCannotGC nogc;
|
||||
dollarIndex = string->hasLatin1Chars()
|
||||
? FindDollarIndex(string->latin1Chars(nogc), string->length())
|
||||
: FindDollarIndex(string->twoByteChars(nogc), string->length());
|
||||
}
|
||||
|
||||
inline void setReplacementFunction(JSObject *func) {
|
||||
|
@ -2550,8 +2574,9 @@ DoMatchForReplaceGlobal(JSContext *cx, RegExpStatics *res, HandleLinearString li
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool
|
||||
InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
|
||||
InterpretDollar(RegExpStatics *res, const CharT *bp, const CharT *dp, const CharT *ep,
|
||||
ReplaceData &rdata, JSSubString *out, size_t *skip)
|
||||
{
|
||||
JS_ASSERT(*dp == '$');
|
||||
|
@ -2568,7 +2593,7 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
|
|||
if (num > res->getMatches().parenCount())
|
||||
return false;
|
||||
|
||||
const jschar *cp = dp + 2;
|
||||
const CharT *cp = dp + 2;
|
||||
if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
|
||||
unsigned tmp = 10 * num + JS7_UNDEC(dc);
|
||||
if (tmp <= res->getMatches().parenCount()) {
|
||||
|
@ -2594,7 +2619,7 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
|
|||
*skip = 2;
|
||||
switch (dc) {
|
||||
case '$':
|
||||
out->init(rdata.repstr, dp - rdata.repstr->chars(), 1);
|
||||
out->init(rdata.repstr, dp - bp, 1);
|
||||
return true;
|
||||
case '&':
|
||||
res->getLastMatch(out);
|
||||
|
@ -2612,6 +2637,45 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
|
|||
return false;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool
|
||||
FindReplaceLengthString(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
|
||||
{
|
||||
JSLinearString *repstr = rdata.repstr;
|
||||
CheckedInt<uint32_t> replen = repstr->length();
|
||||
|
||||
if (rdata.dollarIndex != UINT32_MAX) {
|
||||
AutoCheckCannotGC nogc;
|
||||
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
|
||||
const CharT *bp = repstr->chars<CharT>(nogc);
|
||||
const CharT *dp = bp + rdata.dollarIndex;
|
||||
const CharT *ep = bp + repstr->length();
|
||||
do {
|
||||
JSSubString sub;
|
||||
size_t skip;
|
||||
if (InterpretDollar(res, bp, dp, ep, rdata, &sub, &skip)) {
|
||||
if (sub.length > skip)
|
||||
replen += sub.length - skip;
|
||||
else
|
||||
replen -= skip - sub.length;
|
||||
dp += skip;
|
||||
} else {
|
||||
dp++;
|
||||
}
|
||||
|
||||
dp = js_strchr_limit(dp, '$', ep);
|
||||
} while (dp);
|
||||
}
|
||||
|
||||
if (!replen.isValid()) {
|
||||
js_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
*sizep = replen.value();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
|
||||
{
|
||||
|
@ -2701,36 +2765,9 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
|
|||
return true;
|
||||
}
|
||||
|
||||
JSLinearString *repstr = rdata.repstr;
|
||||
CheckedInt<uint32_t> replen = repstr->length();
|
||||
if (rdata.dollarIndex != UINT32_MAX) {
|
||||
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
|
||||
const jschar *dp = repstr->chars() + rdata.dollarIndex;
|
||||
const jschar *ep = repstr->chars() + repstr->length();
|
||||
do {
|
||||
JSSubString sub;
|
||||
size_t skip;
|
||||
if (InterpretDollar(res, dp, ep, rdata, &sub, &skip)) {
|
||||
if (sub.length > skip)
|
||||
replen += sub.length - skip;
|
||||
else
|
||||
replen -= skip - sub.length;
|
||||
dp += skip;
|
||||
} else {
|
||||
dp++;
|
||||
}
|
||||
|
||||
dp = js_strchr_limit(dp, '$', ep);
|
||||
} while (dp);
|
||||
}
|
||||
|
||||
if (!replen.isValid()) {
|
||||
js_ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
*sizep = replen.value();
|
||||
return true;
|
||||
return rdata.repstr->hasLatin1Chars()
|
||||
? FindReplaceLengthString<Latin1Char>(cx, res, rdata, sizep)
|
||||
: FindReplaceLengthString<jschar>(cx, res, rdata, sizep);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2738,17 +2775,19 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
|
|||
* derived from FindReplaceLength), and has been inflated to TwoByte if
|
||||
* necessary.
|
||||
*/
|
||||
template <typename CharT>
|
||||
static void
|
||||
DoReplace(RegExpStatics *res, ReplaceData &rdata)
|
||||
{
|
||||
AutoCheckCannotGC nogc;
|
||||
JSLinearString *repstr = rdata.repstr;
|
||||
const jschar *bp = repstr->chars();
|
||||
const jschar *cp = bp;
|
||||
const CharT *bp = repstr->chars<CharT>(nogc);
|
||||
const CharT *cp = bp;
|
||||
|
||||
if (rdata.dollarIndex != UINT32_MAX) {
|
||||
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
|
||||
const jschar *dp = bp + rdata.dollarIndex;
|
||||
const jschar *ep = bp + repstr->length();
|
||||
const CharT *dp = bp + rdata.dollarIndex;
|
||||
const CharT *ep = bp + repstr->length();
|
||||
do {
|
||||
/* Move one of the constant portions of the replacement value. */
|
||||
size_t len = dp - cp;
|
||||
|
@ -2757,7 +2796,7 @@ DoReplace(RegExpStatics *res, ReplaceData &rdata)
|
|||
|
||||
JSSubString sub;
|
||||
size_t skip;
|
||||
if (InterpretDollar(res, dp, ep, rdata, &sub, &skip)) {
|
||||
if (InterpretDollar(res, bp, dp, ep, rdata, &sub, &skip)) {
|
||||
rdata.sb.infallibleAppendSubstring(sub.base, sub.offset, sub.length);
|
||||
cp += skip;
|
||||
dp += skip;
|
||||
|
@ -2810,10 +2849,12 @@ ReplaceRegExp(JSContext *cx, RegExpStatics *res, ReplaceData &rdata)
|
|||
return false;
|
||||
|
||||
/* Append skipped-over portion of the search value. */
|
||||
const jschar *left = str.chars() + leftoff;
|
||||
rdata.sb.infallibleAppend(left, leftlen);
|
||||
rdata.sb.infallibleAppendSubstring(&str, leftoff, leftlen);
|
||||
|
||||
DoReplace(res, rdata);
|
||||
if (rdata.repstr->hasLatin1Chars())
|
||||
DoReplace<Latin1Char>(res, rdata);
|
||||
else
|
||||
DoReplace<jschar>(res, rdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2895,6 +2936,57 @@ BuildFlatReplacement(JSContext *cx, HandleString textstr, HandleString repstr,
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool
|
||||
AppendDollarReplacement(StringBuffer &newReplaceChars, size_t firstDollarIndex,
|
||||
const FlatMatch &fm, JSLinearString *text,
|
||||
const CharT *repChars, size_t repLength)
|
||||
{
|
||||
JS_ASSERT(firstDollarIndex < repLength);
|
||||
|
||||
size_t matchStart = fm.match();
|
||||
size_t matchLimit = matchStart + fm.patternLength();
|
||||
|
||||
/* Move the pre-dollar chunk in bulk. */
|
||||
newReplaceChars.infallibleAppend(repChars, firstDollarIndex);
|
||||
|
||||
/* Move the rest char-by-char, interpreting dollars as we encounter them. */
|
||||
const CharT *repLimit = repChars + repLength;
|
||||
for (const CharT *it = repChars + firstDollarIndex; it < repLimit; ++it) {
|
||||
if (*it != '$' || it == repLimit - 1) {
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (*(it + 1)) {
|
||||
case '$': /* Eat one of the dollars. */
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
break;
|
||||
case '&':
|
||||
if (!newReplaceChars.appendSubstring(text, matchStart, matchLimit - matchStart))
|
||||
return false;
|
||||
break;
|
||||
case '`':
|
||||
if (!newReplaceChars.appendSubstring(text, 0, matchStart))
|
||||
return false;
|
||||
break;
|
||||
case '\'':
|
||||
if (!newReplaceChars.appendSubstring(text, matchLimit, text->length() - matchLimit))
|
||||
return false;
|
||||
break;
|
||||
default: /* The dollar we saw was not special (no matter what its mother told it). */
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
++it; /* We always eat an extra char in the above switch. */
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a linear-scan dollar substitution on the replacement text,
|
||||
* constructing a result string that looks like:
|
||||
|
@ -2926,45 +3018,18 @@ BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *reps
|
|||
if (!newReplaceChars.reserve(textstr->length() - fm.patternLength() + repstr->length()))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(firstDollarIndex < repstr->length());
|
||||
|
||||
/* Move the pre-dollar chunk in bulk. */
|
||||
newReplaceChars.infallibleAppend(repstr->chars(), firstDollarIndex);
|
||||
|
||||
/* Move the rest char-by-char, interpreting dollars as we encounter them. */
|
||||
const jschar *textchars = textstr->chars();
|
||||
const jschar *repstrLimit = repstr->chars() + repstr->length();
|
||||
for (const jschar *it = repstr->chars() + firstDollarIndex; it < repstrLimit; ++it) {
|
||||
if (*it != '$' || it == repstrLimit - 1) {
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (*(it + 1)) {
|
||||
case '$': /* Eat one of the dollars. */
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
break;
|
||||
case '&':
|
||||
if (!newReplaceChars.append(textchars + matchStart, textchars + matchLimit))
|
||||
return false;
|
||||
break;
|
||||
case '`':
|
||||
if (!newReplaceChars.append(textchars, textchars + matchStart))
|
||||
return false;
|
||||
break;
|
||||
case '\'':
|
||||
if (!newReplaceChars.append(textchars + matchLimit, textchars + textstr->length()))
|
||||
return false;
|
||||
break;
|
||||
default: /* The dollar we saw was not special (no matter what its mother told it). */
|
||||
if (!newReplaceChars.append(*it))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
++it; /* We always eat an extra char in the above switch. */
|
||||
bool res;
|
||||
if (repstr->hasLatin1Chars()) {
|
||||
AutoCheckCannotGC nogc;
|
||||
res = AppendDollarReplacement(newReplaceChars, firstDollarIndex, fm, textstr,
|
||||
repstr->latin1Chars(nogc), repstr->length());
|
||||
} else {
|
||||
AutoCheckCannotGC nogc;
|
||||
res = AppendDollarReplacement(newReplaceChars, firstDollarIndex, fm, textstr,
|
||||
repstr->twoByteChars(nogc), repstr->length());
|
||||
}
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
RootedString leftSide(cx, js_NewDependentString(cx, textstr, 0, matchStart));
|
||||
if (!leftSide)
|
||||
|
@ -2998,25 +3063,35 @@ struct StringRange
|
|||
{ }
|
||||
};
|
||||
|
||||
static inline JSFatInlineString *
|
||||
FlattenSubstrings(JSContext *cx, const jschar *chars,
|
||||
const StringRange *ranges, size_t rangesLen, size_t outputLen)
|
||||
template <typename CharT>
|
||||
static void
|
||||
CopySubstringsToFatInline(JSFatInlineString *dest, const CharT *src, const StringRange *ranges,
|
||||
size_t rangesLen, size_t outputLen)
|
||||
{
|
||||
JS_ASSERT(JSFatInlineString::twoByteLengthFits(outputLen));
|
||||
CharT *buf = dest->init<CharT>(outputLen);
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < rangesLen; i++) {
|
||||
PodCopy(buf + pos, src + ranges[i].start, ranges[i].length);
|
||||
pos += ranges[i].length;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(pos == outputLen);
|
||||
buf[outputLen] = 0;
|
||||
}
|
||||
|
||||
static inline JSFatInlineString *
|
||||
FlattenSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr, const StringRange *ranges,
|
||||
size_t rangesLen, size_t outputLen)
|
||||
{
|
||||
JSFatInlineString *str = js_NewGCFatInlineString<CanGC>(cx);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
|
||||
jschar *buf = str->initTwoByte(outputLen);
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < rangesLen; i++) {
|
||||
PodCopy(buf + pos, chars + ranges[i].start, ranges[i].length);
|
||||
pos += ranges[i].length;
|
||||
}
|
||||
JS_ASSERT(pos == outputLen);
|
||||
|
||||
buf[outputLen] = 0;
|
||||
AutoCheckCannotGC nogc;
|
||||
if (flatStr->hasLatin1Chars())
|
||||
CopySubstringsToFatInline(str, flatStr->latin1Chars(nogc), ranges, rangesLen, outputLen);
|
||||
else
|
||||
CopySubstringsToFatInline(str, flatStr->twoByteChars(nogc), ranges, rangesLen, outputLen);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -3030,9 +3105,10 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
|
|||
if (rangesLen == 1)
|
||||
return js_NewDependentString(cx, flatStr, ranges[0].start, ranges[0].length);
|
||||
|
||||
const jschar *chars = flatStr->getChars(cx);
|
||||
if (!chars)
|
||||
return nullptr;
|
||||
bool isLatin1 = flatStr->hasLatin1Chars();
|
||||
uint32_t fatInlineMaxLength = isLatin1
|
||||
? JSFatInlineString::MAX_LENGTH_LATIN1
|
||||
: JSFatInlineString::MAX_LENGTH_TWO_BYTE;
|
||||
|
||||
/* Collect substrings into a rope */
|
||||
size_t i = 0;
|
||||
|
@ -3044,7 +3120,7 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
|
|||
size_t substrLen = 0;
|
||||
size_t end = i;
|
||||
for (; end < rangesLen; end++) {
|
||||
if (substrLen + ranges[end].length > JSFatInlineString::MAX_LENGTH_TWO_BYTE)
|
||||
if (substrLen + ranges[end].length > fatInlineMaxLength)
|
||||
break;
|
||||
substrLen += ranges[end].length;
|
||||
}
|
||||
|
@ -3055,7 +3131,7 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
|
|||
part = js_NewDependentString(cx, flatStr, sr.start, sr.length);
|
||||
} else {
|
||||
/* Copy the ranges (linearly) into a JSFatInlineString */
|
||||
part = FlattenSubstrings(cx, chars, ranges + i, end - i, substrLen);
|
||||
part = FlattenSubstrings(cx, flatStr, ranges + i, end - i, substrLen);
|
||||
i = end;
|
||||
}
|
||||
|
||||
|
@ -4623,17 +4699,24 @@ js_strdup(js::ThreadSafeContext *cx, const jschar *s)
|
|||
return ret;
|
||||
}
|
||||
|
||||
jschar *
|
||||
js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
|
||||
template <typename CharT>
|
||||
const CharT *
|
||||
js_strchr_limit(const CharT *s, jschar c, const CharT *limit)
|
||||
{
|
||||
while (s < limit) {
|
||||
if (*s == c)
|
||||
return (jschar *)s;
|
||||
return s;
|
||||
s++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template const Latin1Char *
|
||||
js_strchr_limit(const Latin1Char *s, jschar c, const Latin1Char *limit);
|
||||
|
||||
template const jschar *
|
||||
js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
|
||||
|
||||
jschar *
|
||||
js::InflateString(ThreadSafeContext *cx, const char *bytes, size_t *lengthp)
|
||||
{
|
||||
|
|
|
@ -231,8 +231,9 @@ js_strlen(const jschar *s);
|
|||
extern int32_t
|
||||
js_strcmp(const jschar *lhs, const jschar *rhs);
|
||||
|
||||
extern jschar *
|
||||
js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
|
||||
template <typename CharT>
|
||||
extern const CharT *
|
||||
js_strchr_limit(const CharT *s, jschar c, const CharT *limit);
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
js_strncpy(jschar *dst, const jschar *src, size_t nelem)
|
||||
|
|
|
@ -28,6 +28,8 @@ using mozilla::DebugOnly;
|
|||
using mozilla::Maybe;
|
||||
using js::frontend::TokenStream;
|
||||
|
||||
using JS::AutoCheckCannotGC;
|
||||
|
||||
JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD);
|
||||
JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
|
||||
JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
|
||||
|
@ -592,9 +594,20 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t *lastIndex
|
|||
|
||||
if (uint8_t *byteCode = maybeByteCode(input->hasLatin1Chars())) {
|
||||
AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
|
||||
const jschar *chars = input->chars() + charsOffset;
|
||||
RegExpRunStatus result =
|
||||
irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
|
||||
|
||||
AutoStableStringChars inputChars(cx, input);
|
||||
if (!inputChars.init())
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
RegExpRunStatus result;
|
||||
if (inputChars.isLatin1()) {
|
||||
const Latin1Char *chars = inputChars.latin1Range().start().get() + charsOffset;
|
||||
result = irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
|
||||
} else {
|
||||
const jschar *chars = inputChars.twoByteRange().start().get() + charsOffset;
|
||||
result = irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
|
||||
}
|
||||
|
||||
if (result == RegExpRunStatus_Success) {
|
||||
matches.displace(displacement);
|
||||
matches.checkAgainst(origLength);
|
||||
|
@ -608,8 +621,14 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t *lastIndex
|
|||
RegExpRunStatus result;
|
||||
{
|
||||
AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
|
||||
const jschar *chars = input->chars() + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, jitCodeTwoByte, chars, start, length, &matches);
|
||||
AutoCheckCannotGC nogc;
|
||||
if (input->hasLatin1Chars()) {
|
||||
const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, jitCodeLatin1, chars, start, length, &matches);
|
||||
} else {
|
||||
const jschar *chars = input->twoByteChars(nogc) + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, jitCodeTwoByte, chars, start, length, &matches);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == RegExpRunStatus_Error) {
|
||||
|
@ -885,10 +904,10 @@ js::ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut)
|
|||
bool ok;
|
||||
jschar lastParsed;
|
||||
if (linear->hasLatin1Chars()) {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
AutoCheckCannotGC nogc;
|
||||
ok = ::ParseRegExpFlags(linear->latin1Chars(nogc), len, flagsOut, &lastParsed);
|
||||
} else {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
AutoCheckCannotGC nogc;
|
||||
ok = ::ParseRegExpFlags(linear->twoByteChars(nogc), len, flagsOut, &lastParsed);
|
||||
}
|
||||
|
||||
|
|
|
@ -255,7 +255,7 @@ inline void
|
|||
StringBuffer::infallibleAppendSubstring(JSLinearString *base, size_t off, size_t len)
|
||||
{
|
||||
MOZ_ASSERT(off + len <= base->length());
|
||||
MOZ_ASSERT(base->hasLatin1Chars() == isLatin1());
|
||||
MOZ_ASSERT_IF(base->hasTwoByteChars(), isTwoByte());
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (base->hasLatin1Chars())
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
#include "uachelper.h"
|
||||
#include "updatehelper.h"
|
||||
|
||||
// Link w/ subsystem window so we don't get a console when executing
|
||||
// this binary through the installer.
|
||||
#pragma comment(linker, "/SUBSYSTEM:windows")
|
||||
|
||||
SERVICE_STATUS gSvcStatus = { 0 };
|
||||
SERVICE_STATUS_HANDLE gSvcStatusHandle = nullptr;
|
||||
HANDLE gWorkDoneEvent = nullptr;
|
||||
|
|
Загрузка…
Ссылка в новой задаче