Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (243080 => 243081)
--- trunk/Source/_javascript_Core/ChangeLog 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-03-18 17:50:41 UTC (rev 243081)
@@ -1,3 +1,54 @@
+2019-03-18 Yusuke Suzuki <[email protected]>
+
+ [JSC] jsSubstring should resolve rope before calling JSRopeString::create
+ https://bugs.webkit.org/show_bug.cgi?id=195840
+
+ Reviewed by Geoffrey Garen.
+
+ jsSubstring always ends up resolving rope of the base string because substring JSRopeString only accepts non-rope JSString
+ as its base. Instead of resolving ropes in finishCreationSubstring, we should resolve before passing it to JSRopeString.
+ So that, we can access string data before creating JSRopeString, and we can introduce optimizations like avoiding creation
+ of single character substrings.
+
+ We can find that a lot of substrings for length = 1 are allocated in RAMification regexp tests. This patch avoids creation of these
+ strings to save memory.
+
+ This patch also strengthen error checks caused by rope resolution for base of substrings. Previously we sometimes miss this checks.
+
+ * dfg/DFGOperations.cpp:
+ * runtime/JSString.cpp:
+ (JSC::JSString::dumpToStream):
+ * runtime/JSString.h:
+ (JSC::jsSubstring):
+ (JSC::jsSubstringOfResolved):
+ (JSC::jsSingleCharacterString):
+ * runtime/RegExpCachedResult.cpp:
+ (JSC::RegExpCachedResult::lastResult): We no longer need to have length = 0 path since jsSubstring returns an empty string if length == 0.
+ (JSC::RegExpCachedResult::leftContext):
+ (JSC::RegExpCachedResult::rightContext):
+ (JSC::RegExpCachedResult::setInput):
+ * runtime/RegExpGlobalData.cpp:
+ (JSC::RegExpGlobalData::getBackref):
+ (JSC::RegExpGlobalData::getLastParen):
+ * runtime/StringObject.h:
+ (JSC::jsStringWithReuse):
+ (JSC::jsSubstring):
+ * runtime/StringPrototype.cpp:
+ (JSC::replaceUsingRegExpSearch):
+ (JSC::operationStringProtoFuncReplaceRegExpEmptyStr):
+ (JSC::replaceUsingStringSearch):
+ (JSC::stringProtoFuncSlice):
+ (JSC::splitStringByOneCharacterImpl):
+ (JSC::stringProtoFuncSplitFast):
+ (JSC::stringProtoFuncSubstr):
+ (JSC::stringProtoFuncSubstring):
+ (JSC::stringProtoFuncToLowerCase):
+ (JSC::stringProtoFuncToUpperCase):
+ Some `const String& value = string->value(exec)` is dangerous if GC happens later. Changed to getting `String` instead of `const String&` here.
+
+ * runtime/StringPrototypeInlines.h:
+ (JSC::stringSlice):
+
2019-03-18 Mark Lam <[email protected]>
Missing a ThrowScope release in JSObject::toString().
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (243080 => 243081)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2019-03-18 17:50:41 UTC (rev 243081)
@@ -2168,7 +2168,7 @@
auto string = jsCast<JSString*>(cell)->value(exec);
RETURN_IF_EXCEPTION(scope, nullptr);
- return jsSubstring(exec, string, from, span);
+ return jsSubstring(&vm, string, from, span);
}
JSCell* JIT_OPERATION operationStringSlice(ExecState* exec, JSCell* cell, int32_t start, int32_t end)
@@ -2181,8 +2181,7 @@
RETURN_IF_EXCEPTION(scope, nullptr);
static_assert(static_cast<uint64_t>(JSString::MaxLength) <= static_cast<uint64_t>(std::numeric_limits<int32_t>::max()), "");
- scope.release();
- return stringSlice(exec, WTFMove(string), start, end);
+ return stringSlice(vm, WTFMove(string), start, end);
}
JSString* JIT_OPERATION operationToLowerCase(ExecState* exec, JSString* string, uint32_t failingIndex)
Modified: trunk/Source/_javascript_Core/runtime/JSString.cpp (243080 => 243081)
--- trunk/Source/_javascript_Core/runtime/JSString.cpp 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/runtime/JSString.cpp 2019-03-18 17:50:41 UTC (rev 243081)
@@ -75,9 +75,12 @@
const JSString* thisObject = jsCast<const JSString*>(cell);
out.printf("<%p, %s, [%u], ", thisObject, thisObject->className(vm), thisObject->length());
uintptr_t pointer = thisObject->m_fiber;
- if (pointer & isRopeInPointer)
- out.printf("[rope]");
- else {
+ if (pointer & isRopeInPointer) {
+ if (pointer & JSRopeString::isSubstringInPointer)
+ out.printf("[substring]");
+ else
+ out.printf("[rope]");
+ } else {
if (WTF::StringImpl* ourImpl = bitwise_cast<StringImpl*>(pointer)) {
if (ourImpl->is8Bit())
out.printf("[8 %p]", ourImpl->characters8());
Modified: trunk/Source/_javascript_Core/runtime/JSString.h (243080 => 243081)
--- trunk/Source/_javascript_Core/runtime/JSString.h 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/runtime/JSString.h 2019-03-18 17:50:41 UTC (rev 243081)
@@ -49,7 +49,6 @@
JSString* jsSingleCharacterString(VM*, UChar);
JSString* jsSingleCharacterString(ExecState*, UChar);
JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length);
-JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length);
// Non-trivial strings are two or more characters long.
// These functions are faster than just calling jsString.
@@ -507,42 +506,12 @@
initializeIsSubstring(true);
initializeLength(length);
initializeIs8Bit(base->is8Bit());
- if (base->isSubstring()) {
- JSRopeString* baseRope = jsCast<JSRopeString*>(base);
- initializeSubstringBase(baseRope->substringBase());
- initializeSubstringOffset(baseRope->substringOffset() + offset);
- } else {
- initializeSubstringBase(base);
- initializeSubstringOffset(offset);
- }
- ASSERT(length == this->length());
- }
-
- enum SubstringOfResolvedTag { SubstringOfResolved };
- JSRopeString(SubstringOfResolvedTag, VM& vm, JSString* base, unsigned offset, unsigned length)
- : JSString(vm)
- {
- RELEASE_ASSERT(!sumOverflows<int32_t>(offset, length));
- RELEASE_ASSERT(offset + length <= base->length());
- initializeIsSubstring(true);
- initializeLength(length);
- initializeIs8Bit(base->is8Bit());
initializeSubstringBase(base);
initializeSubstringOffset(offset);
ASSERT(length == this->length());
+ ASSERT(!base->isRope());
}
- ALWAYS_INLINE void finishCreationSubstring(VM& vm, ExecState* exec)
- {
- Base::finishCreation(vm);
- JSString* updatedBase = substringBase();
- // For now, let's not allow substrings with a rope base.
- // Resolve non-substring rope bases so we don't have to deal with it.
- // FIXME: Evaluate if this would be worth adding more branches.
- if (updatedBase->isRope())
- jsCast<JSRopeString*>(updatedBase)->resolveRope(exec);
- }
-
ALWAYS_INLINE void finishCreationSubstringOfResolved(VM& vm)
{
Base::finishCreation(vm);
@@ -591,18 +560,9 @@
return newString;
}
- static JSRopeString* create(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
- {
- JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, base, offset, length);
- newString->finishCreationSubstring(vm, exec);
- ASSERT(newString->length());
- ASSERT(newString->isRope());
- return newString;
- }
-
ALWAYS_INLINE static JSRopeString* createSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* base, unsigned offset, unsigned length)
{
- JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(SubstringOfResolved, vm, base, offset, length);
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(vm, base, offset, length);
newString->finishCreationSubstringOfResolved(vm);
ASSERT(newString->length());
ASSERT(newString->isRope());
@@ -844,16 +804,31 @@
return JSString::create(*vm, *s.impl());
}
-inline JSString* jsSubstring(VM& vm, ExecState* exec, JSString* s, unsigned offset, unsigned length)
+inline JSString* jsSubstring(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
{
- ASSERT(offset <= s->length());
- ASSERT(length <= s->length());
- ASSERT(offset + length <= s->length());
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ ASSERT(offset <= base->length());
+ ASSERT(length <= base->length());
+ ASSERT(offset + length <= base->length());
if (!length)
return vm.smallStrings.emptyString();
- if (!offset && length == s->length())
- return s;
- return JSRopeString::create(vm, exec, s, offset, length);
+ if (!offset && length == base->length())
+ return base;
+
+ // For now, let's not allow substrings with a rope base.
+ // Resolve non-substring rope bases so we don't have to deal with it.
+ // FIXME: Evaluate if this would be worth adding more branches.
+ if (base->isSubstring()) {
+ JSRopeString* baseRope = jsCast<JSRopeString*>(base);
+ base = baseRope->substringBase();
+ offset = baseRope->substringOffset() + offset;
+ ASSERT(!base->isRope());
+ } else if (base->isRope()) {
+ jsCast<JSRopeString*>(base)->resolveRope(exec);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ }
+ return jsSubstringOfResolved(vm, nullptr, base, offset, length);
}
inline JSString* jsSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* s, unsigned offset, unsigned length)
@@ -861,10 +836,17 @@
ASSERT(offset <= s->length());
ASSERT(length <= s->length());
ASSERT(offset + length <= s->length());
+ ASSERT(!s->isRope());
if (!length)
return vm.smallStrings.emptyString();
if (!offset && length == s->length())
return s;
+ if (length == 1) {
+ auto& base = s->valueInternal();
+ UChar character = base.characterAt(offset);
+ if (character <= maxSingleCharacterString)
+ return vm.smallStrings.singleCharacterString(character);
+ }
return JSRopeString::createSubstringOfResolved(vm, deferralContext, s, offset, length);
}
@@ -912,7 +894,6 @@
inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
-inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
inline JSString* jsNontrivialString(ExecState* exec, String&& s) { return jsNontrivialString(&exec->vm(), WTFMove(s)); }
inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
Modified: trunk/Source/_javascript_Core/runtime/RegExpCachedResult.cpp (243080 => 243081)
--- trunk/Source/_javascript_Core/runtime/RegExpCachedResult.cpp 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/runtime/RegExpCachedResult.cpp 2019-03-18 17:50:41 UTC (rev 243081)
@@ -46,14 +46,21 @@
JSArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
{
VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
if (!m_reified) {
m_reifiedInput.set(vm, owner, m_lastInput.get());
if (!m_lastRegExp)
m_lastRegExp.set(vm, owner, vm.regExpCache()->ensureEmptyRegExp(vm));
+
+ JSArray* result = nullptr;
if (m_result)
- m_reifiedResult.setWithoutWriteBarrier(createRegExpMatchesArray(exec, exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get(), m_result.start));
+ result = createRegExpMatchesArray(exec, exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get(), m_result.start);
else
- m_reifiedResult.setWithoutWriteBarrier(createEmptyRegExpMatchesArray(exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get()));
+ result = createEmptyRegExpMatchesArray(exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get());
+ RETURN_IF_EXCEPTION(scope, nullptr);
+
+ m_reifiedResult.setWithoutWriteBarrier(result);
m_reifiedLeftContext.clear();
m_reifiedRightContext.clear();
m_reified = true;
@@ -65,9 +72,17 @@
JSString* RegExpCachedResult::leftContext(ExecState* exec, JSObject* owner)
{
// Make sure we're reified.
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
lastResult(exec, owner);
- if (!m_reifiedLeftContext)
- m_reifiedLeftContext.set(exec->vm(), owner, m_result.start ? jsSubstring(exec, m_reifiedInput.get(), 0, m_result.start) : jsEmptyString(exec));
+ RETURN_IF_EXCEPTION(scope, nullptr);
+
+ if (!m_reifiedLeftContext) {
+ JSString* leftContext = jsSubstring(exec, m_reifiedInput.get(), 0, m_result.start);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ m_reifiedLeftContext.set(vm, owner, leftContext);
+ }
return m_reifiedLeftContext.get();
}
@@ -74,10 +89,17 @@
JSString* RegExpCachedResult::rightContext(ExecState* exec, JSObject* owner)
{
// Make sure we're reified.
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
lastResult(exec, owner);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+
if (!m_reifiedRightContext) {
unsigned length = m_reifiedInput->length();
- m_reifiedRightContext.set(exec->vm(), owner, m_result.end != length ? jsSubstring(exec, m_reifiedInput.get(), m_result.end, length - m_result.end) : jsEmptyString(exec));
+ JSString* rightContext = jsSubstring(exec, m_reifiedInput.get(), m_result.end, length - m_result.end);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ m_reifiedRightContext.set(vm, owner, rightContext);
}
return m_reifiedRightContext.get();
}
@@ -85,11 +107,17 @@
void RegExpCachedResult::setInput(ExecState* exec, JSObject* owner, JSString* input)
{
// Make sure we're reified, otherwise m_reifiedInput will be ignored.
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
lastResult(exec, owner);
+ RETURN_IF_EXCEPTION(scope, void());
leftContext(exec, owner);
+ RETURN_IF_EXCEPTION(scope, void());
rightContext(exec, owner);
+ RETURN_IF_EXCEPTION(scope, void());
ASSERT(m_reified);
- m_reifiedInput.set(exec->vm(), owner, input);
+ m_reifiedInput.set(vm, owner, input);
}
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/RegExpGlobalData.cpp (243080 => 243081)
--- trunk/Source/_javascript_Core/runtime/RegExpGlobalData.cpp 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/runtime/RegExpGlobalData.cpp 2019-03-18 17:50:41 UTC (rev 243081)
@@ -35,7 +35,11 @@
JSValue RegExpGlobalData::getBackref(ExecState* exec, JSGlobalObject* owner, unsigned i)
{
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
JSArray* array = m_cachedResult.lastResult(exec, owner);
+ RETURN_IF_EXCEPTION(scope, { });
if (i < array->length()) {
JSValue result = JSValue(array).get(exec, i);
@@ -43,12 +47,17 @@
if (!result.isUndefined())
return result;
}
- return jsEmptyString(exec);
+ return jsEmptyString(&vm);
}
JSValue RegExpGlobalData::getLastParen(ExecState* exec, JSGlobalObject* owner)
{
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
JSArray* array = m_cachedResult.lastResult(exec, owner);
+ RETURN_IF_EXCEPTION(scope, { });
+
unsigned length = array->length();
if (length > 1) {
JSValue result = JSValue(array).get(exec, length - 1);
@@ -56,7 +65,7 @@
if (!result.isUndefined())
return result;
}
- return jsEmptyString(exec);
+ return jsEmptyString(&vm);
}
JSValue RegExpGlobalData::getLeftContext(ExecState* exec, JSGlobalObject* owner)
Modified: trunk/Source/_javascript_Core/runtime/StringObject.h (243080 => 243081)
--- trunk/Source/_javascript_Core/runtime/StringObject.h 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/runtime/StringObject.h 2019-03-18 17:50:41 UTC (rev 243081)
@@ -85,7 +85,7 @@
ASSERT(asString(originalValue)->value(exec) == string);
return asString(originalValue);
}
- return jsString(exec, string);
+ return jsString(&exec->vm(), string);
}
// Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString.
@@ -99,7 +99,7 @@
ASSERT(asString(originalValue)->value(exec) == string);
return jsSubstring(exec, asString(originalValue), offset, length);
}
- return jsSubstring(exec, string, offset, length);
+ return jsSubstring(&exec->vm(), string, offset, length);
}
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (243080 => 243081)
--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2019-03-18 17:50:41 UTC (rev 243081)
@@ -527,7 +527,7 @@
{
auto scope = DECLARE_THROW_SCOPE(vm);
- const String& source = string->value(exec);
+ String source = string->value(exec);
unsigned sourceLen = source.length();
RETURN_IF_EXCEPTION(scope, nullptr);
RegExpObject* regExpObject = jsCast<RegExpObject*>(searchValue);
@@ -656,8 +656,10 @@
if (matchStart < 0)
patternValue = jsUndefined();
- else
- patternValue = jsSubstring(exec, source, matchStart, matchLen);
+ else {
+ patternValue = jsSubstring(&vm, source, matchStart, matchLen);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ }
args.append(patternValue);
@@ -735,7 +737,7 @@
// ES5.1 15.5.4.10 step 8.a.
searchValue->setLastIndex(exec, 0);
RETURN_IF_EXCEPTION(scope, nullptr);
- const String& source = thisValue->value(exec);
+ String source = thisValue->value(exec);
RETURN_IF_EXCEPTION(scope, nullptr);
RELEASE_AND_RETURN(scope, removeUsingRegExpSearch(vm, exec, thisValue, source, regExp));
}
@@ -778,7 +780,7 @@
{
auto scope = DECLARE_THROW_SCOPE(vm);
- const String& string = jsString->value(exec);
+ String string = jsString->value(exec);
RETURN_IF_EXCEPTION(scope, nullptr);
String searchString = searchValue.toWTFString(exec);
RETURN_IF_EXCEPTION(scope, nullptr);
@@ -792,7 +794,9 @@
CallType callType = getCallData(vm, replaceValue, callData);
if (callType != CallType::None) {
MarkedArgumentBuffer args;
- args.append(jsSubstring(exec, string, matchStart, searchString.impl()->length()));
+ auto* substring = jsSubstring(&vm, string, matchStart, searchString.impl()->length());
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ args.append(substring);
args.append(jsNumber(matchStart));
args.append(jsString);
ASSERT(!args.hasOverflowed());
@@ -1153,8 +1157,7 @@
RETURN_IF_EXCEPTION(scope, encodedJSValue());
double end = a1.isUndefined() ? len : a1.toInteger(exec);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- scope.release();
- return JSValue::encode(stringSlice(exec, WTFMove(s), start, end));
+ return JSValue::encode(stringSlice(vm, WTFMove(s), start, end));
}
// Return true in case of early return (resultLength got to limitLength).
@@ -1176,8 +1179,10 @@
// through q (exclusive).
// 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
// Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
- result->putDirectIndex(exec, resultLength, jsSubstring(exec, originalValue, input, position, matchPosition - position));
+ auto* substring = jsSubstring(exec, originalValue, input, position, matchPosition - position);
RETURN_IF_EXCEPTION(scope, false);
+ result->putDirectIndex(exec, resultLength, substring);
+ RETURN_IF_EXCEPTION(scope, false);
// 3. Increment lengthA by 1.
// 4. If lengthA == lim, return A.
if (++resultLength == limitLength)
@@ -1300,8 +1305,10 @@
// 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
// through q (exclusive).
// 2. Call CreateDataProperty(A, ToString(lengthA), T).
- result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
- RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ auto* substring = jsSubstring(exec, thisValue, input, position, matchPosition - position);
+ RETURN_IF_EXCEPTION(scope, { });
+ result->putDirectIndex(exec, resultLength, substring);
+ RETURN_IF_EXCEPTION(scope, { });
// 3. Increment lengthA by 1.
// 4. If lengthA == lim, return A.
if (++resultLength == limit)
@@ -1316,8 +1323,10 @@
// 15. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
// through s (exclusive).
// 16. Call CreateDataProperty(A, ToString(lengthA), T).
+ auto* substring = jsSubstring(exec, thisValue, input, position, input.length() - position);
+ RETURN_IF_EXCEPTION(scope, { });
scope.release();
- result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position));
+ result->putDirectIndex(exec, resultLength++, substring);
// 17. Return A.
return JSValue::encode(result);
@@ -1361,9 +1370,10 @@
length = len - start;
unsigned substringStart = static_cast<unsigned>(start);
unsigned substringLength = static_cast<unsigned>(length);
+ scope.release();
if (jsString)
return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
- return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
+ return JSValue::encode(jsSubstring(&vm, uString, substringStart, substringLength));
}
EncodedJSValue JSC_HOST_CALL builtinStringSubstrInternal(ExecState* exec)
@@ -1421,7 +1431,7 @@
}
unsigned substringStart = static_cast<unsigned>(start);
unsigned substringLength = static_cast<unsigned>(end) - substringStart;
- return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength)));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
@@ -1434,7 +1444,7 @@
return throwVMTypeError(exec, scope);
JSString* sVal = thisValue.toString(exec);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- const String& s = sVal->value(exec);
+ String s = sVal->value(exec);
String lowercasedString = s.convertToLowercaseWithoutLocale();
if (lowercasedString.impl() == s.impl())
return JSValue::encode(sVal);
@@ -1451,7 +1461,7 @@
return throwVMTypeError(exec, scope);
JSString* sVal = thisValue.toString(exec);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- const String& s = sVal->value(exec);
+ String s = sVal->value(exec);
String uppercasedString = s.convertToUppercaseWithoutLocale();
if (uppercasedString.impl() == s.impl())
return JSValue::encode(sVal);
Modified: trunk/Source/_javascript_Core/runtime/StringPrototypeInlines.h (243080 => 243081)
--- trunk/Source/_javascript_Core/runtime/StringPrototypeInlines.h 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/_javascript_Core/runtime/StringPrototypeInlines.h 2019-03-18 17:50:41 UTC (rev 243081)
@@ -30,7 +30,7 @@
namespace JSC {
template<typename NumberType>
-ALWAYS_INLINE JSString* stringSlice(ExecState* exec, String&& string, NumberType start, NumberType end)
+ALWAYS_INLINE JSString* stringSlice(VM& vm, String&& string, NumberType start, NumberType end)
{
int32_t length = string.length();
NumberType from = start < 0 ? length + start : start;
@@ -40,9 +40,9 @@
from = 0;
if (to > length)
to = length;
- return jsSubstring(exec, WTFMove(string), static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from));
+ return jsSubstring(&vm, WTFMove(string), static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from));
}
- return jsEmptyString(exec);
+ return jsEmptyString(&vm);
}
} // namespace JSC