Bug 1128528 - Don't unnecessarily require flat strings, to avoid wasting a ton of memory in pathological cases. r=luke

This commit is contained in:
Jan de Mooij 2015-02-04 11:16:02 +01:00
parent 38649f4a52
commit 810f7413a5
5 changed files with 62 additions and 62 deletions

View File

@ -191,7 +191,7 @@ ParseEvalStringAsJSON(JSContext *cx, const mozilla::Range<const CharT> chars, Mu
}
static EvalJSONResult
TryEvalJSON(JSContext *cx, JSFlatString *str, MutableHandleValue rval)
TryEvalJSON(JSContext *cx, JSLinearString *str, MutableHandleValue rval)
{
if (str->hasLatin1Chars()) {
AutoCheckCannotGC nogc;
@ -203,13 +203,13 @@ TryEvalJSON(JSContext *cx, JSFlatString *str, MutableHandleValue rval)
return EvalJSON_NotJSON;
}
AutoStableStringChars flatChars(cx);
if (!flatChars.init(cx, str))
AutoStableStringChars linearChars(cx);
if (!linearChars.init(cx, str))
return EvalJSON_Failure;
return flatChars.isLatin1()
? ParseEvalStringAsJSON(cx, flatChars.latin1Range(), rval)
: ParseEvalStringAsJSON(cx, flatChars.twoByteRange(), rval);
return linearChars.isLatin1()
? ParseEvalStringAsJSON(cx, linearChars.latin1Range(), rval)
: ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval);
}
// Define subset of ExecuteType so that casting performs the injection.
@ -277,19 +277,19 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
thisv = ObjectValue(*thisobj);
}
Rooted<JSFlatString*> flatStr(cx, str->ensureFlat(cx));
if (!flatStr)
RootedLinearString linearStr(cx, str->ensureLinear(cx));
if (!linearStr)
return false;
RootedScript callerScript(cx, caller ? caller.script() : nullptr);
EvalJSONResult ejr = TryEvalJSON(cx, flatStr, args.rval());
EvalJSONResult ejr = TryEvalJSON(cx, linearStr, args.rval());
if (ejr != EvalJSON_NotJSON)
return ejr == EvalJSON_Success;
EvalScriptGuard esg(cx);
if (evalType == DIRECT_EVAL && caller.isNonEvalFunctionFrame())
esg.lookupInEvalCache(flatStr, callerScript, pc);
esg.lookupInEvalCache(linearStr, callerScript, pc);
if (!esg.foundScript()) {
RootedScript maybeScript(cx);
@ -323,18 +323,18 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset)
.maybeMakeStrictMode(evalType == DIRECT_EVAL && IsStrictEvalPC(pc));
AutoStableStringChars flatChars(cx);
if (!flatChars.initTwoByte(cx, flatStr))
AutoStableStringChars linearChars(cx);
if (!linearChars.initTwoByte(cx, linearStr))
return false;
const char16_t *chars = flatChars.twoByteRange().start().get();
SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller()
const char16_t *chars = linearChars.twoByteRange().start().get();
SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, flatStr->length(), ownership);
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, callerScript, staticScope,
options, srcBuf, flatStr, staticLevel);
options, srcBuf, linearStr, staticLevel);
if (!compiled)
return false;
@ -366,17 +366,17 @@ js::DirectEvalStringFromIon(JSContext *cx,
unsigned staticLevel = callerScript->staticLevel() + 1;
Rooted<JSFlatString*> flatStr(cx, str->ensureFlat(cx));
if (!flatStr)
RootedLinearString linearStr(cx, str->ensureLinear(cx));
if (!linearStr)
return false;
EvalJSONResult ejr = TryEvalJSON(cx, flatStr, vp);
EvalJSONResult ejr = TryEvalJSON(cx, linearStr, vp);
if (ejr != EvalJSON_NotJSON)
return ejr == EvalJSON_Success;
EvalScriptGuard esg(cx);
esg.lookupInEvalCache(flatStr, callerScript, pc);
esg.lookupInEvalCache(linearStr, callerScript, pc);
if (!esg.foundScript()) {
RootedScript maybeScript(cx);
@ -405,18 +405,18 @@ js::DirectEvalStringFromIon(JSContext *cx,
.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset)
.maybeMakeStrictMode(IsStrictEvalPC(pc));
AutoStableStringChars flatChars(cx);
if (!flatChars.initTwoByte(cx, flatStr))
AutoStableStringChars linearChars(cx);
if (!linearChars.initTwoByte(cx, linearStr))
return false;
const char16_t *chars = flatChars.twoByteRange().start().get();
SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller()
const char16_t *chars = linearChars.twoByteRange().start().get();
SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, flatStr->length(), ownership);
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, callerScript, staticScope,
options, srcBuf, flatStr, staticLevel);
options, srcBuf, linearStr, staticLevel);
if (!compiled)
return false;

View File

@ -836,20 +836,20 @@ json_parse(JSContext *cx, unsigned argc, Value *vp)
if (!str)
return false;
JSFlatString *flat = str->ensureFlat(cx);
if (!flat)
JSLinearString *linear = str->ensureLinear(cx);
if (!linear)
return false;
AutoStableStringChars flatChars(cx);
if (!flatChars.init(cx, flat))
AutoStableStringChars linearChars(cx);
if (!linearChars.init(cx, linear))
return false;
RootedValue reviver(cx, args.get(1));
HandleValue reviver = args.get(1);
/* Steps 2-5. */
return flatChars.isLatin1()
? ParseJSONWithReviver(cx, flatChars.latin1Range(), reviver, args.rval())
: ParseJSONWithReviver(cx, flatChars.twoByteRange(), reviver, args.rval());
return linearChars.isLatin1()
? ParseJSONWithReviver(cx, linearChars.latin1Range(), reviver, args.rval())
: ParseJSONWithReviver(cx, linearChars.twoByteRange(), reviver, args.rval());
}
/* ES5 15.12.3. */

View File

@ -3537,18 +3537,18 @@ reflect_parse(JSContext *cx, uint32_t argc, jsval *vp)
if (!serialize.init(builder))
return false;
JSFlatString *flat = src->ensureFlat(cx);
if (!flat)
JSLinearString *linear = src->ensureLinear(cx);
if (!linear)
return false;
AutoStableStringChars flatChars(cx);
if (!flatChars.initTwoByte(cx, flat))
AutoStableStringChars linearChars(cx);
if (!linearChars.initTwoByte(cx, linear))
return false;
CompileOptions options(cx);
options.setFileAndLine(filename, lineno);
options.setCanLazilyParse(false);
mozilla::Range<const char16_t> chars = flatChars.twoByteRange();
mozilla::Range<const char16_t> chars = linearChars.twoByteRange();
Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, chars.start().get(),
chars.length(), /* foldConstants = */ false, nullptr, nullptr);
if (!parser.checkOptions())

View File

@ -3065,32 +3065,32 @@ CopySubstringsToFatInline(JSFatInlineString *dest, const CharT *src, const Strin
}
static inline JSFatInlineString *
FlattenSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr, const StringRange *ranges,
FlattenSubstrings(JSContext *cx, HandleLinearString str, const StringRange *ranges,
size_t rangesLen, size_t outputLen)
{
JSFatInlineString *str = NewGCFatInlineString<CanGC>(cx);
if (!str)
JSFatInlineString *result = NewGCFatInlineString<CanGC>(cx);
if (!result)
return nullptr;
AutoCheckCannotGC nogc;
if (flatStr->hasLatin1Chars())
CopySubstringsToFatInline(str, flatStr->latin1Chars(nogc), ranges, rangesLen, outputLen);
if (str->hasLatin1Chars())
CopySubstringsToFatInline(result, str->latin1Chars(nogc), ranges, rangesLen, outputLen);
else
CopySubstringsToFatInline(str, flatStr->twoByteChars(nogc), ranges, rangesLen, outputLen);
return str;
CopySubstringsToFatInline(result, str->twoByteChars(nogc), ranges, rangesLen, outputLen);
return result;
}
static JSString *
AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
const StringRange *ranges, size_t rangesLen)
AppendSubstrings(JSContext *cx, HandleLinearString str, const StringRange *ranges,
size_t rangesLen)
{
MOZ_ASSERT(rangesLen);
/* For single substrings, construct a dependent string. */
if (rangesLen == 1)
return NewDependentString(cx, flatStr, ranges[0].start, ranges[0].length);
return NewDependentString(cx, str, ranges[0].start, ranges[0].length);
bool isLatin1 = flatStr->hasLatin1Chars();
bool isLatin1 = str->hasLatin1Chars();
uint32_t fatInlineMaxLength = JSFatInlineString::MAX_LENGTH_TWO_BYTE;
if (isLatin1)
fatInlineMaxLength = JSFatInlineString::MAX_LENGTH_LATIN1;
@ -3113,10 +3113,10 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
if (i == end) {
/* Not even one range fits JSFatInlineString, use DependentString */
const StringRange &sr = ranges[i++];
part = NewDependentString(cx, flatStr, sr.start, sr.length);
part = NewDependentString(cx, str, sr.start, sr.length);
} else {
/* Copy the ranges (linearly) into a JSFatInlineString */
part = FlattenSubstrings(cx, flatStr, ranges + i, end - i, substrLen);
part = FlattenSubstrings(cx, str, ranges + i, end - i, substrLen);
i = end;
}
@ -3134,13 +3134,13 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
static bool
StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, MutableHandleValue rval)
{
Rooted<JSFlatString*> flatStr(cx, str->ensureFlat(cx));
if (!flatStr)
RootedLinearString linearStr(cx, str->ensureLinear(cx));
if (!linearStr)
return false;
Vector<StringRange, 16, SystemAllocPolicy> ranges;
size_t charsLen = flatStr->length();
size_t charsLen = linearStr->length();
ScopedMatchPairs matches(&cx->tempLifoAlloc());
size_t startIndex = 0; /* Index used for iterating through the string. */
@ -3152,7 +3152,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl
if (!CheckForInterrupt(cx))
return false;
RegExpRunStatus status = re.execute(cx, flatStr, startIndex, &matches);
RegExpRunStatus status = re.execute(cx, linearStr, startIndex, &matches);
if (status == RegExpRunStatus_Error)
return false;
if (status == RegExpRunStatus_Success_NotFound)
@ -3183,7 +3183,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl
res = cx->global()->getRegExpStatics(cx);
if (!res)
return false;
res->updateLazily(cx, flatStr, &re, lazyIndex);
res->updateLazily(cx, linearStr, &re, lazyIndex);
}
rval.setString(str);
return true;
@ -3194,7 +3194,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl
if (!res)
return false;
res->updateLazily(cx, flatStr, &re, lazyIndex);
res->updateLazily(cx, linearStr, &re, lazyIndex);
/* Include any remaining part of the string. */
if (lastIndex < charsLen) {
@ -3208,7 +3208,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl
return true;
}
JSString *result = AppendSubstrings(cx, flatStr, ranges.begin(), ranges.length());
JSString *result = AppendSubstrings(cx, linearStr, ranges.begin(), ranges.length());
if (!result)
return false;

View File

@ -6016,8 +6016,8 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName, const Value &code
fullMethodName, "string", InformalValueTypeName(code));
return false;
}
Rooted<JSFlatString *> flat(cx, code.toString()->ensureFlat(cx));
if (!flat)
RootedLinearString linear(cx, code.toString()->ensureLinear(cx));
if (!linear)
return false;
/*
@ -6128,7 +6128,7 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName, const Value &code
AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
jsbytecode *pc = iter ? iter->pc() : nullptr;
AutoStableStringChars stableChars(cx);
if (!stableChars.initTwoByte(cx, flat))
if (!stableChars.initTwoByte(cx, linear))
return false;
mozilla::Range<const char16_t> chars = stableChars.twoByteRange();