<!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>[242484] releases/WebKitGTK/webkit-2.24</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/242484">242484</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2019-03-05 09:22:38 -0800 (Tue, 05 Mar 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/242252">r242252</a> - [JSC] sizeof(JSString) should be 16
https://bugs.webkit.org/show_bug.cgi?id=194375

Reviewed by Saam Barati.

JSTests:

* microbenchmarks/make-rope.js: Added.
(makeRope):
* stress/to-lower-case-intrinsic-on-empty-rope.js: We no longer allow 0 length JSString except for jsEmptyString singleton per VM.
(returnRope.helper): Deleted.
(returnRope): Deleted.

Source/JavaScriptCore:

This patch reduces sizeof(JSString) from 24 to 16 to fit it into GC heap cell atom. And it also reduces sizeof(JSRopeString) from 48 to 32.
Both classes cut 16 bytes per instance in GC allocation. This new layout is used in 64bit architectures which has little endianess.

JSString no longer has length and flags directly. JSString has String, and we query information to this String instead of holding duplicate
information in JSString. We embed isRope bit into this String's pointer so that we can convert JSRopeString to JSString in an atomic manner.
We emit store-store fence before we put String pointer. This should exist even before this patch, so this patch also fixes one concurrency issue.

The old JSRopeString separately had JSString* fibers along with String. In this patch, we merge the first JSString* fiber and String pointer
storage into one to reduce the size of JSRopeString. JSRopeString has three pointer width storage. We pick 48bit effective address of JSString*
fibers to compress three fibers + length + flags into three pointer width storage.

In 64bit architecture, JSString and JSRopeString have the following memory layout to make sizeof(JSString) == 16 and sizeof(JSRopeString) == 32.
JSString has only one pointer. We use it for String. length() and is8Bit() queries go to StringImpl. In JSRopeString, we reuse the above pointer
place for the 1st fiber. JSRopeString has three fibers so its size is 48. To keep length and is8Bit flag information in JSRopeString, JSRopeString
encodes these information into the fiber pointers. is8Bit flag is encoded in the 1st fiber pointer. length is embedded directly, and two fibers
are compressed into 12bytes. isRope information is encoded in the first fiber's LSB.

Since length of JSRopeString should be frequently accessed compared to each fiber, we put length in contiguous 32byte field, and compress 2nd
and 3rd fibers into the following 80byte fields. One problem is that now 2nd and 3rd fibers are split. Storing and loading 2nd and 3rd fibers
are not one pointer load operation. To make concurrent collector work correctly, we must initialize 2nd and 3rd fibers at JSRopeString creation
and we must not modify these part later.

             0                        8        10               16                       32                                     48
JSString     [   ID      ][  header  ][   String pointer      0]
JSRopeString [   ID      ][  header  ][ flags ][ 1st fiber    1][  length  ][2nd lower32][2nd upper16][3rd lower16][3rd upper32]
                                                              ^
                                                           isRope bit

Since fibers in JSRopeString are not initialized in atomic pointer store manner, we must initialize all the fiber fields at JSRopeString creation.
To achieve this, we modify our JSRopeString::RopeBuilder implementation not to create half-baked JSRopeString.

This patch also makes an empty JSString singleton per VM. This makes evaluation of JSString in boolean context one pointer comparison. This is
critical in this change since this patch enlarges the code necessary to get length from JSString in JIT. Without this guarantee, our code of boolean
context evaluation is bloated. This patch hides all the JSString::create and JSRopeString::create in the private permission. JSString and JSRopeString
creation is only allowed from jsString and related helper functions and they return a singleton empty JSString if the length is zero. We also change
JSRopeString::RopeBuilder not to construct an empty JSRopeString.

This patch is performance neutral in Speedometer2 and JetStream2. And it improves RAMification by 2.7%.

* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::storeZero16):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::storeZero16):
(JSC::MacroAssemblerX86Common::store16):
* bytecode/AccessCase.cpp:
(JSC::AccessCase::generateImpl):
* bytecode/InlineAccess.cpp:
(JSC::InlineAccess::dumpCacheSizesAndCrash):
(JSC::linkCodeInline):
(JSC::InlineAccess::isCacheableStringLength):
(JSC::InlineAccess::generateStringLength):
* bytecode/InlineAccess.h:
(JSC::InlineAccess::sizeForPropertyAccess):
(JSC::InlineAccess::sizeForPropertyReplace):
(JSC::InlineAccess::sizeForLengthAccess):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileStringSlice):
(JSC::DFG::SpeculativeJIT::compileToLowerCase):
(JSC::DFG::SpeculativeJIT::compileGetCharCodeAt):
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
(JSC::DFG::SpeculativeJIT::compileStringEquality):
(JSC::DFG::SpeculativeJIT::compileStringZeroLength):
(JSC::DFG::SpeculativeJIT::compileLogicalNotStringOrOther):
(JSC::DFG::SpeculativeJIT::emitStringBranch):
(JSC::DFG::SpeculativeJIT::emitStringOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
(JSC::DFG::SpeculativeJIT::emitPopulateSliceIndex):
(JSC::DFG::SpeculativeJIT::compileArraySlice):
(JSC::DFG::SpeculativeJIT::compileArrayIndexOf):
(JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage):
(JSC::DFG::SpeculativeJIT::emitSwitchCharStringJump):
(JSC::DFG::SpeculativeJIT::emitSwitchStringOnString):
(JSC::DFG::SpeculativeJIT::compileMakeRope): Deleted.
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileMakeRope):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileMakeRope):
* ftl/FTLAbstractHeapRepository.cpp:
(JSC::FTL::AbstractHeapRepository::AbstractHeapRepository):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileGetIndexedPropertyStorage):
(JSC::FTL::DFG::LowerDFGToB3::compileGetArrayLength):
(JSC::FTL::DFG::LowerDFGToB3::compileMakeRope):
(JSC::FTL::DFG::LowerDFGToB3::compileStringCharAt):
(JSC::FTL::DFG::LowerDFGToB3::compileStringCharCodeAt):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
(JSC::FTL::DFG::LowerDFGToB3::compileStringToUntypedStrictEquality):
(JSC::FTL::DFG::LowerDFGToB3::compileSwitch):
(JSC::FTL::DFG::LowerDFGToB3::mapHashString):
(JSC::FTL::DFG::LowerDFGToB3::compileMapHash):
(JSC::FTL::DFG::LowerDFGToB3::compileHasOwnProperty):
(JSC::FTL::DFG::LowerDFGToB3::compileStringSlice):
(JSC::FTL::DFG::LowerDFGToB3::compileToLowerCase):
(JSC::FTL::DFG::LowerDFGToB3::stringsEqual):
(JSC::FTL::DFG::LowerDFGToB3::boolify):
(JSC::FTL::DFG::LowerDFGToB3::switchString):
(JSC::FTL::DFG::LowerDFGToB3::isRopeString):
(JSC::FTL::DFG::LowerDFGToB3::isNotRopeString):
(JSC::FTL::DFG::LowerDFGToB3::speculateStringIdent):
* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::emitConvertValueToBoolean):
(JSC::AssemblyHelpers::branchIfValue):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::branchIfRopeStringImpl):
(JSC::AssemblyHelpers::branchIfNotRopeStringImpl):
* jit/JITInlines.h:
(JSC::JIT::emitLoadCharacterString):
* jit/Repatch.cpp:
(JSC::tryCacheGetByID):
* jit/ThunkGenerators.cpp:
(JSC::stringGetByValGenerator):
(JSC::stringCharLoad):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/JSString.cpp:
(JSC::JSString::createEmptyString):
(JSC::JSRopeString::RopeBuilder<RecordOverflow>::expand):
(JSC::JSString::dumpToStream):
(JSC::JSString::estimatedSize):
(JSC::JSString::visitChildren):
(JSC::JSRopeString::resolveRopeInternal8 const):
(JSC::JSRopeString::resolveRopeInternal8NoSubstring const):
(JSC::JSRopeString::resolveRopeInternal16 const):
(JSC::JSRopeString::resolveRopeInternal16NoSubstring const):
(JSC::JSRopeString::resolveRopeToAtomicString const):
(JSC::JSRopeString::convertToNonRope const):
(JSC::JSRopeString::resolveRopeToExistingAtomicString const):
(JSC::JSRopeString::resolveRopeWithFunction const):
(JSC::JSRopeString::resolveRope const):
(JSC::JSRopeString::resolveRopeSlowCase8 const):
(JSC::JSRopeString::resolveRopeSlowCase const):
(JSC::JSRopeString::outOfMemory const):
(JSC::JSRopeString::visitFibers): Deleted.
(JSC::JSRopeString::clearFibers const): Deleted.
* runtime/JSString.h:
(JSC::JSString::uninitializedValueInternal const):
(JSC::JSString::valueInternal const):
(JSC::JSString::JSString):
(JSC::JSString::finishCreation):
(JSC::JSString::create):
(JSC::JSString::offsetOfValue):
(JSC::JSString::isRope const):
(JSC::JSString::is8Bit const):
(JSC::JSString::length const):
(JSC::JSString::tryGetValueImpl const):
(JSC::JSString::toAtomicString const):
(JSC::JSString::toExistingAtomicString const):
(JSC::JSString::value const):
(JSC::JSString::tryGetValue const):
(JSC::JSRopeString::unsafeView const):
(JSC::JSRopeString::viewWithUnderlyingString const):
(JSC::JSString::unsafeView const):
(JSC::JSString::viewWithUnderlyingString const):
(JSC::JSString::offsetOfLength): Deleted.
(JSC::JSString::offsetOfFlags): Deleted.
(JSC::JSString::setIs8Bit const): Deleted.
(JSC::JSString::setLength): Deleted.
(JSC::JSString::string): Deleted.
(JSC::jsStringBuilder): Deleted.
* runtime/JSStringInlines.h:
(JSC::JSString::~JSString):
(JSC::JSString::equal const):
* runtime/ObjectPrototype.cpp:
(JSC::objectProtoFuncToString):
* runtime/RegExpMatchesArray.h:
(JSC::createRegExpMatchesArray):
* runtime/RegExpObjectInlines.h:
(JSC::collectMatches):
* runtime/RegExpPrototype.cpp:
(JSC::regExpProtoFuncSplitFast):
* runtime/SmallStrings.cpp:
(JSC::SmallStrings::initializeCommonStrings):
(JSC::SmallStrings::createEmptyString): Deleted.
* runtime/SmallStrings.h:
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncSlice):
* runtime/StringPrototypeInlines.h: Added.
(JSC::stringSlice):

Source/WTF:

* wtf/text/StringImpl.h:
(WTF::StringImpl::flagIs8Bit):
(WTF::StringImpl::flagIsAtomic):
(WTF::StringImpl::flagIsSymbol):
(WTF::StringImpl::maskStringKind):
* wtf/text/WTFString.cpp:
(WTF::nullString):
* wtf/text/WTFString.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit224JSTestsChangeLog">releases/WebKitGTK/webkit-2.24/JSTests/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit224JSTestsstresstolowercaseintrinsiconemptyropejs">releases/WebKitGTK/webkit-2.24/JSTests/stress/to-lower-case-intrinsic-on-empty-rope.js</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreChangeLog">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreassemblerMacroAssemblerARM64h">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreassemblerMacroAssemblerX86Commonh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorebytecodeAccessCasecpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/AccessCase.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorebytecodeInlineAccesscpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/InlineAccess.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorebytecodeInlineAccessh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/InlineAccess.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGOperationscpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGOperationsh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGOperations.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGSpeculativeJITcpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGSpeculativeJITh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreftlFTLAbstractHeapRepositorycpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreftlFTLAbstractHeapRepositoryh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreftlFTLLowerDFGToB3cpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorejitAssemblyHelperscpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/AssemblyHelpers.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorejitAssemblyHelpersh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/AssemblyHelpers.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorejitJITInlinesh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/JITInlines.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorejitRepatchcpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorejitThunkGeneratorscpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/ThunkGenerators.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorellintLowLevelInterpreterasm">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorellintLowLevelInterpreter32_64asm">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCorellintLowLevelInterpreter64asm">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeJSStringcpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSString.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeJSStringh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSString.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeJSStringInlinesh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSStringInlines.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeObjectPrototypecpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/ObjectPrototype.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeRegExpMatchesArrayh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpMatchesArray.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeRegExpObjectInlinesh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpObjectInlines.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeRegExpPrototypecpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpPrototype.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeSmallStringscpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/SmallStrings.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeSmallStringsh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/SmallStrings.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeStringPrototypecpp">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/StringPrototype.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceWTFChangeLog">releases/WebKitGTK/webkit-2.24/Source/WTF/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceWTFwtftextStringImplh">releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/StringImpl.h</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceWTFwtftextWTFStringcpp">releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/WTFString.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceWTFwtftextWTFStringh">releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/WTFString.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit224JSTestsmicrobenchmarksmakeropejs">releases/WebKitGTK/webkit-2.24/JSTests/microbenchmarks/make-rope.js</a></li>
<li><a href="#releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeStringPrototypeInlinesh">releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/StringPrototypeInlines.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="releasesWebKitGTKwebkit224JSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/JSTests/ChangeLog (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/JSTests/ChangeLog 2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/JSTests/ChangeLog    2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2019-02-28  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] sizeof(JSString) should be 16
+        https://bugs.webkit.org/show_bug.cgi?id=194375
+
+        Reviewed by Saam Barati.
+
+        * microbenchmarks/make-rope.js: Added.
+        (makeRope):
+        * stress/to-lower-case-intrinsic-on-empty-rope.js: We no longer allow 0 length JSString except for jsEmptyString singleton per VM.
+        (returnRope.helper): Deleted.
+        (returnRope): Deleted.
+
</ins><span class="cx"> 2019-02-27  Mark Lam  <mark.lam@apple.com>
</span><span class="cx"> 
</span><span class="cx">         The parser is failing to record the token location of new in new.target.
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224JSTestsmicrobenchmarksmakeropejs"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.24/JSTests/microbenchmarks/make-rope.js (0 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/JSTests/microbenchmarks/make-rope.js                              (rev 0)
+++ releases/WebKitGTK/webkit-2.24/JSTests/microbenchmarks/make-rope.js 2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+function makeRope(str1, str2, str3)
+{
+    return str1 + str2 + str3;
+}
+noInline(makeRope);
+
+for (var i = 0; i < 1e6; ++i) {
+    makeRope("Hello", "Another", "World");
+    makeRope(makeRope("Hello", "Another", "World"), "Another", makeRope("Hello", "Another", "World"));
+}
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit224JSTestsstresstolowercaseintrinsiconemptyropejs"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/JSTests/stress/to-lower-case-intrinsic-on-empty-rope.js (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/JSTests/stress/to-lower-case-intrinsic-on-empty-rope.js   2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/JSTests/stress/to-lower-case-intrinsic-on-empty-rope.js      2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx">         throw new Error("bad!");
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function returnRope() {
</del><ins>+function returnEmptyString() {
</ins><span class="cx">     function helper(r, s) {
</span><span class="cx">         // I'm paranoid about RegExp matching constant folding.
</span><span class="cx">         return s.match(r)[1];
</span><span class="lines">@@ -11,7 +11,7 @@
</span><span class="cx">     noInline(helper);
</span><span class="cx">     return helper(/(b*)fo/, "fo");
</span><span class="cx"> }
</span><del>-noInline(returnRope);
</del><ins>+noInline(returnEmptyString);
</ins><span class="cx"> 
</span><span class="cx"> function lower(a) {
</span><span class="cx">     return a.toLowerCase();
</span><span class="lines">@@ -19,8 +19,8 @@
</span><span class="cx"> noInline(lower);
</span><span class="cx"> 
</span><span class="cx"> for (let i = 0; i < 10000; i++) {
</span><del>-    let rope = returnRope();
-    assert(!rope.length);
-    assert(isRope(rope)); // Keep this test future proofed. If this stops returning a rope, we should try to find another way to return an empty rope.
-    lower(rope);
</del><ins>+    let notRope = returnEmptyString();
+    assert(!notRope.length);
+    assert(!isRope(notRope));
+    lower(notRope);
</ins><span class="cx"> }
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ChangeLog (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ChangeLog   2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ChangeLog      2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1,3 +1,198 @@
</span><ins>+2019-02-28  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] sizeof(JSString) should be 16
+        https://bugs.webkit.org/show_bug.cgi?id=194375
+
+        Reviewed by Saam Barati.
+
+        This patch reduces sizeof(JSString) from 24 to 16 to fit it into GC heap cell atom. And it also reduces sizeof(JSRopeString) from 48 to 32.
+        Both classes cut 16 bytes per instance in GC allocation. This new layout is used in 64bit architectures which has little endianess.
+
+        JSString no longer has length and flags directly. JSString has String, and we query information to this String instead of holding duplicate
+        information in JSString. We embed isRope bit into this String's pointer so that we can convert JSRopeString to JSString in an atomic manner.
+        We emit store-store fence before we put String pointer. This should exist even before this patch, so this patch also fixes one concurrency issue.
+
+        The old JSRopeString separately had JSString* fibers along with String. In this patch, we merge the first JSString* fiber and String pointer
+        storage into one to reduce the size of JSRopeString. JSRopeString has three pointer width storage. We pick 48bit effective address of JSString*
+        fibers to compress three fibers + length + flags into three pointer width storage.
+
+        In 64bit architecture, JSString and JSRopeString have the following memory layout to make sizeof(JSString) == 16 and sizeof(JSRopeString) == 32.
+        JSString has only one pointer. We use it for String. length() and is8Bit() queries go to StringImpl. In JSRopeString, we reuse the above pointer
+        place for the 1st fiber. JSRopeString has three fibers so its size is 48. To keep length and is8Bit flag information in JSRopeString, JSRopeString
+        encodes these information into the fiber pointers. is8Bit flag is encoded in the 1st fiber pointer. length is embedded directly, and two fibers
+        are compressed into 12bytes. isRope information is encoded in the first fiber's LSB.
+
+        Since length of JSRopeString should be frequently accessed compared to each fiber, we put length in contiguous 32byte field, and compress 2nd
+        and 3rd fibers into the following 80byte fields. One problem is that now 2nd and 3rd fibers are split. Storing and loading 2nd and 3rd fibers
+        are not one pointer load operation. To make concurrent collector work correctly, we must initialize 2nd and 3rd fibers at JSRopeString creation
+        and we must not modify these part later.
+
+                     0                        8        10               16                       32                                     48
+        JSString     [   ID      ][  header  ][   String pointer      0]
+        JSRopeString [   ID      ][  header  ][ flags ][ 1st fiber    1][  length  ][2nd lower32][2nd upper16][3rd lower16][3rd upper32]
+                                                                      ^
+                                                                   isRope bit
+
+        Since fibers in JSRopeString are not initialized in atomic pointer store manner, we must initialize all the fiber fields at JSRopeString creation.
+        To achieve this, we modify our JSRopeString::RopeBuilder implementation not to create half-baked JSRopeString.
+
+        This patch also makes an empty JSString singleton per VM. This makes evaluation of JSString in boolean context one pointer comparison. This is
+        critical in this change since this patch enlarges the code necessary to get length from JSString in JIT. Without this guarantee, our code of boolean
+        context evaluation is bloated. This patch hides all the JSString::create and JSRopeString::create in the private permission. JSString and JSRopeString
+        creation is only allowed from jsString and related helper functions and they return a singleton empty JSString if the length is zero. We also change
+        JSRopeString::RopeBuilder not to construct an empty JSRopeString.
+
+        This patch is performance neutral in Speedometer2 and JetStream2. And it improves RAMification by 2.7%.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::storeZero16):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::storeZero16):
+        (JSC::MacroAssemblerX86Common::store16):
+        * bytecode/AccessCase.cpp:
+        (JSC::AccessCase::generateImpl):
+        * bytecode/InlineAccess.cpp:
+        (JSC::InlineAccess::dumpCacheSizesAndCrash):
+        (JSC::linkCodeInline):
+        (JSC::InlineAccess::isCacheableStringLength):
+        (JSC::InlineAccess::generateStringLength):
+        * bytecode/InlineAccess.h:
+        (JSC::InlineAccess::sizeForPropertyAccess):
+        (JSC::InlineAccess::sizeForPropertyReplace):
+        (JSC::InlineAccess::sizeForLengthAccess):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileStringSlice):
+        (JSC::DFG::SpeculativeJIT::compileToLowerCase):
+        (JSC::DFG::SpeculativeJIT::compileGetCharCodeAt):
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnString):
+        (JSC::DFG::SpeculativeJIT::compileStringEquality):
+        (JSC::DFG::SpeculativeJIT::compileStringZeroLength):
+        (JSC::DFG::SpeculativeJIT::compileLogicalNotStringOrOther):
+        (JSC::DFG::SpeculativeJIT::emitStringBranch):
+        (JSC::DFG::SpeculativeJIT::emitStringOrOtherBranch):
+        (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
+        (JSC::DFG::SpeculativeJIT::compileGetArrayLength):
+        (JSC::DFG::SpeculativeJIT::emitPopulateSliceIndex):
+        (JSC::DFG::SpeculativeJIT::compileArraySlice):
+        (JSC::DFG::SpeculativeJIT::compileArrayIndexOf):
+        (JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage):
+        (JSC::DFG::SpeculativeJIT::emitSwitchCharStringJump):
+        (JSC::DFG::SpeculativeJIT::emitSwitchStringOnString):
+        (JSC::DFG::SpeculativeJIT::compileMakeRope): Deleted.
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        (JSC::DFG::SpeculativeJIT::compileMakeRope):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        (JSC::DFG::SpeculativeJIT::compileMakeRope):
+        * ftl/FTLAbstractHeapRepository.cpp:
+        (JSC::FTL::AbstractHeapRepository::AbstractHeapRepository):
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetIndexedPropertyStorage):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetArrayLength):
+        (JSC::FTL::DFG::LowerDFGToB3::compileMakeRope):
+        (JSC::FTL::DFG::LowerDFGToB3::compileStringCharAt):
+        (JSC::FTL::DFG::LowerDFGToB3::compileStringCharCodeAt):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+        (JSC::FTL::DFG::LowerDFGToB3::compileStringToUntypedStrictEquality):
+        (JSC::FTL::DFG::LowerDFGToB3::compileSwitch):
+        (JSC::FTL::DFG::LowerDFGToB3::mapHashString):
+        (JSC::FTL::DFG::LowerDFGToB3::compileMapHash):
+        (JSC::FTL::DFG::LowerDFGToB3::compileHasOwnProperty):
+        (JSC::FTL::DFG::LowerDFGToB3::compileStringSlice):
+        (JSC::FTL::DFG::LowerDFGToB3::compileToLowerCase):
+        (JSC::FTL::DFG::LowerDFGToB3::stringsEqual):
+        (JSC::FTL::DFG::LowerDFGToB3::boolify):
+        (JSC::FTL::DFG::LowerDFGToB3::switchString):
+        (JSC::FTL::DFG::LowerDFGToB3::isRopeString):
+        (JSC::FTL::DFG::LowerDFGToB3::isNotRopeString):
+        (JSC::FTL::DFG::LowerDFGToB3::speculateStringIdent):
+        * jit/AssemblyHelpers.cpp:
+        (JSC::AssemblyHelpers::emitConvertValueToBoolean):
+        (JSC::AssemblyHelpers::branchIfValue):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::branchIfRopeStringImpl):
+        (JSC::AssemblyHelpers::branchIfNotRopeStringImpl):
+        * jit/JITInlines.h:
+        (JSC::JIT::emitLoadCharacterString):
+        * jit/Repatch.cpp:
+        (JSC::tryCacheGetByID):
+        * jit/ThunkGenerators.cpp:
+        (JSC::stringGetByValGenerator):
+        (JSC::stringCharLoad):
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/JSString.cpp:
+        (JSC::JSString::createEmptyString):
+        (JSC::JSRopeString::RopeBuilder<RecordOverflow>::expand):
+        (JSC::JSString::dumpToStream):
+        (JSC::JSString::estimatedSize):
+        (JSC::JSString::visitChildren):
+        (JSC::JSRopeString::resolveRopeInternal8 const):
+        (JSC::JSRopeString::resolveRopeInternal8NoSubstring const):
+        (JSC::JSRopeString::resolveRopeInternal16 const):
+        (JSC::JSRopeString::resolveRopeInternal16NoSubstring const):
+        (JSC::JSRopeString::resolveRopeToAtomicString const):
+        (JSC::JSRopeString::convertToNonRope const):
+        (JSC::JSRopeString::resolveRopeToExistingAtomicString const):
+        (JSC::JSRopeString::resolveRopeWithFunction const):
+        (JSC::JSRopeString::resolveRope const):
+        (JSC::JSRopeString::resolveRopeSlowCase8 const):
+        (JSC::JSRopeString::resolveRopeSlowCase const):
+        (JSC::JSRopeString::outOfMemory const):
+        (JSC::JSRopeString::visitFibers): Deleted.
+        (JSC::JSRopeString::clearFibers const): Deleted.
+        * runtime/JSString.h:
+        (JSC::JSString::uninitializedValueInternal const):
+        (JSC::JSString::valueInternal const):
+        (JSC::JSString::JSString):
+        (JSC::JSString::finishCreation):
+        (JSC::JSString::create):
+        (JSC::JSString::offsetOfValue):
+        (JSC::JSString::isRope const):
+        (JSC::JSString::is8Bit const):
+        (JSC::JSString::length const):
+        (JSC::JSString::tryGetValueImpl const):
+        (JSC::JSString::toAtomicString const):
+        (JSC::JSString::toExistingAtomicString const):
+        (JSC::JSString::value const):
+        (JSC::JSString::tryGetValue const):
+        (JSC::JSRopeString::unsafeView const):
+        (JSC::JSRopeString::viewWithUnderlyingString const):
+        (JSC::JSString::unsafeView const):
+        (JSC::JSString::viewWithUnderlyingString const):
+        (JSC::JSString::offsetOfLength): Deleted.
+        (JSC::JSString::offsetOfFlags): Deleted.
+        (JSC::JSString::setIs8Bit const): Deleted.
+        (JSC::JSString::setLength): Deleted.
+        (JSC::JSString::string): Deleted.
+        (JSC::jsStringBuilder): Deleted.
+        * runtime/JSStringInlines.h:
+        (JSC::JSString::~JSString):
+        (JSC::JSString::equal const):
+        * runtime/ObjectPrototype.cpp:
+        (JSC::objectProtoFuncToString):
+        * runtime/RegExpMatchesArray.h:
+        (JSC::createRegExpMatchesArray):
+        * runtime/RegExpObjectInlines.h:
+        (JSC::collectMatches):
+        * runtime/RegExpPrototype.cpp:
+        (JSC::regExpProtoFuncSplitFast):
+        * runtime/SmallStrings.cpp:
+        (JSC::SmallStrings::initializeCommonStrings):
+        (JSC::SmallStrings::createEmptyString): Deleted.
+        * runtime/SmallStrings.h:
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncSlice):
+        * runtime/StringPrototypeInlines.h: Added.
+        (JSC::stringSlice):
+
</ins><span class="cx"> 2019-02-27  Mark Lam  <mark.lam@apple.com>
</span><span class="cx"> 
</span><span class="cx">         The parser is failing to record the token location of new in new.target.
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj    2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj       2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1737,6 +1737,7 @@
</span><span class="cx">          E322E5A31DA64439006E7709 /* DFGSnippetParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E322E5A11DA64435006E7709 /* DFGSnippetParams.h */; };
</span><span class="cx">          E322E5A71DA644A8006E7709 /* FTLSnippetParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E322E5A51DA644A4006E7709 /* FTLSnippetParams.h */; };
</span><span class="cx">          E325956421FDA2C9008EDC9C /* RegExpGlobalDataInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E325956321FDA2C8008EDC9C /* RegExpGlobalDataInlines.h */; };
</span><ins>+               E325A36022211590007349A1 /* StringPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E325A35F2221158A007349A1 /* StringPrototypeInlines.h */; };
</ins><span class="cx">           E3282BBB1FE930AF00EDAF71 /* YarrErrorCode.h in Headers */ = {isa = PBXBuildFile; fileRef = E3282BBA1FE930A400EDAF71 /* YarrErrorCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          E328C6C71DA4304500D255FD /* MaxFrameExtentForSlowPathCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 65860177185A8F5E00030EEE /* MaxFrameExtentForSlowPathCall.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          E328C6C81DA4306100D255FD /* RegisterAtOffsetList.h in Headers */ = {isa = PBXBuildFile; fileRef = 6540C79D1B82D99D000F6B79 /* RegisterAtOffsetList.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -4664,6 +4665,7 @@
</span><span class="cx">          E322E5A41DA644A4006E7709 /* FTLSnippetParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLSnippetParams.cpp; path = ftl/FTLSnippetParams.cpp; sourceTree = "<group>"; };
</span><span class="cx">          E322E5A51DA644A4006E7709 /* FTLSnippetParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSnippetParams.h; path = ftl/FTLSnippetParams.h; sourceTree = "<group>"; };
</span><span class="cx">          E325956321FDA2C8008EDC9C /* RegExpGlobalDataInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpGlobalDataInlines.h; sourceTree = "<group>"; };
</span><ins>+               E325A35F2221158A007349A1 /* StringPrototypeInlines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringPrototypeInlines.h; sourceTree = "<group>"; };
</ins><span class="cx">           E326C4961ECBEF5700A9A905 /* ClassInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClassInfo.cpp; sourceTree = "<group>"; };
</span><span class="cx">          E3282BB91FE930A300EDAF71 /* YarrErrorCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrErrorCode.cpp; path = yarr/YarrErrorCode.cpp; sourceTree = "<group>"; };
</span><span class="cx">          E3282BBA1FE930A400EDAF71 /* YarrErrorCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrErrorCode.h; path = yarr/YarrErrorCode.h; sourceTree = "<group>"; };
</span><span class="lines">@@ -7158,6 +7160,7 @@
</span><span class="cx">                          BC18C3C30E16EE3300B34460 /* StringObject.h */,
</span><span class="cx">                          BC18C3C50E16EE3300B34460 /* StringPrototype.cpp */,
</span><span class="cx">                          BC18C3C60E16EE3300B34460 /* StringPrototype.h */,
</span><ins>+                               E325A35F2221158A007349A1 /* StringPrototypeInlines.h */,
</ins><span class="cx">                           93345A8712D838C400302BE3 /* StringRecursionChecker.cpp */,
</span><span class="cx">                          93345A8812D838C400302BE3 /* StringRecursionChecker.h */,
</span><span class="cx">                          BCDE3AB00E6C82CF001453A7 /* Structure.cpp */,
</span><span class="lines">@@ -9689,6 +9692,7 @@
</span><span class="cx">                          996B73261BDA08EF00331B84 /* StringIteratorPrototype.lut.h in Headers */,
</span><span class="cx">                          BC18C4680E16F5CD00B34460 /* StringObject.h in Headers */,
</span><span class="cx">                          BC18C46A0E16F5CD00B34460 /* StringPrototype.h in Headers */,
</span><ins>+                               E325A36022211590007349A1 /* StringPrototypeInlines.h in Headers */,
</ins><span class="cx">                           142E313B134FF0A600AFADB5 /* Strong.h in Headers */,
</span><span class="cx">                          145722861437E140005FDE26 /* StrongInlines.h in Headers */,
</span><span class="cx">                          BCDE3AB80E6C82F5001453A7 /* Structure.h in Headers */,
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1540,6 +1540,16 @@
</span><span class="cx">         m_assembler.strh(src, address.base, memoryTempRegister);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void storeZero16(ImplicitAddress address)
+    {
+        store16(ARM64Registers::zr, address);
+    }
+
+    void storeZero16(BaseIndex address)
+    {
+        store16(ARM64Registers::zr, address);
+    }
+
</ins><span class="cx">     void store8(RegisterID src, BaseIndex address)
</span><span class="cx">     {
</span><span class="cx">         if (!address.offset && !address.scale) {
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h 2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h    2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1348,6 +1348,16 @@
</span><span class="cx">         store32(TrustedImm32(0), address);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void storeZero16(ImplicitAddress address)
+    {
+        store16(TrustedImm32(0), address);
+    }
+
+    void storeZero16(BaseIndex address)
+    {
+        store16(TrustedImm32(0), address);
+    }
+
</ins><span class="cx">     void store8(TrustedImm32 imm, Address address)
</span><span class="cx">     {
</span><span class="cx">         TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
</span><span class="lines">@@ -1434,7 +1444,7 @@
</span><span class="cx">         m_assembler.movw_im(static_cast<int16_t>(imm.m_value), address.offset, address.base, address.index, address.scale);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void store16(TrustedImm32 imm, Address address)
</del><ins>+    void store16(TrustedImm32 imm, ImplicitAddress address)
</ins><span class="cx">     {
</span><span class="cx">         m_assembler.movw_im(static_cast<int16_t>(imm.m_value), address.offset, address.base);
</span><span class="cx">     }
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorebytecodeAccessCasecpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/AccessCase.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/AccessCase.cpp     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/AccessCase.cpp        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1213,8 +1213,16 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case StringLength: {
</span><del>-        jit.load32(CCallHelpers::Address(baseGPR, JSString::offsetOfLength()), valueRegs.payloadGPR());
-        jit.boxInt32(valueRegs.payloadGPR(), valueRegs);
</del><ins>+        jit.loadPtr(CCallHelpers::Address(baseGPR, JSString::offsetOfValue()), scratchGPR);
+        auto isRope = jit.branchIfRopeStringImpl(scratchGPR);
+        jit.load32(CCallHelpers::Address(scratchGPR, StringImpl::lengthMemoryOffset()), scratchGPR);
+        auto done = jit.jump();
+
+        isRope.link(&jit);
+        jit.load32(CCallHelpers::Address(baseGPR, JSRopeString::offsetOfLength()), scratchGPR);
+
+        done.link(&jit);
+        jit.boxInt32(scratchGPR, valueRegs);
</ins><span class="cx">         state.succeed();
</span><span class="cx">         return;
</span><span class="cx">     }
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorebytecodeInlineAccesscpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/InlineAccess.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/InlineAccess.cpp   2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/InlineAccess.cpp      2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -50,11 +50,21 @@
</span><span class="cx">     {
</span><span class="cx">         CCallHelpers jit;
</span><span class="cx"> 
</span><ins>+        GPRReg scratchGPR = value;
</ins><span class="cx">         jit.patchableBranch8(
</span><span class="cx">             CCallHelpers::NotEqual,
</span><span class="cx">             CCallHelpers::Address(base, JSCell::typeInfoTypeOffset()),
</span><span class="cx">             CCallHelpers::TrustedImm32(StringType));
</span><del>-        jit.load32(CCallHelpers::Address(base, JSString::offsetOfLength()), regs.payloadGPR());
</del><ins>+
+        jit.loadPtr(CCallHelpers::Address(base, JSString::offsetOfValue()), scratchGPR);
+        auto isRope = jit.branchIfRopeStringImpl(scratchGPR);
+        jit.load32(CCallHelpers::Address(scratchGPR, StringImpl::lengthMemoryOffset()), regs.payloadGPR());
+        auto done = jit.jump();
+
+        isRope.link(&jit);
+        jit.load32(CCallHelpers::Address(base, JSRopeString::offsetOfLength()), regs.payloadGPR());
+
+        done.link(&jit);
</ins><span class="cx">         jit.boxInt32(regs.payloadGPR(), regs);
</span><span class="cx"> 
</span><span class="cx">         dataLog("string length size: ", jit.m_assembler.buffer().codeSize(), "\n");
</span><span class="lines">@@ -143,7 +153,7 @@
</span><span class="cx"> ALWAYS_INLINE static bool linkCodeInline(const char* name, CCallHelpers& jit, StructureStubInfo& stubInfo, const Function& function)
</span><span class="cx"> {
</span><span class="cx">     if (jit.m_assembler.buffer().codeSize() <= stubInfo.patch.inlineSize()) {
</span><del>-        bool needsBranchCompaction = false;
</del><ins>+        bool needsBranchCompaction = true;
</ins><span class="cx">         LinkBuffer linkBuffer(jit, stubInfo.patch.start, stubInfo.patch.inlineSize(), JITCompilationMustSucceed, needsBranchCompaction);
</span><span class="cx">         ASSERT(linkBuffer.isValid());
</span><span class="cx">         function(linkBuffer);
</span><span class="lines">@@ -156,7 +166,7 @@
</span><span class="cx">     // there may be variability in the length of the code we generate just because
</span><span class="cx">     // of randomness. It's helpful to flip this on when running tests or browsing
</span><span class="cx">     // the web just to see how often it fails. You don't want an IC size that always fails.
</span><del>-    const bool failIfCantInline = false;
</del><ins>+    constexpr bool failIfCantInline = false;
</ins><span class="cx">     if (failIfCantInline) {
</span><span class="cx">         dataLog("Failure for: ", name, "\n");
</span><span class="cx">         dataLog("real size: ", jit.m_assembler.buffer().codeSize(), " inline size:", stubInfo.patch.inlineSize(), "\n");
</span><span class="lines">@@ -288,18 +298,35 @@
</span><span class="cx">     return linkedCodeInline;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool InlineAccess::isCacheableStringLength(StructureStubInfo& stubInfo)
+{
+    return hasFreeRegister(stubInfo);
+}
+
</ins><span class="cx"> bool InlineAccess::generateStringLength(StructureStubInfo& stubInfo)
</span><span class="cx"> {
</span><ins>+    ASSERT(isCacheableStringLength(stubInfo));
+
</ins><span class="cx">     CCallHelpers jit;
</span><span class="cx"> 
</span><span class="cx">     GPRReg base = stubInfo.baseGPR();
</span><span class="cx">     JSValueRegs value = stubInfo.valueRegs();
</span><ins>+    GPRReg scratch = getScratchRegister(stubInfo);
</ins><span class="cx"> 
</span><span class="cx">     auto branchToSlowPath = jit.patchableBranch8(
</span><span class="cx">         CCallHelpers::NotEqual,
</span><span class="cx">         CCallHelpers::Address(base, JSCell::typeInfoTypeOffset()),
</span><span class="cx">         CCallHelpers::TrustedImm32(StringType));
</span><del>-    jit.load32(CCallHelpers::Address(base, JSString::offsetOfLength()), value.payloadGPR());
</del><ins>+
+    jit.loadPtr(CCallHelpers::Address(base, JSString::offsetOfValue()), scratch);
+    auto isRope = jit.branchIfRopeStringImpl(scratch);
+    jit.load32(CCallHelpers::Address(scratch, StringImpl::lengthMemoryOffset()), value.payloadGPR());
+    auto done = jit.jump();
+
+    isRope.link(&jit);
+    jit.load32(CCallHelpers::Address(base, JSRopeString::offsetOfLength()), value.payloadGPR());
+
+    done.link(&jit);
</ins><span class="cx">     jit.boxInt32(value.payloadGPR(), value);
</span><span class="cx"> 
</span><span class="cx">     bool linkedCodeInline = linkCodeInline("string length", jit, stubInfo, [&] (LinkBuffer& linkBuffer) {
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorebytecodeInlineAccessh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/InlineAccess.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/InlineAccess.h     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/bytecode/InlineAccess.h        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx">     static constexpr size_t sizeForPropertyAccess()
</span><span class="cx">     {
</span><span class="cx"> #if CPU(X86_64)
</span><del>-        return 23;
</del><ins>+        return 26;
</ins><span class="cx"> #elif CPU(X86)
</span><span class="cx">         return 27;
</span><span class="cx"> #elif CPU(ARM64)
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx">     static constexpr size_t sizeForPropertyReplace()
</span><span class="cx">     {
</span><span class="cx"> #if CPU(X86_64)
</span><del>-        return 23;
</del><ins>+        return 26;
</ins><span class="cx"> #elif CPU(X86)
</span><span class="cx">         return 27;
</span><span class="cx"> #elif CPU(ARM64)
</span><span class="lines">@@ -83,11 +83,11 @@
</span><span class="cx">     ALWAYS_INLINE static size_t sizeForLengthAccess()
</span><span class="cx">     {
</span><span class="cx"> #if CPU(X86_64)
</span><del>-        size_t size = 26;
</del><ins>+        size_t size = 43;
</ins><span class="cx"> #elif CPU(X86)
</span><span class="cx">         size_t size = 27;
</span><span class="cx"> #elif CPU(ARM64)
</span><del>-        size_t size = 32;
</del><ins>+        size_t size = 44;
</ins><span class="cx"> #elif CPU(ARM_THUMB2)
</span><span class="cx">         size_t size = 30;
</span><span class="cx"> #elif CPU(MIPS)
</span><span class="lines">@@ -102,6 +102,7 @@
</span><span class="cx">     static bool canGenerateSelfPropertyReplace(StructureStubInfo&, PropertyOffset);
</span><span class="cx">     static bool generateSelfPropertyReplace(StructureStubInfo&, Structure*, PropertyOffset);
</span><span class="cx">     static bool isCacheableArrayLength(StructureStubInfo&, JSArray*);
</span><ins>+    static bool isCacheableStringLength(StructureStubInfo&);
</ins><span class="cx">     static bool generateArrayLength(StructureStubInfo&, JSArray*);
</span><span class="cx">     static void rewireStubAsJump(StructureStubInfo&, CodeLocationLabel<JITStubRoutinePtrTag>);
</span><span class="cx">     static bool generateSelfInAccess(StructureStubInfo&, Structure*);
</span><span class="lines">@@ -111,7 +112,7 @@
</span><span class="cx">     // various platforms. When adding a new type of IC, implement
</span><span class="cx">     // its placeholder code here, and log the size. That way we
</span><span class="cx">     // can intelligently choose sizes on various platforms.
</span><del>-    NO_RETURN_DUE_TO_CRASH static void dumpCacheSizesAndCrash();
</del><ins>+    JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void dumpCacheSizesAndCrash();
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGOperations.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGOperations.cpp       2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGOperations.cpp  2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -71,6 +71,7 @@
</span><span class="cx"> #include "Repatch.h"
</span><span class="cx"> #include "ScopedArguments.h"
</span><span class="cx"> #include "StringConstructor.h"
</span><ins>+#include "StringPrototypeInlines.h"
</ins><span class="cx"> #include "SuperSampler.h"
</span><span class="cx"> #include "Symbol.h"
</span><span class="cx"> #include "TypeProfilerLog.h"
</span><span class="lines">@@ -2157,6 +2158,20 @@
</span><span class="cx">     return jsSubstring(exec, string, from, span);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+JSCell* JIT_OPERATION operationStringSlice(ExecState* exec, JSCell* cell, int32_t start, int32_t end)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto string = jsCast<JSString*>(cell)->value(exec);
+    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);
+}
+
</ins><span class="cx"> JSString* JIT_OPERATION operationToLowerCase(ExecState* exec, JSString* string, uint32_t failingIndex)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGOperationsh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGOperations.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGOperations.h 2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGOperations.h    2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -203,6 +203,7 @@
</span><span class="cx"> JSString* JIT_OPERATION operationSingleCharacterString(ExecState*, int32_t);
</span><span class="cx"> 
</span><span class="cx"> JSCell* JIT_OPERATION operationStringSubstr(ExecState*, JSCell*, int32_t, int32_t);
</span><ins>+JSCell* JIT_OPERATION operationStringSlice(ExecState*, JSCell*, int32_t, int32_t);
</ins><span class="cx"> JSString* JIT_OPERATION operationStringValueOf(ExecState*, EncodedJSValue);
</span><span class="cx"> JSString* JIT_OPERATION operationToLowerCase(ExecState*, JSString*, uint32_t);
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp   2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp      2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1530,23 +1530,39 @@
</span><span class="cx"> void SpeculativeJIT::compileStringSlice(Node* node)
</span><span class="cx"> {
</span><span class="cx">     SpeculateCellOperand string(this, node->child1());
</span><del>-    GPRTemporary startIndex(this);
-    GPRTemporary temp(this);
-    GPRTemporary temp2(this);
</del><span class="cx"> 
</span><span class="cx">     GPRReg stringGPR = string.gpr();
</span><del>-    GPRReg startIndexGPR = startIndex.gpr();
-    GPRReg tempGPR = temp.gpr();
-    GPRReg temp2GPR = temp2.gpr();
</del><span class="cx"> 
</span><span class="cx">     speculateString(node->child1(), stringGPR);
</span><span class="cx"> 
</span><ins>+    SpeculateInt32Operand start(this, node->child2());
+    GPRReg startGPR = start.gpr();
+
+    Optional<SpeculateInt32Operand> end;
+    Optional<GPRReg> endGPR;
+    if (node->child3()) {
+        end.emplace(this, node->child3());
+        endGPR.emplace(end->gpr());
+    }
+
+    GPRTemporary temp(this);
+    GPRReg tempGPR = temp.gpr();
+
+    m_jit.loadPtr(CCallHelpers::Address(stringGPR, JSString::offsetOfValue()), tempGPR);
+    auto isRope = m_jit.branchIfRopeStringImpl(tempGPR);
+
+    GPRTemporary temp2(this);
+    GPRTemporary startIndex(this);
+
+    GPRReg temp2GPR = temp2.gpr();
+    GPRReg startIndexGPR = startIndex.gpr();
</ins><span class="cx">     {
</span><del>-        m_jit.load32(JITCompiler::Address(stringGPR, JSString::offsetOfLength()), temp2GPR);
</del><ins>+        m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), temp2GPR);
</ins><span class="cx"> 
</span><del>-        emitPopulateSliceIndex(node->child2(), temp2GPR, startIndexGPR);
</del><ins>+        emitPopulateSliceIndex(node->child2(), startGPR, temp2GPR, startIndexGPR);
+
</ins><span class="cx">         if (node->child3())
</span><del>-            emitPopulateSliceIndex(node->child3(), temp2GPR, tempGPR);
</del><ins>+            emitPopulateSliceIndex(node->child3(), endGPR.value(), temp2GPR, tempGPR);
</ins><span class="cx">         else
</span><span class="cx">             m_jit.move(temp2GPR, tempGPR);
</span><span class="cx">     }
</span><span class="lines">@@ -1562,9 +1578,8 @@
</span><span class="cx">     m_jit.sub32(startIndexGPR, tempGPR); // the size of the sliced string.
</span><span class="cx">     slowCases.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(1)));
</span><span class="cx"> 
</span><ins>+    // Refill StringImpl* here.
</ins><span class="cx">     m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), temp2GPR);
</span><del>-    slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, temp2GPR));
-
</del><span class="cx">     m_jit.loadPtr(MacroAssembler::Address(temp2GPR, StringImpl::dataOffset()), tempGPR);
</span><span class="cx"> 
</span><span class="cx">     // Load the character into scratchReg
</span><span class="lines">@@ -1586,14 +1601,15 @@
</span><span class="cx">     m_jit.addPtr(TrustedImmPtr(m_jit.vm()->smallStrings.singleCharacterStrings()), tempGPR);
</span><span class="cx">     m_jit.loadPtr(tempGPR, tempGPR);
</span><span class="cx"> 
</span><del>-    addSlowPathGenerator(
-        slowPathCall(
-            bigCharacter, this, operationSingleCharacterString, tempGPR, tempGPR));
</del><ins>+    addSlowPathGenerator(slowPathCall(bigCharacter, this, operationSingleCharacterString, tempGPR, tempGPR));
</ins><span class="cx"> 
</span><del>-    addSlowPathGenerator(
-        slowPathCall(
-            slowCases, this, operationStringSubstr, tempGPR, stringGPR, startIndexGPR, tempGPR));
</del><ins>+    addSlowPathGenerator(slowPathCall(slowCases, this, operationStringSubstr, tempGPR, stringGPR, startIndexGPR, tempGPR));
</ins><span class="cx"> 
</span><ins>+    if (endGPR)
+        addSlowPathGenerator(slowPathCall(isRope, this, operationStringSlice, tempGPR, stringGPR, startGPR, *endGPR));
+    else
+        addSlowPathGenerator(slowPathCall(isRope, this, operationStringSlice, tempGPR, stringGPR, startGPR, TrustedImm32(std::numeric_limits<int32_t>::max())));
+
</ins><span class="cx">     doneCases.link(&m_jit);
</span><span class="cx">     cellResult(tempGPR, node);
</span><span class="cx"> }
</span><span class="lines">@@ -1620,8 +1636,7 @@
</span><span class="cx">     m_jit.move(TrustedImmPtr(nullptr), indexGPR);
</span><span class="cx"> 
</span><span class="cx">     m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), tempGPR);
</span><del>-    slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, tempGPR));
-
</del><ins>+    slowPath.append(m_jit.branchIfRopeStringImpl(tempGPR));
</ins><span class="cx">     slowPath.append(m_jit.branchTest32(
</span><span class="cx">         MacroAssembler::Zero, MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()),
</span><span class="cx">         MacroAssembler::TrustedImm32(StringImpl::flagIs8Bit())));
</span><span class="lines">@@ -2128,13 +2143,13 @@
</span><span class="cx">     
</span><span class="cx">     ASSERT(speculationChecked(m_state.forNode(node->child1()).m_type, SpecString));
</span><span class="cx"> 
</span><del>-    // unsigned comparison so we can filter out negative indices and indices that are too large
-    speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, MacroAssembler::Address(stringReg, JSString::offsetOfLength())));
-
</del><span class="cx">     GPRTemporary scratch(this);
</span><span class="cx">     GPRReg scratchReg = scratch.gpr();
</span><span class="cx"> 
</span><span class="cx">     m_jit.loadPtr(MacroAssembler::Address(stringReg, JSString::offsetOfValue()), scratchReg);
</span><ins>+    
+    // unsigned comparison so we can filter out negative indices and indices that are too large
+    speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, CCallHelpers::Address(scratchReg, StringImpl::lengthMemoryOffset())));
</ins><span class="cx"> 
</span><span class="cx">     // Load the character into scratchReg
</span><span class="cx">     JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
</span><span class="lines">@@ -2175,14 +2190,13 @@
</span><span class="cx">     ASSERT(ArrayMode(Array::String, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.child(node, 0))));
</span><span class="cx"> 
</span><span class="cx">     // unsigned comparison so we can filter out negative indices and indices that are too large
</span><ins>+    m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);
</ins><span class="cx">     JITCompiler::Jump outOfBounds = m_jit.branch32(
</span><span class="cx">         MacroAssembler::AboveOrEqual, propertyReg,
</span><del>-        MacroAssembler::Address(baseReg, JSString::offsetOfLength()));
</del><ins>+        MacroAssembler::Address(scratchReg, StringImpl::lengthMemoryOffset()));
</ins><span class="cx">     if (node->arrayMode().isInBounds())
</span><span class="cx">         speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds);
</span><span class="cx"> 
</span><del>-    m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);
-
</del><span class="cx">     // Load the character into scratchReg
</span><span class="cx">     JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
</span><span class="cx"> 
</span><span class="lines">@@ -4330,88 +4344,6 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::compileMakeRope(Node* node)
-{
-    ASSERT(node->child1().useKind() == KnownStringUse);
-    ASSERT(node->child2().useKind() == KnownStringUse);
-    ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse);
-    
-    SpeculateCellOperand op1(this, node->child1());
-    SpeculateCellOperand op2(this, node->child2());
-    SpeculateCellOperand op3(this, node->child3());
-    GPRTemporary result(this);
-    GPRTemporary allocator(this);
-    GPRTemporary scratch(this);
-    
-    GPRReg opGPRs[3];
-    unsigned numOpGPRs;
-    opGPRs[0] = op1.gpr();
-    opGPRs[1] = op2.gpr();
-    if (node->child3()) {
-        opGPRs[2] = op3.gpr();
-        numOpGPRs = 3;
-    } else {
-        opGPRs[2] = InvalidGPRReg;
-        numOpGPRs = 2;
-    }
-    GPRReg resultGPR = result.gpr();
-    GPRReg allocatorGPR = allocator.gpr();
-    GPRReg scratchGPR = scratch.gpr();
-    
-    JITCompiler::JumpList slowPath;
-    Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSRopeString>(*m_jit.vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists);
-    emitAllocateJSCell(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.vm()->stringStructure.get())), scratchGPR, slowPath);
-        
-    m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSString::offsetOfValue()));
-    for (unsigned i = 0; i < numOpGPRs; ++i)
-        m_jit.storePtr(opGPRs[i], JITCompiler::Address(resultGPR, JSRopeString::offsetOfFibers() + sizeof(WriteBarrier<JSString>) * i));
-    for (unsigned i = numOpGPRs; i < JSRopeString::s_maxInternalRopeLength; ++i)
-        m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSRopeString::offsetOfFibers() + sizeof(WriteBarrier<JSString>) * i));
-    m_jit.load16(JITCompiler::Address(opGPRs[0], JSString::offsetOfFlags()), scratchGPR);
-    m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfLength()), allocatorGPR);
-    if (!ASSERT_DISABLED) {
-        JITCompiler::Jump ok = m_jit.branch32(
-            JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
-        m_jit.abortWithReason(DFGNegativeStringLength);
-        ok.link(&m_jit);
-    }
-    for (unsigned i = 1; i < numOpGPRs; ++i) {
-        m_jit.and16(JITCompiler::Address(opGPRs[i], JSString::offsetOfFlags()), scratchGPR);
-        speculationCheck(
-            Uncountable, JSValueSource(), nullptr,
-            m_jit.branchAdd32(
-                JITCompiler::Overflow,
-                JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR));
-    }
-    m_jit.and32(JITCompiler::TrustedImm32(JSString::Is8Bit), scratchGPR);
-    m_jit.store16(scratchGPR, JITCompiler::Address(resultGPR, JSString::offsetOfFlags()));
-    if (!ASSERT_DISABLED) {
-        JITCompiler::Jump ok = m_jit.branch32(
-            JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
-        m_jit.abortWithReason(DFGNegativeStringLength);
-        ok.link(&m_jit);
-    }
-    m_jit.store32(allocatorGPR, JITCompiler::Address(resultGPR, JSString::offsetOfLength()));
-    
-    m_jit.mutatorFence(*m_jit.vm());
-    
-    switch (numOpGPRs) {
-    case 2:
-        addSlowPathGenerator(slowPathCall(
-            slowPath, this, operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]));
-        break;
-    case 3:
-        addSlowPathGenerator(slowPathCall(
-            slowPath, this, operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]));
-        break;
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        break;
-    }
-    
-    cellResult(resultGPR, node);
-}
-
</del><span class="cx"> void SpeculativeJIT::compileArithAbs(Node* node)
</span><span class="cx"> {
</span><span class="cx">     switch (node->child1().useKind()) {
</span><span class="lines">@@ -6320,21 +6252,21 @@
</span><span class="cx">     trueCase.append(fastTrue);
</span><span class="cx">     falseCase.append(fastFalse);
</span><span class="cx"> 
</span><del>-    m_jit.load32(MacroAssembler::Address(leftGPR, JSString::offsetOfLength()), lengthGPR);
</del><ins>+    m_jit.loadPtr(MacroAssembler::Address(leftGPR, JSString::offsetOfValue()), leftTempGPR);
+    m_jit.loadPtr(MacroAssembler::Address(rightGPR, JSString::offsetOfValue()), rightTempGPR);
+
+    slowCase.append(m_jit.branchIfRopeStringImpl(leftTempGPR));
+    slowCase.append(m_jit.branchIfRopeStringImpl(rightTempGPR));
+
+    m_jit.load32(MacroAssembler::Address(leftTempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
</ins><span class="cx">     
</span><span class="cx">     falseCase.append(m_jit.branch32(
</span><span class="cx">         MacroAssembler::NotEqual,
</span><del>-        MacroAssembler::Address(rightGPR, JSString::offsetOfLength()),
</del><ins>+        MacroAssembler::Address(rightTempGPR, StringImpl::lengthMemoryOffset()),
</ins><span class="cx">         lengthGPR));
</span><span class="cx">     
</span><span class="cx">     trueCase.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR));
</span><span class="cx">     
</span><del>-    m_jit.loadPtr(MacroAssembler::Address(leftGPR, JSString::offsetOfValue()), leftTempGPR);
-    m_jit.loadPtr(MacroAssembler::Address(rightGPR, JSString::offsetOfValue()), rightTempGPR);
-    
-    slowCase.append(m_jit.branchTestPtr(MacroAssembler::Zero, leftTempGPR));
-    slowCase.append(m_jit.branchTestPtr(MacroAssembler::Zero, rightTempGPR));
-    
</del><span class="cx">     slowCase.append(m_jit.branchTest32(
</span><span class="cx">         MacroAssembler::Zero,
</span><span class="cx">         MacroAssembler::Address(leftTempGPR, StringImpl::flagsOffset()),
</span><span class="lines">@@ -6638,9 +6570,8 @@
</span><span class="cx">     GPRTemporary eq(this);
</span><span class="cx">     GPRReg eqGPR = eq.gpr();
</span><span class="cx"> 
</span><del>-    // Fetch the length field from the string object.
-    m_jit.test32(MacroAssembler::Zero, MacroAssembler::Address(strGPR, JSString::offsetOfLength()), MacroAssembler::TrustedImm32(-1), eqGPR);
-
</del><ins>+    m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), eqGPR);
+    m_jit.comparePtr(CCallHelpers::Equal, strGPR, eqGPR, eqGPR);
</ins><span class="cx">     unblessedBooleanResult(eqGPR, node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -6655,16 +6586,17 @@
</span><span class="cx">     GPRReg cellGPR = valueRegs.payloadGPR();
</span><span class="cx">     DFG_TYPE_CHECK(
</span><span class="cx">         valueRegs, node->child1(), (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
</span><del>-    m_jit.test32(
-        JITCompiler::Zero, JITCompiler::Address(cellGPR, JSString::offsetOfLength()),
-        JITCompiler::TrustedImm32(-1), tempGPR);
-    JITCompiler::Jump done = m_jit.jump();
</del><ins>+
+    m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), tempGPR);
+    m_jit.comparePtr(CCallHelpers::Equal, cellGPR, tempGPR, tempGPR);
+    auto done = m_jit.jump();
+
</ins><span class="cx">     notCell.link(&m_jit);
</span><span class="cx">     DFG_TYPE_CHECK(
</span><span class="cx">         valueRegs, node->child1(), SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
</span><span class="cx">     m_jit.move(TrustedImm32(1), tempGPR);
</span><ins>+
</ins><span class="cx">     done.link(&m_jit);
</span><del>-
</del><span class="cx">     unblessedBooleanResult(tempGPR, node);
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="lines">@@ -6672,9 +6604,14 @@
</span><span class="cx"> void SpeculativeJIT::emitStringBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)
</span><span class="cx"> {
</span><span class="cx">     SpeculateCellOperand str(this, nodeUse);
</span><del>-    speculateString(nodeUse, str.gpr());
-    branchTest32(JITCompiler::NonZero, MacroAssembler::Address(str.gpr(), JSString::offsetOfLength()), taken);
-    jump(notTaken);
</del><ins>+
+    GPRReg strGPR = str.gpr();
+
+    speculateString(nodeUse, strGPR);
+
+    branchPtr(CCallHelpers::Equal, strGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), notTaken);
+    jump(taken);
+
</ins><span class="cx">     noResult(m_currentNode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -6688,10 +6625,10 @@
</span><span class="cx">     JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
</span><span class="cx">     GPRReg cellGPR = valueRegs.payloadGPR();
</span><span class="cx">     DFG_TYPE_CHECK(valueRegs, nodeUse, (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
</span><del>-    branchTest32(
-        JITCompiler::Zero, JITCompiler::Address(cellGPR, JSString::offsetOfLength()),
-        JITCompiler::TrustedImm32(-1), notTaken);
</del><ins>+
+    branchPtr(CCallHelpers::Equal, cellGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), notTaken);
</ins><span class="cx">     jump(taken, ForceJump);
</span><ins>+
</ins><span class="cx">     notCell.link(&m_jit);
</span><span class="cx">     DFG_TYPE_CHECK(
</span><span class="cx">         valueRegs, nodeUse, SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
</span><span class="lines">@@ -6740,7 +6677,7 @@
</span><span class="cx">         
</span><span class="cx">         addSlowPathGenerator(
</span><span class="cx">             slowPathCall(
</span><del>-                m_jit.branchTest32(MacroAssembler::Zero, storageReg),
</del><ins>+                m_jit.branchIfRopeStringImpl(storageReg),
</ins><span class="cx">                 this, operationResolveRope, storageReg, baseReg));
</span><span class="cx"> 
</span><span class="cx">         m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg);
</span><span class="lines">@@ -6992,9 +6929,20 @@
</span><span class="cx">     case Array::String: {
</span><span class="cx">         SpeculateCellOperand base(this, node->child1());
</span><span class="cx">         GPRTemporary result(this, Reuse, base);
</span><ins>+        GPRTemporary temp(this);
</ins><span class="cx">         GPRReg baseGPR = base.gpr();
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><del>-        m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR);
</del><ins>+        GPRReg tempGPR = temp.gpr();
+
+        m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSString::offsetOfValue()), tempGPR);
+        auto isRope = m_jit.branchIfRopeStringImpl(tempGPR);
+        m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), resultGPR);
+        auto done = m_jit.jump();
+
+        isRope.link(&m_jit);
+        m_jit.load32(CCallHelpers::Address(baseGPR, JSRopeString::offsetOfLength()), resultGPR);
+
+        done.link(&m_jit);
</ins><span class="cx">         int32Result(resultGPR, node);
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="lines">@@ -8139,44 +8087,47 @@
</span><span class="cx">     int32Result(resultGPR, node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, GPRReg length, GPRReg result)
</del><ins>+void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, Optional<GPRReg> indexGPR, GPRReg lengthGPR, GPRReg resultGPR)
</ins><span class="cx"> {
</span><span class="cx">     if (target->isInt32Constant()) {
</span><span class="cx">         int32_t value = target->asInt32();
</span><span class="cx">         if (value == 0) {
</span><del>-            m_jit.move(TrustedImm32(0), result);
</del><ins>+            m_jit.move(TrustedImm32(0), resultGPR);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         MacroAssembler::JumpList done;
</span><span class="cx">         if (value > 0) {
</span><del>-            m_jit.move(TrustedImm32(value), result);
-            done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
-            m_jit.move(length, result);
</del><ins>+            m_jit.move(TrustedImm32(value), resultGPR);
+            done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR));
+            m_jit.move(lengthGPR, resultGPR);
</ins><span class="cx">         } else {
</span><span class="cx">             ASSERT(value != 0);
</span><del>-            m_jit.move(length, result);
-            done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, TrustedImm32(value), result));
-            m_jit.move(TrustedImm32(0), result);
</del><ins>+            m_jit.move(lengthGPR, resultGPR);
+            done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, TrustedImm32(value), resultGPR));
+            m_jit.move(TrustedImm32(0), resultGPR);
</ins><span class="cx">         }
</span><span class="cx">         done.link(&m_jit);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    SpeculateInt32Operand index(this, target);
-    GPRReg indexGPR = index.gpr();
</del><ins>+    Optional<SpeculateInt32Operand> index;
+    if (!indexGPR) {
+        index.emplace(this, target);
+        indexGPR = index->gpr();
+    }
</ins><span class="cx">     MacroAssembler::JumpList done;
</span><span class="cx"> 
</span><del>-    auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR, TrustedImm32(0));
-    m_jit.move(length, result);
-    done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR, result));
-    m_jit.move(TrustedImm32(0), result);
</del><ins>+    auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR.value(), TrustedImm32(0));
+    m_jit.move(lengthGPR, resultGPR);
+    done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR.value(), resultGPR));
+    m_jit.move(TrustedImm32(0), resultGPR);
</ins><span class="cx">     done.append(m_jit.jump());
</span><span class="cx"> 
</span><span class="cx">     isPositive.link(&m_jit);
</span><del>-    m_jit.move(indexGPR, result);
-    done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
-    m_jit.move(length, result);
</del><ins>+    m_jit.move(indexGPR.value(), resultGPR);
+    done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR));
+    m_jit.move(lengthGPR, resultGPR);
</ins><span class="cx"> 
</span><span class="cx">     done.link(&m_jit);
</span><span class="cx"> }
</span><span class="lines">@@ -8204,7 +8155,7 @@
</span><span class="cx">         m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
</span><span class="cx"> 
</span><span class="cx">         if (node->numChildren() == 4)
</span><del>-            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), lengthGPR, tempGPR);
</del><ins>+            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, tempGPR);
</ins><span class="cx">         else
</span><span class="cx">             m_jit.move(lengthGPR, tempGPR);
</span><span class="cx"> 
</span><span class="lines">@@ -8214,7 +8165,7 @@
</span><span class="cx">         } else {
</span><span class="cx">             GPRTemporary tempStartIndex(this);
</span><span class="cx">             GPRReg startGPR = tempStartIndex.gpr();
</span><del>-            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), lengthGPR, startGPR);
</del><ins>+            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, lengthGPR, startGPR);
</ins><span class="cx"> 
</span><span class="cx">             auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
</span><span class="cx">             m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
</span><span class="lines">@@ -8303,10 +8254,10 @@
</span><span class="cx">     } else {
</span><span class="cx">         m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
</span><span class="cx">         if (node->numChildren() == 4)
</span><del>-            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), tempValue, tempGPR);
</del><ins>+            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, tempValue, tempGPR);
</ins><span class="cx">         else
</span><span class="cx">             m_jit.move(tempValue, tempGPR);
</span><del>-        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), tempValue, loadIndex);
</del><ins>+        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, tempValue, loadIndex);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     GPRTemporary temp5(this);
</span><span class="lines">@@ -8360,7 +8311,7 @@
</span><span class="cx">     m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
</span><span class="cx"> 
</span><span class="cx">     if (node->numChildren() == 4)
</span><del>-        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), lengthGPR, indexGPR);
</del><ins>+        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, indexGPR);
</ins><span class="cx">     else
</span><span class="cx">         m_jit.move(TrustedImm32(0), indexGPR);
</span><span class="cx"> 
</span><span class="lines">@@ -10137,7 +10088,7 @@
</span><span class="cx"> 
</span><span class="cx">     speculationCheck(
</span><span class="cx">         BadType, JSValueSource::unboxedCell(string), edge,
</span><del>-        m_jit.branchTestPtr(MacroAssembler::Zero, storage));
</del><ins>+        m_jit.branchIfRopeStringImpl(storage));
</ins><span class="cx">     speculationCheck(
</span><span class="cx">         BadType, JSValueSource::unboxedCell(string), edge, m_jit.branchTest32(
</span><span class="cx">             MacroAssembler::Zero,
</span><span class="lines">@@ -10528,20 +10479,18 @@
</span><span class="cx"> void SpeculativeJIT::emitSwitchCharStringJump(
</span><span class="cx">     SwitchData* data, GPRReg value, GPRReg scratch)
</span><span class="cx"> {
</span><ins>+    m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch);
+    auto isRope = m_jit.branchIfRopeStringImpl(scratch);
+
</ins><span class="cx">     addBranch(
</span><span class="cx">         m_jit.branch32(
</span><span class="cx">             MacroAssembler::NotEqual,
</span><del>-            MacroAssembler::Address(value, JSString::offsetOfLength()),
</del><ins>+            MacroAssembler::Address(scratch, StringImpl::lengthMemoryOffset()),
</ins><span class="cx">             TrustedImm32(1)),
</span><span class="cx">         data->fallThrough.block);
</span><span class="cx">     
</span><del>-    m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch);
</del><ins>+    addSlowPathGenerator(slowPathCall(isRope, this, operationResolveRope, scratch, value));
</ins><span class="cx">     
</span><del>-    addSlowPathGenerator(
-        slowPathCall(
-            m_jit.branchTestPtr(MacroAssembler::Zero, scratch),
-            this, operationResolveRope, scratch, value));
-    
</del><span class="cx">     m_jit.loadPtr(MacroAssembler::Address(scratch, StringImpl::dataOffset()), value);
</span><span class="cx">     
</span><span class="cx">     JITCompiler::Jump is8Bit = m_jit.branchTest32(
</span><span class="lines">@@ -10783,11 +10732,11 @@
</span><span class="cx">     GPRReg lengthGPR = length.gpr();
</span><span class="cx">     GPRReg tempGPR = temp.gpr();
</span><span class="cx">     
</span><del>-    m_jit.load32(MacroAssembler::Address(string, JSString::offsetOfLength()), lengthGPR);
</del><ins>+    MacroAssembler::JumpList slowCases;
</ins><span class="cx">     m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), tempGPR);
</span><ins>+    slowCases.append(m_jit.branchIfRopeStringImpl(tempGPR));
+    m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), lengthGPR);
</ins><span class="cx">     
</span><del>-    MacroAssembler::JumpList slowCases;
-    slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, tempGPR));
</del><span class="cx">     slowCases.append(m_jit.branchTest32(
</span><span class="cx">         MacroAssembler::Zero,
</span><span class="cx">         MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()),
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1542,7 +1542,7 @@
</span><span class="cx">     void emitGetLength(CodeOrigin, GPRReg lengthGPR, bool includeThis = false);
</span><span class="cx">     void emitGetCallee(CodeOrigin, GPRReg calleeGPR);
</span><span class="cx">     void emitGetArgumentStart(CodeOrigin, GPRReg startGPR);
</span><del>-    void emitPopulateSliceIndex(Edge&, GPRReg length, GPRReg result);
</del><ins>+    void emitPopulateSliceIndex(Edge&, Optional<GPRReg> indexGPR, GPRReg lengthGPR, GPRReg resultGPR);
</ins><span class="cx">     
</span><span class="cx">     // Generate an OSR exit fuzz check. Returns Jump() if OSR exit fuzz is not enabled, or if
</span><span class="cx">     // it's in training mode.
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp      2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp 2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -3880,7 +3880,7 @@
</span><span class="cx">         case StringUse: {
</span><span class="cx">             speculateString(node->child2(), keyRegs.payloadGPR());
</span><span class="cx">             m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR);
</span><del>-            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
</del><ins>+            slowPath.append(m_jit.branchIfRopeStringImpl(implGPR));
</ins><span class="cx">             slowPath.append(m_jit.branchTest32(
</span><span class="cx">                 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
</span><span class="cx">                 MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
</span><span class="lines">@@ -3890,7 +3890,7 @@
</span><span class="cx">             slowPath.append(m_jit.branchIfNotCell(keyRegs));
</span><span class="cx">             auto isNotString = m_jit.branchIfNotString(keyRegs.payloadGPR());
</span><span class="cx">             m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR);
</span><del>-            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
</del><ins>+            slowPath.append(m_jit.branchIfRopeStringImpl(implGPR));
</ins><span class="cx">             slowPath.append(m_jit.branchTest32(
</span><span class="cx">                 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
</span><span class="cx">                 MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
</span><span class="lines">@@ -4195,6 +4195,48 @@
</span><span class="cx">     doubleResult(result.fpr(), node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeJIT::compileMakeRope(Node* node)
+{
+    ASSERT(node->child1().useKind() == KnownStringUse);
+    ASSERT(node->child2().useKind() == KnownStringUse);
+    ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse);
+    
+    SpeculateCellOperand op1(this, node->child1());
+    SpeculateCellOperand op2(this, node->child2());
+    SpeculateCellOperand op3(this, node->child3());
+    
+    GPRReg opGPRs[3];
+    unsigned numOpGPRs;
+    opGPRs[0] = op1.gpr();
+    opGPRs[1] = op2.gpr();
+    if (node->child3()) {
+        opGPRs[2] = op3.gpr();
+        numOpGPRs = 3;
+    } else {
+        opGPRs[2] = InvalidGPRReg;
+        numOpGPRs = 2;
+    }
+
+    flushRegisters();
+    GPRFlushedCallResult result(this);
+    GPRReg resultGPR = result.gpr();
+    switch (numOpGPRs) {
+    case 2:
+        callOperation(operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]);
+        m_jit.exceptionCheck();
+        break;
+    case 3:
+        callOperation(operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]);
+        m_jit.exceptionCheck();
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+    
+    cellResult(resultGPR, node);
+}
+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp 2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp    2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -4038,7 +4038,7 @@
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR);
</span><del>-            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
</del><ins>+            slowPath.append(m_jit.branchIfRopeStringImpl(resultGPR));
</ins><span class="cx">             m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR);
</span><span class="cx">             m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
</span><span class="cx">             slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
</span><span class="lines">@@ -4076,7 +4076,7 @@
</span><span class="cx">         MacroAssembler::JumpList slowPath;
</span><span class="cx">         straightHash.append(m_jit.branchIfNotString(inputGPR));
</span><span class="cx">         m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR);
</span><del>-        slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
</del><ins>+        slowPath.append(m_jit.branchIfRopeStringImpl(resultGPR));
</ins><span class="cx">         m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR);
</span><span class="cx">         m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR);
</span><span class="cx">         slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR));
</span><span class="lines">@@ -4450,7 +4450,7 @@
</span><span class="cx">         case StringUse: {
</span><span class="cx">             speculateString(node->child2(), keyGPR);
</span><span class="cx">             m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
</span><del>-            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
</del><ins>+            slowPath.append(m_jit.branchIfRopeStringImpl(implGPR));
</ins><span class="cx">             slowPath.append(m_jit.branchTest32(
</span><span class="cx">                 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
</span><span class="cx">                 MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
</span><span class="lines">@@ -4460,7 +4460,7 @@
</span><span class="cx">             slowPath.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR)));
</span><span class="cx">             auto isNotString = m_jit.branchIfNotString(keyGPR);
</span><span class="cx">             m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR);
</span><del>-            slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, implGPR));
</del><ins>+            slowPath.append(m_jit.branchIfRopeStringImpl(implGPR));
</ins><span class="cx">             slowPath.append(m_jit.branchTest32(
</span><span class="cx">                 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()),
</span><span class="cx">                 MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic())));
</span><span class="lines">@@ -5230,6 +5230,162 @@
</span><span class="cx">     doubleResult(result.fpr(), node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeJIT::compileMakeRope(Node* node)
+{
+    ASSERT(node->child1().useKind() == KnownStringUse);
+    ASSERT(node->child2().useKind() == KnownStringUse);
+    ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse);
+
+    SpeculateCellOperand op1(this, node->child1());
+    SpeculateCellOperand op2(this, node->child2());
+    SpeculateCellOperand op3(this, node->child3());
+    GPRTemporary result(this);
+    GPRTemporary allocator(this);
+    GPRTemporary scratch(this);
+    GPRTemporary scratch2(this);
+
+    Edge edges[3] = {
+        node->child1(),
+        node->child2(),
+        node->child3()
+    };
+    GPRReg opGPRs[3];
+    unsigned numOpGPRs;
+    opGPRs[0] = op1.gpr();
+    opGPRs[1] = op2.gpr();
+    if (node->child3()) {
+        opGPRs[2] = op3.gpr();
+        numOpGPRs = 3;
+    } else {
+        opGPRs[2] = InvalidGPRReg;
+        numOpGPRs = 2;
+    }
+    GPRReg resultGPR = result.gpr();
+    GPRReg allocatorGPR = allocator.gpr();
+    GPRReg scratchGPR = scratch.gpr();
+    GPRReg scratch2GPR = scratch2.gpr();
+
+    CCallHelpers::JumpList slowPath;
+    Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSRopeString>(*m_jit.vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists);
+    emitAllocateJSCell(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.vm()->stringStructure.get())), scratchGPR, slowPath);
+
+    m_jit.orPtr(TrustedImm32(JSString::isRopeInPointer), opGPRs[0], allocatorGPR);
+    m_jit.storePtr(allocatorGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber0()));
+
+    m_jit.move(opGPRs[1], scratchGPR);
+    m_jit.store32(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber1Lower()));
+    m_jit.rshiftPtr(TrustedImm32(32), scratchGPR);
+    m_jit.store16(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber1Upper()));
+
+    if (numOpGPRs == 3) {
+        m_jit.move(opGPRs[2], scratchGPR);
+        m_jit.store32(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2Lower()));
+        m_jit.rshiftPtr(TrustedImm32(32), scratchGPR);
+        m_jit.store16(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2Upper()));
+    } else {
+        m_jit.storeZero32(CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2Lower()));
+        m_jit.storeZero16(CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2Upper()));
+    }
+
+    {
+        if (JSString* string = edges[0]->dynamicCastConstant<JSString*>(*m_jit.vm())) {
+            m_jit.move(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR);
+            m_jit.move(TrustedImm32(string->length()), allocatorGPR);
+        } else {
+            bool canBeRope = !m_state.forNode(edges[0]).isType(SpecStringIdent);
+            m_jit.loadPtr(CCallHelpers::Address(opGPRs[0], JSString::offsetOfValue()), scratch2GPR);
+            CCallHelpers::Jump isRope;
+            if (canBeRope)
+                isRope = m_jit.branchIfRopeStringImpl(scratch2GPR);
+
+            m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR);
+            m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR);
+
+            if (canBeRope) {
+                auto done = m_jit.jump();
+
+                isRope.link(&m_jit);
+                m_jit.load16(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfFlags()), scratchGPR);
+                m_jit.load32(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfLength()), allocatorGPR);
+                done.link(&m_jit);
+            }
+        }
+
+        if (!ASSERT_DISABLED) {
+            CCallHelpers::Jump ok = m_jit.branch32(
+                CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
+            m_jit.abortWithReason(DFGNegativeStringLength);
+            ok.link(&m_jit);
+        }
+    }
+
+    for (unsigned i = 1; i < numOpGPRs; ++i) {
+        if (JSString* string = edges[i]->dynamicCastConstant<JSString*>(*m_jit.vm())) {
+            m_jit.and32(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR);
+            speculationCheck(
+                Uncountable, JSValueSource(), nullptr,
+                m_jit.branchAdd32(
+                    CCallHelpers::Overflow,
+                    TrustedImm32(string->length()), allocatorGPR));
+        } else {
+            bool canBeRope = !m_state.forNode(edges[i]).isType(SpecStringIdent);
+            m_jit.loadPtr(CCallHelpers::Address(opGPRs[i], JSString::offsetOfValue()), scratch2GPR);
+            CCallHelpers::Jump isRope;
+            if (canBeRope)
+                isRope = m_jit.branchIfRopeStringImpl(scratch2GPR);
+
+            m_jit.and16(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR);
+            speculationCheck(
+                Uncountable, JSValueSource(), nullptr,
+                m_jit.branchAdd32(
+                    CCallHelpers::Overflow,
+                    CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR));
+            if (canBeRope) {
+                auto done = m_jit.jump();
+
+                isRope.link(&m_jit);
+                m_jit.and16(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfFlags()), scratchGPR);
+                m_jit.load32(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfLength()), scratch2GPR);
+                speculationCheck(
+                    Uncountable, JSValueSource(), nullptr,
+                    m_jit.branchAdd32(
+                        CCallHelpers::Overflow, scratch2GPR, allocatorGPR));
+                done.link(&m_jit);
+            }
+        }
+    }
+    m_jit.store16(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFlags()));
+    if (!ASSERT_DISABLED) {
+        CCallHelpers::Jump ok = m_jit.branch32(
+            CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
+        m_jit.abortWithReason(DFGNegativeStringLength);
+        ok.link(&m_jit);
+    }
+    m_jit.store32(allocatorGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfLength()));
+    auto isNonEmptyString = m_jit.branchTest32(CCallHelpers::NonZero, allocatorGPR);
+
+    m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(&m_jit.graph().m_vm)), resultGPR);
+
+    isNonEmptyString.link(&m_jit);
+    m_jit.mutatorFence(*m_jit.vm());
+
+    switch (numOpGPRs) {
+    case 2:
+        addSlowPathGenerator(slowPathCall(
+            slowPath, this, operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]));
+        break;
+    case 3:
+        addSlowPathGenerator(slowPathCall(
+            slowPath, this, operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]));
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+
+    cellResult(resultGPR, node);
+}
+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreftlFTLAbstractHeapRepositorycpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp   2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp      2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -60,8 +60,6 @@
</span><span class="cx">     , JSCell_freeListNext(JSCell_header)
</span><span class="cx">     , ArrayStorage_publicLength(Butterfly_publicLength)
</span><span class="cx">     , ArrayStorage_vectorLength(Butterfly_vectorLength)
</span><del>-    , JSBigInt_length(JSBigIntOrString_length)
-    , JSString_length(JSBigIntOrString_length)
</del><span class="cx">     
</span><span class="cx"> #define INDEXED_ABSTRACT_HEAP_INITIALIZATION(name, offset, size) , name(&root, #name, offset, size)
</span><span class="cx">     FOR_EACH_INDEXED_ABSTRACT_HEAP(INDEXED_ABSTRACT_HEAP_INITIALIZATION)
</span><span class="lines">@@ -71,6 +69,8 @@
</span><span class="cx">     FOR_EACH_NUMBERED_ABSTRACT_HEAP(NUMBERED_ABSTRACT_HEAP_INITIALIZATION)
</span><span class="cx"> #undef NUMBERED_ABSTRACT_HEAP_INITIALIZATION
</span><span class="cx"> 
</span><ins>+    , JSString_value(JSRopeString_fiber0)
+
</ins><span class="cx">     , absolute(&root, "absolute")
</span><span class="cx"> {
</span><span class="cx">     // Make sure that our explicit assumptions about the StructureIDBlob match reality.
</span><span class="lines">@@ -79,8 +79,6 @@
</span><span class="cx">     RELEASE_ASSERT(JSCell_indexingTypeAndMisc.offset() + 2 == JSCell_typeInfoFlags.offset());
</span><span class="cx">     RELEASE_ASSERT(JSCell_indexingTypeAndMisc.offset() + 3 == JSCell_cellState.offset());
</span><span class="cx"> 
</span><del>-    RELEASE_ASSERT(JSBigInt::offsetOfLength() == JSString::offsetOfLength());
-
</del><span class="cx">     JSCell_structureID.changeParent(&JSCell_header);
</span><span class="cx">     JSCell_usefulBytes.changeParent(&JSCell_header);
</span><span class="cx">     JSCell_indexingTypeAndMisc.changeParent(&JSCell_usefulBytes);
</span><span class="lines">@@ -87,6 +85,7 @@
</span><span class="cx">     JSCell_typeInfoType.changeParent(&JSCell_usefulBytes);
</span><span class="cx">     JSCell_typeInfoFlags.changeParent(&JSCell_usefulBytes);
</span><span class="cx">     JSCell_cellState.changeParent(&JSCell_usefulBytes);
</span><ins>+    JSRopeString_flags.changeParent(&JSRopeString_fiber0);
</ins><span class="cx"> 
</span><span class="cx">     RELEASE_ASSERT(!JSCell_freeListNext.offset());
</span><span class="cx"> }
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreftlFTLAbstractHeapRepositoryh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -64,7 +64,7 @@
</span><span class="cx">     macro(JSArrayBufferView_length, JSArrayBufferView::offsetOfLength()) \
</span><span class="cx">     macro(JSArrayBufferView_mode, JSArrayBufferView::offsetOfMode()) \
</span><span class="cx">     macro(JSArrayBufferView_vector, JSArrayBufferView::offsetOfVector()) \
</span><del>-    macro(JSBigIntOrString_length, JSBigInt::offsetOfLength()) \
</del><ins>+    macro(JSBigInt_length, JSBigInt::offsetOfLength()) \
</ins><span class="cx">     macro(JSCell_cellState, JSCell::cellStateOffset()) \
</span><span class="cx">     macro(JSCell_header, 0) \
</span><span class="cx">     macro(JSCell_indexingTypeAndMisc, JSCell::indexingTypeAndMiscOffset()) \
</span><span class="lines">@@ -88,9 +88,14 @@
</span><span class="cx">     macro(JSPropertyNameEnumerator_endGenericPropertyIndex, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()) \
</span><span class="cx">     macro(JSPropertyNameEnumerator_endStructurePropertyIndex, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()) \
</span><span class="cx">     macro(JSPropertyNameEnumerator_indexLength, JSPropertyNameEnumerator::indexedLengthOffset()) \
</span><ins>+    macro(JSRopeString_flags, JSRopeString::offsetOfFlags()) \
+    macro(JSRopeString_fiber0, JSRopeString::offsetOfFiber0()) \
+    macro(JSRopeString_length, JSRopeString::offsetOfLength()) \
+    macro(JSRopeString_fiber1Lower, JSRopeString::offsetOfFiber1Lower()) \
+    macro(JSRopeString_fiber1Upper, JSRopeString::offsetOfFiber1Upper()) \
+    macro(JSRopeString_fiber2Lower, JSRopeString::offsetOfFiber2Lower()) \
+    macro(JSRopeString_fiber2Upper, JSRopeString::offsetOfFiber2Upper()) \
</ins><span class="cx">     macro(JSScope_next, JSScope::offsetOfNext()) \
</span><del>-    macro(JSString_flags, JSString::offsetOfFlags()) \
-    macro(JSString_value, JSString::offsetOfValue()) \
</del><span class="cx">     macro(JSSymbolTableObject_symbolTable, JSSymbolTableObject::offsetOfSymbolTable()) \
</span><span class="cx">     macro(JSWrapperObject_internalValue, JSWrapperObject::internalValueOffset()) \
</span><span class="cx">     macro(RegExpObject_regExp, RegExpObject::offsetOfRegExp()) \
</span><span class="lines">@@ -140,7 +145,6 @@
</span><span class="cx">     macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \
</span><span class="cx">     macro(JSLexicalEnvironment_variables, JSLexicalEnvironment::offsetOfVariables(), sizeof(EncodedJSValue)) \
</span><span class="cx">     macro(JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, 0, sizeof(WriteBarrier<JSString>)) \
</span><del>-    macro(JSRopeString_fibers, JSRopeString::offsetOfFibers(), sizeof(WriteBarrier<JSString>)) \
</del><span class="cx">     macro(ScopedArguments_Storage_storage, 0, sizeof(EncodedJSValue)) \
</span><span class="cx">     macro(WriteBarrierBuffer_bufferContents, 0, sizeof(JSCell*)) \
</span><span class="cx">     macro(characters8, 0, sizeof(LChar)) \
</span><span class="lines">@@ -180,8 +184,6 @@
</span><span class="cx">     AbstractHeap& JSCell_freeListNext;
</span><span class="cx">     AbstractHeap& ArrayStorage_publicLength;
</span><span class="cx">     AbstractHeap& ArrayStorage_vectorLength;
</span><del>-    AbstractHeap& JSBigInt_length;
-    AbstractHeap& JSString_length;
</del><span class="cx">     
</span><span class="cx"> #define INDEXED_ABSTRACT_HEAP_DECLARATION(name, offset, size) IndexedAbstractHeap name;
</span><span class="cx">     FOR_EACH_INDEXED_ABSTRACT_HEAP(INDEXED_ABSTRACT_HEAP_DECLARATION)
</span><span class="lines">@@ -191,6 +193,8 @@
</span><span class="cx">     FOR_EACH_NUMBERED_ABSTRACT_HEAP(NUMBERED_ABSTRACT_HEAP_DECLARATION)
</span><span class="cx"> #undef NUMBERED_ABSTRACT_HEAP_DECLARATION
</span><span class="cx"> 
</span><ins>+    AbstractHeap& JSString_value;
+
</ins><span class="cx">     AbsoluteAbstractHeap absolute;
</span><span class="cx">     
</span><span class="cx">     IndexedAbstractHeap* forIndexingType(IndexingType indexingType)
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -3652,8 +3652,7 @@
</span><span class="cx">             LValue fastResultValue = m_out.loadPtr(cell, m_heaps.JSString_value);
</span><span class="cx">             ValueFromBlock fastResult = m_out.anchor(fastResultValue);
</span><span class="cx">             
</span><del>-            m_out.branch(
-                m_out.notNull(fastResultValue), usually(continuation), rarely(slowPath));
</del><ins>+            m_out.branch(isRopeString(cell, m_node->child1()), rarely(slowPath), usually(continuation));
</ins><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
</span><span class="cx">             
</span><span class="lines">@@ -3825,7 +3824,23 @@
</span><span class="cx">             
</span><span class="cx">         case Array::String: {
</span><span class="cx">             LValue string = lowCell(m_node->child1());
</span><del>-            setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length));
</del><ins>+
+            LBasicBlock ropePath = m_out.newBlock();
+            LBasicBlock nonRopePath = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
+
+            m_out.branch(isRopeString(string, m_node->child1()), rarely(ropePath), usually(nonRopePath));
+
+            LBasicBlock lastNext = m_out.appendTo(ropePath, nonRopePath);
+            ValueFromBlock ropeLength = m_out.anchor(m_out.load32NonNegative(string, m_heaps.JSRopeString_length));
+            m_out.jump(continuation);
+
+            m_out.appendTo(nonRopePath, continuation);
+            ValueFromBlock nonRopeLength = m_out.anchor(m_out.load32NonNegative(m_out.loadPtr(string, m_heaps.JSString_value), m_heaps.StringImpl_length));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            setInt32(m_out.phi(Int32, ropeLength, nonRopeLength));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="lines">@@ -6487,12 +6502,22 @@
</span><span class="cx">     
</span><span class="cx">     void compileMakeRope()
</span><span class="cx">     {
</span><ins>+        struct FlagsAndLength {
+            LValue flags;
+            LValue length;
+        };
+
+        Edge edges[3] = {
+            m_node->child1(),
+            m_node->child2(),
+            m_node->child3(),
+        };
</ins><span class="cx">         LValue kids[3];
</span><span class="cx">         unsigned numKids;
</span><del>-        kids[0] = lowCell(m_node->child1());
-        kids[1] = lowCell(m_node->child2());
-        if (m_node->child3()) {
-            kids[2] = lowCell(m_node->child3());
</del><ins>+        kids[0] = lowCell(edges[0]);
+        kids[1] = lowCell(edges[1]);
+        if (edges[2]) {
+            kids[2] = lowCell(edges[2]);
</ins><span class="cx">             numKids = 3;
</span><span class="cx">         } else {
</span><span class="cx">             kids[2] = 0;
</span><span class="lines">@@ -6502,37 +6527,78 @@
</span><span class="cx">         LBasicBlock slowPath = m_out.newBlock();
</span><span class="cx">         LBasicBlock continuation = m_out.newBlock();
</span><span class="cx">         
</span><del>-        LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
-        
</del><span class="cx">         Allocator allocator = allocatorForNonVirtualConcurrently<JSRopeString>(vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists);
</span><span class="cx">         
</span><span class="cx">         LValue result = allocateCell(
</span><span class="cx">             m_out.constIntPtr(allocator.localAllocator()), vm().stringStructure.get(), slowPath);
</span><span class="cx">         
</span><del>-        m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSString_value);
-        for (unsigned i = 0; i < numKids; ++i)
-            m_out.storePtr(kids[i], result, m_heaps.JSRopeString_fibers[i]);
-        for (unsigned i = numKids; i < JSRopeString::s_maxInternalRopeLength; ++i)
-            m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSRopeString_fibers[i]);
-        LValue flags = m_out.load16ZeroExt32(kids[0], m_heaps.JSString_flags);
-        LValue length = m_out.load32(kids[0], m_heaps.JSString_length);
</del><ins>+        m_out.storePtr(m_out.bitOr(kids[0], m_out.constIntPtr(JSString::isRopeInPointer)), result, m_heaps.JSRopeString_fiber0);
+
+        m_out.store32(m_out.castToInt32(kids[1]), result, m_heaps.JSRopeString_fiber1Lower);
+        m_out.store32As16(m_out.castToInt32(m_out.lShr(kids[1], m_out.constInt32(32))), result, m_heaps.JSRopeString_fiber1Upper);
+
+        if (numKids == 3) {
+            m_out.store32(m_out.castToInt32(kids[2]), result, m_heaps.JSRopeString_fiber2Lower);
+            m_out.store32As16(m_out.castToInt32(m_out.lShr(kids[2], m_out.constInt32(32))), result, m_heaps.JSRopeString_fiber2Upper);
+        } else {
+            m_out.store32(m_out.int32Zero, result, m_heaps.JSRopeString_fiber2Lower);
+            m_out.store32As16(m_out.int32Zero, result, m_heaps.JSRopeString_fiber2Upper);
+        }
+
+        auto getFlagsAndLength = [&] (Edge& edge, LValue child) {
+            if (JSString* string = edge->dynamicCastConstant<JSString*>(vm())) {
+                return FlagsAndLength {
+                    m_out.constInt32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0),
+                    m_out.constInt32(string->length())
+                };
+            }
+
+            LBasicBlock continuation = m_out.newBlock();
+            LBasicBlock ropeCase = m_out.newBlock();
+            LBasicBlock notRopeCase = m_out.newBlock();
+
+            m_out.branch(isRopeString(child, edge), unsure(ropeCase), unsure(notRopeCase));
+
+            LBasicBlock lastNext = m_out.appendTo(ropeCase, notRopeCase);
+            ValueFromBlock flagsForRope = m_out.anchor(m_out.load16ZeroExt32(child, m_heaps.JSRopeString_flags));
+            ValueFromBlock lengthForRope = m_out.anchor(m_out.load32NonNegative(child, m_heaps.JSRopeString_length));
+            m_out.jump(continuation);
+
+            m_out.appendTo(notRopeCase, continuation);
+            LValue stringImpl = m_out.loadPtr(child, m_heaps.JSString_value);
+            ValueFromBlock flagsForNonRope = m_out.anchor(m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_hashAndFlags));
+            ValueFromBlock lengthForNonRope = m_out.anchor(m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_length));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            return FlagsAndLength {
+                m_out.phi(Int32, flagsForRope, flagsForNonRope),
+                m_out.phi(Int32, lengthForRope, lengthForNonRope)
+            };
+        };
+
+        FlagsAndLength flagsAndLength = getFlagsAndLength(edges[0], kids[0]);
</ins><span class="cx">         for (unsigned i = 1; i < numKids; ++i) {
</span><del>-            flags = m_out.bitAnd(flags, m_out.load16ZeroExt32(kids[i], m_heaps.JSString_flags));
-            CheckValue* lengthCheck = m_out.speculateAdd(
-                length, m_out.load32(kids[i], m_heaps.JSString_length));
-            blessSpeculation(lengthCheck, Uncountable, noValue(), nullptr, m_origin);
-            length = lengthCheck;
</del><ins>+            auto mergeFlagsAndLength = [&] (Edge& edge, LValue child, FlagsAndLength previousFlagsAndLength) {
+                FlagsAndLength flagsAndLength = getFlagsAndLength(edge, child);
+                LValue flags = m_out.bitAnd(previousFlagsAndLength.flags, flagsAndLength.flags);
+                CheckValue* lengthCheck = m_out.speculateAdd(previousFlagsAndLength.length, flagsAndLength.length);
+                blessSpeculation(lengthCheck, Uncountable, noValue(), nullptr, m_origin);
+                return FlagsAndLength {
+                    flags,
+                    lengthCheck
+                };
+            };
+            flagsAndLength = mergeFlagsAndLength(edges[i], kids[i], flagsAndLength);
</ins><span class="cx">         }
</span><del>-        m_out.store32As16(
-            m_out.bitAnd(m_out.constInt32(JSString::Is8Bit), flags),
-            result, m_heaps.JSString_flags);
-        m_out.store32(length, result, m_heaps.JSString_length);
</del><ins>+        m_out.store32As16(flagsAndLength.flags, result, m_heaps.JSRopeString_flags);
+        m_out.store32(flagsAndLength.length, result, m_heaps.JSRopeString_length);
</ins><span class="cx">         
</span><span class="cx">         mutatorFence();
</span><del>-        ValueFromBlock fastResult = m_out.anchor(result);
</del><ins>+        ValueFromBlock fastResult = m_out.anchor(m_out.select(m_out.isZero32(flagsAndLength.length), weakPointer(jsEmptyString(&m_graph.m_vm)), result));
</ins><span class="cx">         m_out.jump(continuation);
</span><span class="cx">         
</span><del>-        m_out.appendTo(slowPath, continuation);
</del><ins>+        LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
</ins><span class="cx">         LValue slowResultValue;
</span><span class="cx">         VM& vm = this->vm();
</span><span class="cx">         switch (numKids) {
</span><span class="lines">@@ -6573,15 +6639,14 @@
</span><span class="cx">         LBasicBlock slowPath = m_out.newBlock();
</span><span class="cx">         LBasicBlock continuation = m_out.newBlock();
</span><span class="cx">             
</span><ins>+        LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
</ins><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.aboveOrEqual(
</span><del>-                index, m_out.load32NonNegative(base, m_heaps.JSString_length)),
</del><ins>+                index, m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_length)),
</ins><span class="cx">             rarely(slowPath), usually(fastPath));
</span><span class="cx">             
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
</span><span class="cx">             
</span><del>-        LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
-            
</del><span class="cx">         LBasicBlock is8Bit = m_out.newBlock();
</span><span class="cx">         LBasicBlock is16Bit = m_out.newBlock();
</span><span class="cx">         LBasicBlock bitsContinuation = m_out.newBlock();
</span><span class="lines">@@ -6683,13 +6748,13 @@
</span><span class="cx">         LValue index = lowInt32(m_node->child2());
</span><span class="cx">         LValue storage = lowStorage(m_node->child3());
</span><span class="cx">         
</span><ins>+        LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
+
</ins><span class="cx">         speculate(
</span><span class="cx">             Uncountable, noValue(), 0,
</span><span class="cx">             m_out.aboveOrEqual(
</span><del>-                index, m_out.load32NonNegative(base, m_heaps.JSString_length)));
</del><ins>+                index, m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_length)));
</ins><span class="cx">         
</span><del>-        LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
-        
</del><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.testIsZero32(
</span><span class="cx">                 m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
</span><span class="lines">@@ -7202,7 +7267,7 @@
</span><span class="cx"> 
</span><span class="cx">             speculateString(m_node->child2(), right);
</span><span class="cx">             
</span><del>-            ValueFromBlock slowResult = m_out.anchor(stringsEqual(left, right));
</del><ins>+            ValueFromBlock slowResult = m_out.anchor(stringsEqual(left, right, m_node->child1(), m_node->child2()));
</ins><span class="cx">             m_out.jump(continuation);
</span><span class="cx"> 
</span><span class="cx">             m_out.appendTo(continuation, lastNext);
</span><span class="lines">@@ -7376,7 +7441,7 @@
</span><span class="cx"> 
</span><span class="cx">         // Full String compare.
</span><span class="cx">         m_out.appendTo(testStringEquality, continuation);
</span><del>-        ValueFromBlock slowResult = m_out.anchor(stringsEqual(leftString, rightValue));
</del><ins>+        ValueFromBlock slowResult = m_out.anchor(stringsEqual(leftString, rightValue, stringEdge, untypedEdge));
</ins><span class="cx">         m_out.jump(continuation);
</span><span class="cx"> 
</span><span class="cx">         // Continuation.
</span><span class="lines">@@ -9026,25 +9091,25 @@
</span><span class="cx">             LBasicBlock is16Bit = m_out.newBlock();
</span><span class="cx">             LBasicBlock continuation = m_out.newBlock();
</span><span class="cx">             
</span><ins>+            ValueFromBlock fastValue = m_out.anchor(m_out.loadPtr(stringValue, m_heaps.JSString_value));
</ins><span class="cx">             m_out.branch(
</span><ins>+                isRopeString(stringValue, m_node->child1()),
+                rarely(needResolution), usually(resolved));
+
+            LBasicBlock lastNext = m_out.appendTo(needResolution, resolved);
+            ValueFromBlock slowValue = m_out.anchor(
+                vmCall(pointerType(), m_out.operation(operationResolveRope), m_callFrame, stringValue));
+            m_out.jump(resolved);
+
+            m_out.appendTo(resolved, lengthIs1);
+            LValue value = m_out.phi(pointerType(), fastValue, slowValue);
+            m_out.branch(
</ins><span class="cx">                 m_out.notEqual(
</span><del>-                    m_out.load32NonNegative(stringValue, m_heaps.JSString_length),
</del><ins>+                    m_out.load32NonNegative(value, m_heaps.StringImpl_length),
</ins><span class="cx">                     m_out.int32One),
</span><span class="cx">                 unsure(lowBlock(data->fallThrough.block)), unsure(lengthIs1));
</span><del>-            
-            LBasicBlock lastNext = m_out.appendTo(lengthIs1, needResolution);
-            Vector<ValueFromBlock, 2> values;
-            LValue fastValue = m_out.loadPtr(stringValue, m_heaps.JSString_value);
-            values.append(m_out.anchor(fastValue));
-            m_out.branch(m_out.isNull(fastValue), rarely(needResolution), usually(resolved));
-            
-            m_out.appendTo(needResolution, resolved);
-            values.append(m_out.anchor(
-                vmCall(pointerType(), m_out.operation(operationResolveRope), m_callFrame, stringValue)));
-            m_out.jump(resolved);
-            
-            m_out.appendTo(resolved, is8Bit);
-            LValue value = m_out.phi(pointerType(), values);
</del><ins>+
+            m_out.appendTo(lengthIs1, is8Bit);
</ins><span class="cx">             LValue characterData = m_out.loadPtr(value, m_heaps.StringImpl_data);
</span><span class="cx">             m_out.branch(
</span><span class="cx">                 m_out.testNonZero32(
</span><span class="lines">@@ -9086,7 +9151,7 @@
</span><span class="cx">             }
</span><span class="cx">                 
</span><span class="cx">             case StringUse: {
</span><del>-                switchString(data, lowString(m_node->child1()));
</del><ins>+                switchString(data, lowString(m_node->child1()), m_node->child1());
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">                 
</span><span class="lines">@@ -9108,7 +9173,7 @@
</span><span class="cx">                 
</span><span class="cx">                 m_out.appendTo(isStringBlock, lastNext);
</span><span class="cx">                 
</span><del>-                switchString(data, value);
</del><ins>+                switchString(data, value, m_node->child1());
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">                 
</span><span class="lines">@@ -9446,17 +9511,16 @@
</span><span class="cx">         return key;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue mapHashString(LValue string)
</del><ins>+    LValue mapHashString(LValue string, Edge& edge)
</ins><span class="cx">     {
</span><span class="cx">         LBasicBlock nonEmptyStringCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock slowCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock continuation = m_out.newBlock();
</span><span class="cx"> 
</span><del>-        LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
-        m_out.branch(
-            m_out.equal(stringImpl, m_out.constIntPtr(0)), unsure(slowCase), unsure(nonEmptyStringCase));
</del><ins>+        m_out.branch(isRopeString(string, edge), rarely(slowCase), usually(nonEmptyStringCase));
</ins><span class="cx"> 
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(nonEmptyStringCase, slowCase);
</span><ins>+        LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
</ins><span class="cx">         LValue hash = m_out.lShr(m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount));
</span><span class="cx">         ValueFromBlock nonEmptyStringHashResult = m_out.anchor(hash);
</span><span class="cx">         m_out.branch(m_out.equal(hash, m_out.constInt32(0)),
</span><span class="lines">@@ -9495,7 +9559,7 @@
</span><span class="cx">                 isStringValue, unsure(isString), unsure(notString));
</span><span class="cx"> 
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(isString, notString);
</span><del>-            ValueFromBlock stringResult = m_out.anchor(mapHashString(value));
</del><ins>+            ValueFromBlock stringResult = m_out.anchor(mapHashString(value, m_node->child1()));
</ins><span class="cx">             m_out.jump(continuation);
</span><span class="cx"> 
</span><span class="cx">             m_out.appendTo(notString, continuation);
</span><span class="lines">@@ -9509,7 +9573,7 @@
</span><span class="cx"> 
</span><span class="cx">         case StringUse: {
</span><span class="cx">             LValue string = lowString(m_node->child1());
</span><del>-            setInt32(mapHashString(string));
</del><ins>+            setInt32(mapHashString(string, m_node->child1()));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -9536,11 +9600,10 @@
</span><span class="cx">             isString, unsure(isStringCase), unsure(straightHash));
</span><span class="cx"> 
</span><span class="cx">         m_out.appendTo(isStringCase, nonEmptyStringCase);
</span><del>-        LValue stringImpl = m_out.loadPtr(value, m_heaps.JSString_value);
-        m_out.branch(
-            m_out.equal(stringImpl, m_out.constIntPtr(0)), rarely(slowCase), usually(nonEmptyStringCase));
</del><ins>+        m_out.branch(isRopeString(value, m_node->child1()), rarely(slowCase), usually(nonEmptyStringCase));
</ins><span class="cx"> 
</span><span class="cx">         m_out.appendTo(nonEmptyStringCase, straightHash);
</span><ins>+        LValue stringImpl = m_out.loadPtr(value, m_heaps.JSString_value);
</ins><span class="cx">         LValue hash = m_out.lShr(m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount));
</span><span class="cx">         ValueFromBlock nonEmptyStringHashResult = m_out.anchor(hash);
</span><span class="cx">         m_out.branch(m_out.equal(hash, m_out.constInt32(0)),
</span><span class="lines">@@ -10138,10 +10201,10 @@
</span><span class="cx">             LBasicBlock isAtomicString = m_out.newBlock();
</span><span class="cx"> 
</span><span class="cx">             keyAsValue = lowString(m_node->child2());
</span><del>-            uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
-            m_out.branch(m_out.notNull(uniquedStringImpl), usually(isNonEmptyString), rarely(slowCase));
</del><ins>+            m_out.branch(isNotRopeString(keyAsValue, m_node->child2()), usually(isNonEmptyString), rarely(slowCase));
</ins><span class="cx"> 
</span><span class="cx">             lastNext = m_out.appendTo(isNonEmptyString, isAtomicString);
</span><ins>+            uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
</ins><span class="cx">             LValue isNotAtomic = m_out.testIsZero32(m_out.load32(uniquedStringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic()));
</span><span class="cx">             m_out.branch(isNotAtomic, rarely(slowCase), usually(isAtomicString));
</span><span class="cx"> 
</span><span class="lines">@@ -10169,11 +10232,11 @@
</span><span class="cx">             m_out.branch(isString(keyAsValue), unsure(isStringCase), unsure(notStringCase));
</span><span class="cx"> 
</span><span class="cx">             m_out.appendTo(isStringCase, isNonEmptyString);
</span><ins>+            m_out.branch(isNotRopeString(keyAsValue, m_node->child2()), usually(isNonEmptyString), rarely(slowCase));
+
+            m_out.appendTo(isNonEmptyString, notStringCase);
</ins><span class="cx">             LValue implFromString = m_out.loadPtr(keyAsValue, m_heaps.JSString_value);
</span><span class="cx">             ValueFromBlock stringResult = m_out.anchor(implFromString);
</span><del>-            m_out.branch(m_out.notNull(implFromString), usually(isNonEmptyString), rarely(slowCase));
-
-            m_out.appendTo(isNonEmptyString, notStringCase);
</del><span class="cx">             LValue isNotAtomic = m_out.testIsZero32(m_out.load32(implFromString, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic()));
</span><span class="cx">             m_out.branch(isNotAtomic, rarely(slowCase), usually(hasUniquedStringImpl));
</span><span class="cx"> 
</span><span class="lines">@@ -11911,34 +11974,39 @@
</span><span class="cx"> 
</span><span class="cx">     void compileStringSlice()
</span><span class="cx">     {
</span><ins>+        LBasicBlock lengthCheckCase = m_out.newBlock();
</ins><span class="cx">         LBasicBlock emptyCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock notEmptyCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock oneCharCase = m_out.newBlock();
</span><del>-        LBasicBlock bitCheckCase = m_out.newBlock();
</del><span class="cx">         LBasicBlock is8Bit = m_out.newBlock();
</span><span class="cx">         LBasicBlock is16Bit = m_out.newBlock();
</span><span class="cx">         LBasicBlock bitsContinuation = m_out.newBlock();
</span><span class="cx">         LBasicBlock bigCharacter = m_out.newBlock();
</span><span class="cx">         LBasicBlock slowCase = m_out.newBlock();
</span><ins>+        LBasicBlock ropeSlowCase = m_out.newBlock();
</ins><span class="cx">         LBasicBlock continuation = m_out.newBlock();
</span><span class="cx"> 
</span><span class="cx">         LValue string = lowString(m_node->child1());
</span><del>-        LValue length = m_out.load32NonNegative(string, m_heaps.JSString_length);
</del><span class="cx">         LValue start = lowInt32(m_node->child2());
</span><span class="cx">         LValue end = nullptr;
</span><span class="cx">         if (m_node->child3())
</span><span class="cx">             end = lowInt32(m_node->child3());
</span><ins>+        else
+            end = m_out.constInt32(std::numeric_limits<int32_t>::max());
+        m_out.branch(isRopeString(string, m_node->child1()), rarely(ropeSlowCase), usually(lengthCheckCase));
</ins><span class="cx"> 
</span><ins>+        LBasicBlock lastNext = m_out.appendTo(lengthCheckCase, emptyCase);
+        LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
+        LValue length = m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_length);
</ins><span class="cx">         auto range = populateSliceRange(start, end, length);
</span><span class="cx">         LValue from = range.first;
</span><span class="cx">         LValue to = range.second;
</span><del>-
</del><span class="cx">         LValue span = m_out.sub(to, from);
</span><span class="cx">         m_out.branch(m_out.lessThanOrEqual(span, m_out.int32Zero), unsure(emptyCase), unsure(notEmptyCase));
</span><span class="cx"> 
</span><del>-        Vector<ValueFromBlock, 4> results;
</del><ins>+        Vector<ValueFromBlock, 5> results;
</ins><span class="cx"> 
</span><del>-        LBasicBlock lastNext = m_out.appendTo(emptyCase, notEmptyCase);
</del><ins>+        m_out.appendTo(emptyCase, notEmptyCase);
</ins><span class="cx">         results.append(m_out.anchor(weakPointer(jsEmptyString(&vm()))));
</span><span class="cx">         m_out.jump(continuation);
</span><span class="cx"> 
</span><span class="lines">@@ -11945,11 +12013,7 @@
</span><span class="cx">         m_out.appendTo(notEmptyCase, oneCharCase);
</span><span class="cx">         m_out.branch(m_out.equal(span, m_out.int32One), unsure(oneCharCase), unsure(slowCase));
</span><span class="cx"> 
</span><del>-        m_out.appendTo(oneCharCase, bitCheckCase);
-        LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
-        m_out.branch(m_out.isNull(stringImpl), unsure(slowCase), unsure(bitCheckCase));
-
-        m_out.appendTo(bitCheckCase, is8Bit);
</del><ins>+        m_out.appendTo(oneCharCase, is8Bit);
</ins><span class="cx">         LValue storage = m_out.loadPtr(stringImpl, m_heaps.StringImpl_data);
</span><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.testIsZero32(
</span><span class="lines">@@ -11958,8 +12022,6 @@
</span><span class="cx">             unsure(is16Bit), unsure(is8Bit));
</span><span class="cx"> 
</span><span class="cx">         m_out.appendTo(is8Bit, is16Bit);
</span><del>-        // FIXME: Need to cage strings!
-        // https://bugs.webkit.org/show_bug.cgi?id=174924
</del><span class="cx">         ValueFromBlock char8Bit = m_out.anchor(m_out.load8ZeroExt32(m_out.baseIndex(m_heaps.characters8, storage, m_out.zeroExtPtr(from))));
</span><span class="cx">         m_out.jump(bitsContinuation);
</span><span class="cx"> 
</span><span class="lines">@@ -11983,10 +12045,14 @@
</span><span class="cx">             m_heaps.singleCharacterStrings, smallStrings, m_out.zeroExtPtr(character)))));
</span><span class="cx">         m_out.jump(continuation);
</span><span class="cx"> 
</span><del>-        m_out.appendTo(slowCase, continuation);
</del><ins>+        m_out.appendTo(slowCase, ropeSlowCase);
</ins><span class="cx">         results.append(m_out.anchor(vmCall(pointerType(), m_out.operation(operationStringSubstr), m_callFrame, string, from, span)));
</span><span class="cx">         m_out.jump(continuation);
</span><span class="cx"> 
</span><ins>+        m_out.appendTo(ropeSlowCase, continuation);
+        results.append(m_out.anchor(vmCall(pointerType(), m_out.operation(operationStringSlice), m_callFrame, string, start, end)));
+        m_out.jump(continuation);
+
</ins><span class="cx">         m_out.appendTo(continuation, lastNext);
</span><span class="cx">         setJSValue(m_out.phi(pointerType(), results));
</span><span class="cx">     }
</span><span class="lines">@@ -12003,12 +12069,11 @@
</span><span class="cx">         LValue string = lowString(m_node->child1());
</span><span class="cx">         ValueFromBlock startIndex = m_out.anchor(m_out.constInt32(0));
</span><span class="cx">         ValueFromBlock startIndexForCall = m_out.anchor(m_out.constInt32(0));
</span><del>-        LValue impl = m_out.loadPtr(string, m_heaps.JSString_value);
-        m_out.branch(m_out.isZero64(impl),
</del><ins>+        m_out.branch(isRopeString(string, m_node->child1()),
</ins><span class="cx">             unsure(slowPath), unsure(notRope));
</span><span class="cx"> 
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(notRope, is8Bit);
</span><del>-
</del><ins>+        LValue impl = m_out.loadPtr(string, m_heaps.JSString_value);
</ins><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.testIsZero32(
</span><span class="cx">                 m_out.load32(impl, m_heaps.StringImpl_hashAndFlags),
</span><span class="lines">@@ -12779,7 +12844,7 @@
</span><span class="cx">         setBoolean(m_out.phi(Int32, fastResult, slowResult));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue stringsEqual(LValue leftJSString, LValue rightJSString)
</del><ins>+    LValue stringsEqual(LValue leftJSString, LValue rightJSString, Edge leftJSStringEdge = Edge(), Edge rightJSStringEdge = Edge())
</ins><span class="cx">     {
</span><span class="cx">         LBasicBlock notTriviallyUnequalCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock notEmptyCase = m_out.newBlock();
</span><span class="lines">@@ -12794,29 +12859,23 @@
</span><span class="cx">         LBasicBlock slowCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock continuation = m_out.newBlock();
</span><span class="cx"> 
</span><del>-        LValue length = m_out.load32(leftJSString, m_heaps.JSString_length);
</del><ins>+        m_out.branch(isRopeString(leftJSString, leftJSStringEdge), rarely(slowCase), usually(leftReadyCase));
</ins><span class="cx"> 
</span><ins>+        LBasicBlock lastNext = m_out.appendTo(leftReadyCase, rightReadyCase);
+        m_out.branch(isRopeString(rightJSString, rightJSStringEdge), rarely(slowCase), usually(rightReadyCase));
+
+        m_out.appendTo(rightReadyCase, notTriviallyUnequalCase);
+        LValue left = m_out.loadPtr(leftJSString, m_heaps.JSString_value);
+        LValue right = m_out.loadPtr(rightJSString, m_heaps.JSString_value);
+        LValue length = m_out.load32(left, m_heaps.StringImpl_length);
</ins><span class="cx">         m_out.branch(
</span><del>-            m_out.notEqual(length, m_out.load32(rightJSString, m_heaps.JSString_length)),
</del><ins>+            m_out.notEqual(length, m_out.load32(right, m_heaps.StringImpl_length)),
</ins><span class="cx">             unsure(falseCase), unsure(notTriviallyUnequalCase));
</span><span class="cx"> 
</span><del>-        LBasicBlock lastNext = m_out.appendTo(notTriviallyUnequalCase, notEmptyCase);
-
</del><ins>+        m_out.appendTo(notTriviallyUnequalCase, notEmptyCase);
</ins><span class="cx">         m_out.branch(m_out.isZero32(length), unsure(trueCase), unsure(notEmptyCase));
</span><span class="cx"> 
</span><del>-        m_out.appendTo(notEmptyCase, leftReadyCase);
-
-        LValue left = m_out.loadPtr(leftJSString, m_heaps.JSString_value);
-        LValue right = m_out.loadPtr(rightJSString, m_heaps.JSString_value);
-
-        m_out.branch(m_out.notNull(left), usually(leftReadyCase), rarely(slowCase));
-
-        m_out.appendTo(leftReadyCase, rightReadyCase);
-        
-        m_out.branch(m_out.notNull(right), usually(rightReadyCase), rarely(slowCase));
-
-        m_out.appendTo(rightReadyCase, left8BitCase);
-
</del><ins>+        m_out.appendTo(notEmptyCase, left8BitCase);
</ins><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.testIsZero32(
</span><span class="cx">                 m_out.load32(left, m_heaps.StringImpl_hashAndFlags),
</span><span class="lines">@@ -12824,7 +12883,6 @@
</span><span class="cx">             unsure(slowCase), unsure(left8BitCase));
</span><span class="cx"> 
</span><span class="cx">         m_out.appendTo(left8BitCase, right8BitCase);
</span><del>-
</del><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.testIsZero32(
</span><span class="cx">                 m_out.load32(right, m_heaps.StringImpl_hashAndFlags),
</span><span class="lines">@@ -13546,11 +13604,8 @@
</span><span class="cx">                 equalNullOrUndefined(
</span><span class="cx">                     edge, CellCaseSpeculatesObject, SpeculateNullOrUndefined,
</span><span class="cx">                     ManualOperandSpeculation));
</span><del>-        case StringUse: {
-            LValue stringValue = lowString(edge);
-            LValue length = m_out.load32NonNegative(stringValue, m_heaps.JSString_length);
-            return m_out.notEqual(length, m_out.int32Zero);
-        }
</del><ins>+        case StringUse:
+            return m_out.notEqual(lowString(edge), weakPointer(jsEmptyString(&m_graph.m_vm)));
</ins><span class="cx">         case StringOrOtherUse: {
</span><span class="cx">             LValue value = lowJSValue(edge, ManualOperandSpeculation);
</span><span class="cx"> 
</span><span class="lines">@@ -13561,20 +13616,17 @@
</span><span class="cx">             m_out.branch(isCell(value, provenType(edge)), unsure(cellCase), unsure(notCellCase));
</span><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
</span><del>-            
</del><span class="cx">             FTL_TYPE_CHECK(jsValueValue(value), edge, (~SpecCellCheck) | SpecString, isNotString(value));
</span><del>-            LValue length = m_out.load32NonNegative(value, m_heaps.JSString_length);
-            ValueFromBlock cellResult = m_out.anchor(m_out.notEqual(length, m_out.int32Zero));
</del><ins>+            ValueFromBlock stringResult = m_out.anchor(m_out.notEqual(value, weakPointer(jsEmptyString(&m_graph.m_vm))));
</ins><span class="cx">             m_out.jump(continuation);
</span><del>-            
</del><ins>+
</ins><span class="cx">             m_out.appendTo(notCellCase, continuation);
</span><del>-            
</del><span class="cx">             FTL_TYPE_CHECK(jsValueValue(value), edge, SpecCellCheck | SpecOther, isNotOther(value));
</span><span class="cx">             ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
</span><span class="cx">             m_out.jump(continuation);
</span><ins>+
</ins><span class="cx">             m_out.appendTo(continuation, lastNext);
</span><del>-
-            return m_out.phi(Int32, cellResult, notCellResult);
</del><ins>+            return m_out.phi(Int32, stringResult, notCellResult);
</ins><span class="cx">         }
</span><span class="cx">         case UntypedUse: {
</span><span class="cx">             LValue value = lowJSValue(edge);
</span><span class="lines">@@ -13597,7 +13649,8 @@
</span><span class="cx">             
</span><span class="cx">             LBasicBlock cellCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock notStringCase = m_out.newBlock();
</span><del>-            LBasicBlock stringOrBigIntCase = m_out.newBlock();
</del><ins>+            LBasicBlock stringCase = m_out.newBlock();
+            LBasicBlock bigIntCase = m_out.newBlock();
</ins><span class="cx">             LBasicBlock notStringOrBigIntCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock notCellCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock int32Case = m_out.newBlock();
</span><span class="lines">@@ -13613,18 +13666,22 @@
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(cellCase, notStringCase);
</span><span class="cx">             m_out.branch(
</span><span class="cx">                 isString(value, provenType(edge) & SpecCell),
</span><del>-                unsure(stringOrBigIntCase), unsure(notStringCase));
</del><ins>+                unsure(stringCase), unsure(notStringCase));
</ins><span class="cx">             
</span><del>-            m_out.appendTo(notStringCase, stringOrBigIntCase);
</del><ins>+            m_out.appendTo(notStringCase, stringCase);
</ins><span class="cx">             m_out.branch(
</span><span class="cx">                 isBigInt(value, provenType(edge) & (SpecCell - SpecString)),
</span><del>-                unsure(stringOrBigIntCase), unsure(notStringOrBigIntCase));
</del><ins>+                unsure(bigIntCase), unsure(notStringOrBigIntCase));
</ins><span class="cx"> 
</span><del>-            m_out.appendTo(stringOrBigIntCase, notStringOrBigIntCase);
-            LValue nonZeroCell = m_out.notZero32(
-                m_out.load32NonNegative(value, m_heaps.JSBigIntOrString_length));
-            results.append(m_out.anchor(nonZeroCell));
</del><ins>+            m_out.appendTo(stringCase, bigIntCase);
+            results.append(m_out.anchor(m_out.notEqual(value, weakPointer(jsEmptyString(&m_graph.m_vm)))));
</ins><span class="cx">             m_out.jump(continuation);
</span><ins>+
+            m_out.appendTo(bigIntCase, notStringOrBigIntCase);
+            LValue nonZeroBigInt = m_out.notZero32(
+                m_out.load32NonNegative(value, m_heaps.JSBigInt_length));
+            results.append(m_out.anchor(nonZeroBigInt));
+            m_out.jump(continuation);
</ins><span class="cx">             
</span><span class="cx">             m_out.appendTo(notStringOrBigIntCase, notCellCase);
</span><span class="cx">             LValue isTruthyObject;
</span><span class="lines">@@ -13887,7 +13944,7 @@
</span><span class="cx">             lowBlock(data->fallThrough.block), Weight(data->fallThrough.count));
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void switchString(SwitchData* data, LValue string)
</del><ins>+    void switchString(SwitchData* data, LValue string, Edge& edge)
</ins><span class="cx">     {
</span><span class="cx">         bool canDoBinarySwitch = true;
</span><span class="cx">         unsigned totalLength = 0;
</span><span class="lines">@@ -13910,16 +13967,16 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
-        LValue length = m_out.load32(string, m_heaps.JSString_length);
-        
</del><span class="cx">         LBasicBlock hasImplBlock = m_out.newBlock();
</span><span class="cx">         LBasicBlock is8BitBlock = m_out.newBlock();
</span><span class="cx">         LBasicBlock slowBlock = m_out.newBlock();
</span><span class="cx">         
</span><del>-        m_out.branch(m_out.isNull(stringImpl), unsure(slowBlock), unsure(hasImplBlock));
</del><ins>+        m_out.branch(isRopeString(string, edge), unsure(slowBlock), unsure(hasImplBlock));
</ins><span class="cx">         
</span><span class="cx">         LBasicBlock lastNext = m_out.appendTo(hasImplBlock, is8BitBlock);
</span><ins>+
+        LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
+        LValue length = m_out.load32(stringImpl, m_heaps.StringImpl_length);
</ins><span class="cx">         
</span><span class="cx">         m_out.branch(
</span><span class="cx">             m_out.testIsZero32(
</span><span class="lines">@@ -15614,6 +15671,34 @@
</span><span class="cx">             m_out.constInt32(vm().stringStructure->id()));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    LValue isRopeString(LValue string, Edge edge = Edge())
+    {
+        if (edge) {
+            if (!((provenType(edge) & SpecString) & ~SpecStringIdent))
+                return m_out.booleanFalse;
+            if (JSValue value = provenValue(edge)) {
+                if (value.isCell() && value.asCell()->type() == StringType && !asString(value)->isRope())
+                    return m_out.booleanFalse;
+            }
+        }
+
+        return m_out.testNonZeroPtr(m_out.loadPtr(string, m_heaps.JSString_value), m_out.constIntPtr(JSString::isRopeInPointer));
+    }
+
+    LValue isNotRopeString(LValue string, Edge edge = Edge())
+    {
+        if (edge) {
+            if (!((provenType(edge) & SpecString) & ~SpecStringIdent))
+                return m_out.booleanTrue;
+            if (JSValue value = provenValue(edge)) {
+                if (value.isCell() && value.asCell()->type() == StringType && !asString(value)->isRope())
+                    return m_out.booleanTrue;
+            }
+        }
+
+        return m_out.testIsZeroPtr(m_out.loadPtr(string, m_heaps.JSString_value), m_out.constIntPtr(JSString::isRopeInPointer));
+    }
+
</ins><span class="cx">     LValue isNotSymbol(LValue cell, SpeculatedType type = SpecFullTop)
</span><span class="cx">     {
</span><span class="cx">         if (LValue proven = isProvenValue(type & SpecCell, ~SpecSymbol))
</span><span class="lines">@@ -16011,7 +16096,7 @@
</span><span class="cx">         if (!m_interpreter.needsTypeCheck(edge, SpecStringIdent | ~SpecString))
</span><span class="cx">             return;
</span><span class="cx">         
</span><del>-        speculate(BadType, jsValueValue(string), edge.node(), m_out.isNull(stringImpl));
</del><ins>+        speculate(BadType, jsValueValue(string), edge.node(), isRopeString(string));
</ins><span class="cx">         speculate(
</span><span class="cx">             BadType, jsValueValue(string), edge.node(),
</span><span class="cx">             m_out.testIsZero32(
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorejitAssemblyHelperscpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/AssemblyHelpers.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/AssemblyHelpers.cpp     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -727,8 +727,11 @@
</span><span class="cx">     done.append(jump());
</span><span class="cx"> 
</span><span class="cx">     isString.link(this);
</span><ins>+    move(TrustedImmPtr(jsEmptyString(&vm)), result);
+    comparePtr(invert ? Equal : NotEqual, value.payloadGPR(), result, result);
+    done.append(jump());
+
</ins><span class="cx">     isBigInt.link(this);
</span><del>-    RELEASE_ASSERT(JSString::offsetOfLength() == JSBigInt::offsetOfLength());
</del><span class="cx">     load32(Address(value.payloadGPR(), JSBigInt::offsetOfLength()), result);
</span><span class="cx">     compare32(invert ? Equal : NotEqual, result, TrustedImm32(0), result);
</span><span class="cx">     done.append(jump());
</span><span class="lines">@@ -814,8 +817,10 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     isString.link(this);
</span><ins>+    truthy.append(branchPtr(invert ? Equal : NotEqual, value.payloadGPR(), TrustedImmPtr(jsEmptyString(&vm))));
+    done.append(jump());
+
</ins><span class="cx">     isBigInt.link(this);
</span><del>-    RELEASE_ASSERT(JSString::offsetOfLength() == JSBigInt::offsetOfLength());
</del><span class="cx">     truthy.append(branchTest32(invert ? Zero : NonZero, Address(value.payloadGPR(), JSBigInt::offsetOfLength())));
</span><span class="cx">     done.append(jump());
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorejitAssemblyHelpersh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/AssemblyHelpers.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/AssemblyHelpers.h       2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/AssemblyHelpers.h  2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1075,6 +1075,16 @@
</span><span class="cx">         return branchDouble(DoubleEqual, fpr, fpr);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Jump branchIfRopeStringImpl(GPRReg stringImplGPR)
+    {
+        return branchTestPtr(NonZero, stringImplGPR, TrustedImm32(JSString::isRopeInPointer));
+    }
+
+    Jump branchIfNotRopeStringImpl(GPRReg stringImplGPR)
+    {
+        return branchTestPtr(Zero, stringImplGPR, TrustedImm32(JSString::isRopeInPointer));
+    }
+
</ins><span class="cx">     static Address addressForByteOffset(ptrdiff_t byteOffset)
</span><span class="cx">     {
</span><span class="cx">         return Address(GPRInfo::callFrameRegister, byteOffset);
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorejitJITInlinesh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/JITInlines.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/JITInlines.h    2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/JITInlines.h       2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -94,9 +94,9 @@
</span><span class="cx"> ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures)
</span><span class="cx"> {
</span><span class="cx">     failures.append(branchIfNotString(src));
</span><del>-    failures.append(branch32(NotEqual, MacroAssembler::Address(src, JSString::offsetOfLength()), TrustedImm32(1)));
</del><span class="cx">     loadPtr(MacroAssembler::Address(src, JSString::offsetOfValue()), dst);
</span><del>-    failures.append(branchTest32(Zero, dst));
</del><ins>+    failures.append(branchIfRopeStringImpl(dst));
+    failures.append(branch32(NotEqual, MacroAssembler::Address(dst, StringImpl::lengthMemoryOffset()), TrustedImm32(1)));
</ins><span class="cx">     loadPtr(MacroAssembler::Address(dst, StringImpl::flagsOffset()), regT1);
</span><span class="cx">     loadPtr(MacroAssembler::Address(dst, StringImpl::dataOffset()), dst);
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/Repatch.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/Repatch.cpp     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/Repatch.cpp        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -210,7 +210,7 @@
</span><span class="cx"> 
</span><span class="cx">                 newCase = AccessCase::create(vm, codeBlock, AccessCase::ArrayLength);
</span><span class="cx">             } else if (isJSString(baseCell)) {
</span><del>-                if (stubInfo.cacheType == CacheType::Unset) {
</del><ins>+                if (stubInfo.cacheType == CacheType::Unset && InlineAccess::isCacheableStringLength(stubInfo)) {
</ins><span class="cx">                     bool generatedCodeInline = InlineAccess::generateStringLength(stubInfo);
</span><span class="cx">                     if (generatedCodeInline) {
</span><span class="cx">                         ftlThunkAwareRepatchCall(codeBlock, stubInfo.slowPathCallLocation(), appropriateOptimizingGetByIdFunction(kind));
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorejitThunkGeneratorscpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/ThunkGenerators.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/ThunkGenerators.cpp     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -622,9 +622,9 @@
</span><span class="cx">     jit.tagReturnAddress();
</span><span class="cx"> 
</span><span class="cx">     // Load string length to regT2, and start the process of loading the data pointer into regT0
</span><del>-    jit.load32(JSInterfaceJIT::Address(stringGPR, JSString::offsetOfLength()), scratchGPR);
</del><span class="cx">     jit.loadPtr(JSInterfaceJIT::Address(stringGPR, JSString::offsetOfValue()), stringGPR);
</span><del>-    failures.append(jit.branchTestPtr(JSInterfaceJIT::Zero, stringGPR));
</del><ins>+    failures.append(jit.branchIfRopeStringImpl(stringGPR));
+    jit.load32(JSInterfaceJIT::Address(stringGPR, StringImpl::lengthMemoryOffset()), scratchGPR);
</ins><span class="cx"> 
</span><span class="cx">     // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large
</span><span class="cx">     failures.append(jit.branch32(JSInterfaceJIT::AboveOrEqual, indexGPR, scratchGPR));
</span><span class="lines">@@ -661,9 +661,9 @@
</span><span class="cx">     jit.loadJSStringArgument(SpecializedThunkJIT::ThisArgument, SpecializedThunkJIT::regT0);
</span><span class="cx"> 
</span><span class="cx">     // Load string length to regT2, and start the process of loading the data pointer into regT0
</span><del>-    jit.load32(MacroAssembler::Address(SpecializedThunkJIT::regT0, JSString::offsetOfLength()), SpecializedThunkJIT::regT2);
</del><span class="cx">     jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, JSString::offsetOfValue()), SpecializedThunkJIT::regT0);
</span><del>-    jit.appendFailure(jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0));
</del><ins>+    jit.appendFailure(jit.branchIfRopeStringImpl(SpecializedThunkJIT::regT0));
+    jit.load32(MacroAssembler::Address(SpecializedThunkJIT::regT0, StringImpl::lengthMemoryOffset()), SpecializedThunkJIT::regT2);
</ins><span class="cx"> 
</span><span class="cx">     // load index
</span><span class="cx">     jit.loadInt32Argument(0, SpecializedThunkJIT::regT1); // regT1 contains the index
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter.asm       2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter.asm  2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -482,6 +482,7 @@
</span><span class="cx"> const LLIntReturnPC = ArgumentCount + TagOffset
</span><span class="cx"> 
</span><span class="cx"> # String flags.
</span><ins>+const isRopeInPointer = constexpr JSString::isRopeInPointer
</ins><span class="cx"> const HashFlags8BitBuffer = constexpr StringImpl::s_hashFlag8BitBuffer
</span><span class="cx"> 
</span><span class="cx"> # Copied from PropertyOffset.h
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm  2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm     2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1788,9 +1788,9 @@
</span><span class="cx">     addp t3, t2
</span><span class="cx">     bineq t1, CellTag, .opSwitchCharFallThrough
</span><span class="cx">     bbneq JSCell::m_type[t0], StringType, .opSwitchCharFallThrough
</span><del>-    bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough
-    loadp JSString::m_value[t0], t0
-    btpz  t0, .opSwitchOnRope
</del><ins>+    loadp JSString::m_fiber[t0], t0
+    btpnz t0, isRopeInPointer, .opSwitchOnRope
+    bineq StringImpl::m_length[t0], 1, .opSwitchCharFallThrough
</ins><span class="cx">     loadp StringImpl::m_data8[t0], t1
</span><span class="cx">     btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
</span><span class="cx">     loadh [t1], t0
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm     2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1877,9 +1877,9 @@
</span><span class="cx">     addp t3, t2
</span><span class="cx">     btqnz t1, tagMask, .opSwitchCharFallThrough
</span><span class="cx">     bbneq JSCell::m_type[t1], StringType, .opSwitchCharFallThrough
</span><del>-    bineq JSString::m_length[t1], 1, .opSwitchCharFallThrough
-    loadp JSString::m_value[t1], t0
-    btpz  t0, .opSwitchOnRope
</del><ins>+    loadp JSString::m_fiber[t1], t0
+    btpnz t0, isRopeInPointer, .opSwitchOnRope
+    bineq StringImpl::m_length[t0], 1, .opSwitchCharFallThrough
</ins><span class="cx">     loadp StringImpl::m_data8[t0], t1
</span><span class="cx">     btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
</span><span class="cx">     loadh [t1], t0
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeJSStringcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSString.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSString.cpp        2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSString.cpp   2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -40,15 +40,28 @@
</span><span class="cx">     return Structure::create(vm, globalObject, proto, TypeInfo(StringType, StructureFlags), info());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+JSString* JSString::createEmptyString(VM& vm)
+{
+    JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, *StringImpl::empty());
+    newString->finishCreation(vm);
+    return newString;
+}
+
</ins><span class="cx"> template<>
</span><span class="cx"> void JSRopeString::RopeBuilder<RecordOverflow>::expand()
</span><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(!this->hasOverflowed());
</span><del>-    ASSERT(m_index == JSRopeString::s_maxInternalRopeLength);
-    JSString* jsString = m_jsString;
-    m_jsString = jsStringBuilder(&m_vm);
-    m_index = 0;
-    append(jsString);
</del><ins>+    ASSERT(m_strings.size() == JSRopeString::s_maxInternalRopeLength);
+    static_assert(3 == JSRopeString::s_maxInternalRopeLength, "");
+    ASSERT(m_length);
+    ASSERT(asString(m_strings.at(0))->length());
+    ASSERT(asString(m_strings.at(1))->length());
+    ASSERT(asString(m_strings.at(2))->length());
+
+    JSString* string = JSRopeString::create(m_vm, asString(m_strings.at(0)), asString(m_strings.at(1)), asString(m_strings.at(2)));
+    ASSERT(string->length() == m_length);
+    m_strings.clear();
+    m_strings.append(string);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JSString::destroy(JSCell* cell)
</span><span class="lines">@@ -61,14 +74,16 @@
</span><span class="cx">     VM& vm = *cell->vm();
</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><del>-    if (thisObject->isRope())
</del><ins>+    uintptr_t pointer = thisObject->m_fiber;
+    if (pointer & isRopeInPointer)
</ins><span class="cx">         out.printf("[rope]");
</span><span class="cx">     else {
</span><del>-        WTF::StringImpl* ourImpl = thisObject->m_value.impl();
-        if (ourImpl->is8Bit())
-            out.printf("[8 %p]", ourImpl->characters8());
-        else
-            out.printf("[16 %p]", ourImpl->characters16());
</del><ins>+        if (WTF::StringImpl* ourImpl = bitwise_cast<StringImpl*>(pointer)) {
+            if (ourImpl->is8Bit())
+                out.printf("[8 %p]", ourImpl->characters8());
+            else
+                out.printf("[16 %p]", ourImpl->characters16());
+        }
</ins><span class="cx">     }
</span><span class="cx">     out.printf(">");
</span><span class="cx"> }
</span><span class="lines">@@ -86,9 +101,10 @@
</span><span class="cx"> size_t JSString::estimatedSize(JSCell* cell, VM& vm)
</span><span class="cx"> {
</span><span class="cx">     JSString* thisObject = asString(cell);
</span><del>-    if (thisObject->isRope())
</del><ins>+    uintptr_t pointer = thisObject->m_fiber;
+    if (pointer & isRopeInPointer)
</ins><span class="cx">         return Base::estimatedSize(cell, vm);
</span><del>-    return Base::estimatedSize(cell, vm) + thisObject->m_value.impl()->costDuringGC();
</del><ins>+    return Base::estimatedSize(cell, vm) + bitwise_cast<StringImpl*>(pointer)->costDuringGC();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor)
</span><span class="lines">@@ -96,20 +112,36 @@
</span><span class="cx">     JSString* thisObject = asString(cell);
</span><span class="cx">     Base::visitChildren(thisObject, visitor);
</span><span class="cx">     
</span><del>-    if (thisObject->isRope())
-        static_cast<JSRopeString*>(thisObject)->visitFibers(visitor);
-    if (StringImpl* impl = thisObject->m_value.impl())
-        visitor.reportExtraMemoryVisited(impl->costDuringGC());
-}
-
-void JSRopeString::visitFibers(SlotVisitor& visitor)
-{
-    if (isSubstring()) {
-        visitor.append(substringBase());
</del><ins>+    uintptr_t pointer = thisObject->m_fiber;
+    if (pointer & isRopeInPointer) {
+        if ((pointer & JSRopeString::stringMask) == JSRopeString::substringSentinel()) {
+            visitor.appendUnbarriered(static_cast<JSRopeString*>(thisObject)->fiber1());
+            return;
+        }
+        for (unsigned index = 0; index < JSRopeString::s_maxInternalRopeLength; ++index) {
+            JSString* fiber = nullptr;
+            switch (index) {
+            case 0:
+                fiber = bitwise_cast<JSString*>(pointer & JSRopeString::stringMask);
+                break;
+            case 1:
+                fiber = static_cast<JSRopeString*>(thisObject)->fiber1();
+                break;
+            case 2:
+                fiber = static_cast<JSRopeString*>(thisObject)->fiber2();
+                break;
+            default:
+                ASSERT_NOT_REACHED();
+                return;
+            }
+            if (!fiber)
+                break;
+            visitor.appendUnbarriered(fiber);
+        }
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i)
-        visitor.append(fiber(i));
</del><ins>+    if (StringImpl* impl = bitwise_cast<StringImpl*>(pointer))
+        visitor.reportExtraMemoryVisited(impl->costDuringGC());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static const unsigned maxLengthForOnStackResolve = 2048;
</span><span class="lines">@@ -117,7 +149,7 @@
</span><span class="cx"> void JSRopeString::resolveRopeInternal8(LChar* buffer) const
</span><span class="cx"> {
</span><span class="cx">     if (isSubstring()) {
</span><del>-        StringImpl::copyCharacters(buffer, substringBase()->m_value.characters8() + substringOffset(), length());
</del><ins>+        StringImpl::copyCharacters(buffer, substringBase()->valueInternal().characters8() + substringOffset(), length());
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -135,7 +167,7 @@
</span><span class="cx"> 
</span><span class="cx">     LChar* position = buffer;
</span><span class="cx">     for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
</span><del>-        const StringImpl& fiberString = *fiber(i)->m_value.impl();
</del><ins>+        const StringImpl& fiberString = *fiber(i)->valueInternal().impl();
</ins><span class="cx">         unsigned length = fiberString.length();
</span><span class="cx">         StringImpl::copyCharacters(position, fiberString.characters8(), length);
</span><span class="cx">         position += length;
</span><span class="lines">@@ -147,7 +179,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (isSubstring()) {
</span><span class="cx">         StringImpl::copyCharacters(
</span><del>-            buffer, substringBase()->m_value.characters16() + substringOffset(), length());
</del><ins>+            buffer, substringBase()->valueInternal().characters16() + substringOffset(), length());
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -165,7 +197,7 @@
</span><span class="cx"> 
</span><span class="cx">     UChar* position = buffer;
</span><span class="cx">     for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
</span><del>-        const StringImpl& fiberString = *fiber(i)->m_value.impl();
</del><ins>+        const StringImpl& fiberString = *fiber(i)->valueInternal().impl();
</ins><span class="cx">         unsigned length = fiberString.length();
</span><span class="cx">         if (fiberString.is8Bit())
</span><span class="cx">             StringImpl::copyCharacters(position, fiberString.characters8(), length);
</span><span class="lines">@@ -176,55 +208,61 @@
</span><span class="cx">     ASSERT((buffer + length()) == position);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSRopeString::resolveRopeToAtomicString(ExecState* exec) const
</del><ins>+AtomicString JSRopeString::resolveRopeToAtomicString(ExecState* exec) const
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx"> 
</span><span class="cx">     if (length() > maxLengthForOnStackResolve) {
</span><del>-        resolveRope(exec);
-        RETURN_IF_EXCEPTION(scope, void());
-        m_value = AtomicString(m_value);
-        setIs8Bit(m_value.impl()->is8Bit());
-        return;
</del><ins>+        scope.release();
+        return resolveRopeWithFunction(exec, [&] (Ref<StringImpl>&& newImpl) {
+            return AtomicStringImpl::add(newImpl.ptr());
+        });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (is8Bit()) {
</span><span class="cx">         LChar buffer[maxLengthForOnStackResolve];
</span><span class="cx">         resolveRopeInternal8(buffer);
</span><del>-        m_value = AtomicString(buffer, length());
-        setIs8Bit(m_value.impl()->is8Bit());
</del><ins>+        convertToNonRope(AtomicStringImpl::add(buffer, length()));
</ins><span class="cx">     } else {
</span><span class="cx">         UChar buffer[maxLengthForOnStackResolve];
</span><span class="cx">         resolveRopeInternal16(buffer);
</span><del>-        m_value = AtomicString(buffer, length());
-        setIs8Bit(m_value.impl()->is8Bit());
</del><ins>+        convertToNonRope(AtomicStringImpl::add(buffer, length()));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    clearFibers();
-
</del><span class="cx">     // If we resolved a string that didn't previously exist, notify the heap that we've grown.
</span><del>-    if (m_value.impl()->hasOneRef())
-        vm.heap.reportExtraMemoryAllocated(m_value.impl()->cost());
</del><ins>+    if (valueInternal().impl()->hasOneRef())
+        vm.heap.reportExtraMemoryAllocated(valueInternal().impl()->cost());
+    return valueInternal();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSRopeString::clearFibers() const
</del><ins>+inline void JSRopeString::convertToNonRope(String&& string) const
</ins><span class="cx"> {
</span><del>-    for (size_t i = 0; i < s_maxInternalRopeLength; ++i)
-        u[i].number = 0;
</del><ins>+    // Concurrent compiler threads can access String held by JSString. So we always emit
+    // store-store barrier here to ensure concurrent compiler threads see initialized String.
+    ASSERT(JSString::isRope());
+    WTF::storeStoreFence();
+    new (&uninitializedValueInternal()) String(WTFMove(string));
+    static_assert(sizeof(String) == sizeof(RefPtr<StringImpl>), "JSString's String initialization must be done in one pointer move.");
+    // We do not clear the trailing fibers and length information (fiber1 and fiber2) because we could be reading the length concurrently.
+    ASSERT(!JSString::isRope());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RefPtr<AtomicStringImpl> JSRopeString::resolveRopeToExistingAtomicString(ExecState* exec) const
</span><span class="cx"> {
</span><ins>+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     if (length() > maxLengthForOnStackResolve) {
</span><del>-        resolveRope(exec);
-        if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(m_value.impl())) {
-            m_value = *existingAtomicString;
-            setIs8Bit(m_value.impl()->is8Bit());
-            clearFibers();
-            return existingAtomicString;
-        }
-        return nullptr;
</del><ins>+        RefPtr<AtomicStringImpl> existingAtomicString;
+        resolveRopeWithFunction(exec, [&] (Ref<StringImpl>&& newImpl) -> Ref<StringImpl> {
+            existingAtomicString = AtomicStringImpl::lookUp(newImpl.ptr());
+            if (existingAtomicString)
+                return makeRef(*existingAtomicString);
+            return WTFMove(newImpl);
+        });
+        RETURN_IF_EXCEPTION(scope, nullptr);
+        return existingAtomicString;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (is8Bit()) {
</span><span class="lines">@@ -231,9 +269,7 @@
</span><span class="cx">         LChar buffer[maxLengthForOnStackResolve];
</span><span class="cx">         resolveRopeInternal8(buffer);
</span><span class="cx">         if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, length())) {
</span><del>-            m_value = *existingAtomicString;
-            setIs8Bit(m_value.impl()->is8Bit());
-            clearFibers();
</del><ins>+            convertToNonRope(*existingAtomicString);
</ins><span class="cx">             return existingAtomicString;
</span><span class="cx">         }
</span><span class="cx">     } else {
</span><span class="lines">@@ -240,9 +276,7 @@
</span><span class="cx">         UChar buffer[maxLengthForOnStackResolve];
</span><span class="cx">         resolveRopeInternal16(buffer);
</span><span class="cx">         if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, length())) {
</span><del>-            m_value = *existingAtomicString;
-            setIs8Bit(m_value.impl()->is8Bit());
-            clearFibers();
</del><ins>+            convertToNonRope(*existingAtomicString);
</ins><span class="cx">             return existingAtomicString;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -250,46 +284,53 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSRopeString::resolveRope(ExecState* nullOrExecForOOM) const
</del><ins>+template<typename Function>
+const String& JSRopeString::resolveRopeWithFunction(ExecState* nullOrExecForOOM, Function&& function) const
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(isRope());
</span><span class="cx">     
</span><ins>+    VM& vm = *this->vm();
</ins><span class="cx">     if (isSubstring()) {
</span><span class="cx">         ASSERT(!substringBase()->isRope());
</span><del>-        m_value = substringBase()->m_value.substringSharingImpl(substringOffset(), length());
-        substringBase().clear();
-        return;
</del><ins>+        auto newImpl = substringBase()->valueInternal().substringSharingImpl(substringOffset(), length());
+        convertToNonRope(function(newImpl.releaseImpl().releaseNonNull()));
+        return valueInternal();
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (is8Bit()) {
</span><span class="cx">         LChar* buffer;
</span><del>-        if (auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer)) {
-            Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost());
-            m_value = WTFMove(newImpl);
-        } else {
</del><ins>+        auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer);
+        if (!newImpl) {
</ins><span class="cx">             outOfMemory(nullOrExecForOOM);
</span><del>-            return;
</del><ins>+            return nullString();
</ins><span class="cx">         }
</span><ins>+        vm.heap.reportExtraMemoryAllocated(newImpl->cost());
+
</ins><span class="cx">         resolveRopeInternal8NoSubstring(buffer);
</span><del>-        clearFibers();
-        ASSERT(!isRope());
-        return;
</del><ins>+        convertToNonRope(function(newImpl.releaseNonNull()));
+        return valueInternal();
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     UChar* buffer;
</span><del>-    if (auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer)) {
-        Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost());
-        m_value = WTFMove(newImpl);
-    } else {
</del><ins>+    auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer);
+    if (!newImpl) {
</ins><span class="cx">         outOfMemory(nullOrExecForOOM);
</span><del>-        return;
</del><ins>+        return nullString();
</ins><span class="cx">     }
</span><ins>+    vm.heap.reportExtraMemoryAllocated(newImpl->cost());
</ins><span class="cx">     
</span><span class="cx">     resolveRopeInternal16NoSubstring(buffer);
</span><del>-    clearFibers();
-    ASSERT(!isRope());
</del><ins>+    convertToNonRope(function(newImpl.releaseNonNull()));
+    return valueInternal();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+const String& JSRopeString::resolveRope(ExecState* nullOrExecForOOM) const
+{
+    return resolveRopeWithFunction(nullOrExecForOOM, [] (Ref<StringImpl>&& newImpl) {
+        return WTFMove(newImpl);
+    });
+}
+
</ins><span class="cx"> // Overview: These functions convert a JSString from holding a string in rope form
</span><span class="cx"> // down to a simple String representation. It does so by building up the string
</span><span class="cx"> // backwards, since we want to avoid recursion, we expect that the tree structure
</span><span class="lines">@@ -306,7 +347,7 @@
</span><span class="cx">     Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method.
</span><span class="cx">     
</span><span class="cx">     for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i)
</span><del>-        workQueue.append(fiber(i).get());
</del><ins>+        workQueue.append(fiber(i));
</ins><span class="cx"> 
</span><span class="cx">     while (!workQueue.isEmpty()) {
</span><span class="cx">         JSString* currentFiber = workQueue.last();
</span><span class="lines">@@ -318,15 +359,15 @@
</span><span class="cx">             JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber);
</span><span class="cx">             if (!currentFiberAsRope->isSubstring()) {
</span><span class="cx">                 for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i)
</span><del>-                    workQueue.append(currentFiberAsRope->fiber(i).get());
</del><ins>+                    workQueue.append(currentFiberAsRope->fiber(i));
</ins><span class="cx">                 continue;
</span><span class="cx">             }
</span><span class="cx">             ASSERT(!currentFiberAsRope->substringBase()->isRope());
</span><span class="cx">             characters =
</span><del>-                currentFiberAsRope->substringBase()->m_value.characters8() +
</del><ins>+                currentFiberAsRope->substringBase()->valueInternal().characters8() +
</ins><span class="cx">                 currentFiberAsRope->substringOffset();
</span><span class="cx">         } else
</span><del>-            characters = currentFiber->m_value.characters8();
</del><ins>+            characters = currentFiber->valueInternal().characters8();
</ins><span class="cx">         
</span><span class="cx">         unsigned length = currentFiber->length();
</span><span class="cx">         position -= length;
</span><span class="lines">@@ -342,7 +383,7 @@
</span><span class="cx">     Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK.
</span><span class="cx"> 
</span><span class="cx">     for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i)
</span><del>-        workQueue.append(fiber(i).get());
</del><ins>+        workQueue.append(fiber(i));
</ins><span class="cx"> 
</span><span class="cx">     while (!workQueue.isEmpty()) {
</span><span class="cx">         JSString* currentFiber = workQueue.last();
</span><span class="lines">@@ -353,7 +394,7 @@
</span><span class="cx">             if (currentFiberAsRope->isSubstring()) {
</span><span class="cx">                 ASSERT(!currentFiberAsRope->substringBase()->isRope());
</span><span class="cx">                 StringImpl* string = static_cast<StringImpl*>(
</span><del>-                    currentFiberAsRope->substringBase()->m_value.impl());
</del><ins>+                    currentFiberAsRope->substringBase()->valueInternal().impl());
</ins><span class="cx">                 unsigned offset = currentFiberAsRope->substringOffset();
</span><span class="cx">                 unsigned length = currentFiberAsRope->length();
</span><span class="cx">                 position -= length;
</span><span class="lines">@@ -364,11 +405,11 @@
</span><span class="cx">                 continue;
</span><span class="cx">             }
</span><span class="cx">             for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i)
</span><del>-                workQueue.append(currentFiberAsRope->fiber(i).get());
</del><ins>+                workQueue.append(currentFiberAsRope->fiber(i));
</ins><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl());
</del><ins>+        StringImpl* string = static_cast<StringImpl*>(currentFiber->valueInternal().impl());
</ins><span class="cx">         unsigned length = string->length();
</span><span class="cx">         position -= length;
</span><span class="cx">         if (string->is8Bit())
</span><span class="lines">@@ -382,9 +423,7 @@
</span><span class="cx"> 
</span><span class="cx"> void JSRopeString::outOfMemory(ExecState* nullOrExecForOOM) const
</span><span class="cx"> {
</span><del>-    clearFibers();
</del><span class="cx">     ASSERT(isRope());
</span><del>-    ASSERT(m_value.isNull());
</del><span class="cx">     if (nullOrExecForOOM) {
</span><span class="cx">         VM& vm = nullOrExecForOOM->vm();
</span><span class="cx">         auto scope = DECLARE_THROW_SCOPE(vm);
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeJSStringh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSString.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSString.h  2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSString.h     2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -22,6 +22,7 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><ins>+#include "ArgList.h"
</ins><span class="cx"> #include "CallFrame.h"
</span><span class="cx"> #include "CommonIdentifiers.h"
</span><span class="cx"> #include "Identifier.h"
</span><span class="lines">@@ -31,6 +32,7 @@
</span><span class="cx"> #include "ThrowScope.h"
</span><span class="cx"> #include <array>
</span><span class="cx"> #include <wtf/CheckedArithmetic.h>
</span><ins>+#include <wtf/ForbidHeapAllocation.h>
</ins><span class="cx"> #include <wtf/text/StringView.h>
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -61,8 +63,6 @@
</span><span class="cx"> JSString* jsOwnedString(VM*, const String&);
</span><span class="cx"> JSString* jsOwnedString(ExecState*, const String&);
</span><span class="cx"> 
</span><del>-JSRopeString* jsStringBuilder(VM*);
-
</del><span class="cx"> bool isJSString(JSCell*);
</span><span class="cx"> bool isJSString(JSValue);
</span><span class="cx"> JSString* asString(JSValue);
</span><span class="lines">@@ -72,6 +72,23 @@
</span><span class="cx">     String underlyingString;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+
+// In 64bit architecture, JSString and JSRopeString have the following memory layout to make sizeof(JSString) == 16 and sizeof(JSRopeString) == 32.
+// JSString has only one pointer. We use it for String. length() and is8Bit() queries go to StringImpl. In JSRopeString, we reuse the above pointer
+// place for the 1st fiber. JSRopeString has three fibers so its size is 48. To keep length and is8Bit flag information in JSRopeString, JSRopeString
+// encodes these information into the fiber pointers. is8Bit flag is encoded in the 1st fiber pointer. length is embedded directly, and two fibers
+// are compressed into 12bytes. isRope information is encoded in the first fiber's LSB.
+//
+// Since length of JSRopeString should be frequently accessed compared to each fiber, we put length in contiguous 32byte field, and compress 2nd
+// and 3rd fibers into the following 80byte fields. One problem is that now 2nd and 3rd fibers are split. Storing and loading 2nd and 3rd fibers
+// are not one pointer load operation. To make concurrent collector work correctly, we must initialize 2nd and 3rd fibers at JSRopeString creation
+// and we must not modify these part later.
+//
+//              0                        8        10               16                       32                                     48
+// JSString     [   ID      ][  header  ][   String pointer      0]
+// JSRopeString [   ID      ][  header  ][ flags ][ 1st fiber    1][  length  ][2nd lower32][2nd upper16][3rd lower16][3rd upper32]
+//                                                               ^
+//                                                            isRope bit
</ins><span class="cx"> class JSString : public JSCell {
</span><span class="cx"> public:
</span><span class="cx">     friend class JIT;
</span><span class="lines">@@ -80,6 +97,7 @@
</span><span class="cx">     friend class JSRopeString;
</span><span class="cx">     friend class MarkStack;
</span><span class="cx">     friend class SlotVisitor;
</span><ins>+    friend class SmallStrings;
</ins><span class="cx"> 
</span><span class="cx">     typedef JSCell Base;
</span><span class="cx">     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal | OverridesToThis;
</span><span class="lines">@@ -101,47 +119,53 @@
</span><span class="cx">     static constexpr unsigned MaxLength = std::numeric_limits<int32_t>::max();
</span><span class="cx">     static_assert(MaxLength == String::MaxLength, "");
</span><span class="cx"> 
</span><ins>+    static constexpr uintptr_t isRopeInPointer = 0x1;
+
</ins><span class="cx"> private:
</span><ins>+    String& uninitializedValueInternal() const
+    {
+        return *bitwise_cast<String*>(&m_fiber);
+    }
+
+    String& valueInternal() const
+    {
+        ASSERT(!isRope());
+        return uninitializedValueInternal();
+    }
+
</ins><span class="cx">     JSString(VM& vm, Ref<StringImpl>&& value)
</span><span class="cx">         : JSCell(vm, vm.stringStructure.get())
</span><del>-        , m_value(WTFMove(value))
</del><span class="cx">     {
</span><ins>+        new (&uninitializedValueInternal()) String(WTFMove(value));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     JSString(VM& vm)
</span><span class="cx">         : JSCell(vm, vm.stringStructure.get())
</span><ins>+        , m_fiber(isRopeInPointer)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void finishCreation(VM& vm, unsigned length)
</span><span class="cx">     {
</span><del>-        ASSERT(!m_value.isNull());
</del><ins>+        ASSERT_UNUSED(length, length > 0);
+        ASSERT(!valueInternal().isNull());
</ins><span class="cx">         Base::finishCreation(vm);
</span><del>-        setLength(length);
-        setIs8Bit(m_value.impl()->is8Bit());
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void finishCreation(VM& vm, unsigned length, size_t cost)
</span><span class="cx">     {
</span><del>-        ASSERT(!m_value.isNull());
</del><ins>+        ASSERT_UNUSED(length, length > 0);
+        ASSERT(!valueInternal().isNull());
</ins><span class="cx">         Base::finishCreation(vm);
</span><del>-        setLength(length);
-        setIs8Bit(m_value.impl()->is8Bit());
</del><span class="cx">         vm.heap.reportExtraMemoryAllocated(cost);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-protected:
-    void finishCreation(VM& vm)
-    {
-        Base::finishCreation(vm);
-        setLength(0);
-        setIs8Bit(true);
-    }
</del><ins>+    static JSString* createEmptyString(VM&);
</ins><span class="cx"> 
</span><del>-public:
</del><span class="cx">     static JSString* create(VM& vm, Ref<StringImpl>&& value)
</span><span class="cx">     {
</span><span class="cx">         unsigned length = value->length();
</span><ins>+        ASSERT(length > 0);
</ins><span class="cx">         size_t cost = value->cost();
</span><span class="cx">         JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, WTFMove(value));
</span><span class="cx">         newString->finishCreation(vm, length, cost);
</span><span class="lines">@@ -155,6 +179,15 @@
</span><span class="cx">         return newString;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+protected:
+    void finishCreation(VM& vm)
+    {
+        Base::finishCreation(vm);
+    }
+
+public:
+    ~JSString();
+
</ins><span class="cx">     Identifier toIdentifier(ExecState*) const;
</span><span class="cx">     AtomicString toAtomicString(ExecState*) const;
</span><span class="cx">     RefPtr<AtomicStringImpl> toExistingAtomicString(ExecState*) const;
</span><span class="lines">@@ -165,7 +198,7 @@
</span><span class="cx">     const String& value(ExecState*) const;
</span><span class="cx">     inline const String& tryGetValue(bool allocationAllowed = true) const;
</span><span class="cx">     const StringImpl* tryGetValueImpl() const;
</span><del>-    ALWAYS_INLINE unsigned length() const { return m_length; }
</del><ins>+    ALWAYS_INLINE unsigned length() const;
</ins><span class="cx"> 
</span><span class="cx">     JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
</span><span class="cx">     bool toBoolean() const { return !!length(); }
</span><span class="lines">@@ -182,9 +215,7 @@
</span><span class="cx"> 
</span><span class="cx">     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
</span><span class="cx"> 
</span><del>-    static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); }
-    static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); }
-    static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); }
</del><ins>+    static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_fiber); }
</ins><span class="cx"> 
</span><span class="cx">     DECLARE_EXPORT_INFO;
</span><span class="cx"> 
</span><span class="lines">@@ -192,11 +223,12 @@
</span><span class="cx">     static size_t estimatedSize(JSCell*, VM&);
</span><span class="cx">     static void visitChildren(JSCell*, SlotVisitor&);
</span><span class="cx"> 
</span><del>-    enum {
-        Is8Bit = 1u
-    };
</del><ins>+    ALWAYS_INLINE bool isRope() const
+    {
+        return m_fiber & isRopeInPointer;
+    }
</ins><span class="cx"> 
</span><del>-    bool isRope() const { return m_value.isNull(); }
</del><ins>+    bool is8Bit() const;
</ins><span class="cx"> 
</span><span class="cx"> protected:
</span><span class="cx">     friend class JSValue;
</span><span class="lines">@@ -203,36 +235,30 @@
</span><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE bool equalSlowCase(ExecState*, JSString* other) const;
</span><span class="cx">     bool isSubstring() const;
</span><del>-    bool is8Bit() const { return m_flags & Is8Bit; }
-    void setIs8Bit(bool flag) const
-    {
-        if (flag)
-            m_flags |= Is8Bit;
-        else
-            m_flags &= ~Is8Bit;
-    }
</del><span class="cx"> 
</span><del>-    ALWAYS_INLINE void setLength(unsigned length)
-    {
-        ASSERT(length <= MaxLength);
-        m_length = length;
-    }
</del><ins>+    mutable uintptr_t m_fiber;
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    // A string is represented either by a String or a rope of fibers.
-    unsigned m_length { 0 };
-    mutable uint16_t m_flags { 0 };
-    mutable String m_value;
-
</del><span class="cx">     friend class LLIntOffsetsExtractor;
</span><span class="cx"> 
</span><span class="cx">     static JSValue toThis(JSCell*, ExecState*, ECMAMode);
</span><span class="cx"> 
</span><del>-    String& string() { ASSERT(!isRope()); return m_value; }
</del><span class="cx">     StringView unsafeView(ExecState*) const;
</span><span class="cx"> 
</span><ins>+    friend JSString* jsString(VM*, const String&);
</ins><span class="cx">     friend JSString* jsString(ExecState*, JSString*, JSString*);
</span><del>-    friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
</del><ins>+    friend JSString* jsString(ExecState*, const String&, JSString*);
+    friend JSString* jsString(ExecState*, JSString*, const String&);
+    friend JSString* jsString(ExecState*, const String&, const String&);
+    friend JSString* jsString(ExecState*, JSString*, JSString*, JSString*);
+    friend JSString* jsString(ExecState*, const String&, const String&, const String&);
+    friend JSString* jsSingleCharacterString(VM*, UChar);
+    friend JSString* jsNontrivialString(VM*, const String&);
+    friend JSString* jsNontrivialString(VM*, String&&);
+    friend JSString* jsSubstring(VM*, const String&, unsigned, unsigned);
+    friend JSString* jsSubstring(VM&, ExecState*, JSString*, unsigned, unsigned);
+    friend JSString* jsSubstringOfResolved(VM&, GCDeferralContext*, JSString*, unsigned, unsigned);
+    friend JSString* jsOwnedString(VM*, const String&);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> // NOTE: This class cannot override JSString's destructor. JSString's destructor is called directly
</span><span class="lines">@@ -239,17 +265,117 @@
</span><span class="cx"> // from JSStringSubspace::
</span><span class="cx"> class JSRopeString final : public JSString {
</span><span class="cx">     friend class JSString;
</span><ins>+public:
+#if CPU(ADDRESS64)
+    static_assert(sizeof(uintptr_t) == sizeof(uint64_t), "");
+    static constexpr uintptr_t flagMask = 0xffff000000000000ULL;
+    static constexpr uintptr_t stringMask = ~(flagMask | isRopeInPointer);
+    static_assert(StringImpl::flagIs8Bit() == 0b100, "");
+    static constexpr uintptr_t is8BitInPointer = static_cast<uintptr_t>(StringImpl::flagIs8Bit()) << 48;
</ins><span class="cx"> 
</span><del>-    friend JSRopeString* jsStringBuilder(VM*);
</del><ins>+    class CompactFibers {
+    public:
+        JSString* fiber1() const
+        {
+            return bitwise_cast<JSString*>(static_cast<uintptr_t>(m_fiber1Lower) | (static_cast<uintptr_t>(m_fiber1Upper) << 32));
+        }
</ins><span class="cx"> 
</span><del>-public:
</del><ins>+        void initializeFiber1(JSString* fiber)
+        {
+            uintptr_t pointer = bitwise_cast<uintptr_t>(fiber);
+            m_fiber1Lower = static_cast<uint32_t>(pointer);
+            m_fiber1Upper = static_cast<uint16_t>(pointer >> 32);
+        }
+
+        JSString* fiber2() const
+        {
+            return bitwise_cast<JSString*>(static_cast<uintptr_t>(m_fiber2Lower) | (static_cast<uintptr_t>(m_fiber2Upper) << 32));
+        }
+        void initializeFiber2(JSString* fiber)
+        {
+            uintptr_t pointer = bitwise_cast<uintptr_t>(fiber);
+            m_fiber2Lower = static_cast<uint32_t>(pointer);
+            m_fiber2Upper = static_cast<uint16_t>(pointer >> 32);
+        }
+
+        unsigned length() const { return m_length; }
+        void initializeLength(unsigned length)
+        {
+            m_length = length;
+        }
+
+        static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(CompactFibers, m_length); }
+        static ptrdiff_t offsetOfFiber1Lower() { return OBJECT_OFFSETOF(CompactFibers, m_fiber1Lower); }
+        static ptrdiff_t offsetOfFiber1Upper() { return OBJECT_OFFSETOF(CompactFibers, m_fiber1Upper); }
+        static ptrdiff_t offsetOfFiber2Lower() { return OBJECT_OFFSETOF(CompactFibers, m_fiber2Lower); }
+        static ptrdiff_t offsetOfFiber2Upper() { return OBJECT_OFFSETOF(CompactFibers, m_fiber2Upper); }
+
+    private:
+        uint32_t m_length { 0 };
+        uint32_t m_fiber1Lower { 0 };
+        uint16_t m_fiber1Upper { 0 };
+        uint16_t m_fiber2Upper { 0 };
+        uint32_t m_fiber2Lower { 0 };
+    };
+    static_assert(sizeof(CompactFibers) == sizeof(void*) * 2, "");
+#else
+    static constexpr uintptr_t stringMask = ~(isRopeInPointer);
+
+    class CompactFibers {
+    public:
+        JSString* fiber1() const
+        {
+            return m_fiber1;
+        }
+        void initializeFiber1(JSString* fiber)
+        {
+            m_fiber1 = fiber;
+        }
+
+        JSString* fiber2() const
+        {
+            return m_fiber2;
+        }
+        void initializeFiber2(JSString* fiber)
+        {
+            m_fiber2 = fiber;
+        }
+
+        unsigned length() const { return m_length; }
+        void initializeLength(unsigned length)
+        {
+            m_length = length;
+        }
+
+        void initializeIs8Bit(bool flag)
+        {
+            if (flag)
+                m_flags |= static_cast<uintptr_t>(StringImpl::flagIs8Bit());
+            else
+                m_flags &= ~static_cast<uintptr_t>(StringImpl::flagIs8Bit());
+        }
+
+        bool is8Bit()
+        {
+            return m_flags & static_cast<uintptr_t>(StringImpl::flagIs8Bit());
+        }
+
+        static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(CompactFibers, m_length); }
+
+    private:
+        uint32_t m_length { 0 };
+        uint32_t m_flags { 0 };
+        JSString* m_fiber1 { nullptr };
+        JSString* m_fiber2 { nullptr };
+    };
+#endif
+
</ins><span class="cx">     template <class OverflowHandler = CrashOnOverflow>
</span><span class="cx">     class RopeBuilder : public OverflowHandler {
</span><ins>+        WTF_FORBID_HEAP_ALLOCATION;
</ins><span class="cx">     public:
</span><span class="cx">         RopeBuilder(VM& vm)
</span><span class="cx">             : m_vm(vm)
</span><del>-            , m_jsString(jsStringBuilder(&vm))
-            , m_index(0)
</del><span class="cx">         {
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -257,32 +383,59 @@
</span><span class="cx">         {
</span><span class="cx">             if (UNLIKELY(this->hasOverflowed()))
</span><span class="cx">                 return false;
</span><del>-            if (m_index == JSRopeString::s_maxInternalRopeLength)
</del><ins>+            if (!jsString->length())
+                return true;
+            if (m_strings.size() == JSRopeString::s_maxInternalRopeLength)
</ins><span class="cx">                 expand();
</span><span class="cx"> 
</span><span class="cx">             static_assert(JSString::MaxLength == std::numeric_limits<int32_t>::max(), "");
</span><del>-            auto sum = checkedSum<int32_t>(m_jsString->length(), jsString->length());
</del><ins>+            auto sum = checkedSum<int32_t>(m_length, jsString->length());
</ins><span class="cx">             if (sum.hasOverflowed()) {
</span><span class="cx">                 this->overflowed();
</span><span class="cx">                 return false;
</span><span class="cx">             }
</span><span class="cx">             ASSERT(static_cast<unsigned>(sum.unsafeGet()) <= MaxLength);
</span><del>-            m_jsString->append(m_vm, m_index++, jsString);
</del><ins>+            m_strings.append(jsString);
+            m_length = static_cast<unsigned>(sum.unsafeGet());
</ins><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        JSRopeString* release()
</del><ins>+        JSString* release()
</ins><span class="cx">         {
</span><span class="cx">             RELEASE_ASSERT(!this->hasOverflowed());
</span><del>-            JSRopeString* tmp = m_jsString;
-            m_jsString = nullptr;
-            return tmp;
</del><ins>+            JSString* result = nullptr;
+            switch (m_strings.size()) {
+            case 0: {
+                ASSERT(!m_length);
+                result = jsEmptyString(&m_vm);
+                break;
+            }
+            case 1: {
+                result = asString(m_strings.at(0));
+                break;
+            }
+            case 2: {
+                result = JSRopeString::create(m_vm, asString(m_strings.at(0)), asString(m_strings.at(1)));
+                break;
+            }
+            case 3: {
+                result = JSRopeString::create(m_vm, asString(m_strings.at(0)), asString(m_strings.at(1)), asString(m_strings.at(2)));
+                break;
+            }
+            default:
+                ASSERT_NOT_REACHED();
+                break;
+            }
+            ASSERT(result->length() == m_length);
+            m_strings.clear();
+            m_length = 0;
+            return result;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         unsigned length() const
</span><span class="cx">         {
</span><span class="cx">             ASSERT(!this->hasOverflowed());
</span><del>-            return m_jsString->length();
</del><ins>+            return m_length;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">     private:
</span><span class="lines">@@ -289,138 +442,155 @@
</span><span class="cx">         void expand();
</span><span class="cx"> 
</span><span class="cx">         VM& m_vm;
</span><del>-        JSRopeString* m_jsString;
-        size_t m_index;
</del><ins>+        MarkedArgumentBuffer m_strings;
+        unsigned m_length { 0 };
</ins><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    inline unsigned length() const
+    {
+        return m_compactFibers.length();
+    }
+
</ins><span class="cx"> private:
</span><del>-    ALWAYS_INLINE JSRopeString(VM& vm)
-        : JSString(vm)
</del><ins>+    void convertToNonRope(String&&) const;
+
+    void initializeIs8Bit(bool flag) const
</ins><span class="cx">     {
</span><ins>+#if CPU(ADDRESS64)
+        if (flag)
+            m_fiber |= is8BitInPointer;
+        else
+            m_fiber &= ~is8BitInPointer;
+#else
+        m_compactFibers.initializeIs8Bit(flag);
+#endif
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void finishCreation(VM& vm, JSString* s1, JSString* s2)
</del><ins>+    ALWAYS_INLINE void initializeLength(unsigned length)
</ins><span class="cx">     {
</span><del>-        Base::finishCreation(vm);
</del><ins>+        ASSERT(length <= MaxLength);
+        m_compactFibers.initializeLength(length);
+    }
+
+    JSRopeString(VM& vm, JSString* s1, JSString* s2)
+        : JSString(vm)
+    {
</ins><span class="cx">         ASSERT(!sumOverflows<int32_t>(s1->length(), s2->length()));
</span><del>-        setLength(s1->length() + s2->length());
-        setIs8Bit(s1->is8Bit() && s2->is8Bit());
-        setIsSubstring(false);
-        fiber(0).set(vm, this, s1);
-        fiber(1).set(vm, this, s2);
-        fiber(2).clear();
</del><ins>+        initializeIsSubstring(false);
+        initializeLength(s1->length() + s2->length());
+        initializeIs8Bit(s1->is8Bit() && s2->is8Bit());
+        initializeFiber0(s1);
+        initializeFiber1(s2);
+        initializeFiber2(nullptr);
+        ASSERT((s1->length() + s2->length()) == length());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3)
</del><ins>+    JSRopeString(VM& vm, JSString* s1, JSString* s2, JSString* s3)
+        : JSString(vm)
</ins><span class="cx">     {
</span><del>-        Base::finishCreation(vm);
</del><span class="cx">         ASSERT(!sumOverflows<int32_t>(s1->length(), s2->length(), s3->length()));
</span><del>-        setLength(s1->length() + s2->length() + s3->length());
-        setIs8Bit(s1->is8Bit() && s2->is8Bit() &&  s3->is8Bit());
-        setIsSubstring(false);
-        fiber(0).set(vm, this, s1);
-        fiber(1).set(vm, this, s2);
-        fiber(2).set(vm, this, s3);
</del><ins>+        initializeIsSubstring(false);
+        initializeLength(s1->length() + s2->length() + s3->length());
+        initializeIs8Bit(s1->is8Bit() && s2->is8Bit() &&  s3->is8Bit());
+        initializeFiber0(s1);
+        initializeFiber1(s2);
+        initializeFiber2(s3);
+        ASSERT((s1->length() + s2->length() + s3->length()) == length());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void finishCreation(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
</del><ins>+    JSRopeString(VM& vm, JSString* base, unsigned offset, unsigned length)
+        : JSString(vm)
</ins><span class="cx">     {
</span><del>-        Base::finishCreation(vm);
</del><span class="cx">         RELEASE_ASSERT(!sumOverflows<int32_t>(offset, length));
</span><span class="cx">         RELEASE_ASSERT(offset + length <= base->length());
</span><del>-        setLength(length);
-        setIs8Bit(base->is8Bit());
-        setIsSubstring(true);
</del><ins>+        initializeIsSubstring(true);
+        initializeLength(length);
+        initializeIs8Bit(base->is8Bit());
</ins><span class="cx">         if (base->isSubstring()) {
</span><span class="cx">             JSRopeString* baseRope = jsCast<JSRopeString*>(base);
</span><del>-            substringBase().set(vm, this, baseRope->substringBase().get());
-            substringOffset() = baseRope->substringOffset() + offset;
</del><ins>+            initializeSubstringBase(baseRope->substringBase());
+            initializeSubstringOffset(baseRope->substringOffset() + offset);
</ins><span class="cx">         } else {
</span><del>-            substringBase().set(vm, this, base);
-            substringOffset() = offset;
-
-            // 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->isRope())
-                jsCast<JSRopeString*>(base)->resolveRope(exec);
</del><ins>+            initializeSubstringBase(base);
+            initializeSubstringOffset(offset);
</ins><span class="cx">         }
</span><ins>+        ASSERT(length == this->length());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ALWAYS_INLINE void finishCreationSubstringOfResolved(VM& vm, JSString* base, unsigned offset, unsigned length)
</del><ins>+    enum SubstringOfResolvedTag { SubstringOfResolved };
+    JSRopeString(SubstringOfResolvedTag, VM& vm, JSString* base, unsigned offset, unsigned length)
+        : JSString(vm)
</ins><span class="cx">     {
</span><del>-        Base::finishCreation(vm);
</del><span class="cx">         RELEASE_ASSERT(!sumOverflows<int32_t>(offset, length));
</span><span class="cx">         RELEASE_ASSERT(offset + length <= base->length());
</span><del>-        setLength(length);
-        setIs8Bit(base->is8Bit());
-        setIsSubstring(true);
-        substringBase().set(vm, this, base);
-        substringOffset() = offset;
</del><ins>+        initializeIsSubstring(true);
+        initializeLength(length);
+        initializeIs8Bit(base->is8Bit());
+        initializeSubstringBase(base);
+        initializeSubstringOffset(offset);
+        ASSERT(length == this->length());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void finishCreation(VM& vm)
</del><ins>+    ALWAYS_INLINE void finishCreationSubstring(VM& vm, ExecState* exec)
</ins><span class="cx">     {
</span><del>-        JSString::finishCreation(vm);
-        setIsSubstring(false);
-        fiber(0).clear();
-        fiber(1).clear();
-        fiber(2).clear();
</del><ins>+        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);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void append(VM& vm, size_t index, JSString* jsString)
</del><ins>+    ALWAYS_INLINE void finishCreationSubstringOfResolved(VM& vm)
</ins><span class="cx">     {
</span><del>-        fiber(index).set(vm, this, jsString);
-        setLength(length() + jsString->length());
-        setIs8Bit(is8Bit() && jsString->is8Bit());
</del><ins>+        Base::finishCreation(vm);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static JSRopeString* createNull(VM& vm)
</del><ins>+public:
+    static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfLength(); } // 32byte width.
+#if CPU(ADDRESS64)
+    static ptrdiff_t offsetOfFlags() { return offsetOfValue() + sizeof(uint16_t) * 3; } // 16byte width.
+    static ptrdiff_t offsetOfFiber0() { return offsetOfValue(); }
+    static ptrdiff_t offsetOfFiber1Lower() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber1Lower(); } // 32byte width.
+    static ptrdiff_t offsetOfFiber1Upper() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber1Upper(); } // 16byte width.
+    static ptrdiff_t offsetOfFiber2Lower() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber2Lower(); } // 32byte width.
+    static ptrdiff_t offsetOfFiber2Upper() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber2Upper(); } // 16byte width.
+#endif
+
+    static constexpr unsigned s_maxInternalRopeLength = 3;
+
+private:
+    static JSRopeString* create(VM& vm, JSString* s1, JSString* s2)
</ins><span class="cx">     {
</span><del>-        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
</del><ins>+        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, s1, s2);
</ins><span class="cx">         newString->finishCreation(vm);
</span><ins>+        ASSERT(newString->length());
</ins><span class="cx">         return newString;
</span><span class="cx">     }
</span><del>-
-public:
-    static JSString* create(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
</del><ins>+    static JSRopeString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3)
</ins><span class="cx">     {
</span><del>-        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
-        newString->finishCreation(vm, exec, base, offset, length);
</del><ins>+        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, s1, s2, s3);
+        newString->finishCreation(vm);
+        ASSERT(newString->length());
</ins><span class="cx">         return newString;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ALWAYS_INLINE static JSString* createSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* base, unsigned offset, unsigned length)
</del><ins>+    static JSRopeString* create(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length)
</ins><span class="cx">     {
</span><del>-        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(vm);
-        newString->finishCreationSubstringOfResolved(vm, base, offset, length);
</del><ins>+        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, base, offset, length);
+        newString->finishCreationSubstring(vm, exec);
+        ASSERT(newString->length());
</ins><span class="cx">         return newString;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ALWAYS_INLINE static JSString* createSubstringOfResolved(VM& vm, JSString* base, unsigned offset, unsigned length)
</del><ins>+    ALWAYS_INLINE static JSRopeString* createSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* base, unsigned offset, unsigned length)
</ins><span class="cx">     {
</span><del>-        return createSubstringOfResolved(vm, nullptr, base, offset, length);
-    }
-
-    void visitFibers(SlotVisitor&);
-
-    static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, u); }
-
-    static const unsigned s_maxInternalRopeLength = 3;
-
-private:
-    static JSString* create(VM& vm, JSString* s1, JSString* s2)
-    {
-        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
-        newString->finishCreation(vm, s1, s2);
</del><ins>+        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(SubstringOfResolved, vm, base, offset, length);
+        newString->finishCreationSubstringOfResolved(vm);
+        ASSERT(newString->length());
</ins><span class="cx">         return newString;
</span><span class="cx">     }
</span><del>-    static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3)
-    {
-        JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
-        newString->finishCreation(vm, s1, s2, s3);
-        return newString;
-    }
</del><span class="cx"> 
</span><span class="cx">     friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned);
</span><span class="cx">     friend JSValue jsStringFromArguments(ExecState*, JSValue);
</span><span class="lines">@@ -427,8 +597,9 @@
</span><span class="cx"> 
</span><span class="cx">     // If nullOrExecForOOM is null, resolveRope() will be do nothing in the event of an OOM error.
</span><span class="cx">     // The rope value will remain a null string in that case.
</span><del>-    JS_EXPORT_PRIVATE void resolveRope(ExecState* nullOrExecForOOM) const;
-    JS_EXPORT_PRIVATE void resolveRopeToAtomicString(ExecState*) const;
</del><ins>+    JS_EXPORT_PRIVATE const String& resolveRope(ExecState* nullOrExecForOOM) const;
+    template<typename Function> const String& resolveRopeWithFunction(ExecState* nullOrExecForOOM, Function&&) const;
+    JS_EXPORT_PRIVATE AtomicString resolveRopeToAtomicString(ExecState*) const;
</ins><span class="cx">     JS_EXPORT_PRIVATE RefPtr<AtomicStringImpl> resolveRopeToExistingAtomicString(ExecState*) const;
</span><span class="cx">     void resolveRopeSlowCase8(LChar*) const;
</span><span class="cx">     void resolveRopeSlowCase(UChar*) const;
</span><span class="lines">@@ -437,66 +608,144 @@
</span><span class="cx">     void resolveRopeInternal8NoSubstring(LChar*) const;
</span><span class="cx">     void resolveRopeInternal16(UChar*) const;
</span><span class="cx">     void resolveRopeInternal16NoSubstring(UChar*) const;
</span><del>-    void clearFibers() const;
</del><span class="cx">     StringView unsafeView(ExecState*) const;
</span><span class="cx">     StringViewWithUnderlyingString viewWithUnderlyingString(ExecState*) const;
</span><span class="cx"> 
</span><del>-    WriteBarrierBase<JSString>& fiber(unsigned i) const
</del><ins>+    JSString* fiber0() const
</ins><span class="cx">     {
</span><ins>+        return bitwise_cast<JSString*>(m_fiber & stringMask);
+    }
+
+    JSString* fiber1() const
+    {
+        return m_compactFibers.fiber1();
+    }
+
+    JSString* fiber2() const
+    {
+        return m_compactFibers.fiber2();
+    }
+
+    JSString* fiber(unsigned i) const
+    {
</ins><span class="cx">         ASSERT(!isSubstring());
</span><span class="cx">         ASSERT(i < s_maxInternalRopeLength);
</span><del>-        return u[i].string;
</del><ins>+        switch (i) {
+        case 0:
+            return fiber0();
+        case 1:
+            return fiber1();
+        case 2:
+            return fiber2();
+        }
+        ASSERT_NOT_REACHED();
+        return nullptr;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    WriteBarrierBase<JSString>& substringBase() const
</del><ins>+    void initializeFiber0(JSString* fiber)
</ins><span class="cx">     {
</span><del>-        return u[1].string;
</del><ins>+        uintptr_t pointer = bitwise_cast<uintptr_t>(fiber);
+        ASSERT(!(pointer & ~stringMask));
+        m_fiber = (pointer | (m_fiber & ~stringMask));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    uintptr_t& substringOffset() const
</del><ins>+    void initializeFiber1(JSString* fiber)
</ins><span class="cx">     {
</span><del>-        return u[2].number;
</del><ins>+        m_compactFibers.initializeFiber1(fiber);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static uintptr_t notSubstringSentinel()
</del><ins>+    void initializeFiber2(JSString* fiber)
</ins><span class="cx">     {
</span><ins>+        m_compactFibers.initializeFiber2(fiber);
+    }
+
+    void initializeSubstringBase(JSString* fiber)
+    {
+        initializeFiber1(fiber);
+    }
+
+    JSString* substringBase() const { return fiber1(); }
+
+    void initializeSubstringOffset(unsigned offset)
+    {
+        m_compactFibers.initializeFiber2(bitwise_cast<JSString*>(static_cast<uintptr_t>(offset)));
+    }
+
+    unsigned substringOffset() const
+    {
+        return static_cast<unsigned>(bitwise_cast<uintptr_t>(fiber2()));
+    }
+
+    static constexpr uintptr_t notSubstringSentinel()
+    {
</ins><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static uintptr_t substringSentinel()
</del><ins>+    static constexpr uintptr_t substringSentinel()
</ins><span class="cx">     {
</span><del>-        return 1;
</del><ins>+        return 2;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     bool isSubstring() const
</span><span class="cx">     {
</span><del>-        return u[0].number == substringSentinel();
</del><ins>+        return (m_fiber & stringMask) == substringSentinel();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void setIsSubstring(bool isSubstring)
</del><ins>+    void initializeIsSubstring(bool isSubstring)
</ins><span class="cx">     {
</span><del>-        u[0].number = isSubstring ? substringSentinel() : notSubstringSentinel();
</del><ins>+        m_fiber |= (isSubstring ? substringSentinel() : notSubstringSentinel());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    mutable union {
-        uintptr_t number;
-        WriteBarrierBase<JSString> string;
-    } u[s_maxInternalRopeLength];
</del><ins>+    static_assert(s_maxInternalRopeLength >= 2, "");
+    mutable CompactFibers m_compactFibers;
</ins><span class="cx"> 
</span><del>-
</del><span class="cx">     friend JSString* jsString(ExecState*, JSString*, JSString*);
</span><span class="cx">     friend JSString* jsString(ExecState*, const String&, JSString*);
</span><span class="cx">     friend JSString* jsString(ExecState*, JSString*, const String&);
</span><ins>+    friend JSString* jsString(ExecState*, const String&, const String&);
</ins><span class="cx">     friend JSString* jsString(ExecState*, JSString*, JSString*, JSString*);
</span><del>-    friend JSString* jsString(ExecState*, const String&, const String&);
</del><span class="cx">     friend JSString* jsString(ExecState*, const String&, const String&, const String&);
</span><ins>+    friend JSString* jsSubstringOfResolved(VM&, GCDeferralContext*, JSString*, unsigned, unsigned);
+    friend JSString* jsSubstring(VM&, ExecState*, JSString*, unsigned, unsigned);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&);
</span><span class="cx"> 
</span><ins>+// JSString::is8Bit is safe to be called concurrently. Concurrent threads can access is8Bit even if the main thread
+// is in the middle of converting JSRopeString to JSString.
+ALWAYS_INLINE bool JSString::is8Bit() const
+{
+    uintptr_t pointer = m_fiber;
+    if (pointer & isRopeInPointer) {
+#if CPU(ADDRESS64)
+        // Do not load m_fiber twice. We should use the information in pointer.
+        // Otherwise, JSRopeString may be converted to JSString between the first and second accesses.
+        return pointer & JSRopeString::is8BitInPointer;
+#else
+        // It is OK to load flag since even if JSRopeString is converted to JSString, this flag still exists.
+        return jsCast<const JSRopeString*>(this)->m_compactFibers.is8Bit();
+#endif
+    }
+    return bitwise_cast<StringImpl*>(pointer)->is8Bit();
+}
+
+// JSString::length is safe to be called concurrently. Concurrent threads can access length even if the main thread
+// is in the middle of converting JSRopeString to JSString. This is OK because we never override the length bits
+// when we resolve a JSRopeString.
+ALWAYS_INLINE unsigned JSString::length() const
+{
+    uintptr_t pointer = m_fiber;
+    if (pointer & isRopeInPointer)
+        return jsCast<const JSRopeString*>(this)->length();
+    return bitwise_cast<StringImpl*>(pointer)->length();
+}
+
</ins><span class="cx"> inline const StringImpl* JSString::tryGetValueImpl() const
</span><span class="cx"> {
</span><del>-    return m_value.impl();
</del><ins>+    uintptr_t pointer = m_fiber;
+    if (pointer & isRopeInPointer)
+        return nullptr;
+    return bitwise_cast<StringImpl*>(pointer);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline JSString* asString(JSValue value)
</span><span class="lines">@@ -542,8 +791,8 @@
</span><span class="cx">     if (validateDFGDoesGC)
</span><span class="cx">         RELEASE_ASSERT(vm()->heap.expectDoesGC());
</span><span class="cx">     if (isRope())
</span><del>-        static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec);
-    return AtomicString(m_value);
</del><ins>+        return static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec);
+    return AtomicString(valueInternal());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(ExecState* exec) const
</span><span class="lines">@@ -552,9 +801,9 @@
</span><span class="cx">         RELEASE_ASSERT(vm()->heap.expectDoesGC());
</span><span class="cx">     if (isRope())
</span><span class="cx">         return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec);
</span><del>-    if (m_value.impl()->isAtomic())
-        return static_cast<AtomicStringImpl*>(m_value.impl());
-    return AtomicStringImpl::lookUp(m_value.impl());
</del><ins>+    if (valueInternal().impl()->isAtomic())
+        return static_cast<AtomicStringImpl*>(valueInternal().impl());
+    return AtomicStringImpl::lookUp(valueInternal().impl());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline const String& JSString::value(ExecState* exec) const
</span><span class="lines">@@ -562,8 +811,8 @@
</span><span class="cx">     if (validateDFGDoesGC)
</span><span class="cx">         RELEASE_ASSERT(vm()->heap.expectDoesGC());
</span><span class="cx">     if (isRope())
</span><del>-        static_cast<const JSRopeString*>(this)->resolveRope(exec);
-    return m_value;
</del><ins>+        return static_cast<const JSRopeString*>(this)->resolveRope(exec);
+    return valueInternal();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline const String& JSString::tryGetValue(bool allocationAllowed) const
</span><span class="lines">@@ -573,11 +822,11 @@
</span><span class="cx">             RELEASE_ASSERT(vm()->heap.expectDoesGC());
</span><span class="cx">         if (isRope()) {
</span><span class="cx">             // Pass nullptr for the ExecState so that resolveRope does not throw in the event of an OOM error.
</span><del>-            static_cast<const JSRopeString*>(this)->resolveRope(nullptr);
</del><ins>+            return static_cast<const JSRopeString*>(this)->resolveRope(nullptr);
</ins><span class="cx">         }
</span><span class="cx">     } else
</span><span class="cx">         RELEASE_ASSERT(!isRope());
</span><del>-    return m_value;
</del><ins>+    return valueInternal();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
</span><span class="lines">@@ -668,11 +917,6 @@
</span><span class="cx">     return JSString::createHasOtherOwner(*vm, *s.impl());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline JSRopeString* jsStringBuilder(VM* vm)
-{
-    return JSRopeString::createNull(*vm);
-}
-
</del><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><span class="lines">@@ -753,12 +997,12 @@
</span><span class="cx">     if (validateDFGDoesGC)
</span><span class="cx">         RELEASE_ASSERT(vm()->heap.expectDoesGC());
</span><span class="cx">     if (isSubstring()) {
</span><del>-        if (is8Bit())
-            return StringView(substringBase()->m_value.characters8() + substringOffset(), length());
-        return StringView(substringBase()->m_value.characters16() + substringOffset(), length());
</del><ins>+        auto& base = substringBase()->valueInternal();
+        if (base.is8Bit())
+            return StringView(base.characters8() + substringOffset(), length());
+        return StringView(base.characters16() + substringOffset(), length());
</ins><span class="cx">     }
</span><del>-    resolveRope(exec);
-    return m_value;
</del><ins>+    return resolveRope(exec);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState* exec) const
</span><span class="lines">@@ -766,13 +1010,13 @@
</span><span class="cx">     if (validateDFGDoesGC)
</span><span class="cx">         RELEASE_ASSERT(vm()->heap.expectDoesGC());
</span><span class="cx">     if (isSubstring()) {
</span><del>-        auto& base = substringBase()->m_value;
-        if (is8Bit())
</del><ins>+        auto& base = substringBase()->valueInternal();
+        if (base.is8Bit())
</ins><span class="cx">             return { { base.characters8() + substringOffset(), length() }, base };
</span><span class="cx">         return { { base.characters16() + substringOffset(), length() }, base };
</span><span class="cx">     }
</span><del>-    resolveRope(exec);
-    return { m_value, m_value };
</del><ins>+    auto& string = resolveRope(exec);
+    return { string, string };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE StringView JSString::unsafeView(ExecState* exec) const
</span><span class="lines">@@ -781,7 +1025,7 @@
</span><span class="cx">         RELEASE_ASSERT(vm()->heap.expectDoesGC());
</span><span class="cx">     if (isRope())
</span><span class="cx">         return static_cast<const JSRopeString*>(this)->unsafeView(exec);
</span><del>-    return m_value;
</del><ins>+    return valueInternal();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE StringViewWithUnderlyingString JSString::viewWithUnderlyingString(ExecState* exec) const
</span><span class="lines">@@ -788,7 +1032,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (isRope())
</span><span class="cx">         return static_cast<const JSRopeString&>(*this).viewWithUnderlyingString(exec);
</span><del>-    return { m_value, m_value };
</del><ins>+    return { valueInternal(), valueInternal() };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool JSString::isSubstring() const
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeJSStringInlinesh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSStringInlines.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSStringInlines.h   2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/JSStringInlines.h      2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -29,11 +29,18 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx">     
</span><ins>+inline JSString::~JSString()
+{
+    if (isRope())
+        return;
+    valueInternal().~String();
+}
+
</ins><span class="cx"> bool JSString::equal(ExecState* exec, JSString* other) const
</span><span class="cx"> {
</span><span class="cx">     if (isRope() || other->isRope())
</span><span class="cx">         return equalSlowCase(exec, other);
</span><del>-    return WTF::equal(*m_value.impl(), *other->m_value.impl());
</del><ins>+    return WTF::equal(*valueInternal().impl(), *other->valueInternal().impl());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<typename StringType>
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeObjectPrototypecpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/ObjectPrototype.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/ObjectPrototype.cpp 2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/ObjectPrototype.cpp    2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -332,14 +332,8 @@
</span><span class="cx">             JSValue stringTag = toStringTagSlot.getValue(exec, toStringTagSymbol);
</span><span class="cx">             RETURN_IF_EXCEPTION(scope, { });
</span><span class="cx">             if (stringTag.isString()) {
</span><del>-                JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm);
-                ropeBuilder.append(vm.smallStrings.objectStringStart());
-                ropeBuilder.append(asString(stringTag));
-                ropeBuilder.append(vm.smallStrings.singleCharacterString(']'));
-                if (ropeBuilder.hasOverflowed())
-                    return throwOutOfMemoryError(exec, scope);
-
-                JSString* result = ropeBuilder.release();
</del><ins>+                JSString* result = jsString(exec, vm.smallStrings.objectStringStart(), asString(stringTag), vm.smallStrings.singleCharacterString(']'));
+                RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx">                 thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot);
</span><span class="cx">                 return result;
</span><span class="cx">             }
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeRegExpMatchesArrayh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpMatchesArray.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpMatchesArray.h        2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpMatchesArray.h   2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -120,7 +120,7 @@
</span><span class="cx">             int start = subpatternResults[2 * i];
</span><span class="cx">             JSValue value;
</span><span class="cx">             if (start >= 0)
</span><del>-                value = JSRopeString::createSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start);
</del><ins>+                value = jsSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start);
</ins><span class="cx">             else
</span><span class="cx">                 value = jsUndefined();
</span><span class="cx">             array->initializeIndexWithoutBarrier(scope, i, value);
</span><span class="lines">@@ -144,7 +144,7 @@
</span><span class="cx">             int start = subpatternResults[2 * i];
</span><span class="cx">             JSValue value;
</span><span class="cx">             if (start >= 0)
</span><del>-                value = JSRopeString::createSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start);
</del><ins>+                value = jsSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start);
</ins><span class="cx">             else
</span><span class="cx">                 value = jsUndefined();
</span><span class="cx">             array->initializeIndexWithoutBarrier(scope, i, value, ArrayWithContiguous);
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeRegExpObjectInlinesh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpObjectInlines.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpObjectInlines.h       2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpObjectInlines.h  2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -162,7 +162,7 @@
</span><span class="cx">     auto iterate = [&] () {
</span><span class="cx">         size_t end = result.end;
</span><span class="cx">         size_t length = end - result.start;
</span><del>-        array->putDirectIndex(exec, arrayIndex++, JSRopeString::createSubstringOfResolved(vm, string, result.start, length));
</del><ins>+        array->putDirectIndex(exec, arrayIndex++, jsSubstringOfResolved(vm, string, result.start, length));
</ins><span class="cx">         if (UNLIKELY(scope.exception())) {
</span><span class="cx">             hasException = true;
</span><span class="cx">             return;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeRegExpPrototypecpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpPrototype.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpPrototype.cpp 2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/RegExpPrototype.cpp    2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -653,7 +653,7 @@
</span><span class="cx">             return ContinueSplit;
</span><span class="cx">         },
</span><span class="cx">         [&] (bool isDefined, unsigned start, unsigned length) -> SplitControl {
</span><del>-            result->putDirectIndex(exec, resultLength++, isDefined ? JSRopeString::createSubstringOfResolved(vm, inputString, start, length) : jsUndefined());
</del><ins>+            result->putDirectIndex(exec, resultLength++, isDefined ? jsSubstringOfResolved(vm, inputString, start, length) : jsUndefined());
</ins><span class="cx">             RETURN_IF_EXCEPTION(scope, AbortSplit);
</span><span class="cx">             if (resultLength >= limit)
</span><span class="cx">                 return AbortSplit;
</span><span class="lines">@@ -667,7 +667,7 @@
</span><span class="cx">         // 20. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through size (exclusive).
</span><span class="cx">         // 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
</span><span class="cx">         scope.release();
</span><del>-        result->putDirectIndex(exec, resultLength, JSRopeString::createSubstringOfResolved(vm, inputString, position, inputSize - position));
</del><ins>+        result->putDirectIndex(exec, resultLength, jsSubstringOfResolved(vm, inputString, position, inputSize - position));
</ins><span class="cx">         
</span><span class="cx">         // 22. Return A.
</span><span class="cx">         return JSValue::encode(result);
</span><span class="lines">@@ -706,7 +706,7 @@
</span><span class="cx">             return ContinueSplit;
</span><span class="cx">         },
</span><span class="cx">         [&] (bool isDefined, unsigned start, unsigned length) -> SplitControl {
</span><del>-            result->putDirectIndex(exec, resultLength++, isDefined ? JSRopeString::createSubstringOfResolved(vm, inputString, start, length) : jsUndefined());
</del><ins>+            result->putDirectIndex(exec, resultLength++, isDefined ? jsSubstringOfResolved(vm, inputString, start, length) : jsUndefined());
</ins><span class="cx">             RETURN_IF_EXCEPTION(scope, AbortSplit);
</span><span class="cx">             if (resultLength >= limit)
</span><span class="cx">                 return AbortSplit;
</span><span class="lines">@@ -720,7 +720,7 @@
</span><span class="cx">     // 20. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through size (exclusive).
</span><span class="cx">     // 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
</span><span class="cx">     scope.release();
</span><del>-    result->putDirectIndex(exec, resultLength, JSRopeString::createSubstringOfResolved(vm, inputString, position, inputSize - position));
</del><ins>+    result->putDirectIndex(exec, resultLength, jsSubstringOfResolved(vm, inputString, position, inputSize - position));
</ins><span class="cx">     // 22. Return A.
</span><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeSmallStringscpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/SmallStrings.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/SmallStrings.cpp    2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/SmallStrings.cpp       2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -44,7 +44,9 @@
</span><span class="cx"> 
</span><span class="cx"> void SmallStrings::initializeCommonStrings(VM& vm)
</span><span class="cx"> {
</span><del>-    createEmptyString(&vm);
</del><ins>+    ASSERT(!m_emptyString);
+    m_emptyString = JSString::createEmptyString(vm);
+    ASSERT(m_needsToBeVisited);
</ins><span class="cx"> 
</span><span class="cx">     for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
</span><span class="cx">         ASSERT(!m_singleCharacterStrings[i]);
</span><span class="lines">@@ -81,13 +83,6 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SmallStrings::createEmptyString(VM* vm)
-{
-    ASSERT(!m_emptyString);
-    m_emptyString = JSString::createHasOtherOwner(*vm, *StringImpl::empty());
-    ASSERT(m_needsToBeVisited);
-}
-
</del><span class="cx"> Ref<StringImpl> SmallStrings::singleCharacterStringRep(unsigned char character)
</span><span class="cx"> {
</span><span class="cx">     if (LIKELY(m_isInitialized))
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeSmallStringsh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/SmallStrings.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/SmallStrings.h      2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/SmallStrings.h 2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -127,8 +127,6 @@
</span><span class="cx"> private:
</span><span class="cx">     static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
</span><span class="cx"> 
</span><del>-    void createEmptyString(VM*);
-
</del><span class="cx">     void initialize(VM*, JSString*&, const char* value);
</span><span class="cx"> 
</span><span class="cx">     JSString* m_emptyString { nullptr };
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeStringPrototypecpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/StringPrototype.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/StringPrototype.cpp 2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/StringPrototype.cpp    2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -45,6 +45,7 @@
</span><span class="cx"> #include "RegExpCache.h"
</span><span class="cx"> #include "RegExpConstructor.h"
</span><span class="cx"> #include "RegExpGlobalDataInlines.h"
</span><ins>+#include "StringPrototypeInlines.h"
</ins><span class="cx"> #include "SuperSampler.h"
</span><span class="cx"> #include <algorithm>
</span><span class="cx"> #include <unicode/uconfig.h>
</span><span class="lines">@@ -1141,28 +1142,19 @@
</span><span class="cx">     String s = thisValue.toWTFString(exec);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="cx"> 
</span><ins>+    JSValue a0 = exec->argument(0);
+    JSValue a1 = exec->argument(1);
+
</ins><span class="cx">     int len = s.length();
</span><span class="cx">     RELEASE_ASSERT(len >= 0);
</span><span class="cx"> 
</span><del>-    JSValue a0 = exec->argument(0);
-    JSValue a1 = exec->argument(1);
-
</del><span class="cx">     // The arg processing is very much like ArrayProtoFunc::Slice
</span><span class="cx">     double start = a0.toInteger(exec);
</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>-    double from = start < 0 ? len + start : start;
-    double to = end < 0 ? len + end : end;
-    if (to > from && to > 0 && from < len) {
-        if (from < 0)
-            from = 0;
-        if (to > len)
-            to = len;
-        return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from)));
-    }
-
-    return JSValue::encode(jsEmptyString(exec));
</del><ins>+    scope.release();
+    return JSValue::encode(stringSlice(exec, 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></pre></div>
<a id="releasesWebKitGTKwebkit224SourceJavaScriptCoreruntimeStringPrototypeInlinesh"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/StringPrototypeInlines.h (0 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/StringPrototypeInlines.h                            (rev 0)
+++ releases/WebKitGTK/webkit-2.24/Source/JavaScriptCore/runtime/StringPrototypeInlines.h       2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -0,0 +1,48 @@
</span><ins>+/*
+ * Copyright (C) 2019 Apple, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "StringPrototype.h"
+
+namespace JSC {
+
+template<typename NumberType>
+ALWAYS_INLINE JSString* stringSlice(ExecState* exec, String&& string, NumberType start, NumberType end)
+{
+    int32_t length = string.length();
+    NumberType from = start < 0 ? length + start : start;
+    NumberType to = end < 0 ? length + end : end;
+    if (to > from && to > 0 && from < length) {
+        if (from < 0)
+            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 jsEmptyString(exec);
+}
+
+} // namespace JSC
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/WTF/ChangeLog (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/WTF/ChangeLog      2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/WTF/ChangeLog 2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2019-02-28  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] sizeof(JSString) should be 16
+        https://bugs.webkit.org/show_bug.cgi?id=194375
+
+        Reviewed by Saam Barati.
+
+        * wtf/text/StringImpl.h:
+        (WTF::StringImpl::flagIs8Bit):
+        (WTF::StringImpl::flagIsAtomic):
+        (WTF::StringImpl::flagIsSymbol):
+        (WTF::StringImpl::maskStringKind):
+        * wtf/text/WTFString.cpp:
+        (WTF::nullString):
+        * wtf/text/WTFString.h:
+
</ins><span class="cx"> 2019-02-26  Mark Lam  <mark.lam@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Remove remaining poisoning code.
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceWTFwtftextStringImplh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/StringImpl.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/StringImpl.h  2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/StringImpl.h     2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -200,8 +200,8 @@
</span><span class="cx">     static constexpr const unsigned s_hashFlagStringKindIsAtomic = 1u << (s_flagStringKindCount);
</span><span class="cx">     static constexpr const unsigned s_hashFlagStringKindIsSymbol = 1u << (s_flagStringKindCount + 1);
</span><span class="cx">     static constexpr const unsigned s_hashMaskStringKind = s_hashFlagStringKindIsAtomic | s_hashFlagStringKindIsSymbol;
</span><del>-    static constexpr const unsigned s_hashFlag8BitBuffer = 1u << 3;
-    static constexpr const unsigned s_hashFlagDidReportCost = 1u << 2;
</del><ins>+    static constexpr const unsigned s_hashFlagDidReportCost = 1u << 3;
+    static constexpr const unsigned s_hashFlag8BitBuffer = 1u << 2;
</ins><span class="cx">     static constexpr const unsigned s_hashMaskBufferOwnership = (1u << 0) | (1u << 1);
</span><span class="cx"> 
</span><span class="cx">     enum StringKind {
</span><span class="lines">@@ -264,10 +264,10 @@
</span><span class="cx">     static Expected<Ref<StringImpl>, UTF8ConversionError> tryReallocate(Ref<StringImpl>&& originalString, unsigned length, UChar*& data);
</span><span class="cx"> 
</span><span class="cx">     static unsigned flagsOffset() { return OBJECT_OFFSETOF(StringImpl, m_hashAndFlags); }
</span><del>-    static unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; }
-    static unsigned flagIsAtomic() { return s_hashFlagStringKindIsAtomic; }
-    static unsigned flagIsSymbol() { return s_hashFlagStringKindIsSymbol; }
-    static unsigned maskStringKind() { return s_hashMaskStringKind; }
</del><ins>+    static constexpr unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; }
+    static constexpr unsigned flagIsAtomic() { return s_hashFlagStringKindIsAtomic; }
+    static constexpr unsigned flagIsSymbol() { return s_hashFlagStringKindIsSymbol; }
+    static constexpr unsigned maskStringKind() { return s_hashMaskStringKind; }
</ins><span class="cx">     static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data8); }
</span><span class="cx"> 
</span><span class="cx">     template<typename CharacterType, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceWTFwtftextWTFStringcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/WTFString.cpp (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/WTFString.cpp 2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/WTFString.cpp    2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -1121,6 +1121,12 @@
</span><span class="cx">     return emptyString;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+const String& nullString()
+{
+    static NeverDestroyed<String> nullString;
+    return nullString;
+}
+
</ins><span class="cx"> } // namespace WTF
</span><span class="cx"> 
</span><span class="cx"> #ifndef NDEBUG
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit224SourceWTFwtftextWTFStringh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/WTFString.h (242483 => 242484)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/WTFString.h   2019-03-05 17:22:21 UTC (rev 242483)
+++ releases/WebKitGTK/webkit-2.24/Source/WTF/wtf/text/WTFString.h      2019-03-05 17:22:38 UTC (rev 242484)
</span><span class="lines">@@ -423,8 +423,9 @@
</span><span class="cx"> 
</span><span class="cx"> template<typename CharacterType> void appendNumber(Vector<CharacterType>&, unsigned char number);
</span><span class="cx"> 
</span><del>-// Shared global empty string.
</del><ins>+// Shared global empty and null string.
</ins><span class="cx"> WTF_EXPORT_PRIVATE const String& emptyString();
</span><ins>+WTF_EXPORT_PRIVATE const String& nullString();
</ins><span class="cx"> 
</span><span class="cx"> template<typename> struct DefaultHash;
</span><span class="cx"> template<> struct DefaultHash<String> { using Hash = StringHash; };
</span><span class="lines">@@ -658,6 +659,7 @@
</span><span class="cx"> using WTF::charactersToUInt;
</span><span class="cx"> using WTF::charactersToUIntStrict;
</span><span class="cx"> using WTF::emptyString;
</span><ins>+using WTF::nullString;
</ins><span class="cx"> using WTF::equal;
</span><span class="cx"> using WTF::find;
</span><span class="cx"> using WTF::isAllSpecialCharacters;
</span></span></pre>
</div>
</div>

</body>
</html>