Ignore:
Timestamp:
Dec 17, 2019, 2:12:00 PM (6 years ago)
Author:
[email protected]
Message:

[JSC] 8Bit JSRopeString can contain 16Bit string in its rope
https://bugs.webkit.org/show_bug.cgi?id=205323

Reviewed by Mark Lam.

JSTests:

  • stress/8bit-resolve-can-encounter-16bit-string.js: Added.

(foo):

Source/JavaScriptCore:

When resolving JSRopeString, it is possible that 8Bit JSRopeString becomes 16Bit resolved JSString.
This happens when we attempt to resolve it to produce AtomicStringImpl, and 16Bit version of the
resolved content is already in AtomicStringTable. This means that 16Bit flag never changes after resolving
JSString, but that of JSRopeString is some sort of hint, which can be changed.

This means that 8Bit JSRopeString can include 16Bit JSString, since some of children can be changed from
8Bit JSRopeString to resolved 16Bit JSString. Even in that case, we can still ensure that resolved string
can be represented as 8Bit. Let's see the example.

A => B + C, 8Bit Rope
B => D + E, 8Bit Rope
C => 8Bit String

And when we convert B to 16Bit String since content of D + E is already registered as 16Bit String in AtomicStringTable.

A => B + C, 8Bit Rope
B => 16Bit String
C => 8Bit String

When resolving A, creating 8Bit string buffer is totally OK since we know that whole A string can be represented in 8Bit.
When copying the content of B into 8Bit buffer, we should ignore upper 8Bit since they must be zero.

In this patch, we completely share the implementation of resolveRopeInternalNoSubstring and resolveRopeSlowCase in 8Bit and
16Bit case: we take result buffer CharacterType, but the underlying code must check is8Bit() for each fiber.

  • runtime/JSCJSValue.cpp:

(JSC::JSValue::dumpInContextAssumingStructure const):

  • runtime/JSString.cpp:

(JSC::JSRopeString::resolveRopeInternal8 const):
(JSC::JSRopeString::resolveRopeInternal16 const):
(JSC::JSRopeString::resolveRopeInternalNoSubstring const):
(JSC::JSRopeString::resolveRopeWithFunction const):
(JSC::JSRopeString::resolveRopeSlowCase const):
(JSC::JSRopeString::resolveRopeInternal8NoSubstring const): Deleted.
(JSC::JSRopeString::resolveRopeInternal16NoSubstring const): Deleted.
(JSC::JSRopeString::resolveRopeSlowCase8 const): Deleted.

  • runtime/JSString.h:

Source/WTF:

  • wtf/text/StringImpl.h:

(WTF::StringImpl::copyCharacters):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSString.cpp

    r252843 r253648  
    154154    }
    155155   
    156     resolveRopeInternal8NoSubstring(buffer);
    157 }
    158 
    159 void JSRopeString::resolveRopeInternal8NoSubstring(LChar* buffer) const
    160 {
    161     for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
    162         if (fiber(i)->isRope()) {
    163             resolveRopeSlowCase8(buffer);
    164             return;
    165         }
    166     }
    167 
    168     LChar* position = buffer;
    169     for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
    170         const StringImpl& fiberString = *fiber(i)->valueInternal().impl();
    171         unsigned length = fiberString.length();
    172         StringImpl::copyCharacters(position, fiberString.characters8(), length);
    173         position += length;
    174     }
    175     ASSERT((buffer + length()) == position);
     156    resolveRopeInternalNoSubstring(buffer);
    176157}
    177158
     
    184165    }
    185166   
    186     resolveRopeInternal16NoSubstring(buffer);
    187 }
    188 
    189 void JSRopeString::resolveRopeInternal16NoSubstring(UChar* buffer) const
     167    resolveRopeInternalNoSubstring(buffer);
     168}
     169
     170template<typename CharacterType>
     171void JSRopeString::resolveRopeInternalNoSubstring(CharacterType* buffer) const
    190172{
    191173    for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
     
    196178    }
    197179
    198     UChar* position = buffer;
     180    CharacterType* position = buffer;
    199181    for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
    200182        const StringImpl& fiberString = *fiber(i)->valueInternal().impl();
     
    307289        vm.heap.reportExtraMemoryAllocated(newImpl->cost());
    308290
    309         resolveRopeInternal8NoSubstring(buffer);
     291        resolveRopeInternalNoSubstring(buffer);
    310292        convertToNonRope(function(newImpl.releaseNonNull()));
    311293        return valueInternal();
     
    320302    vm.heap.reportExtraMemoryAllocated(newImpl->cost());
    321303   
    322     resolveRopeInternal16NoSubstring(buffer);
     304    resolveRopeInternalNoSubstring(buffer);
    323305    convertToNonRope(function(newImpl.releaseNonNull()));
    324306    return valueInternal();
     
    342324// only fill the queue with the number of substrings at any given level in a
    343325// rope-of-ropes.)
    344 void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const
    345 {
    346     LChar* position = buffer + length(); // We will be working backwards over the rope.
    347     Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method.
    348    
    349     for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i)
    350         workQueue.append(fiber(i));
    351 
    352     while (!workQueue.isEmpty()) {
    353         JSString* currentFiber = workQueue.last();
    354         workQueue.removeLast();
    355 
    356         const LChar* characters;
    357        
    358         if (currentFiber->isRope()) {
    359             JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber);
    360             if (!currentFiberAsRope->isSubstring()) {
    361                 for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i)
    362                     workQueue.append(currentFiberAsRope->fiber(i));
    363                 continue;
    364             }
    365             ASSERT(!currentFiberAsRope->substringBase()->isRope());
    366             characters =
    367                 currentFiberAsRope->substringBase()->valueInternal().characters8() +
    368                 currentFiberAsRope->substringOffset();
    369         } else
    370             characters = currentFiber->valueInternal().characters8();
    371        
    372         unsigned length = currentFiber->length();
    373         position -= length;
    374         StringImpl::copyCharacters(position, characters, length);
    375     }
    376 
    377     ASSERT(buffer == position);
    378 }
    379 
    380 void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
    381 {
    382     UChar* position = buffer + length(); // We will be working backwards over the rope.
     326template<typename CharacterType>
     327void JSRopeString::resolveRopeSlowCase(CharacterType* buffer) const
     328{
     329    CharacterType* position = buffer + length(); // We will be working backwards over the rope.
    383330    Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK.
    384331
Note: See TracChangeset for help on using the changeset viewer.