- Revision
- 100202
- Author
- msab...@apple.com
- Date
- 2011-11-14 15:51:06 -0800 (Mon, 14 Nov 2011)
Log Message
Towards 8 bit strings - Add 8 bit handling to JSString Ropes
https://bugs.webkit.org/show_bug.cgi?id=72317
Added bit to track that a rope is made up of all 8 bit fibers.
Created an 8 bit path (fast and slow cases) to handle 8 bit
only ropes.
Reviewed by Oliver Hunt.
* runtime/JSString.cpp:
(JSC::JSString::resolveRope):
(JSC::JSString::resolveRopeSlowCase8):
(JSC::JSString::resolveRopeSlowCase16):
* runtime/JSString.h:
(JSC::RopeBuilder::finishCreation):
(JSC::RopeBuilder::is8Bit):
(JSC::jsSubstring8):
Modified Paths
Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (100201 => 100202)
--- trunk/Source/_javascript_Core/ChangeLog 2011-11-14 23:33:30 UTC (rev 100201)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-11-14 23:51:06 UTC (rev 100202)
@@ -1,3 +1,23 @@
+2011-11-14 Michael Saboff <msab...@apple.com>
+
+ Towards 8 bit strings - Add 8 bit handling to JSString Ropes
+ https://bugs.webkit.org/show_bug.cgi?id=72317
+
+ Added bit to track that a rope is made up of all 8 bit fibers.
+ Created an 8 bit path (fast and slow cases) to handle 8 bit
+ only ropes.
+
+ Reviewed by Oliver Hunt.
+
+ * runtime/JSString.cpp:
+ (JSC::JSString::resolveRope):
+ (JSC::JSString::resolveRopeSlowCase8):
+ (JSC::JSString::resolveRopeSlowCase16):
+ * runtime/JSString.h:
+ (JSC::RopeBuilder::finishCreation):
+ (JSC::RopeBuilder::is8Bit):
+ (JSC::jsSubstring8):
+
2011-11-14 Geoffrey Garen <gga...@apple.com>
A little bit of function call cleanup
Modified: trunk/Source/_javascript_Core/runtime/JSString.cpp (100201 => 100202)
--- trunk/Source/_javascript_Core/runtime/JSString.cpp 2011-11-14 23:33:30 UTC (rev 100201)
+++ trunk/Source/_javascript_Core/runtime/JSString.cpp 2011-11-14 23:51:06 UTC (rev 100202)
@@ -62,6 +62,34 @@
{
ASSERT(isRope());
+ if (is8Bit()) {
+ LChar* buffer;
+ if (PassRefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer))
+ m_value = newImpl;
+ else {
+ outOfMemory(exec);
+ return;
+ }
+
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
+ if (m_fibers[i]->isRope())
+ return resolveRopeSlowCase(exec, buffer);
+ }
+
+ LChar* position = buffer;
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
+ StringImpl* string = m_fibers[i]->m_value.impl();
+ unsigned length = string->length();
+ StringImpl::copyChars(position, string->characters8(), length);
+ position += length;
+ m_fibers[i].clear();
+ }
+ ASSERT((buffer + m_length) == position);
+ ASSERT(!isRope());
+
+ return;
+ }
+
UChar* buffer;
if (PassRefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer))
m_value = newImpl;
@@ -79,7 +107,7 @@
for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
StringImpl* string = m_fibers[i]->m_value.impl();
unsigned length = string->length();
- StringImpl::copyChars(position, string->characters16(), length);
+ StringImpl::copyChars(position, string->characters(), length);
position += length;
m_fibers[i].clear();
}
@@ -87,7 +115,7 @@
ASSERT(!isRope());
}
-// Overview: this methods converts a JSString from holding a string in rope form
+// Overview: These functions convert a JSString from holding a string in rope form
// down to a simple UString representation. It does so by building up the string
// backwards, since we want to avoid recursion, we expect that the tree structure
// representing the rope is likely imbalanced with more nodes down the left side
@@ -97,11 +125,11 @@
// Vector before performing any concatenation, but by working backwards we likely
// only fill the queue with the number of substrings at any given level in a
// rope-of-ropes.)
-void JSString::resolveRopeSlowCase(ExecState* exec, UChar* buffer) const
+void JSString::resolveRopeSlowCase(ExecState* exec, LChar* buffer) const
{
UNUSED_PARAM(exec);
- UChar* position = buffer + m_length; // We will be working backwards over the rope.
+ LChar* position = buffer + m_length; // We will be working backwards over the rope.
Vector<JSString*, 32> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method.
for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
@@ -123,13 +151,43 @@
StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl());
unsigned length = string->length();
position -= length;
- StringImpl::copyChars(position, string->characters16(), length);
+ StringImpl::copyChars(position, string->characters8(), length);
}
ASSERT(buffer == position);
ASSERT(!isRope());
}
+void JSString::resolveRopeSlowCase(ExecState* exec, UChar* buffer) const
+{
+ UNUSED_PARAM(exec);
+
+ UChar* position = buffer + m_length; // We will be working backwards over the rope.
+ Vector<JSString*, 32> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK.
+
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
+ workQueue.append(m_fibers[i].get());
+
+ while (!workQueue.isEmpty()) {
+ JSString* currentFiber = workQueue.last();
+ workQueue.removeLast();
+
+ if (currentFiber->isRope()) {
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiber->m_fibers[i]; ++i)
+ workQueue.append(currentFiber->m_fibers[i].get());
+ continue;
+ }
+
+ StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl());
+ unsigned length = string->length();
+ position -= length;
+ StringImpl::copyChars(position, string->characters(), length);
+ }
+
+ ASSERT(buffer == position);
+ ASSERT(!isRope());
+}
+
void JSString::outOfMemory(ExecState* exec) const
{
for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
Modified: trunk/Source/_javascript_Core/runtime/JSString.h (100201 => 100202)
--- trunk/Source/_javascript_Core/runtime/JSString.h 2011-11-14 23:33:30 UTC (rev 100201)
+++ trunk/Source/_javascript_Core/runtime/JSString.h 2011-11-14 23:51:06 UTC (rev 100202)
@@ -22,7 +22,6 @@
#ifndef JSString_h
#define JSString_h
-
#include "CallFrame.h"
#include "CommonIdentifiers.h"
#include "Identifier.h"
@@ -85,6 +84,7 @@
expand();
m_jsString->m_fibers[m_index++].set(m_globalData, m_jsString, jsString);
m_jsString->m_length += jsString->m_length;
+ m_jsString->m_is8Bit = m_jsString->m_is8Bit && jsString->m_is8Bit;
}
JSString* release()
@@ -127,6 +127,7 @@
ASSERT(!m_value.isNull());
Base::finishCreation(globalData);
m_length = length;
+ m_is8Bit = m_value.impl()->is8Bit();
}
void finishCreation(JSGlobalData& globalData, size_t length, size_t cost)
@@ -134,6 +135,7 @@
ASSERT(!m_value.isNull());
Base::finishCreation(globalData);
m_length = length;
+ m_is8Bit = m_value.impl()->is8Bit();
Heap::heap(this)->reportExtraMemoryCost(cost);
}
@@ -141,6 +143,7 @@
{
Base::finishCreation(globalData);
m_length = s1->length() + s2->length();
+ m_is8Bit = (s1->is8Bit() && s2->is8Bit());
m_fibers[0].set(globalData, this, s1);
m_fibers[1].set(globalData, this, s2);
}
@@ -149,6 +152,7 @@
{
Base::finishCreation(globalData);
m_length = s1->length() + s2->length() + s3->length();
+ m_is8Bit = (s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
m_fibers[0].set(globalData, this, s1);
m_fibers[1].set(globalData, this, s2);
m_fibers[2].set(globalData, this, s3);
@@ -244,6 +248,7 @@
}
void resolveRope(ExecState*) const;
+ void resolveRopeSlowCase(ExecState*, LChar*) const;
void resolveRopeSlowCase(ExecState*, UChar*) const;
void outOfMemory(ExecState*) const;
@@ -256,11 +261,13 @@
static const unsigned s_maxInternalRopeLength = 3;
// A string is represented either by a UString or a rope of fibers.
+ bool m_is8Bit : 1;
unsigned m_length;
mutable UString m_value;
mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
bool isRope() const { return m_value.isNull(); }
+ bool is8Bit() const { return m_is8Bit; }
UString& string() { ASSERT(!isRope()); return m_value; }
friend JSValue jsString(ExecState*, JSString*, JSString*);