18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is free software; you can redistribute it and/or
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  modify it under the terms of the GNU Library General Public
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License as published by the Free Software Foundation; either
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  version 2 of the License, or (at your option) any later version.
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is distributed in the hope that it will be useful,
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  but WITHOUT ANY WARRANTY; without even the implied warranty of
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Library General Public License for more details.
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  You should have received a copy of the GNU Library General Public License
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  along with this library; see the file COPYING.LIB.  If not, write to
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Boston, MA 02110-1301, USA.
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSString.h"
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSGlobalObject.h"
27f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick#include "JSGlobalObjectFunctions.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSObject.h"
29643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#include "Operations.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "StringObject.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "StringPrototype.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace JSC {
34f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
35f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochstatic const unsigned substringFromRopeCutoff = 4;
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
37643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// Overview: this methods converts a JSString from holding a string in rope form
38643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// down to a simple UString representation.  It does so by building up the string
39643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// backwards, since we want to avoid recursion, we expect that the tree structure
40643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// representing the rope is likely imbalanced with more nodes down the left side
41643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// (since appending to the string is likely more common) - and as such resolving
42643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// in this fashion should minimize work queue size.  (If we built the queue forwards
43f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick// we would likely have to place all of the constituent StringImpls into the
44643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// Vector before performing any concatenation, but by working backwards we likely
45643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// only fill the queue with the number of substrings at any given level in a
46643ca7872b450ea4efacab6188849e5aac2ba161Steve Block// rope-of-ropes.)
47643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid JSString::resolveRope(ExecState* exec) const
48643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
49643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    ASSERT(isRope());
50643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
51643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Allocate the buffer to hold the final string, position initially points to the end.
52643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    UChar* buffer;
53f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (PassRefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer))
54d0825bca7fe65beaee391d30da42e937db621564Steve Block        m_value = newImpl;
55d0825bca7fe65beaee391d30da42e937db621564Steve Block    else {
56692e5dbf12901edacf14812a6fae25462920af42Steve Block        for (unsigned i = 0; i < m_fiberCount; ++i) {
57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            RopeImpl::deref(m_other.m_fibers[i]);
58692e5dbf12901edacf14812a6fae25462920af42Steve Block            m_other.m_fibers[i] = 0;
59d0825bca7fe65beaee391d30da42e937db621564Steve Block        }
60692e5dbf12901edacf14812a6fae25462920af42Steve Block        m_fiberCount = 0;
61643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        ASSERT(!isRope());
62643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        ASSERT(m_value == UString());
63e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        if (exec)
64e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block            throwOutOfMemoryError(exec);
65643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return;
66643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
67692e5dbf12901edacf14812a6fae25462920af42Steve Block    UChar* position = buffer + m_length;
68643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Start with the current RopeImpl.
70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    Vector<RopeImpl::Fiber, 32> workQueue;
71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    RopeImpl::Fiber currentFiber;
72692e5dbf12901edacf14812a6fae25462920af42Steve Block    for (unsigned i = 0; i < (m_fiberCount - 1); ++i)
73692e5dbf12901edacf14812a6fae25462920af42Steve Block        workQueue.append(m_other.m_fibers[i]);
74692e5dbf12901edacf14812a6fae25462920af42Steve Block    currentFiber = m_other.m_fibers[m_fiberCount - 1];
75643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    while (true) {
76dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (RopeImpl::isRope(currentFiber)) {
77dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            RopeImpl* rope = static_cast<RopeImpl*>(currentFiber);
78643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber'
79643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            // (we will be working backwards over the rope).
80692e5dbf12901edacf14812a6fae25462920af42Steve Block            unsigned fiberCountMinusOne = rope->fiberCount() - 1;
81692e5dbf12901edacf14812a6fae25462920af42Steve Block            for (unsigned i = 0; i < fiberCountMinusOne; ++i)
826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen                workQueue.append(rope->fibers()[i]);
836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            currentFiber = rope->fibers()[fiberCountMinusOne];
84643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        } else {
85f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick            StringImpl* string = static_cast<StringImpl*>(currentFiber);
86692e5dbf12901edacf14812a6fae25462920af42Steve Block            unsigned length = string->length();
87643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            position -= length;
88f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick            StringImpl::copyChars(position, string->characters(), length);
89643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
90643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            // Was this the last item in the work queue?
91643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            if (workQueue.isEmpty()) {
92643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                // Create a string from the UChar buffer, clear the rope RefPtr.
93643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                ASSERT(buffer == position);
94692e5dbf12901edacf14812a6fae25462920af42Steve Block                for (unsigned i = 0; i < m_fiberCount; ++i) {
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    RopeImpl::deref(m_other.m_fibers[i]);
96692e5dbf12901edacf14812a6fae25462920af42Steve Block                    m_other.m_fibers[i] = 0;
97d0825bca7fe65beaee391d30da42e937db621564Steve Block                }
98692e5dbf12901edacf14812a6fae25462920af42Steve Block                m_fiberCount = 0;
99643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
100643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                ASSERT(!isRope());
101643ca7872b450ea4efacab6188849e5aac2ba161Steve Block                return;
102643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            }
103643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
104643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            // No! - set the next item up to process.
105643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            currentFiber = workQueue.last();
106643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            workQueue.removeLast();
107643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        }
108643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
109643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
110f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
111f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch// This function construsts a substring out of a rope without flattening by reusing the existing fibers.
112f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch// This can reduce memory usage substantially. Since traversing ropes is slow the function will revert
113f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch// back to flattening if the rope turns out to be long.
114f05b935882198ccf7d81675736e3aeb089c5113aBen MurdochJSString* JSString::substringFromRope(ExecState* exec, unsigned substringStart, unsigned substringLength)
115f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{
116f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    ASSERT(isRope());
117f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    ASSERT(substringLength);
118f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
119f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    JSGlobalData* globalData = &exec->globalData();
120f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
121f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    UString substringFibers[3];
122f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
123f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    unsigned fiberCount = 0;
124f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    unsigned substringFiberCount = 0;
125f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    unsigned substringEnd = substringStart + substringLength;
126f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    unsigned fiberEnd = 0;
127f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
128f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    RopeIterator end;
129f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    for (RopeIterator it(m_other.m_fibers.data(), m_fiberCount); it != end; ++it) {
130f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        ++fiberCount;
131f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        StringImpl* fiberString = *it;
132f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        unsigned fiberStart = fiberEnd;
133f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        fiberEnd = fiberStart + fiberString->length();
134f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (fiberEnd <= substringStart)
135f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            continue;
136f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        unsigned copyStart = std::max(substringStart, fiberStart);
137f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        unsigned copyEnd = std::min(substringEnd, fiberEnd);
138f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (copyStart == fiberStart && copyEnd == fiberEnd)
139f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            substringFibers[substringFiberCount++] = UString(fiberString);
140f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        else
141f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            substringFibers[substringFiberCount++] = UString(StringImpl::create(fiberString, copyStart - fiberStart, copyEnd - copyStart));
142f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (fiberEnd >= substringEnd)
143f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            break;
144f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        if (fiberCount > substringFromRopeCutoff || substringFiberCount >= 3) {
145f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            // This turned out to be a really inefficient rope. Just flatten it.
146f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            resolveRope(exec);
147f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            return jsSubstring(&exec->globalData(), m_value, substringStart, substringLength);
148f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        }
149f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    }
150f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    ASSERT(substringFiberCount && substringFiberCount <= 3);
151f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch
152f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (substringLength == 1) {
153f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        ASSERT(substringFiberCount == 1);
154f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        UChar c = substringFibers[0].characters()[0];
1552bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (c <= maxSingleCharacterString)
156f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            return globalData->smallStrings.singleCharacterString(globalData, c);
157f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    }
158f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (substringFiberCount == 1)
159f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return new (globalData) JSString(globalData, substringFibers[0]);
160f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (substringFiberCount == 2)
161f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        return new (globalData) JSString(globalData, substringFibers[0], substringFibers[1]);
162f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    return new (globalData) JSString(globalData, substringFibers[0], substringFibers[1], substringFibers[2]);
163f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch}
164643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1656c2af9490927c3c5959b5cb07461b646f8b32f6cKristian MonsenJSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UString& replacement)
1666c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
1676c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (!isRope()) {
168f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        size_t matchPosition = m_value.find(character);
169f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        if (matchPosition == notFound)
1706c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            return JSValue(this);
171f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        return jsString(exec, m_value.substringSharingImpl(0, matchPosition), replacement, m_value.substringSharingImpl(matchPosition + 1));
1726c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    }
1736c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1746c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    RopeIterator end;
1756c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1766c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // Count total fibers and find matching string.
1776c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    size_t fiberCount = 0;
178f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    StringImpl* matchString = 0;
179f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t matchPosition = notFound;
180ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    for (RopeIterator it(m_other.m_fibers.data(), m_fiberCount); it != end; ++it) {
1816c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        ++fiberCount;
1826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        if (matchString)
1836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            continue;
1846c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
185f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        StringImpl* string = *it;
1866c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        matchPosition = string->find(character);
187f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        if (matchPosition == notFound)
1886c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            continue;
1896c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        matchString = string;
1906c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    }
1916c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1926c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (!matchString)
1936c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        return this;
1946c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
195f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    RopeBuilder builder(replacement.length() ? fiberCount + 2 : fiberCount + 1);
1966c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (UNLIKELY(builder.isOutOfMemory()))
1976c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        return throwOutOfMemoryError(exec);
1986c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
199ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block    for (RopeIterator it(m_other.m_fibers.data(), m_fiberCount); it != end; ++it) {
200f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        StringImpl* string = *it;
2016c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        if (string != matchString) {
2026c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            builder.append(UString(string));
2036c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            continue;
2046c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        }
2056c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
206f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        builder.append(UString(string).substringSharingImpl(0, matchPosition));
207f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        if (replacement.length())
2086c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            builder.append(replacement);
209f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        builder.append(UString(string).substringSharingImpl(matchPosition + 1));
21006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        matchString = 0;
2116c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    }
2126c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2136c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    JSGlobalData* globalData = &exec->globalData();
2146c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    return JSValue(new (globalData) JSString(globalData, builder.release()));
2156c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
2166c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
217dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockJSString* JSString::getIndexSlowCase(ExecState* exec, unsigned i)
218dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
219dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT(isRope());
220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    resolveRope(exec);
221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Return a safe no-value result, this should never be used, since the excetion will be thrown.
222dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (exec->exception())
223dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return jsString(exec, "");
224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT(!isRope());
225f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    ASSERT(i < m_value.length());
226dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return jsSingleCharacterSubstring(exec, m_value, i);
227dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
228dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
2295f1ab04193ad0130ca8204aadaceae083aca9881Feng QianJSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return const_cast<JSString*>(this);
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
234643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockbool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
236643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    result = this;
237f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    number = jsToNumber(value(exec));
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool JSString::toBoolean(ExecState*) const
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
243692e5dbf12901edacf14812a6fae25462920af42Steve Block    return m_length;
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
246643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockdouble JSString::toNumber(ExecState* exec) const
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
248f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    return jsToNumber(value(exec));
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
251643ca7872b450ea4efacab6188849e5aac2ba161Steve BlockUString JSString::toString(ExecState* exec) const
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
253643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return value(exec);
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2562bde8e466a4451c7319e3a072d118917957d6554Steve Blockinline StringObject* StringObject::create(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2582bde8e466a4451c7319e3a072d118917957d6554Steve Block    return new (exec) StringObject(exec->globalData(), globalObject->stringObjectStructure(), string);
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2612bde8e466a4451c7319e3a072d118917957d6554Steve BlockJSObject* JSString::toObject(ExecState* exec, JSGlobalObject* globalObject) const
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2632bde8e466a4451c7319e3a072d118917957d6554Steve Block    return StringObject::create(exec, globalObject, const_cast<JSString*>(this));
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectJSObject* JSString::toThisObject(ExecState* exec) const
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2682bde8e466a4451c7319e3a072d118917957d6554Steve Block    return StringObject::create(exec, exec->lexicalGlobalObject(), const_cast<JSString*>(this));
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The semantics here are really getPropertySlot, not getOwnPropertySlot.
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // This function should only be called by JSValue::get.
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (getStringPropertySlot(exec, propertyName, slot))
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return true;
2775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (propertyName == exec->propertyNames().underscoreProto) {
2785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        slot.setValue(exec->lexicalGlobalObject()->stringPrototype());
2795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return true;
2805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    slot.setBase(this);
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    JSObject* object;
2835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (JSValue prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype.isNull(); prototype = object->prototype()) {
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        object = asObject(prototype);
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (object->getOwnPropertySlot(exec, propertyName, slot))
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return true;
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    slot.setUndefined();
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
292231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockbool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
293231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
294231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (propertyName == exec->propertyNames().length) {
295e14391e94c850b8bd03680c23b38978db68687a8John Reck        descriptor.setDescriptor(jsNumber(m_length), DontEnum | DontDelete | ReadOnly);
296231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return true;
297231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
298231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
299231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    bool isStrictUInt32;
300f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned i = propertyName.toUInt32(isStrictUInt32);
301692e5dbf12901edacf14812a6fae25462920af42Steve Block    if (isStrictUInt32 && i < m_length) {
302dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly);
303231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return true;
304231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
305231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
306231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return false;
307231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
308231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
309231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockbool JSString::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
310231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
311231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (getStringPropertyDescriptor(exec, propertyName, descriptor))
312231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return true;
313231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (propertyName != exec->propertyNames().underscoreProto)
314231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return false;
315231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    descriptor.setDescriptor(exec->lexicalGlobalObject()->stringPrototype(), DontEnum);
316231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return true;
317231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
318231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The semantics here are really getPropertySlot, not getOwnPropertySlot.
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // This function should only be called by JSValue::get.
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (getStringPropertySlot(exec, propertyName, slot))
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return true;
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace JSC
329