Changeset 242252 in webkit
- Timestamp:
- Feb 28, 2019 7:13:31 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 40 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r242213 r242252 1 2019-02-28 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] sizeof(JSString) should be 16 4 https://bugs.webkit.org/show_bug.cgi?id=194375 5 6 Reviewed by Saam Barati. 7 8 * microbenchmarks/make-rope.js: Added. 9 (makeRope): 10 * stress/to-lower-case-intrinsic-on-empty-rope.js: We no longer allow 0 length JSString except for jsEmptyString singleton per VM. 11 (returnRope.helper): Deleted. 12 (returnRope): Deleted. 13 1 14 2019-02-28 Yusuke Suzuki <ysuzuki@apple.com> 2 15 -
trunk/JSTests/stress/to-lower-case-intrinsic-on-empty-rope.js
r207377 r242252 4 4 } 5 5 6 function return Rope() {6 function returnEmptyString() { 7 7 function helper(r, s) { 8 8 // I'm paranoid about RegExp matching constant folding. … … 12 12 return helper(/(b*)fo/, "fo"); 13 13 } 14 noInline(return Rope);14 noInline(returnEmptyString); 15 15 16 16 function lower(a) { … … 20 20 21 21 for (let i = 0; i < 10000; i++) { 22 let rope = returnRope();23 assert(! rope.length);24 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.25 lower( rope);22 let notRope = returnEmptyString(); 23 assert(!notRope.length); 24 assert(!isRope(notRope)); 25 lower(notRope); 26 26 } -
trunk/Source/JavaScriptCore/ChangeLog
r242247 r242252 1 2019-02-28 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] sizeof(JSString) should be 16 4 https://bugs.webkit.org/show_bug.cgi?id=194375 5 6 Reviewed by Saam Barati. 7 8 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. 9 Both classes cut 16 bytes per instance in GC allocation. This new layout is used in 64bit architectures which has little endianess. 10 11 JSString no longer has length and flags directly. JSString has String, and we query information to this String instead of holding duplicate 12 information in JSString. We embed isRope bit into this String's pointer so that we can convert JSRopeString to JSString in an atomic manner. 13 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. 14 15 The old JSRopeString separately had JSString* fibers along with String. In this patch, we merge the first JSString* fiber and String pointer 16 storage into one to reduce the size of JSRopeString. JSRopeString has three pointer width storage. We pick 48bit effective address of JSString* 17 fibers to compress three fibers + length + flags into three pointer width storage. 18 19 In 64bit architecture, JSString and JSRopeString have the following memory layout to make sizeof(JSString) == 16 and sizeof(JSRopeString) == 32. 20 JSString has only one pointer. We use it for String. length() and is8Bit() queries go to StringImpl. In JSRopeString, we reuse the above pointer 21 place for the 1st fiber. JSRopeString has three fibers so its size is 48. To keep length and is8Bit flag information in JSRopeString, JSRopeString 22 encodes these information into the fiber pointers. is8Bit flag is encoded in the 1st fiber pointer. length is embedded directly, and two fibers 23 are compressed into 12bytes. isRope information is encoded in the first fiber's LSB. 24 25 Since length of JSRopeString should be frequently accessed compared to each fiber, we put length in contiguous 32byte field, and compress 2nd 26 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 27 are not one pointer load operation. To make concurrent collector work correctly, we must initialize 2nd and 3rd fibers at JSRopeString creation 28 and we must not modify these part later. 29 30 0 8 10 16 32 48 31 JSString [ ID ][ header ][ String pointer 0] 32 JSRopeString [ ID ][ header ][ flags ][ 1st fiber 1][ length ][2nd lower32][2nd upper16][3rd lower16][3rd upper32] 33 ^ 34 isRope bit 35 36 Since fibers in JSRopeString are not initialized in atomic pointer store manner, we must initialize all the fiber fields at JSRopeString creation. 37 To achieve this, we modify our JSRopeString::RopeBuilder implementation not to create half-baked JSRopeString. 38 39 This patch also makes an empty JSString singleton per VM. This makes evaluation of JSString in boolean context one pointer comparison. This is 40 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 41 context evaluation is bloated. This patch hides all the JSString::create and JSRopeString::create in the private permission. JSString and JSRopeString 42 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 43 JSRopeString::RopeBuilder not to construct an empty JSRopeString. 44 45 This patch is performance neutral in Speedometer2 and JetStream2. And it improves RAMification by 2.7%. 46 47 * JavaScriptCore.xcodeproj/project.pbxproj: 48 * assembler/MacroAssemblerARM64.h: 49 (JSC::MacroAssemblerARM64::storeZero16): 50 * assembler/MacroAssemblerX86Common.h: 51 (JSC::MacroAssemblerX86Common::storeZero16): 52 (JSC::MacroAssemblerX86Common::store16): 53 * bytecode/AccessCase.cpp: 54 (JSC::AccessCase::generateImpl): 55 * bytecode/InlineAccess.cpp: 56 (JSC::InlineAccess::dumpCacheSizesAndCrash): 57 (JSC::linkCodeInline): 58 (JSC::InlineAccess::isCacheableStringLength): 59 (JSC::InlineAccess::generateStringLength): 60 * bytecode/InlineAccess.h: 61 (JSC::InlineAccess::sizeForPropertyAccess): 62 (JSC::InlineAccess::sizeForPropertyReplace): 63 (JSC::InlineAccess::sizeForLengthAccess): 64 * dfg/DFGOperations.cpp: 65 * dfg/DFGOperations.h: 66 * dfg/DFGSpeculativeJIT.cpp: 67 (JSC::DFG::SpeculativeJIT::compileStringSlice): 68 (JSC::DFG::SpeculativeJIT::compileToLowerCase): 69 (JSC::DFG::SpeculativeJIT::compileGetCharCodeAt): 70 (JSC::DFG::SpeculativeJIT::compileGetByValOnString): 71 (JSC::DFG::SpeculativeJIT::compileStringEquality): 72 (JSC::DFG::SpeculativeJIT::compileStringZeroLength): 73 (JSC::DFG::SpeculativeJIT::compileLogicalNotStringOrOther): 74 (JSC::DFG::SpeculativeJIT::emitStringBranch): 75 (JSC::DFG::SpeculativeJIT::emitStringOrOtherBranch): 76 (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): 77 (JSC::DFG::SpeculativeJIT::compileGetArrayLength): 78 (JSC::DFG::SpeculativeJIT::emitPopulateSliceIndex): 79 (JSC::DFG::SpeculativeJIT::compileArraySlice): 80 (JSC::DFG::SpeculativeJIT::compileArrayIndexOf): 81 (JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage): 82 (JSC::DFG::SpeculativeJIT::emitSwitchCharStringJump): 83 (JSC::DFG::SpeculativeJIT::emitSwitchStringOnString): 84 (JSC::DFG::SpeculativeJIT::compileMakeRope): Deleted. 85 * dfg/DFGSpeculativeJIT.h: 86 * dfg/DFGSpeculativeJIT32_64.cpp: 87 (JSC::DFG::SpeculativeJIT::compile): 88 (JSC::DFG::SpeculativeJIT::compileMakeRope): 89 * dfg/DFGSpeculativeJIT64.cpp: 90 (JSC::DFG::SpeculativeJIT::compile): 91 (JSC::DFG::SpeculativeJIT::compileMakeRope): 92 * ftl/FTLAbstractHeapRepository.cpp: 93 (JSC::FTL::AbstractHeapRepository::AbstractHeapRepository): 94 * ftl/FTLAbstractHeapRepository.h: 95 * ftl/FTLLowerDFGToB3.cpp: 96 (JSC::FTL::DFG::LowerDFGToB3::compileGetIndexedPropertyStorage): 97 (JSC::FTL::DFG::LowerDFGToB3::compileGetArrayLength): 98 (JSC::FTL::DFG::LowerDFGToB3::compileMakeRope): 99 (JSC::FTL::DFG::LowerDFGToB3::compileStringCharAt): 100 (JSC::FTL::DFG::LowerDFGToB3::compileStringCharCodeAt): 101 (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq): 102 (JSC::FTL::DFG::LowerDFGToB3::compileStringToUntypedStrictEquality): 103 (JSC::FTL::DFG::LowerDFGToB3::compileSwitch): 104 (JSC::FTL::DFG::LowerDFGToB3::mapHashString): 105 (JSC::FTL::DFG::LowerDFGToB3::compileMapHash): 106 (JSC::FTL::DFG::LowerDFGToB3::compileHasOwnProperty): 107 (JSC::FTL::DFG::LowerDFGToB3::compileStringSlice): 108 (JSC::FTL::DFG::LowerDFGToB3::compileToLowerCase): 109 (JSC::FTL::DFG::LowerDFGToB3::stringsEqual): 110 (JSC::FTL::DFG::LowerDFGToB3::boolify): 111 (JSC::FTL::DFG::LowerDFGToB3::switchString): 112 (JSC::FTL::DFG::LowerDFGToB3::isRopeString): 113 (JSC::FTL::DFG::LowerDFGToB3::isNotRopeString): 114 (JSC::FTL::DFG::LowerDFGToB3::speculateStringIdent): 115 * jit/AssemblyHelpers.cpp: 116 (JSC::AssemblyHelpers::emitConvertValueToBoolean): 117 (JSC::AssemblyHelpers::branchIfValue): 118 * jit/AssemblyHelpers.h: 119 (JSC::AssemblyHelpers::branchIfRopeStringImpl): 120 (JSC::AssemblyHelpers::branchIfNotRopeStringImpl): 121 * jit/JITInlines.h: 122 (JSC::JIT::emitLoadCharacterString): 123 * jit/Repatch.cpp: 124 (JSC::tryCacheGetByID): 125 * jit/ThunkGenerators.cpp: 126 (JSC::stringGetByValGenerator): 127 (JSC::stringCharLoad): 128 * llint/LowLevelInterpreter.asm: 129 * llint/LowLevelInterpreter32_64.asm: 130 * llint/LowLevelInterpreter64.asm: 131 * runtime/JSString.cpp: 132 (JSC::JSString::createEmptyString): 133 (JSC::JSRopeString::RopeBuilder<RecordOverflow>::expand): 134 (JSC::JSString::dumpToStream): 135 (JSC::JSString::estimatedSize): 136 (JSC::JSString::visitChildren): 137 (JSC::JSRopeString::resolveRopeInternal8 const): 138 (JSC::JSRopeString::resolveRopeInternal8NoSubstring const): 139 (JSC::JSRopeString::resolveRopeInternal16 const): 140 (JSC::JSRopeString::resolveRopeInternal16NoSubstring const): 141 (JSC::JSRopeString::resolveRopeToAtomicString const): 142 (JSC::JSRopeString::convertToNonRope const): 143 (JSC::JSRopeString::resolveRopeToExistingAtomicString const): 144 (JSC::JSRopeString::resolveRopeWithFunction const): 145 (JSC::JSRopeString::resolveRope const): 146 (JSC::JSRopeString::resolveRopeSlowCase8 const): 147 (JSC::JSRopeString::resolveRopeSlowCase const): 148 (JSC::JSRopeString::outOfMemory const): 149 (JSC::JSRopeString::visitFibers): Deleted. 150 (JSC::JSRopeString::clearFibers const): Deleted. 151 * runtime/JSString.h: 152 (JSC::JSString::uninitializedValueInternal const): 153 (JSC::JSString::valueInternal const): 154 (JSC::JSString::JSString): 155 (JSC::JSString::finishCreation): 156 (JSC::JSString::create): 157 (JSC::JSString::offsetOfValue): 158 (JSC::JSString::isRope const): 159 (JSC::JSString::is8Bit const): 160 (JSC::JSString::length const): 161 (JSC::JSString::tryGetValueImpl const): 162 (JSC::JSString::toAtomicString const): 163 (JSC::JSString::toExistingAtomicString const): 164 (JSC::JSString::value const): 165 (JSC::JSString::tryGetValue const): 166 (JSC::JSRopeString::unsafeView const): 167 (JSC::JSRopeString::viewWithUnderlyingString const): 168 (JSC::JSString::unsafeView const): 169 (JSC::JSString::viewWithUnderlyingString const): 170 (JSC::JSString::offsetOfLength): Deleted. 171 (JSC::JSString::offsetOfFlags): Deleted. 172 (JSC::JSString::setIs8Bit const): Deleted. 173 (JSC::JSString::setLength): Deleted. 174 (JSC::JSString::string): Deleted. 175 (JSC::jsStringBuilder): Deleted. 176 * runtime/JSStringInlines.h: 177 (JSC::JSString::~JSString): 178 (JSC::JSString::equal const): 179 * runtime/ObjectPrototype.cpp: 180 (JSC::objectProtoFuncToString): 181 * runtime/RegExpMatchesArray.h: 182 (JSC::createRegExpMatchesArray): 183 * runtime/RegExpObjectInlines.h: 184 (JSC::collectMatches): 185 * runtime/RegExpPrototype.cpp: 186 (JSC::regExpProtoFuncSplitFast): 187 * runtime/SmallStrings.cpp: 188 (JSC::SmallStrings::initializeCommonStrings): 189 (JSC::SmallStrings::createEmptyString): Deleted. 190 * runtime/SmallStrings.h: 191 * runtime/StringPrototype.cpp: 192 (JSC::stringProtoFuncSlice): 193 * runtime/StringPrototypeInlines.h: Added. 194 (JSC::stringSlice): 195 1 196 2019-02-28 Saam barati <sbarati@apple.com> 2 197 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r242123 r242252 1740 1740 E322E5A71DA644A8006E7709 /* FTLSnippetParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E322E5A51DA644A4006E7709 /* FTLSnippetParams.h */; }; 1741 1741 E325956421FDA2C9008EDC9C /* RegExpGlobalDataInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E325956321FDA2C8008EDC9C /* RegExpGlobalDataInlines.h */; }; 1742 E325A36022211590007349A1 /* StringPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E325A35F2221158A007349A1 /* StringPrototypeInlines.h */; }; 1742 1743 E3282BBB1FE930AF00EDAF71 /* YarrErrorCode.h in Headers */ = {isa = PBXBuildFile; fileRef = E3282BBA1FE930A400EDAF71 /* YarrErrorCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1743 1744 E328C6C71DA4304500D255FD /* MaxFrameExtentForSlowPathCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 65860177185A8F5E00030EEE /* MaxFrameExtentForSlowPathCall.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 4670 4671 E322E5A51DA644A4006E7709 /* FTLSnippetParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSnippetParams.h; path = ftl/FTLSnippetParams.h; sourceTree = "<group>"; }; 4671 4672 E325956321FDA2C8008EDC9C /* RegExpGlobalDataInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpGlobalDataInlines.h; sourceTree = "<group>"; }; 4673 E325A35F2221158A007349A1 /* StringPrototypeInlines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringPrototypeInlines.h; sourceTree = "<group>"; }; 4672 4674 E326C4961ECBEF5700A9A905 /* ClassInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClassInfo.cpp; sourceTree = "<group>"; }; 4673 4675 E3282BB91FE930A300EDAF71 /* YarrErrorCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrErrorCode.cpp; path = yarr/YarrErrorCode.cpp; sourceTree = "<group>"; }; … … 7167 7169 BC18C3C50E16EE3300B34460 /* StringPrototype.cpp */, 7168 7170 BC18C3C60E16EE3300B34460 /* StringPrototype.h */, 7171 E325A35F2221158A007349A1 /* StringPrototypeInlines.h */, 7169 7172 93345A8712D838C400302BE3 /* StringRecursionChecker.cpp */, 7170 7173 93345A8812D838C400302BE3 /* StringRecursionChecker.h */, … … 9698 9701 BC18C4680E16F5CD00B34460 /* StringObject.h in Headers */, 9699 9702 BC18C46A0E16F5CD00B34460 /* StringPrototype.h in Headers */, 9703 E325A36022211590007349A1 /* StringPrototypeInlines.h in Headers */, 9700 9704 142E313B134FF0A600AFADB5 /* Strong.h in Headers */, 9701 9705 145722861437E140005FDE26 /* StrongInlines.h in Headers */, -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
r239427 r242252 1541 1541 } 1542 1542 1543 void storeZero16(ImplicitAddress address) 1544 { 1545 store16(ARM64Registers::zr, address); 1546 } 1547 1548 void storeZero16(BaseIndex address) 1549 { 1550 store16(ARM64Registers::zr, address); 1551 } 1552 1543 1553 void store8(RegisterID src, BaseIndex address) 1544 1554 { -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
r239427 r242252 1349 1349 } 1350 1350 1351 void storeZero16(ImplicitAddress address) 1352 { 1353 store16(TrustedImm32(0), address); 1354 } 1355 1356 void storeZero16(BaseIndex address) 1357 { 1358 store16(TrustedImm32(0), address); 1359 } 1360 1351 1361 void store8(TrustedImm32 imm, Address address) 1352 1362 { … … 1435 1445 } 1436 1446 1437 void store16(TrustedImm32 imm, Address address)1447 void store16(TrustedImm32 imm, ImplicitAddress address) 1438 1448 { 1439 1449 m_assembler.movw_im(static_cast<int16_t>(imm.m_value), address.offset, address.base); -
trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp
r242123 r242252 1214 1214 1215 1215 case StringLength: { 1216 jit.load32(CCallHelpers::Address(baseGPR, JSString::offsetOfLength()), valueRegs.payloadGPR()); 1217 jit.boxInt32(valueRegs.payloadGPR(), valueRegs); 1216 jit.loadPtr(CCallHelpers::Address(baseGPR, JSString::offsetOfValue()), scratchGPR); 1217 auto isRope = jit.branchIfRopeStringImpl(scratchGPR); 1218 jit.load32(CCallHelpers::Address(scratchGPR, StringImpl::lengthMemoryOffset()), scratchGPR); 1219 auto done = jit.jump(); 1220 1221 isRope.link(&jit); 1222 jit.load32(CCallHelpers::Address(baseGPR, JSRopeString::offsetOfLength()), scratchGPR); 1223 1224 done.link(&jit); 1225 jit.boxInt32(scratchGPR, valueRegs); 1218 1226 state.succeed(); 1219 1227 return; -
trunk/Source/JavaScriptCore/bytecode/InlineAccess.cpp
r236584 r242252 51 51 CCallHelpers jit; 52 52 53 GPRReg scratchGPR = value; 53 54 jit.patchableBranch8( 54 55 CCallHelpers::NotEqual, 55 56 CCallHelpers::Address(base, JSCell::typeInfoTypeOffset()), 56 57 CCallHelpers::TrustedImm32(StringType)); 57 jit.load32(CCallHelpers::Address(base, JSString::offsetOfLength()), regs.payloadGPR()); 58 59 jit.loadPtr(CCallHelpers::Address(base, JSString::offsetOfValue()), scratchGPR); 60 auto isRope = jit.branchIfRopeStringImpl(scratchGPR); 61 jit.load32(CCallHelpers::Address(scratchGPR, StringImpl::lengthMemoryOffset()), regs.payloadGPR()); 62 auto done = jit.jump(); 63 64 isRope.link(&jit); 65 jit.load32(CCallHelpers::Address(base, JSRopeString::offsetOfLength()), regs.payloadGPR()); 66 67 done.link(&jit); 58 68 jit.boxInt32(regs.payloadGPR(), regs); 59 69 … … 144 154 { 145 155 if (jit.m_assembler.buffer().codeSize() <= stubInfo.patch.inlineSize()) { 146 bool needsBranchCompaction = false;156 bool needsBranchCompaction = true; 147 157 LinkBuffer linkBuffer(jit, stubInfo.patch.start, stubInfo.patch.inlineSize(), JITCompilationMustSucceed, needsBranchCompaction); 148 158 ASSERT(linkBuffer.isValid()); … … 157 167 // of randomness. It's helpful to flip this on when running tests or browsing 158 168 // the web just to see how often it fails. You don't want an IC size that always fails. 159 const bool failIfCantInline = false;169 constexpr bool failIfCantInline = false; 160 170 if (failIfCantInline) { 161 171 dataLog("Failure for: ", name, "\n"); … … 289 299 } 290 300 301 bool InlineAccess::isCacheableStringLength(StructureStubInfo& stubInfo) 302 { 303 return hasFreeRegister(stubInfo); 304 } 305 291 306 bool InlineAccess::generateStringLength(StructureStubInfo& stubInfo) 292 307 { 293 CCallHelpers jit; 294 295 GPRReg base = stubInfo.baseGPR(); 296 JSValueRegs value = stubInfo.valueRegs(); 308 ASSERT(isCacheableStringLength(stubInfo)); 309 310 CCallHelpers jit; 311 312 GPRReg base = stubInfo.baseGPR(); 313 JSValueRegs value = stubInfo.valueRegs(); 314 GPRReg scratch = getScratchRegister(stubInfo); 297 315 298 316 auto branchToSlowPath = jit.patchableBranch8( … … 300 318 CCallHelpers::Address(base, JSCell::typeInfoTypeOffset()), 301 319 CCallHelpers::TrustedImm32(StringType)); 302 jit.load32(CCallHelpers::Address(base, JSString::offsetOfLength()), value.payloadGPR()); 320 321 jit.loadPtr(CCallHelpers::Address(base, JSString::offsetOfValue()), scratch); 322 auto isRope = jit.branchIfRopeStringImpl(scratch); 323 jit.load32(CCallHelpers::Address(scratch, StringImpl::lengthMemoryOffset()), value.payloadGPR()); 324 auto done = jit.jump(); 325 326 isRope.link(&jit); 327 jit.load32(CCallHelpers::Address(base, JSRopeString::offsetOfLength()), value.payloadGPR()); 328 329 done.link(&jit); 303 330 jit.boxInt32(value.payloadGPR(), value); 304 331 -
trunk/Source/JavaScriptCore/bytecode/InlineAccess.h
r238439 r242252 45 45 { 46 46 #if CPU(X86_64) 47 return 2 3;47 return 26; 48 48 #elif CPU(X86) 49 49 return 27; … … 63 63 { 64 64 #if CPU(X86_64) 65 return 2 3;65 return 26; 66 66 #elif CPU(X86) 67 67 return 27; … … 84 84 { 85 85 #if CPU(X86_64) 86 size_t size = 26;86 size_t size = 43; 87 87 #elif CPU(X86) 88 88 size_t size = 27; 89 89 #elif CPU(ARM64) 90 size_t size = 32;90 size_t size = 44; 91 91 #elif CPU(ARM_THUMB2) 92 92 size_t size = 30; … … 103 103 static bool generateSelfPropertyReplace(StructureStubInfo&, Structure*, PropertyOffset); 104 104 static bool isCacheableArrayLength(StructureStubInfo&, JSArray*); 105 static bool isCacheableStringLength(StructureStubInfo&); 105 106 static bool generateArrayLength(StructureStubInfo&, JSArray*); 106 107 static void rewireStubAsJump(StructureStubInfo&, CodeLocationLabel<JITStubRoutinePtrTag>); … … 112 113 // its placeholder code here, and log the size. That way we 113 114 // can intelligently choose sizes on various platforms. 114 NO_RETURN_DUE_TO_CRASH static void dumpCacheSizesAndCrash();115 JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void dumpCacheSizesAndCrash(); 115 116 }; 116 117 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r242192 r242252 72 72 #include "ScopedArguments.h" 73 73 #include "StringConstructor.h" 74 #include "StringPrototypeInlines.h" 74 75 #include "SuperSampler.h" 75 76 #include "Symbol.h" … … 2156 2157 RETURN_IF_EXCEPTION(scope, nullptr); 2157 2158 return jsSubstring(exec, string, from, span); 2159 } 2160 2161 JSCell* JIT_OPERATION operationStringSlice(ExecState* exec, JSCell* cell, int32_t start, int32_t end) 2162 { 2163 VM& vm = exec->vm(); 2164 NativeCallFrameTracer tracer(&vm, exec); 2165 auto scope = DECLARE_THROW_SCOPE(vm); 2166 2167 auto string = jsCast<JSString*>(cell)->value(exec); 2168 RETURN_IF_EXCEPTION(scope, nullptr); 2169 static_assert(static_cast<uint64_t>(JSString::MaxLength) <= static_cast<uint64_t>(std::numeric_limits<int32_t>::max()), ""); 2170 2171 scope.release(); 2172 return stringSlice(exec, WTFMove(string), start, end); 2158 2173 } 2159 2174 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r240327 r242252 204 204 205 205 JSCell* JIT_OPERATION operationStringSubstr(ExecState*, JSCell*, int32_t, int32_t); 206 JSCell* JIT_OPERATION operationStringSlice(ExecState*, JSCell*, int32_t, int32_t); 206 207 JSString* JIT_OPERATION operationStringValueOf(ExecState*, EncodedJSValue); 207 208 JSString* JIT_OPERATION operationToLowerCase(ExecState*, JSString*, uint32_t); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r242123 r242252 1531 1531 { 1532 1532 SpeculateCellOperand string(this, node->child1()); 1533 1534 GPRReg stringGPR = string.gpr(); 1535 1536 speculateString(node->child1(), stringGPR); 1537 1538 SpeculateInt32Operand start(this, node->child2()); 1539 GPRReg startGPR = start.gpr(); 1540 1541 Optional<SpeculateInt32Operand> end; 1542 Optional<GPRReg> endGPR; 1543 if (node->child3()) { 1544 end.emplace(this, node->child3()); 1545 endGPR.emplace(end->gpr()); 1546 } 1547 1548 GPRTemporary temp(this); 1549 GPRReg tempGPR = temp.gpr(); 1550 1551 m_jit.loadPtr(CCallHelpers::Address(stringGPR, JSString::offsetOfValue()), tempGPR); 1552 auto isRope = m_jit.branchIfRopeStringImpl(tempGPR); 1553 1554 GPRTemporary temp2(this); 1533 1555 GPRTemporary startIndex(this); 1534 GPRTemporary temp(this); 1535 GPRTemporary temp2(this); 1536 1537 GPRReg stringGPR = string.gpr(); 1556 1557 GPRReg temp2GPR = temp2.gpr(); 1538 1558 GPRReg startIndexGPR = startIndex.gpr(); 1539 GPRReg tempGPR = temp.gpr();1540 GPRReg temp2GPR = temp2.gpr();1541 1542 speculateString(node->child1(), stringGPR);1543 1544 1559 { 1545 m_jit.load32(JITCompiler::Address(stringGPR, JSString::offsetOfLength()), temp2GPR); 1546 1547 emitPopulateSliceIndex(node->child2(), temp2GPR, startIndexGPR); 1560 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), temp2GPR); 1561 1562 emitPopulateSliceIndex(node->child2(), startGPR, temp2GPR, startIndexGPR); 1563 1548 1564 if (node->child3()) 1549 emitPopulateSliceIndex(node->child3(), temp2GPR, tempGPR);1565 emitPopulateSliceIndex(node->child3(), endGPR.value(), temp2GPR, tempGPR); 1550 1566 else 1551 1567 m_jit.move(temp2GPR, tempGPR); … … 1563 1579 slowCases.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(1))); 1564 1580 1581 // Refill StringImpl* here. 1565 1582 m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), temp2GPR); 1566 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, temp2GPR));1567 1568 1583 m_jit.loadPtr(MacroAssembler::Address(temp2GPR, StringImpl::dataOffset()), tempGPR); 1569 1584 … … 1587 1602 m_jit.loadPtr(tempGPR, tempGPR); 1588 1603 1589 addSlowPathGenerator( 1590 slowPathCall( 1591 bigCharacter, this, operationSingleCharacterString, tempGPR, tempGPR)); 1592 1593 addSlowPathGenerator( 1594 slowPathCall( 1595 slowCases, this, operationStringSubstr, tempGPR, stringGPR, startIndexGPR, tempGPR)); 1604 addSlowPathGenerator(slowPathCall(bigCharacter, this, operationSingleCharacterString, tempGPR, tempGPR)); 1605 1606 addSlowPathGenerator(slowPathCall(slowCases, this, operationStringSubstr, tempGPR, stringGPR, startIndexGPR, tempGPR)); 1607 1608 if (endGPR) 1609 addSlowPathGenerator(slowPathCall(isRope, this, operationStringSlice, tempGPR, stringGPR, startGPR, *endGPR)); 1610 else 1611 addSlowPathGenerator(slowPathCall(isRope, this, operationStringSlice, tempGPR, stringGPR, startGPR, TrustedImm32(std::numeric_limits<int32_t>::max()))); 1596 1612 1597 1613 doneCases.link(&m_jit); … … 1621 1637 1622 1638 m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), tempGPR); 1623 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, tempGPR)); 1624 1639 slowPath.append(m_jit.branchIfRopeStringImpl(tempGPR)); 1625 1640 slowPath.append(m_jit.branchTest32( 1626 1641 MacroAssembler::Zero, MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()), … … 2129 2144 ASSERT(speculationChecked(m_state.forNode(node->child1()).m_type, SpecString)); 2130 2145 2131 // unsigned comparison so we can filter out negative indices and indices that are too large2132 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, MacroAssembler::Address(stringReg, JSString::offsetOfLength())));2133 2134 2146 GPRTemporary scratch(this); 2135 2147 GPRReg scratchReg = scratch.gpr(); 2136 2148 2137 2149 m_jit.loadPtr(MacroAssembler::Address(stringReg, JSString::offsetOfValue()), scratchReg); 2150 2151 // unsigned comparison so we can filter out negative indices and indices that are too large 2152 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, CCallHelpers::Address(scratchReg, StringImpl::lengthMemoryOffset()))); 2138 2153 2139 2154 // Load the character into scratchReg … … 2176 2191 2177 2192 // unsigned comparison so we can filter out negative indices and indices that are too large 2193 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg); 2178 2194 JITCompiler::Jump outOfBounds = m_jit.branch32( 2179 2195 MacroAssembler::AboveOrEqual, propertyReg, 2180 MacroAssembler::Address( baseReg, JSString::offsetOfLength()));2196 MacroAssembler::Address(scratchReg, StringImpl::lengthMemoryOffset())); 2181 2197 if (node->arrayMode().isInBounds()) 2182 2198 speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds); 2183 2184 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);2185 2199 2186 2200 // Load the character into scratchReg … … 4329 4343 break; 4330 4344 } 4331 }4332 4333 void SpeculativeJIT::compileMakeRope(Node* node)4334 {4335 ASSERT(node->child1().useKind() == KnownStringUse);4336 ASSERT(node->child2().useKind() == KnownStringUse);4337 ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse);4338 4339 SpeculateCellOperand op1(this, node->child1());4340 SpeculateCellOperand op2(this, node->child2());4341 SpeculateCellOperand op3(this, node->child3());4342 GPRTemporary result(this);4343 GPRTemporary allocator(this);4344 GPRTemporary scratch(this);4345 4346 GPRReg opGPRs[3];4347 unsigned numOpGPRs;4348 opGPRs[0] = op1.gpr();4349 opGPRs[1] = op2.gpr();4350 if (node->child3()) {4351 opGPRs[2] = op3.gpr();4352 numOpGPRs = 3;4353 } else {4354 opGPRs[2] = InvalidGPRReg;4355 numOpGPRs = 2;4356 }4357 GPRReg resultGPR = result.gpr();4358 GPRReg allocatorGPR = allocator.gpr();4359 GPRReg scratchGPR = scratch.gpr();4360 4361 JITCompiler::JumpList slowPath;4362 Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSRopeString>(*m_jit.vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists);4363 emitAllocateJSCell(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.vm()->stringStructure.get())), scratchGPR, slowPath);4364 4365 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSString::offsetOfValue()));4366 for (unsigned i = 0; i < numOpGPRs; ++i)4367 m_jit.storePtr(opGPRs[i], JITCompiler::Address(resultGPR, JSRopeString::offsetOfFibers() + sizeof(WriteBarrier<JSString>) * i));4368 for (unsigned i = numOpGPRs; i < JSRopeString::s_maxInternalRopeLength; ++i)4369 m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSRopeString::offsetOfFibers() + sizeof(WriteBarrier<JSString>) * i));4370 m_jit.load16(JITCompiler::Address(opGPRs[0], JSString::offsetOfFlags()), scratchGPR);4371 m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfLength()), allocatorGPR);4372 if (!ASSERT_DISABLED) {4373 JITCompiler::Jump ok = m_jit.branch32(4374 JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));4375 m_jit.abortWithReason(DFGNegativeStringLength);4376 ok.link(&m_jit);4377 }4378 for (unsigned i = 1; i < numOpGPRs; ++i) {4379 m_jit.and16(JITCompiler::Address(opGPRs[i], JSString::offsetOfFlags()), scratchGPR);4380 speculationCheck(4381 Uncountable, JSValueSource(), nullptr,4382 m_jit.branchAdd32(4383 JITCompiler::Overflow,4384 JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR));4385 }4386 m_jit.and32(JITCompiler::TrustedImm32(JSString::Is8Bit), scratchGPR);4387 m_jit.store16(scratchGPR, JITCompiler::Address(resultGPR, JSString::offsetOfFlags()));4388 if (!ASSERT_DISABLED) {4389 JITCompiler::Jump ok = m_jit.branch32(4390 JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));4391 m_jit.abortWithReason(DFGNegativeStringLength);4392 ok.link(&m_jit);4393 }4394 m_jit.store32(allocatorGPR, JITCompiler::Address(resultGPR, JSString::offsetOfLength()));4395 4396 m_jit.mutatorFence(*m_jit.vm());4397 4398 switch (numOpGPRs) {4399 case 2:4400 addSlowPathGenerator(slowPathCall(4401 slowPath, this, operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]));4402 break;4403 case 3:4404 addSlowPathGenerator(slowPathCall(4405 slowPath, this, operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]));4406 break;4407 default:4408 RELEASE_ASSERT_NOT_REACHED();4409 break;4410 }4411 4412 cellResult(resultGPR, node);4413 4345 } 4414 4346 … … 6321 6253 falseCase.append(fastFalse); 6322 6254 6323 m_jit.load32(MacroAssembler::Address(leftGPR, JSString::offsetOfLength()), lengthGPR); 6255 m_jit.loadPtr(MacroAssembler::Address(leftGPR, JSString::offsetOfValue()), leftTempGPR); 6256 m_jit.loadPtr(MacroAssembler::Address(rightGPR, JSString::offsetOfValue()), rightTempGPR); 6257 6258 slowCase.append(m_jit.branchIfRopeStringImpl(leftTempGPR)); 6259 slowCase.append(m_jit.branchIfRopeStringImpl(rightTempGPR)); 6260 6261 m_jit.load32(MacroAssembler::Address(leftTempGPR, StringImpl::lengthMemoryOffset()), lengthGPR); 6324 6262 6325 6263 falseCase.append(m_jit.branch32( 6326 6264 MacroAssembler::NotEqual, 6327 MacroAssembler::Address(right GPR, JSString::offsetOfLength()),6265 MacroAssembler::Address(rightTempGPR, StringImpl::lengthMemoryOffset()), 6328 6266 lengthGPR)); 6329 6267 6330 6268 trueCase.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR)); 6331 6332 m_jit.loadPtr(MacroAssembler::Address(leftGPR, JSString::offsetOfValue()), leftTempGPR);6333 m_jit.loadPtr(MacroAssembler::Address(rightGPR, JSString::offsetOfValue()), rightTempGPR);6334 6335 slowCase.append(m_jit.branchTestPtr(MacroAssembler::Zero, leftTempGPR));6336 slowCase.append(m_jit.branchTestPtr(MacroAssembler::Zero, rightTempGPR));6337 6269 6338 6270 slowCase.append(m_jit.branchTest32( … … 6639 6571 GPRReg eqGPR = eq.gpr(); 6640 6572 6641 // Fetch the length field from the string object. 6642 m_jit.test32(MacroAssembler::Zero, MacroAssembler::Address(strGPR, JSString::offsetOfLength()), MacroAssembler::TrustedImm32(-1), eqGPR); 6643 6573 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), eqGPR); 6574 m_jit.comparePtr(CCallHelpers::Equal, strGPR, eqGPR, eqGPR); 6644 6575 unblessedBooleanResult(eqGPR, node); 6645 6576 } … … 6656 6587 DFG_TYPE_CHECK( 6657 6588 valueRegs, node->child1(), (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR)); 6658 m_jit.test32( 6659 JITCompiler::Zero, JITCompiler::Address(cellGPR, JSString::offsetOfLength()), 6660 JITCompiler::TrustedImm32(-1), tempGPR); 6661 JITCompiler::Jump done = m_jit.jump(); 6589 6590 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), tempGPR); 6591 m_jit.comparePtr(CCallHelpers::Equal, cellGPR, tempGPR, tempGPR); 6592 auto done = m_jit.jump(); 6593 6662 6594 notCell.link(&m_jit); 6663 6595 DFG_TYPE_CHECK( 6664 6596 valueRegs, node->child1(), SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR)); 6665 6597 m_jit.move(TrustedImm32(1), tempGPR); 6598 6666 6599 done.link(&m_jit); 6667 6668 6600 unblessedBooleanResult(tempGPR, node); 6669 6601 … … 6673 6605 { 6674 6606 SpeculateCellOperand str(this, nodeUse); 6675 speculateString(nodeUse, str.gpr()); 6676 branchTest32(JITCompiler::NonZero, MacroAssembler::Address(str.gpr(), JSString::offsetOfLength()), taken); 6677 jump(notTaken); 6607 6608 GPRReg strGPR = str.gpr(); 6609 6610 speculateString(nodeUse, strGPR); 6611 6612 branchPtr(CCallHelpers::Equal, strGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), notTaken); 6613 jump(taken); 6614 6678 6615 noResult(m_currentNode); 6679 6616 } … … 6689 6626 GPRReg cellGPR = valueRegs.payloadGPR(); 6690 6627 DFG_TYPE_CHECK(valueRegs, nodeUse, (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR)); 6691 branchTest32( 6692 JITCompiler::Zero, JITCompiler::Address(cellGPR, JSString::offsetOfLength()), 6693 JITCompiler::TrustedImm32(-1), notTaken); 6628 6629 branchPtr(CCallHelpers::Equal, cellGPR, TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(m_jit.vm())), notTaken); 6694 6630 jump(taken, ForceJump); 6631 6695 6632 notCell.link(&m_jit); 6696 6633 DFG_TYPE_CHECK( … … 6741 6678 addSlowPathGenerator( 6742 6679 slowPathCall( 6743 m_jit.branch Test32(MacroAssembler::Zero,storageReg),6680 m_jit.branchIfRopeStringImpl(storageReg), 6744 6681 this, operationResolveRope, storageReg, baseReg)); 6745 6682 … … 6993 6930 SpeculateCellOperand base(this, node->child1()); 6994 6931 GPRTemporary result(this, Reuse, base); 6932 GPRTemporary temp(this); 6995 6933 GPRReg baseGPR = base.gpr(); 6996 6934 GPRReg resultGPR = result.gpr(); 6997 m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); 6935 GPRReg tempGPR = temp.gpr(); 6936 6937 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSString::offsetOfValue()), tempGPR); 6938 auto isRope = m_jit.branchIfRopeStringImpl(tempGPR); 6939 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), resultGPR); 6940 auto done = m_jit.jump(); 6941 6942 isRope.link(&m_jit); 6943 m_jit.load32(CCallHelpers::Address(baseGPR, JSRopeString::offsetOfLength()), resultGPR); 6944 6945 done.link(&m_jit); 6998 6946 int32Result(resultGPR, node); 6999 6947 break; … … 8140 8088 } 8141 8089 8142 void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, GPRReg length, GPRReg result)8090 void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, Optional<GPRReg> indexGPR, GPRReg lengthGPR, GPRReg resultGPR) 8143 8091 { 8144 8092 if (target->isInt32Constant()) { 8145 8093 int32_t value = target->asInt32(); 8146 8094 if (value == 0) { 8147 m_jit.move(TrustedImm32(0), result );8095 m_jit.move(TrustedImm32(0), resultGPR); 8148 8096 return; 8149 8097 } … … 8151 8099 MacroAssembler::JumpList done; 8152 8100 if (value > 0) { 8153 m_jit.move(TrustedImm32(value), result );8154 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result , length));8155 m_jit.move(length , result);8101 m_jit.move(TrustedImm32(value), resultGPR); 8102 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR)); 8103 m_jit.move(lengthGPR, resultGPR); 8156 8104 } else { 8157 8105 ASSERT(value != 0); 8158 m_jit.move(length , result);8159 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, TrustedImm32(value), result ));8160 m_jit.move(TrustedImm32(0), result );8106 m_jit.move(lengthGPR, resultGPR); 8107 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, TrustedImm32(value), resultGPR)); 8108 m_jit.move(TrustedImm32(0), resultGPR); 8161 8109 } 8162 8110 done.link(&m_jit); … … 8164 8112 } 8165 8113 8166 SpeculateInt32Operand index(this, target); 8167 GPRReg indexGPR = index.gpr(); 8114 Optional<SpeculateInt32Operand> index; 8115 if (!indexGPR) { 8116 index.emplace(this, target); 8117 indexGPR = index->gpr(); 8118 } 8168 8119 MacroAssembler::JumpList done; 8169 8120 8170 auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR , TrustedImm32(0));8171 m_jit.move(length , result);8172 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR , result));8173 m_jit.move(TrustedImm32(0), result );8121 auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR.value(), TrustedImm32(0)); 8122 m_jit.move(lengthGPR, resultGPR); 8123 done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR.value(), resultGPR)); 8124 m_jit.move(TrustedImm32(0), resultGPR); 8174 8125 done.append(m_jit.jump()); 8175 8126 8176 8127 isPositive.link(&m_jit); 8177 m_jit.move(indexGPR , result);8178 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result , length));8179 m_jit.move(length , result);8128 m_jit.move(indexGPR.value(), resultGPR); 8129 done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, resultGPR, lengthGPR)); 8130 m_jit.move(lengthGPR, resultGPR); 8180 8131 8181 8132 done.link(&m_jit); … … 8205 8156 8206 8157 if (node->numChildren() == 4) 8207 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), lengthGPR, tempGPR);8158 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, tempGPR); 8208 8159 else 8209 8160 m_jit.move(lengthGPR, tempGPR); … … 8215 8166 GPRTemporary tempStartIndex(this); 8216 8167 GPRReg startGPR = tempStartIndex.gpr(); 8217 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), lengthGPR, startGPR);8168 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, lengthGPR, startGPR); 8218 8169 8219 8170 auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR); … … 8304 8255 m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue); 8305 8256 if (node->numChildren() == 4) 8306 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), tempValue, tempGPR);8257 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, tempValue, tempGPR); 8307 8258 else 8308 8259 m_jit.move(tempValue, tempGPR); 8309 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), tempValue, loadIndex);8260 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), WTF::nullopt, tempValue, loadIndex); 8310 8261 } 8311 8262 … … 8361 8312 8362 8313 if (node->numChildren() == 4) 8363 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), lengthGPR, indexGPR);8314 emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), WTF::nullopt, lengthGPR, indexGPR); 8364 8315 else 8365 8316 m_jit.move(TrustedImm32(0), indexGPR); … … 10138 10089 speculationCheck( 10139 10090 BadType, JSValueSource::unboxedCell(string), edge, 10140 m_jit.branch TestPtr(MacroAssembler::Zero,storage));10091 m_jit.branchIfRopeStringImpl(storage)); 10141 10092 speculationCheck( 10142 10093 BadType, JSValueSource::unboxedCell(string), edge, m_jit.branchTest32( … … 10529 10480 SwitchData* data, GPRReg value, GPRReg scratch) 10530 10481 { 10482 m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch); 10483 auto isRope = m_jit.branchIfRopeStringImpl(scratch); 10484 10531 10485 addBranch( 10532 10486 m_jit.branch32( 10533 10487 MacroAssembler::NotEqual, 10534 MacroAssembler::Address( value, JSString::offsetOfLength()),10488 MacroAssembler::Address(scratch, StringImpl::lengthMemoryOffset()), 10535 10489 TrustedImm32(1)), 10536 10490 data->fallThrough.block); 10537 10491 10538 m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch); 10539 10540 addSlowPathGenerator( 10541 slowPathCall( 10542 m_jit.branchTestPtr(MacroAssembler::Zero, scratch), 10543 this, operationResolveRope, scratch, value)); 10492 addSlowPathGenerator(slowPathCall(isRope, this, operationResolveRope, scratch, value)); 10544 10493 10545 10494 m_jit.loadPtr(MacroAssembler::Address(scratch, StringImpl::dataOffset()), value); … … 10784 10733 GPRReg tempGPR = temp.gpr(); 10785 10734 10786 m_jit.load32(MacroAssembler::Address(string, JSString::offsetOfLength()), lengthGPR);10735 MacroAssembler::JumpList slowCases; 10787 10736 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), tempGPR); 10788 10789 MacroAssembler::JumpList slowCases;10790 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, tempGPR));10737 slowCases.append(m_jit.branchIfRopeStringImpl(tempGPR)); 10738 m_jit.load32(MacroAssembler::Address(tempGPR, StringImpl::lengthMemoryOffset()), lengthGPR); 10739 10791 10740 slowCases.append(m_jit.branchTest32( 10792 10741 MacroAssembler::Zero, -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r242123 r242252 1543 1543 void emitGetCallee(CodeOrigin, GPRReg calleeGPR); 1544 1544 void emitGetArgumentStart(CodeOrigin, GPRReg startGPR); 1545 void emitPopulateSliceIndex(Edge&, GPRReg length, GPRReg result);1545 void emitPopulateSliceIndex(Edge&, Optional<GPRReg> indexGPR, GPRReg lengthGPR, GPRReg resultGPR); 1546 1546 1547 1547 // Generate an OSR exit fuzz check. Returns Jump() if OSR exit fuzz is not enabled, or if -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r240327 r242252 3881 3881 speculateString(node->child2(), keyRegs.payloadGPR()); 3882 3882 m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR); 3883 slowPath.append(m_jit.branch TestPtr(MacroAssembler::Zero,implGPR));3883 slowPath.append(m_jit.branchIfRopeStringImpl(implGPR)); 3884 3884 slowPath.append(m_jit.branchTest32( 3885 3885 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()), … … 3891 3891 auto isNotString = m_jit.branchIfNotString(keyRegs.payloadGPR()); 3892 3892 m_jit.loadPtr(MacroAssembler::Address(keyRegs.payloadGPR(), JSString::offsetOfValue()), implGPR); 3893 slowPath.append(m_jit.branch TestPtr(MacroAssembler::Zero,implGPR));3893 slowPath.append(m_jit.branchIfRopeStringImpl(implGPR)); 3894 3894 slowPath.append(m_jit.branchTest32( 3895 3895 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()), … … 4196 4196 } 4197 4197 4198 void SpeculativeJIT::compileMakeRope(Node* node) 4199 { 4200 ASSERT(node->child1().useKind() == KnownStringUse); 4201 ASSERT(node->child2().useKind() == KnownStringUse); 4202 ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse); 4203 4204 SpeculateCellOperand op1(this, node->child1()); 4205 SpeculateCellOperand op2(this, node->child2()); 4206 SpeculateCellOperand op3(this, node->child3()); 4207 4208 GPRReg opGPRs[3]; 4209 unsigned numOpGPRs; 4210 opGPRs[0] = op1.gpr(); 4211 opGPRs[1] = op2.gpr(); 4212 if (node->child3()) { 4213 opGPRs[2] = op3.gpr(); 4214 numOpGPRs = 3; 4215 } else { 4216 opGPRs[2] = InvalidGPRReg; 4217 numOpGPRs = 2; 4218 } 4219 4220 flushRegisters(); 4221 GPRFlushedCallResult result(this); 4222 GPRReg resultGPR = result.gpr(); 4223 switch (numOpGPRs) { 4224 case 2: 4225 callOperation(operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1]); 4226 m_jit.exceptionCheck(); 4227 break; 4228 case 3: 4229 callOperation(operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2]); 4230 m_jit.exceptionCheck(); 4231 break; 4232 default: 4233 RELEASE_ASSERT_NOT_REACHED(); 4234 break; 4235 } 4236 4237 cellResult(resultGPR, node); 4238 } 4239 4198 4240 #endif 4199 4241 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r242015 r242252 4039 4039 4040 4040 m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR); 4041 slowPath.append(m_jit.branch TestPtr(MacroAssembler::Zero,resultGPR));4041 slowPath.append(m_jit.branchIfRopeStringImpl(resultGPR)); 4042 4042 m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR); 4043 4043 m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR); … … 4077 4077 straightHash.append(m_jit.branchIfNotString(inputGPR)); 4078 4078 m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR); 4079 slowPath.append(m_jit.branch TestPtr(MacroAssembler::Zero,resultGPR));4079 slowPath.append(m_jit.branchIfRopeStringImpl(resultGPR)); 4080 4080 m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR); 4081 4081 m_jit.urshift32(MacroAssembler::TrustedImm32(StringImpl::s_flagCount), resultGPR); … … 4451 4451 speculateString(node->child2(), keyGPR); 4452 4452 m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR); 4453 slowPath.append(m_jit.branch TestPtr(MacroAssembler::Zero,implGPR));4453 slowPath.append(m_jit.branchIfRopeStringImpl(implGPR)); 4454 4454 slowPath.append(m_jit.branchTest32( 4455 4455 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()), … … 4461 4461 auto isNotString = m_jit.branchIfNotString(keyGPR); 4462 4462 m_jit.loadPtr(MacroAssembler::Address(keyGPR, JSString::offsetOfValue()), implGPR); 4463 slowPath.append(m_jit.branch TestPtr(MacroAssembler::Zero,implGPR));4463 slowPath.append(m_jit.branchIfRopeStringImpl(implGPR)); 4464 4464 slowPath.append(m_jit.branchTest32( 4465 4465 MacroAssembler::Zero, MacroAssembler::Address(implGPR, StringImpl::flagsOffset()), … … 5231 5231 } 5232 5232 5233 void SpeculativeJIT::compileMakeRope(Node* node) 5234 { 5235 ASSERT(node->child1().useKind() == KnownStringUse); 5236 ASSERT(node->child2().useKind() == KnownStringUse); 5237 ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse); 5238 5239 SpeculateCellOperand op1(this, node->child1()); 5240 SpeculateCellOperand op2(this, node->child2()); 5241 SpeculateCellOperand op3(this, node->child3()); 5242 GPRTemporary result(this); 5243 GPRTemporary allocator(this); 5244 GPRTemporary scratch(this); 5245 GPRTemporary scratch2(this); 5246 5247 Edge edges[3] = { 5248 node->child1(), 5249 node->child2(), 5250 node->child3() 5251 }; 5252 GPRReg opGPRs[3]; 5253 unsigned numOpGPRs; 5254 opGPRs[0] = op1.gpr(); 5255 opGPRs[1] = op2.gpr(); 5256 if (node->child3()) { 5257 opGPRs[2] = op3.gpr(); 5258 numOpGPRs = 3; 5259 } else { 5260 opGPRs[2] = InvalidGPRReg; 5261 numOpGPRs = 2; 5262 } 5263 GPRReg resultGPR = result.gpr(); 5264 GPRReg allocatorGPR = allocator.gpr(); 5265 GPRReg scratchGPR = scratch.gpr(); 5266 GPRReg scratch2GPR = scratch2.gpr(); 5267 5268 CCallHelpers::JumpList slowPath; 5269 Allocator allocatorValue = allocatorForNonVirtualConcurrently<JSRopeString>(*m_jit.vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists); 5270 emitAllocateJSCell(resultGPR, JITAllocator::constant(allocatorValue), allocatorGPR, TrustedImmPtr(m_jit.graph().registerStructure(m_jit.vm()->stringStructure.get())), scratchGPR, slowPath); 5271 5272 m_jit.orPtr(TrustedImm32(JSString::isRopeInPointer), opGPRs[0], allocatorGPR); 5273 m_jit.storePtr(allocatorGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber0())); 5274 5275 m_jit.move(opGPRs[1], scratchGPR); 5276 m_jit.store32(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber1Lower())); 5277 m_jit.rshiftPtr(TrustedImm32(32), scratchGPR); 5278 m_jit.store16(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber1Upper())); 5279 5280 if (numOpGPRs == 3) { 5281 m_jit.move(opGPRs[2], scratchGPR); 5282 m_jit.store32(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2Lower())); 5283 m_jit.rshiftPtr(TrustedImm32(32), scratchGPR); 5284 m_jit.store16(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2Upper())); 5285 } else { 5286 m_jit.storeZero32(CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2Lower())); 5287 m_jit.storeZero16(CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFiber2Upper())); 5288 } 5289 5290 { 5291 if (JSString* string = edges[0]->dynamicCastConstant<JSString*>(*m_jit.vm())) { 5292 m_jit.move(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR); 5293 m_jit.move(TrustedImm32(string->length()), allocatorGPR); 5294 } else { 5295 bool canBeRope = !m_state.forNode(edges[0]).isType(SpecStringIdent); 5296 m_jit.loadPtr(CCallHelpers::Address(opGPRs[0], JSString::offsetOfValue()), scratch2GPR); 5297 CCallHelpers::Jump isRope; 5298 if (canBeRope) 5299 isRope = m_jit.branchIfRopeStringImpl(scratch2GPR); 5300 5301 m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR); 5302 m_jit.load32(CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR); 5303 5304 if (canBeRope) { 5305 auto done = m_jit.jump(); 5306 5307 isRope.link(&m_jit); 5308 m_jit.load16(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfFlags()), scratchGPR); 5309 m_jit.load32(CCallHelpers::Address(opGPRs[0], JSRopeString::offsetOfLength()), allocatorGPR); 5310 done.link(&m_jit); 5311 } 5312 } 5313 5314 if (!ASSERT_DISABLED) { 5315 CCallHelpers::Jump ok = m_jit.branch32( 5316 CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0)); 5317 m_jit.abortWithReason(DFGNegativeStringLength); 5318 ok.link(&m_jit); 5319 } 5320 } 5321 5322 for (unsigned i = 1; i < numOpGPRs; ++i) { 5323 if (JSString* string = edges[i]->dynamicCastConstant<JSString*>(*m_jit.vm())) { 5324 m_jit.and32(TrustedImm32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), scratchGPR); 5325 speculationCheck( 5326 Uncountable, JSValueSource(), nullptr, 5327 m_jit.branchAdd32( 5328 CCallHelpers::Overflow, 5329 TrustedImm32(string->length()), allocatorGPR)); 5330 } else { 5331 bool canBeRope = !m_state.forNode(edges[i]).isType(SpecStringIdent); 5332 m_jit.loadPtr(CCallHelpers::Address(opGPRs[i], JSString::offsetOfValue()), scratch2GPR); 5333 CCallHelpers::Jump isRope; 5334 if (canBeRope) 5335 isRope = m_jit.branchIfRopeStringImpl(scratch2GPR); 5336 5337 m_jit.and16(CCallHelpers::Address(scratch2GPR, StringImpl::flagsOffset()), scratchGPR); 5338 speculationCheck( 5339 Uncountable, JSValueSource(), nullptr, 5340 m_jit.branchAdd32( 5341 CCallHelpers::Overflow, 5342 CCallHelpers::Address(scratch2GPR, StringImpl::lengthMemoryOffset()), allocatorGPR)); 5343 if (canBeRope) { 5344 auto done = m_jit.jump(); 5345 5346 isRope.link(&m_jit); 5347 m_jit.and16(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfFlags()), scratchGPR); 5348 m_jit.load32(CCallHelpers::Address(opGPRs[i], JSRopeString::offsetOfLength()), scratch2GPR); 5349 speculationCheck( 5350 Uncountable, JSValueSource(), nullptr, 5351 m_jit.branchAdd32( 5352 CCallHelpers::Overflow, scratch2GPR, allocatorGPR)); 5353 done.link(&m_jit); 5354 } 5355 } 5356 } 5357 m_jit.store16(scratchGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfFlags())); 5358 if (!ASSERT_DISABLED) { 5359 CCallHelpers::Jump ok = m_jit.branch32( 5360 CCallHelpers::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0)); 5361 m_jit.abortWithReason(DFGNegativeStringLength); 5362 ok.link(&m_jit); 5363 } 5364 m_jit.store32(allocatorGPR, CCallHelpers::Address(resultGPR, JSRopeString::offsetOfLength())); 5365 auto isNonEmptyString = m_jit.branchTest32(CCallHelpers::NonZero, allocatorGPR); 5366 5367 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(&m_jit.graph().m_vm)), resultGPR); 5368 5369 isNonEmptyString.link(&m_jit); 5370 m_jit.mutatorFence(*m_jit.vm()); 5371 5372 switch (numOpGPRs) { 5373 case 2: 5374 addSlowPathGenerator(slowPathCall( 5375 slowPath, this, operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1])); 5376 break; 5377 case 3: 5378 addSlowPathGenerator(slowPathCall( 5379 slowPath, this, operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2])); 5380 break; 5381 default: 5382 RELEASE_ASSERT_NOT_REACHED(); 5383 break; 5384 } 5385 5386 cellResult(resultGPR, node); 5387 } 5388 5233 5389 #endif 5234 5390 -
trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp
r240593 r242252 61 61 , ArrayStorage_publicLength(Butterfly_publicLength) 62 62 , ArrayStorage_vectorLength(Butterfly_vectorLength) 63 , JSBigInt_length(JSBigIntOrString_length)64 , JSString_length(JSBigIntOrString_length)65 63 66 64 #define INDEXED_ABSTRACT_HEAP_INITIALIZATION(name, offset, size) , name(&root, #name, offset, size) … … 72 70 #undef NUMBERED_ABSTRACT_HEAP_INITIALIZATION 73 71 72 , JSString_value(JSRopeString_fiber0) 73 74 74 , absolute(&root, "absolute") 75 75 { … … 80 80 RELEASE_ASSERT(JSCell_indexingTypeAndMisc.offset() + 3 == JSCell_cellState.offset()); 81 81 82 RELEASE_ASSERT(JSBigInt::offsetOfLength() == JSString::offsetOfLength());83 84 82 JSCell_structureID.changeParent(&JSCell_header); 85 83 JSCell_usefulBytes.changeParent(&JSCell_header); … … 88 86 JSCell_typeInfoFlags.changeParent(&JSCell_usefulBytes); 89 87 JSCell_cellState.changeParent(&JSCell_usefulBytes); 88 JSRopeString_flags.changeParent(&JSRopeString_fiber0); 90 89 91 90 RELEASE_ASSERT(!JSCell_freeListNext.offset()); -
trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
r240593 r242252 65 65 macro(JSArrayBufferView_mode, JSArrayBufferView::offsetOfMode()) \ 66 66 macro(JSArrayBufferView_vector, JSArrayBufferView::offsetOfVector()) \ 67 macro(JSBigInt OrString_length, JSBigInt::offsetOfLength()) \67 macro(JSBigInt_length, JSBigInt::offsetOfLength()) \ 68 68 macro(JSCell_cellState, JSCell::cellStateOffset()) \ 69 69 macro(JSCell_header, 0) \ … … 89 89 macro(JSPropertyNameEnumerator_endStructurePropertyIndex, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()) \ 90 90 macro(JSPropertyNameEnumerator_indexLength, JSPropertyNameEnumerator::indexedLengthOffset()) \ 91 macro(JSRopeString_flags, JSRopeString::offsetOfFlags()) \ 92 macro(JSRopeString_fiber0, JSRopeString::offsetOfFiber0()) \ 93 macro(JSRopeString_length, JSRopeString::offsetOfLength()) \ 94 macro(JSRopeString_fiber1Lower, JSRopeString::offsetOfFiber1Lower()) \ 95 macro(JSRopeString_fiber1Upper, JSRopeString::offsetOfFiber1Upper()) \ 96 macro(JSRopeString_fiber2Lower, JSRopeString::offsetOfFiber2Lower()) \ 97 macro(JSRopeString_fiber2Upper, JSRopeString::offsetOfFiber2Upper()) \ 91 98 macro(JSScope_next, JSScope::offsetOfNext()) \ 92 macro(JSString_flags, JSString::offsetOfFlags()) \93 macro(JSString_value, JSString::offsetOfValue()) \94 99 macro(JSSymbolTableObject_symbolTable, JSSymbolTableObject::offsetOfSymbolTable()) \ 95 100 macro(JSWrapperObject_internalValue, JSWrapperObject::internalValueOffset()) \ … … 141 146 macro(JSLexicalEnvironment_variables, JSLexicalEnvironment::offsetOfVariables(), sizeof(EncodedJSValue)) \ 142 147 macro(JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, 0, sizeof(WriteBarrier<JSString>)) \ 143 macro(JSRopeString_fibers, JSRopeString::offsetOfFibers(), sizeof(WriteBarrier<JSString>)) \144 148 macro(ScopedArguments_Storage_storage, 0, sizeof(EncodedJSValue)) \ 145 149 macro(WriteBarrierBuffer_bufferContents, 0, sizeof(JSCell*)) \ … … 181 185 AbstractHeap& ArrayStorage_publicLength; 182 186 AbstractHeap& ArrayStorage_vectorLength; 183 AbstractHeap& JSBigInt_length;184 AbstractHeap& JSString_length;185 187 186 188 #define INDEXED_ABSTRACT_HEAP_DECLARATION(name, offset, size) IndexedAbstractHeap name; … … 191 193 FOR_EACH_NUMBERED_ABSTRACT_HEAP(NUMBERED_ABSTRACT_HEAP_DECLARATION) 192 194 #undef NUMBERED_ABSTRACT_HEAP_DECLARATION 195 196 AbstractHeap& JSString_value; 193 197 194 198 AbsoluteAbstractHeap absolute; -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r242123 r242252 3653 3653 ValueFromBlock fastResult = m_out.anchor(fastResultValue); 3654 3654 3655 m_out.branch( 3656 m_out.notNull(fastResultValue), usually(continuation), rarely(slowPath)); 3655 m_out.branch(isRopeString(cell, m_node->child1()), rarely(slowPath), usually(continuation)); 3657 3656 3658 3657 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation); … … 3826 3825 case Array::String: { 3827 3826 LValue string = lowCell(m_node->child1()); 3828 setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length)); 3827 3828 LBasicBlock ropePath = m_out.newBlock(); 3829 LBasicBlock nonRopePath = m_out.newBlock(); 3830 LBasicBlock continuation = m_out.newBlock(); 3831 3832 m_out.branch(isRopeString(string, m_node->child1()), rarely(ropePath), usually(nonRopePath)); 3833 3834 LBasicBlock lastNext = m_out.appendTo(ropePath, nonRopePath); 3835 ValueFromBlock ropeLength = m_out.anchor(m_out.load32NonNegative(string, m_heaps.JSRopeString_length)); 3836 m_out.jump(continuation); 3837 3838 m_out.appendTo(nonRopePath, continuation); 3839 ValueFromBlock nonRopeLength = m_out.anchor(m_out.load32NonNegative(m_out.loadPtr(string, m_heaps.JSString_value), m_heaps.StringImpl_length)); 3840 m_out.jump(continuation); 3841 3842 m_out.appendTo(continuation, lastNext); 3843 setInt32(m_out.phi(Int32, ropeLength, nonRopeLength)); 3829 3844 return; 3830 3845 } … … 6488 6503 void compileMakeRope() 6489 6504 { 6505 struct FlagsAndLength { 6506 LValue flags; 6507 LValue length; 6508 }; 6509 6510 Edge edges[3] = { 6511 m_node->child1(), 6512 m_node->child2(), 6513 m_node->child3(), 6514 }; 6490 6515 LValue kids[3]; 6491 6516 unsigned numKids; 6492 kids[0] = lowCell( m_node->child1());6493 kids[1] = lowCell( m_node->child2());6494 if ( m_node->child3()) {6495 kids[2] = lowCell( m_node->child3());6517 kids[0] = lowCell(edges[0]); 6518 kids[1] = lowCell(edges[1]); 6519 if (edges[2]) { 6520 kids[2] = lowCell(edges[2]); 6496 6521 numKids = 3; 6497 6522 } else { … … 6503 6528 LBasicBlock continuation = m_out.newBlock(); 6504 6529 6505 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);6506 6507 6530 Allocator allocator = allocatorForNonVirtualConcurrently<JSRopeString>(vm(), sizeof(JSRopeString), AllocatorForMode::AllocatorIfExists); 6508 6531 … … 6510 6533 m_out.constIntPtr(allocator.localAllocator()), vm().stringStructure.get(), slowPath); 6511 6534 6512 m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSString_value); 6513 for (unsigned i = 0; i < numKids; ++i) 6514 m_out.storePtr(kids[i], result, m_heaps.JSRopeString_fibers[i]); 6515 for (unsigned i = numKids; i < JSRopeString::s_maxInternalRopeLength; ++i) 6516 m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSRopeString_fibers[i]); 6517 LValue flags = m_out.load16ZeroExt32(kids[0], m_heaps.JSString_flags); 6518 LValue length = m_out.load32(kids[0], m_heaps.JSString_length); 6535 m_out.storePtr(m_out.bitOr(kids[0], m_out.constIntPtr(JSString::isRopeInPointer)), result, m_heaps.JSRopeString_fiber0); 6536 6537 m_out.store32(m_out.castToInt32(kids[1]), result, m_heaps.JSRopeString_fiber1Lower); 6538 m_out.store32As16(m_out.castToInt32(m_out.lShr(kids[1], m_out.constInt32(32))), result, m_heaps.JSRopeString_fiber1Upper); 6539 6540 if (numKids == 3) { 6541 m_out.store32(m_out.castToInt32(kids[2]), result, m_heaps.JSRopeString_fiber2Lower); 6542 m_out.store32As16(m_out.castToInt32(m_out.lShr(kids[2], m_out.constInt32(32))), result, m_heaps.JSRopeString_fiber2Upper); 6543 } else { 6544 m_out.store32(m_out.int32Zero, result, m_heaps.JSRopeString_fiber2Lower); 6545 m_out.store32As16(m_out.int32Zero, result, m_heaps.JSRopeString_fiber2Upper); 6546 } 6547 6548 auto getFlagsAndLength = [&] (Edge& edge, LValue child) { 6549 if (JSString* string = edge->dynamicCastConstant<JSString*>(vm())) { 6550 return FlagsAndLength { 6551 m_out.constInt32(string->is8Bit() ? StringImpl::flagIs8Bit() : 0), 6552 m_out.constInt32(string->length()) 6553 }; 6554 } 6555 6556 LBasicBlock continuation = m_out.newBlock(); 6557 LBasicBlock ropeCase = m_out.newBlock(); 6558 LBasicBlock notRopeCase = m_out.newBlock(); 6559 6560 m_out.branch(isRopeString(child, edge), unsure(ropeCase), unsure(notRopeCase)); 6561 6562 LBasicBlock lastNext = m_out.appendTo(ropeCase, notRopeCase); 6563 ValueFromBlock flagsForRope = m_out.anchor(m_out.load16ZeroExt32(child, m_heaps.JSRopeString_flags)); 6564 ValueFromBlock lengthForRope = m_out.anchor(m_out.load32NonNegative(child, m_heaps.JSRopeString_length)); 6565 m_out.jump(continuation); 6566 6567 m_out.appendTo(notRopeCase, continuation); 6568 LValue stringImpl = m_out.loadPtr(child, m_heaps.JSString_value); 6569 ValueFromBlock flagsForNonRope = m_out.anchor(m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_hashAndFlags)); 6570 ValueFromBlock lengthForNonRope = m_out.anchor(m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_length)); 6571 m_out.jump(continuation); 6572 6573 m_out.appendTo(continuation, lastNext); 6574 return FlagsAndLength { 6575 m_out.phi(Int32, flagsForRope, flagsForNonRope), 6576 m_out.phi(Int32, lengthForRope, lengthForNonRope) 6577 }; 6578 }; 6579 6580 FlagsAndLength flagsAndLength = getFlagsAndLength(edges[0], kids[0]); 6519 6581 for (unsigned i = 1; i < numKids; ++i) { 6520 flags = m_out.bitAnd(flags, m_out.load16ZeroExt32(kids[i], m_heaps.JSString_flags)); 6521 CheckValue* lengthCheck = m_out.speculateAdd( 6522 length, m_out.load32(kids[i], m_heaps.JSString_length)); 6523 blessSpeculation(lengthCheck, Uncountable, noValue(), nullptr, m_origin); 6524 length = lengthCheck; 6525 } 6526 m_out.store32As16( 6527 m_out.bitAnd(m_out.constInt32(JSString::Is8Bit), flags), 6528 result, m_heaps.JSString_flags); 6529 m_out.store32(length, result, m_heaps.JSString_length); 6582 auto mergeFlagsAndLength = [&] (Edge& edge, LValue child, FlagsAndLength previousFlagsAndLength) { 6583 FlagsAndLength flagsAndLength = getFlagsAndLength(edge, child); 6584 LValue flags = m_out.bitAnd(previousFlagsAndLength.flags, flagsAndLength.flags); 6585 CheckValue* lengthCheck = m_out.speculateAdd(previousFlagsAndLength.length, flagsAndLength.length); 6586 blessSpeculation(lengthCheck, Uncountable, noValue(), nullptr, m_origin); 6587 return FlagsAndLength { 6588 flags, 6589 lengthCheck 6590 }; 6591 }; 6592 flagsAndLength = mergeFlagsAndLength(edges[i], kids[i], flagsAndLength); 6593 } 6594 m_out.store32As16(flagsAndLength.flags, result, m_heaps.JSRopeString_flags); 6595 m_out.store32(flagsAndLength.length, result, m_heaps.JSRopeString_length); 6530 6596 6531 6597 mutatorFence(); 6532 ValueFromBlock fastResult = m_out.anchor( result);6598 ValueFromBlock fastResult = m_out.anchor(m_out.select(m_out.isZero32(flagsAndLength.length), weakPointer(jsEmptyString(&m_graph.m_vm)), result)); 6533 6599 m_out.jump(continuation); 6534 6600 6535 m_out.appendTo(slowPath, continuation);6601 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation); 6536 6602 LValue slowResultValue; 6537 6603 VM& vm = this->vm(); … … 6574 6640 LBasicBlock continuation = m_out.newBlock(); 6575 6641 6642 LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value); 6576 6643 m_out.branch( 6577 6644 m_out.aboveOrEqual( 6578 index, m_out.load32NonNegative( base, m_heaps.JSString_length)),6645 index, m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_length)), 6579 6646 rarely(slowPath), usually(fastPath)); 6580 6647 6581 6648 LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath); 6582 6583 LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);6584 6649 6585 6650 LBasicBlock is8Bit = m_out.newBlock(); … … 6684 6749 LValue storage = lowStorage(m_node->child3()); 6685 6750 6751 LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value); 6752 6686 6753 speculate( 6687 6754 Uncountable, noValue(), 0, 6688 6755 m_out.aboveOrEqual( 6689 index, m_out.load32NonNegative(base, m_heaps.JSString_length))); 6690 6691 LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value); 6756 index, m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_length))); 6692 6757 6693 6758 m_out.branch( … … 7203 7268 speculateString(m_node->child2(), right); 7204 7269 7205 ValueFromBlock slowResult = m_out.anchor(stringsEqual(left, right ));7270 ValueFromBlock slowResult = m_out.anchor(stringsEqual(left, right, m_node->child1(), m_node->child2())); 7206 7271 m_out.jump(continuation); 7207 7272 … … 7377 7442 // Full String compare. 7378 7443 m_out.appendTo(testStringEquality, continuation); 7379 ValueFromBlock slowResult = m_out.anchor(stringsEqual(leftString, rightValue ));7444 ValueFromBlock slowResult = m_out.anchor(stringsEqual(leftString, rightValue, stringEdge, untypedEdge)); 7380 7445 m_out.jump(continuation); 7381 7446 … … 9027 9092 LBasicBlock continuation = m_out.newBlock(); 9028 9093 9094 ValueFromBlock fastValue = m_out.anchor(m_out.loadPtr(stringValue, m_heaps.JSString_value)); 9095 m_out.branch( 9096 isRopeString(stringValue, m_node->child1()), 9097 rarely(needResolution), usually(resolved)); 9098 9099 LBasicBlock lastNext = m_out.appendTo(needResolution, resolved); 9100 ValueFromBlock slowValue = m_out.anchor( 9101 vmCall(pointerType(), m_out.operation(operationResolveRope), m_callFrame, stringValue)); 9102 m_out.jump(resolved); 9103 9104 m_out.appendTo(resolved, lengthIs1); 9105 LValue value = m_out.phi(pointerType(), fastValue, slowValue); 9029 9106 m_out.branch( 9030 9107 m_out.notEqual( 9031 m_out.load32NonNegative( stringValue, m_heaps.JSString_length),9108 m_out.load32NonNegative(value, m_heaps.StringImpl_length), 9032 9109 m_out.int32One), 9033 9110 unsure(lowBlock(data->fallThrough.block)), unsure(lengthIs1)); 9034 9035 LBasicBlock lastNext = m_out.appendTo(lengthIs1, needResolution); 9036 Vector<ValueFromBlock, 2> values; 9037 LValue fastValue = m_out.loadPtr(stringValue, m_heaps.JSString_value); 9038 values.append(m_out.anchor(fastValue)); 9039 m_out.branch(m_out.isNull(fastValue), rarely(needResolution), usually(resolved)); 9040 9041 m_out.appendTo(needResolution, resolved); 9042 values.append(m_out.anchor( 9043 vmCall(pointerType(), m_out.operation(operationResolveRope), m_callFrame, stringValue))); 9044 m_out.jump(resolved); 9045 9046 m_out.appendTo(resolved, is8Bit); 9047 LValue value = m_out.phi(pointerType(), values); 9111 9112 m_out.appendTo(lengthIs1, is8Bit); 9048 9113 LValue characterData = m_out.loadPtr(value, m_heaps.StringImpl_data); 9049 9114 m_out.branch( … … 9087 9152 9088 9153 case StringUse: { 9089 switchString(data, lowString(m_node->child1()) );9154 switchString(data, lowString(m_node->child1()), m_node->child1()); 9090 9155 return; 9091 9156 } … … 9109 9174 m_out.appendTo(isStringBlock, lastNext); 9110 9175 9111 switchString(data, value );9176 switchString(data, value, m_node->child1()); 9112 9177 return; 9113 9178 } … … 9447 9512 } 9448 9513 9449 LValue mapHashString(LValue string )9514 LValue mapHashString(LValue string, Edge& edge) 9450 9515 { 9451 9516 LBasicBlock nonEmptyStringCase = m_out.newBlock(); … … 9453 9518 LBasicBlock continuation = m_out.newBlock(); 9454 9519 9520 m_out.branch(isRopeString(string, edge), rarely(slowCase), usually(nonEmptyStringCase)); 9521 9522 LBasicBlock lastNext = m_out.appendTo(nonEmptyStringCase, slowCase); 9455 9523 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value); 9456 m_out.branch(9457 m_out.equal(stringImpl, m_out.constIntPtr(0)), unsure(slowCase), unsure(nonEmptyStringCase));9458 9459 LBasicBlock lastNext = m_out.appendTo(nonEmptyStringCase, slowCase);9460 9524 LValue hash = m_out.lShr(m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount)); 9461 9525 ValueFromBlock nonEmptyStringHashResult = m_out.anchor(hash); … … 9496 9560 9497 9561 LBasicBlock lastNext = m_out.appendTo(isString, notString); 9498 ValueFromBlock stringResult = m_out.anchor(mapHashString(value ));9562 ValueFromBlock stringResult = m_out.anchor(mapHashString(value, m_node->child1())); 9499 9563 m_out.jump(continuation); 9500 9564 … … 9510 9574 case StringUse: { 9511 9575 LValue string = lowString(m_node->child1()); 9512 setInt32(mapHashString(string ));9576 setInt32(mapHashString(string, m_node->child1())); 9513 9577 return; 9514 9578 } … … 9537 9601 9538 9602 m_out.appendTo(isStringCase, nonEmptyStringCase); 9603 m_out.branch(isRopeString(value, m_node->child1()), rarely(slowCase), usually(nonEmptyStringCase)); 9604 9605 m_out.appendTo(nonEmptyStringCase, straightHash); 9539 9606 LValue stringImpl = m_out.loadPtr(value, m_heaps.JSString_value); 9540 m_out.branch(9541 m_out.equal(stringImpl, m_out.constIntPtr(0)), rarely(slowCase), usually(nonEmptyStringCase));9542 9543 m_out.appendTo(nonEmptyStringCase, straightHash);9544 9607 LValue hash = m_out.lShr(m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::s_flagCount)); 9545 9608 ValueFromBlock nonEmptyStringHashResult = m_out.anchor(hash); … … 10139 10202 10140 10203 keyAsValue = lowString(m_node->child2()); 10204 m_out.branch(isNotRopeString(keyAsValue, m_node->child2()), usually(isNonEmptyString), rarely(slowCase)); 10205 10206 lastNext = m_out.appendTo(isNonEmptyString, isAtomicString); 10141 10207 uniquedStringImpl = m_out.loadPtr(keyAsValue, m_heaps.JSString_value); 10142 m_out.branch(m_out.notNull(uniquedStringImpl), usually(isNonEmptyString), rarely(slowCase));10143 10144 lastNext = m_out.appendTo(isNonEmptyString, isAtomicString);10145 10208 LValue isNotAtomic = m_out.testIsZero32(m_out.load32(uniquedStringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic())); 10146 10209 m_out.branch(isNotAtomic, rarely(slowCase), usually(isAtomicString)); … … 10170 10233 10171 10234 m_out.appendTo(isStringCase, isNonEmptyString); 10235 m_out.branch(isNotRopeString(keyAsValue, m_node->child2()), usually(isNonEmptyString), rarely(slowCase)); 10236 10237 m_out.appendTo(isNonEmptyString, notStringCase); 10172 10238 LValue implFromString = m_out.loadPtr(keyAsValue, m_heaps.JSString_value); 10173 10239 ValueFromBlock stringResult = m_out.anchor(implFromString); 10174 m_out.branch(m_out.notNull(implFromString), usually(isNonEmptyString), rarely(slowCase));10175 10176 m_out.appendTo(isNonEmptyString, notStringCase);10177 10240 LValue isNotAtomic = m_out.testIsZero32(m_out.load32(implFromString, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(StringImpl::flagIsAtomic())); 10178 10241 m_out.branch(isNotAtomic, rarely(slowCase), usually(hasUniquedStringImpl)); … … 11912 11975 void compileStringSlice() 11913 11976 { 11977 LBasicBlock lengthCheckCase = m_out.newBlock(); 11914 11978 LBasicBlock emptyCase = m_out.newBlock(); 11915 11979 LBasicBlock notEmptyCase = m_out.newBlock(); 11916 11980 LBasicBlock oneCharCase = m_out.newBlock(); 11917 LBasicBlock bitCheckCase = m_out.newBlock();11918 11981 LBasicBlock is8Bit = m_out.newBlock(); 11919 11982 LBasicBlock is16Bit = m_out.newBlock(); … … 11921 11984 LBasicBlock bigCharacter = m_out.newBlock(); 11922 11985 LBasicBlock slowCase = m_out.newBlock(); 11986 LBasicBlock ropeSlowCase = m_out.newBlock(); 11923 11987 LBasicBlock continuation = m_out.newBlock(); 11924 11988 11925 11989 LValue string = lowString(m_node->child1()); 11926 LValue length = m_out.load32NonNegative(string, m_heaps.JSString_length);11927 11990 LValue start = lowInt32(m_node->child2()); 11928 11991 LValue end = nullptr; 11929 11992 if (m_node->child3()) 11930 11993 end = lowInt32(m_node->child3()); 11931 11994 else 11995 end = m_out.constInt32(std::numeric_limits<int32_t>::max()); 11996 m_out.branch(isRopeString(string, m_node->child1()), rarely(ropeSlowCase), usually(lengthCheckCase)); 11997 11998 LBasicBlock lastNext = m_out.appendTo(lengthCheckCase, emptyCase); 11999 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value); 12000 LValue length = m_out.load32NonNegative(stringImpl, m_heaps.StringImpl_length); 11932 12001 auto range = populateSliceRange(start, end, length); 11933 12002 LValue from = range.first; 11934 12003 LValue to = range.second; 11935 11936 12004 LValue span = m_out.sub(to, from); 11937 12005 m_out.branch(m_out.lessThanOrEqual(span, m_out.int32Zero), unsure(emptyCase), unsure(notEmptyCase)); 11938 12006 11939 Vector<ValueFromBlock, 4> results;11940 11941 LBasicBlock lastNext =m_out.appendTo(emptyCase, notEmptyCase);12007 Vector<ValueFromBlock, 5> results; 12008 12009 m_out.appendTo(emptyCase, notEmptyCase); 11942 12010 results.append(m_out.anchor(weakPointer(jsEmptyString(&vm())))); 11943 12011 m_out.jump(continuation); … … 11946 12014 m_out.branch(m_out.equal(span, m_out.int32One), unsure(oneCharCase), unsure(slowCase)); 11947 12015 11948 m_out.appendTo(oneCharCase, bitCheckCase); 11949 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value); 11950 m_out.branch(m_out.isNull(stringImpl), unsure(slowCase), unsure(bitCheckCase)); 11951 11952 m_out.appendTo(bitCheckCase, is8Bit); 12016 m_out.appendTo(oneCharCase, is8Bit); 11953 12017 LValue storage = m_out.loadPtr(stringImpl, m_heaps.StringImpl_data); 11954 12018 m_out.branch( … … 11959 12023 11960 12024 m_out.appendTo(is8Bit, is16Bit); 11961 // FIXME: Need to cage strings!11962 // https://bugs.webkit.org/show_bug.cgi?id=17492411963 12025 ValueFromBlock char8Bit = m_out.anchor(m_out.load8ZeroExt32(m_out.baseIndex(m_heaps.characters8, storage, m_out.zeroExtPtr(from)))); 11964 12026 m_out.jump(bitsContinuation); … … 11984 12046 m_out.jump(continuation); 11985 12047 11986 m_out.appendTo(slowCase, continuation);12048 m_out.appendTo(slowCase, ropeSlowCase); 11987 12049 results.append(m_out.anchor(vmCall(pointerType(), m_out.operation(operationStringSubstr), m_callFrame, string, from, span))); 12050 m_out.jump(continuation); 12051 12052 m_out.appendTo(ropeSlowCase, continuation); 12053 results.append(m_out.anchor(vmCall(pointerType(), m_out.operation(operationStringSlice), m_callFrame, string, start, end))); 11988 12054 m_out.jump(continuation); 11989 12055 … … 12004 12070 ValueFromBlock startIndex = m_out.anchor(m_out.constInt32(0)); 12005 12071 ValueFromBlock startIndexForCall = m_out.anchor(m_out.constInt32(0)); 12072 m_out.branch(isRopeString(string, m_node->child1()), 12073 unsure(slowPath), unsure(notRope)); 12074 12075 LBasicBlock lastNext = m_out.appendTo(notRope, is8Bit); 12006 12076 LValue impl = m_out.loadPtr(string, m_heaps.JSString_value); 12007 m_out.branch(m_out.isZero64(impl),12008 unsure(slowPath), unsure(notRope));12009 12010 LBasicBlock lastNext = m_out.appendTo(notRope, is8Bit);12011 12012 12077 m_out.branch( 12013 12078 m_out.testIsZero32( … … 12780 12845 } 12781 12846 12782 LValue stringsEqual(LValue leftJSString, LValue rightJSString )12847 LValue stringsEqual(LValue leftJSString, LValue rightJSString, Edge leftJSStringEdge = Edge(), Edge rightJSStringEdge = Edge()) 12783 12848 { 12784 12849 LBasicBlock notTriviallyUnequalCase = m_out.newBlock(); … … 12795 12860 LBasicBlock continuation = m_out.newBlock(); 12796 12861 12797 LValue length = m_out.load32(leftJSString, m_heaps.JSString_length); 12798 12799 m_out.branch( 12800 m_out.notEqual(length, m_out.load32(rightJSString, m_heaps.JSString_length)), 12801 unsure(falseCase), unsure(notTriviallyUnequalCase)); 12802 12803 LBasicBlock lastNext = m_out.appendTo(notTriviallyUnequalCase, notEmptyCase); 12804 12805 m_out.branch(m_out.isZero32(length), unsure(trueCase), unsure(notEmptyCase)); 12806 12807 m_out.appendTo(notEmptyCase, leftReadyCase); 12808 12862 m_out.branch(isRopeString(leftJSString, leftJSStringEdge), rarely(slowCase), usually(leftReadyCase)); 12863 12864 LBasicBlock lastNext = m_out.appendTo(leftReadyCase, rightReadyCase); 12865 m_out.branch(isRopeString(rightJSString, rightJSStringEdge), rarely(slowCase), usually(rightReadyCase)); 12866 12867 m_out.appendTo(rightReadyCase, notTriviallyUnequalCase); 12809 12868 LValue left = m_out.loadPtr(leftJSString, m_heaps.JSString_value); 12810 12869 LValue right = m_out.loadPtr(rightJSString, m_heaps.JSString_value); 12811 12812 m_out.branch( m_out.notNull(left), usually(leftReadyCase), rarely(slowCase));12813 12814 m_out.appendTo(leftReadyCase, rightReadyCase);12815 12816 m_out. branch(m_out.notNull(right), usually(rightReadyCase), rarely(slowCase));12817 12818 m_out.appendTo(rightReadyCase, left8BitCase); 12819 12870 LValue length = m_out.load32(left, m_heaps.StringImpl_length); 12871 m_out.branch( 12872 m_out.notEqual(length, m_out.load32(right, m_heaps.StringImpl_length)), 12873 unsure(falseCase), unsure(notTriviallyUnequalCase)); 12874 12875 m_out.appendTo(notTriviallyUnequalCase, notEmptyCase); 12876 m_out.branch(m_out.isZero32(length), unsure(trueCase), unsure(notEmptyCase)); 12877 12878 m_out.appendTo(notEmptyCase, left8BitCase); 12820 12879 m_out.branch( 12821 12880 m_out.testIsZero32( … … 12825 12884 12826 12885 m_out.appendTo(left8BitCase, right8BitCase); 12827 12828 12886 m_out.branch( 12829 12887 m_out.testIsZero32( … … 13547 13605 edge, CellCaseSpeculatesObject, SpeculateNullOrUndefined, 13548 13606 ManualOperandSpeculation)); 13549 case StringUse: { 13550 LValue stringValue = lowString(edge); 13551 LValue length = m_out.load32NonNegative(stringValue, m_heaps.JSString_length); 13552 return m_out.notEqual(length, m_out.int32Zero); 13553 } 13607 case StringUse: 13608 return m_out.notEqual(lowString(edge), weakPointer(jsEmptyString(&m_graph.m_vm))); 13554 13609 case StringOrOtherUse: { 13555 13610 LValue value = lowJSValue(edge, ManualOperandSpeculation); … … 13562 13617 13563 13618 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase); 13564 13565 13619 FTL_TYPE_CHECK(jsValueValue(value), edge, (~SpecCellCheck) | SpecString, isNotString(value)); 13566 LValue length = m_out.load32NonNegative(value, m_heaps.JSString_length); 13567 ValueFromBlock cellResult = m_out.anchor(m_out.notEqual(length, m_out.int32Zero)); 13620 ValueFromBlock stringResult = m_out.anchor(m_out.notEqual(value, weakPointer(jsEmptyString(&m_graph.m_vm)))); 13568 13621 m_out.jump(continuation); 13569 13622 13570 13623 m_out.appendTo(notCellCase, continuation); 13571 13572 13624 FTL_TYPE_CHECK(jsValueValue(value), edge, SpecCellCheck | SpecOther, isNotOther(value)); 13573 13625 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse); 13574 13626 m_out.jump(continuation); 13627 13575 13628 m_out.appendTo(continuation, lastNext); 13576 13577 return m_out.phi(Int32, cellResult, notCellResult); 13629 return m_out.phi(Int32, stringResult, notCellResult); 13578 13630 } 13579 13631 case UntypedUse: { … … 13598 13650 LBasicBlock cellCase = m_out.newBlock(); 13599 13651 LBasicBlock notStringCase = m_out.newBlock(); 13600 LBasicBlock stringOrBigIntCase = m_out.newBlock(); 13652 LBasicBlock stringCase = m_out.newBlock(); 13653 LBasicBlock bigIntCase = m_out.newBlock(); 13601 13654 LBasicBlock notStringOrBigIntCase = m_out.newBlock(); 13602 13655 LBasicBlock notCellCase = m_out.newBlock(); … … 13614 13667 m_out.branch( 13615 13668 isString(value, provenType(edge) & SpecCell), 13616 unsure(string OrBigIntCase), unsure(notStringCase));13617 13618 m_out.appendTo(notStringCase, string OrBigIntCase);13669 unsure(stringCase), unsure(notStringCase)); 13670 13671 m_out.appendTo(notStringCase, stringCase); 13619 13672 m_out.branch( 13620 13673 isBigInt(value, provenType(edge) & (SpecCell - SpecString)), 13621 unsure(stringOrBigIntCase), unsure(notStringOrBigIntCase)); 13622 13623 m_out.appendTo(stringOrBigIntCase, notStringOrBigIntCase); 13624 LValue nonZeroCell = m_out.notZero32( 13625 m_out.load32NonNegative(value, m_heaps.JSBigIntOrString_length)); 13626 results.append(m_out.anchor(nonZeroCell)); 13674 unsure(bigIntCase), unsure(notStringOrBigIntCase)); 13675 13676 m_out.appendTo(stringCase, bigIntCase); 13677 results.append(m_out.anchor(m_out.notEqual(value, weakPointer(jsEmptyString(&m_graph.m_vm))))); 13678 m_out.jump(continuation); 13679 13680 m_out.appendTo(bigIntCase, notStringOrBigIntCase); 13681 LValue nonZeroBigInt = m_out.notZero32( 13682 m_out.load32NonNegative(value, m_heaps.JSBigInt_length)); 13683 results.append(m_out.anchor(nonZeroBigInt)); 13627 13684 m_out.jump(continuation); 13628 13685 … … 13888 13945 } 13889 13946 13890 void switchString(SwitchData* data, LValue string )13947 void switchString(SwitchData* data, LValue string, Edge& edge) 13891 13948 { 13892 13949 bool canDoBinarySwitch = true; … … 13911 13968 } 13912 13969 13913 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);13914 LValue length = m_out.load32(string, m_heaps.JSString_length);13915 13916 13970 LBasicBlock hasImplBlock = m_out.newBlock(); 13917 13971 LBasicBlock is8BitBlock = m_out.newBlock(); 13918 13972 LBasicBlock slowBlock = m_out.newBlock(); 13919 13973 13920 m_out.branch( m_out.isNull(stringImpl), unsure(slowBlock), unsure(hasImplBlock));13974 m_out.branch(isRopeString(string, edge), unsure(slowBlock), unsure(hasImplBlock)); 13921 13975 13922 13976 LBasicBlock lastNext = m_out.appendTo(hasImplBlock, is8BitBlock); 13977 13978 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value); 13979 LValue length = m_out.load32(stringImpl, m_heaps.StringImpl_length); 13923 13980 13924 13981 m_out.branch( … … 15615 15672 } 15616 15673 15674 LValue isRopeString(LValue string, Edge edge = Edge()) 15675 { 15676 if (edge) { 15677 if (!((provenType(edge) & SpecString) & ~SpecStringIdent)) 15678 return m_out.booleanFalse; 15679 if (JSValue value = provenValue(edge)) { 15680 if (value.isCell() && value.asCell()->type() == StringType && !asString(value)->isRope()) 15681 return m_out.booleanFalse; 15682 } 15683 } 15684 15685 return m_out.testNonZeroPtr(m_out.loadPtr(string, m_heaps.JSString_value), m_out.constIntPtr(JSString::isRopeInPointer)); 15686 } 15687 15688 LValue isNotRopeString(LValue string, Edge edge = Edge()) 15689 { 15690 if (edge) { 15691 if (!((provenType(edge) & SpecString) & ~SpecStringIdent)) 15692 return m_out.booleanTrue; 15693 if (JSValue value = provenValue(edge)) { 15694 if (value.isCell() && value.asCell()->type() == StringType && !asString(value)->isRope()) 15695 return m_out.booleanTrue; 15696 } 15697 } 15698 15699 return m_out.testIsZeroPtr(m_out.loadPtr(string, m_heaps.JSString_value), m_out.constIntPtr(JSString::isRopeInPointer)); 15700 } 15701 15617 15702 LValue isNotSymbol(LValue cell, SpeculatedType type = SpecFullTop) 15618 15703 { … … 16012 16097 return; 16013 16098 16014 speculate(BadType, jsValueValue(string), edge.node(), m_out.isNull(stringImpl));16099 speculate(BadType, jsValueValue(string), edge.node(), isRopeString(string)); 16015 16100 speculate( 16016 16101 BadType, jsValueValue(string), edge.node(), -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
r242123 r242252 728 728 729 729 isString.link(this); 730 move(TrustedImmPtr(jsEmptyString(&vm)), result); 731 comparePtr(invert ? Equal : NotEqual, value.payloadGPR(), result, result); 732 done.append(jump()); 733 730 734 isBigInt.link(this); 731 RELEASE_ASSERT(JSString::offsetOfLength() == JSBigInt::offsetOfLength());732 735 load32(Address(value.payloadGPR(), JSBigInt::offsetOfLength()), result); 733 736 compare32(invert ? Equal : NotEqual, result, TrustedImm32(0), result); … … 815 818 816 819 isString.link(this); 820 truthy.append(branchPtr(invert ? Equal : NotEqual, value.payloadGPR(), TrustedImmPtr(jsEmptyString(&vm)))); 821 done.append(jump()); 822 817 823 isBigInt.link(this); 818 RELEASE_ASSERT(JSString::offsetOfLength() == JSBigInt::offsetOfLength());819 824 truthy.append(branchTest32(invert ? Zero : NonZero, Address(value.payloadGPR(), JSBigInt::offsetOfLength()))); 820 825 done.append(jump()); -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h
r242123 r242252 1074 1074 { 1075 1075 return branchDouble(DoubleEqual, fpr, fpr); 1076 } 1077 1078 Jump branchIfRopeStringImpl(GPRReg stringImplGPR) 1079 { 1080 return branchTestPtr(NonZero, stringImplGPR, TrustedImm32(JSString::isRopeInPointer)); 1081 } 1082 1083 Jump branchIfNotRopeStringImpl(GPRReg stringImplGPR) 1084 { 1085 return branchTestPtr(Zero, stringImplGPR, TrustedImm32(JSString::isRopeInPointer)); 1076 1086 } 1077 1087 -
trunk/Source/JavaScriptCore/jit/JITInlines.h
r240041 r242252 95 95 { 96 96 failures.append(branchIfNotString(src)); 97 failures.append(branch32(NotEqual, MacroAssembler::Address(src, JSString::offsetOfLength()), TrustedImm32(1)));98 97 loadPtr(MacroAssembler::Address(src, JSString::offsetOfValue()), dst); 99 failures.append(branchTest32(Zero, dst)); 98 failures.append(branchIfRopeStringImpl(dst)); 99 failures.append(branch32(NotEqual, MacroAssembler::Address(dst, StringImpl::lengthMemoryOffset()), TrustedImm32(1))); 100 100 loadPtr(MacroAssembler::Address(dst, StringImpl::flagsOffset()), regT1); 101 101 loadPtr(MacroAssembler::Address(dst, StringImpl::dataOffset()), dst); -
trunk/Source/JavaScriptCore/jit/Repatch.cpp
r242123 r242252 211 211 newCase = AccessCase::create(vm, codeBlock, AccessCase::ArrayLength); 212 212 } else if (isJSString(baseCell)) { 213 if (stubInfo.cacheType == CacheType::Unset ) {213 if (stubInfo.cacheType == CacheType::Unset && InlineAccess::isCacheableStringLength(stubInfo)) { 214 214 bool generatedCodeInline = InlineAccess::generateStringLength(stubInfo); 215 215 if (generatedCodeInline) { -
trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp
r242123 r242252 623 623 624 624 // Load string length to regT2, and start the process of loading the data pointer into regT0 625 jit.load32(JSInterfaceJIT::Address(stringGPR, JSString::offsetOfLength()), scratchGPR);626 625 jit.loadPtr(JSInterfaceJIT::Address(stringGPR, JSString::offsetOfValue()), stringGPR); 627 failures.append(jit.branchTestPtr(JSInterfaceJIT::Zero, stringGPR)); 626 failures.append(jit.branchIfRopeStringImpl(stringGPR)); 627 jit.load32(JSInterfaceJIT::Address(stringGPR, StringImpl::lengthMemoryOffset()), scratchGPR); 628 628 629 629 // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large … … 662 662 663 663 // Load string length to regT2, and start the process of loading the data pointer into regT0 664 jit.load32(MacroAssembler::Address(SpecializedThunkJIT::regT0, JSString::offsetOfLength()), SpecializedThunkJIT::regT2);665 664 jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, JSString::offsetOfValue()), SpecializedThunkJIT::regT0); 666 jit.appendFailure(jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0)); 665 jit.appendFailure(jit.branchIfRopeStringImpl(SpecializedThunkJIT::regT0)); 666 jit.load32(MacroAssembler::Address(SpecializedThunkJIT::regT0, StringImpl::lengthMemoryOffset()), SpecializedThunkJIT::regT2); 667 667 668 668 // load index -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r242096 r242252 483 483 484 484 # String flags. 485 const isRopeInPointer = constexpr JSString::isRopeInPointer 485 486 const HashFlags8BitBuffer = constexpr StringImpl::s_hashFlag8BitBuffer 486 487 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
r242067 r242252 1789 1789 bineq t1, CellTag, .opSwitchCharFallThrough 1790 1790 bbneq JSCell::m_type[t0], StringType, .opSwitchCharFallThrough 1791 bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough1792 loadp JSString::m_value[t0], t01793 b tpz t0, .opSwitchOnRope1791 loadp JSString::m_fiber[t0], t0 1792 btpnz t0, isRopeInPointer, .opSwitchOnRope 1793 bineq StringImpl::m_length[t0], 1, .opSwitchCharFallThrough 1794 1794 loadp StringImpl::m_data8[t0], t1 1795 1795 btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r242096 r242252 1878 1878 btqnz t1, tagMask, .opSwitchCharFallThrough 1879 1879 bbneq JSCell::m_type[t1], StringType, .opSwitchCharFallThrough 1880 bineq JSString::m_length[t1], 1, .opSwitchCharFallThrough1881 loadp JSString::m_value[t1], t01882 b tpz t0, .opSwitchOnRope1880 loadp JSString::m_fiber[t1], t0 1881 btpnz t0, isRopeInPointer, .opSwitchOnRope 1882 bineq StringImpl::m_length[t0], 1, .opSwitchCharFallThrough 1883 1883 loadp StringImpl::m_data8[t0], t1 1884 1884 btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit -
trunk/Source/JavaScriptCore/runtime/JSString.cpp
r239427 r242252 41 41 } 42 42 43 JSString* JSString::createEmptyString(VM& vm) 44 { 45 JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, *StringImpl::empty()); 46 newString->finishCreation(vm); 47 return newString; 48 } 49 43 50 template<> 44 51 void JSRopeString::RopeBuilder<RecordOverflow>::expand() 45 52 { 46 53 RELEASE_ASSERT(!this->hasOverflowed()); 47 ASSERT(m_index == JSRopeString::s_maxInternalRopeLength); 48 JSString* jsString = m_jsString; 49 m_jsString = jsStringBuilder(&m_vm); 50 m_index = 0; 51 append(jsString); 54 ASSERT(m_strings.size() == JSRopeString::s_maxInternalRopeLength); 55 static_assert(3 == JSRopeString::s_maxInternalRopeLength, ""); 56 ASSERT(m_length); 57 ASSERT(asString(m_strings.at(0))->length()); 58 ASSERT(asString(m_strings.at(1))->length()); 59 ASSERT(asString(m_strings.at(2))->length()); 60 61 JSString* string = JSRopeString::create(m_vm, asString(m_strings.at(0)), asString(m_strings.at(1)), asString(m_strings.at(2))); 62 ASSERT(string->length() == m_length); 63 m_strings.clear(); 64 m_strings.append(string); 52 65 } 53 66 … … 62 75 const JSString* thisObject = jsCast<const JSString*>(cell); 63 76 out.printf("<%p, %s, [%u], ", thisObject, thisObject->className(vm), thisObject->length()); 64 if (thisObject->isRope()) 77 uintptr_t pointer = thisObject->m_fiber; 78 if (pointer & isRopeInPointer) 65 79 out.printf("[rope]"); 66 80 else { 67 WTF::StringImpl* ourImpl = thisObject->m_value.impl(); 68 if (ourImpl->is8Bit()) 69 out.printf("[8 %p]", ourImpl->characters8()); 70 else 71 out.printf("[16 %p]", ourImpl->characters16()); 81 if (WTF::StringImpl* ourImpl = bitwise_cast<StringImpl*>(pointer)) { 82 if (ourImpl->is8Bit()) 83 out.printf("[8 %p]", ourImpl->characters8()); 84 else 85 out.printf("[16 %p]", ourImpl->characters16()); 86 } 72 87 } 73 88 out.printf(">"); … … 87 102 { 88 103 JSString* thisObject = asString(cell); 89 if (thisObject->isRope()) 104 uintptr_t pointer = thisObject->m_fiber; 105 if (pointer & isRopeInPointer) 90 106 return Base::estimatedSize(cell, vm); 91 return Base::estimatedSize(cell, vm) + thisObject->m_value.impl()->costDuringGC();107 return Base::estimatedSize(cell, vm) + bitwise_cast<StringImpl*>(pointer)->costDuringGC(); 92 108 } 93 109 … … 97 113 Base::visitChildren(thisObject, visitor); 98 114 99 if (thisObject->isRope()) 100 static_cast<JSRopeString*>(thisObject)->visitFibers(visitor); 101 if (StringImpl* impl = thisObject->m_value.impl()) 115 uintptr_t pointer = thisObject->m_fiber; 116 if (pointer & isRopeInPointer) { 117 if ((pointer & JSRopeString::stringMask) == JSRopeString::substringSentinel()) { 118 visitor.appendUnbarriered(static_cast<JSRopeString*>(thisObject)->fiber1()); 119 return; 120 } 121 for (unsigned index = 0; index < JSRopeString::s_maxInternalRopeLength; ++index) { 122 JSString* fiber = nullptr; 123 switch (index) { 124 case 0: 125 fiber = bitwise_cast<JSString*>(pointer & JSRopeString::stringMask); 126 break; 127 case 1: 128 fiber = static_cast<JSRopeString*>(thisObject)->fiber1(); 129 break; 130 case 2: 131 fiber = static_cast<JSRopeString*>(thisObject)->fiber2(); 132 break; 133 default: 134 ASSERT_NOT_REACHED(); 135 return; 136 } 137 if (!fiber) 138 break; 139 visitor.appendUnbarriered(fiber); 140 } 141 return; 142 } 143 if (StringImpl* impl = bitwise_cast<StringImpl*>(pointer)) 102 144 visitor.reportExtraMemoryVisited(impl->costDuringGC()); 103 145 } 104 146 105 void JSRopeString::visitFibers(SlotVisitor& visitor) 147 static const unsigned maxLengthForOnStackResolve = 2048; 148 149 void JSRopeString::resolveRopeInternal8(LChar* buffer) const 106 150 { 107 151 if (isSubstring()) { 108 visitor.append(substringBase()); 109 return; 110 } 111 for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) 112 visitor.append(fiber(i)); 113 } 114 115 static const unsigned maxLengthForOnStackResolve = 2048; 116 117 void JSRopeString::resolveRopeInternal8(LChar* buffer) const 118 { 119 if (isSubstring()) { 120 StringImpl::copyCharacters(buffer, substringBase()->m_value.characters8() + substringOffset(), length()); 152 StringImpl::copyCharacters(buffer, substringBase()->valueInternal().characters8() + substringOffset(), length()); 121 153 return; 122 154 } … … 136 168 LChar* position = buffer; 137 169 for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { 138 const StringImpl& fiberString = *fiber(i)-> m_value.impl();170 const StringImpl& fiberString = *fiber(i)->valueInternal().impl(); 139 171 unsigned length = fiberString.length(); 140 172 StringImpl::copyCharacters(position, fiberString.characters8(), length); … … 148 180 if (isSubstring()) { 149 181 StringImpl::copyCharacters( 150 buffer, substringBase()-> m_value.characters16() + substringOffset(), length());182 buffer, substringBase()->valueInternal().characters16() + substringOffset(), length()); 151 183 return; 152 184 } … … 166 198 UChar* position = buffer; 167 199 for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) { 168 const StringImpl& fiberString = *fiber(i)-> m_value.impl();200 const StringImpl& fiberString = *fiber(i)->valueInternal().impl(); 169 201 unsigned length = fiberString.length(); 170 202 if (fiberString.is8Bit()) … … 177 209 } 178 210 179 voidJSRopeString::resolveRopeToAtomicString(ExecState* exec) const211 AtomicString JSRopeString::resolveRopeToAtomicString(ExecState* exec) const 180 212 { 181 213 VM& vm = exec->vm(); … … 183 215 184 216 if (length() > maxLengthForOnStackResolve) { 185 resolveRope(exec); 186 RETURN_IF_EXCEPTION(scope, void()); 187 m_value = AtomicString(m_value); 188 setIs8Bit(m_value.impl()->is8Bit()); 189 return; 217 scope.release(); 218 return resolveRopeWithFunction(exec, [&] (Ref<StringImpl>&& newImpl) { 219 return AtomicStringImpl::add(newImpl.ptr()); 220 }); 190 221 } 191 222 … … 193 224 LChar buffer[maxLengthForOnStackResolve]; 194 225 resolveRopeInternal8(buffer); 195 m_value = AtomicString(buffer, length()); 196 setIs8Bit(m_value.impl()->is8Bit()); 226 convertToNonRope(AtomicStringImpl::add(buffer, length())); 197 227 } else { 198 228 UChar buffer[maxLengthForOnStackResolve]; 199 229 resolveRopeInternal16(buffer); 200 m_value = AtomicString(buffer, length()); 201 setIs8Bit(m_value.impl()->is8Bit()); 202 } 203 204 clearFibers(); 230 convertToNonRope(AtomicStringImpl::add(buffer, length())); 231 } 205 232 206 233 // If we resolved a string that didn't previously exist, notify the heap that we've grown. 207 if (m_value.impl()->hasOneRef()) 208 vm.heap.reportExtraMemoryAllocated(m_value.impl()->cost()); 209 } 210 211 void JSRopeString::clearFibers() const 212 { 213 for (size_t i = 0; i < s_maxInternalRopeLength; ++i) 214 u[i].number = 0; 234 if (valueInternal().impl()->hasOneRef()) 235 vm.heap.reportExtraMemoryAllocated(valueInternal().impl()->cost()); 236 return valueInternal(); 237 } 238 239 inline void JSRopeString::convertToNonRope(String&& string) const 240 { 241 // Concurrent compiler threads can access String held by JSString. So we always emit 242 // store-store barrier here to ensure concurrent compiler threads see initialized String. 243 ASSERT(JSString::isRope()); 244 WTF::storeStoreFence(); 245 new (&uninitializedValueInternal()) String(WTFMove(string)); 246 static_assert(sizeof(String) == sizeof(RefPtr<StringImpl>), "JSString's String initialization must be done in one pointer move."); 247 // We do not clear the trailing fibers and length information (fiber1 and fiber2) because we could be reading the length concurrently. 248 ASSERT(!JSString::isRope()); 215 249 } 216 250 217 251 RefPtr<AtomicStringImpl> JSRopeString::resolveRopeToExistingAtomicString(ExecState* exec) const 218 252 { 253 VM& vm = exec->vm(); 254 auto scope = DECLARE_THROW_SCOPE(vm); 255 219 256 if (length() > maxLengthForOnStackResolve) { 220 resolveRope(exec); 221 if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(m_value.impl())) { 222 m_value = *existingAtomicString; 223 setIs8Bit(m_value.impl()->is8Bit()); 224 clearFibers(); 225 return existingAtomicString; 226 } 227 return nullptr; 257 RefPtr<AtomicStringImpl> existingAtomicString; 258 resolveRopeWithFunction(exec, [&] (Ref<StringImpl>&& newImpl) -> Ref<StringImpl> { 259 existingAtomicString = AtomicStringImpl::lookUp(newImpl.ptr()); 260 if (existingAtomicString) 261 return makeRef(*existingAtomicString); 262 return WTFMove(newImpl); 263 }); 264 RETURN_IF_EXCEPTION(scope, nullptr); 265 return existingAtomicString; 228 266 } 229 267 … … 232 270 resolveRopeInternal8(buffer); 233 271 if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, length())) { 234 m_value = *existingAtomicString; 235 setIs8Bit(m_value.impl()->is8Bit()); 236 clearFibers(); 272 convertToNonRope(*existingAtomicString); 237 273 return existingAtomicString; 238 274 } … … 241 277 resolveRopeInternal16(buffer); 242 278 if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, length())) { 243 m_value = *existingAtomicString; 244 setIs8Bit(m_value.impl()->is8Bit()); 245 clearFibers(); 279 convertToNonRope(*existingAtomicString); 246 280 return existingAtomicString; 247 281 } … … 251 285 } 252 286 253 void JSRopeString::resolveRope(ExecState* nullOrExecForOOM) const 287 template<typename Function> 288 const String& JSRopeString::resolveRopeWithFunction(ExecState* nullOrExecForOOM, Function&& function) const 254 289 { 255 290 ASSERT(isRope()); 256 291 292 VM& vm = *this->vm(); 257 293 if (isSubstring()) { 258 294 ASSERT(!substringBase()->isRope()); 259 m_value = substringBase()->m_value.substringSharingImpl(substringOffset(), length());260 substringBase().clear();261 return ;295 auto newImpl = substringBase()->valueInternal().substringSharingImpl(substringOffset(), length()); 296 convertToNonRope(function(newImpl.releaseImpl().releaseNonNull())); 297 return valueInternal(); 262 298 } 263 299 264 300 if (is8Bit()) { 265 301 LChar* buffer; 266 if (auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer)) { 267 Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost()); 268 m_value = WTFMove(newImpl); 269 } else { 302 auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer); 303 if (!newImpl) { 270 304 outOfMemory(nullOrExecForOOM); 271 return; 272 } 305 return nullString(); 306 } 307 vm.heap.reportExtraMemoryAllocated(newImpl->cost()); 308 273 309 resolveRopeInternal8NoSubstring(buffer); 274 clearFibers(); 275 ASSERT(!isRope()); 276 return; 310 convertToNonRope(function(newImpl.releaseNonNull())); 311 return valueInternal(); 277 312 } 278 313 279 314 UChar* buffer; 280 if (auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer)) { 281 Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost()); 282 m_value = WTFMove(newImpl); 283 } else { 315 auto newImpl = StringImpl::tryCreateUninitialized(length(), buffer); 316 if (!newImpl) { 284 317 outOfMemory(nullOrExecForOOM); 285 return; 286 } 318 return nullString(); 319 } 320 vm.heap.reportExtraMemoryAllocated(newImpl->cost()); 287 321 288 322 resolveRopeInternal16NoSubstring(buffer); 289 clearFibers(); 290 ASSERT(!isRope()); 323 convertToNonRope(function(newImpl.releaseNonNull())); 324 return valueInternal(); 325 } 326 327 const String& JSRopeString::resolveRope(ExecState* nullOrExecForOOM) const 328 { 329 return resolveRopeWithFunction(nullOrExecForOOM, [] (Ref<StringImpl>&& newImpl) { 330 return WTFMove(newImpl); 331 }); 291 332 } 292 333 … … 307 348 308 349 for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) 309 workQueue.append(fiber(i) .get());350 workQueue.append(fiber(i)); 310 351 311 352 while (!workQueue.isEmpty()) { … … 319 360 if (!currentFiberAsRope->isSubstring()) { 320 361 for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i) 321 workQueue.append(currentFiberAsRope->fiber(i) .get());362 workQueue.append(currentFiberAsRope->fiber(i)); 322 363 continue; 323 364 } 324 365 ASSERT(!currentFiberAsRope->substringBase()->isRope()); 325 366 characters = 326 currentFiberAsRope->substringBase()-> m_value.characters8() +367 currentFiberAsRope->substringBase()->valueInternal().characters8() + 327 368 currentFiberAsRope->substringOffset(); 328 369 } else 329 characters = currentFiber-> m_value.characters8();370 characters = currentFiber->valueInternal().characters8(); 330 371 331 372 unsigned length = currentFiber->length(); … … 343 384 344 385 for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) 345 workQueue.append(fiber(i) .get());386 workQueue.append(fiber(i)); 346 387 347 388 while (!workQueue.isEmpty()) { … … 354 395 ASSERT(!currentFiberAsRope->substringBase()->isRope()); 355 396 StringImpl* string = static_cast<StringImpl*>( 356 currentFiberAsRope->substringBase()-> m_value.impl());397 currentFiberAsRope->substringBase()->valueInternal().impl()); 357 398 unsigned offset = currentFiberAsRope->substringOffset(); 358 399 unsigned length = currentFiberAsRope->length(); … … 365 406 } 366 407 for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i) 367 workQueue.append(currentFiberAsRope->fiber(i) .get());408 workQueue.append(currentFiberAsRope->fiber(i)); 368 409 continue; 369 410 } 370 411 371 StringImpl* string = static_cast<StringImpl*>(currentFiber-> m_value.impl());412 StringImpl* string = static_cast<StringImpl*>(currentFiber->valueInternal().impl()); 372 413 unsigned length = string->length(); 373 414 position -= length; … … 383 424 void JSRopeString::outOfMemory(ExecState* nullOrExecForOOM) const 384 425 { 385 clearFibers();386 426 ASSERT(isRope()); 387 ASSERT(m_value.isNull());388 427 if (nullOrExecForOOM) { 389 428 VM& vm = nullOrExecForOOM->vm(); -
trunk/Source/JavaScriptCore/runtime/JSString.h
r242123 r242252 23 23 #pragma once 24 24 25 #include "ArgList.h" 25 26 #include "CallFrame.h" 26 27 #include "CommonIdentifiers.h" … … 32 33 #include <array> 33 34 #include <wtf/CheckedArithmetic.h> 35 #include <wtf/ForbidHeapAllocation.h> 34 36 #include <wtf/text/StringView.h> 35 37 … … 62 64 JSString* jsOwnedString(ExecState*, const String&); 63 65 64 JSRopeString* jsStringBuilder(VM*);65 66 66 bool isJSString(JSCell*); 67 67 bool isJSString(JSValue); … … 73 73 }; 74 74 75 76 // In 64bit architecture, JSString and JSRopeString have the following memory layout to make sizeof(JSString) == 16 and sizeof(JSRopeString) == 32. 77 // JSString has only one pointer. We use it for String. length() and is8Bit() queries go to StringImpl. In JSRopeString, we reuse the above pointer 78 // place for the 1st fiber. JSRopeString has three fibers so its size is 48. To keep length and is8Bit flag information in JSRopeString, JSRopeString 79 // encodes these information into the fiber pointers. is8Bit flag is encoded in the 1st fiber pointer. length is embedded directly, and two fibers 80 // are compressed into 12bytes. isRope information is encoded in the first fiber's LSB. 81 // 82 // Since length of JSRopeString should be frequently accessed compared to each fiber, we put length in contiguous 32byte field, and compress 2nd 83 // 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 84 // are not one pointer load operation. To make concurrent collector work correctly, we must initialize 2nd and 3rd fibers at JSRopeString creation 85 // and we must not modify these part later. 86 // 87 // 0 8 10 16 32 48 88 // JSString [ ID ][ header ][ String pointer 0] 89 // JSRopeString [ ID ][ header ][ flags ][ 1st fiber 1][ length ][2nd lower32][2nd upper16][3rd lower16][3rd upper32] 90 // ^ 91 // isRope bit 75 92 class JSString : public JSCell { 76 93 public: … … 81 98 friend class MarkStack; 82 99 friend class SlotVisitor; 100 friend class SmallStrings; 83 101 84 102 typedef JSCell Base; … … 102 120 static_assert(MaxLength == String::MaxLength, ""); 103 121 122 static constexpr uintptr_t isRopeInPointer = 0x1; 123 104 124 private: 125 String& uninitializedValueInternal() const 126 { 127 return *bitwise_cast<String*>(&m_fiber); 128 } 129 130 String& valueInternal() const 131 { 132 ASSERT(!isRope()); 133 return uninitializedValueInternal(); 134 } 135 105 136 JSString(VM& vm, Ref<StringImpl>&& value) 106 137 : JSCell(vm, vm.stringStructure.get()) 107 , m_value(WTFMove(value))108 {138 { 139 new (&uninitializedValueInternal()) String(WTFMove(value)); 109 140 } 110 141 111 142 JSString(VM& vm) 112 143 : JSCell(vm, vm.stringStructure.get()) 144 , m_fiber(isRopeInPointer) 113 145 { 114 146 } … … 116 148 void finishCreation(VM& vm, unsigned length) 117 149 { 118 ASSERT(!m_value.isNull()); 150 ASSERT_UNUSED(length, length > 0); 151 ASSERT(!valueInternal().isNull()); 119 152 Base::finishCreation(vm); 120 setLength(length);121 setIs8Bit(m_value.impl()->is8Bit());122 153 } 123 154 124 155 void finishCreation(VM& vm, unsigned length, size_t cost) 125 156 { 126 ASSERT(!m_value.isNull()); 157 ASSERT_UNUSED(length, length > 0); 158 ASSERT(!valueInternal().isNull()); 127 159 Base::finishCreation(vm); 128 setLength(length);129 setIs8Bit(m_value.impl()->is8Bit());130 160 vm.heap.reportExtraMemoryAllocated(cost); 131 161 } 132 162 133 protected: 134 void finishCreation(VM& vm) 135 { 136 Base::finishCreation(vm); 137 setLength(0); 138 setIs8Bit(true); 139 } 140 141 public: 163 static JSString* createEmptyString(VM&); 164 142 165 static JSString* create(VM& vm, Ref<StringImpl>&& value) 143 166 { 144 167 unsigned length = value->length(); 168 ASSERT(length > 0); 145 169 size_t cost = value->cost(); 146 170 JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, WTFMove(value)); … … 156 180 } 157 181 182 protected: 183 void finishCreation(VM& vm) 184 { 185 Base::finishCreation(vm); 186 } 187 188 public: 189 ~JSString(); 190 158 191 Identifier toIdentifier(ExecState*) const; 159 192 AtomicString toAtomicString(ExecState*) const; … … 166 199 inline const String& tryGetValue(bool allocationAllowed = true) const; 167 200 const StringImpl* tryGetValueImpl() const; 168 ALWAYS_INLINE unsigned length() const { return m_length; }201 ALWAYS_INLINE unsigned length() const; 169 202 170 203 JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; … … 183 216 static Structure* createStructure(VM&, JSGlobalObject*, JSValue); 184 217 185 static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); } 186 static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); } 187 static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); } 218 static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_fiber); } 188 219 189 220 DECLARE_EXPORT_INFO; … … 193 224 static void visitChildren(JSCell*, SlotVisitor&); 194 225 195 enum { 196 Is8Bit = 1u 197 }; 198 199 bool isRope() const { return m_value.isNull(); } 226 ALWAYS_INLINE bool isRope() const 227 { 228 return m_fiber & isRopeInPointer; 229 } 230 231 bool is8Bit() const; 200 232 201 233 protected: … … 204 236 JS_EXPORT_PRIVATE bool equalSlowCase(ExecState*, JSString* other) const; 205 237 bool isSubstring() const; 206 bool is8Bit() const { return m_flags & Is8Bit; } 207 void setIs8Bit(bool flag) const 208 { 209 if (flag) 210 m_flags |= Is8Bit; 211 else 212 m_flags &= ~Is8Bit; 213 } 214 215 ALWAYS_INLINE void setLength(unsigned length) 216 { 217 ASSERT(length <= MaxLength); 218 m_length = length; 219 } 238 239 mutable uintptr_t m_fiber; 220 240 221 241 private: 222 // A string is represented either by a String or a rope of fibers.223 unsigned m_length { 0 };224 mutable uint16_t m_flags { 0 };225 mutable String m_value;226 227 242 friend class LLIntOffsetsExtractor; 228 243 229 244 static JSValue toThis(JSCell*, ExecState*, ECMAMode); 230 245 231 String& string() { ASSERT(!isRope()); return m_value; }232 246 StringView unsafeView(ExecState*) const; 233 247 248 friend JSString* jsString(VM*, const String&); 234 249 friend JSString* jsString(ExecState*, JSString*, JSString*); 235 friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length); 250 friend JSString* jsString(ExecState*, const String&, JSString*); 251 friend JSString* jsString(ExecState*, JSString*, const String&); 252 friend JSString* jsString(ExecState*, const String&, const String&); 253 friend JSString* jsString(ExecState*, JSString*, JSString*, JSString*); 254 friend JSString* jsString(ExecState*, const String&, const String&, const String&); 255 friend JSString* jsSingleCharacterString(VM*, UChar); 256 friend JSString* jsNontrivialString(VM*, const String&); 257 friend JSString* jsNontrivialString(VM*, String&&); 258 friend JSString* jsSubstring(VM*, const String&, unsigned, unsigned); 259 friend JSString* jsSubstring(VM&, ExecState*, JSString*, unsigned, unsigned); 260 friend JSString* jsSubstringOfResolved(VM&, GCDeferralContext*, JSString*, unsigned, unsigned); 261 friend JSString* jsOwnedString(VM*, const String&); 236 262 }; 237 263 … … 240 266 class JSRopeString final : public JSString { 241 267 friend class JSString; 242 243 friend JSRopeString* jsStringBuilder(VM*);244 245 268 public: 269 #if CPU(ADDRESS64) 270 static_assert(sizeof(uintptr_t) == sizeof(uint64_t), ""); 271 static constexpr uintptr_t flagMask = 0xffff000000000000ULL; 272 static constexpr uintptr_t stringMask = ~(flagMask | isRopeInPointer); 273 static_assert(StringImpl::flagIs8Bit() == 0b100, ""); 274 static constexpr uintptr_t is8BitInPointer = static_cast<uintptr_t>(StringImpl::flagIs8Bit()) << 48; 275 276 class CompactFibers { 277 public: 278 JSString* fiber1() const 279 { 280 return bitwise_cast<JSString*>(static_cast<uintptr_t>(m_fiber1Lower) | (static_cast<uintptr_t>(m_fiber1Upper) << 32)); 281 } 282 283 void initializeFiber1(JSString* fiber) 284 { 285 uintptr_t pointer = bitwise_cast<uintptr_t>(fiber); 286 m_fiber1Lower = static_cast<uint32_t>(pointer); 287 m_fiber1Upper = static_cast<uint16_t>(pointer >> 32); 288 } 289 290 JSString* fiber2() const 291 { 292 return bitwise_cast<JSString*>(static_cast<uintptr_t>(m_fiber2Lower) | (static_cast<uintptr_t>(m_fiber2Upper) << 32)); 293 } 294 void initializeFiber2(JSString* fiber) 295 { 296 uintptr_t pointer = bitwise_cast<uintptr_t>(fiber); 297 m_fiber2Lower = static_cast<uint32_t>(pointer); 298 m_fiber2Upper = static_cast<uint16_t>(pointer >> 32); 299 } 300 301 unsigned length() const { return m_length; } 302 void initializeLength(unsigned length) 303 { 304 m_length = length; 305 } 306 307 static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(CompactFibers, m_length); } 308 static ptrdiff_t offsetOfFiber1Lower() { return OBJECT_OFFSETOF(CompactFibers, m_fiber1Lower); } 309 static ptrdiff_t offsetOfFiber1Upper() { return OBJECT_OFFSETOF(CompactFibers, m_fiber1Upper); } 310 static ptrdiff_t offsetOfFiber2Lower() { return OBJECT_OFFSETOF(CompactFibers, m_fiber2Lower); } 311 static ptrdiff_t offsetOfFiber2Upper() { return OBJECT_OFFSETOF(CompactFibers, m_fiber2Upper); } 312 313 private: 314 uint32_t m_length { 0 }; 315 uint32_t m_fiber1Lower { 0 }; 316 uint16_t m_fiber1Upper { 0 }; 317 uint16_t m_fiber2Upper { 0 }; 318 uint32_t m_fiber2Lower { 0 }; 319 }; 320 static_assert(sizeof(CompactFibers) == sizeof(void*) * 2, ""); 321 #else 322 static constexpr uintptr_t stringMask = ~(isRopeInPointer); 323 324 class CompactFibers { 325 public: 326 JSString* fiber1() const 327 { 328 return m_fiber1; 329 } 330 void initializeFiber1(JSString* fiber) 331 { 332 m_fiber1 = fiber; 333 } 334 335 JSString* fiber2() const 336 { 337 return m_fiber2; 338 } 339 void initializeFiber2(JSString* fiber) 340 { 341 m_fiber2 = fiber; 342 } 343 344 unsigned length() const { return m_length; } 345 void initializeLength(unsigned length) 346 { 347 m_length = length; 348 } 349 350 void initializeIs8Bit(bool flag) 351 { 352 if (flag) 353 m_flags |= static_cast<uintptr_t>(StringImpl::flagIs8Bit()); 354 else 355 m_flags &= ~static_cast<uintptr_t>(StringImpl::flagIs8Bit()); 356 } 357 358 bool is8Bit() 359 { 360 return m_flags & static_cast<uintptr_t>(StringImpl::flagIs8Bit()); 361 } 362 363 static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(CompactFibers, m_length); } 364 365 private: 366 uint32_t m_length { 0 }; 367 uint32_t m_flags { 0 }; 368 JSString* m_fiber1 { nullptr }; 369 JSString* m_fiber2 { nullptr }; 370 }; 371 #endif 372 246 373 template <class OverflowHandler = CrashOnOverflow> 247 374 class RopeBuilder : public OverflowHandler { 375 WTF_FORBID_HEAP_ALLOCATION; 248 376 public: 249 377 RopeBuilder(VM& vm) 250 378 : m_vm(vm) 251 , m_jsString(jsStringBuilder(&vm))252 , m_index(0)253 379 { 254 380 } … … 258 384 if (UNLIKELY(this->hasOverflowed())) 259 385 return false; 260 if (m_index == JSRopeString::s_maxInternalRopeLength) 386 if (!jsString->length()) 387 return true; 388 if (m_strings.size() == JSRopeString::s_maxInternalRopeLength) 261 389 expand(); 262 390 263 391 static_assert(JSString::MaxLength == std::numeric_limits<int32_t>::max(), ""); 264 auto sum = checkedSum<int32_t>(m_ jsString->length(), jsString->length());392 auto sum = checkedSum<int32_t>(m_length, jsString->length()); 265 393 if (sum.hasOverflowed()) { 266 394 this->overflowed(); … … 268 396 } 269 397 ASSERT(static_cast<unsigned>(sum.unsafeGet()) <= MaxLength); 270 m_jsString->append(m_vm, m_index++, jsString); 398 m_strings.append(jsString); 399 m_length = static_cast<unsigned>(sum.unsafeGet()); 271 400 return true; 272 401 } 273 402 274 JS RopeString* release()403 JSString* release() 275 404 { 276 405 RELEASE_ASSERT(!this->hasOverflowed()); 277 JSRopeString* tmp = m_jsString; 278 m_jsString = nullptr; 279 return tmp; 406 JSString* result = nullptr; 407 switch (m_strings.size()) { 408 case 0: { 409 ASSERT(!m_length); 410 result = jsEmptyString(&m_vm); 411 break; 412 } 413 case 1: { 414 result = asString(m_strings.at(0)); 415 break; 416 } 417 case 2: { 418 result = JSRopeString::create(m_vm, asString(m_strings.at(0)), asString(m_strings.at(1))); 419 break; 420 } 421 case 3: { 422 result = JSRopeString::create(m_vm, asString(m_strings.at(0)), asString(m_strings.at(1)), asString(m_strings.at(2))); 423 break; 424 } 425 default: 426 ASSERT_NOT_REACHED(); 427 break; 428 } 429 ASSERT(result->length() == m_length); 430 m_strings.clear(); 431 m_length = 0; 432 return result; 280 433 } 281 434 … … 283 436 { 284 437 ASSERT(!this->hasOverflowed()); 285 return m_ jsString->length();438 return m_length; 286 439 } 287 440 … … 290 443 291 444 VM& m_vm; 292 JSRopeString* m_jsString;293 size_t m_index;445 MarkedArgumentBuffer m_strings; 446 unsigned m_length { 0 }; 294 447 }; 295 448 449 inline unsigned length() const 450 { 451 return m_compactFibers.length(); 452 } 453 296 454 private: 297 ALWAYS_INLINE JSRopeString(VM& vm) 455 void convertToNonRope(String&&) const; 456 457 void initializeIs8Bit(bool flag) const 458 { 459 #if CPU(ADDRESS64) 460 if (flag) 461 m_fiber |= is8BitInPointer; 462 else 463 m_fiber &= ~is8BitInPointer; 464 #else 465 m_compactFibers.initializeIs8Bit(flag); 466 #endif 467 } 468 469 ALWAYS_INLINE void initializeLength(unsigned length) 470 { 471 ASSERT(length <= MaxLength); 472 m_compactFibers.initializeLength(length); 473 } 474 475 JSRopeString(VM& vm, JSString* s1, JSString* s2) 298 476 : JSString(vm) 299 477 { 300 }301 302 void finishCreation(VM& vm, JSString* s1, JSString* s2)303 {304 Base::finishCreation(vm);305 478 ASSERT(!sumOverflows<int32_t>(s1->length(), s2->length())); 306 setLength(s1->length() + s2->length()); 307 setIs8Bit(s1->is8Bit() && s2->is8Bit()); 308 setIsSubstring(false); 309 fiber(0).set(vm, this, s1); 310 fiber(1).set(vm, this, s2); 311 fiber(2).clear(); 312 } 313 314 void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3) 315 { 316 Base::finishCreation(vm); 479 initializeIsSubstring(false); 480 initializeLength(s1->length() + s2->length()); 481 initializeIs8Bit(s1->is8Bit() && s2->is8Bit()); 482 initializeFiber0(s1); 483 initializeFiber1(s2); 484 initializeFiber2(nullptr); 485 ASSERT((s1->length() + s2->length()) == length()); 486 } 487 488 JSRopeString(VM& vm, JSString* s1, JSString* s2, JSString* s3) 489 : JSString(vm) 490 { 317 491 ASSERT(!sumOverflows<int32_t>(s1->length(), s2->length(), s3->length())); 318 setLength(s1->length() + s2->length() + s3->length()); 319 setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); 320 setIsSubstring(false); 321 fiber(0).set(vm, this, s1); 322 fiber(1).set(vm, this, s2); 323 fiber(2).set(vm, this, s3); 324 } 325 326 void finishCreation(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length) 327 { 328 Base::finishCreation(vm); 492 initializeIsSubstring(false); 493 initializeLength(s1->length() + s2->length() + s3->length()); 494 initializeIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); 495 initializeFiber0(s1); 496 initializeFiber1(s2); 497 initializeFiber2(s3); 498 ASSERT((s1->length() + s2->length() + s3->length()) == length()); 499 } 500 501 JSRopeString(VM& vm, JSString* base, unsigned offset, unsigned length) 502 : JSString(vm) 503 { 329 504 RELEASE_ASSERT(!sumOverflows<int32_t>(offset, length)); 330 505 RELEASE_ASSERT(offset + length <= base->length()); 331 setLength(length);332 setIs8Bit(base->is8Bit());333 setIsSubstring(true);506 initializeIsSubstring(true); 507 initializeLength(length); 508 initializeIs8Bit(base->is8Bit()); 334 509 if (base->isSubstring()) { 335 510 JSRopeString* baseRope = jsCast<JSRopeString*>(base); 336 substringBase().set(vm, this, baseRope->substringBase().get());337 substringOffset() = baseRope->substringOffset() + offset;511 initializeSubstringBase(baseRope->substringBase()); 512 initializeSubstringOffset(baseRope->substringOffset() + offset); 338 513 } else { 339 substringBase().set(vm, this, base); 340 substringOffset() = offset; 341 342 // For now, let's not allow substrings with a rope base. 343 // Resolve non-substring rope bases so we don't have to deal with it. 344 // FIXME: Evaluate if this would be worth adding more branches. 345 if (base->isRope()) 346 jsCast<JSRopeString*>(base)->resolveRope(exec); 347 } 348 } 349 350 ALWAYS_INLINE void finishCreationSubstringOfResolved(VM& vm, JSString* base, unsigned offset, unsigned length) 351 { 352 Base::finishCreation(vm); 514 initializeSubstringBase(base); 515 initializeSubstringOffset(offset); 516 } 517 ASSERT(length == this->length()); 518 } 519 520 enum SubstringOfResolvedTag { SubstringOfResolved }; 521 JSRopeString(SubstringOfResolvedTag, VM& vm, JSString* base, unsigned offset, unsigned length) 522 : JSString(vm) 523 { 353 524 RELEASE_ASSERT(!sumOverflows<int32_t>(offset, length)); 354 525 RELEASE_ASSERT(offset + length <= base->length()); 355 setLength(length); 356 setIs8Bit(base->is8Bit()); 357 setIsSubstring(true); 358 substringBase().set(vm, this, base); 359 substringOffset() = offset; 360 } 361 362 void finishCreation(VM& vm) 363 { 364 JSString::finishCreation(vm); 365 setIsSubstring(false); 366 fiber(0).clear(); 367 fiber(1).clear(); 368 fiber(2).clear(); 369 } 370 371 void append(VM& vm, size_t index, JSString* jsString) 372 { 373 fiber(index).set(vm, this, jsString); 374 setLength(length() + jsString->length()); 375 setIs8Bit(is8Bit() && jsString->is8Bit()); 376 } 377 378 static JSRopeString* createNull(VM& vm) 379 { 380 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 526 initializeIsSubstring(true); 527 initializeLength(length); 528 initializeIs8Bit(base->is8Bit()); 529 initializeSubstringBase(base); 530 initializeSubstringOffset(offset); 531 ASSERT(length == this->length()); 532 } 533 534 ALWAYS_INLINE void finishCreationSubstring(VM& vm, ExecState* exec) 535 { 536 Base::finishCreation(vm); 537 JSString* updatedBase = substringBase(); 538 // For now, let's not allow substrings with a rope base. 539 // Resolve non-substring rope bases so we don't have to deal with it. 540 // FIXME: Evaluate if this would be worth adding more branches. 541 if (updatedBase->isRope()) 542 jsCast<JSRopeString*>(updatedBase)->resolveRope(exec); 543 } 544 545 ALWAYS_INLINE void finishCreationSubstringOfResolved(VM& vm) 546 { 547 Base::finishCreation(vm); 548 } 549 550 public: 551 static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfLength(); } // 32byte width. 552 #if CPU(ADDRESS64) 553 static ptrdiff_t offsetOfFlags() { return offsetOfValue() + sizeof(uint16_t) * 3; } // 16byte width. 554 static ptrdiff_t offsetOfFiber0() { return offsetOfValue(); } 555 static ptrdiff_t offsetOfFiber1Lower() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber1Lower(); } // 32byte width. 556 static ptrdiff_t offsetOfFiber1Upper() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber1Upper(); } // 16byte width. 557 static ptrdiff_t offsetOfFiber2Lower() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber2Lower(); } // 32byte width. 558 static ptrdiff_t offsetOfFiber2Upper() { return OBJECT_OFFSETOF(JSRopeString, m_compactFibers) + CompactFibers::offsetOfFiber2Upper(); } // 16byte width. 559 #endif 560 561 static constexpr unsigned s_maxInternalRopeLength = 3; 562 563 private: 564 static JSRopeString* create(VM& vm, JSString* s1, JSString* s2) 565 { 566 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, s1, s2); 381 567 newString->finishCreation(vm); 568 ASSERT(newString->length()); 382 569 return newString; 383 570 } 384 385 public: 386 static JSString* create(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length) 387 { 388 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 389 newString->finishCreation(vm, exec, base, offset, length); 571 static JSRopeString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3) 572 { 573 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, s1, s2, s3); 574 newString->finishCreation(vm); 575 ASSERT(newString->length()); 390 576 return newString; 391 577 } 392 578 393 ALWAYS_INLINE static JSString* createSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* base, unsigned offset, unsigned length) 394 { 395 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(vm); 396 newString->finishCreationSubstringOfResolved(vm, base, offset, length); 579 static JSRopeString* create(VM& vm, ExecState* exec, JSString* base, unsigned offset, unsigned length) 580 { 581 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm, base, offset, length); 582 newString->finishCreationSubstring(vm, exec); 583 ASSERT(newString->length()); 397 584 return newString; 398 585 } 399 586 400 ALWAYS_INLINE static JSString* createSubstringOfResolved(VM& vm, JSString* base, unsigned offset, unsigned length) 401 { 402 return createSubstringOfResolved(vm, nullptr, base, offset, length); 403 } 404 405 void visitFibers(SlotVisitor&); 406 407 static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, u); } 408 409 static const unsigned s_maxInternalRopeLength = 3; 410 411 private: 412 static JSString* create(VM& vm, JSString* s1, JSString* s2) 413 { 414 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 415 newString->finishCreation(vm, s1, s2); 416 return newString; 417 } 418 static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3) 419 { 420 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); 421 newString->finishCreation(vm, s1, s2, s3); 587 ALWAYS_INLINE static JSRopeString* createSubstringOfResolved(VM& vm, GCDeferralContext* deferralContext, JSString* base, unsigned offset, unsigned length) 588 { 589 JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap, deferralContext)) JSRopeString(SubstringOfResolved, vm, base, offset, length); 590 newString->finishCreationSubstringOfResolved(vm); 591 ASSERT(newString->length()); 422 592 return newString; 423 593 } … … 428 598 // If nullOrExecForOOM is null, resolveRope() will be do nothing in the event of an OOM error. 429 599 // The rope value will remain a null string in that case. 430 JS_EXPORT_PRIVATE void resolveRope(ExecState* nullOrExecForOOM) const; 431 JS_EXPORT_PRIVATE void resolveRopeToAtomicString(ExecState*) const; 600 JS_EXPORT_PRIVATE const String& resolveRope(ExecState* nullOrExecForOOM) const; 601 template<typename Function> const String& resolveRopeWithFunction(ExecState* nullOrExecForOOM, Function&&) const; 602 JS_EXPORT_PRIVATE AtomicString resolveRopeToAtomicString(ExecState*) const; 432 603 JS_EXPORT_PRIVATE RefPtr<AtomicStringImpl> resolveRopeToExistingAtomicString(ExecState*) const; 433 604 void resolveRopeSlowCase8(LChar*) const; … … 438 609 void resolveRopeInternal16(UChar*) const; 439 610 void resolveRopeInternal16NoSubstring(UChar*) const; 440 void clearFibers() const;441 611 StringView unsafeView(ExecState*) const; 442 612 StringViewWithUnderlyingString viewWithUnderlyingString(ExecState*) const; 443 613 444 WriteBarrierBase<JSString>& fiber(unsigned i) const 614 JSString* fiber0() const 615 { 616 return bitwise_cast<JSString*>(m_fiber & stringMask); 617 } 618 619 JSString* fiber1() const 620 { 621 return m_compactFibers.fiber1(); 622 } 623 624 JSString* fiber2() const 625 { 626 return m_compactFibers.fiber2(); 627 } 628 629 JSString* fiber(unsigned i) const 445 630 { 446 631 ASSERT(!isSubstring()); 447 632 ASSERT(i < s_maxInternalRopeLength); 448 return u[i].string; 449 } 450 451 WriteBarrierBase<JSString>& substringBase() const 452 { 453 return u[1].string; 454 } 455 456 uintptr_t& substringOffset() const 457 { 458 return u[2].number; 459 } 460 461 static uintptr_t notSubstringSentinel() 633 switch (i) { 634 case 0: 635 return fiber0(); 636 case 1: 637 return fiber1(); 638 case 2: 639 return fiber2(); 640 } 641 ASSERT_NOT_REACHED(); 642 return nullptr; 643 } 644 645 void initializeFiber0(JSString* fiber) 646 { 647 uintptr_t pointer = bitwise_cast<uintptr_t>(fiber); 648 ASSERT(!(pointer & ~stringMask)); 649 m_fiber = (pointer | (m_fiber & ~stringMask)); 650 } 651 652 void initializeFiber1(JSString* fiber) 653 { 654 m_compactFibers.initializeFiber1(fiber); 655 } 656 657 void initializeFiber2(JSString* fiber) 658 { 659 m_compactFibers.initializeFiber2(fiber); 660 } 661 662 void initializeSubstringBase(JSString* fiber) 663 { 664 initializeFiber1(fiber); 665 } 666 667 JSString* substringBase() const { return fiber1(); } 668 669 void initializeSubstringOffset(unsigned offset) 670 { 671 m_compactFibers.initializeFiber2(bitwise_cast<JSString*>(static_cast<uintptr_t>(offset))); 672 } 673 674 unsigned substringOffset() const 675 { 676 return static_cast<unsigned>(bitwise_cast<uintptr_t>(fiber2())); 677 } 678 679 static constexpr uintptr_t notSubstringSentinel() 462 680 { 463 681 return 0; 464 682 } 465 683 466 static uintptr_t substringSentinel()467 { 468 return 1;684 static constexpr uintptr_t substringSentinel() 685 { 686 return 2; 469 687 } 470 688 471 689 bool isSubstring() const 472 690 { 473 return u[0].number == substringSentinel(); 474 } 475 476 void setIsSubstring(bool isSubstring) 477 { 478 u[0].number = isSubstring ? substringSentinel() : notSubstringSentinel(); 479 } 480 481 mutable union { 482 uintptr_t number; 483 WriteBarrierBase<JSString> string; 484 } u[s_maxInternalRopeLength]; 485 691 return (m_fiber & stringMask) == substringSentinel(); 692 } 693 694 void initializeIsSubstring(bool isSubstring) 695 { 696 m_fiber |= (isSubstring ? substringSentinel() : notSubstringSentinel()); 697 } 698 699 static_assert(s_maxInternalRopeLength >= 2, ""); 700 mutable CompactFibers m_compactFibers; 486 701 487 702 friend JSString* jsString(ExecState*, JSString*, JSString*); 488 703 friend JSString* jsString(ExecState*, const String&, JSString*); 489 704 friend JSString* jsString(ExecState*, JSString*, const String&); 705 friend JSString* jsString(ExecState*, const String&, const String&); 490 706 friend JSString* jsString(ExecState*, JSString*, JSString*, JSString*); 491 friend JSString* jsString(ExecState*, const String&, const String&);492 707 friend JSString* jsString(ExecState*, const String&, const String&, const String&); 708 friend JSString* jsSubstringOfResolved(VM&, GCDeferralContext*, JSString*, unsigned, unsigned); 709 friend JSString* jsSubstring(VM&, ExecState*, JSString*, unsigned, unsigned); 493 710 }; 494 711 495 712 JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&); 496 713 714 // JSString::is8Bit is safe to be called concurrently. Concurrent threads can access is8Bit even if the main thread 715 // is in the middle of converting JSRopeString to JSString. 716 ALWAYS_INLINE bool JSString::is8Bit() const 717 { 718 uintptr_t pointer = m_fiber; 719 if (pointer & isRopeInPointer) { 720 #if CPU(ADDRESS64) 721 // Do not load m_fiber twice. We should use the information in pointer. 722 // Otherwise, JSRopeString may be converted to JSString between the first and second accesses. 723 return pointer & JSRopeString::is8BitInPointer; 724 #else 725 // It is OK to load flag since even if JSRopeString is converted to JSString, this flag still exists. 726 return jsCast<const JSRopeString*>(this)->m_compactFibers.is8Bit(); 727 #endif 728 } 729 return bitwise_cast<StringImpl*>(pointer)->is8Bit(); 730 } 731 732 // JSString::length is safe to be called concurrently. Concurrent threads can access length even if the main thread 733 // is in the middle of converting JSRopeString to JSString. This is OK because we never override the length bits 734 // when we resolve a JSRopeString. 735 ALWAYS_INLINE unsigned JSString::length() const 736 { 737 uintptr_t pointer = m_fiber; 738 if (pointer & isRopeInPointer) 739 return jsCast<const JSRopeString*>(this)->length(); 740 return bitwise_cast<StringImpl*>(pointer)->length(); 741 } 742 497 743 inline const StringImpl* JSString::tryGetValueImpl() const 498 744 { 499 return m_value.impl(); 745 uintptr_t pointer = m_fiber; 746 if (pointer & isRopeInPointer) 747 return nullptr; 748 return bitwise_cast<StringImpl*>(pointer); 500 749 } 501 750 … … 543 792 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 544 793 if (isRope()) 545 static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec);546 return AtomicString( m_value);794 return static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec); 795 return AtomicString(valueInternal()); 547 796 } 548 797 … … 553 802 if (isRope()) 554 803 return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec); 555 if ( m_value.impl()->isAtomic())556 return static_cast<AtomicStringImpl*>( m_value.impl());557 return AtomicStringImpl::lookUp( m_value.impl());804 if (valueInternal().impl()->isAtomic()) 805 return static_cast<AtomicStringImpl*>(valueInternal().impl()); 806 return AtomicStringImpl::lookUp(valueInternal().impl()); 558 807 } 559 808 … … 563 812 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 564 813 if (isRope()) 565 static_cast<const JSRopeString*>(this)->resolveRope(exec);566 return m_value;814 return static_cast<const JSRopeString*>(this)->resolveRope(exec); 815 return valueInternal(); 567 816 } 568 817 … … 574 823 if (isRope()) { 575 824 // Pass nullptr for the ExecState so that resolveRope does not throw in the event of an OOM error. 576 static_cast<const JSRopeString*>(this)->resolveRope(nullptr);825 return static_cast<const JSRopeString*>(this)->resolveRope(nullptr); 577 826 } 578 827 } else 579 828 RELEASE_ASSERT(!isRope()); 580 return m_value;829 return valueInternal(); 581 830 } 582 831 … … 669 918 } 670 919 671 inline JSRopeString* jsStringBuilder(VM* vm)672 {673 return JSRopeString::createNull(*vm);674 }675 676 920 inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); } 677 921 inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); } … … 754 998 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 755 999 if (isSubstring()) { 756 if (is8Bit())757 return StringView(substringBase()->m_value.characters8() + substringOffset(), length());758 return StringView(substringBase()->m_value.characters16() + substringOffset(), length());759 }760 resolveRope(exec);761 return m_value;1000 auto& base = substringBase()->valueInternal(); 1001 if (base.is8Bit()) 1002 return StringView(base.characters8() + substringOffset(), length()); 1003 return StringView(base.characters16() + substringOffset(), length()); 1004 } 1005 return resolveRope(exec); 762 1006 } 763 1007 … … 767 1011 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 768 1012 if (isSubstring()) { 769 auto& base = substringBase()-> m_value;770 if ( is8Bit())1013 auto& base = substringBase()->valueInternal(); 1014 if (base.is8Bit()) 771 1015 return { { base.characters8() + substringOffset(), length() }, base }; 772 1016 return { { base.characters16() + substringOffset(), length() }, base }; 773 1017 } 774 resolveRope(exec);775 return { m_value, m_value};1018 auto& string = resolveRope(exec); 1019 return { string, string }; 776 1020 } 777 1021 … … 782 1026 if (isRope()) 783 1027 return static_cast<const JSRopeString*>(this)->unsafeView(exec); 784 return m_value;1028 return valueInternal(); 785 1029 } 786 1030 … … 789 1033 if (isRope()) 790 1034 return static_cast<const JSRopeString&>(*this).viewWithUnderlyingString(exec); 791 return { m_value, m_value};1035 return { valueInternal(), valueInternal() }; 792 1036 } 793 1037 -
trunk/Source/JavaScriptCore/runtime/JSStringInlines.h
r242081 r242252 30 30 namespace JSC { 31 31 32 inline JSString::~JSString() 33 { 34 if (isRope()) 35 return; 36 valueInternal().~String(); 37 } 38 32 39 bool JSString::equal(ExecState* exec, JSString* other) const 33 40 { 34 41 if (isRope() || other->isRope()) 35 42 return equalSlowCase(exec, other); 36 return WTF::equal(* m_value.impl(), *other->m_value.impl());43 return WTF::equal(*valueInternal().impl(), *other->valueInternal().impl()); 37 44 } 38 45 -
trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
r240327 r242252 333 333 RETURN_IF_EXCEPTION(scope, { }); 334 334 if (stringTag.isString()) { 335 JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm); 336 ropeBuilder.append(vm.smallStrings.objectStringStart()); 337 ropeBuilder.append(asString(stringTag)); 338 ropeBuilder.append(vm.smallStrings.singleCharacterString(']')); 339 if (ropeBuilder.hasOverflowed()) 340 return throwOutOfMemoryError(exec, scope); 341 342 JSString* result = ropeBuilder.release(); 335 JSString* result = jsString(exec, vm.smallStrings.objectStringStart(), asString(stringTag), vm.smallStrings.singleCharacterString(']')); 336 RETURN_IF_EXCEPTION(scope, { }); 343 337 thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot); 344 338 return result; -
trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
r241927 r242252 121 121 JSValue value; 122 122 if (start >= 0) 123 value = JSRopeString::createSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start);123 value = jsSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start); 124 124 else 125 125 value = jsUndefined(); … … 145 145 JSValue value; 146 146 if (start >= 0) 147 value = JSRopeString::createSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start);147 value = jsSubstringOfResolved(vm, &deferralContext, input, start, subpatternResults[2 * i + 1] - start); 148 148 else 149 149 value = jsUndefined(); -
trunk/Source/JavaScriptCore/runtime/RegExpObjectInlines.h
r240593 r242252 163 163 size_t end = result.end; 164 164 size_t length = end - result.start; 165 array->putDirectIndex(exec, arrayIndex++, JSRopeString::createSubstringOfResolved(vm, string, result.start, length));165 array->putDirectIndex(exec, arrayIndex++, jsSubstringOfResolved(vm, string, result.start, length)); 166 166 if (UNLIKELY(scope.exception())) { 167 167 hasException = true; -
trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
r240593 r242252 654 654 }, 655 655 [&] (bool isDefined, unsigned start, unsigned length) -> SplitControl { 656 result->putDirectIndex(exec, resultLength++, isDefined ? JSRopeString::createSubstringOfResolved(vm, inputString, start, length) : jsUndefined());656 result->putDirectIndex(exec, resultLength++, isDefined ? jsSubstringOfResolved(vm, inputString, start, length) : jsUndefined()); 657 657 RETURN_IF_EXCEPTION(scope, AbortSplit); 658 658 if (resultLength >= limit) … … 668 668 // 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T). 669 669 scope.release(); 670 result->putDirectIndex(exec, resultLength, JSRopeString::createSubstringOfResolved(vm, inputString, position, inputSize - position));670 result->putDirectIndex(exec, resultLength, jsSubstringOfResolved(vm, inputString, position, inputSize - position)); 671 671 672 672 // 22. Return A. … … 707 707 }, 708 708 [&] (bool isDefined, unsigned start, unsigned length) -> SplitControl { 709 result->putDirectIndex(exec, resultLength++, isDefined ? JSRopeString::createSubstringOfResolved(vm, inputString, start, length) : jsUndefined());709 result->putDirectIndex(exec, resultLength++, isDefined ? jsSubstringOfResolved(vm, inputString, start, length) : jsUndefined()); 710 710 RETURN_IF_EXCEPTION(scope, AbortSplit); 711 711 if (resultLength >= limit) … … 721 721 // 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T). 722 722 scope.release(); 723 result->putDirectIndex(exec, resultLength, JSRopeString::createSubstringOfResolved(vm, inputString, position, inputSize - position));723 result->putDirectIndex(exec, resultLength, jsSubstringOfResolved(vm, inputString, position, inputSize - position)); 724 724 // 22. Return A. 725 725 return JSValue::encode(result); -
trunk/Source/JavaScriptCore/runtime/SmallStrings.cpp
r241955 r242252 45 45 void SmallStrings::initializeCommonStrings(VM& vm) 46 46 { 47 createEmptyString(&vm); 47 ASSERT(!m_emptyString); 48 m_emptyString = JSString::createEmptyString(vm); 49 ASSERT(m_needsToBeVisited); 48 50 49 51 for (unsigned i = 0; i < singleCharacterStringCount; ++i) { … … 82 84 } 83 85 84 void SmallStrings::createEmptyString(VM* vm)85 {86 ASSERT(!m_emptyString);87 m_emptyString = JSString::createHasOtherOwner(*vm, *StringImpl::empty());88 ASSERT(m_needsToBeVisited);89 }90 91 86 Ref<StringImpl> SmallStrings::singleCharacterStringRep(unsigned char character) 92 87 { -
trunk/Source/JavaScriptCore/runtime/SmallStrings.h
r241954 r242252 128 128 static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1; 129 129 130 void createEmptyString(VM*);131 132 130 void initialize(VM*, JSString*&, const char* value); 133 131 -
trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp
r242081 r242252 46 46 #include "RegExpConstructor.h" 47 47 #include "RegExpGlobalDataInlines.h" 48 #include "StringPrototypeInlines.h" 48 49 #include "SuperSampler.h" 49 50 #include <algorithm> … … 1142 1143 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1143 1144 1145 JSValue a0 = exec->argument(0); 1146 JSValue a1 = exec->argument(1); 1147 1144 1148 int len = s.length(); 1145 1149 RELEASE_ASSERT(len >= 0); 1146 1150 1147 JSValue a0 = exec->argument(0);1148 JSValue a1 = exec->argument(1);1149 1150 1151 // The arg processing is very much like ArrayProtoFunc::Slice 1151 1152 double start = a0.toInteger(exec); … … 1153 1154 double end = a1.isUndefined() ? len : a1.toInteger(exec); 1154 1155 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1155 double from = start < 0 ? len + start : start; 1156 double to = end < 0 ? len + end : end; 1157 if (to > from && to > 0 && from < len) { 1158 if (from < 0) 1159 from = 0; 1160 if (to > len) 1161 to = len; 1162 return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from))); 1163 } 1164 1165 return JSValue::encode(jsEmptyString(exec)); 1156 scope.release(); 1157 return JSValue::encode(stringSlice(exec, WTFMove(s), start, end)); 1166 1158 } 1167 1159 -
trunk/Source/WTF/ChangeLog
r242235 r242252 1 2019-02-28 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] sizeof(JSString) should be 16 4 https://bugs.webkit.org/show_bug.cgi?id=194375 5 6 Reviewed by Saam Barati. 7 8 * wtf/text/StringImpl.h: 9 (WTF::StringImpl::flagIs8Bit): 10 (WTF::StringImpl::flagIsAtomic): 11 (WTF::StringImpl::flagIsSymbol): 12 (WTF::StringImpl::maskStringKind): 13 * wtf/text/WTFString.cpp: 14 (WTF::nullString): 15 * wtf/text/WTFString.h: 16 1 17 2019-02-28 Mark Lam <mark.lam@apple.com> 2 18 -
trunk/Source/WTF/wtf/text/StringImpl.h
r241493 r242252 201 201 static constexpr const unsigned s_hashFlagStringKindIsSymbol = 1u << (s_flagStringKindCount + 1); 202 202 static constexpr const unsigned s_hashMaskStringKind = s_hashFlagStringKindIsAtomic | s_hashFlagStringKindIsSymbol; 203 static constexpr const unsigned s_hashFlag 8BitBuffer= 1u << 3;204 static constexpr const unsigned s_hashFlag DidReportCost= 1u << 2;203 static constexpr const unsigned s_hashFlagDidReportCost = 1u << 3; 204 static constexpr const unsigned s_hashFlag8BitBuffer = 1u << 2; 205 205 static constexpr const unsigned s_hashMaskBufferOwnership = (1u << 0) | (1u << 1); 206 206 … … 265 265 266 266 static unsigned flagsOffset() { return OBJECT_OFFSETOF(StringImpl, m_hashAndFlags); } 267 static unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; }268 static unsigned flagIsAtomic() { return s_hashFlagStringKindIsAtomic; }269 static unsigned flagIsSymbol() { return s_hashFlagStringKindIsSymbol; }270 static unsigned maskStringKind() { return s_hashMaskStringKind; }267 static constexpr unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; } 268 static constexpr unsigned flagIsAtomic() { return s_hashFlagStringKindIsAtomic; } 269 static constexpr unsigned flagIsSymbol() { return s_hashFlagStringKindIsSymbol; } 270 static constexpr unsigned maskStringKind() { return s_hashMaskStringKind; } 271 271 static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data8); } 272 272 -
trunk/Source/WTF/wtf/text/WTFString.cpp
r242189 r242252 1122 1122 } 1123 1123 1124 const String& nullString() 1125 { 1126 static NeverDestroyed<String> nullString; 1127 return nullString; 1128 } 1129 1124 1130 } // namespace WTF 1125 1131 -
trunk/Source/WTF/wtf/text/WTFString.h
r242189 r242252 424 424 template<typename CharacterType> void appendNumber(Vector<CharacterType>&, unsigned char number); 425 425 426 // Shared global empty string.426 // Shared global empty and null string. 427 427 WTF_EXPORT_PRIVATE const String& emptyString(); 428 WTF_EXPORT_PRIVATE const String& nullString(); 428 429 429 430 template<typename> struct DefaultHash; … … 659 660 using WTF::charactersToUIntStrict; 660 661 using WTF::emptyString; 662 using WTF::nullString; 661 663 using WTF::equal; 662 664 using WTF::find;
Note: See TracChangeset
for help on using the changeset viewer.