Title: [100314] trunk/Source/_javascript_Core
Revision
100314
Author
msab...@apple.com
Date
2011-11-15 13:38:35 -0800 (Tue, 15 Nov 2011)

Log Message

Towards 8 bit Strings - Initial JS String Tuning
https://bugs.webkit.org/show_bug.cgi?id=72326

Added 8 bit optimized paths for the methods below.

Reviewed by Geoffrey Garen.

* runtime/JSString.h:
(JSC::jsSubstring8):
* runtime/StringPrototype.cpp:
(JSC::jsSpliceSubstrings):
(JSC::jsSpliceSubstringsWithSeparators):
(JSC::stringProtoFuncReplace):
(JSC::stringProtoFuncCharCodeAt):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (100313 => 100314)


--- trunk/Source/_javascript_Core/ChangeLog	2011-11-15 21:03:52 UTC (rev 100313)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-11-15 21:38:35 UTC (rev 100314)
@@ -1,3 +1,20 @@
+2011-11-15  Michael Saboff  <msab...@apple.com>
+
+        Towards 8 bit Strings - Initial JS String Tuning
+        https://bugs.webkit.org/show_bug.cgi?id=72326
+
+        Added 8 bit optimized paths for the methods below.
+
+        Reviewed by Geoffrey Garen.
+
+        * runtime/JSString.h:
+        (JSC::jsSubstring8):
+        * runtime/StringPrototype.cpp:
+        (JSC::jsSpliceSubstrings):
+        (JSC::jsSpliceSubstringsWithSeparators):
+        (JSC::stringProtoFuncReplace):
+        (JSC::stringProtoFuncCharCodeAt):
+
 2011-11-15  Gavin Barraclough  <barraclo...@apple.com>
 
         Result of Error.prototype.toString not ES5 conformant

Modified: trunk/Source/_javascript_Core/runtime/JSString.h (100313 => 100314)


--- trunk/Source/_javascript_Core/runtime/JSString.h	2011-11-15 21:03:52 UTC (rev 100313)
+++ trunk/Source/_javascript_Core/runtime/JSString.h	2011-11-15 21:38:35 UTC (rev 100314)
@@ -363,6 +363,21 @@
         return jsSubstring(globalData, s->value(exec), offset, length);
     }
 
+    inline JSString* jsSubstring8(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
+    {
+        ASSERT(offset <= static_cast<unsigned>(s.length()));
+        ASSERT(length <= static_cast<unsigned>(s.length()));
+        ASSERT(offset + length <= static_cast<unsigned>(s.length()));
+        if (!length)
+            return globalData->smallStrings.emptyString(globalData);
+        if (length == 1) {
+            UChar c = s[offset];
+            if (c <= maxSingleCharacterString)
+                return globalData->smallStrings.singleCharacterString(globalData, c);
+        }
+        return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, StringImpl::create8(s.impl(), offset, length)));
+    }
+
     inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
     {
         ASSERT(offset <= static_cast<unsigned>(s.length()));
@@ -399,6 +414,7 @@
     inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
     inline JSString* jsString(ExecState* exec, const UString& s) { return jsString(&exec->globalData(), s); }
     inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->globalData(), c); }
+    inline JSString* jsSubstring8(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->globalData(), s, offset, length); }
     inline JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring(&exec->globalData(), s, offset, length); }
     inline JSString* jsNontrivialString(ExecState* exec, const UString& s) { return jsNontrivialString(&exec->globalData(), s); }
     inline JSString* jsNontrivialString(ExecState* exec, const char* s) { return jsNontrivialString(&exec->globalData(), s); }

Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (100313 => 100314)


--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2011-11-15 21:03:52 UTC (rev 100313)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2011-11-15 21:38:35 UTC (rev 100314)
@@ -283,7 +283,27 @@
     if (!totalLength)
         return jsString(exec, "");
 
+    if (source.is8Bit()) {
+        LChar* buffer;
+        const LChar* sourceData = source.characters8();
+        RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
+        if (!impl)
+            return throwOutOfMemoryError(exec);
+
+        int bufferPos = 0;
+        for (int i = 0; i < rangeCount; i++) {
+            if (int srcLen = substringRanges[i].length) {
+                StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
+                bufferPos += srcLen;
+            }
+        }
+
+        return jsString(exec, impl.release());
+    }
+
     UChar* buffer;
+    const UChar* sourceData = source.characters16();
+
     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
     if (!impl)
         return throwOutOfMemoryError(exec);
@@ -291,7 +311,7 @@
     int bufferPos = 0;
     for (int i = 0; i < rangeCount; i++) {
         if (int srcLen = substringRanges[i].length) {
-            StringImpl::copyChars(buffer + bufferPos, source.characters() + substringRanges[i].position, srcLen);
+            StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
             bufferPos += srcLen;
         }
     }
@@ -312,14 +332,46 @@
     }
 
     int totalLength = 0;
+    bool allSeperators8Bit = true;
     for (int i = 0; i < rangeCount; i++)
         totalLength += substringRanges[i].length;
-    for (int i = 0; i < separatorCount; i++)
+    for (int i = 0; i < separatorCount; i++) {
         totalLength += separators[i].length();
+        if (separators[i].length() && !separators[i].is8Bit())
+            allSeperators8Bit = false;
+    }
 
     if (!totalLength)
         return jsString(exec, "");
 
+    if (source.is8Bit() && allSeperators8Bit) {
+        LChar* buffer;
+        const LChar* sourceData = source.characters8();
+
+        RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
+        if (!impl)
+            return throwOutOfMemoryError(exec);
+
+        int maxCount = max(rangeCount, separatorCount);
+        int bufferPos = 0;
+        for (int i = 0; i < maxCount; i++) {
+            if (i < rangeCount) {
+                if (int srcLen = substringRanges[i].length) {
+                    StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
+                    bufferPos += srcLen;
+                }
+            }
+            if (i < separatorCount) {
+                if (int sepLen = separators[i].length()) {
+                    StringImpl::copyChars(buffer + bufferPos, separators[i].characters8(), sepLen);
+                    bufferPos += sepLen;
+                }
+            }
+        }        
+
+        return jsString(exec, impl.release());
+    }
+
     UChar* buffer;
     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
     if (!impl)
@@ -330,13 +382,13 @@
     for (int i = 0; i < maxCount; i++) {
         if (i < rangeCount) {
             if (int srcLen = substringRanges[i].length) {
-                StringImpl::copyChars(buffer + bufferPos, source.characters16() + substringRanges[i].position, srcLen);
+                StringImpl::copyChars(buffer + bufferPos, source.characters() + substringRanges[i].position, srcLen);
                 bufferPos += srcLen;
             }
         }
         if (i < separatorCount) {
             if (int sepLen = separators[i].length()) {
-                StringImpl::copyChars(buffer + bufferPos, separators[i].characters16(), sepLen);
+                StringImpl::copyChars(buffer + bufferPos, separators[i].characters(), sepLen);
                 bufferPos += sepLen;
             }
         }
@@ -423,48 +475,95 @@
             CachedCall cachedCall(exec, func, argCount);
             if (exec->hadException())
                 return JSValue::encode(jsNull());
-            while (true) {
-                int matchIndex;
-                int matchLen = 0;
-                int* ovector;
-                regExpConstructor->performMatch(*globalData, reg, source, startPosition, matchIndex, matchLen, &ovector);
-                if (matchIndex < 0)
-                    break;
+            if (source.is8Bit()) {
+                while (true) {
+                    int matchIndex;
+                    int matchLen = 0;
+                    int* ovector;
+                    regExpConstructor->performMatch(*globalData, reg, source, startPosition, matchIndex, matchLen, &ovector);
+                    if (matchIndex < 0)
+                        break;
 
-                sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+                    sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
 
-                int completeMatchStart = ovector[0];
-                unsigned i = 0;
-                for (; i < reg->numSubpatterns() + 1; ++i) {
-                    int matchStart = ovector[i * 2];
-                    int matchLen = ovector[i * 2 + 1] - matchStart;
+                    int completeMatchStart = ovector[0];
+                    unsigned i = 0;
+                    for (; i < reg->numSubpatterns() + 1; ++i) {
+                        int matchStart = ovector[i * 2];
+                        int matchLen = ovector[i * 2 + 1] - matchStart;
 
-                    if (matchStart < 0)
-                        cachedCall.setArgument(i, jsUndefined());
+                        if (matchStart < 0)
+                            cachedCall.setArgument(i, jsUndefined());
+                        else
+                            cachedCall.setArgument(i, jsSubstring8(globalData, source, matchStart, matchLen));
+                    }
+
+                    cachedCall.setArgument(i++, jsNumber(completeMatchStart));
+                    cachedCall.setArgument(i++, sourceVal);
+
+                    cachedCall.setThis(jsUndefined());
+                    JSValue result = cachedCall.call();
+                    if (LIKELY(result.isString()))
+                        replacements.append(asString(result)->value(exec));
                     else
-                        cachedCall.setArgument(i, jsSubstring(exec, source, matchStart, matchLen));
+                        replacements.append(result.toString(cachedCall.newCallFrame(exec)));
+                    if (exec->hadException())
+                        break;
+
+                    lastIndex = matchIndex + matchLen;
+                    startPosition = lastIndex;
+
+                    // special case of empty match
+                    if (!matchLen) {
+                        startPosition++;
+                        if (startPosition > sourceLen)
+                            break;
+                    }
                 }
+            } else {
+                while (true) {
+                    int matchIndex;
+                    int matchLen = 0;
+                    int* ovector;
+                    regExpConstructor->performMatch(*globalData, reg, source, startPosition, matchIndex, matchLen, &ovector);
+                    if (matchIndex < 0)
+                        break;
 
-                cachedCall.setArgument(i++, jsNumber(completeMatchStart));
-                cachedCall.setArgument(i++, sourceVal);
+                    sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
 
-                cachedCall.setThis(jsUndefined());
-                JSValue result = cachedCall.call();
-                if (LIKELY(result.isString()))
-                    replacements.append(asString(result)->value(exec));
-                else
-                    replacements.append(result.toString(cachedCall.newCallFrame(exec)));
-                if (exec->hadException())
-                    break;
+                    int completeMatchStart = ovector[0];
+                    unsigned i = 0;
+                    for (; i < reg->numSubpatterns() + 1; ++i) {
+                        int matchStart = ovector[i * 2];
+                        int matchLen = ovector[i * 2 + 1] - matchStart;
 
-                lastIndex = matchIndex + matchLen;
-                startPosition = lastIndex;
+                        if (matchStart < 0)
+                            cachedCall.setArgument(i, jsUndefined());
+                        else
+                            cachedCall.setArgument(i, jsSubstring(globalData, source, matchStart, matchLen));
+                    }
 
-                // special case of empty match
-                if (!matchLen) {
-                    startPosition++;
-                    if (startPosition > sourceLen)
+                    cachedCall.setArgument(i++, jsNumber(completeMatchStart));
+                    cachedCall.setArgument(i++, sourceVal);
+
+                    cachedCall.setThis(jsUndefined());
+                    JSValue result = cachedCall.call();
+                    if (LIKELY(result.isString()))
+                        replacements.append(asString(result)->value(exec));
+                    else
+                        replacements.append(result.toString(cachedCall.newCallFrame(exec)));
+                    if (exec->hadException())
                         break;
+
+                    lastIndex = matchIndex + matchLen;
+                    startPosition = lastIndex;
+
+                    // special case of empty match
+                    if (!matchLen) {
+                        startPosition++;
+                        if (startPosition > sourceLen)
+                            break;
+                    }
                 }
             }
         } else {
@@ -615,8 +714,11 @@
     JSValue a0 = exec->argument(0);
     if (a0.isUInt32()) {
         uint32_t i = a0.asUInt32();
-        if (i < len)
-            return JSValue::encode(jsNumber(s.characters()[i]));
+        if (i < len) {
+            if (s.is8Bit())
+                return JSValue::encode(jsNumber(s.characters8()[i]));
+            return JSValue::encode(jsNumber(s.characters16()[i]));
+        }
         return JSValue::encode(jsNaN());
     }
     double dpos = a0.toInteger(exec);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to