Ignore:
Timestamp:
Dec 3, 2009, 6:15:18 PM (15 years ago)
Author:
[email protected]
Message:

https://bugs.webkit.org/show_bug.cgi?id=32136
Add a rope representation to JSString. Presently JSString always holds its data in UString form.
Instead, allow the result of a string concatenation to be represented in a tree form - with a
variable sized, reference-counted rope node retaining a set of UString::Reps (or other rope nopes).

Reviewed by Oliver "Brraaaaiiiinnnnnzzzzzzzz" Hunt.

Strings must still currently be resolved down to a flat UString representation before being used,
but by holding the string in a rope representation during construction we can avoid copying data
until we know the final size of the string.

~2% progression on SunSpider (~25% on date-format-xparb, ~20% on string-validate-input).

  • Update exports.
  • interpreter/Interpreter.cpp:

(JSC::Interpreter::privateExecute):

  • Make use of new JSString::length() method to avoid prematurely resolving ropes.
  • jit/JITOpcodes.cpp:

(JSC::JIT::privateCompileCTIMachineTrampolines):

  • Switch the string length trampoline to read the length directly from JSString::m_length, rather than from the JSString's UString::Rep's 'len' property.
  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • Modify op_add such that addition of two strings, where either or both strings are already in rope representation, produces a rope as a result.
  • runtime/JSString.cpp:

(JSC::JSString::Rope::~Rope):
(JSC::copyChars):
(JSC::JSString::resolveRope):
(JSC::JSString::getPrimitiveNumber):
(JSC::JSString::toBoolean):
(JSC::JSString::toNumber):
(JSC::JSString::toString):
(JSC::JSString::toThisString):
(JSC::JSString::getStringPropertyDescriptor):

  • runtime/JSString.h:

(JSC::JSString::Rope::Fiber::Fiber):
(JSC::JSString::Rope::Fiber::destroy):
(JSC::JSString::Rope::Fiber::isRope):
(JSC::JSString::Rope::Fiber::rope):
(JSC::JSString::Rope::Fiber::string):
(JSC::JSString::Rope::create):
(JSC::JSString::Rope::initializeFiber):
(JSC::JSString::Rope::ropeLength):
(JSC::JSString::Rope::stringLength):
(JSC::JSString::Rope::fibers):
(JSC::JSString::Rope::Rope):
(JSC::JSString::Rope::operator new):
(JSC::JSString::JSString):
(JSC::JSString::value):
(JSC::JSString::length):
(JSC::JSString::isRope):
(JSC::JSString::rope):
(JSC::JSString::string):
(JSC::JSString::canGetIndex):
(JSC::jsSingleCharacterSubstring):
(JSC::JSString::getIndex):
(JSC::jsSubstring):
(JSC::JSString::getStringPropertySlot):

  • Add rope form.
  • runtime/Operations.h:

(JSC::jsAdd):
(JSC::concatenateStrings):

  • Update string concatenation, and addition of ropes, to produce ropes.
  • runtime/StringObject.cpp:

(JSC::StringObject::getOwnPropertyNames):

  • Make use of new JSString::length() method to avoid prematurely resolving ropes.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/Operations.h

    r50704 r51671  
    205205        bool leftIsString = v1.isString();
    206206        if (leftIsString && v2.isString()) {
     207            if (asString(v1)->isRope() || asString(v2)->isRope()) {
     208                RefPtr<JSString::Rope> rope = JSString::Rope::create(2);
     209                rope->initializeFiber(0, asString(v1));
     210                rope->initializeFiber(1, asString(v2));
     211                JSGlobalData* globalData = &callFrame->globalData();
     212                return new (globalData) JSString(globalData, rope.release());
     213            }
     214
    207215            RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep());
    208216            if (!value)
     
    299307        ASSERT(count >= 3);
    300308
    301         // Estimate the amount of space required to hold the entire string.  If all
    302         // arguments are strings, we can easily calculate the exact amount of space
    303         // required.  For any other arguments, for now let's assume they may require
    304         // 11 UChars of storage.  This is enouch to hold any int, and likely is also
    305         // reasonable for the other immediates.  We may want to come back and tune
    306         // this value at some point.
    307         unsigned bufferSize = 0;
     309        RefPtr<JSString::Rope> rope = JSString::Rope::create(count);
     310
    308311        for (unsigned i = 0; i < count; ++i) {
    309312            JSValue v = strings[i].jsValue();
    310313            if (LIKELY(v.isString()))
    311                 bufferSize += asString(v)->value().size();
     314                rope->initializeFiber(i, asString(v));
    312315            else
    313                 bufferSize += 11;
    314         }
    315 
    316         // Allocate an output string to store the result.
    317         // If the first argument is a String, and if it has the capacity (or can grow
    318         // its capacity) to hold the entire result then use this as a base to concatenate
    319         // onto.  Otherwise, allocate a new empty output buffer.
    320         JSValue firstValue = strings[0].jsValue();
    321         RefPtr<UString::Rep> resultRep;
    322         if (firstValue.isString() && (resultRep = asString(firstValue)->value().rep())->reserveCapacity(bufferSize)) {
    323             // We're going to concatenate onto the first string - remove it from the list of items to be appended.
    324             ++strings;
    325             --count;
    326         } else
    327             resultRep = UString::Rep::createEmptyBuffer(bufferSize);
    328         UString result(resultRep);
    329 
    330         // Loop over the operands, writing them into the output buffer.
    331         for (unsigned i = 0; i < count; ++i) {
    332             JSValue v = strings[i].jsValue();
    333             if (LIKELY(v.isString()))
    334                 result.append(asString(v)->value());
    335             else
    336                 result.append(v.toString(callFrame));
    337         }
    338 
    339         return jsString(callFrame, result);
    340     }
    341 
     316                rope->initializeFiber(i, v.toString(callFrame).rep());
     317        }
     318
     319        JSGlobalData* globalData = &callFrame->globalData();
     320        return new (globalData) JSString(globalData, rope.release());
     321    }
    342322} // namespace JSC
    343323
Note: See TracChangeset for help on using the changeset viewer.