<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[243081] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/243081">243081</a></dd>
<dt>Author</dt> <dd>ysuzuki@apple.com</dd>
<dt>Date</dt> <dd>2019-03-18 10:50:41 -0700 (Mon, 18 Mar 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>[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):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSStringcpp">trunk/Source/JavaScriptCore/runtime/JSString.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSStringh">trunk/Source/JavaScriptCore/runtime/JSString.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpCachedResultcpp">trunk/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpGlobalDatacpp">trunk/Source/JavaScriptCore/runtime/RegExpGlobalData.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStringObjecth">trunk/Source/JavaScriptCore/runtime/StringObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStringPrototypecpp">trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStringPrototypeInlinesh">trunk/Source/JavaScriptCore/runtime/StringPrototypeInlines.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/ChangeLog       2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -1,3 +1,54 @@
</span><ins>+2019-03-18  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [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):
+
</ins><span class="cx"> 2019-03-18  Mark Lam  <mark.lam@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Missing a ThrowScope release in JSObject::toString().
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp   2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -2168,7 +2168,7 @@
</span><span class="cx"> 
</span><span class="cx">     auto string = jsCast<JSString*>(cell)->value(exec);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, nullptr);
</span><del>-    return jsSubstring(exec, string, from, span);
</del><ins>+    return jsSubstring(&vm, string, from, span);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSCell* JIT_OPERATION operationStringSlice(ExecState* exec, JSCell* cell, int32_t start, int32_t end)
</span><span class="lines">@@ -2181,8 +2181,7 @@
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">     static_assert(static_cast<uint64_t>(JSString::MaxLength) <= static_cast<uint64_t>(std::numeric_limits<int32_t>::max()), "");
</span><span class="cx"> 
</span><del>-    scope.release();
-    return stringSlice(exec, WTFMove(string), start, end);
</del><ins>+    return stringSlice(vm, WTFMove(string), start, end);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSString* JIT_OPERATION operationToLowerCase(ExecState* exec, JSString* string, uint32_t failingIndex)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSStringcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSString.cpp (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSString.cpp 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/runtime/JSString.cpp    2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -75,9 +75,12 @@
</span><span class="cx">     const JSString* thisObject = jsCast<const JSString*>(cell);
</span><span class="cx">     out.printf("<%p, %s, [%u], ", thisObject, thisObject->className(vm), thisObject->length());
</span><span class="cx">     uintptr_t pointer = thisObject->m_fiber;
</span><del>-    if (pointer & isRopeInPointer)
-        out.printf("[rope]");
-    else {
</del><ins>+    if (pointer & isRopeInPointer) {
+        if (pointer & JSRopeString::isSubstringInPointer)
+            out.printf("[substring]");
+        else
+            out.printf("[rope]");
+    } else {
</ins><span class="cx">         if (WTF::StringImpl* ourImpl = bitwise_cast<StringImpl*>(pointer)) {
</span><span class="cx">             if (ourImpl->is8Bit())
</span><span class="cx">                 out.printf("[8 %p]", ourImpl->characters8());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSStringh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSString.h (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSString.h   2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/runtime/JSString.h      2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -49,7 +49,6 @@
</span><span class="cx"> JSString* jsSingleCharacterString(VM*, UChar);
</span><span class="cx"> JSString* jsSingleCharacterString(ExecState*, UChar);
</span><span class="cx"> JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length);
</span><del>-JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length);
</del><span class="cx"> 
</span><span class="cx"> // Non-trivial strings are two or more characters long.
</span><span class="cx"> // These functions are faster than just calling jsString.
</span><span class="lines">@@ -507,42 +506,12 @@
</span><span class="cx">         initializeIsSubstring(true);
</span><span class="cx">         initializeLength(length);
</span><span class="cx">         initializeIs8Bit(base->is8Bit());
</span><del>-        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());
</del><span class="cx">         initializeSubstringBase(base);
</span><span class="cx">         initializeSubstringOffset(offset);
</span><span class="cx">         ASSERT(length == this->length());
</span><ins>+        ASSERT(!base->isRope());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    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);
-    }
-
</del><span class="cx">     ALWAYS_INLINE void finishCreationSubstringOfResolved(VM& vm)
</span><span class="cx">     {
</span><span class="cx">         Base::finishCreation(vm);
</span><span class="lines">@@ -591,18 +560,9 @@
</span><span class="cx">         return newString;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    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;
-    }
-
</del><span class="cx">     ALWAYS_INLINE static JSRopeString* createSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* base, unsigned offset, unsigned length)
</span><span class="cx">     {
</span><del>-        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(SubstringOfResolved, vm, base, offset, length);
</del><ins>+        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(vm, base, offset, length);
</ins><span class="cx">         newString->finishCreationSubstringOfResolved(vm);
</span><span class="cx">         ASSERT(newString->length());
</span><span class="cx">         ASSERT(newString->isRope());
</span><span class="lines">@@ -844,16 +804,31 @@
</span><span class="cx">     return JSString::create(*vm, *s.impl());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSString* jsSubstring(VM& vm, ExecState* exec, JSString* s, unsigned offset, unsigned length)
</del><ins>+inline JSString* jsSubstring(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
</ins><span class="cx"> {
</span><del>-    ASSERT(offset <= s->length());
-    ASSERT(length <= s->length());
-    ASSERT(offset + length <= s->length());
</del><ins>+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    ASSERT(offset <= base->length());
+    ASSERT(length <= base->length());
+    ASSERT(offset + length <= base->length());
</ins><span class="cx">     if (!length)
</span><span class="cx">         return vm.smallStrings.emptyString();
</span><del>-    if (!offset && length == s->length())
-        return s;
-    return JSRopeString::create(vm, exec, s, offset, length);
</del><ins>+    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);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline JSString* jsSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* s, unsigned offset, unsigned length)
</span><span class="lines">@@ -861,10 +836,17 @@
</span><span class="cx">     ASSERT(offset <= s->length());
</span><span class="cx">     ASSERT(length <= s->length());
</span><span class="cx">     ASSERT(offset + length <= s->length());
</span><ins>+    ASSERT(!s->isRope());
</ins><span class="cx">     if (!length)
</span><span class="cx">         return vm.smallStrings.emptyString();
</span><span class="cx">     if (!offset && length == s->length())
</span><span class="cx">         return s;
</span><ins>+    if (length == 1) {
+        auto& base = s->valueInternal();
+        UChar character = base.characterAt(offset);
+        if (character <= maxSingleCharacterString)
+            return vm.smallStrings.singleCharacterString(character);
+    }
</ins><span class="cx">     return JSRopeString::createSubstringOfResolved(vm, deferralContext, s, offset, length);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -912,7 +894,6 @@
</span><span class="cx"> inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
</span><span class="cx"> inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
</span><span class="cx"> inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
</span><del>-inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
</del><span class="cx"> inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
</span><span class="cx"> inline JSString* jsNontrivialString(ExecState* exec, String&& s) { return jsNontrivialString(&exec->vm(), WTFMove(s)); }
</span><span class="cx"> inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpCachedResultcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp       2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp  2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -46,14 +46,21 @@
</span><span class="cx"> JSArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span><ins>+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     if (!m_reified) {
</span><span class="cx">         m_reifiedInput.set(vm, owner, m_lastInput.get());
</span><span class="cx">         if (!m_lastRegExp)
</span><span class="cx">             m_lastRegExp.set(vm, owner, vm.regExpCache()->ensureEmptyRegExp(vm));
</span><ins>+
+        JSArray* result = nullptr;
</ins><span class="cx">         if (m_result)
</span><del>-            m_reifiedResult.setWithoutWriteBarrier(createRegExpMatchesArray(exec, exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get(), m_result.start));
</del><ins>+            result = createRegExpMatchesArray(exec, exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get(), m_result.start);
</ins><span class="cx">         else
</span><del>-            m_reifiedResult.setWithoutWriteBarrier(createEmptyRegExpMatchesArray(exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get()));
</del><ins>+            result = createEmptyRegExpMatchesArray(exec->lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get());
+        RETURN_IF_EXCEPTION(scope, nullptr);
+
+        m_reifiedResult.setWithoutWriteBarrier(result);
</ins><span class="cx">         m_reifiedLeftContext.clear();
</span><span class="cx">         m_reifiedRightContext.clear();
</span><span class="cx">         m_reified = true;
</span><span class="lines">@@ -65,9 +72,17 @@
</span><span class="cx"> JSString* RegExpCachedResult::leftContext(ExecState* exec, JSObject* owner)
</span><span class="cx"> {
</span><span class="cx">     // Make sure we're reified.
</span><ins>+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     lastResult(exec, owner);
</span><del>-    if (!m_reifiedLeftContext)
-        m_reifiedLeftContext.set(exec->vm(), owner, m_result.start ? jsSubstring(exec, m_reifiedInput.get(), 0, m_result.start) : jsEmptyString(exec));
</del><ins>+    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);
+    }
</ins><span class="cx">     return m_reifiedLeftContext.get();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -74,10 +89,17 @@
</span><span class="cx"> JSString* RegExpCachedResult::rightContext(ExecState* exec, JSObject* owner)
</span><span class="cx"> {
</span><span class="cx">     // Make sure we're reified.
</span><ins>+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     lastResult(exec, owner);
</span><ins>+    RETURN_IF_EXCEPTION(scope, nullptr);
+
</ins><span class="cx">     if (!m_reifiedRightContext) {
</span><span class="cx">         unsigned length = m_reifiedInput->length();
</span><del>-        m_reifiedRightContext.set(exec->vm(), owner, m_result.end != length ? jsSubstring(exec, m_reifiedInput.get(), m_result.end, length - m_result.end) : jsEmptyString(exec));
</del><ins>+        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);
</ins><span class="cx">     }
</span><span class="cx">     return m_reifiedRightContext.get();
</span><span class="cx"> }
</span><span class="lines">@@ -85,11 +107,17 @@
</span><span class="cx"> void RegExpCachedResult::setInput(ExecState* exec, JSObject* owner, JSString* input)
</span><span class="cx"> {
</span><span class="cx">     // Make sure we're reified, otherwise m_reifiedInput will be ignored.
</span><ins>+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     lastResult(exec, owner);
</span><ins>+    RETURN_IF_EXCEPTION(scope, void());
</ins><span class="cx">     leftContext(exec, owner);
</span><ins>+    RETURN_IF_EXCEPTION(scope, void());
</ins><span class="cx">     rightContext(exec, owner);
</span><ins>+    RETURN_IF_EXCEPTION(scope, void());
</ins><span class="cx">     ASSERT(m_reified);
</span><del>-    m_reifiedInput.set(exec->vm(), owner, input);
</del><ins>+    m_reifiedInput.set(vm, owner, input);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpGlobalDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpGlobalData.cpp (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpGlobalData.cpp 2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/runtime/RegExpGlobalData.cpp    2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -35,7 +35,11 @@
</span><span class="cx"> 
</span><span class="cx"> JSValue RegExpGlobalData::getBackref(ExecState* exec, JSGlobalObject* owner, unsigned i)
</span><span class="cx"> {
</span><ins>+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     JSArray* array = m_cachedResult.lastResult(exec, owner);
</span><ins>+    RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx"> 
</span><span class="cx">     if (i < array->length()) {
</span><span class="cx">         JSValue result = JSValue(array).get(exec, i);
</span><span class="lines">@@ -43,12 +47,17 @@
</span><span class="cx">         if (!result.isUndefined())
</span><span class="cx">             return result;
</span><span class="cx">     }
</span><del>-    return jsEmptyString(exec);
</del><ins>+    return jsEmptyString(&vm);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSValue RegExpGlobalData::getLastParen(ExecState* exec, JSGlobalObject* owner)
</span><span class="cx"> {
</span><ins>+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     JSArray* array = m_cachedResult.lastResult(exec, owner);
</span><ins>+    RETURN_IF_EXCEPTION(scope, { });
+
</ins><span class="cx">     unsigned length = array->length();
</span><span class="cx">     if (length > 1) {
</span><span class="cx">         JSValue result = JSValue(array).get(exec, length - 1);
</span><span class="lines">@@ -56,7 +65,7 @@
</span><span class="cx">         if (!result.isUndefined())
</span><span class="cx">             return result;
</span><span class="cx">     }
</span><del>-    return jsEmptyString(exec);
</del><ins>+    return jsEmptyString(&vm);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSValue RegExpGlobalData::getLeftContext(ExecState* exec, JSGlobalObject* owner)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStringObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StringObject.h (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StringObject.h       2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/runtime/StringObject.h  2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -85,7 +85,7 @@
</span><span class="cx">         ASSERT(asString(originalValue)->value(exec) == string);
</span><span class="cx">         return asString(originalValue);
</span><span class="cx">     }
</span><del>-    return jsString(exec, string);
</del><ins>+    return jsString(&exec->vm(), string);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString.
</span><span class="lines">@@ -99,7 +99,7 @@
</span><span class="cx">         ASSERT(asString(originalValue)->value(exec) == string);
</span><span class="cx">         return jsSubstring(exec, asString(originalValue), offset, length);
</span><span class="cx">     }
</span><del>-    return jsSubstring(exec, string, offset, length);
</del><ins>+    return jsSubstring(&exec->vm(), string, offset, length);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStringPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp  2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp     2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -527,7 +527,7 @@
</span><span class="cx"> {
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx"> 
</span><del>-    const String& source = string->value(exec);
</del><ins>+    String source = string->value(exec);
</ins><span class="cx">     unsigned sourceLen = source.length();
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">     RegExpObject* regExpObject = jsCast<RegExpObject*>(searchValue);
</span><span class="lines">@@ -656,8 +656,10 @@
</span><span class="cx"> 
</span><span class="cx">                     if (matchStart < 0)
</span><span class="cx">                         patternValue = jsUndefined();
</span><del>-                    else
-                        patternValue = jsSubstring(exec, source, matchStart, matchLen);
</del><ins>+                    else {
+                        patternValue = jsSubstring(&vm, source, matchStart, matchLen);
+                        RETURN_IF_EXCEPTION(scope, nullptr);
+                    }
</ins><span class="cx"> 
</span><span class="cx">                     args.append(patternValue);
</span><span class="cx"> 
</span><span class="lines">@@ -735,7 +737,7 @@
</span><span class="cx">         // ES5.1 15.5.4.10 step 8.a.
</span><span class="cx">         searchValue->setLastIndex(exec, 0);
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, nullptr);
</span><del>-        const String& source = thisValue->value(exec);
</del><ins>+        String source = thisValue->value(exec);
</ins><span class="cx">         RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">         RELEASE_AND_RETURN(scope, removeUsingRegExpSearch(vm, exec, thisValue, source, regExp));
</span><span class="cx">     }
</span><span class="lines">@@ -778,7 +780,7 @@
</span><span class="cx"> {
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx"> 
</span><del>-    const String& string = jsString->value(exec);
</del><ins>+    String string = jsString->value(exec);
</ins><span class="cx">     RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">     String searchString = searchValue.toWTFString(exec);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="lines">@@ -792,7 +794,9 @@
</span><span class="cx">     CallType callType = getCallData(vm, replaceValue, callData);
</span><span class="cx">     if (callType != CallType::None) {
</span><span class="cx">         MarkedArgumentBuffer args;
</span><del>-        args.append(jsSubstring(exec, string, matchStart, searchString.impl()->length()));
</del><ins>+        auto* substring = jsSubstring(&vm, string, matchStart, searchString.impl()->length());
+        RETURN_IF_EXCEPTION(scope, nullptr);
+        args.append(substring);
</ins><span class="cx">         args.append(jsNumber(matchStart));
</span><span class="cx">         args.append(jsString);
</span><span class="cx">         ASSERT(!args.hasOverflowed());
</span><span class="lines">@@ -1153,8 +1157,7 @@
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="cx">     double end = a1.isUndefined() ? len : a1.toInteger(exec);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><del>-    scope.release();
-    return JSValue::encode(stringSlice(exec, WTFMove(s), start, end));
</del><ins>+    return JSValue::encode(stringSlice(vm, WTFMove(s), start, end));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Return true in case of early return (resultLength got to limitLength).
</span><span class="lines">@@ -1176,8 +1179,10 @@
</span><span class="cx">         //    through q (exclusive).
</span><span class="cx">         // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
</span><span class="cx">         //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
</span><del>-        result->putDirectIndex(exec, resultLength, jsSubstring(exec, originalValue, input, position, matchPosition - position));
</del><ins>+        auto* substring = jsSubstring(exec, originalValue, input, position, matchPosition - position);
</ins><span class="cx">         RETURN_IF_EXCEPTION(scope, false);
</span><ins>+        result->putDirectIndex(exec, resultLength, substring);
+        RETURN_IF_EXCEPTION(scope, false);
</ins><span class="cx">         // 3. Increment lengthA by 1.
</span><span class="cx">         // 4. If lengthA == lim, return A.
</span><span class="cx">         if (++resultLength == limitLength)
</span><span class="lines">@@ -1300,8 +1305,10 @@
</span><span class="cx">             // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
</span><span class="cx">             //    through q (exclusive).
</span><span class="cx">             // 2. Call CreateDataProperty(A, ToString(lengthA), T).
</span><del>-            result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
-            RETURN_IF_EXCEPTION(scope, encodedJSValue());
</del><ins>+            auto* substring = jsSubstring(exec, thisValue, input, position, matchPosition - position);
+            RETURN_IF_EXCEPTION(scope, { });
+            result->putDirectIndex(exec, resultLength, substring);
+            RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx">             // 3. Increment lengthA by 1.
</span><span class="cx">             // 4. If lengthA == lim, return A.
</span><span class="cx">             if (++resultLength == limit)
</span><span class="lines">@@ -1316,8 +1323,10 @@
</span><span class="cx">     // 15. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
</span><span class="cx">     //     through s (exclusive).
</span><span class="cx">     // 16. Call CreateDataProperty(A, ToString(lengthA), T).
</span><ins>+    auto* substring = jsSubstring(exec, thisValue, input, position, input.length() - position);
+    RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx">     scope.release();
</span><del>-    result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position));
</del><ins>+    result->putDirectIndex(exec, resultLength++, substring);
</ins><span class="cx"> 
</span><span class="cx">     // 17. Return A.
</span><span class="cx">     return JSValue::encode(result);
</span><span class="lines">@@ -1361,9 +1370,10 @@
</span><span class="cx">         length = len - start;
</span><span class="cx">     unsigned substringStart = static_cast<unsigned>(start);
</span><span class="cx">     unsigned substringLength = static_cast<unsigned>(length);
</span><ins>+    scope.release();
</ins><span class="cx">     if (jsString)
</span><span class="cx">         return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
</span><del>-    return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
</del><ins>+    return JSValue::encode(jsSubstring(&vm, uString, substringStart, substringLength));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL builtinStringSubstrInternal(ExecState* exec)
</span><span class="lines">@@ -1421,7 +1431,7 @@
</span><span class="cx">     }
</span><span class="cx">     unsigned substringStart = static_cast<unsigned>(start);
</span><span class="cx">     unsigned substringLength = static_cast<unsigned>(end) - substringStart;
</span><del>-    return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
</del><ins>+    RELEASE_AND_RETURN(scope, JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
</span><span class="lines">@@ -1434,7 +1444,7 @@
</span><span class="cx">         return throwVMTypeError(exec, scope);
</span><span class="cx">     JSString* sVal = thisValue.toString(exec);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><del>-    const String& s = sVal->value(exec);
</del><ins>+    String s = sVal->value(exec);
</ins><span class="cx">     String lowercasedString = s.convertToLowercaseWithoutLocale();
</span><span class="cx">     if (lowercasedString.impl() == s.impl())
</span><span class="cx">         return JSValue::encode(sVal);
</span><span class="lines">@@ -1451,7 +1461,7 @@
</span><span class="cx">         return throwVMTypeError(exec, scope);
</span><span class="cx">     JSString* sVal = thisValue.toString(exec);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><del>-    const String& s = sVal->value(exec);
</del><ins>+    String s = sVal->value(exec);
</ins><span class="cx">     String uppercasedString = s.convertToUppercaseWithoutLocale();
</span><span class="cx">     if (uppercasedString.impl() == s.impl())
</span><span class="cx">         return JSValue::encode(sVal);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStringPrototypeInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StringPrototypeInlines.h (243080 => 243081)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StringPrototypeInlines.h     2019-03-18 17:38:34 UTC (rev 243080)
+++ trunk/Source/JavaScriptCore/runtime/StringPrototypeInlines.h        2019-03-18 17:50:41 UTC (rev 243081)
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="cx"> template<typename NumberType>
</span><del>-ALWAYS_INLINE JSString* stringSlice(ExecState* exec, String&& string, NumberType start, NumberType end)
</del><ins>+ALWAYS_INLINE JSString* stringSlice(VM& vm, String&& string, NumberType start, NumberType end)
</ins><span class="cx"> {
</span><span class="cx">     int32_t length = string.length();
</span><span class="cx">     NumberType from = start < 0 ? length + start : start;
</span><span class="lines">@@ -40,9 +40,9 @@
</span><span class="cx">             from = 0;
</span><span class="cx">         if (to > length)
</span><span class="cx">             to = length;
</span><del>-        return jsSubstring(exec, WTFMove(string), static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from));
</del><ins>+        return jsSubstring(&vm, WTFMove(string), static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from));
</ins><span class="cx">     }
</span><del>-    return jsEmptyString(exec);
</del><ins>+    return jsEmptyString(&vm);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre>
</div>
</div>

</body>
</html>